import { useEffect, useRef, useState } from 'react'; import { Link, useParams } from 'react-router-dom'; import { ChevronLeft } from 'lucide-react'; import { toast } from 'sonner'; import { api } from '@/api/client'; import type { Session as SessionType } from '@/api/types'; import { useSessionStream } from '@/hooks/useSessionStream'; import { sessionEvents } from '@/hooks/sessionEvents'; import { MessageList } from '@/components/MessageList'; import { ChatInput } from '@/components/ChatInput'; import { ModelPicker } from '@/components/ModelPicker'; export function Session() { const { id } = useParams<{ id: string }>(); const stream = useSessionStream(id); const [session, setSession] = useState(null); const [name, setName] = useState(''); const [editingName, setEditingName] = useState(false); const lastErrorRef = useRef(null); useEffect(() => { if (stream.error && stream.error !== lastErrorRef.current) { lastErrorRef.current = stream.error; toast.error(stream.error); } if (!stream.error) { lastErrorRef.current = null; } }, [stream.error]); useEffect(() => { if (!id) return; setSession(null); api.sessions .get(id) .then((s) => { setSession(s); setName(s.name); }) .catch(() => {}); }, [id]); useEffect(() => { if (!id) return; return sessionEvents.subscribe((event) => { if (event.type !== 'session_renamed') return; if (event.session_id !== id) return; setSession((prev) => (prev ? { ...prev, name: event.name } : prev)); setName((prev) => (editingName ? prev : event.name)); }); }, [id, editingName]); async function saveName() { if (!id || !session) return; const trimmed = name.trim(); if (!trimmed || trimmed === session.name) { setName(session.name); setEditingName(false); return; } const updated = await api.sessions.update(id, { name: trimmed }); setSession(updated); sessionEvents.emit({ type: 'session_renamed', session_id: id, name: trimmed, }); setEditingName(false); } async function handleSend(content: string) { if (!id) return; await api.messages.send(id, content); } const streaming = stream.messages.some((m) => m.status === 'streaming'); return (
{session && ( )} {editingName ? ( setName(e.target.value)} onBlur={() => void saveName()} onKeyDown={(e) => { if (e.key === 'Enter') void saveName(); if (e.key === 'Escape') { setName(session?.name ?? ''); setEditingName(false); } }} className="bg-transparent border-b border-border px-1 py-0.5 text-sm font-medium outline-none focus:border-ring" /> ) : ( )}
{session && ( { const updated = await api.sessions.update(session.id, { model }); setSession(updated); }} /> )}
{!stream.connected && ( reconnecting… )}
{id && }
); }