/** * Asset Add Modal - JavaScript handler * Handles the creation of new assets from modal forms */ (function() { 'use strict'; // Initialize all add asset modals on the page document.addEventListener('DOMContentLoaded', function() { initializeAddAssetModals(); }); function initializeAddAssetModals() { const forms = document.querySelectorAll('.add-asset-form'); forms.forEach(form => { const modalId = form.closest('.modal').id; initializeForm(form, modalId); }); } const categoriesCache = {}; function initializeForm(form, modalId) { const thematicCode = form.dataset.thematic; const categorySelect = form.querySelector('.asset-category-select'); const modelSelect = form.querySelector('.asset-model-select'); const typeSelect = form.querySelector('.asset-type-select'); const typeContainer = form.querySelector(`#${modalId}TypeContainer`); const modelRequiredStar = form.querySelector(`#${modalId}ModelRequiredStar`); const alertContainer = form.querySelector(`#${modalId}Alert`); const submitBtn = form.querySelector(`#${modalId}Submit`); // Fetch and cache categories for this thematic if (thematicCode && !categoriesCache[thematicCode]) { fetch(`/assets/${thematicCode}/categories/`) .then(response => response.json()) .then(data => { if (data.categories) { categoriesCache[thematicCode] = data.categories; } }) .catch(error => { console.error('Error prefetching categories:', error); }); } async function onCategoryChange() { const categoryId = categorySelect.value; // Clear & disable model select modelSelect.innerHTML = ''; modelSelect.disabled = true; modelSelect.required = false; if (modelRequiredStar) modelRequiredStar.style.display = 'none'; if (!categoryId) { if (typeContainer) typeContainer.classList.add('d-none'); if (typeSelect) { typeSelect.innerHTML = ''; typeSelect.value = ''; typeSelect.required = false; } return; } // Ensure categories are loaded in cache if (!categoriesCache[thematicCode]) { try { const response = await fetch(`/assets/${thematicCode}/categories/`); const data = await response.json(); if (data.categories) { categoriesCache[thematicCode] = data.categories; } } catch (error) { console.error('Error fetching categories:', error); } } const categories = categoriesCache[thematicCode] || []; const categoryData = categories.find(c => c.id == categoryId); if (categoryData && categoryData.allowed_models && categoryData.allowed_models.length > 1) { // Show Type selection if (typeContainer) typeContainer.classList.remove('d-none'); if (typeSelect) { typeSelect.innerHTML = ''; categoryData.allowed_models.forEach(model => { const option = document.createElement('option'); option.value = model.model_name; option.textContent = model.verbose_name; option.dataset.isModelRequired = model.is_model_required; typeSelect.appendChild(option); }); typeSelect.value = ''; typeSelect.required = true; } } else { // Hide Type selection if (typeContainer) typeContainer.classList.add('d-none'); if (typeSelect) { typeSelect.innerHTML = ''; typeSelect.value = ''; typeSelect.required = false; } const singleModel = (categoryData && categoryData.allowed_models && categoryData.allowed_models.length === 1) ? categoryData.allowed_models[0] : null; const selectedType = singleModel ? singleModel.model_name : null; const isModelRequired = singleModel ? singleModel.is_model_required : false; // Load models for this category loadModelsForCategory(thematicCode, categoryId, modelSelect, selectedType); // Set model template requirement if (isModelRequired) { if (modelRequiredStar) modelRequiredStar.style.display = ''; modelSelect.required = true; } else { if (modelRequiredStar) modelRequiredStar.style.display = 'none'; modelSelect.required = false; } } } // Handle category change if (categorySelect && modelSelect) { categorySelect.addEventListener('change', onCategoryChange); } // Handle Type selection change if (typeSelect) { typeSelect.addEventListener('change', function() { const selectedType = this.value; const categoryId = categorySelect ? categorySelect.value : null; // Clear & disable model select modelSelect.innerHTML = ''; modelSelect.disabled = true; modelSelect.required = false; if (modelRequiredStar) modelRequiredStar.style.display = 'none'; if (!categoryId || !selectedType) { return; } // Find the allowed model metadata to check if template is required const categories = categoriesCache[thematicCode] || []; const categoryData = categories.find(c => c.id == categoryId); const allowedModel = categoryData && categoryData.allowed_models ? categoryData.allowed_models.find(m => m.model_name === selectedType) : null; const isModelRequired = allowedModel ? allowedModel.is_model_required : false; // Load models filtered by the selected type loadModelsForCategory(thematicCode, categoryId, modelSelect, selectedType); // Set model template requirement if (isModelRequired) { if (modelRequiredStar) modelRequiredStar.style.display = ''; modelSelect.required = true; } else { if (modelRequiredStar) modelRequiredStar.style.display = 'none'; modelSelect.required = false; } }); } // Handle form submission form.addEventListener('submit', function(e) { e.preventDefault(); submitNewAsset(form, modalId, alertContainer, submitBtn); }); // Reset form when modal is hidden const modal = document.getElementById(modalId); if (modal) { modal.addEventListener('hidden.bs.modal', function() { resetForm(form, modelSelect, alertContainer); }); } } function loadModelsForCategory(thematicCode, categoryId, modelSelect, selectedType = null) { modelSelect.innerHTML = ''; modelSelect.disabled = true; if (!categoryId) { modelSelect.innerHTML = ''; return; } const url = `/assets/${thematicCode}/category/${categoryId}/models/`; fetch(url) .then(response => response.json()) .then(data => { modelSelect.innerHTML = ''; if (data.models && data.models.length > 0) { let filteredModels = data.models; if (selectedType) { filteredModels = data.models.filter(model => { const mType = model.model_type ? model.model_type.toLowerCase() : ''; const sType = selectedType.toLowerCase(); const mTypeClean = mType.replace('model', '').replace('geo', ''); const sTypeClean = sType.replace('model', '').replace('geo', ''); return mTypeClean === sTypeClean; }); } if (filteredModels.length > 0) { filteredModels.forEach(model => { const option = document.createElement('option'); option.value = model.id; option.dataset.modelType = model.model_type; option.textContent = `${model.name}`; modelSelect.appendChild(option); }); modelSelect.disabled = false; } else { modelSelect.innerHTML = ''; } } else { modelSelect.innerHTML = ''; } }) .catch(error => { console.error('Error loading models:', error); modelSelect.innerHTML = ''; }); } function submitNewAsset(form, modalId, alertContainer, submitBtn) { // Disable submit button const originalBtnText = submitBtn.innerHTML; submitBtn.disabled = true; submitBtn.innerHTML = '' + gettext('Création...'); // Clear previous alerts alertContainer.classList.add('d-none'); alertContainer.classList.remove('alert-success', 'alert-danger'); // Gather form data const formData = new FormData(form); const data = {}; formData.forEach((value, key) => { data[key] = value; }); // Resolve asset_type let assetType = null; const typeSelect = form.querySelector('.asset-type-select'); if (typeSelect && typeSelect.value) { assetType = typeSelect.value; } else { const modelSelect = form.querySelector('.asset-model-select'); const selectedOption = modelSelect ? modelSelect.options[modelSelect.selectedIndex] : null; if (selectedOption && selectedOption.dataset.modelType) { let mType = selectedOption.dataset.modelType.toLowerCase(); if (mType.includes('assetmodel') && !mType.includes('geo')) { assetType = mType.replace('assetmodel', 'geoasset'); } else { assetType = mType.replace('model', ''); } } } const categorySelect = form.querySelector('.asset-category-select'); const categoryId = categorySelect ? categorySelect.value : null; const thematicCode = form.dataset.thematic; if (!assetType && categoryId && thematicCode) { const catData = (categoriesCache[thematicCode] || []).find(c => c.id == categoryId); if (catData && catData.allowed_models && catData.allowed_models.length === 1) { assetType = catData.allowed_models[0].model_name; } } if (!assetType) { assetType = getAssetTypeForThematic(thematicCode); } data.asset_type = assetType; const csrfToken = form.querySelector('[name=csrfmiddlewaretoken]').value; const interventionId = form.dataset.interventionId; fetch('/assets/api/create-asset/', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRFToken': csrfToken }, body: JSON.stringify(data) }) .then(response => response.json()) .then(result => { submitBtn.disabled = false; submitBtn.innerHTML = originalBtnText; if (result.success) { alertContainer.className = 'alert alert-success'; alertContainer.innerHTML = '' + result.message; alertContainer.classList.remove('d-none'); // Si un asset a été créé et nécessite la sélection d'un template if (result.needs_template_selection && result.asset_id) { checkAssetTemplates(interventionId, data.asset_type, result.asset_id, modalId, csrfToken); } else { // Redirection normale après un court délai setTimeout(() => { performRedirect(modalId, interventionId, result); }, 1000); } } else { alertContainer.className = 'alert alert-danger'; alertContainer.innerHTML = '' + (result.error || gettext('Erreur lors de la création')); alertContainer.classList.remove('d-none'); } }) .catch(error => { console.error('Error:', error); submitBtn.disabled = false; submitBtn.innerHTML = originalBtnText; alertContainer.className = 'alert alert-danger'; alertContainer.innerHTML = '' + gettext('Erreur de connexion'); alertContainer.classList.remove('d-none'); }); } function checkAssetTemplates(interventionId, assetType, assetId, modalId, csrfToken) { // Vérifier si l'asset a des templates correspondants fetch(`/interventions/${interventionId}/check-asset-templates/`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRFToken': csrfToken, 'X-Requested-With': 'XMLHttpRequest' }, body: JSON.stringify({ asset_type: assetType, asset_id: assetId }) }) .then(response => response.json()) .then(data => { if (data.success && data.has_templates && data.available_templates && data.available_templates.length > 0) { // Afficher le modal de sélection de template showTemplateSelectionModal( interventionId, assetType, assetId, data.available_templates, modalId, csrfToken, data.message ); } else { // Pas de templates disponibles, rediriger normalement setTimeout(() => { performRedirect(modalId, interventionId, {intervention_linked: true}); }, 1000); } }) .catch(error => { console.error('Error checking templates:', error); // En cas d'erreur, rediriger quand même setTimeout(() => { performRedirect(modalId, interventionId, {intervention_linked: true}); }, 1000); }); } function showTemplateSelectionModal(interventionId, assetType, assetId, templates, originalModalId, csrfToken, customMessage) { // Fermer le modal de création d'asset const originalModal = document.getElementById(originalModalId); if (originalModal) { const bsModal = bootstrap.Modal.getInstance(originalModal); if (bsModal) { bsModal.hide(); } } // Créer un modal pour la sélection du template const modalHtml = `
`; // Ajouter le modal au DOM const modalContainer = document.createElement('div'); modalContainer.innerHTML = modalHtml; document.body.appendChild(modalContainer); const selectTemplateModal = document.getElementById('selectTemplateModal'); const templateCheckboxes = selectTemplateModal.querySelectorAll('.template-checkbox'); const createBtn = document.getElementById('createOperationsBtn'); const skipBtn = document.getElementById('skipTemplateBtn'); const templateAlert = document.getElementById('templateAlert'); const selectAllBtn = document.getElementById('selectAllTemplates'); const deselectAllBtn = document.getElementById('deselectAllTemplates'); // Fonction pour vérifier si au moins un template est sélectionné function updateCreateButtonState() { const anyChecked = Array.from(templateCheckboxes).some(cb => cb.checked); createBtn.disabled = !anyChecked; } // Activer le bouton de création quand au moins un template est sélectionné templateCheckboxes.forEach(checkbox => { checkbox.addEventListener('change', updateCreateButtonState); }); // Bouton "Tout sélectionner" selectAllBtn.addEventListener('click', function() { templateCheckboxes.forEach(cb => cb.checked = true); updateCreateButtonState(); }); // Bouton "Tout désélectionner" deselectAllBtn.addEventListener('click', function() { templateCheckboxes.forEach(cb => cb.checked = false); updateCreateButtonState(); }); // Gérer le clic sur "Ignorer et continuer" skipBtn.addEventListener('click', function() { const bsModal = bootstrap.Modal.getInstance(selectTemplateModal); bsModal.hide(); performRedirect(originalModalId, interventionId, {intervention_linked: true}); }); // Gérer le clic sur "Créer les opérations" createBtn.addEventListener('click', function() { const selectedTemplateIds = Array.from(templateCheckboxes) .filter(cb => cb.checked) .map(cb => parseInt(cb.value)); if (selectedTemplateIds.length === 0) return; createBtn.disabled = true; const originalBtnText = createBtn.innerHTML; createBtn.innerHTML = '' + gettext('Création en cours...'); // Appeler l'API pour créer les opérations fetch(`/interventions/${interventionId}/create-operations-from-template/`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRFToken': csrfToken, 'X-Requested-With': 'XMLHttpRequest' }, body: JSON.stringify({ asset_type: assetType, asset_id: assetId, template_ids: selectedTemplateIds }) }) .then(response => response.json()) .then(data => { if (data.success) { templateAlert.className = 'alert alert-success'; templateAlert.innerHTML = '' + data.message; templateAlert.classList.remove('d-none'); // Fermer le modal et rediriger après un court délai setTimeout(() => { const bsModal = bootstrap.Modal.getInstance(selectTemplateModal); bsModal.hide(); performRedirect(originalModalId, interventionId, {intervention_linked: true}); }, 1500); } else { createBtn.disabled = false; createBtn.innerHTML = originalBtnText; templateAlert.className = 'alert alert-danger'; templateAlert.innerHTML = '' + (data.error || gettext('Erreur lors de la création')); templateAlert.classList.remove('d-none'); } }) .catch(error => { console.error('Error:', error); createBtn.disabled = false; createBtn.innerHTML = originalBtnText; templateAlert.className = 'alert alert-danger'; templateAlert.innerHTML = '' + gettext('Erreur de connexion'); templateAlert.classList.remove('d-none'); }); }); // Nettoyer le modal du DOM après fermeture selectTemplateModal.addEventListener('hidden.bs.modal', function() { modalContainer.remove(); }); // Afficher le modal const bsModal = new bootstrap.Modal(selectTemplateModal); bsModal.show(); } function performRedirect(modalId, interventionId, result) { const modalEl = document.getElementById(modalId); const modal = bootstrap.Modal.getInstance(modalEl); if (modal) { modal.hide(); } // Determine redirect URL let redirectUrl = null; // Check if we're on a mobile view const isMobileView = window.location.pathname.startsWith('/mobile/') || document.body.classList.contains('mobile-view') || document.querySelector('body')?.getAttribute('data-mobile-view') === 'true'; if (interventionId && result.intervention_linked) { // If we're in mobile view and there's an intervention, redirect to mobile intervention view if (isMobileView) { redirectUrl = `/mobile/interventions/${interventionId}/`; } else { redirectUrl = `/interventions/${interventionId}/`; } } else if (result.redirect_url) { redirectUrl = result.redirect_url; } // Reload or redirect if (redirectUrl) { window.location.href = redirectUrl; } else { window.location.reload(); } } function getAssetTypeForThematic(thematicCode) { const mapping = { 'structures': 'structuregeoasset', 'trafficlights': 'trafficlightgeoasset', 'publiclighting': 'publiclightinggeoasset', 'nature': 'naturegeoasset', 'artworks': 'artworksgeoasset', 'controlcenters': 'controlcentergeoasset', 'its': 'itsgeoasset', 'sign': 'signgeoasset', 'roads': 'roadgeoasset', 'publicbuildings': 'publicbuilding', 'buildings': 'publicbuilding' }; return mapping[thematicCode] || 'geoasset'; } function resetForm(form, modelSelect, alertContainer) { form.reset(); const modalId = form.closest('.modal').id; const typeContainer = form.querySelector(`#${modalId}TypeContainer`); const typeSelect = form.querySelector('.asset-type-select'); const modelRequiredStar = form.querySelector(`#${modalId}ModelRequiredStar`); if (typeContainer) typeContainer.classList.add('d-none'); if (typeSelect) { typeSelect.innerHTML = ''; typeSelect.value = ''; typeSelect.required = false; } if (modelRequiredStar) modelRequiredStar.style.display = 'none'; if (modelSelect) { modelSelect.innerHTML = ''; modelSelect.disabled = true; modelSelect.required = false; } alertContainer.classList.add('d-none'); } // Helper function for translations (fallback if gettext is not available) function gettext(text) { if (typeof window.gettext === 'function') { return window.gettext(text); } return text; } // Expose for external use window.AssetAddModal = { initialize: initializeAddAssetModals, loadModelsForCategory: loadModelsForCategory }; })();