import { useEffect, useRef, useState } from "react"; import { useStore } from "../store/useStore"; import { ChevronDown, PlusIcon, TrashIcon } from "./Icon"; import { relTime } from "../lib/time"; /** Sélecteur de session de la barre supérieure : titre courant + menu déroulant * (nouvelle session, liste, renommage inline, suppression). */ export function SessionMenu() { const { sessions, currentSessionId, streamingSessionId, newSession, openSession, removeSession, renameSession, } = useStore(); const [open, setOpen] = useState(false); const [editingId, setEditingId] = useState(null); const [draft, setDraft] = useState(""); const rootRef = useRef(null); const current = sessions.find((s) => s.id === currentSessionId); // Fermeture au clic extérieur + Escape. useEffect(() => { if (!open) return; const onDown = (e: MouseEvent) => { if (rootRef.current && !rootRef.current.contains(e.target as Node)) { setOpen(false); setEditingId(null); } }; const onKey = (e: KeyboardEvent) => { if (e.key === "Escape") { setOpen(false); setEditingId(null); } }; document.addEventListener("mousedown", onDown); document.addEventListener("keydown", onKey); return () => { document.removeEventListener("mousedown", onDown); document.removeEventListener("keydown", onKey); }; }, [open]); const commitRename = async (id: string) => { const title = draft.trim(); setEditingId(null); if (title) await renameSession(id, title); }; return (
{open && (
{sessions.length === 0 && (
Aucune session enregistrée.
)} {sessions.map((s) => { const active = s.id === currentSessionId; const working = s.id === streamingSessionId; return (
{ if (editingId === s.id) return; setOpen(false); void openSession(s.id); }} className={`group cursor-pointer border-b-2 border-chrome-3 px-3 py-2 last:border-b-0 ${ active ? "bg-chrome-3" : "hover:bg-chrome-3" }`} >
{editingId === s.id ? ( setDraft(e.target.value)} onClick={(e) => e.stopPropagation()} onKeyDown={(e) => { if (e.key === "Enter") void commitRename(s.id); if (e.key === "Escape") { e.stopPropagation(); setEditingId(null); } }} onBlur={() => setEditingId(null)} className="min-w-0 flex-1 border-2 border-line bg-card-deep px-1.5 py-0.5 text-[13px] text-white outline-none" /> ) : ( {s.title} )} {working && ( EN COURS )}
{relTime(s.updated_at)} · {s.message_count ?? 0} message {(s.message_count ?? 0) > 1 ? "s" : ""}
); })}
)}
); }