brf/client/admin/contexts/notifications.tsx
2025-12-18 07:31:37 +01:00

93 lines
2.3 KiB
TypeScript

// @ts-nocheck
import { h, createContext, type FunctionComponent } from 'preact'
import { useContext, useReducer } from 'preact/hooks'
type MessageType = 'error' | 'info' | 'success'
type Payload = {
id: number
message: string
type: MessageType
dismiss?: () => void
}
type Action = {
type: typeof NOTIFY | typeof DISMISS
payload: Payload
}
const NotificationsContext = createContext<{
notifications: ANY[]
notify: ((message: string, type?: MessageType, timeout?: number) => void) & {
error: (message: string, timeout?: number) => void
info: (message: string, timeout?: number) => void
success: (message: string, timeout?: number) => void
}
}>()
const NOTIFY = 'notify'
export const notifyAction = (message: string, type: MessageType): Action => ({
type: NOTIFY,
payload: {
id: counter++,
message,
type,
},
})
const DISMISS = 'dismiss'
export const dismissAction = (id: number) => ({
type: DISMISS,
id,
})
let counter = 0
export const reducer = (state: Payload[], action: Action) => {
switch (action.type) {
case NOTIFY:
return state.concat(action.payload)
case DISMISS: {
const index = state.findIndex((notification) => notification.id === action.id)
if (index > -1) {
return [...state.slice(0, index), ...state.slice(index + 1)]
}
return state
}
default:
return state
}
}
export const useNotifications = () => useContext(NotificationsContext)
export const NotificationsProvider: FunctionComponent<{ defaultTimeout?: number }> = ({
children,
defaultTimeout = 0,
}) => {
const [notifications, dispatch] = useReducer(reducer, [])
function notify(message: string, type: MessageType = 'info', timeout = defaultTimeout) {
const action = notifyAction(message, type)
const dismiss = (action.payload.dismiss = () => dispatch(dismissAction(action.payload.id)))
dispatch(action)
if (timeout) {
setTimeout(dismiss, timeout)
}
return dismiss
}
notify.error = (message: string, timeout?: number) => notify(message, 'error', timeout)
notify.success = (message: string, timeout?: number) => notify(message, 'success', timeout)
notify.info = (message: string, timeout?: number) => notify(message, 'info', timeout)
return <NotificationsContext.Provider value={{ notifications, notify }}>{children}</NotificationsContext.Provider>
}