admin and vendor backends features
This commit is contained in:
209
static/js/shared/modal-system.js
Normal file
209
static/js/shared/modal-system.js
Normal file
@@ -0,0 +1,209 @@
|
||||
/**
|
||||
* Modal System Helper Functions
|
||||
* Utility functions for modal operations across all sections
|
||||
*/
|
||||
|
||||
window.modalHelpers = {
|
||||
/**
|
||||
* Show a simple confirmation dialog
|
||||
* Returns a Promise that resolves with true/false
|
||||
*/
|
||||
async confirm(options) {
|
||||
return new Promise((resolve) => {
|
||||
const component = Alpine.$data(document.body);
|
||||
|
||||
component.showConfirmModal({
|
||||
title: options.title || 'Confirm Action',
|
||||
message: options.message || 'Are you sure?',
|
||||
warning: options.warning || '',
|
||||
buttonText: options.buttonText || 'Confirm',
|
||||
buttonClass: options.buttonClass || 'btn-danger',
|
||||
onConfirm: () => resolve(true),
|
||||
onCancel: () => resolve(false)
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Show a success message
|
||||
*/
|
||||
success(message, options = {}) {
|
||||
const component = Alpine.$data(document.body);
|
||||
|
||||
component.showSuccessModal({
|
||||
title: options.title || 'Success',
|
||||
message: message,
|
||||
redirectUrl: options.redirectUrl || null,
|
||||
redirectDelay: options.redirectDelay || 2000
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Show an error message
|
||||
*/
|
||||
error(message, details = '') {
|
||||
const component = Alpine.$data(document.body);
|
||||
|
||||
component.showErrorModal({
|
||||
title: 'Error',
|
||||
message: message,
|
||||
details: details
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Show API error with proper formatting
|
||||
*/
|
||||
apiError(error) {
|
||||
const component = Alpine.$data(document.body);
|
||||
|
||||
let message = 'An error occurred';
|
||||
let details = '';
|
||||
|
||||
if (error.message) {
|
||||
message = error.message;
|
||||
}
|
||||
|
||||
if (error.details) {
|
||||
details = typeof error.details === 'string'
|
||||
? error.details
|
||||
: JSON.stringify(error.details, null, 2);
|
||||
} else if (error.error_code) {
|
||||
details = `Error Code: ${error.error_code}`;
|
||||
}
|
||||
|
||||
component.showErrorModal({
|
||||
title: 'Error',
|
||||
message: message,
|
||||
details: details
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Show loading overlay
|
||||
*/
|
||||
showLoading() {
|
||||
const component = Alpine.$data(document.body);
|
||||
component.showLoading();
|
||||
},
|
||||
|
||||
/**
|
||||
* Hide loading overlay
|
||||
*/
|
||||
hideLoading() {
|
||||
const component = Alpine.$data(document.body);
|
||||
component.hideLoading();
|
||||
},
|
||||
|
||||
/**
|
||||
* Execute an async operation with loading state
|
||||
*/
|
||||
async withLoading(asyncFunction) {
|
||||
try {
|
||||
this.showLoading();
|
||||
const result = await asyncFunction();
|
||||
return result;
|
||||
} finally {
|
||||
this.hideLoading();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Execute an async operation with error handling
|
||||
*/
|
||||
async withErrorHandling(asyncFunction, errorMessage = 'Operation failed') {
|
||||
try {
|
||||
return await asyncFunction();
|
||||
} catch (error) {
|
||||
console.error('Operation error:', error);
|
||||
this.apiError({
|
||||
message: errorMessage,
|
||||
details: error.message || error.toString()
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Execute an async operation with both loading and error handling
|
||||
*/
|
||||
async execute(asyncFunction, options = {}) {
|
||||
const {
|
||||
errorMessage = 'Operation failed',
|
||||
successMessage = null,
|
||||
redirectUrl = null
|
||||
} = options;
|
||||
|
||||
try {
|
||||
this.showLoading();
|
||||
const result = await asyncFunction();
|
||||
|
||||
if (successMessage) {
|
||||
this.success(successMessage, { redirectUrl });
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error('Operation error:', error);
|
||||
this.apiError({
|
||||
message: errorMessage,
|
||||
details: error.message || error.toString()
|
||||
});
|
||||
throw error;
|
||||
} finally {
|
||||
this.hideLoading();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Confirm a destructive action
|
||||
*/
|
||||
async confirmDelete(itemName, itemType = 'item') {
|
||||
return this.confirm({
|
||||
title: `Delete ${itemType}`,
|
||||
message: `Are you sure you want to delete "${itemName}"?`,
|
||||
warning: 'This action cannot be undone.',
|
||||
buttonText: 'Delete',
|
||||
buttonClass: 'btn-danger'
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Confirm logout
|
||||
*/
|
||||
async confirmLogout() {
|
||||
return this.confirm({
|
||||
title: 'Confirm Logout',
|
||||
message: 'Are you sure you want to logout?',
|
||||
buttonText: 'Logout',
|
||||
buttonClass: 'btn-primary'
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Show validation errors
|
||||
*/
|
||||
validationError(errors) {
|
||||
let message = 'Please correct the following errors:';
|
||||
let details = '';
|
||||
|
||||
if (Array.isArray(errors)) {
|
||||
details = errors.join('\n');
|
||||
} else if (typeof errors === 'object') {
|
||||
details = Object.entries(errors)
|
||||
.map(([field, error]) => `${field}: ${error}`)
|
||||
.join('\n');
|
||||
} else {
|
||||
details = errors.toString();
|
||||
}
|
||||
|
||||
this.error(message, details);
|
||||
}
|
||||
};
|
||||
|
||||
// Shorthand aliases for convenience
|
||||
window.showConfirm = window.modalHelpers.confirm.bind(window.modalHelpers);
|
||||
window.showSuccess = window.modalHelpers.success.bind(window.modalHelpers);
|
||||
window.showError = window.modalHelpers.error.bind(window.modalHelpers);
|
||||
window.showLoading = window.modalHelpers.showLoading.bind(window.modalHelpers);
|
||||
window.hideLoading = window.modalHelpers.hideLoading.bind(window.modalHelpers);
|
||||
Reference in New Issue
Block a user