websync / components /chat /ChatPanel.tsx
Shivam
Committing all changes
987282d
"use client"
import { FC, useEffect, useRef, useState } from "react"
import { Socket } from "socket.io-client"
import { ClientToServerEvents, ServerToClientEvents } from "../../lib/socket"
type ChatMessage = {
id: string
userId: string
name: string
text: string
ts: number
}
interface Props {
socket: Socket<ServerToClientEvents, ClientToServerEvents>
className?: string
}
const ChatPanel: FC<Props> = ({ socket, className }) => {
const [messages, _setMessages] = useState<ChatMessage[]>([])
const [text, setText] = useState("")
const messagesRef = useRef(messages)
const setMessages = (m: ChatMessage[]) => {
messagesRef.current = m
_setMessages(m)
}
useEffect(() => {
const onHistory = (history: ChatMessage[]) => {
setMessages(history)
}
const onNew = (msg: ChatMessage) => {
setMessages([...messagesRef.current, msg].slice(-200))
}
socket.on("chatHistory", onHistory)
socket.on("chatNew", onNew)
return () => {
socket.off("chatHistory", onHistory)
socket.off("chatNew", onNew)
}
}, [socket])
const send = () => {
const trimmed = text.trim()
if (!trimmed) return
socket.emit("chatMessage", trimmed)
setText("")
}
return (
<div className={className ?? "flex flex-col h-64 border rounded-md"}>
<div className="flex-1 overflow-y-auto p-2 space-y-2 bg-neutral-900/30">
{messages.map((m) => (
<div key={m.id} className="text-sm">
<span className="font-semibold">{m.name}</span>
<span className="opacity-60"> • {new Date(m.ts).toLocaleTimeString()}</span>
<div className="break-words">{m.text}</div>
</div>
))}
{messages.length === 0 && <div className="opacity-60 text-sm">No messages yet</div>}
</div>
<div className="p-2 flex gap-2">
<input
className="input flex-1 bg-neutral-800 p-2 rounded-md outline-none"
placeholder="Type a message…"
value={text}
onChange={(e) => setText(e.target.value)}
onKeyDown={(e) => {
if (e.key === "Enter") send()
}}
/>
<button className="btn bg-primary-700 hover:bg-primary-600 px-3 rounded-md" onClick={send}>
Send
</button>
</div>
</div>
)
}
export default ChatPanel