EDMS/composables/useNotifications.js
2025-06-05 14:57:08 +08:00

325 lines
8.0 KiB
JavaScript

// Notification System Composable
// Provides consistent toast, alert, and confirmation patterns
import { ref, reactive, readonly } from 'vue';
import { useDesignSystem } from './useDesignSystem';
// Global notification state
const notifications = ref([]);
const nextId = ref(1);
export const useNotifications = () => {
const { statusColors, utils } = useDesignSystem();
// Generate unique ID for notifications
const generateId = () => nextId.value++;
// Notification types
const types = {
SUCCESS: 'success',
ERROR: 'error',
WARNING: 'warning',
INFO: 'info'
};
// Default configuration
const defaultConfig = {
duration: 5000,
persistent: false,
position: 'top-right',
showIcon: true,
showClose: true,
allowHtml: false,
maxNotifications: 5
};
// Add notification to queue
const addNotification = (notification) => {
const id = generateId();
const config = { ...defaultConfig, ...notification, id };
// Limit number of notifications
if (notifications.value.length >= defaultConfig.maxNotifications) {
notifications.value.shift();
}
notifications.value.push(config);
// Auto-remove if not persistent
if (!config.persistent && config.duration > 0) {
setTimeout(() => {
removeNotification(id);
}, config.duration);
}
return id;
};
// Remove notification by ID
const removeNotification = (id) => {
const index = notifications.value.findIndex(n => n.id === id);
if (index > -1) {
notifications.value.splice(index, 1);
}
};
// Clear all notifications
const clearAll = () => {
notifications.value = [];
};
// Success notification
const success = (message, options = {}) => {
return addNotification({
type: types.SUCCESS,
title: options.title || 'Success',
message,
icon: 'mdi:check-circle',
...options
});
};
// Error notification
const error = (message, options = {}) => {
return addNotification({
type: types.ERROR,
title: options.title || 'Error',
message,
icon: 'mdi:alert-circle',
persistent: options.persistent !== undefined ? options.persistent : true,
...options
});
};
// Warning notification
const warning = (message, options = {}) => {
return addNotification({
type: types.WARNING,
title: options.title || 'Warning',
message,
icon: 'mdi:alert',
duration: options.duration || 7000,
...options
});
};
// Info notification
const info = (message, options = {}) => {
return addNotification({
type: types.INFO,
title: options.title || 'Information',
message,
icon: 'mdi:information',
...options
});
};
// Confirmation dialog
const confirm = (options = {}) => {
return new Promise((resolve) => {
const id = addNotification({
type: 'confirm',
title: options.title || 'Confirm Action',
message: options.message || 'Are you sure you want to proceed?',
icon: options.icon || 'mdi:help-circle',
persistent: true,
showClose: false,
actions: [
{
label: options.cancelLabel || 'Cancel',
variant: 'secondary-outline',
action: () => {
removeNotification(id);
resolve(false);
}
},
{
label: options.confirmLabel || 'Confirm',
variant: options.dangerous ? 'danger' : 'primary',
action: () => {
removeNotification(id);
resolve(true);
}
}
],
...options
});
});
};
// Loading notification with promise
const loading = (promise, options = {}) => {
const id = addNotification({
type: 'loading',
title: options.title || 'Loading...',
message: options.message || 'Please wait...',
icon: 'mdi:loading',
persistent: true,
showClose: false,
...options
});
return promise
.then((result) => {
removeNotification(id);
if (options.successMessage) {
success(options.successMessage);
}
return result;
})
.catch((err) => {
removeNotification(id);
if (options.errorMessage) {
error(options.errorMessage);
} else {
error(err.message || 'An error occurred');
}
throw err;
});
};
// DMS-specific notifications
const dms = {
// Document operations
documentUploaded: (filename, count = 1) => {
const message = count === 1
? `Document "${filename}" uploaded successfully`
: `${count} documents uploaded successfully`;
return success(message, { title: 'Upload Complete' });
},
documentDeleted: (filename) => {
return success(`Document "${filename}" deleted successfully`, {
title: 'Document Deleted'
});
},
documentShared: (filename, users) => {
const userCount = Array.isArray(users) ? users.length : 1;
const message = `Document "${filename}" shared with ${userCount} user${userCount > 1 ? 's' : ''}`;
return success(message, { title: 'Document Shared' });
},
// Permission changes
accessGranted: (resource) => {
return success(`Access granted to ${resource}`, {
title: 'Access Granted'
});
},
accessRevoked: (resource) => {
return warning(`Access revoked for ${resource}`, {
title: 'Access Revoked'
});
},
// Sync operations
syncStarted: () => {
return info('Synchronization started', {
title: 'Sync in Progress',
duration: 3000
});
},
syncCompleted: (itemCount) => {
return success(`Synchronization completed. ${itemCount} items updated.`, {
title: 'Sync Complete'
});
},
syncFailed: (error) => {
return error(`Synchronization failed: ${error}`, {
title: 'Sync Error'
});
},
// Version control
newVersionCreated: (filename, version) => {
return success(`Version ${version} created for "${filename}"`, {
title: 'New Version'
});
},
versionRestored: (filename, version) => {
return success(`Document "${filename}" restored to version ${version}`, {
title: 'Version Restored'
});
},
// Audit & Security
unauthorizedAccess: (resource) => {
return error(`Unauthorized access attempt to ${resource}`, {
title: 'Security Alert',
persistent: true
});
},
sessionExpiring: (minutes) => {
return warning(`Your session will expire in ${minutes} minutes`, {
title: 'Session Warning',
duration: 10000
});
}
};
// Bulk operations helper
const bulk = {
success: (operations) => {
const count = operations.length;
const message = `${count} operation${count > 1 ? 's' : ''} completed successfully`;
return success(message, { title: 'Bulk Operation Complete' });
},
partialSuccess: (successful, failed) => {
const message = `${successful} operation(s) completed, ${failed} failed`;
return warning(message, { title: 'Partial Success' });
},
failed: (count, error) => {
const message = `${count} operation(s) failed: ${error}`;
return error(message, { title: 'Bulk Operation Failed' });
}
};
return {
// State
notifications: readonly(notifications),
// Core methods
success,
error,
warning,
info,
confirm,
loading,
// Management
removeNotification,
clearAll,
// DMS-specific
dms,
bulk,
// Utilities
types,
defaultConfig
};
};
// Global instance for app-wide usage
let globalInstance = null;
export const setupNotifications = () => {
if (!globalInstance) {
globalInstance = useNotifications();
}
return globalInstance;
};
export const useGlobalNotifications = () => {
if (!globalInstance) {
throw new Error('Notifications not initialized. Call setupNotifications() first.');
}
return globalInstance;
};