111 lines
2.7 KiB
TypeScript
111 lines
2.7 KiB
TypeScript
import {create} from 'zustand'
|
|
|
|
export type ToastType = 'success' | 'error'
|
|
|
|
type ToastState = {
|
|
message: string
|
|
type: ToastType
|
|
visible: boolean
|
|
}
|
|
|
|
type ToastStore = {
|
|
toast: ToastState | null
|
|
showToast: (message: string, type?: ToastType) => void
|
|
clearToast: () => void
|
|
}
|
|
|
|
let toastTimer: ReturnType<typeof setTimeout> | null = null
|
|
let toastRemoveTimer: ReturnType<typeof setTimeout> | null = null
|
|
|
|
export function resolveToastMessage(source: unknown, fallback = '') {
|
|
if (typeof source === 'string' && source.trim()) {
|
|
return source.trim()
|
|
}
|
|
|
|
if (typeof source === 'object' && source !== null && 'msg' in source) {
|
|
const message = (source as {msg?: unknown}).msg
|
|
if (typeof message === 'string' && message.trim()) {
|
|
return message.trim()
|
|
}
|
|
}
|
|
|
|
return fallback.trim()
|
|
}
|
|
|
|
export const useToastStore = create<ToastStore>((set) => ({
|
|
toast: null,
|
|
showToast: (message, type = 'success') => {
|
|
if (toastTimer) {
|
|
clearTimeout(toastTimer)
|
|
}
|
|
if (toastRemoveTimer) {
|
|
clearTimeout(toastRemoveTimer)
|
|
}
|
|
|
|
set({
|
|
toast: {
|
|
message,
|
|
type,
|
|
visible: false,
|
|
},
|
|
})
|
|
|
|
requestAnimationFrame(() => {
|
|
set((state) => state.toast
|
|
? {
|
|
toast: {
|
|
...state.toast,
|
|
visible: true,
|
|
},
|
|
}
|
|
: state)
|
|
})
|
|
|
|
toastTimer = setTimeout(() => {
|
|
set((state) => state.toast
|
|
? {
|
|
toast: {
|
|
...state.toast,
|
|
visible: false,
|
|
},
|
|
}
|
|
: state)
|
|
toastTimer = null
|
|
|
|
toastRemoveTimer = setTimeout(() => {
|
|
set({toast: null})
|
|
toastRemoveTimer = null
|
|
}, 220)
|
|
}, 2000)
|
|
},
|
|
clearToast: () => {
|
|
if (toastTimer) {
|
|
clearTimeout(toastTimer)
|
|
toastTimer = null
|
|
}
|
|
if (toastRemoveTimer) {
|
|
clearTimeout(toastRemoveTimer)
|
|
toastRemoveTimer = null
|
|
}
|
|
set({toast: null})
|
|
},
|
|
}))
|
|
|
|
export function notifySuccess(source: unknown, fallback = '') {
|
|
const message = resolveToastMessage(source, fallback)
|
|
if (!message) {
|
|
return
|
|
}
|
|
|
|
useToastStore.getState().showToast(message, 'success')
|
|
}
|
|
|
|
export function notifyError(source: unknown, fallback = '') {
|
|
const message = resolveToastMessage(source, fallback)
|
|
if (!message) {
|
|
return
|
|
}
|
|
|
|
useToastStore.getState().showToast(message, 'error')
|
|
}
|