diff --git a/components/AtlasChat.tsx b/components/AtlasChat.tsx index 8154fc9..a4f9af9 100644 --- a/components/AtlasChat.tsx +++ b/components/AtlasChat.tsx @@ -147,34 +147,50 @@ export function AtlasChat({ projectId }: AtlasChatProps) { } }, [projectId]); - // On mount: load stored history; if empty, trigger Atlas greeting + // On mount: load stored history; if empty, trigger Atlas greeting exactly once useEffect(() => { - if (historyLoaded) return; + let cancelled = false; // guard against unmount during fetch fetch(`/api/projects/${projectId}/atlas-chat`) .then(r => r.json()) .then((data: { messages: ChatMessage[] }) => { + if (cancelled) return; const stored = data.messages ?? []; setMessages(stored); setHistoryLoaded(true); - // Only trigger greeting if there's genuinely no history yet + // Only greet if there is genuinely no history and we haven't triggered yet if (stored.length === 0 && !initTriggered.current) { initTriggered.current = true; sendToAtlas("__atlas_init__", true); } }) .catch(() => { + if (cancelled) return; setHistoryLoaded(true); - // If we can't load, still try to greet on first open - if (!initTriggered.current) { - initTriggered.current = true; - sendToAtlas("__atlas_init__", true); - } }); + + return () => { cancelled = true; }; // eslint-disable-next-line react-hooks/exhaustive-deps }, [projectId]); + const handleReset = async () => { + if (!confirm("Clear this conversation and start fresh?")) return; + try { + await fetch(`/api/projects/${projectId}/atlas-chat`, { method: "DELETE" }); + setMessages([]); + setHistoryLoaded(false); + initTriggered.current = false; + // Trigger fresh greeting + setTimeout(() => { + initTriggered.current = true; + sendToAtlas("__atlas_init__", true); + }, 100); + } catch { + // swallow + } + }; + const handleSend = () => { const text = input.trim(); if (!text || isStreaming) return; @@ -226,7 +242,22 @@ export function AtlasChat({ projectId }: AtlasChatProps) { {/* Messages */} {!isEmpty && ( -