import { useEffect, useMemo, useRef, useState } from 'react'; import { useChat } from '../context/ChatContext.jsx'; import { useSession } from '../context/SessionContext.jsx'; function roleColors(role, fromDiscord) { if (fromDiscord) return 'text-indigo-200'; switch (role) { case 'admin': case 'lockdown': case 'lockdown-admin': return 'text-amber-300'; case 'spectator': return 'text-slate-400'; default: return 'text-sky-300'; } } function formatTime(ts) { const date = new Date(ts); return `${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}`; } function displayName(message) { return message.nickname || message.socketId?.slice(0, 6) || 'unknown'; } export default function ChatPanel({ hideInput = false, hideSpectatorNotice = false, fillHeight = false }) { const { session } = useSession(); const { messages, sendMessage, registerInputRef, onInputFocus, onInputBlur, blurChat } = useChat(); const [draft, setDraft] = useState(''); const [sending, setSending] = useState(false); const canChat = session?.role !== 'spectator'; const listRef = useRef(null); const sorted = useMemo(() => messages.slice(-200), [messages]); useEffect(() => { if (!listRef.current) return; listRef.current.scrollTop = listRef.current.scrollHeight; }, [sorted]); async function handleSend(event) { event.preventDefault(); if (!canChat || hideInput) return; const clean = draft.trim(); if (!clean) return; setSending(true); try { await sendMessage(clean); setDraft(''); blurChat(); } catch (err) { alert(err.message); } finally { setSending(false); } } const listClass = fillHeight ? 'flex-1 min-h-0 overflow-y-auto' : 'h-48 overflow-y-auto'; return (
{sorted.length === 0 ? (

No messages yet.

) : ( sorted.map((msg) => { const isAdmin = msg.role === 'admin' || msg.role === 'lockdown' || msg.role === 'lockdown-admin'; return (
{formatTime(msg.ts)} {displayName(msg)} {msg.fromDiscord && ( Discord )} {msg.roverId && ( rover {msg.roverId} )} {msg.text}
); }) )}
{!hideInput && (
setDraft(e.target.value)} onFocus={onInputFocus} onBlur={onInputBlur} ref={(el) => registerInputRef(el)} placeholder={canChat ? 'Type a message…' : hideSpectatorNotice ? '' : 'Spectators cannot chat'} disabled={!canChat} />
)}
); }