Files
codeg/src/contexts/alert-context.tsx
2026-03-06 22:56:13 +08:00

111 lines
2.3 KiB
TypeScript

"use client"
import {
createContext,
useCallback,
useContext,
useMemo,
useReducer,
type ReactNode,
} from "react"
import type { FixActionKind } from "@/lib/types"
export type AlertLevel = "error" | "warning"
export interface AlertAction {
label: string
kind: FixActionKind
payload: string
}
export interface Alert {
id: string
level: AlertLevel
message: string
detail?: string
actions?: AlertAction[]
timestamp: number
}
interface AlertContextValue {
alerts: Alert[]
hasAlerts: boolean
pushAlert: (
level: AlertLevel,
message: string,
detail?: string,
actions?: AlertAction[]
) => string
dismissAlert: (id: string) => void
clearAll: () => void
}
type Action =
| { type: "push"; alert: Alert }
| { type: "dismiss"; id: string }
| { type: "clear_all" }
let seq = 0
const MAX_ALERTS = 50
function reducer(state: Alert[], action: Action): Alert[] {
switch (action.type) {
case "push": {
const next = [...state, action.alert]
return next.length > MAX_ALERTS ? next.slice(-MAX_ALERTS) : next
}
case "dismiss":
return state.filter((a) => a.id !== action.id)
case "clear_all":
return []
}
}
const AlertContext = createContext<AlertContextValue | null>(null)
export function useAlertContext() {
const ctx = useContext(AlertContext)
if (!ctx) {
throw new Error("useAlertContext must be used within AlertProvider")
}
return ctx
}
export function AlertProvider({ children }: { children: ReactNode }) {
const [alerts, dispatch] = useReducer(reducer, [])
const pushAlert = useCallback(
(
level: AlertLevel,
message: string,
detail?: string,
actions?: AlertAction[]
) => {
const id = `alert-${++seq}-${Date.now()}`
dispatch({
type: "push",
alert: { id, level, message, detail, actions, timestamp: Date.now() },
})
return id
},
[]
)
const dismissAlert = useCallback((id: string) => {
dispatch({ type: "dismiss", id })
}, [])
const clearAll = useCallback(() => {
dispatch({ type: "clear_all" })
}, [])
const hasAlerts = alerts.length > 0
const value = useMemo(
() => ({ alerts, hasAlerts, pushAlert, dismissAlert, clearAll }),
[alerts, hasAlerts, pushAlert, dismissAlert, clearAll]
)
return <AlertContext.Provider value={value}>{children}</AlertContext.Provider>
}