'use client' import { useState, useEffect, useCallback, useRef } from 'react' import { useTheme } from '@/lib/ThemeContext' import { useMessages } from '@/lib/MessagesContext' import { useRouter } from 'next/navigation' interface ChatMessage { id: string senderName: string senderAvatar?: string senderInitials: string content: string timestamp: Date conversationId: string isGroup?: boolean } interface ChatOverlayProps { /** Auto-dismiss after X milliseconds (0 = manual dismiss only) */ autoDismissMs?: number /** Maximum messages to queue */ maxQueue?: number /** Enable typewriter effect */ typewriterEnabled?: boolean /** Typewriter speed in ms per character */ typewriterSpeed?: number /** Enable sound notification */ soundEnabled?: boolean } export function ChatOverlay({ autoDismissMs = 0, maxQueue = 5, typewriterEnabled = true, typewriterSpeed = 30, soundEnabled = false }: ChatOverlayProps) { const { isDark } = useTheme() const router = useRouter() const { conversations, contacts, messages: allMessages } = useMessages() const [messageQueue, setMessageQueue] = useState([]) const [currentMessage, setCurrentMessage] = useState(null) const [isVisible, setIsVisible] = useState(false) const [isExiting, setIsExiting] = useState(false) const [displayedText, setDisplayedText] = useState('') const [isTyping, setIsTyping] = useState(false) const [replyText, setReplyText] = useState('') const [isReplying, setIsReplying] = useState(false) const audioRef = useRef(null) const typewriterRef = useRef(null) const dismissTimerRef = useRef(null) // Initialize audio useEffect(() => { if (soundEnabled && typeof window !== 'undefined') { audioRef.current = new Audio('/sounds/message-pop.mp3') audioRef.current.volume = 0.3 } }, [soundEnabled]) // Simulate incoming messages (for demo - replace with real WebSocket later) useEffect(() => { // Demo: Show a message after 5 seconds const demoTimer = setTimeout(() => { const demoMessage: ChatMessage = { id: `demo-${Date.now()}`, senderName: 'Familie Mueller', senderInitials: 'FM', content: 'Hallo! Lisa hatte heute leider Fieber und konnte nicht zur Schule kommen. Könnten Sie uns bitte die Hausaufgaben für morgen mitteilen?', timestamp: new Date(), conversationId: 'conv1', isGroup: false } addToQueue(demoMessage) }, 5000) return () => clearTimeout(demoTimer) }, []) // Add message to queue const addToQueue = useCallback((message: ChatMessage) => { setMessageQueue(prev => { if (prev.length >= maxQueue) { return [...prev.slice(1), message] } return [...prev, message] }) }, [maxQueue]) // Process queue - show next message useEffect(() => { if (!currentMessage && messageQueue.length > 0 && !isExiting) { const nextMessage = messageQueue[0] setMessageQueue(prev => prev.slice(1)) setCurrentMessage(nextMessage) setIsVisible(true) setDisplayedText('') setIsTyping(true) // Play sound if (soundEnabled && audioRef.current) { audioRef.current.play().catch(() => {}) } } }, [currentMessage, messageQueue, isExiting, soundEnabled]) // Typewriter effect useEffect(() => { if (!currentMessage || !isTyping) return const fullText = currentMessage.content let charIndex = 0 if (typewriterEnabled) { typewriterRef.current = setInterval(() => { charIndex++ setDisplayedText(fullText.slice(0, charIndex)) if (charIndex >= fullText.length) { if (typewriterRef.current) { clearInterval(typewriterRef.current) } setIsTyping(false) } }, typewriterSpeed) } else { setDisplayedText(fullText) setIsTyping(false) } return () => { if (typewriterRef.current) { clearInterval(typewriterRef.current) } } }, [currentMessage, isTyping, typewriterEnabled, typewriterSpeed]) // Auto-dismiss timer useEffect(() => { if (currentMessage && autoDismissMs > 0 && !isTyping && !isReplying) { dismissTimerRef.current = setTimeout(() => { handleDismiss() }, autoDismissMs) } return () => { if (dismissTimerRef.current) { clearTimeout(dismissTimerRef.current) } } }, [currentMessage, autoDismissMs, isTyping, isReplying]) // Dismiss current message const handleDismiss = useCallback(() => { setIsExiting(true) setTimeout(() => { setCurrentMessage(null) setIsVisible(false) setIsExiting(false) setDisplayedText('') setReplyText('') setIsReplying(false) }, 300) // Match exit animation duration }, []) // Open full conversation const handleOpenConversation = useCallback(() => { if (currentMessage) { router.push(`/messages?conversation=${currentMessage.conversationId}`) handleDismiss() } }, [currentMessage, router, handleDismiss]) // Toggle reply mode const handleReplyClick = useCallback(() => { setIsReplying(true) }, []) // Send reply const handleSendReply = useCallback(() => { if (!replyText.trim() || !currentMessage) return // TODO: Actually send the message via MessagesContext console.log('Sending reply:', replyText, 'to conversation:', currentMessage.conversationId) // For now, just dismiss handleDismiss() }, [replyText, currentMessage, handleDismiss]) // Handle keyboard in reply const handleReplyKeyDown = useCallback((e: React.KeyboardEvent) => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault() handleSendReply() } if (e.key === 'Escape') { setIsReplying(false) setReplyText('') } }, [handleSendReply]) if (!isVisible) return null // Glassmorphism styles const overlayStyle = isDark ? 'bg-slate-900/80 backdrop-blur-2xl border-white/20' : 'bg-white/90 backdrop-blur-2xl border-black/10 shadow-2xl' const textColor = isDark ? 'text-white' : 'text-slate-900' const mutedColor = isDark ? 'text-white/60' : 'text-slate-500' const buttonPrimary = isDark ? 'bg-gradient-to-r from-purple-500 to-pink-500 text-white hover:shadow-lg hover:shadow-purple-500/30' : 'bg-gradient-to-r from-purple-600 to-pink-600 text-white hover:shadow-lg hover:shadow-purple-600/30' const buttonSecondary = isDark ? 'bg-white/10 text-white/80 hover:bg-white/20' : 'bg-slate-100 text-slate-700 hover:bg-slate-200' return ( <> {/* Backdrop (subtle) */}
{/* Chat Overlay - Slide in from right */}
{/* Header */}
{/* Avatar */}
{currentMessage?.senderInitials}

{currentMessage?.senderName}

{currentMessage?.isGroup ? 'Gruppenchat' : 'Direktnachricht'} • Jetzt

{/* Close button */}
{/* Message Content with Typewriter Effect */}

{displayedText} {isTyping && ( )}

{/* Reply Input (when replying) */} {isReplying && (