import { useEffect, useRef } from "react"; import { dismissMapNotice, showMapNotice } from "@/features/map/core"; import type { WorkbenchAlert } from "../types"; import { useScadaEventAtmosphere, type ScadaEventTask } from "./use-scada-event-atmosphere"; export type { ScadaAlertAtmosphereState } from "./use-scada-event-atmosphere"; /** Announce newly persisted alerts, including while the peripheral panel is closed. */ export function useScadaAlertNotices( projectId: string | null, alerts: WorkbenchAlert[] | null, onOpen: (alert: WorkbenchAlert) => void, tasks: readonly ScadaEventTask[] | null = null ) { const atmosphere = useScadaEventAtmosphere(projectId, alerts, tasks); const openRef = useRef(onOpen); openRef.current = onOpen; const state = useRef<{ initialized: boolean; seen: Set; visible: Set; linked: Set }>({ initialized: false, seen: new Set(), visible: new Set(), linked: new Set() }); useEffect(() => { const current = { initialized: false, seen: new Set(), visible: new Set(), linked: new Set() }; state.current = current; return () => { current.visible.forEach((id) => dismissMapNotice(id)); }; }, [projectId]); useEffect(() => { if (!alerts) return; const current = state.current; const incoming = alerts.filter((alert) => alert.source && "kind" in alert.source && alert.source.kind === "scada_replay"); const noticeId = (id: string) => `scada-alert:${projectId}:${id}`; const activeIds = new Set(incoming.map((alert) => noticeId(alert.id))); for (const id of current.visible) { if (!activeIds.has(id) && !current.linked.has(id)) { dismissMapNotice(id); current.visible.delete(id); } } for (const alert of incoming) { if (current.seen.has(alert.id)) continue; current.seen.add(alert.id); // Opening a project restores its notification center without replaying old popups. if (!current.initialized) continue; const id = noticeId(alert.id); current.visible.add(id); if (alert.conditionId) current.linked.add(id); showMapNotice({ id, title: alert.title, message: alert.description, tone: alert.severity === "critical" ? "error" : "warning", position: "top-center", duration: alert.conditionId ? Infinity : 10_000, actionLabel: alert.conditionId ? "查看调查" : undefined, onAction: alert.conditionId ? () => openRef.current(alert) : undefined }); } current.initialized = true; }, [alerts, projectId]); return atmosphere; }