Files
playX/src/features/notifications/store.ts
2026-04-10 17:29:49 +08:00

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')
}