1- import React from 'react' ;
1+ import React , { useEffect , useCallback } from 'react' ;
22import { motion , AnimatePresence } from 'framer-motion' ;
33import { X , Loader2 } from 'lucide-react' ;
44import { toast } from 'sonner' ;
55import aiTorAvatar from '@/assets/ai-tor-avatar.jpg' ;
66
7+ const PROACTIVE_MESSAGES = [
8+ "¿Puedo ayudarte a encontrar algo?" ,
9+ "¿Tienes alguna pregunta sobre AlienFlowSpace?" ,
10+ "¿Necesitas ayuda con los NFTs o las DAOs?" ,
11+ "¿Te gustaría conocer más sobre nuestro ecosistema?" ,
12+ "¿En qué puedo asistirte hoy?"
13+ ] ;
14+
715const AIChatbot = ( ) => {
816 const [ isOpen , setIsOpen ] = React . useState ( false ) ;
917 const [ isLoading , setIsLoading ] = React . useState ( true ) ;
18+ const [ showProactive , setShowProactive ] = React . useState ( false ) ;
19+ const [ proactiveMessage , setProactiveMessage ] = React . useState ( '' ) ;
20+ const [ hasInteracted , setHasInteracted ] = React . useState ( false ) ;
21+
22+ // Proactive engagement - show after 45 seconds of inactivity
23+ useEffect ( ( ) => {
24+ if ( hasInteracted || isOpen ) return ;
25+
26+ const timer = setTimeout ( ( ) => {
27+ const randomMessage = PROACTIVE_MESSAGES [ Math . floor ( Math . random ( ) * PROACTIVE_MESSAGES . length ) ] ;
28+ setProactiveMessage ( randomMessage ) ;
29+ setShowProactive ( true ) ;
30+
31+ // Auto-hide after 8 seconds
32+ setTimeout ( ( ) => setShowProactive ( false ) , 8000 ) ;
33+ } , 45000 ) ;
34+
35+ return ( ) => clearTimeout ( timer ) ;
36+ } , [ hasInteracted , isOpen ] ) ;
1037
11- const handleOpen = ( ) => {
38+ // Track user interaction
39+ useEffect ( ( ) => {
40+ const handleInteraction = ( ) => setHasInteracted ( true ) ;
41+ window . addEventListener ( 'click' , handleInteraction , { once : true } ) ;
42+ window . addEventListener ( 'scroll' , handleInteraction , { once : true } ) ;
43+ return ( ) => {
44+ window . removeEventListener ( 'click' , handleInteraction ) ;
45+ window . removeEventListener ( 'scroll' , handleInteraction ) ;
46+ } ;
47+ } , [ ] ) ;
48+
49+ const handleOpen = useCallback ( ( ) => {
1250 setIsOpen ( true ) ;
1351 setIsLoading ( true ) ;
52+ setShowProactive ( false ) ;
53+ setHasInteracted ( true ) ;
1454 toast . info ( 'AI Assistant Loading' , {
1555 description : 'Opening AI Tor Assistant...'
1656 } ) ;
17- } ;
57+ } , [ ] ) ;
1858
19- const handleIframeLoad = ( ) => {
59+ const handleIframeLoad = useCallback ( ( ) => {
2060 setIsLoading ( false ) ;
21- } ;
61+ } , [ ] ) ;
2262
2363 return (
2464 < >
@@ -35,6 +75,35 @@ const AIChatbot = () => {
3575 ) }
3676 </ AnimatePresence >
3777
78+ { /* Proactive Engagement Bubble */ }
79+ < AnimatePresence >
80+ { showProactive && ! isOpen && (
81+ < motion . div
82+ initial = { { opacity : 0 , x : 20 , scale : 0.8 } }
83+ animate = { { opacity : 1 , x : 0 , scale : 1 } }
84+ exit = { { opacity : 0 , x : 20 , scale : 0.8 } }
85+ className = "fixed bottom-36 right-4 sm:bottom-40 sm:right-8 z-40
86+ max-w-[250px] p-3 rounded-xl rounded-br-sm
87+ bg-gradient-to-br from-alien-gold/90 to-alien-gold-dark/90
88+ backdrop-blur-md border border-alien-gold-light/50
89+ shadow-lg shadow-alien-gold/20 cursor-pointer"
90+ onClick = { handleOpen }
91+ >
92+ < p className = "text-alien-space-dark font-exo text-sm font-medium" >
93+ { proactiveMessage }
94+ </ p >
95+ < button
96+ onClick = { ( e ) => { e . stopPropagation ( ) ; setShowProactive ( false ) ; } }
97+ className = "absolute -top-2 -right-2 w-5 h-5 bg-alien-space-dark rounded-full
98+ flex items-center justify-center border border-alien-gold/50
99+ hover:bg-alien-gold/20 transition-colors"
100+ >
101+ < X className = "w-3 h-3 text-alien-gold" />
102+ </ button >
103+ </ motion . div >
104+ ) }
105+ </ AnimatePresence >
106+
38107 { /* Floating Button */ }
39108 < motion . button
40109 initial = { { opacity : 0 , scale : 0.5 } }
@@ -56,7 +125,7 @@ const AIChatbot = () => {
56125 />
57126 </ motion . button >
58127
59- { /* Chat Window - Fullscreen on mobile */ }
128+ { /* Chat Window - Fullscreen on mobile, optimized size on desktop */ }
60129 < AnimatePresence >
61130 { isOpen && (
62131 < motion . div
@@ -67,8 +136,8 @@ const AIChatbot = () => {
67136 className = "fixed z-50
68137 inset-0 sm:inset-auto
69138 sm:bottom-24 sm:right-8
70- sm:w-[380px ] md:w-[420px ]
71- sm:h-[550px ] md:h-[600px ]
139+ sm:w-[360px ] md:w-[380px ]
140+ sm:h-[480px ] md:h-[520px ]
72141 sm:max-h-[calc(100vh-8rem)]
73142 bg-alien-space-dark/98 backdrop-blur-xl
74143 sm:border-2 border-alien-gold/40 sm:rounded-2xl
@@ -91,10 +160,20 @@ const AIChatbot = () => {
91160 </ h3 >
92161 < p className = "text-xs text-alien-green font-exo" > AI Tor</ p >
93162 </ div >
94- { /* Status indicator */ }
163+ { /* Status indicator with typing animation when loading */ }
95164 < div className = "flex items-center gap-1.5 ml-2" >
96- < span className = "w-2 h-2 bg-alien-green rounded-full animate-pulse" />
97- < span className = "text-xs text-muted-foreground hidden sm:inline" > Online</ span >
165+ { isLoading ? (
166+ < div className = "flex items-center gap-1" >
167+ < span className = "typing-dot" />
168+ < span className = "typing-dot" style = { { animationDelay : '0.2s' } } />
169+ < span className = "typing-dot" style = { { animationDelay : '0.4s' } } />
170+ </ div >
171+ ) : (
172+ < >
173+ < span className = "w-2 h-2 bg-alien-green rounded-full animate-pulse" />
174+ < span className = "text-xs text-muted-foreground hidden sm:inline" > Online</ span >
175+ </ >
176+ ) }
98177 </ div >
99178 </ div >
100179 < button
@@ -127,10 +206,11 @@ const AIChatbot = () => {
127206 < Loader2 className = "absolute -bottom-1 -right-1 h-8 w-8 text-alien-gold animate-spin" />
128207 </ div >
129208 < p className = "text-alien-gold font-nasalization text-sm mt-4" > Loading AI Tor...</ p >
130- < div className = "flex gap-1 mt-3" >
131- < span className = "w-2 h-2 bg-alien-gold rounded-full animate-bounce" style = { { animationDelay : '0ms' } } />
132- < span className = "w-2 h-2 bg-alien-gold rounded-full animate-bounce" style = { { animationDelay : '150ms' } } />
133- < span className = "w-2 h-2 bg-alien-gold rounded-full animate-bounce" style = { { animationDelay : '300ms' } } />
209+ { /* Typing indicator animation */ }
210+ < div className = "flex gap-1.5 mt-3" >
211+ < span className = "typing-dot-lg" />
212+ < span className = "typing-dot-lg" style = { { animationDelay : '0.15s' } } />
213+ < span className = "typing-dot-lg" style = { { animationDelay : '0.3s' } } />
134214 </ div >
135215 </ motion . div >
136216 ) }
0 commit comments