93 lines
2.3 KiB
TypeScript
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>
|
|
}
|