import { ref } from 'vue' export type ToastType = 'success' | 'error' | 'warning' | 'info' export interface Toast { id: number message: string type: ToastType visible: boolean } const toasts = ref([]) const MAX_TOASTS = 3 let nextId = 1 // Anti-doublon : ignore un toast identique affiché dans les 2 dernières secondes const recentMessages = new Map() const DEDUP_WINDOW = 2000 export function useToast() { const showToast = (message: string, type: ToastType = 'info', duration = 3500): number => { const dedupKey = `${type}::${message}` const lastShown = recentMessages.get(dedupKey) if (lastShown && Date.now() - lastShown < DEDUP_WINDOW) { return -1 } recentMessages.set(dedupKey, Date.now()) const id = nextId++ const toast: Toast = { id, message, type, visible: true, } if (toasts.value.length >= MAX_TOASTS) { toasts.value.shift() } toasts.value.push(toast) // Auto-remove after duration setTimeout(() => { removeToast(id) }, duration) return id } const showSuccess = (message: string, duration = 5000): number => { return showToast(message, 'success', duration) } const showError = (message: string, duration = 5000): number => { return showToast(message, 'error', duration) } const showWarning = (message: string, duration = 6000): number => { return showToast(message, 'warning', duration) } const showInfo = (message: string, duration = 5000): number => { return showToast(message, 'info', duration) } const removeToast = (id: number): void => { const index = toasts.value.findIndex((toast) => toast.id === id) if (index !== -1 && toasts.value[index]) { toasts.value[index].visible = false setTimeout(() => { toasts.value.splice(index, 1) }, 300) // Animation duration } } const clearAll = (): void => { toasts.value = [] recentMessages.clear() } return { toasts, showToast, showSuccess, showError, showWarning, showInfo, removeToast, clearAll, } }