155 lines
4.0 KiB
TypeScript
155 lines
4.0 KiB
TypeScript
import { Toast, ToastContainer, ToastType } from '@/component/ui/toast'
|
|
import {
|
|
createContext,
|
|
FC,
|
|
PropsWithChildren,
|
|
useCallback,
|
|
useContext,
|
|
useState,
|
|
} from 'react'
|
|
|
|
interface ToastContextType {
|
|
showToast: (
|
|
message: string,
|
|
type?: ToastType,
|
|
options?: { title?: string; duration?: number }
|
|
) => void
|
|
removeToast: (id: string) => void
|
|
// Методы для быстрого доступа к разным типам уведомлений
|
|
success: (
|
|
message: string,
|
|
options?: { title?: string; duration?: number }
|
|
) => void
|
|
error: (
|
|
message: string,
|
|
options?: { title?: string; duration?: number }
|
|
) => void
|
|
warning: (
|
|
message: string,
|
|
options?: { title?: string; duration?: number }
|
|
) => void
|
|
info: (
|
|
message: string,
|
|
options?: { title?: string; duration?: number }
|
|
) => void
|
|
}
|
|
|
|
const ToastContext = createContext<ToastContextType | null>(null)
|
|
|
|
export const ToastProvider: FC<PropsWithChildren> = ({ children }) => {
|
|
const [toasts, setToasts] = useState<Toast[]>([])
|
|
|
|
const showToast = useCallback(
|
|
(
|
|
message: string,
|
|
type: ToastType = 'info',
|
|
options: { title?: string; duration?: number } = {}
|
|
) => {
|
|
const id = Math.random().toString(36).substr(2, 9)
|
|
const newToast: Toast = {
|
|
id,
|
|
message,
|
|
type,
|
|
title: options.title,
|
|
duration: options.duration,
|
|
}
|
|
|
|
setToasts(prev => [...prev, newToast])
|
|
},
|
|
[]
|
|
)
|
|
|
|
const removeToast = useCallback((id: string) => {
|
|
setToasts(prev => prev.filter(toast => toast.id !== id))
|
|
}, [])
|
|
|
|
// Методы для быстрого доступа
|
|
const success = useCallback(
|
|
(message: string, options?: { title?: string; duration?: number }) => {
|
|
showToast(message, 'success', options)
|
|
},
|
|
[showToast]
|
|
)
|
|
|
|
const error = useCallback(
|
|
(message: string, options?: { title?: string; duration?: number }) => {
|
|
showToast(message, 'error', options)
|
|
},
|
|
[showToast]
|
|
)
|
|
|
|
const warning = useCallback(
|
|
(message: string, options?: { title?: string; duration?: number }) => {
|
|
showToast(message, 'warning', options)
|
|
},
|
|
[showToast]
|
|
)
|
|
|
|
const info = useCallback(
|
|
(message: string, options?: { title?: string; duration?: number }) => {
|
|
showToast(message, 'info', options)
|
|
},
|
|
[showToast]
|
|
)
|
|
|
|
const value: ToastContextType = {
|
|
showToast,
|
|
removeToast,
|
|
success,
|
|
error,
|
|
warning,
|
|
info,
|
|
}
|
|
|
|
return (
|
|
<ToastContext.Provider value={value}>
|
|
{children}
|
|
<ToastContainer toasts={toasts} onRemove={removeToast} />
|
|
</ToastContext.Provider>
|
|
)
|
|
}
|
|
|
|
export const useToast = (): ToastContextType => {
|
|
const context = useContext(ToastContext)
|
|
if (!context) {
|
|
throw new Error('useToast must be used within a ToastProvider')
|
|
}
|
|
return context
|
|
}
|
|
|
|
// Глобальное переопределение alert
|
|
let globalToastContext: ToastContextType | null = null
|
|
|
|
export const setGlobalToastContext = (context: ToastContextType) => {
|
|
globalToastContext = context
|
|
}
|
|
|
|
// Переопределяем глобальный alert
|
|
if (typeof window !== 'undefined') {
|
|
const originalAlert = window.alert
|
|
window.alert = (message: string) => {
|
|
if (globalToastContext) {
|
|
// Определяем тип уведомления по содержанию сообщения
|
|
const lowerMessage = message.toLowerCase()
|
|
if (lowerMessage.includes('ошибка') || lowerMessage.includes('error')) {
|
|
globalToastContext.error(message)
|
|
} else if (
|
|
lowerMessage.includes('сохранен') ||
|
|
lowerMessage.includes('успешно')
|
|
) {
|
|
globalToastContext.success(message)
|
|
} else if (
|
|
lowerMessage.includes('предупреждение') ||
|
|
lowerMessage.includes('warning')
|
|
) {
|
|
globalToastContext.warning(message)
|
|
} else {
|
|
globalToastContext.info(message)
|
|
}
|
|
} else {
|
|
// Fallback на обычный alert, если контекст недоступен
|
|
originalAlert(message)
|
|
}
|
|
}
|
|
}
|