diff --git a/src/App.tsx b/src/App.tsx index a195a50..3dd1c09 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,5 +1,5 @@ // App shell — scene switcher + top bar + command palette + console + toaster. -import { useEffect } from "react"; +import { useEffect, useState } from "react"; import { useApp, scenarioById } from "./state/store"; import Landing from "./scenes/Landing"; import MissionControl from "./scenes/MissionControl"; @@ -76,6 +76,46 @@ export default function App() { const liveAge = liveFetchedAt ? `${Math.max(0, Math.floor((Date.now() - liveFetchedAt) / 1000))}s ago` : null; + const [chatUnread, setChatUnread] = useState(0); + const [queueCount, setQueueCount] = useState(0); + const tenantId = useApp((s) => s.tenantId); + useEffect(() => { + if (!isAuthed || !tenantId || !userEmail) return; + let cancelled = false; + const refresh = async () => { + try { + const { chatApi } = await import("./lib/chatApi"); + const { api: apiMod } = await import("./lib/api"); + const [threads, items] = await Promise.all([ + chatApi.listThreads(userEmail).catch(() => []), + apiMod.workItems().catch(() => []), + ]); + if (cancelled) return; + const readMap: Record = (() => { + try { return JSON.parse(localStorage.getItem(`fm.canvas.chat.read.${userEmail}`) || "{}"); } catch { return {}; } + })(); + let unread = 0; + for (const t of threads) { + try { + const msgs = await chatApi.listMessages(t._key); + const last = msgs[msgs.length - 1]; + if (!last) continue; + if (last.author_email === userEmail) continue; + const readAt = readMap[t._key]; + if (!readAt || last.created_at > readAt) unread++; + } catch { /* ignore */ } + } + if (!cancelled) { + setChatUnread(unread); + setQueueCount(items.filter((it) => (it as any).tenant_id === tenantId).length); + } + } catch { /* ignore */ } + }; + void refresh(); + const id = window.setInterval(refresh, 60_000); + return () => { cancelled = true; window.clearInterval(id); }; + }, [isAuthed, tenantId, userEmail]); + return (
{scene !== "landing" && scene !== "login" && scene !== "sso-callback" && ( @@ -91,6 +131,10 @@ export default function App() { + @@ -99,6 +143,7 @@ export default function App() {