import { useEffect, useSyncExternalStore } from "react" import { ago } from "@/components/Health/queries" import { connectionStore } from "@/lib/connectionStore" import { dismiss, notify } from "@/lib/notificationStore" import { isPortal } from "@/lib/portal" /** One card, replaced in place, rather than one per poll that confirms it. */ const ID = "connection-offline" /** * Says when the instance cannot be reached, and when it was last heard * from. * * Only ever meaningful under a portal: a local install cannot lose contact with * itself. The screen underneath keeps its last data rather than blanking — * stale readings with a timestamp are more use than an empty page, which is why * this leads with when we last heard anything. * * Draws nothing of its own: it raises a persistent notification and takes it * back when the tunnel returns, so being offline is said in the same place as * everything else the app has to say. Still a component rather than a * subscription inside the store, because it is what scopes the notice to the * shell — a wall panel or a kiosk has nobody to read it. */ export function ConnectionNotice() { const connection = useSyncExternalStore( connectionStore.subscribe, connectionStore.snapshot, connectionStore.snapshot, ) const portal = isPortal() useEffect(() => { if (!portal) return if (!connection.offline) { dismiss(ID) return } notify( connection.lastSeen ? `Instance offline — last seen ${ago(connection.lastSeen / 1000)}, reconnecting…` : "Instance offline — reconnecting…", "warning", { id: ID, persistent: true }, ) }, [portal, connection]) return null }