jQuery(function($) {
jQuery('form.load_simulator').each(function() {
jQuery(this).attr('action', window.location.origin + '/credit-step1')
})
/**
* Système de sauvegarde localStorage
*/
const FORM_STORAGE_KEY = 'credit_direct_form_data';
const FORM_STORAGE_TIMESTAMP = 'credit_direct_form_timestamp';
const STORAGE_EXPIRY_HOURS = 24; // Les données expirent après 24h
/**
* Affiche l'indicateur de sauvegarde
*/
function showSaveIndicator(message, type = 'success') {
let indicator = jQuery('.auto-save-indicator');
if (indicator.length === 0) {
indicator = jQuery('
');
jQuery('body').append(indicator);
}
indicator.removeClass('show saving error').addClass('show ' + type);
indicator.text(message);
// Masquer après 3 secondes
setTimeout(() => {
indicator.removeClass('show');
}, 3000);
}
/**
* Sauvegarde les données du formulaire dans localStorage
*/
function saveFormData() {
// Afficher l'indicateur de sauvegarde
showSaveIndicator('Sauvegarde en cours...', 'saving');
const formData = {};
const currentStep = getCurrentStep();
// Récupérer tous les champs du formulaire
jQuery('form.form-submit').find('input, select, textarea').each(function() {
const $field = jQuery(this);
const name = $field.attr('name');
const type = $field.attr('type');
if (!name) return;
let value = '';
switch (type) {
case 'checkbox':
value = $field.is(':checked') ? $field.val() : '';
break;
case 'radio':
if ($field.is(':checked')) {
value = $field.val();
}
break;
case 'file':
// Ne pas sauvegarder les fichiers
return;
default:
value = $field.val() || '';
break;
}
// Ne sauvegarder que si la valeur n'est pas vide
if (value !== '') {
formData[name] = value;
}
});
// Sauvegarder avec l'étape actuelle et le timestamp
const dataToSave = {
step: currentStep,
data: formData,
timestamp: Date.now()
};
try {
localStorage.setItem(FORM_STORAGE_KEY, JSON.stringify(dataToSave));
localStorage.setItem(FORM_STORAGE_TIMESTAMP, Date.now().toString());
console.log('Données sauvegardées dans localStorage:', dataToSave);
// Afficher le succès
setTimeout(() => {
showSaveIndicator('Données sauvegardées', 'success');
}, 500);
} catch (e) {
console.error('Erreur lors de la sauvegarde localStorage:', e);
showSaveIndicator('Erreur de sauvegarde', 'error');
}
}
/**
* Restaure les données du formulaire depuis localStorage
*/
function restoreFormData() {
try {
const savedData = localStorage.getItem(FORM_STORAGE_KEY);
if (!savedData) return false;
const parsedData = JSON.parse(savedData);
const now = Date.now();
const savedTime = parsedData.timestamp || 0;
console.log('parsedData', parsedData);
// Vérifier si les données ne sont pas expirées
if (now - savedTime > STORAGE_EXPIRY_HOURS * 60 * 60 * 1000) {
console.log('Données localStorage expirées, suppression...');
clearFormData();
return false;
}
const formData = parsedData.data || {};
let restoredCount = 0;
// Traiter d'abord les champs de crédits en cours
const currentLoansData = {};
const coCurrentLoansData = {};
// Séparer les données des crédits en cours des autres champs
Object.keys(formData).forEach(name => {
if (name.startsWith('currentloans[')) {
const match = name.match(/currentloans\[(\d+)\]\[([^\]]+)\]/);
if (match) {
const index = parseInt(match[1]);
const field = match[2];
if (!currentLoansData[index]) currentLoansData[index] = {};
currentLoansData[index][field] = formData[name];
}
} else if (name.startsWith('cocurrentloans[')) {
const match = name.match(/cocurrentloans\[(\d+)\]\[([^\]]+)\]/);
if (match) {
const index = parseInt(match[1]);
const field = match[2];
if (!coCurrentLoansData[index]) coCurrentLoansData[index] = {};
coCurrentLoansData[index][field] = formData[name];
}
}
});
// Restaurer les valeurs des champs simples
Object.keys(formData).forEach(name => {
// Ignorer les champs de crédits en cours (traités séparément)
if (name.startsWith('currentloans[') || name.startsWith('cocurrentloans[')) {
return;
}
const $field = jQuery('form.form-submit').find(`[name="${name}"]`);
if ($field.length === 0) return;
const value = formData[name];
const type = $field.attr('type');
switch (type) {
case 'checkbox':
if (value) {
$field.prop('checked', true);
}
break;
case 'radio':
$field.filter(`[value="${value}"]`).prop('checked', true);
break;
default:
$field.val(value);
break;
}
// Ajouter un effet visuel temporaire
$field.addClass('field-restored');
setTimeout(() => {
$field.removeClass('field-restored');
}, 2000);
restoredCount++;
});
// Restaurer les crédits en cours de l'emprunteur
Object.keys(currentLoansData).forEach(index => {
const loanData = currentLoansData[index];
const blockIndex = parseInt(index);
// Créer le bloc si nécessaire
while (jQuery('.wpcf-currentloan--block').length <= blockIndex) {
addCurrentLoan();
}
// Remplir les champs du bloc
const $block = jQuery('.wpcf-currentloan--block').eq(blockIndex);
Object.keys(loanData).forEach(field => {
const $field = $block.find(`[name="currentloans[${index}][${field}]"]`);
if ($field.length > 0) {
$field.val(loanData[field]);
$field.addClass('field-restored');
setTimeout(() => {
$field.removeClass('field-restored');
}, 2000);
restoredCount++;
}
});
// Appliquer la logique de désactivation du champ durationmonth selon le type de prêt
const loanType = loanData.loantype;
if (loanType === '1') {
const $durationField = $block.find('input[name*="durationmonth"]');
if ($durationField.length > 0) {
$durationField.prop('readonly', true);
$durationField.addClass('readonly-field');
}
// Mettre à jour les labels selon le type de prêt
const $borrowedCapitalField = $block.find('input[name*="borrowedcapital"]');
const $monthlyPaymentField = $block.find('input[name*="monthlypayment"]');
if ($borrowedCapitalField.length > 0) {
const $borrowedCapitalLabel = $borrowedCapitalField.closest('.form-group').find('label');
if ($borrowedCapitalLabel.length > 0) {
$borrowedCapitalLabel.text('Plafond de la carte');
}
}
if ($monthlyPaymentField.length > 0) {
const $monthlyPaymentLabel = $monthlyPaymentField.closest('.form-group').find('label');
if ($monthlyPaymentLabel.length > 0) {
$monthlyPaymentLabel.text('Remboursement mensuel');
}
}
}
});
// Restaurer les crédits en cours du co-emprunteur
Object.keys(coCurrentLoansData).forEach(index => {
const loanData = coCurrentLoansData[index];
const blockIndex = parseInt(index);
// Créer le bloc si nécessaire
while (jQuery('.wpcf-cocurrentloan--block').length <= blockIndex) {
addCoCurrentLoan();
}
// Remplir les champs du bloc
const $block = jQuery('.wpcf-cocurrentloan--block').eq(blockIndex);
Object.keys(loanData).forEach(field => {
const $field = $block.find(`[name="cocurrentloans[${index}][${field}]"]`);
if ($field.length > 0) {
$field.val(loanData[field]);
$field.addClass('field-restored');
setTimeout(() => {
$field.removeClass('field-restored');
}, 2000);
restoredCount++;
}
});
// Appliquer la logique de désactivation du champ durationmonth selon le type de prêt
const loanType = loanData.loantype;
if (loanType === '1') {
const $durationField = $block.find('input[name*="durationmonth"]');
if ($durationField.length > 0) {
$durationField.prop('readonly', true);
$durationField.addClass('readonly-field');
}
// Mettre à jour les labels selon le type de prêt
const $borrowedCapitalField = $block.find('input[name*="borrowedcapital"]');
const $monthlyPaymentField = $block.find('input[name*="monthlypayment"]');
if ($borrowedCapitalField.length > 0) {
const $borrowedCapitalLabel = $borrowedCapitalField.closest('.form-group').find('label');
if ($borrowedCapitalLabel.length > 0) {
$borrowedCapitalLabel.text('Plafond de la carte');
}
}
if ($monthlyPaymentField.length > 0) {
const $monthlyPaymentLabel = $monthlyPaymentField.closest('.form-group').find('label');
if ($monthlyPaymentLabel.length > 0) {
$monthlyPaymentLabel.text('Remboursement mensuel');
}
}
}
});
console.log(`${restoredCount} champs restaurés depuis localStorage`);
if (restoredCount > 0) {
showSaveIndicator(`${restoredCount} champs restaurés`, 'success');
}
return restoredCount > 0;
} catch (e) {
console.error('Erreur lors de la restauration localStorage:', e);
return false;
}
}
/**
* Efface les données du formulaire du localStorage
*/
function clearFormData() {
try {
localStorage.removeItem(FORM_STORAGE_KEY);
localStorage.removeItem(FORM_STORAGE_TIMESTAMP);
console.log('Données localStorage effacées');
// Masquer le message d'information
jQuery('.localstorage-info').fadeOut();
// Afficher un message de confirmation
showSaveIndicator('Données effacées', 'success');
} catch (e) {
console.error('Erreur lors de l\'effacement localStorage:', e);
showSaveIndicator('Erreur lors de l\'effacement', 'error');
}
}
// Rendre la fonction accessible globalement
window.clearFormData = clearFormData;
/**
* Détermine l'étape actuelle basée sur l'URL
*/
function getCurrentStep() {
const path = window.location.pathname;
if (path.includes('credit-step1')) return 'step1';
if (path.includes('credit-step2')) return 'step2';
if (path.includes('credit-step3')) return 'step3';
if (path.includes('credit-step4')) return 'step4';
if (path.includes('credit-step5')) return 'step5';
return 'unknown';
}
/**
* Sauvegarde automatique lors de la modification des champs
*/
function setupAutoSave() {
// Sauvegarde sur clic du lien "previous-step"
jQuery('a.previous-step').on('click', function(e) {
/* e.preventDefault(); */
saveFormData();
});
// Sauvegarde sur changement de valeur (désactivé)
// jQuery('form.form-submit').on('change input', 'input, select, textarea', function() {
// // Debounce pour éviter trop de sauvegardes
// clearTimeout(window.autoSaveTimeout);
// window.autoSaveTimeout = setTimeout(saveFormData, 1000);
// });
// Sauvegarde sur clic des boutons radio/checkbox (désactivé)
// jQuery('form.form-submit').on('click', 'input[type="radio"], input[type="checkbox"]', function() {
// setTimeout(saveFormData, 100);
// });
// Sauvegarde avant soumission du formulaire (désactivé)
// jQuery('form.form-submit').on('submit', function() {
// saveFormData();
// });
// Sauvegarde avant navigation (bouton étape précédente) (désactivé)
// jQuery('a[href*="credit-step"]').on('click', function() {
// saveFormData();
// });
// Sauvegarde lors de l'ajout/suppression de crédits en cours (désactivé)
// $(document).on('currentLoanAdded currentLoanRemoved', function() {
// setTimeout(saveFormData, 500);
// });
}
/**
* Affiche le message d'information localStorage
*/
function showLocalStorageInfo() {
const savedData = localStorage.getItem(FORM_STORAGE_KEY);
if (!savedData) return;
// Vérifier si le message existe déjà
if (jQuery('.localstorage-info').length > 0) return;
const infoHtml = `
💾
Vos données sont sauvegardées automatiquement.
`;
// Insérer au début du formulaire
jQuery('form.form-submit').prepend(infoHtml);
}
/**
* Initialise le système de sauvegarde
*/
function initFormStorage() {
if(hasCreditDirectToken())
return;
//check if localStorage is empty
/* if(localStorage.getItem(FORM_STORAGE_KEY) === null)
return; */
// Restaurer les données au chargement
const restored = restoreFormData();
// Configurer la sauvegarde automatique
setupAutoSave();
// Effacer les données après soumission réussie (optionnel)
jQuery(document).on('formSubmitted', function() {
clearFormData();
});
// Si des données ont été restaurées, initialiser l'affichage des zones conditionnelles
if (restored) {
setTimeout(function() {
initializePreFilledValues();
}, 200);
}
// Afficher le message d'information
showLocalStorageInfo();
console.log('Système de sauvegarde localStorage initialisé');
}
function hasCreditDirectToken() {
return window.location.search.includes('credit-direct-token');
}
// Initialiser le système de sauvegarde UNIQUEMENT si le paramètre est présent dans l'URL
// (déplacé après la définition des fonctions addCurrentLoan et addCoCurrentLoan)
if (hasCreditDirectToken()) {
}
/**
* General
*/
function empty(value) { return value == undefined || value == null || value == [] || value == ''; }
function makeLabelRequired(containerSelector = 'body') {
if (jQuery(containerSelector).length > 0) {
jQuery(containerSelector).find('input:required, select:required, textarea:required').each(function() {
var labelId = jQuery(this).attr('id');
var label = jQuery('label[for="' + labelId + '"]')
if (label.length > 0 && label.html().charAt(label.html().length - 1) !== '*') {
label.html(label.html() + '*')
}
})
}
}
// Marque les champs initialement requis pour pouvoir restaurer l'attribut required quand on ré-affiche une zone
function markInitialRequired(containerSelector) {
if (jQuery(containerSelector).length > 0) {
jQuery(containerSelector).find('input, select, textarea').each(function() {
var $el = jQuery(this);
if ($el.is('[required]')) {
$el.attr('data-initial-required', '1');
}
var pattern = $el.attr('pattern');
if (typeof pattern !== 'undefined' && pattern !== null && pattern !== '') {
$el.attr('data-initial-pattern', '1');
$el.attr('data-initial-pattern-value', pattern);
}
});
}
}
// Active/désactive l'attribut pattern pour les seuls champs date (input.input-date) du conteneur
function togglePatternForContainer($container, isVisible) {
if (!$container || $container.length === 0) { return; }
$container.find('input.input-date').each(function() {
var $el = jQuery(this);
var defaultDatePattern = '\\d{1,2}/\\d{1,2}/\\d{4}';
// Capture paresseuse du pattern initial si non marqué mais présent
var currentPattern = $el.attr('pattern');
if (!$el.attr('data-initial-pattern') && typeof currentPattern !== 'undefined' && currentPattern !== '') {
$el.attr('data-initial-pattern', '1');
$el.attr('data-initial-pattern-value', currentPattern);
}
if (isVisible) {
if ($el.attr('data-initial-pattern') === '1') {
$el.attr('pattern', $el.attr('data-initial-pattern-value'));
} else {
// Si aucun pattern initial, appliquer le pattern date par défaut
$el.attr('pattern', defaultDatePattern);
}
} else {
$el.removeAttr('pattern');
}
});
}
// Retire l'attribut required de tous les champs dans les sections cachées
// Cette fonction est appelée avant la soumission du formulaire pour éviter l'erreur
// "An invalid form control with name='...' is not focusable"
function removeRequiredFromHiddenFields() {
// Retirer required uniquement des champs qui sont VRAIMENT cachés (display:none ou visibility:hidden)
// Ne pas toucher aux champs visibles même s'ils ont la classe d-none (qui peut être retirée dynamiquement)
jQuery('input, select, textarea').each(function() {
var $field = jQuery(this);
var $fieldElement = $field[0];
// Vérifier si le champ est vraiment caché (display:none ou dans un élément avec display:none)
var isReallyHidden = false;
// Vérifier d'abord si l'élément lui-même est caché
if ($fieldElement.offsetParent === null && $field.css('display') === 'none') {
isReallyHidden = true;
} else {
// Vérifier si un parent est caché avec display:none ou a la classe 'hidden'
var $parent = $field.parent();
while ($parent.length > 0 && !$parent.is('form') && !$parent.is('body')) {
// Ignorer les sections co-emprunteur qui pourraient être visibles
if ($parent.hasClass('wpcf-coborrower') || $parent.hasClass('co-borrower-section') || $parent.hasClass('co-emprunteur')) {
// Si la section co-emprunteur n'est pas vraiment cachée, ne pas retirer required
if ($parent.css('display') !== 'none' && $parent.is(':visible') && !$parent.hasClass('hidden')) {
break;
}
}
// Vérifier aussi la classe 'hidden' pour les sections comme independent_section
if ($parent.css('display') === 'none' || !$parent.is(':visible') || $parent.hasClass('hidden')) {
isReallyHidden = true;
break;
}
$parent = $parent.parent();
}
}
// Retirer required seulement si vraiment caché ET que ce n'est pas un champ du co-emprunteur visible
if (isReallyHidden) {
// Exception : ne pas retirer required des champs du co-emprunteur si celui-ci est activé
// et que la section est visible (même si elle a la classe d-none)
var hasCoBorrower = jQuery('input[name="hascoborrower"]:checked').length > 0 &&
jQuery('input[name="hascoborrower"]:checked').val() == '1';
if (hasCoBorrower) {
var $coSection = $field.closest('.wpcf-coborrower, .co-borrower-section, .co-emprunteur');
if ($coSection.length > 0) {
// Vérifier si la section co-emprunteur est visible malgré la classe d-none/hidden
if ($coSection.is(':visible') && $coSection.css('display') !== 'none' && !$coSection.hasClass('hidden')) {
// Vérifier aussi si le champ est dans une sous-section cachée (comme independent_section)
var $hiddenSubSection = $field.closest('.hidden');
if ($hiddenSubSection.length === 0) {
// Ne pas retirer required si la section est visible et pas dans une sous-section cachée
return;
}
}
}
}
$field.removeAttr('required');
}
});
}
if (jQuery('.wpcf-borrower').length > 0) {
makeLabelRequired('.wpcf-borrower')
} else {
makeLabelRequired('.form-submit')
}
// Enregistrer l'état initial des champs requis/pattern (global + zones clés)
markInitialRequired('.form-submit');
markInitialRequired('.co-borrower-section');
markInitialRequired('.wpcf-coborrower');
markInitialRequired('.isIndependant');
/**
* Step 2
*/
function changeJobLabels(value, container) {
var jobLabels = {
independent: {
factory: 'de l\'entreprise',
salary: 'Revenu imposable annuel',
startDate: 'de début d\'activité'
},
withoutEmployer: {
employer: 'de l\'employeur/organisme de paiement',
salary: 'Indemnités mensuelles',
startDate: 'd\'engagement'
},
withEmployer: {
employer: 'de l\'employeur/organisme de paiement',
salary: 'Salaire net mensuel',
startDate: 'd\'engagement'
}
}, job = {
independent: 5,
withoutEmployer: ['1','6','9','12']
};
console.log('job', value, job.independent);
var prefix = container.find('#IDcofirstname').length > 0 ? 'co' : ''
var fields = ['emname', 'emaddress', 'emzip', 'emcity', 'emcountry', 'commitmentdate', 'salary']
fields.forEach(id => {
var labelText = null
switch (id) {
case 'commitmentdate':
if(value === job.independent) {
labelText = jobLabels.independent.startDate
} else if(job.withoutEmployer.includes(value)) {
labelText = jobLabels.withoutEmployer.startDate
} else {
labelText = jobLabels.withEmployer.startDate
}
break;
case 'salary':
if(value === job.independent) {
labelText = jobLabels.independent.salary
} else if(job.withoutEmployer.includes(value)) {
labelText = jobLabels.withoutEmployer.salary
} else {
labelText = jobLabels.withEmployer.salary
}
break;
default:
if(value === job.independent) {
labelText = jobLabels.independent.factory
} else if(job.withoutEmployer.includes(value)) {
labelText = jobLabels.withoutEmployer.employer
} else {
labelText = jobLabels.withEmployer.employer
}
break;
}
container.find('label[for="ID' + prefix + id + '"] > span').text(labelText);
console.log('labelText', labelText);
});
/* console.log('container', container);
console.log('prefix', container.find('.'+prefix+'independent_section')); */
console.log('value', value);
excludedFields = ['IDnotice_of_assessment', 'IDpaycheck', 'IDcopaycheck', 'IDconotice_of_assessment'];
if(value == job.independent) {
container.find('.'+prefix+'independent_section').fadeIn().removeClass('hidden');
//remove required attributes
container.find('.'+prefix+'employee_section').find('input, select').removeAttr('required');
container.find('.'+prefix+'employee_section').fadeOut().addClass('hidden');
container.find('.'+prefix+'independent_section').find('input, select').each(function() {
var fieldId = jQuery(this).attr('id');
if (excludedFields.indexOf(fieldId) === -1) {
jQuery(this).attr('required', true);
}
});
// Patterns: visible sur independent_section, masqué sur employee_section
togglePatternForContainer(container.find('.'+prefix+'independent_section'), true);
togglePatternForContainer(container.find('.'+prefix+'employee_section'), false);
} else if(job.withoutEmployer.includes(value)) {
container.find('.withemployer_section').fadeOut().addClass('hidden');
container.find('.withemployer_section').find('input, select').removeAttr('required');
togglePatternForContainer(container.find('.withemployer_section'), false);
// Retirer aussi required des champs de la section indépendant (cas où on passe de indépendant à sans employeur)
container.find('.'+prefix+'independent_section').fadeOut().addClass('hidden');
container.find('.'+prefix+'independent_section').find('input, select').removeAttr('required');
togglePatternForContainer(container.find('.'+prefix+'independent_section'), false);
console.log((jobLabels.withoutEmployer.salary));
/* container.find('.'+prefix+'IDsalary').prev().text(jobLabels.withoutEmployer.salary);
console.log(container.find('#'+prefix+'IDsalary').prev()); */
} else {
container.find('.'+prefix+'independent_section').fadeOut().addClass('hidden');
//not input field required
container.find('.'+prefix+'employee_section').find('input:not([type="file"]), select').attr('required', true);
container.find('.'+prefix+'employee_section').fadeIn().removeClass('hidden');
//except file inputs
container.find('.'+prefix+'independent_section').find('input, select').removeAttr('required');
if(jQuery('.withemployer_section').hasClass('hidden')) {
jQuery('.withemployer_section').fadeIn().removeClass('hidden');
jQuery('.withemployer_section').find('input, select').attr('required', true);
togglePatternForContainer(jQuery('.withemployer_section'), true);
}
// Patterns: visible sur employee_section, masqué sur independent_section
togglePatternForContainer(container.find('.'+prefix+'employee_section'), true);
togglePatternForContainer(container.find('.'+prefix+'independent_section'), false);
}
container
.find('#ID' + prefix + 'emnumber')
.attr('required', value === job.independent)
.parent()
.toggleClass('d-none', value !== job.independent)
makeLabelRequired()
}
// Ajouter un gestionnaire sur les boutons submit pour retirer required AVANT la validation HTML5
jQuery('body').on('click', '.form-submit button[type="submit"]', function(e) {
// Retirer l'attribut required de tous les champs dans les sections cachées
// AVANT la validation HTML5 pour éviter l'erreur "not focusable"
removeRequiredFromHiddenFields();
});
function displayCoBorrower() {
// Éviter les exécutions multiples
if (displayCoBorrower._isRunning) {
return;
}
displayCoBorrower._isRunning = true;
var
excludedFieldsName = [
'cocontract_type',
'coemname',
'coemaddress',
'coemzip',
'coemcity',
'coemcountry',
'cocommitmentdate',
'cooiamouthmealvoucher',
'cooiamouthrentalincome',
'cooiamouthunemployment',
'cooiamouthother',
'cooiothertext',
'co_secteur_activite',
'co_num_tva',
'coMtn_loyer',
'coHabitation_loyer'
],
hasCoBorrower =
jQuery('input[name="hascoborrower"]:checked').length > 0 &&
jQuery('input[name="hascoborrower"]:checked').val() == 1,
key = '.wpcf-coborrower',
cols_key = '.credit-cols';
console.log('hasCoBorrower', hasCoBorrower);
// Gestion de l'affichage/masquage
jQuery(key).toggleClass('d-none', !hasCoBorrower);
jQuery('.co-borrower-section').toggleClass('d-none', !hasCoBorrower);
// Note: .co-emprunteur est géré dans cd_main.js pour le formulaire one-step
// Gérer l'attribut required/pattern en fonction de la visibilité
var coContainers = jQuery(key).add('.co-borrower-section');
var cojobValue = jQuery('select[name="cojob"]').val();
var isCojobIndependent = cojobValue === '5';
if (hasCoBorrower) {
coContainers.find('input, select, textarea').each(function() {
var wasRequired = jQuery(this).attr('data-initial-required') === '1';
if (wasRequired) {
jQuery(this).attr('required', true);
} else {
jQuery(this).removeAttr('required');
}
});
// Gestion des patterns selon le statut indépendant du cojob
// Activer les patterns pour tous les conteneurs sauf co-independent_section / coindependent_section
togglePatternForContainer(coContainers.not('.co-independent_section, .coindependent_section'), true);
// Pour co-independent_section / coindependent_section, activer le pattern uniquement si cojob = 5
if (isCojobIndependent) {
togglePatternForContainer(jQuery('.co-independent_section, .coindependent_section'), true);
} else {
togglePatternForContainer(jQuery('.co-independent_section, .coindependent_section'), false);
}
} else {
coContainers.find('input, select, textarea').removeAttr('required');
togglePatternForContainer(coContainers, false);
}
makeLabelRequired();
// Gestion des colonnes
if (hasCoBorrower) {
// Mode deux colonnes
jQuery(cols_key).removeClass('col-md-12').addClass('col-md-6');
// Ajuster les colonnes internes
jQuery('.credit-cols [class*="col-md-"]').each(function() {
var classes = jQuery(this).attr('class').split(' ');
classes.forEach(function(className) {
if (className.startsWith('col-md-')) {
var currentSize = parseInt(className.replace('col-md-', ''));
console.log('currentSize', currentSize);
// Sauvegarder la taille originale si ce n'est pas déjà fait
if (!jQuery(this).data('original-size')) {
jQuery(this).data('original-size', className);
}
// Définir la nouvelle taille
jQuery(this).removeClass(className).addClass('col-md-12');
}
}.bind(this));
});
// Ajuster spécifiquement les colonnes dans .other-credit-cols et ses sous-éléments
jQuery('.other-credit-cols').find('[class*="col-md-"]').each(function() {
var classes = jQuery(this).attr('class').split(' ');
classes.forEach(function(className) {
if (className.startsWith('col-md-')) {
var currentSize = parseInt(className.replace('col-md-', ''));
console.log('currentSize other-credit-cols', currentSize);
// Sauvegarder la taille originale si ce n'est pas déjà fait
if (!jQuery(this).data('original-size')) {
jQuery(this).data('original-size', className);
}
// Définir la nouvelle taille pour .other-credit-cols et ses sous-éléments
jQuery(this).removeClass(className).addClass('col-md-6');
}
}.bind(this));
});
} else {
// Mode une colonne
jQuery('.credit-cols .wpcf-borrower').removeClass('col-md-6');
if(!jQuery(cols_key).hasClass('col-md-12'))
jQuery(cols_key).addClass('col-md-12').removeClass('col-md-6');
// Restaurer les colonnes internes à leur taille d'origine
jQuery('.credit-cols [class*="col-md-"]').each(function() {
var originalSize = jQuery(this).data('original-size');
if (originalSize) {
// Supprimer toutes les classes col-md-* actuelles
var classes = jQuery(this).attr('class').split(' ');
classes.forEach(function(className) {
if (className.startsWith('col-md-')) {
jQuery(this).removeClass(className);
}
}.bind(this));
// Restaurer la taille originale
jQuery(this).addClass(originalSize);
}
});
// Pour .other-credit-cols, forcer une taille appropriée même sans co-emprunteur
jQuery('.other-credit-cols').find('[class*="col-md-"]').each(function() {
// Supprimer toutes les classes col-md-* actuelles
var classes = jQuery(this).attr('class').split(' ');
classes.forEach(function(className) {
if (className.startsWith('col-md-')) {
jQuery(this).removeClass(className);
}
}.bind(this));
// Toujours appliquer col-md-6 pour .other-credit-cols, même sans co-emprunteur
jQuery(this).addClass('col-md-6');
});
}
// Gestion des champs requis
jQuery(key).find('input[type="text"], input[type="number"], input[type="date"], select, textarea').each(function() {
if (excludedFieldsName.indexOf(jQuery(this).attr('name')) < 0) {
jQuery(this).attr('required', hasCoBorrower)
}
})
if (!hasCoBorrower) {
jQuery(key).find('input[type="checkbox"]:checked, input[type="radio"][value="0"]').each(function() {
jQuery(this).prop('checked', jQuery(this).attr('type') === 'radio')
})
jQuery(key).find('input:not([type="checkbox"]):not([type="radio"]), select, textarea').each(function() {
jQuery(this).val('')
})
}
makeLabelRequired(key)
// Afficher les autres revenus si nécessaire (même si cojob = 5)
displayOtherIncome(
hasCoBorrower && jQuery('input[name="cohasotherincome"]:checked').length > 0 && jQuery('input[name="cohasotherincome"]:checked').val() == 1,
'.co'
);
// Réinitialiser le flag après un court délai
setTimeout(function() {
displayCoBorrower._isRunning = false;
}, 50);
}
function displayOtherIncome(show, key) {
var target = jQuery('.wpcf-otherincome' + key)
if (target.length > 0) {
target.toggleClass('d-none', !show);
if (!show) {
target.find('input[type="checkbox"]:checked, input[type="radio"][value="0"]').each(function() {
jQuery(this).prop('checked', jQuery(this).attr('type') === 'radio')
})
}
displayOtherIncomeSubFields(target.find('input[type="checkbox"], input[type="radio"]:checked'))
}
}
function displayOtherIncomeSubFields(el) {
el.each(function() {
var subFields = jQuery(this).closest('.form-row').find('.form-group')
if (subFields.length > 0) {
subFields.toggleClass('d-none', !jQuery(this).is(':checked'))
subFields.find('input').attr('required', jQuery(this).is(':checked'))
}
})
}
function initializePreFilledValues() {
// Gérer l'affichage des sections basé sur les valeurs pré-remplies
setTimeout(function() {
// Vérifier si hascoborrower est pré-rempli
var hasCoBorrowerChecked = jQuery('input[name="hascoborrower"]:checked');
if (hasCoBorrowerChecked.length > 0) {
displayCoBorrower();
}
// Vérifier si hasotherincome est pré-rempli (emprunteur)
var hasOtherIncomeChecked = jQuery('input[name="hasotherincome"]:checked');
if (hasOtherIncomeChecked.length > 0) {
displayOtherIncome(hasOtherIncomeChecked.val() == 1, '.em');
}
// Vérifier si cohasotherincome est pré-rempli (co-emprunteur)
var coHasOtherIncomeChecked = jQuery('input[name="cohasotherincome"]:checked');
if (coHasOtherIncomeChecked.length > 0) {
displayOtherIncome(coHasOtherIncomeChecked.val() == 1, '.co');
}
// Vérifier si hascurrentloan est pré-rempli
var hasCurrentLoanChecked = jQuery('input[name="hascurrentloan"]:checked');
if (hasCurrentLoanChecked.length > 0) {
var isChecked = hasCurrentLoanChecked.val() == '1';
jQuery('.wpcf-currentloan').toggleClass('d-none', !isChecked);
}
// Vérifier si cohascurrentloan est pré-rempli
var coHasCurrentLoanChecked = jQuery('input[name="cohascurrentloan"]:checked');
if (coHasCurrentLoanChecked.length > 0) {
var isChecked = coHasCurrentLoanChecked.val() == '1';
jQuery('.wpcf-cocurrentloan').toggleClass('d-none', !isChecked);
}
// Gérer les champs autres revenus pré-remplis
jQuery('.wpcf-otherincome input[type="checkbox"]:checked').each(function() {
displayOtherIncomeSubFields(jQuery(this));
});
// Gérer les champs indépendant pré-remplis
var jobSelect = jQuery('select[name="job"]');
if (jobSelect.length > 0 && jobSelect.val()) {
changeJobLabels(jobSelect.val(), jobSelect.closest('fieldset'));
}
var coJobSelect = jQuery('select[name="cojob"]');
if (coJobSelect.length > 0 && coJobSelect.val()) {
changeJobLabels(coJobSelect.val(), coJobSelect.closest('fieldset'));
}
}, 100); // Petit délai pour s'assurer que le DOM est chargé
}
var hasCoBorrowerField = jQuery('input[name="hascoborrower"]:checked')
if (hasCoBorrowerField.length > 0) {
displayCoBorrower()
}
if (jQuery('input[name="hasotherincome"]:checked').length > 0) {
displayOtherIncome(jQuery('input[name="hasotherincome"]:checked').val() == 1, '.em')
}
// Initialisation pour les valeurs pré-remplies
initializePreFilledValues();
// Flag pour éviter les déclenchements multiples
var isProcessingJobChange = false;
jQuery('body').on('change', 'input[name="hascoborrower"]', function() {
// Éviter les déclenchements multiples quand cojob = 5
if (!isProcessingJobChange) {
displayCoBorrower();
}
});
jQuery('body').on('change', 'input[name="hasotherincome"]', function() {
displayOtherIncome(jQuery(this).val() == 1, '.em')
});
jQuery('body').on('change', 'input.wpcf-otherincome--oitype', function(e) {
displayOtherIncomeSubFields(jQuery(e.target))
});
jQuery('body').on('change', 'input[name="cohasotherincome"]', function() {
displayOtherIncome(jQuery(this).val() == 1, '.co')
});
jQuery('body').on('change', 'select[name="job"], select[name="cojob"]', function() {
var jobValue = jQuery(this).val();
var isCojob = jQuery(this).attr('name') === 'cojob';
var container = jQuery(this).closest('fieldset');
// Activer le flag pour éviter les déclenchements multiples
isProcessingJobChange = true;
// Appeler changeJobLabels
changeJobLabels(jobValue, container);
// Si c'est cojob, mettre à jour les patterns dans displayCoBorrower
if (isCojob) {
var hasCoBorrower = jQuery('input[name="hascoborrower"]:checked').length > 0 &&
jQuery('input[name="hascoborrower"]:checked').val() == 1;
if (hasCoBorrower) {
// Mettre à jour les patterns pour co-independent_section / coindependent_section selon la valeur
if (jobValue == '5') {
togglePatternForContainer(jQuery('.co-independent_section, .coindependent_section'), true);
} else {
togglePatternForContainer(jQuery('.co-independent_section, .coindependent_section'), false);
}
}
}
// Si c'est cojob et valeur = 5, éviter de déclencher displayCoBorrower en cascade
if (isCojob && jobValue == '5') {
// Attendre un peu avant de réactiver pour éviter les cascades
setTimeout(function() {
isProcessingJobChange = false;
}, 100);
} else {
isProcessingJobChange = false;
}
});
/**
* Step 3
*/
jQuery('body').on('change', 'select[name="hometype"], select[name="cohometype"]', function(e) {
var val = jQuery(this).val(),
c = 'd-none',
cname = 'wpcf-' + jQuery(this).attr('name') + '--complement-home' + val,
elements = jQuery('.wpcf-' + jQuery(this).attr('name') + '--complement .form-group');
elements.addClass(c);
elements.each(function() {
if (jQuery(this).hasClass(cname)) {
jQuery('.' + cname).removeClass(c);
}
jQuery(this).find('input, select').attr('required', !jQuery(this).hasClass(c))
// Synchroniser aussi le pattern avec la visibilité (comme required)
togglePatternForContainer(jQuery(this), !jQuery(this).hasClass(c))
makeLabelRequired(jQuery(this).context)
})
});
var currentLoanProto = jQuery('.wpcf-currentloan--block').length > 0 ? jQuery('.wpcf-currentloan--block') : null;
var currentLoanCount = 0;
if (currentLoanProto !== null) {
currentLoanProto.removeClass('wpcf-prototype');
currentLoanProto = currentLoanProto[0].outerHTML
jQuery('.wpcf-currentloan--block').remove()
}
var coCurrentLoanProto = jQuery('.wpcf-cocurrentloan--block').length > 0 ? jQuery('.wpcf-cocurrentloan--block') : null;
var coCurrentLoanCount = 0;
if (coCurrentLoanProto !== null) {
coCurrentLoanProto.removeClass('wpcf-prototype');
coCurrentLoanProto = coCurrentLoanProto[0].outerHTML
jQuery('.wpcf-cocurrentloan--block').remove()
}
jQuery('body').on('change', 'input[name="hascurrentloan"], input[name="cohascurrentloan"]', function(e) {
var selector = jQuery(this).attr('name') === 'hascurrentloan' ? '.wpcf-currentloan' : '.wpcf-cocurrentloan';
var elem = jQuery(selector),
c = 'd-none';
// Pour les radio, on vérifie la value sélectionnée
var isChecked = jQuery('input[name="' + jQuery(this).attr('name') + '"]:checked').val() == '1';
elem.toggleClass(c, !isChecked);
if (!isChecked) {
jQuery(this).attr('name') === 'hascurrentloan' ? jQuery('.wpcf-currentloan--block').remove() : jQuery('.wpcf-cocurrentloan--block').remove();
} else if (elem.find(selector + '--block').length < 1) {
jQuery(this).attr('name') === 'hascurrentloan' ? addCurrentLoan() : addCoCurrentLoan();
}
});
// Affichage initial au chargement de la page
function updateCurrentLoanVisibility() {
var isChecked = jQuery('input[name="hascurrentloan"]:checked').val() == '1';
jQuery('.wpcf-currentloan').toggleClass('d-none', !isChecked);
if (!isChecked) {
jQuery('.wpcf-currentloan--block').remove();
} else if (jQuery('.wpcf-currentloan--block').length < 1) {
addCurrentLoan();
}
var isCoChecked = jQuery('input[name="cohascurrentloan"]:checked').val() == '1';
jQuery('.wpcf-cocurrentloan').toggleClass('d-none', !isCoChecked);
if (!isCoChecked) {
jQuery('.wpcf-cocurrentloan--block').remove();
} else if (jQuery('.wpcf-cocurrentloan--block').length < 1) {
addCoCurrentLoan();
}
}
// Appel au chargement
updateCurrentLoanVisibility();
// Initialiser l'état des champs durationmonth et labels selon les types de prêt existants
function initializeDurationMonthFields() {
jQuery('.wpcf-currentloan--block, .wpcf-cocurrentloan--block').each(function() {
const $block = jQuery(this);
const $loanTypeField = $block.find('select[name*="loantype"]');
const $durationField = $block.find('input[name*="durationmonth"]');
const $borrowedCapitalField = $block.find('input[name*="borrowedcapital"]');
const $monthlyPaymentField = $block.find('input[name*="monthlypayment"]');
if ($loanTypeField.length > 0) {
const selectedValue = $loanTypeField.val();
// Gestion du champ durationmonth
if ($durationField.length > 0) {
if (selectedValue === '1') {
$durationField.prop('readonly', true);
$durationField.addClass('readonly-field');
} else {
$durationField.prop('readonly', false);
$durationField.removeClass('readonly-field');
}
}
// Gestion des labels borrowedcapital
if ($borrowedCapitalField.length > 0) {
const $borrowedCapitalLabel = $borrowedCapitalField.closest('.form-group').find('label');
if ($borrowedCapitalLabel.length > 0) {
if (selectedValue === '1') {
$borrowedCapitalLabel.text('Plafond de la carte');
} else {
$borrowedCapitalLabel.text('Capital emprunté');
}
}
}
// Gestion des labels monthlypayment
if ($monthlyPaymentField.length > 0) {
const $monthlyPaymentLabel = $monthlyPaymentField.closest('.form-group').find('label');
if ($monthlyPaymentLabel.length > 0) {
if (selectedValue === '1') {
$monthlyPaymentLabel.text('Remboursement mensuel');
} else {
$monthlyPaymentLabel.text('Mensualité');
}
}
}
}
});
}
// Initialiser au chargement de la page
initializeDurationMonthFields();
// Initialiser le système de sauvegarde après la définition des fonctions addCurrentLoan et addCoCurrentLoan
initFormStorage();
jQuery('body').on('click', 'button.wpcf-currentload--add, button.wpcf-cocurrentload--add', function(e) {
e.preventDefault()
jQuery(this).hasClass('wpcf-currentload--add') ? addCurrentLoan() : addCoCurrentLoan()
})
function addCurrentLoan() {
var newLoan = currentLoanProto.replaceAll('__number__', currentLoanCount)
jQuery(newLoan).insertBefore(jQuery('.wpcf-currentload--add'))
currentLoanCount++
// Déclencher l'événement personnalisé pour la sauvegarde
$(document).trigger('currentLoanAdded');
}
function addCoCurrentLoan() {
var newLoan = coCurrentLoanProto.replaceAll('__number__', coCurrentLoanCount)
jQuery(newLoan).insertBefore(jQuery('.wpcf-cocurrentload--add'))
coCurrentLoanCount++
// Déclencher l'événement personnalisé pour la sauvegarde
$(document).trigger('currentLoanAdded');
}
jQuery('body').on('click', '.wpcf-currentloan--block--remove, .wpcf-cocurrentloan--block--remove', function(e) {
e.preventDefault();
jQuery(this).parent().remove();
// Déclencher l'événement personnalisé pour la sauvegarde
$(document).trigger('currentLoanRemoved');
});
// Gestionnaire pour les champs de type de prêt des crédits en cours
jQuery('body').on('change', 'select[name*="loantype"]', function() {
const selectedValue = jQuery(this).val();
const $currentBlock = jQuery(this).closest('.wpcf-currentloan--block, .wpcf-cocurrentloan--block');
console.log('Type de prêt sélectionné:', selectedValue, 'dans le bloc:', $currentBlock);
// Gestion du champ durationmonth selon le type de prêt
const $durationField = $currentBlock.find('input[name*="durationmonth"]');
if ($durationField.length > 0) {
if (selectedValue === '1') {
// Si le type de prêt vaut "1", rendre le champ durationmonth readonly
$durationField.prop('readonly', true);
$durationField.addClass('readonly-field');
console.log('Champ durationmonth mis en readonly');
} else {
// Sinon, rendre le champ éditable
$durationField.prop('readonly', false);
$durationField.removeClass('readonly-field');
console.log('Champ durationmonth rendu éditable');
}
}
// Gestion des labels des champs borrowedcapital et monthlypayment
const $borrowedCapitalField = $currentBlock.find('input[name*="borrowedcapital"]');
const $monthlyPaymentField = $currentBlock.find('input[name*="monthlypayment"]');
if ($borrowedCapitalField.length > 0) {
const $borrowedCapitalLabel = $borrowedCapitalField.closest('.form-group').find('label');
if ($borrowedCapitalLabel.length > 0) {
if (selectedValue === '1') {
$borrowedCapitalLabel.text('Plafond de la carte');
} else {
$borrowedCapitalLabel.text('Capital emprunté');
}
}
}
if ($monthlyPaymentField.length > 0) {
const $monthlyPaymentLabel = $monthlyPaymentField.closest('.form-group').find('label');
if ($monthlyPaymentLabel.length > 0) {
if (selectedValue === '1') {
$monthlyPaymentLabel.text('Remboursement mensuel');
} else {
$monthlyPaymentLabel.text('Mensualité');
}
}
}
// Ici vous pouvez ajouter la logique spécifique selon le type de prêt sélectionné
// Par exemple, afficher/masquer d'autres champs selon le type
// Exemple de logique conditionnelle selon le type de prêt
switch(selectedValue) {
case '1': // Hypothèque
console.log('Prêt hypothécaire sélectionné');
// Logique spécifique pour les prêts hypothécaires
break;
case '2': // Prêt personnel
console.log('Prêt personnel sélectionné');
// Logique spécifique pour les prêts personnels
break;
case '3': // Crédit auto
console.log('Crédit auto sélectionné');
// Logique spécifique pour les crédits auto
break;
default:
console.log('Autre type de prêt sélectionné:', selectedValue);
break;
}
// Déclencher l'événement personnalisé pour la sauvegarde
$(document).trigger('currentLoanTypeChanged', {
value: selectedValue,
block: $currentBlock
});
});
// Fonction pour afficher/cacher la zone isFichedDisplay
function displayIsFichedZone() {
var hasFiched = jQuery('input[name="isFiched"]:checked').length > 0 &&
jQuery('input[name="isFiched"]:checked').val() == 1;
jQuery('.isFichedDisplay').toggleClass('d-none', !hasFiched);
}
// Vérifier l'état initial
var isFichedField = jQuery('input[name="isFiched"]:checked');
if (isFichedField.length > 0) {
displayIsFichedZone();
}
// Ajouter l'écouteur d'événement pour le changement
jQuery('body').on('change', 'input[name="isFiched"]', displayIsFichedZone);
// Fonction pour afficher/cacher la zone isIndependant
function displayIsIndependantZone() {
var isIndependant = jQuery('select[name="job"]').val() === '5';
var zone = jQuery('.isIndependant');
zone.toggleClass('d-none', !isIndependant);
// Gérer l'attribut required/pattern en fonction de la visibilité
if (isIndependant) {
zone.find('input, select, textarea').each(function() {
var wasRequired = jQuery(this).attr('data-initial-required') === '1';
if (wasRequired) {
jQuery(this).attr('required', true);
} else {
jQuery(this).removeAttr('required');
}
});
togglePatternForContainer(zone, true);
} else {
zone.find('input, select, textarea').removeAttr('required');
togglePatternForContainer(zone, false);
}
makeLabelRequired();
}
// Vérifier l'état initial
var jobSelect = jQuery('select[name="job"]');
if (jobSelect.length > 0) {
displayIsIndependantZone();
}
// Ajouter l'écouteur d'événement pour le changement
jQuery('body').on('change', 'select[name="job"]', displayIsIndependantZone);
// Fonction pour afficher/cacher la zone hasLoyer
function displayHasLoyerZone() {
var isLocataire = jQuery('select[name="habitation_type"]').val() === 'locataire';
jQuery('.hasLoyer').toggleClass('d-none', !isLocataire);
}
// Vérifier l'état initial
var situationSelect = jQuery('select[name="habitation_type"]');
if (situationSelect.length > 0) {
displayHasLoyerZone();
}
// Ajouter l'écouteur d'événement pour le changement
jQuery('body').on('change', 'select[name="habitation_type"]', displayHasLoyerZone);
// Affichage de la taille totale des fichiers sélectionnés pour le champ IDpaycheck + vérification taille max 2 Mo
jQuery('body').on('change', '#IDpaycheck, #IDcopaycheck', function(e) {
var files = e.target.files;
var totalSize = 0;
var maxSize = 2 * 1024 * 1024; // 2 Mo en octets
var errorFiles = [];
for (var i = 0; i < files.length; i++) {
totalSize += files[i].size;
if (files[i].size > maxSize) {
errorFiles.push(files[i].name);
}
}
// Conversion en Mo, arrondi à 2 décimales
var totalSizeMo = (totalSize / (1024 * 1024)).toFixed(2);
// Création ou sélection de l'élément d'affichage
var infoId = 'paycheck-size-info';
var infoElem = jQuery('#' + infoId);
if (infoElem.length === 0) {
infoElem = jQuery('');
jQuery(this).after(infoElem);
}
// Création ou sélection de l'élément d'erreur
var errorId = 'paycheck-size-error';
var errorElem = jQuery('#' + errorId);
if (errorElem.length === 0) {
errorElem = jQuery('');
infoElem.after(errorElem);
}
var submitBtn = jQuery('.form-submit button[type="submit"]');
if (files.length > 0) {
infoElem.text('Taille totale des fichiers sélectionnés : ' + totalSizeMo + ' Mo');
} else {
infoElem.text('');
}
if (errorFiles.length > 0) {
errorElem.html('Fichier(s) trop volumineux (> 2 Mo) : ' + errorFiles.join(', ') + '');
submitBtn.prop('disabled', true);
} else {
errorElem.text('');
submitBtn.prop('disabled', false);
}
});
// Affichage conditionnel du champ "fonds propres" selon le choix Oui/Non avec effet slide
const yesRadio = document.getElementById('estateequity_yes');
const noRadio = document.getElementById('estateequity_no');
if (yesRadio && noRadio) {
$(yesRadio).on('change', function() {
if (yesRadio.checked) {
$('.fonds-propres').stop(true, true).slideDown();
$('[name="estateequity"]').prop('required', true);
}
});
$(noRadio).on('change', function() {
if (noRadio.checked) {
$('.fonds-propres').stop(true, true).slideUp();
$('[name="estateequity"]').prop('required', false);
}
});
// Initialisation à l'ouverture de la page
if (yesRadio.checked) {
$('.fonds-propres').show();
} else {
$('.fonds-propres').hide();
}
}
// Variables pour le debouncing des inputs
let capitalTimeout;
let durationTimeout;
let isCreditCalculationEnabled = true;
if(jQuery('#creditCalcManualSwitch').length > 0)
isCreditCalculationEnabled = true;
// Liste des types de crédit qui utilisent des années
const LOAN_TYPES_IN_YEARS = ['am', 'amr', 'cied', 'ph'];
// Fonction pour mettre à jour l'affichage des valeurs calculées
function updateCreditDisplay(result) {
console.log('updateCreditDisplay - result:', result);
// Calcul du TAEG
const taeg = parseFloat(result.taux_nominal_annuel.replace('%', ''));
const taux_debiteur = (taeg * 0.11 + taeg).toFixed(2);
// Mise à jour des champs cachés
jQuery('input[name="capital"]').val(result.capital);
jQuery('input[name="duree"]').val(result.duree);
jQuery('input[name="cout_total"]').val(result.cout_total);
jQuery('input[name="mensualite"]').val(result.mensualite);
jQuery('input[name="taux_nominal_annuel"]').val(result.taux_nominal_annuel);
console.log('updateCreditDisplay - Champs cachés mis à jour:', {
capital: result.capital,
duree: result.duree,
cout_total: result.cout_total,
mensualite: result.mensualite,
taux: result.taux_nominal_annuel
});
// Mise à jour de l'affichage dans .credit-info
jQuery('.credit-info .credit-item').each(function() {
var $value = jQuery(this).find('.credit-value');
var $label = jQuery(this).find('.credit-label');
if($label.text().includes('Montant:')) {
$value.text(result.capital + ' €');
}
else if($label.text().includes('Durée:')) {
$value.text(result.duree + ($('input[name="type_credit"]').val() === 'am' ? ' ans' : ' mois'));
}
else if($label.text().includes('Mensualité:')) {
$value.text(result.mensualite + '€');
}
else if($label.text().includes('Coût total:')) {
$value.text(result.cout_total + '€');
}
else if($label.text().includes('TAEG:')) {
$value.text(taux_debiteur + '%');
}
else if($label.text().includes('Taux débiteur:')) {
$value.text(result.taux_nominal_annuel);
}
});
// Mise à jour du récapitulatif dans .info-credits-step
jQuery('.info-credits-step .row > div').each(function() {
$(this).find('p').each(function() {
var $label = $(this);
var $value = $label.next('span');
if($label.text().includes('Montant emprunté :')) {
$value.text(result.capital + ' €');
}
else if($label.text().includes('Durée :')) {
$value.text(result.duree + ($('input[name="type_credit"]').val() === 'am' ? ' ans' : ' mois'));
}
else if($label.text().includes('Mensualité :')) {
$value.text(result.mensualite + ' €');
}
else if($label.text().includes('Coût Total :')) {
$value.text(result.cout_total + ' €');
}
else if($label.text().includes('Taux débiteur :')) {
$value.text(result.taux_nominal_annuel);
}
else if($label.text().includes('Taeg :')) {
$value.text(taux_debiteur + '%');
}
});
});
console.log('updateCreditDisplay - Affichage mis à jour');
}
// Fonction pour mettre à jour les limites et valeurs des champs selon le type de crédit
function updateFieldLimits(selectedType) {
const creditType = map_values[selectedType];
if (!creditType) {
console.warn('Type de crédit non reconnu:', selectedType);
return;
}
const $capitalField = jQuery('#IDbatiment_emprunt');
const $durationField = jQuery('#IDbatiment_duree');
let currentCapital = parseFloat($capitalField.val());
// Récupérer les limites depuis form_sliders pour les durées
const sliderConfig = form_sliders[creditType];
if (!sliderConfig) {
console.warn('Configuration slider non trouvée pour:', creditType);
return;
}
// Récupérer les limites spécifiques du crédit depuis cd_js.groups
const creditConfig = cd_js.groups[selectedType];
if (creditConfig && creditConfig.capital_max) {
// Ne modifier le montant que s'il dépasse la limite du crédit choisi
if (currentCapital > creditConfig.capital_max) {
currentCapital = creditConfig.capital_selected || creditConfig.capital_max;
$capitalField.val(currentCapital);
}
}
// Mettre à jour les attributs min/max du champ capital
$capitalField.attr('min', sliderConfig.capital_min);
$capitalField.attr('max', sliderConfig.capital_max);
$capitalField.attr('step', sliderConfig.capital_step || 100);
// Ajuster la valeur du capital si nécessaire selon les limites du slider
if (currentCapital > sliderConfig.capital_max) {
currentCapital = sliderConfig.capital_max;
$capitalField.val(currentCapital);
} else if (currentCapital < sliderConfig.capital_min) {
currentCapital = sliderConfig.capital_min;
$capitalField.val(currentCapital);
}
// Déterminer la durée maximale disponible pour ce montant
const isYearlyDuration = LOAN_TYPES_IN_YEARS.includes(creditType);
let maxDurationForAmount = sliderConfig.durees[sliderConfig.durees.length - 1];
// Parcourir les durées disponibles dans l'ordre décroissant
for (let i = sliderConfig.durees.length - 1; i >= 0; i--) {
const duration = sliderConfig.durees[i];
// Vérifier si cette durée est valide pour le montant actuel
if (currentCapital >= sliderConfig.capital_min && currentCapital <= sliderConfig.capital_max) {
maxDurationForAmount = duration;
break;
}
}
// Convertir la durée maximale en années si nécessaire
const displayDuration = isYearlyDuration ? Math.floor(maxDurationForAmount / 12) : maxDurationForAmount;
const minDuration = isYearlyDuration ? Math.ceil(sliderConfig.duree_min / 12) : sliderConfig.duree_min;
const maxDuration = isYearlyDuration ? Math.floor(sliderConfig.duree_max / 12) : sliderConfig.duree_max;
// Mettre à jour les attributs min/max du champ durée
$durationField.attr('min', minDuration);
$durationField.attr('max', maxDuration);
// Définir la durée maximale disponible
$durationField.val(displayDuration);
// Mettre à jour l'unité dans l'input-group-text
jQuery('.input-group-text').text(isYearlyDuration ? 'Ans' : 'Mois');
// Mettre à jour l'affichage
calculateCredit();
// Mettre à jour le champ caché type_credit
jQuery('input[name="type_credit"]').val(creditType);
}
// Gestionnaire pour le changement de type de crédit
jQuery('#IDestateloantype').on('change', function() {
const creditType = jQuery(this).val();
if (creditType) {
updateFieldLimits(creditType);
calculateCredit();
}
});
// Fonction pour arrondir le capital à la valeur acceptable la plus proche
function snapCapitalValue(value, creditType) {
if (!creditType || !form_sliders[creditType]) {
return value;
}
const sliderConfig = form_sliders[creditType];
// Utiliser le step défini dans form_sliders
const step = sliderConfig.capital_step || 100;
// S'assurer que la valeur est dans les limites
value = Math.max(sliderConfig.capital_min, Math.min(value, sliderConfig.capital_max));
// Arrondir à la valeur la plus proche selon le step
return Math.round(value / step) * step;
}
// Fonction pour arrondir la durée à la valeur acceptable la plus proche
function snapDurationValue(value, creditType) {
if (!creditType || !form_sliders[creditType]) {
return value;
}
const sliderConfig = form_sliders[creditType];
const isYearlyDuration = LOAN_TYPES_IN_YEARS.includes(creditType);
console.log('snapDurationValue - value:', value);
console.log('snapDurationValue - creditType:', creditType);
console.log('snapDurationValue - isYearlyDuration:', isYearlyDuration);
if (isYearlyDuration) {
// Pour les crédits en années, on vérifie juste les limites min/max
// Les limites sont déjà en années pour ces types de crédit
const minYears = sliderConfig.duree_min;
const maxYears = sliderConfig.duree_max;
console.log('snapDurationValue - minYears:', minYears);
console.log('snapDurationValue - maxYears:', maxYears);
if (value > maxYears) return maxYears;
if (value < minYears) return minYears;
return value;
} else {
// Pour les autres crédits, on cherche la durée disponible la plus proche
let closestDuration = sliderConfig.durees[0];
let minDiff = Math.abs(value - sliderConfig.durees[0]);
for (let i = 1; i < sliderConfig.durees.length; i++) {
const diff = Math.abs(value - sliderConfig.durees[i]);
if (diff < minDiff) {
minDiff = diff;
closestDuration = sliderConfig.durees[i];
}
}
return closestDuration;
}
}
// Fonction pour calculer la mensualité
function calc_mens(mnt, dur, taeg) {
const creditType = jQuery('input[name="type_credit"]').val();
// Pour le crédit pont, on ne calcule que les intérêts mensuels
if (creditType === 'cdp') {
const t100 = taeg / 100;
// Calcul des intérêts mensuels uniquement : (capital * taux_annuel) / 12
const mens = (mnt * t100) / 12;
return Math.floor(mens * 100) / 100;
}
// Pour les autres types de crédit, calcul normal
const t100 = taeg / 100;
const t101 = 1 + t100;
const d12 = 1 / 12;
const dur12 = dur / 12;
const buf1 = Math.pow(t101, d12);
const buf2 = Math.pow(1 / t101, dur12);
const mens = (mnt * (buf1 - 1)) / (1 - buf2);
return Math.floor(mens * 100) / 100;
}
// Notre propre fonction de calcul qui utilise les fonctions de base de cd_main.js
function calculateCredit() {
const capital = parseFloat(jQuery('#IDbatiment_emprunt').val());
const duration = parseInt(jQuery('#IDbatiment_duree').val());
const selectedType = jQuery('#IDestateloantype').val();
const creditType = map_values[selectedType];
console.log('=== Début calcul crédit ===');
console.log('Type sélectionné:', selectedType);
console.log('Type de crédit mappé:', creditType);
console.log('Capital:', capital);
console.log('Durée:', duration);
if (isNaN(capital) || isNaN(duration) || !creditType) {
console.warn('Valeurs invalides pour le calcul:', {
capital: isNaN(capital) ? 'invalide' : capital,
duration: isNaN(duration) ? 'invalide' : duration,
selectedType,
creditType: !creditType ? 'non mappé' : creditType
});
return;
}
// Convertir la durée en mois si nécessaire pour les calculs
const isYearlyDuration = LOAN_TYPES_IN_YEARS.includes(creditType);
const durationForCalculation = isYearlyDuration ? duration * 12 : duration;
console.log('Durée pour calcul:', durationForCalculation, isYearlyDuration ? '(en années)' : '(en mois)');
let results;
// Appeler la fonction de calcul appropriée
switch(creditType) {
case 'pat':
results = calculate_pat(capital, duration);
break;
case 'am':
results = calculate_am(capital, duration);
break;
case 'ph':
results = calculate_ph(capital, duration);
break;
case 'amr':
case 'cdp':
case 'cied':
results = calculate_mono_rate_bt_10_30(creditType, capital, duration);
break;
case 'fin_neuve':
results = calculate_fin_neuve(capital, duration);
break;
case 'fin_occ_m3a':
results = calculate_pao_m_3(capital, duration);
break;
case 'fin_occ_p3a':
results = calculate_pao_p_3(capital, duration);
break;
case 'mobil_carav':
results = calculate_mobilhome(capital, duration);
break;
case 'regroup_cred':
results = calculate_regroupement_de_credit(capital, duration);
break;
case 'frais_notaire':
results = calculate_frais_notaire(capital, duration);
break;
case 'but_immo':
results = calculate_but_immo(capital, duration);
break;
default:
console.warn('Type de crédit non reconnu:', creditType);
results = calculate_pat(capital, duration);
}
if (!results) {
console.warn('Pas de résultats retournés par la fonction de calcul');
return;
}
console.log('Résultats bruts:', results);
// Extraire les valeurs des résultats
const [min_duration, max_duration, selected_duration, duree_in_range, taux_nominal] = results;
// Convertir le taux en nombre si c'est une chaîne
const taux = parseFloat(String(taux_nominal).replace('%', ''));
if (isNaN(taux)) {
console.error('Taux nominal invalide après conversion:', {
original: taux_nominal,
converti: taux
});
return;
}
console.log('Taux nominal (débiteur):', taux + '%');
console.log('Durée sélectionnée:', selected_duration, isYearlyDuration ? 'mois (convertie)' : 'mois');
// Pour les crédits en années, la durée retournée est déjà en mois
const durationInMonths = isYearlyDuration ? durationForCalculation : selected_duration;
// Calculer la mensualité avec notre fonction locale
const mensualite = calc_mens(capital, durationInMonths, taux);
if (isNaN(mensualite)) {
console.error('Erreur dans le calcul de la mensualité:', {
capital,
durationInMonths,
taux
});
return;
}
const cout_total = (mensualite * durationInMonths).toFixed(2);
console.log('Mensualité calculée:', mensualite.toFixed(2) + '€');
console.log('Coût total calculé:', cout_total + '€');
// Créer l'objet result pour updateCreditDisplay
const displayResult = {
capital: capital,
duree: duration,
mensualite: mensualite.toFixed(2),
cout_total: cout_total,
taux_nominal_annuel: taux.toFixed(2) + ' %',
taux_debiteur: taux.toFixed(2) + ' %'
};
console.log('Résultat final pour affichage:', displayResult);
console.log('--- Fin calcul crédit ---');
// Mettre à jour l'affichage
updateCreditDisplay(displayResult);
// Mettre à jour le champ caché type_credit
jQuery('input[name="type_credit"]').val(creditType);
}
if(isCreditCalculationEnabled) {
// Remplacer tous les appels à calculate_mensualite par calculateCredit
jQuery('#IDbatiment_emprunt')
.on('input', function() {
const $this = jQuery(this);
clearTimeout(capitalTimeout);
if ($this.val() !== '') {
capitalTimeout = setTimeout(() => {
let capital = parseFloat($this.val());
if (!isNaN(capital)) {
const creditType = jQuery('input[name="type_credit"]').val();
const snappedValue = snapCapitalValue(capital, creditType);
if (snappedValue !== capital) {
$this.val(snappedValue);
}
calculateCredit();
}
}, 500); // Délai un peu plus long pour laisser le temps de taper
}
})
.on('change', function() {
// Validation finale quand on quitte le champ (onblur)
const $this = jQuery(this);
if ($this.val() !== '') {
let capital = parseFloat($this.val());
if (!isNaN(capital)) {
const selectedType = jQuery('#IDestateloantype').val();
const creditConfig = cd_js.groups[selectedType];
// Vérifier les limites du crédit
if (creditConfig && creditConfig.capital_max && capital > creditConfig.capital_max) {
capital = creditConfig.capital_selected || creditConfig.capital_max;
$this.val(capital);
}
// Snap à la valeur la plus proche et recalcul
const creditType = jQuery('input[name="type_credit"]').val();
const snappedValue = snapCapitalValue(capital, creditType);
if (snappedValue !== capital) {
$this.val(snappedValue);
}
calculateCredit();
}
}
});
jQuery('#IDbatiment_duree')
.on('input', function() {
const $this = jQuery(this);
clearTimeout(durationTimeout);
durationTimeout = setTimeout(() => {
let duration = parseInt($this.val());
if (!isNaN(duration)) {
const creditType = jQuery('input[name="type_credit"]').val();
console.log('Input duration:', duration);
console.log('Credit type:', creditType);
console.log('Is yearly:', LOAN_TYPES_IN_YEARS.includes(creditType));
// Ne pas snapper pendant la saisie pour les crédits en années
if (LOAN_TYPES_IN_YEARS.includes(creditType)) {
calculateCredit();
} else {
const snappedValue = snapDurationValue(duration, creditType);
if (snappedValue !== duration) {
$this.val(snappedValue);
}
calculateCredit();
}
}
}, 300);
})
.on('change', function() {
let duration = parseInt($(this).val());
if (!isNaN(duration)) {
const creditType = jQuery('input[name="type_credit"]').val();
console.log('onchange - creditType:', creditType);
console.log('onchange - LOAN_TYPES_IN_YEARS:', LOAN_TYPES_IN_YEARS);
console.log('onchange - includes?', LOAN_TYPES_IN_YEARS.includes(creditType));
if (LOAN_TYPES_IN_YEARS.includes(creditType)) {
console.log('change', duration);
const snappedValue = snapDurationValue(duration, creditType);
console.log('snappedValue', snappedValue);
if (snappedValue !== duration) {
$(this).val(snappedValue);
}
} else {
// Pour les autres crédits, comportement normal
const snappedValue = snapDurationValue(duration, creditType);
if (snappedValue !== duration) {
$(this).val(snappedValue);
}
}
calculateCredit();
}
});
// Calcul initial au chargement
/* $(document).ready(function() {
const creditType = $('input[name="type_credit"]').val();
if (creditType) {
updateFieldLimits(creditType);
calculateCredit();
}
}); */
// Gestionnaire pour la soumission du formulaire - s'exécute AVANT la validation HTML5
jQuery('.form-submit').on('submit', function(e) {
// Retirer l'attribut required de tous les champs dans les sections cachées
// AVANT la validation HTML5 pour éviter l'erreur "not focusable"
removeRequiredFromHiddenFields();
// Recalculer une dernière fois avant l'envoi
calculateCredit();
// Laisser le formulaire se soumettre normalement après avoir retiré les required des champs cachés
});
}
function findRate(type) {
console.log('findRate - Type recherché:', type);
let rate;
switch(type) {
case 'amr':
rate = cd_js.groups.achat_maison_de_rapport.de_10_a_30_ans;
break;
case 'cdp':
rate = cd_js.groups.credit_pont.de_10_a_30_ans;
break;
case 'cied':
rate = cd_js.groups.independants_et_entreprises_en_difficultes.de_10_a_30_ans;
break;
default:
console.warn('Type de crédit non reconnu pour le taux mono:', type);
rate = null;
}
console.log('findRate - Taux trouvé:', rate);
return rate;
}
function calculate_mono_rate_bt_10_30(type, selected_capital, selected_duration) {
const annual_rate = findRate(type);
if (!annual_rate) {
console.error('Taux non trouvé pour le type:', type);
return null;
}
const min_duration = 10;
const max_duration = 30;
let duree_in_range = true;
const add_message = '';
if (min_duration <= parseInt(selected_duration) && parseInt(selected_duration) <= max_duration) {
// La durée est dans la plage
} else {
duree_in_range = false;
selected_duration = max_duration;
}
// Convertir la durée en mois pour le calcul
selected_duration = selected_duration * 12;
return [min_duration, max_duration, selected_duration, duree_in_range, annual_rate, add_message];
}
});
// --- Changement dynamique du label Numéro de registre national selon la nationalité (emprunteur et co-emprunteur) ---
jQuery(function($) {
function setupNationalRegLabel(selectId, labelId) {
var defaultLabel = 'Numéro de registre national';
var luxLabel = 'Numéro de sécurité sociale';
var select = $('#' + selectId);
var labelSelector = 'label[for="' + labelId + '"]';
function updateLabel() {
var val = select.val();
if (val === 'LU') {
$(labelSelector).text(luxLabel);
} else {
$(labelSelector).text(defaultLabel);
}
}
select.on('change', updateLabel);
// Initialisation au chargement
updateLabel();
}
setupNationalRegLabel('IDnationality', 'IDnationalregistrationnumber');
setupNationalRegLabel('IDconationality', 'IDconationalregistrationnumber');
});
// --- Initialisation des Inputmasks pour les champs de date ---
jQuery(function($) {
// Initialisation des champs de date avec inputmask
jQuery('input[data-inputmask]').inputmask();
// Configuration spécifique pour tous les champs de date
jQuery('.input-date').inputmask({
mask: '99/99/9999',
placeholder: 'JJ/MM/AAAA',
clearMaskOnLostFocus: false,
showMaskOnHover: true,
showMaskOnFocus: true
});
});
if(jQuery('.etat-civil-pat').length > 0) {
// Variable pour tracker si le co-emprunteur a été forcé par l'état civil
let coBorrowerForcedByCivilStatus = false;
jQuery('#IDcivilstatus').on('change', function() {
let etatCivil = jQuery('#IDcivilstatus').val(),
switchValue = 4,
hascoborrower_input = jQuery('[name="hascoborrower"]'),
parent = hascoborrower_input.parents('fieldset'),
info = cd_js.info_pat;
if(etatCivil == switchValue) {
// État civil = 4 : forcer l'activation du co-emprunteur
hascoborrower_input[1].checked = true;
coBorrowerForcedByCivilStatus = true;
parent.append('
' + info + '
');
} else {
// État civil ≠ 4 : ne désactiver que si c'était précédemment forcé
if(coBorrowerForcedByCivilStatus) {
hascoborrower_input[0].checked = true;
coBorrowerForcedByCivilStatus = false;
parent.find('.alert').remove();
}
// Si ce n'était pas forcé, on laisse le choix de l'utilisateur
}
// Déclencher l'événement change sur le bouton radio pour activer displayCoBorrower
// Mais éviter les déclenchements multiples si cojob = 5
var cojobValue = jQuery('select[name="cojob"]').val();
if (cojobValue !== '5') {
jQuery('input[name="hascoborrower"]:checked').trigger('change');
} else {
// Si cojob = 5, appeler directement sans trigger pour éviter la cascade
displayCoBorrower();
}
});
// Réinitialiser le flag quand l'utilisateur change manuellement le co-emprunteur
jQuery('[name="hascoborrower"]').on('change', function() {
if(!jQuery('#IDcivilstatus').val() == 4) {
coBorrowerForcedByCivilStatus = false;
}
});
}