import { defineStore } from "pinia"; // Global toast instance - will be set during app initialization let toastInstance = null; export const useNotificationStore = defineStore("notifications", { state: () => ({ // Configuration for PrimeVue Toast defaultLife: 4000, position: "top-right", }), getters: { // Helper to check if toast is available isToastAvailable: () => !!toastInstance, }, actions: { // Add a new notification addNotification(notification) { const newNotification = { id: this.nextId++, type: notification.type || "info", // info, success, warning, error title: notification.title || "", message: notification.message || "", duration: notification.duration ?? this.defaultDuration, persistent: notification.persistent || false, // If true, won't auto-dismiss actions: notification.actions || [], // Array of action buttons data: notification.data || null, // Any additional data timestamp: new Date().toISOString(), dismissed: false, seen: false, }; // Add to beginning of array (newest first) this.notifications.unshift(newNotification); // Trim notifications if we exceed max count if (this.notifications.length > this.maxNotifications * 2) { // Keep twice the max to maintain some history this.notifications = this.notifications.slice(0, this.maxNotifications * 2); } // Auto-dismiss if not persistent if (!newNotification.persistent && newNotification.duration > 0) { setTimeout(() => { this.dismissNotification(newNotification.id); }, newNotification.duration); } return newNotification.id; }, // Convenience methods for different types of notifications addSuccess(message, title = "Success", options = {}) { return this.addNotification({ type: "success", title, message, ...options, }); }, addError(message, title = "Error", options = {}) { return this.addNotification({ type: "error", title, message, duration: options.duration ?? 6000, // Errors stay longer by default ...options, }); }, addWarning(message, title = "Warning", options = {}) { return this.addNotification({ type: "warning", title, message, ...options, }); }, addInfo(message, title = "Info", options = {}) { return this.addNotification({ type: "info", title, message, ...options, }); }, // Dismiss a specific notification dismissNotification(id) { const notification = this.notifications.find((n) => n.id === id); if (notification) { notification.dismissed = true; } }, // Remove a notification completely removeNotification(id) { const index = this.notifications.findIndex((n) => n.id === id); if (index !== -1) { this.notifications.splice(index, 1); } }, // Mark notification as seen markAsSeen(id) { const notification = this.notifications.find((n) => n.id === id); if (notification) { notification.seen = true; } }, // Clear all notifications of a specific type clearType(type) { this.notifications = this.notifications.filter((n) => n.type !== type); }, // Clear all notifications clearAll() { this.notifications = []; }, // Clear all dismissed notifications clearDismissed() { this.notifications = this.notifications.filter((n) => !n.dismissed); }, // Update notification content updateNotification(id, updates) { const notification = this.notifications.find((n) => n.id === id); if (notification) { Object.assign(notification, updates); } }, // Show a loading notification that can be updated showLoadingNotification(message, title = "Loading...") { return this.addNotification({ type: "info", title, message, persistent: true, actions: [], }); }, // Update a loading notification to success updateToSuccess(id, message, title = "Success") { this.updateNotification(id, { type: "success", title, message, persistent: false, duration: this.defaultDuration, }); // Auto-dismiss after updating setTimeout(() => { this.dismissNotification(id); }, this.defaultDuration); }, // Update a loading notification to error updateToError(id, message, title = "Error") { this.updateNotification(id, { type: "error", title, message, persistent: false, duration: 6000, }); // Auto-dismiss after updating setTimeout(() => { this.dismissNotification(id); }, 6000); }, // Show API operation notifications showApiSuccess(operation, message = null) { const defaultMessages = { create: "Item created successfully", update: "Item updated successfully", delete: "Item deleted successfully", fetch: "Data loaded successfully", }; return this.addSuccess( message || defaultMessages[operation] || "Operation completed successfully", "Success", ); }, showApiError(operation, error, message = null) { const defaultMessages = { create: "Failed to create item", update: "Failed to update item", delete: "Failed to delete item", fetch: "Failed to load data", }; let errorMessage = message; if (!errorMessage) { if (typeof error === "string") { errorMessage = error; } else if (error?.response?.data?.message) { errorMessage = error.response.data.message; } else if (error?.message) { errorMessage = error.message; } else { errorMessage = defaultMessages[operation] || "Operation failed"; } } return this.addError(errorMessage, "Operation Failed"); }, // Configuration methods setPosition(position) { this.position = position; }, setDefaultDuration(duration) { this.defaultDuration = duration; }, setMaxNotifications(max) { this.maxNotifications = max; }, // Utility method for handling async operations with notifications async withNotifications(operation, asyncFunction, options = {}) { const { loadingMessage = "Processing...", successMessage = null, errorMessage = null, showLoading = true, } = options; let loadingId = null; try { if (showLoading) { loadingId = this.showLoadingNotification(loadingMessage); } const result = await asyncFunction(); if (loadingId) { this.updateToSuccess( loadingId, successMessage || `${operation} completed successfully`, ); } else if (successMessage !== false) { this.showApiSuccess(operation, successMessage); } return result; } catch (error) { if (loadingId) { this.updateToError(loadingId, errorMessage || error.message); } else { this.showApiError(operation, error, errorMessage); } throw error; } }, }, });