1- import { memo , useRef , useEffect , useCallback , useMemo } from "react"
1+ import { memo , useRef , useEffect , useCallback , useMemo , useState } from "react"
22import { Card , CardContent , CardHeader , CardTitle } from "@/components/ui/card"
33import { ScrollArea } from "@/components/ui/scroll-area"
44import { Input } from "@/components/ui/input"
55import { Button } from "@/components/ui/button"
66import { Avatar , AvatarFallback , AvatarImage } from "@/components/ui/avatar"
7- import { MessageCircle , Send } from "lucide-react"
7+ import { MessageCircle , Send , Lock , Sparkles } from "lucide-react"
88import { cn } from "@/lib/utils"
9+ import UpgradeDialog from "@/components/UpgradeDialog"
910
10- // Activity Message Component (system messages for queue events)
1111const ActivityMessage = memo ( ( { msg } ) => (
1212 < div className = "flex justify-center py-1" >
1313 < p className = "text-xs text-muted-foreground/70 bg-green-950/30 px-3 py-1 rounded-full" >
@@ -16,7 +16,6 @@ const ActivityMessage = memo(({ msg }) => (
1616 </ div >
1717) )
1818
19- // Chat Message Component
2019const ChatMessage = memo ( ( { msg, isOwn } ) => (
2120 < div className = { cn ( "flex gap-2" , isOwn ? "justify-end" : "justify-start" ) } >
2221 { ! isOwn && (
@@ -49,15 +48,39 @@ const ChatMessage = memo(({ msg, isOwn }) => (
4948 </ div >
5049) )
5150
52- // Empty State
5351const EmptyState = memo ( ( ) => (
5452 < div className = "h-full flex flex-col items-center justify-center text-center p-4" >
5553 < MessageCircle className = "h-8 w-8 md:h-12 md:w-12 text-muted-foreground/30 mb-2" />
5654 < p className = "text-muted-foreground text-xs md:text-sm" > No messages yet</ p >
5755 </ div >
5856) )
5957
60- // Messages List with activity message support
58+ const ChatLockedOverlay = memo ( ( { onUpgrade } ) => (
59+ < div
60+ className = "absolute inset-0 z-10 flex flex-col items-center justify-center bg-background/80 backdrop-blur-sm rounded-lg cursor-pointer"
61+ onClick = { onUpgrade }
62+ >
63+ < div className = "flex flex-col items-center gap-3 p-6 text-center" >
64+ < div className = "p-3 rounded-full bg-primary/10" >
65+ < Lock className = "h-6 w-6 text-primary" />
66+ </ div >
67+ < div >
68+ < p className = "font-semibold text-sm" > Group Chat is a PRO feature</ p >
69+ < p className = "text-xs text-muted-foreground mt-1" >
70+ Tap to upgrade and chat with your group
71+ </ p >
72+ </ div >
73+ < Button
74+ size = "sm"
75+ className = "gap-1.5 rounded-full bg-gradient-to-r from-amber-500 to-orange-500 hover:from-amber-600 hover:to-orange-600 text-white"
76+ >
77+ < Sparkles className = "h-3.5 w-3.5" />
78+ Upgrade to PRO
79+ </ Button >
80+ </ div >
81+ </ div >
82+ ) )
83+
6184const MessagesList = memo ( ( { messages, currentUserId } ) => {
6285 if ( messages . length === 0 ) {
6386 return < EmptyState />
@@ -76,12 +99,11 @@ const MessagesList = memo(({ messages, currentUserId }) => {
7699 )
77100} )
78101
79- // Main GroupChat Component
80- const GroupChat = ( { messages, currentUserId, onSendMessage } ) => {
102+ const GroupChat = ( { messages, currentUserId, onSendMessage, locked = false } ) => {
81103 const inputRef = useRef ( null )
82104 const scrollRef = useRef ( null )
105+ const [ showUpgrade , setShowUpgrade ] = useState ( false )
83106
84- // Auto-scroll to bottom on new messages
85107 useEffect ( ( ) => {
86108 if ( scrollRef . current ) {
87109 const scrollContainer = scrollRef . current . querySelector ( "[data-radix-scroll-area-viewport]" )
@@ -92,12 +114,13 @@ const GroupChat = ({ messages, currentUserId, onSendMessage }) => {
92114 } , [ messages . length ] )
93115
94116 const handleSend = useCallback ( ( ) => {
117+ if ( locked ) return
95118 const message = inputRef . current ?. value ?. trim ( )
96119 if ( message ) {
97120 onSendMessage ( message )
98121 inputRef . current . value = ""
99122 }
100- } , [ onSendMessage ] )
123+ } , [ onSendMessage , locked ] )
101124
102125 const handleKeyPress = useCallback (
103126 ( e ) => {
@@ -109,20 +132,22 @@ const GroupChat = ({ messages, currentUserId, onSendMessage }) => {
109132 [ handleSend ] ,
110133 )
111134
112- // Memoize message count (exclude activity messages from count)
113135 const userMessageCount = useMemo (
114136 ( ) => messages . filter ( ( m ) => m . type !== "activity" ) . length ,
115137 [ messages ] ,
116138 )
117139
118140 return (
119- < Card className = "h-full flex flex-col border-border/50 shadow-lg overflow-hidden" >
141+ < Card className = "h-full flex flex-col border-border/50 shadow-lg overflow-hidden relative" >
142+ { locked && < ChatLockedOverlay onUpgrade = { ( ) => setShowUpgrade ( true ) } /> }
143+
120144 < CardHeader className = "py-2 md:pb-3 px-3 md:px-6 border-b border-border/50" >
121145 < CardTitle className = "text-sm md:text-lg flex items-center gap-2" >
122146 < div className = "p-1 md:p-1.5 rounded-full bg-primary/10" >
123147 < MessageCircle className = "h-3 w-3 md:h-4 md:w-4 text-primary" />
124148 </ div >
125149 Chat
150+ { locked && < Lock className = "h-3 w-3 text-muted-foreground" /> }
126151 { userMessageCount > 0 && (
127152 < span className = "text-xs font-normal text-muted-foreground" > ({ userMessageCount } )</ span >
128153 ) }
@@ -138,20 +163,24 @@ const GroupChat = ({ messages, currentUserId, onSendMessage }) => {
138163 < div className = "flex gap-2" >
139164 < Input
140165 ref = { inputRef }
141- placeholder = " Type a message..."
166+ placeholder = { locked ? "PRO feature" : " Type a message..."}
142167 onKeyPress = { handleKeyPress }
168+ disabled = { locked }
143169 className = "rounded-full bg-background border-border/50 h-9 md:h-10 text-sm"
144170 />
145171 < Button
146172 onClick = { handleSend }
147173 size = "icon"
174+ disabled = { locked }
148175 className = "rounded-full shrink-0 h-9 w-9 md:h-10 md:w-10"
149176 >
150177 < Send className = "h-3.5 w-3.5 md:h-4 md:w-4" />
151178 </ Button >
152179 </ div >
153180 </ div >
154181 </ CardContent >
182+
183+ < UpgradeDialog open = { showUpgrade } onOpenChange = { setShowUpgrade } feature = "realtimeChat" />
155184 </ Card >
156185 )
157186}
0 commit comments