/** * Soft Delete Conflict Handler * * This module handles the detection and resolution of soft delete conflicts. * Save this file to public/js/soft-delete-conflict-handler.js */ const SoftDeleteConflictHandler = { /** * Initialize the handler for a specific form. * * @param {string} formSelector - The CSS selector for the form * @param {string} modelClass - The fully qualified class name of the model * @param {object} options - Additional options */ init: function(formSelector, modelClass, options = {}) { const form = document.querySelector(formSelector); if (!form) { console.error(`Form not found: ${formSelector}`); return; } // Store the model class on the form for later use form.dataset.modelClass = modelClass; // Set success and cancel redirect URLs if provided if (options.successRedirect) { form.dataset.successRedirect = options.successRedirect; } if (options.cancelRedirect) { form.dataset.cancelRedirect = options.cancelRedirect; } // Intercept form submission form.addEventListener('submit', (event) => { // Don't prevent submission if we've already checked for conflicts if (form.dataset.conflictChecked === 'true') { return true; } // Prevent the default form submission event.preventDefault(); // Check for conflicts this.checkForConflicts(form, modelClass, (hasConflict, conflictData) => { if (hasConflict) { // Show the conflict resolution modal this.showConflictModal(conflictData, form); } else { // No conflict, continue with form submission form.dataset.conflictChecked = 'true'; form.submit(); } }); }); }, /** * Check for soft delete conflicts before form submission. * * @param {HTMLFormElement} form - The form element * @param {string} modelClass - The fully qualified class name of the model * @param {Function} callback - Callback function to handle the result */ checkForConflicts: function(form, modelClass, callback) { // Create a FormData object from the form const formData = new FormData(form); // Add the model class formData.append('model_class', modelClass); // Send the request to check for conflicts fetch('/admin/soft-delete/check-conflict', { method: 'POST', body: formData, headers: { 'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content'), 'Accept': 'application/json', }, }) .then(response => response.json()) .then(data => { if (data.success && data.conflict) { // Conflict found callback(true, data.duplicate); } else { // No conflict callback(false, null); } }) .catch(error => { console.error('Error checking for conflicts:', error); // On error, allow the form to submit to let server-side validation handle it callback(false, null); }); }, /** * Show the conflict resolution modal. * * @param {object} conflictData - Data about the conflicting record * @param {HTMLFormElement} form - The form element */ showConflictModal: function(conflictData, form) { // Get form data as an object const formDataObj = {}; const formData = new FormData(form); for (const [key, value] of formData.entries()) { formDataObj[key] = value; } // Dispatch a custom event to open the modal window.dispatchEvent(new CustomEvent('open-soft-delete-modal', { detail: { conflict: conflictData, formData: formDataObj, formElement: form, modelClass: form.dataset.modelClass } })); } }; // Expose to window for global access window.SoftDeleteConflictHandler = SoftDeleteConflictHandler;