diff --git a/frontend/components/chat/chat-panel.tsx b/frontend/components/chat/chat-panel.tsx index 463b1fd..46ff655 100644 --- a/frontend/components/chat/chat-panel.tsx +++ b/frontend/components/chat/chat-panel.tsx @@ -2,7 +2,7 @@ import { useChat } from "@ai-sdk/react"; import { DefaultChatTransport } from "ai"; -import { AlertTriangle, ShieldCheck } from "lucide-react"; +import { AlertTriangle, ShieldCheck, X } from "lucide-react"; import { nanoid } from "nanoid"; import { useSearchParams } from "next/navigation"; import { useCallback, useEffect, useMemo, useRef, useState } from "react"; @@ -47,7 +47,6 @@ import type { TemetroUIMessage } from "@/lib/ai-chat"; import { getAiConfig } from "@/lib/ai-settings"; import { API_BASE_URL } from "@/lib/api-client"; import { getPatient } from "@/lib/patients"; -import { notify } from "@/lib/toast"; // Trigger: `/patient 10293` or just `/10293` — a client-side fast-path that // pulls records instantly without the LLM (also works offline). @@ -96,12 +95,13 @@ export function ChatPanel() { }; }, []); - // Pop a toast whenever a request errors, so failures are never silent. + // Surface errors inline (and dismissible) instead of as a toast, so a failure + // stays visible until acknowledged and isn't duplicated. Reset the dismissed + // flag whenever a fresh error arrives. + const [errorDismissed, setErrorDismissed] = useState(false); useEffect(() => { - if (error) { - notify.error(t("chat.error.title"), error.message || t("chat.error.body")); - } - }, [error, t]); + if (error) setErrorDismissed(false); + }, [error]); const isCloudModel = (getModel(model)?.provider ?? "ollama") !== "ollama"; @@ -210,20 +210,29 @@ export function ChatPanel() { /> ) : null; - const errorAlert = error ? ( -
- -
-

{t("chat.error.title")}

-

- {error.message || t("chat.error.body")} -

+ const errorAlert = + error && !errorDismissed ? ( +
+ +
+

{t("chat.error.title")}

+

+ {error.message || t("chat.error.body")} +

+
+
-
- ) : null; + ) : null; // Render one assistant/user message: a Chain-of-Thought trace built from any // `data-step` parts, then the rest of the parts (text + record cards) in order. diff --git a/frontend/components/chat/import-preview-card.tsx b/frontend/components/chat/import-preview-card.tsx index 63512d0..a924344 100644 --- a/frontend/components/chat/import-preview-card.tsx +++ b/frontend/components/chat/import-preview-card.tsx @@ -67,13 +67,19 @@ export function ImportPreviewCard({ data }: { data: ImportPreviewData }) {
{data.invalid.length > 0 ? ( -