File size: 2,503 Bytes
ace186a
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
import { useEffect, useRef, useState } from 'react'
const API=(p:string)=>'/api'+p
type Msg={role:'user'|'assistant',content:string}
export default function ChatBox(){const [messages,setMessages]=useState<Msg[]>([]);const [text,setText]=useState('');const [mode,setMode]=useState<'file'|'mic'|'video'>('file');const pressTimer=useRef<number|undefined>(undefined);const feedRef=useRef<HTMLDivElement>(null);const token=localStorage.getItem('token')||'';const headers={'Content-Type':'application/json','Authorization':'Bearer '+token};useEffect(()=>{fetch(API('/chat/history'),{headers}).then(r=>r.json()).then((data)=>{setMessages(data.map((m:any)=>({role:m.role,content:m.content})))})},[]);useEffect(()=>{feedRef.current?.scrollTo({top:feedRef.current.scrollHeight})},[messages]);const send=async()=>{if(!text.trim()) return; setMessages(m=>[...m,{role:'user',content:text}]); setText(''); const r=await fetch(API('/chat'),{method:'POST',headers,body:JSON.stringify({message:text})}); const data=await r.json(); setMessages(m=>[...m,{role:'assistant',content:data.reply}])}
const cycle=()=>setMode(m=> m==='file'?'mic': m==='mic'?'video':'file')
const onMouseDown=()=>{pressTimer.current=window.setTimeout(cycle,450)}
const onMouseUp=()=>{if(pressTimer.current){clearTimeout(pressTimer.current); pressTimer.current=undefined}}
return (<div className="flex flex-col h-full"><div ref={feedRef} className="flex-1 overflow-y-auto p-3 border border-slate-800 rounded-xl bg-slate-900/40 space-y-2">{messages.map((m,i)=>(<div key={i} className={`max-w-[70%] px-3 py-2 rounded-2xl ${m.role==='user'?'self-end bg-blue-600 text-white rounded-br-sm':'self-start bg-slate-800 border border-slate-700 rounded-bl-sm'}`}>{m.content}</div>))}</div><div className="grid grid-cols-[44px_1fr_60px] gap-2 mt-2 items-center"><button onMouseDown={onMouseDown} onMouseUp={onMouseUp} onTouchStart={onMouseDown} onTouchEnd={onMouseUp} onClick={()=>{if(mode==='file'){alert('Upload placeholder')}else if(mode==='mic'){alert('Record audio placeholder')}else{alert('Record video placeholder')}}} className="w-11 h-11 rounded-full border border-slate-700 bg-slate-800">{mode==='file'?'πŸ“Ž':mode==='mic'?'🎀':'πŸ“Ή'}</button><input value={text} onChange={e=>setText((e.target as any).value)} placeholder="Type a message" className="px-3 py-2 rounded-xl border border-slate-700 bg-slate-800 outline-none"/><button onClick={send} className="px-3 py-2 rounded-xl bg-sky-400 text-slate-900 font-semibold">Send</button></div></div>)}