/** * Fonctions utilitaires partagées entre les écrans RC Tarif et Projet. */ (function(window) { 'use strict'; // ═══════════════════════════════════════════════════════════════════════ // CONSTANTES // ═══════════════════════════════════════════════════════════════════════ /** * Champs qui influencent le calcul du tarif. * On s'en sert pour savoir quand proposer un retour vers l'onglet Tarif. */ const TARIF_IMPACTING_FIELDS = [ // Chiffre d'affaires et type de contrat 'ca', 'chiffreAffaires', 'CA', 'typeCotisation', 'cotisation', 'nombreVehicules', 'nbVehicules', // Activités RCC 'checkVoiturier', 'capitalVoiturier', 'actVoiturier', 'checkCommissionnaire', 'capitalCommissionnaire', 'actMultimodal', 'checkDemenageur', 'capitalDemenageur', 'checkLogistique', 'capitalLogistique', 'checkAutocariste', 'capitalAutocariste', 'checkAutres', 'capitalAutres', // RCE 'checkRCE', 'autresRC', // Activités complémentaires 'actComplVoiturier', 'actComplCommissionnaire', 'actComplDemenageur', 'actComplLogistique', 'activitesVoiturier', 'activitesCommissionnaire', 'activitesDemenageur', 'activitesLogistique', // Marchandises 'marchandisesVoiturier', 'marchandisesCommissionnaire', 'marchandisesDemenageur', 'marchandisesLogistique', 'marchandisesAutocariste', 'marchandisesAutres', 'marOrdinaire', 'marRoulant', 'marEngins', 'marRoulantDem', 'marMobilerUsag', 'marPerissable', 'marAnimaux', 'marCiterne', 'marBeton', 'marExceptionnels', 'marVrac', // Zones géographiques 'zone1', 'zone2', 'zone3', 'zone4', 'zone5', 'zone6', // Extensions de garantie RCC 'extRCCModifCalArrim', 'extRCCFerroutage', 'extRCCFraisRecons', 'extRCCConfie', 'typeExtConfies', 'extRCCTPPC', 'extRCCRegie', 'extRCCSansMontageDemontage', 'checkDomImmat', 'capitalDomImmat', 'checkContConf', 'capitalContConf', 'checkDiffInv', 'capitalDiffInv', 'checkTPPC', 'capitalTPPC', 'vehiculesTPPC', // Extensions de garantie RCE 'extRCEBraDebra', 'extRCEMontageDemontage', // Garanties additionnelles 'checkStationLavage', 'checkGarageInterne', 'checkCSE', 'checkPJ', 'pj', // Sinistralité 'sinistre', 'nbSinistres3ans', 'montantSinistres3ans' ]; // ═══════════════════════════════════════════════════════════════════════ // HELPERS - MANIPULATION DE VALEURS // ═══════════════════════════════════════════════════════════════════════ /** * Convertit une valeur texte/nombre en nombre JS. * Accepte les formats FR/EN (espaces, virgules, points). */ function toNumber(x) { if (x == null) return 0; let value = String(x).trim(); if (!value) return 0; value = value .replace(/\s/g, '') .replace(/[^\d.,-]/g, ''); if (!value) return 0; const isNegative = value.startsWith('-'); value = value.replace(/-/g, ''); if (isNegative && value) { value = '-' + value; } const hasComma = value.includes(','); const hasDot = value.includes('.'); if (hasComma) { value = value.replace(/\./g, '').replace(/,/g, '.'); } else if (hasDot) { const dotMatches = value.match(/\./g); const dotCount = dotMatches ? dotMatches.length : 0; if (dotCount > 1) { const parts = value.split('.'); const lastSegment = parts[parts.length - 1]; if (lastSegment.length === 3) { value = parts.join(''); } else { value = parts.slice(0, -1).join('') + '.' + lastSegment; } } } const parsed = Number(value); return Number.isFinite(parsed) ? parsed : 0; } /** * Récupère un élément par id, avec fallback querySelector. */ function getElementByIdFlexible(id) { if (!id) return null; const direct = document.getElementById(id); if (direct) return direct; try { return document.querySelector(`[id="${id.replace(/"/g, '\\"')}"]`); } catch (err) { return null; } } /** * Lit la valeur d'un champ de formulaire selon son type. */ function getValue(elementId) { const element = getElementByIdFlexible(elementId); if (!element) return null; if (element.type === 'checkbox') { return element.checked; } else if (element.type === 'radio') { const checked = document.querySelector(`input[name="${element.name}"]:checked`); return checked ? checked.value : null; } else if (element.tagName === 'SELECT') { return element.value; } else if (element.value !== undefined) { return element.value; } else { return element.textContent || element.innerText || null; } } /** * Ecrit une valeur dans un champ de formulaire selon son type. */ function setValue(elementId, value) { const element = getElementByIdFlexible(elementId); if (!element) { console.warn(`Élément non trouvé: ${elementId}`); return; } if (element.type === 'checkbox') { element.checked = Boolean(value); } else if (element.type === 'radio') { const radio = document.querySelector(`input[name="${element.name}"][value="${value}"]`); if (radio) radio.checked = true; } else if (element.tagName === 'SELECT') { element.value = value; // Réinitialiser Materialize select si présent if (window.M && window.M.FormSelect) { const instance = window.M.FormSelect.getInstance(element); if (instance) instance.destroy(); window.M.FormSelect.init(element); } } else if (element.value !== undefined) { element.value = value; } else { element.textContent = value; } } // ═══════════════════════════════════════════════════════════════════════ // DÉTECTION DE CHANGEMENTS IMPACTANTS // ═══════════════════════════════════════════════════════════════════════ /** * Dit si un nom de champ fait partie des champs qui influencent le tarif. */ function isFieldImpactingTarif(fieldName) { return TARIF_IMPACTING_FIELDS.some(field => fieldName.includes(field) || field.includes(fieldName) ); } // ═══════════════════════════════════════════════════════════════════════ // MODAL DE RETOUR AU TARIF // ═══════════════════════════════════════════════════════════════════════ /** * Ouvre le modal "modif tarif" déjà présent dans la vue projet. */ function showReturnToTarifModal(fieldName) { const modal = document.getElementById('modalModif'); if (!modal) { console.warn('Modal "modalModif" introuvable'); return; } if (fieldName) { console.warn(`Modification impactant le tarif: ${fieldName}`); } const okBtn = document.getElementById('modif-OK'); const noBtn = document.getElementById('modif-NO'); if (okBtn) { okBtn.onclick = (event) => { event?.preventDefault?.(); navigateToTarif(); }; } if (noBtn) { noBtn.onclick = (event) => { event?.preventDefault?.(); if (!window.M || !window.M.Modal) return; const instance = window.M.Modal.getInstance(modal); if (instance) instance.close(); }; } if (window.M && window.M.Modal) { const instance = window.M.Modal.getInstance(modal) || window.M.Modal.init(modal); instance.open(); } } /** * Redirige vers l'onglet Tarif depuis le Projet. */ function navigateToTarif() { // Fermer le modal const modal = document.getElementById('modalModif'); if (modal && window.M) { const instance = window.M.Modal.getInstance(modal); if (instance) instance.close(); } // Si on est sur le formulaire projet, on garde un snapshot local // pour pré-remplir le tarif juste après la navigation. try { if (typeof window.collectProjetDataForTarifPrefill === 'function') { const projetData = window.collectProjetDataForTarifPrefill(); if (projetData) { sessionStorage.setItem('rc_projet_data', JSON.stringify(projetData)); } } } catch (error) { console.error('Impossible de stocker les donnees projet avant redirection:', error); } // Naviguer vers le tarif const numParcours = new URLSearchParams(window.location.search).get('numParcours'); if (numParcours) { window.location.href = `/navParcours?numParcours=${numParcours}&submenu=tarif`; } } // ═══════════════════════════════════════════════════════════════════════ // EXPORT PUBLIC // ═══════════════════════════════════════════════════════════════════════ /** * API publique du module RC Sync. */ window.RCSync = { // Helpers toNumber, getValue, setValue, getElementByIdFlexible, // Détection changements isFieldImpactingTarif, // Modal showReturnToTarifModal, navigateToTarif, // Constantes TARIF_IMPACTING_FIELDS }; console.log('RC Sync Utils loaded'); })(window);