import { create } from 'zustand' /** * Tracks live connection state. * * status: * 'online' — server reachable, SSE connected, normal operation * 'reconnecting' — blip detected, grace period (amber bar) * 'offline' — confirmed unreachable, working from local DB (red bar) * * The old 'emergency' and 'lost' states are gone. The app now enters offline * mode automatically — no user prompt needed. * * After 5 minutes offline the bar flashes to signal a serious problem. */ const GRACE_MS = 4_000 // how long to wait before declaring offline const FLASH_MS = 5 * 60 * 1000 // 5 minutes before bar starts flashing const useConnectionStore = create((set, get) => ({ status: 'online', // 'online' | 'reconnecting' | 'offline' sseAlive: false, // true when SSE stream is actively connected lostAt: null, // Date when connection was first lost flashing: false, // true when offline > 5 min _graceTimer: null, _flashTimer: null, setSseAlive: (alive) => set({ sseAlive: alive }), setLost: () => { const { status, _graceTimer } = get() if (status === 'offline') return if (status === 'reconnecting') return const graceTimer = setTimeout(() => { if (get().status !== 'reconnecting') return const lostAt = get().lostAt // Start the 5-min flash timer const flashTimer = setTimeout(() => { if (get().status === 'offline') set({ flashing: true }) }, FLASH_MS) set({ status: 'offline', _graceTimer: null, _flashTimer: flashTimer }) }, GRACE_MS) set({ status: 'reconnecting', lostAt: new Date(), _graceTimer: graceTimer }) }, setOnline: () => { const { _graceTimer, _flashTimer } = get() if (_graceTimer) clearTimeout(_graceTimer) if (_flashTimer) clearTimeout(_flashTimer) set({ status: 'online', lostAt: null, flashing: false, _graceTimer: null, _flashTimer: null }) }, // Convenience accessors isOnline: () => get().status === 'online', isOffline: () => get().status === 'offline' || get().status === 'reconnecting', // Legacy compat — SSEContext still calls these enterEmergency: () => { // treated as manual offline entry (immediate, no grace period) const { _graceTimer, _flashTimer } = get() if (_graceTimer) clearTimeout(_graceTimer) if (_flashTimer) clearTimeout(_flashTimer) const flashTimer = setTimeout(() => { if (get().status === 'offline') set({ flashing: true }) }, FLASH_MS) set({ status: 'offline', lostAt: new Date(), flashing: false, _graceTimer: null, _flashTimer: flashTimer }) }, exitEmergency: () => get().setOnline(), isEmergency: () => get().status === 'offline', isLost: () => get().status === 'offline', })) export default useConnectionStore