241 lines
8.6 KiB
JavaScript
241 lines
8.6 KiB
JavaScript
/* ===================================
|
|
* NETGESCON FORM HANDLER
|
|
* ===================================
|
|
* Gestione form con UX migliorata:
|
|
* - Modal di conferma
|
|
* - Progress indicators
|
|
* - No refresh pagina
|
|
* - Feedback immediato
|
|
* =================================== */
|
|
|
|
class NetGesConFormHandler {
|
|
constructor() {
|
|
this.init();
|
|
}
|
|
|
|
init() {
|
|
this.setupFormListeners();
|
|
this.createLoadingModal();
|
|
this.setupAjaxDefaults();
|
|
}
|
|
|
|
setupAjaxDefaults() {
|
|
// Setup CSRF token per tutte le richieste AJAX
|
|
$.ajaxSetup({
|
|
headers: {
|
|
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
|
|
}
|
|
});
|
|
}
|
|
|
|
setupFormListeners() {
|
|
// Intercetta tutti i form con classe 'netgescon-form'
|
|
$(document).on('submit', '.netgescon-form', (e) => {
|
|
e.preventDefault();
|
|
this.handleFormSubmit(e.target);
|
|
});
|
|
|
|
// Intercetta i form di creazione/modifica stabili
|
|
$(document).on('submit', 'form[action*="stabili"]', (e) => {
|
|
if (!$(e.target).hasClass('netgescon-form')) {
|
|
e.preventDefault();
|
|
this.handleFormSubmit(e.target);
|
|
}
|
|
});
|
|
}
|
|
|
|
createLoadingModal() {
|
|
const modalHtml = `
|
|
<div id="netgescon-loading-modal" class="fixed inset-0 bg-black bg-opacity-50 hidden z-50">
|
|
<div class="flex items-center justify-center min-h-screen p-4">
|
|
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-xl p-6 max-w-sm w-full mx-auto">
|
|
<div class="text-center">
|
|
<div class="mx-auto flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 dark:bg-blue-900 mb-4">
|
|
<i class="fas fa-spinner fa-spin text-blue-600 dark:text-blue-400 text-2xl"></i>
|
|
</div>
|
|
<h3 class="text-lg font-medium text-gray-900 dark:text-gray-100 mb-2">
|
|
Elaborazione in corso...
|
|
</h3>
|
|
<p class="text-sm text-gray-500 dark:text-gray-400" id="loading-message">
|
|
Attendere mentre salviamo i dati
|
|
</p>
|
|
<div class="mt-4">
|
|
<div class="bg-gray-200 dark:bg-gray-700 rounded-full h-2">
|
|
<div class="bg-blue-600 h-2 rounded-full transition-all duration-300"
|
|
id="progress-bar" style="width: 0%"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
|
|
$('body').append(modalHtml);
|
|
}
|
|
|
|
showLoadingModal(message = 'Elaborazione in corso...') {
|
|
$('#loading-message').text(message);
|
|
$('#progress-bar').css('width', '20%');
|
|
$('#netgescon-loading-modal').removeClass('hidden');
|
|
|
|
// Simula progress
|
|
setTimeout(() => $('#progress-bar').css('width', '60%'), 500);
|
|
setTimeout(() => $('#progress-bar').css('width', '80%'), 1000);
|
|
}
|
|
|
|
hideLoadingModal() {
|
|
$('#progress-bar').css('width', '100%');
|
|
setTimeout(() => {
|
|
$('#netgescon-loading-modal').addClass('hidden');
|
|
$('#progress-bar').css('width', '0%');
|
|
}, 300);
|
|
}
|
|
|
|
handleFormSubmit(form) {
|
|
const $form = $(form);
|
|
const formData = new FormData(form);
|
|
const action = $form.attr('action');
|
|
const method = $form.attr('method') || 'POST';
|
|
|
|
// Determina il messaggio di loading in base al form
|
|
let loadingMessage = 'Salvataggio in corso...';
|
|
if (action.includes('create') || method.toUpperCase() === 'POST') {
|
|
loadingMessage = 'Creazione in corso...';
|
|
} else if (action.includes('edit') || action.includes('update')) {
|
|
loadingMessage = 'Aggiornamento in corso...';
|
|
}
|
|
|
|
this.showLoadingModal(loadingMessage);
|
|
|
|
// Se il form ha un metodo specificato tramite _method, usalo
|
|
const actualMethod = formData.get('_method') || method;
|
|
|
|
$.ajax({
|
|
url: action,
|
|
type: method,
|
|
data: formData,
|
|
processData: false,
|
|
contentType: false,
|
|
success: (response) => {
|
|
this.hideLoadingModal();
|
|
this.handleSuccess(response, $form);
|
|
},
|
|
error: (xhr) => {
|
|
this.hideLoadingModal();
|
|
this.handleError(xhr, $form);
|
|
}
|
|
});
|
|
}
|
|
|
|
handleSuccess(response, $form) {
|
|
// Mostra notifica di successo
|
|
this.showNotification('Operazione completata con successo!', 'success');
|
|
|
|
// Reindirizza se specificato nella risposta
|
|
if (response.redirect) {
|
|
setTimeout(() => {
|
|
window.location.href = response.redirect;
|
|
}, 1500);
|
|
} else {
|
|
// Altrimenti ricarica la pagina dopo un delay
|
|
setTimeout(() => {
|
|
window.location.reload();
|
|
}, 1500);
|
|
}
|
|
}
|
|
|
|
handleError(xhr, $form) {
|
|
console.error('Form submission error:', xhr);
|
|
|
|
let errorMessage = 'Si è verificato un errore. Riprova.';
|
|
|
|
if (xhr.status === 422 && xhr.responseJSON && xhr.responseJSON.errors) {
|
|
// Errori di validazione
|
|
errorMessage = 'Errori di validazione:';
|
|
const errors = xhr.responseJSON.errors;
|
|
const errorList = Object.values(errors).flat();
|
|
|
|
this.showValidationErrors(errorList, $form);
|
|
return;
|
|
} else if (xhr.responseJSON && xhr.responseJSON.message) {
|
|
errorMessage = xhr.responseJSON.message;
|
|
}
|
|
|
|
this.showNotification(errorMessage, 'error');
|
|
}
|
|
|
|
showValidationErrors(errors, $form) {
|
|
// Rimuovi errori precedenti
|
|
$form.find('.error-message').remove();
|
|
$form.find('.border-red-500').removeClass('border-red-500');
|
|
|
|
// Mostra nuovo alert con errori
|
|
const errorHtml = `
|
|
<div class="error-message bg-red-50 border border-red-200 text-red-700 px-4 py-3 rounded mb-4">
|
|
<div class="flex items-start">
|
|
<i class="fas fa-exclamation-triangle mr-2 mt-1"></i>
|
|
<div>
|
|
<h4 class="font-bold">Errori di validazione:</h4>
|
|
<ul class="mt-2 text-sm">
|
|
${errors.map(error => `<li>• ${error}</li>`).join('')}
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
|
|
$form.prepend(errorHtml);
|
|
|
|
// Scroll al primo errore
|
|
$form[0].scrollIntoView({ behavior: 'smooth' });
|
|
}
|
|
|
|
showNotification(message, type = 'info') {
|
|
const bgColor = type === 'success' ? 'bg-green-500' :
|
|
type === 'error' ? 'bg-red-500' : 'bg-blue-500';
|
|
|
|
const notification = $(`
|
|
<div class="fixed top-4 right-4 ${bgColor} text-white px-6 py-4 rounded-lg shadow-lg z-50 transform translate-x-full transition-transform duration-300">
|
|
<div class="flex items-center">
|
|
<i class="fas fa-${type === 'success' ? 'check' : type === 'error' ? 'exclamation-triangle' : 'info'} mr-2"></i>
|
|
<span>${message}</span>
|
|
</div>
|
|
</div>
|
|
`);
|
|
|
|
$('body').append(notification);
|
|
|
|
// Mostra notifica
|
|
setTimeout(() => {
|
|
notification.removeClass('translate-x-full');
|
|
}, 100);
|
|
|
|
// Nascondi dopo 4 secondi
|
|
setTimeout(() => {
|
|
notification.addClass('translate-x-full');
|
|
setTimeout(() => notification.remove(), 300);
|
|
}, 4000);
|
|
}
|
|
}
|
|
|
|
// Inizializza quando il DOM è pronto
|
|
$(document).ready(() => {
|
|
// Verifica se jQuery è disponibile
|
|
if (typeof $ === 'undefined') {
|
|
console.warn('NetGesConFormHandler: jQuery non trovato, caricamento alternativo...');
|
|
// Carica jQuery se non presente
|
|
const script = document.createElement('script');
|
|
script.src = 'https://code.jquery.com/jquery-3.6.0.min.js';
|
|
script.onload = () => {
|
|
new NetGesConFormHandler();
|
|
};
|
|
document.head.appendChild(script);
|
|
} else {
|
|
new NetGesConFormHandler();
|
|
}
|
|
});
|
|
|
|
// Esporta per uso globale
|
|
window.NetGesConFormHandler = NetGesConFormHandler;
|