import { useState, useEffect, useRef } from 'react'; import { useStore } from '../store'; import { socket } from '../socket'; import { motion, AnimatePresence } from 'framer-motion'; import { X, Send, User } from 'lucide-react'; import { v4 as uuidv4 } from 'uuid'; export function ChatOverlay() { const { activeChatUser, closeChat, currentUser } = useStore(); const [messages, setMessages] = useState([]); const [inputText, setInputText] = useState(''); const messagesEndRef = useRef(null); useEffect(() => { if (!activeChatUser || !currentUser) return; // Fetch History fetch(`/api/messages/history/${currentUser.id}/${activeChatUser.id}`) .then(res => res.json()) .then(data => { setMessages(data); return fetch(`/api/messages/read/${activeChatUser.id}/${currentUser.id}`, { method: 'PATCH' }); }) .then(() => useStore.getState().fetchUnreadCount()) .catch(console.error); const handleReceiveMessage = (msg) => { // Only append if it belongs to this conversation if (msg.senderId === activeChatUser.id || msg.receiverId === activeChatUser.id) { setMessages(prev => { if (prev.some(m => m.id === msg.id)) return prev; return [...prev, msg]; }); } }; socket.on('receive-message', handleReceiveMessage); return () => { socket.off('receive-message', handleReceiveMessage); }; }, [activeChatUser, currentUser]); useEffect(() => { messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' }); }, [messages]); const sendMessage = async (e) => { e.preventDefault(); if (!inputText.trim() || !activeChatUser) return; const newMsg = { id: uuidv4(), senderId: currentUser.id, receiverId: activeChatUser.id, message: inputText.trim(), timestamp: Date.now() }; // Optimistically update UI setMessages(prev => [...prev, newMsg]); setInputText(''); // Emit via socket purely for live relay socket.emit('send-message', newMsg); // Save strictly to database try { await fetch(`/api/messages`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-socket-id': socket.id }, body: JSON.stringify(newMsg) }); } catch(err) { console.error("Failed to send message", err); } }; if (!activeChatUser) return null; return (
e.stopPropagation()} // Prevent closing when clicking inside > {/* Chat Header */}
{activeChatUser.selfiePath ? ( Avatar ) : ( )}

{activeChatUser.name}

Active Now

{/* Chat Transcript Log */}
{messages.length === 0 ? (
Start your conversation!
Messages are end-to-end direct.
) : ( messages.map(msg => { const isMe = msg.senderId === currentUser?.id; return (
{msg.message}
{new Date(msg.timestamp).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}
); }) )}
{/* Chat Input Dock */}
setInputText(e.target.value)} placeholder="Type your message..." style={{ flex: 1, background: 'var(--surface-light)', border: '1px solid var(--border-color)', color: 'white', padding: '12px 16px', borderRadius: '24px', fontSize: '15px', outline: 'none' }} />
); }