generated from corrad-software/corrad-af-2024
325 lines
8.0 KiB
JavaScript
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;
|
|
};
|