Files
Inventory/frontend/app/composables/useToast.ts
Matthieu 27d51ffdb1 fix(toasts) : auto-dismiss des notifications d'erreur apres 8 secondes
Les toasts d'erreur etaient persistants (duration force a 0) et restaient
affiches jusqu'a fermeture manuelle, ce qui pouvait empiler des messages
obsoletes a l'ecran. Aligne le comportement sur les autres types : duree
par defaut 8s (plus que warning a 6s pour laisser le temps de lire). Une
erreur critique peut toujours etre rendue persistante en passant
explicitement showError(msg, 0).
2026-05-06 16:51:08 +02:00

96 lines
2.1 KiB
TypeScript

import { ref } from 'vue'
export type ToastType = 'success' | 'error' | 'warning' | 'info'
export interface Toast {
id: number
message: string
type: ToastType
visible: boolean
duration: number
}
const toasts = ref<Toast[]>([])
const MAX_TOASTS = 3
let nextId = 1
// Anti-doublon : ignore un toast identique affiché dans les 2 dernières secondes
const recentMessages = new Map<string, number>()
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,
duration,
}
if (toasts.value.length >= MAX_TOASTS) {
toasts.value.shift()
}
toasts.value.push(toast)
if (duration > 0) {
setTimeout(() => {
removeToast(id)
}, duration)
}
return id
}
const showSuccess = (message: string, duration = 5000): number => {
return showToast(message, 'success', duration)
}
const showError = (message: string, duration = 8000): 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,
}
}