Files
udyamlinc/src/lib/alertStore.ts
T
LincPayandClaude Opus 5 f430f85202 chore: initial commit — UdyamLinc UI, phases A-E
Vite/React 19 console and enterprise PWA. Officer console screens, offline
ledger and sync, data feeds and trip-wire rules screens with freshness chip.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-06 13:30:24 +05:30

71 lines
2.2 KiB
TypeScript

import { useCallback, useEffect, useState } from 'react'
import type { AlertState, RiskAlert } from './api'
import { alertsFor } from './demo/ops'
/*
* Officer actions on the alert queue.
*
* The queue itself is derived from the portfolio; only the state changes an
* officer makes (acknowledge / escalate / snooze / close) and their audit trail
* are persisted, which is exactly the split the deck describes — the model
* proposes, the officer disposes, and every disposal is auditable.
*/
const KEY = 'ul-alert-states'
const AUDIT_KEY = 'ul-alert-audit'
export interface AuditEntry {
alertId: string
from: AlertState
to: AlertState
actor: string
note: string | null
at: string
}
function readStates(): Record<string, AlertState> {
try {
return JSON.parse(localStorage.getItem(KEY) ?? '{}') as Record<string, AlertState>
} catch {
return {}
}
}
export function readAudit(): AuditEntry[] {
try {
return JSON.parse(localStorage.getItem(AUDIT_KEY) ?? '[]') as AuditEntry[]
} catch {
return []
}
}
export function setAlertState(alert: RiskAlert, to: AlertState, actor: string, note?: string) {
const states = readStates()
const from = states[alert.alertId] ?? alert.state
states[alert.alertId] = to
localStorage.setItem(KEY, JSON.stringify(states))
const audit: AuditEntry = { alertId: alert.alertId, from, to, actor, note: note ?? null, at: new Date().toISOString() }
localStorage.setItem(AUDIT_KEY, JSON.stringify([audit, ...readAudit()].slice(0, 200)))
window.dispatchEvent(new Event('ul-alerts-changed'))
}
/** The alert queue for a block, with any officer actions applied on top. */
export function useAlerts(block: string) {
const [version, setVersion] = useState(0)
const bump = useCallback(() => setVersion((v) => v + 1), [])
useEffect(() => {
window.addEventListener('ul-alerts-changed', bump)
return () => window.removeEventListener('ul-alerts-changed', bump)
}, [bump])
const states = readStates()
// `version` is read so the memo-free derivation re-runs after every action.
void version
const alerts = alertsFor(block).map((a) => ({ ...a, state: states[a.alertId] ?? a.state }))
return { alerts, audit: readAudit() }
}