weather
This commit is contained in:
@@ -196,5 +196,28 @@ require __DIR__ . '/header.php';
|
|||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
window.I18N = {
|
||||||
|
...(window.I18N || {}),
|
||||||
|
'fc_menu_carole': "<?= tr('fc_menu_carole') ?>",
|
||||||
|
'btn_off': "<?= tr('btn_off') ?>",
|
||||||
|
'btn_extra': "<?= tr('btn_extra') ?>",
|
||||||
|
'leg_centre': "<?= tr('leg_centre') ?>",
|
||||||
|
'leg_avis': "<?= tr('leg_avis') ?>",
|
||||||
|
'leg_pep_sick': "<?= tr('leg_pep_sick') ?>",
|
||||||
|
'fc_menu_kids_leaves': "<?= tr('fc_menu_kids_leaves') ?>",
|
||||||
|
'fc_clear': "<?= tr('fc_clear') ?>",
|
||||||
|
'fc_unit_days': "<?= tr('fc_unit_days') ?>",
|
||||||
|
'vac_toussaint': "<?= tr('vac_toussaint') ?>",
|
||||||
|
'vac_noel': "<?= tr('vac_noel') ?>",
|
||||||
|
'vac_hiver': "<?= tr('vac_hiver') ?>",
|
||||||
|
'vac_printemps': "<?= tr('vac_printemps') ?>",
|
||||||
|
'vac_ascension': "<?= tr('vac_ascension') ?>",
|
||||||
|
'vac_ete': "<?= tr('vac_ete') ?>",
|
||||||
|
'leg_school_holidays': "<?= tr('leg_school_holidays') ?>",
|
||||||
|
'fc_school_year': "<?= tr('fc_school_year') ?>",
|
||||||
|
'fc_modal_holidays_title': "<?= tr('fc_modal_holidays_title') ?>"
|
||||||
|
};
|
||||||
|
</script>
|
||||||
<script src="/modules/family-calendar/family-calendar.js"></script>
|
<script src="/modules/family-calendar/family-calendar.js"></script>
|
||||||
<?php require __DIR__ . '/footer.php'; ?>
|
<?php require __DIR__ . '/footer.php'; ?>
|
||||||
@@ -206,6 +206,20 @@ return [
|
|||||||
'hdl_js_missing_dates_title'=> 'Dates mancants',
|
'hdl_js_missing_dates_title'=> 'Dates mancants',
|
||||||
'hdl_js_missing_dates_msg' => 'Cal definir una data d’arribada i sortida per organitzar la planificació.',
|
'hdl_js_missing_dates_msg' => 'Cal definir una data d’arribada i sortida per organitzar la planificació.',
|
||||||
'hdl_to_place' => 'Per situar',
|
'hdl_to_place' => 'Per situar',
|
||||||
|
'hdl_from' => 'Des del',
|
||||||
|
'hdl_to' => 'Fins al',
|
||||||
|
'hdl_btn_add_step' => 'Afegir una etapa',
|
||||||
|
'hdl_quick_edit_title' => 'Modificació ràpida',
|
||||||
|
'hdl_paid' => 'Pagat',
|
||||||
|
'weather_forecast' => 'Previsions meteorològiques',
|
||||||
|
'weather_not_available' => 'Temps no disponible',
|
||||||
|
'temp_max' => 'Temp. Màxima',
|
||||||
|
'weather_loading' => 'Carregant el temps...',
|
||||||
|
'weather_error' => 'Temps no disponible',
|
||||||
|
'weather_sunny' => 'Assolellat',
|
||||||
|
'weather_cloudy' => 'Ennuvolat',
|
||||||
|
'weather_rainy' => 'Plujós',
|
||||||
|
'weather_snowy' => 'Nevat',
|
||||||
|
|
||||||
// Anciennes clés Holidays non préfixées (conservades)
|
// Anciennes clés Holidays non préfixées (conservades)
|
||||||
'outbound_trip' => 'Anada',
|
'outbound_trip' => 'Anada',
|
||||||
@@ -373,6 +387,9 @@ return [
|
|||||||
'bud_reg_none' => 'Cap',
|
'bud_reg_none' => 'Cap',
|
||||||
'bud_recap_confirm_delete' => 'Segur que vols suprimir aquest element?',
|
'bud_recap_confirm_delete' => 'Segur que vols suprimir aquest element?',
|
||||||
'bud_err_delete' => 'Error en suprimir.',
|
'bud_err_delete' => 'Error en suprimir.',
|
||||||
|
'bud_sav_modal_title_add' => 'Introduir un mes',
|
||||||
|
'bud_sav_ph_name' => 'Nom (ex: Vacances)',
|
||||||
|
'bud_prev_label_name' => 'Nom',
|
||||||
|
|
||||||
// --- BUDGET : EPARGNE ---
|
// --- BUDGET : EPARGNE ---
|
||||||
'bud_sav_add_month' => 'Introduir un mes',
|
'bud_sav_add_month' => 'Introduir un mes',
|
||||||
|
|||||||
@@ -206,6 +206,20 @@ return [
|
|||||||
'hdl_js_missing_dates_title'=> 'Dates manquantes',
|
'hdl_js_missing_dates_title'=> 'Dates manquantes',
|
||||||
'hdl_js_missing_dates_msg' => 'Veuillez définir une date d’arrivée et de départ pour organiser le planning.',
|
'hdl_js_missing_dates_msg' => 'Veuillez définir une date d’arrivée et de départ pour organiser le planning.',
|
||||||
'hdl_to_place' => 'À placer',
|
'hdl_to_place' => 'À placer',
|
||||||
|
'hdl_from' => 'Du',
|
||||||
|
'hdl_to' => 'Au',
|
||||||
|
'hdl_btn_add_step' => 'Ajouter une étape',
|
||||||
|
'hdl_quick_edit_title' => 'Modification rapide',
|
||||||
|
'hdl_paid' => 'Payé',
|
||||||
|
'weather_forecast' => 'Prévisions météo',
|
||||||
|
'weather_not_available' => 'Météo indisponible',
|
||||||
|
'temp_max' => 'Temp. Max',
|
||||||
|
'weather_loading' => 'Chargement météo...',
|
||||||
|
'weather_error' => 'Météo indisponible',
|
||||||
|
'weather_sunny' => 'Ensoleillé',
|
||||||
|
'weather_cloudy' => 'Nuageux',
|
||||||
|
'weather_rainy' => 'Pluvieux',
|
||||||
|
'weather_snowy' => 'Neigeux',
|
||||||
|
|
||||||
// Anciennes clés Holidays non préfixées (conservées pour compatibilité si utilisées)
|
// Anciennes clés Holidays non préfixées (conservées pour compatibilité si utilisées)
|
||||||
'outbound_trip' => 'Aller',
|
'outbound_trip' => 'Aller',
|
||||||
@@ -438,6 +452,9 @@ return [
|
|||||||
'bud_prev_err_no_history' => 'Impossible : pas d\'historique disponible pour copier.',
|
'bud_prev_err_no_history' => 'Impossible : pas d\'historique disponible pour copier.',
|
||||||
'bud_prev_confirm_copy' => "Voulez-vous copier les données de %s vers %t ?\n\n⚠️ Cela écrasera toutes les valeurs déjà présentes pour %t.",
|
'bud_prev_confirm_copy' => "Voulez-vous copier les données de %s vers %t ?\n\n⚠️ Cela écrasera toutes les valeurs déjà présentes pour %t.",
|
||||||
'bud_prev_confirm_transfers' => "Confirmer que %p a bien effectué tous ses virements pour %m ?\n\nCela mettra à jour l'Épargne automatiquement.",
|
'bud_prev_confirm_transfers' => "Confirmer que %p a bien effectué tous ses virements pour %m ?\n\nCela mettra à jour l'Épargne automatiquement.",
|
||||||
|
'bud_sav_modal_title_add' => 'Saisir un mois',
|
||||||
|
'bud_sav_ph_name' => 'Nom (ex: Vacances)',
|
||||||
|
'bud_prev_label_name' => 'Nom',
|
||||||
|
|
||||||
// ==========================================
|
// ==========================================
|
||||||
// CADEAUX (GIFTS)
|
// CADEAUX (GIFTS)
|
||||||
|
|||||||
@@ -571,19 +571,22 @@ body.sum-mode-active .sum-target {
|
|||||||
<button onclick="toggleSumMode()" class="pf-sum-close" title="<?= tr('btn_close') ?>">×</button>
|
<button onclick="toggleSumMode()" class="pf-sum-close" title="<?= tr('btn_close') ?>">×</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
window.I18N = {
|
// --- 1. SÉCURISATION TRADUCTIONS ET LANGUE ---
|
||||||
...window.I18N,
|
window.appLang = document.documentElement.lang === "ca" ? "ca-ES" : "fr-FR";
|
||||||
|
window.I18N = {
|
||||||
|
...(window.I18N || {}),
|
||||||
|
'bud_prev_label_name': "<?= tr('bud_prev_label_name') ?>",
|
||||||
'bud_prev_err_no_history': "<?= tr('bud_prev_err_no_history') ?>",
|
'bud_prev_err_no_history': "<?= tr('bud_prev_err_no_history') ?>",
|
||||||
'bud_prev_confirm_copy': "<?= tr('bud_prev_confirm_copy') ?>",
|
'bud_prev_confirm_copy': "<?= tr('bud_prev_confirm_copy') ?>",
|
||||||
'bud_prev_confirm_transfers': "<?= tr('bud_prev_confirm_transfers') ?>",
|
'bud_prev_confirm_transfers': "<?= tr('bud_prev_confirm_transfers') ?>",
|
||||||
'bud_err_tech': "<?= tr('bud_err_tech') ?>"
|
'bud_err_tech': "<?= tr('bud_err_tech') ?>"
|
||||||
};
|
};
|
||||||
|
|
||||||
const currentLang = document.documentElement.lang === "ca" ? "ca-ES" : "fr-FR";
|
const currentYear = <?= $currentYear ?? 'new Date().getFullYear()' ?>;
|
||||||
</script>
|
const months = <?= json_encode($months ?? []) ?>;
|
||||||
|
|
||||||
<script>
|
|
||||||
function openEditModal(btn) {
|
function openEditModal(btn) {
|
||||||
const id = btn.getAttribute('data-id');
|
const id = btn.getAttribute('data-id');
|
||||||
const name = btn.getAttribute('data-name');
|
const name = btn.getAttribute('data-name');
|
||||||
@@ -599,9 +602,6 @@ function openEditModal(btn) {
|
|||||||
document.body.classList.add('no-scroll');
|
document.body.classList.add('no-scroll');
|
||||||
}
|
}
|
||||||
|
|
||||||
const currentYear = <?= $currentYear ?>;
|
|
||||||
const months = <?= json_encode($months) ?>;
|
|
||||||
|
|
||||||
function updateSalary(person, input) {
|
function updateSalary(person, input) {
|
||||||
const row = input.closest('tr');
|
const row = input.closest('tr');
|
||||||
const salary = parseFloat(row.querySelector('[data-field="salary"]').value) || 0;
|
const salary = parseFloat(row.querySelector('[data-field="salary"]').value) || 0;
|
||||||
@@ -611,7 +611,7 @@ function updateSalary(person, input) {
|
|||||||
const ecoF = parseFloat(row.querySelector('[data-field="eco_family"]').value) || 0;
|
const ecoF = parseFloat(row.querySelector('[data-field="eco_family"]').value) || 0;
|
||||||
|
|
||||||
const restant = salary - (mens + frais + ecoP + ecoF);
|
const restant = salary - (mens + frais + ecoP + ecoF);
|
||||||
document.getElementById('restant_' + person).innerText = Math.round(restant).toLocaleString(currentLang) + ' €';
|
document.getElementById('restant_' + person).innerText = Math.round(restant).toLocaleString(window.appLang) + ' €';
|
||||||
|
|
||||||
saveData('update_salary_config', { year: currentYear, person: person, field: input.dataset.field, value: input.value });
|
saveData('update_salary_config', { year: currentYear, person: person, field: input.dataset.field, value: input.value });
|
||||||
recalcAllAllocations();
|
recalcAllAllocations();
|
||||||
@@ -632,7 +632,7 @@ function duplicateMonth() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const formatMonth = (d) => {
|
const formatMonth = (d) => {
|
||||||
let str = new Date(d).toLocaleDateString(currentLang, { month: 'long', year: 'numeric' });
|
let str = new Date(d).toLocaleDateString(window.appLang, { month: 'long', year: 'numeric' });
|
||||||
return str.charAt(0).toUpperCase() + str.slice(1);
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -716,7 +716,6 @@ function recalcAllAllocations() {
|
|||||||
|
|
||||||
function updateSummaryTable() {
|
function updateSummaryTable() {
|
||||||
const focusMonth = months[0];
|
const focusMonth = months[0];
|
||||||
const sums = {};
|
|
||||||
let grandTotalAlex = 0;
|
let grandTotalAlex = 0;
|
||||||
let grandTotalLaia = 0;
|
let grandTotalLaia = 0;
|
||||||
const dataByTarget = {};
|
const dataByTarget = {};
|
||||||
@@ -745,18 +744,18 @@ function updateSummaryTable() {
|
|||||||
const laiaSum = dataByTarget[targetName] ? dataByTarget[targetName].laia : 0;
|
const laiaSum = dataByTarget[targetName] ? dataByTarget[targetName].laia : 0;
|
||||||
const globalSum = alexSum + laiaSum;
|
const globalSum = alexSum + laiaSum;
|
||||||
|
|
||||||
row.cells[1].innerText = Math.round(alexSum).toLocaleString(currentLang) + ' €';
|
row.cells[1].innerText = Math.round(alexSum).toLocaleString(window.appLang) + ' €';
|
||||||
row.cells[2].innerText = Math.round(laiaSum).toLocaleString(currentLang) + ' €';
|
row.cells[2].innerText = Math.round(laiaSum).toLocaleString(window.appLang) + ' €';
|
||||||
row.cells[3].innerText = Math.round(globalSum).toLocaleString(currentLang) + ' €';
|
row.cells[3].innerText = Math.round(globalSum).toLocaleString(window.appLang) + ' €';
|
||||||
|
|
||||||
grandTotalAlex += alexSum;
|
grandTotalAlex += alexSum;
|
||||||
grandTotalLaia += laiaSum;
|
grandTotalLaia += laiaSum;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
document.getElementById('grand_total_alex').innerText = Math.round(grandTotalAlex).toLocaleString(currentLang) + ' €';
|
document.getElementById('grand_total_alex').innerText = Math.round(grandTotalAlex).toLocaleString(window.appLang) + ' €';
|
||||||
document.getElementById('grand_total_laia').innerText = Math.round(grandTotalLaia).toLocaleString(currentLang) + ' €';
|
document.getElementById('grand_total_laia').innerText = Math.round(grandTotalLaia).toLocaleString(window.appLang) + ' €';
|
||||||
document.getElementById('grand_total_global').innerText = Math.round(grandTotalAlex + grandTotalLaia).toLocaleString(currentLang) + ' €';
|
document.getElementById('grand_total_global').innerText = Math.round(grandTotalAlex + grandTotalLaia).toLocaleString(window.appLang) + ' €';
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveData(action, data) {
|
function saveData(action, data) {
|
||||||
@@ -825,7 +824,6 @@ function saveGenericNote(noteType, refId, content) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// LOGIQUE POUR LA CALCULATRICE RAPIDE
|
|
||||||
let isSumModeActive = false;
|
let isSumModeActive = false;
|
||||||
let selectedElementsForSum = new Set();
|
let selectedElementsForSum = new Set();
|
||||||
|
|
||||||
@@ -868,7 +866,7 @@ function updateSumResult() {
|
|||||||
total += val;
|
total += val;
|
||||||
});
|
});
|
||||||
|
|
||||||
document.getElementById('sumResultValue').innerText = new Intl.NumberFormat(currentLang, { style: 'currency', currency: 'EUR', maximumFractionDigits: 0 }).format(total);
|
document.getElementById('sumResultValue').innerText = new Intl.NumberFormat(window.appLang, { style: 'currency', currency: 'EUR', maximumFractionDigits: 0 }).format(total);
|
||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener('click', function(e) {
|
document.addEventListener('click', function(e) {
|
||||||
|
|||||||
@@ -244,31 +244,27 @@ function getMonthName($dateString) {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
window.I18N = {
|
// --- 1. SÉCURISATION TRADUCTIONS ET LANGUE ---
|
||||||
...window.I18N,
|
window.appLang = document.documentElement.lang === "ca" ? "ca-ES" : "fr-FR";
|
||||||
'bud_sav_ph_name' : "<?= tr('bud_sav_ph_name') ?>",
|
window.I18N = {
|
||||||
'bud_sav_modal_title_edit' : "<?= tr('bud_sav_modal_title_edit') ?>",
|
...(window.I18N || {}),
|
||||||
'bud_sav_modal_title_add' : "<?= tr('bud_sav_modal_title_add') ?>",
|
'bud_sav_modal_title_add': "<?= tr('bud_sav_modal_title_add') ?>",
|
||||||
'bud_sav_saving' : "<?= tr('bud_sav_saving') ?>",
|
'bud_sav_modal_title_edit': "<?= tr('bud_sav_modal_title_edit') ?>",
|
||||||
'bud_err_tech' : "<?= tr('bud_err_tech') ?>",
|
'bud_sav_ph_name': "<?= tr('bud_sav_ph_name') ?>",
|
||||||
'bud_sav_confirm_delete_month' : "<?= tr('bud_sav_confirm_delete_month') ?>",
|
'bud_sav_confirm_delete_month': "<?= tr('bud_sav_confirm_delete_month') ?>",
|
||||||
'bud_sav_prompt_duplicate' : "<?= tr('bud_sav_prompt_duplicate') ?>",
|
'bud_sav_prompt_duplicate': "<?= tr('bud_sav_prompt_duplicate') ?>",
|
||||||
'bud_err_server' : "<?= tr('bud_err_server') ?>",
|
'bud_err_tech': "<?= tr('bud_err_tech') ?>",
|
||||||
'bud_err_network_dup' : "<?= tr('bud_err_network_dup') ?>"
|
'bud_err_server': "<?= tr('bud_err_server') ?>",
|
||||||
};
|
'bud_err_network_dup': "<?= tr('bud_err_network_dup') ?>",
|
||||||
|
'bud_sav_saving': "<?= tr('bud_sav_saving') ?>",
|
||||||
|
'bud_err_delete': "<?= tr('bud_err_delete') ?>"
|
||||||
|
};
|
||||||
|
|
||||||
// Détection de la langue pour le JS
|
// --- 2. GESTION DE L'ÉDITION INVISIBLE EN DIRECT ---
|
||||||
const currentLang = document.documentElement.lang === "ca" ? "ca-ES" : "fr-FR";
|
const cycleConfigs = <?= json_encode($cycleConfigs ?? []) ?>;
|
||||||
</script>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
// ============================================================================
|
|
||||||
// 1. GESTION DE L'ÉDITION INVISIBLE EN DIRECT (Input Classique)
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
function updateEpargneCell(month, category, owner, inputEl) {
|
function updateEpargneCell(month, category, owner, inputEl) {
|
||||||
const val = parseFloat(inputEl.value) || 0;
|
const val = parseFloat(inputEl.value) || 0;
|
||||||
|
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append('action', 'update_single_entry');
|
formData.append('action', 'update_single_entry');
|
||||||
formData.append('month_date', month);
|
formData.append('month_date', month);
|
||||||
@@ -282,7 +278,7 @@ function updateEpargneCell(month, category, owner, inputEl) {
|
|||||||
}).catch(err => alert(tr("bud_err_tech")));
|
}).catch(err => alert(tr("bud_err_tech")));
|
||||||
|
|
||||||
const totalInput = document.querySelector(`.total-input-${owner}-${month}`);
|
const totalInput = document.querySelector(`.total-input-${owner}-${month}`);
|
||||||
const totalVal = parseFloat(totalInput.value) || 0;
|
const totalVal = parseFloat(totalInput ? totalInput.value : 0) || 0;
|
||||||
|
|
||||||
let sumCats = 0;
|
let sumCats = 0;
|
||||||
document.querySelectorAll(`.cat-input-${owner}-${month}`).forEach(inp => {
|
document.querySelectorAll(`.cat-input-${owner}-${month}`).forEach(inp => {
|
||||||
@@ -293,18 +289,13 @@ function updateEpargneCell(month, category, owner, inputEl) {
|
|||||||
const extraCell = document.getElementById(`extra_${owner}_${month}`);
|
const extraCell = document.getElementById(`extra_${owner}_${month}`);
|
||||||
|
|
||||||
if (extraCell) {
|
if (extraCell) {
|
||||||
extraCell.innerText = Math.round(extra).toLocaleString(currentLang) + ' €';
|
extraCell.innerText = Math.round(extra).toLocaleString(window.appLang) + ' €';
|
||||||
extraCell.style.color = extra >= 0 ? '#10b981' : '#ef4444';
|
extraCell.style.color = extra >= 0 ? '#10b981' : '#ef4444';
|
||||||
}
|
}
|
||||||
|
|
||||||
if(isSumModeActive) updateSumResult();
|
if(isSumModeActive) updateSumResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// 2. MODALE D'ÉDITION CLASSIQUE / AJOUT
|
|
||||||
// ============================================================================
|
|
||||||
const cycleConfigs = <?= json_encode($cycleConfigs) ?>;
|
|
||||||
|
|
||||||
function addCustomEpargneLine(catName = '', amount = '') {
|
function addCustomEpargneLine(catName = '', amount = '') {
|
||||||
const container = document.getElementById('linesContainer');
|
const container = document.getElementById('linesContainer');
|
||||||
const baseAmount = (amount !== '' && amount !== null) ? parseFloat(amount).toFixed(2) : '0.00';
|
const baseAmount = (amount !== '' && amount !== null) ? parseFloat(amount).toFixed(2) : '0.00';
|
||||||
@@ -315,19 +306,15 @@ function addCustomEpargneLine(catName = '', amount = '') {
|
|||||||
<div style="flex:2;">
|
<div style="flex:2;">
|
||||||
<input type="text" class="pf-input cat-name-input" value="${catName}" placeholder="${tr("bud_sav_ph_name")}" oninput="updateCustomFieldName(this)" style="padding:6px; font-size:0.9rem;" required>
|
<input type="text" class="pf-input cat-name-input" value="${catName}" placeholder="${tr("bud_sav_ph_name")}" oninput="updateCustomFieldName(this)" style="padding:6px; font-size:0.9rem;" required>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style="width:100px;">
|
<div style="width:100px;">
|
||||||
<input type="number" step="0.01" class="pf-input base-amount no-spinners" value="${baseAmount}" oninput="recalculateCustomLine(this)" style="padding:6px; font-size:0.9rem; background:#fff;">
|
<input type="number" step="0.01" class="pf-input base-amount no-spinners" value="${baseAmount}" oninput="recalculateCustomLine(this)" style="padding:6px; font-size:0.9rem; background:#fff;">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style="width:90px;">
|
<div style="width:90px;">
|
||||||
<input type="number" step="0.01" class="pf-input adjustment-amount no-spinners" placeholder="+ / -" oninput="recalculateCustomLine(this)" style="padding:6px; font-size:0.9rem; color:#f59e0b; font-weight:bold;">
|
<input type="number" step="0.01" class="pf-input adjustment-amount no-spinners" placeholder="+ / -" oninput="recalculateCustomLine(this)" style="padding:6px; font-size:0.9rem; color:#f59e0b; font-weight:bold;">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style="width:100px;">
|
<div style="width:100px;">
|
||||||
<input type="number" step="0.01" name="${inputName}" class="pf-input final-amount no-spinners" value="${baseAmount}" style="padding:6px; font-size:0.9rem; font-weight:bold; background:#e0f2fe; border-color:#bae6fd; color:#0369a1;" readonly>
|
<input type="number" step="0.01" name="${inputName}" class="pf-input final-amount no-spinners" value="${baseAmount}" style="padding:6px; font-size:0.9rem; font-weight:bold; background:#e0f2fe; border-color:#bae6fd; color:#0369a1;" readonly>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button type="button" onclick="this.parentElement.remove()" style="width:28px; height:28px; border:none; background:#fee2e2; color:#ef4444; border-radius:4px; cursor:pointer; display:flex; align-items:center; justify-content:center; font-weight:bold;">×</button>
|
<button type="button" onclick="this.parentElement.remove()" style="width:28px; height:28px; border:none; background:#fee2e2; color:#ef4444; border-radius:4px; cursor:pointer; display:flex; align-items:center; justify-content:center; font-weight:bold;">×</button>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
@@ -360,7 +347,7 @@ function editCustomSavingsMonth(monthDate, owner, rowData) {
|
|||||||
document.getElementById('sav_month').value = ym;
|
document.getElementById('sav_month').value = ym;
|
||||||
|
|
||||||
const dateObj = new Date(monthDate);
|
const dateObj = new Date(monthDate);
|
||||||
const monthName = dateObj.toLocaleDateString(currentLang, { month: 'long', year: 'numeric' });
|
const monthName = dateObj.toLocaleDateString(window.appLang, { month: 'long', year: 'numeric' });
|
||||||
document.getElementById('savingsModalTitle').innerText = tr("bud_sav_modal_title_edit") + " " + monthName + " (" + owner + ")";
|
document.getElementById('savingsModalTitle').innerText = tr("bud_sav_modal_title_edit") + " " + monthName + " (" + owner + ")";
|
||||||
|
|
||||||
document.getElementById('sav_total').value = rowData['TOTAL_BANQUE'] || '';
|
document.getElementById('sav_total').value = rowData['TOTAL_BANQUE'] || '';
|
||||||
@@ -440,7 +427,7 @@ function deleteEntireMonth(monthDate, owner) {
|
|||||||
formData.append("owner", owner);
|
formData.append("owner", owner);
|
||||||
fetch("/modules/budget/includes/api/save-savings.php", { method: "POST", body: formData })
|
fetch("/modules/budget/includes/api/save-savings.php", { method: "POST", body: formData })
|
||||||
.then(() => window.location.reload())
|
.then(() => window.location.reload())
|
||||||
.catch(err => alert("<?= tr('bud_err_delete') ?>"));
|
.catch(err => alert(tr('bud_err_delete')));
|
||||||
}
|
}
|
||||||
|
|
||||||
function duplicateLastMonth(lastMonthDate, owner) {
|
function duplicateLastMonth(lastMonthDate, owner) {
|
||||||
@@ -451,7 +438,7 @@ function duplicateLastMonth(lastMonthDate, owner) {
|
|||||||
let nextMonthStr = `${year}-${month}-01`;
|
let nextMonthStr = `${year}-${month}-01`;
|
||||||
|
|
||||||
const formatMonth = (d) => {
|
const formatMonth = (d) => {
|
||||||
let str = new Date(d).toLocaleDateString(currentLang, { month: 'long', year: 'numeric' });
|
let str = new Date(d).toLocaleDateString(window.appLang, { month: 'long', year: 'numeric' });
|
||||||
return str.charAt(0).toUpperCase() + str.slice(1);
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -496,15 +483,12 @@ function duplicateLastMonth(lastMonthDate, owner) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// --- CALCULATRICE ---
|
||||||
// 3. CALCULATRICE (SOMME RAPIDE)
|
|
||||||
// ============================================================================
|
|
||||||
let isSumModeActive = false;
|
let isSumModeActive = false;
|
||||||
let selectedElementsForSum = new Set();
|
let selectedElementsForSum = new Set();
|
||||||
|
|
||||||
function toggleSumMode() {
|
function toggleSumMode() {
|
||||||
isSumModeActive = !isSumModeActive;
|
isSumModeActive = !isSumModeActive;
|
||||||
|
|
||||||
const fab = document.getElementById('fabSumMode');
|
const fab = document.getElementById('fabSumMode');
|
||||||
const resultBar = document.getElementById('sumResultBar');
|
const resultBar = document.getElementById('sumResultBar');
|
||||||
|
|
||||||
@@ -541,13 +525,12 @@ function updateSumResult() {
|
|||||||
total += val;
|
total += val;
|
||||||
});
|
});
|
||||||
|
|
||||||
document.getElementById('sumResultValue').innerText = new Intl.NumberFormat(currentLang, { style: 'currency', currency: 'EUR', maximumFractionDigits: 0 }).format(total);
|
document.getElementById('sumResultValue').innerText = new Intl.NumberFormat(window.appLang, { style: 'currency', currency: 'EUR', maximumFractionDigits: 0 }).format(total);
|
||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener('click', function(e) {
|
document.addEventListener('click', function(e) {
|
||||||
if (!isSumModeActive) return;
|
if (!isSumModeActive) return;
|
||||||
|
|
||||||
// Cible les inputs type number OU les cellules (td/th/div) ayant la classe .sum-target
|
|
||||||
const targetElement = e.target.closest('input[type="number"], .sum-target');
|
const targetElement = e.target.closest('input[type="number"], .sum-target');
|
||||||
|
|
||||||
if (targetElement) {
|
if (targetElement) {
|
||||||
@@ -563,5 +546,5 @@ document.addEventListener('click', function(e) {
|
|||||||
|
|
||||||
updateSumResult();
|
updateSumResult();
|
||||||
}
|
}
|
||||||
}, true); // Le 'true' intercepte le clic avant le focus normal
|
}, true);
|
||||||
</script>
|
</script>
|
||||||
@@ -168,7 +168,6 @@
|
|||||||
min-width: 1000px;
|
min-width: 1000px;
|
||||||
border-collapse: separate;
|
border-collapse: separate;
|
||||||
border-spacing: 0;
|
border-spacing: 0;
|
||||||
table-layout: fixed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Sticky Header */
|
/* Sticky Header */
|
||||||
@@ -303,12 +302,25 @@
|
|||||||
width: auto !important;
|
width: auto !important;
|
||||||
border-right: 2px solid var(--border-color) !important;
|
border-right: 2px solid var(--border-color) !important;
|
||||||
}
|
}
|
||||||
.col-total,
|
th.col-total,
|
||||||
.col-alex-sub,
|
td.col-total,
|
||||||
.col-laia-sub {
|
th.col-alex-sub,
|
||||||
|
td.col-alex-sub,
|
||||||
|
th.col-laia-sub,
|
||||||
|
td.col-laia-sub {
|
||||||
width: 32px !important;
|
width: 32px !important;
|
||||||
min-width: 32px !important;
|
min-width: 32px !important;
|
||||||
max-width: 32px !important;
|
max-width: 32px !important;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 0 2px !important; /* On réduit le padding pour que les chiffres respirent */
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
th.col-day,
|
||||||
|
td.col-day {
|
||||||
|
width: auto !important;
|
||||||
|
min-width: 35px !important;
|
||||||
|
border-right: 2px solid var(--border-color) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.rotated-text span {
|
.rotated-text span {
|
||||||
|
|||||||
@@ -944,10 +944,10 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
div.innerHTML = `
|
div.innerHTML = `
|
||||||
<div class="fc-summary-item"><span class="fc-summary-label">Off Carole</span><span class="fc-summary-value">${parseFloat(stats.off.toFixed(1))} jours</span></div>
|
<div class="fc-summary-item"><span class="fc-summary-label">${tr("leg_off_carole")}</span><span class="fc-summary-value">${parseFloat(stats.off.toFixed(1))} ${tr("fc_unit_days")}</span></div>
|
||||||
<div class="fc-summary-item"><span class="fc-summary-label">Extra Off Carole</span><span class="fc-summary-value">${parseFloat(stats.extra.toFixed(1))} jours</span></div>
|
<div class="fc-summary-item"><span class="fc-summary-label">${tr("leg_extra_off")}</span><span class="fc-summary-value">${parseFloat(stats.extra.toFixed(1))} ${tr("fc_unit_days")}</span></div>
|
||||||
<div class="fc-summary-item"><span class="fc-summary-label">Pep Malade</span><span class="fc-summary-value">${parseFloat(stats.sick.toFixed(1))} jours</span></div>
|
<div class="fc-summary-item"><span class="fc-summary-label">${tr("leg_pep_sick")}</span><span class="fc-summary-value">${parseFloat(stats.sick.toFixed(1))} ${tr("fc_unit_days")}</span></div>
|
||||||
<div class="fc-summary-item"><span class="fc-summary-label">Présence Pep</span><span class="fc-summary-value">${parseFloat(stats.pep.toFixed(1))} jours</span></div>
|
<div class="fc-summary-item"><span class="fc-summary-label">${tr("leg_presence")} Pep</span><span class="fc-summary-value">${parseFloat(stats.pep.toFixed(1))} ${tr("fc_unit_days")}</span></div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1196,3 +1196,26 @@ input[type="date"]::-webkit-calendar-picker-indicator:hover {
|
|||||||
box-shadow: 0 0 0 3px var(--primary);
|
box-shadow: 0 0 0 3px var(--primary);
|
||||||
transform: scale(1.02);
|
transform: scale(1.02);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Style du badge météo injecté par le JS */
|
||||||
|
.hol-weather-info {
|
||||||
|
display: inline-flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pf-weather-badge {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
background: #f8fafc; /* Slate 50 */
|
||||||
|
border: 1px solid #e2e8f0; /* Slate 200 */
|
||||||
|
padding: 1px 6px;
|
||||||
|
border-radius: 6px;
|
||||||
|
color: #475569; /* Slate 600 */
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 0.7rem;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pf-weather-icon {
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,8 +5,60 @@ function tr(key) {
|
|||||||
return window.I18N && window.I18N[key] ? window.I18N[key] : key;
|
return window.I18N && window.I18N[key] ? window.I18N[key] : key;
|
||||||
}
|
}
|
||||||
|
|
||||||
// On détecte la langue de la page (définie dans la balise <html lang="..."> du header)
|
// On utilise 'var' au lieu de 'const/let' pour éviter les crashs si le fichier est lu 2 fois
|
||||||
const currentLang = document.documentElement.lang === "ca" ? "ca-ES" : "fr-FR";
|
var currentLang = document.documentElement.lang === "ca" ? "ca-ES" : "fr-FR";
|
||||||
|
var selectedItemIdForMove = null; // Déplacé ici pour plus de clarté
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// UTILITAIRES MÉTÉO
|
||||||
|
// ============================================================================
|
||||||
|
function getWeatherInfo(code) {
|
||||||
|
// Transformation en conditions pour regrouper les codes WMO
|
||||||
|
if (code === 0) return { icon: "☀️", label: tr("weather_sunny") };
|
||||||
|
if ([1, 2].includes(code)) return { icon: "🌤️", label: tr("weather_sunny") };
|
||||||
|
if ([3, 45, 48].includes(code))
|
||||||
|
return { icon: "☁️", label: tr("weather_cloudy") };
|
||||||
|
// Les codes 51 à 67 et 80 à 82 couvrent toutes les formes de pluie et bruine
|
||||||
|
if ([51, 53, 55, 56, 57, 61, 63, 65, 66, 67, 80, 81, 82].includes(code))
|
||||||
|
return { icon: "🌧️", label: tr("weather_rainy") };
|
||||||
|
// Les codes neigeux
|
||||||
|
if ([71, 73, 75, 77, 85, 86].includes(code))
|
||||||
|
return { icon: "❄️", label: tr("weather_snowy") };
|
||||||
|
// Orages
|
||||||
|
if ([95, 96, 99].includes(code))
|
||||||
|
return { icon: "⛈️", label: tr("weather_rainy") };
|
||||||
|
|
||||||
|
return { icon: "🌡️", label: tr("weather_forecast") };
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadWeatherForStep(pt) {
|
||||||
|
if (!pt.step_start_date || !pt.lat || !pt.lng) return;
|
||||||
|
|
||||||
|
const container = document.querySelector(
|
||||||
|
`#step-card-${pt.sort_order} .hol-weather-info`,
|
||||||
|
);
|
||||||
|
if (!container) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const resp = await fetch(
|
||||||
|
`/modules/holidays/includes/api/get_weather.php?lat=${pt.lat}&lng=${pt.lng}&date=${pt.step_start_date}`,
|
||||||
|
);
|
||||||
|
const res = await resp.json();
|
||||||
|
|
||||||
|
console.log(`Météo pour ${pt.location_name} :`, res);
|
||||||
|
|
||||||
|
if (res.success) {
|
||||||
|
const info = getWeatherInfo(res.data.code);
|
||||||
|
container.innerHTML = `
|
||||||
|
<div class="pf-weather-badge" title="${info.label}">
|
||||||
|
<span class="pf-weather-icon">${info.icon}</span>
|
||||||
|
<span>${Math.round(res.data.temp_min)}° / ${Math.round(res.data.temp_max)}°C</span>
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Weather error", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// FERMETURE UNIVERSELLE DES MODALES
|
// FERMETURE UNIVERSELLE DES MODALES
|
||||||
@@ -150,7 +202,7 @@ function deleteHoliday() {
|
|||||||
|
|
||||||
// --- 3. GESTION DE LA CARTE ---
|
// --- 3. GESTION DE LA CARTE ---
|
||||||
|
|
||||||
let map = null;
|
var map = null;
|
||||||
|
|
||||||
function toggleMap() {
|
function toggleMap() {
|
||||||
const modal = document.getElementById("hol-map-modal");
|
const modal = document.getElementById("hol-map-modal");
|
||||||
@@ -197,7 +249,7 @@ function initMap() {
|
|||||||
// 4. GESTION DE LA CARTE DÉTAILLÉE (ROADTRIP) ET GÉOCODAGE
|
// 4. GESTION DE LA CARTE DÉTAILLÉE (ROADTRIP) ET GÉOCODAGE
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
let detailMap = null;
|
var detailMap = null;
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", () => {
|
document.addEventListener("DOMContentLoaded", () => {
|
||||||
if (document.getElementById("tripMap")) {
|
if (document.getElementById("tripMap")) {
|
||||||
@@ -208,6 +260,11 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
function initDetailMap() {
|
function initDetailMap() {
|
||||||
if (typeof L === "undefined" || typeof MAP_POINTS === "undefined") return;
|
if (typeof L === "undefined" || typeof MAP_POINTS === "undefined") return;
|
||||||
|
|
||||||
|
const mapContainer = L.DomUtil.get("tripMap");
|
||||||
|
if (mapContainer !== null && mapContainer._leaflet_id) {
|
||||||
|
mapContainer._leaflet_id = null;
|
||||||
|
}
|
||||||
|
|
||||||
detailMap = L.map("tripMap");
|
detailMap = L.map("tripMap");
|
||||||
L.tileLayer("https://tile.openstreetmap.org/{z}/{x}/{y}.png", {
|
L.tileLayer("https://tile.openstreetmap.org/{z}/{x}/{y}.png", {
|
||||||
maxZoom: 19,
|
maxZoom: 19,
|
||||||
@@ -323,6 +380,11 @@ function initDetailMap() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
detailMap.fitBounds(bounds, { padding: [50, 50] });
|
||||||
|
// Lancement de la météo pour chaque étape
|
||||||
|
if (typeof MAP_POINTS !== "undefined") {
|
||||||
|
MAP_POINTS.forEach((pt) => loadWeatherForStep(pt));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function drawFallbackLine(coords, color, weight) {
|
function drawFallbackLine(coords, color, weight) {
|
||||||
@@ -582,7 +644,6 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||||||
// ============================================================================
|
// ============================================================================
|
||||||
// MOTEUR DRAG & DROP DU PLANNING
|
// MOTEUR DRAG & DROP DU PLANNING
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
let selectedItemIdForMove = null;
|
|
||||||
|
|
||||||
function closePlanningModal() {
|
function closePlanningModal() {
|
||||||
document.getElementById("planningModal").style.display = "none";
|
document.getElementById("planningModal").style.display = "none";
|
||||||
|
|||||||
@@ -0,0 +1,63 @@
|
|||||||
|
<?php
|
||||||
|
// modules/holidays/includes/api/get_weather.php
|
||||||
|
|
||||||
|
// 1. Désactiver les erreurs HTML pour ne pas corrompre le JSON
|
||||||
|
ini_set('display_errors', 0);
|
||||||
|
error_reporting(0);
|
||||||
|
|
||||||
|
// 2. Inclusion de tes fichiers vitaux (C'est auth.php qui sécurise l'accès !)
|
||||||
|
$basePath = '../../../../';
|
||||||
|
require_once $basePath . 'includes/db.php';
|
||||||
|
require_once $basePath . 'includes/auth.php';
|
||||||
|
|
||||||
|
// Si on arrive à cette ligne, c'est que auth.php a validé la session.
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
|
// 3. Récupération des paramètres GPS et Date
|
||||||
|
$lat = filter_input(INPUT_GET, 'lat', FILTER_VALIDATE_FLOAT);
|
||||||
|
$lng = filter_input(INPUT_GET, 'lng', FILTER_VALIDATE_FLOAT);
|
||||||
|
$date = $_GET['date'] ?? null;
|
||||||
|
|
||||||
|
if (!$lat || !$lng || !$date) {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'Paramètres manquants']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$date = substr($date, 0, 10);
|
||||||
|
$today = new DateTime();
|
||||||
|
$targetDate = new DateTime($date);
|
||||||
|
$interval = $today->diff($targetDate);
|
||||||
|
$daysDiff = (int)$interval->format('%R%a');
|
||||||
|
|
||||||
|
// 4. Choix du bon modèle météo (Prévisions vs Historique)
|
||||||
|
if ($daysDiff < -2) {
|
||||||
|
$baseUrl = "https://archive-api.open-meteo.com/v1/archive";
|
||||||
|
} else {
|
||||||
|
$baseUrl = "https://api.open-meteo.com/v1/forecast";
|
||||||
|
}
|
||||||
|
|
||||||
|
$url = "$baseUrl?latitude=$lat&longitude=$lng&daily=weather_code,temperature_2m_max,temperature_2m_min&timezone=auto&start_date=$date&end_date=$date";
|
||||||
|
|
||||||
|
// 5. Interrogation d'Open-Meteo
|
||||||
|
$res = @file_get_contents($url);
|
||||||
|
|
||||||
|
if (!$res) {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'Erreur API Open-Meteo']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = json_decode($res, true);
|
||||||
|
|
||||||
|
// 6. Formatage et envoi au Javascript
|
||||||
|
if (isset($data['daily']['weather_code'][0])) {
|
||||||
|
echo json_encode([
|
||||||
|
'success' => true,
|
||||||
|
'data' => [
|
||||||
|
'code' => $data['daily']['weather_code'][0],
|
||||||
|
'temp_max' => $data['daily']['temperature_2m_max'][0],
|
||||||
|
'temp_min' => $data['daily']['temperature_2m_min'][0]
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'Aucune donnée pour cette date']);
|
||||||
|
}
|
||||||
@@ -204,8 +204,11 @@ $pctSaved = $cost > 0 ? min(100 - $pctPaid, ($saved / $cost) * 100) : 0;
|
|||||||
<span style="background: #fff7ed; color: #ea580c; padding: 2px 6px; border-radius: 4px; font-size: 0.7rem; font-weight: bold; margin-left: 5px; border: 1px solid #ffedd5; vertical-align: middle;">🏁 <?= tr('hdl_return') ?></span>
|
<span style="background: #fff7ed; color: #ea580c; padding: 2px 6px; border-radius: 4px; font-size: 0.7rem; font-weight: bold; margin-left: 5px; border: 1px solid #ffedd5; vertical-align: middle;">🏁 <?= tr('hdl_return') ?></span>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
<?php if (!empty($step['step_start_date']) && !empty($step['step_end_date'])): ?>
|
<?php if (!empty($step['step_start_date']) && !empty($step['step_end_date'])): ?>
|
||||||
<div style="font-size:0.75rem; color:#64748b; font-weight:normal; margin-top:2px;">
|
<div style="font-size:0.75rem; color:#64748b; font-weight:normal; margin-top:2px; display: flex; align-items: center; gap: 10px;">
|
||||||
|
<span>
|
||||||
<?= tr('hdl_from') ?> <?= date('d/m', strtotime($step['step_start_date'])) ?> <?= tr('hdl_to') ?> <?= date('d/m', strtotime($step['step_end_date'])) ?>
|
<?= tr('hdl_from') ?> <?= date('d/m', strtotime($step['step_start_date'])) ?> <?= tr('hdl_to') ?> <?= date('d/m', strtotime($step['step_end_date'])) ?>
|
||||||
|
</span>
|
||||||
|
<div class="hol-weather-info"></div>
|
||||||
</div>
|
</div>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
@@ -352,19 +355,52 @@ $pctSaved = $cost > 0 ? min(100 - $pctPaid, ($saved / $cost) * 100) : 0;
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<?php include __DIR__ . '/modal.php'; ?>
|
||||||
const MAP_POINTS = <?= json_encode($mapPoints) ?>;
|
|
||||||
|
|
||||||
// Le pont i18n pour Javascript (Holidays specific)
|
<script>
|
||||||
window.I18N = {
|
// --- 1. SÉCURISATION TRADUCTIONS ET VARIABLES ---
|
||||||
...window.I18N,
|
window.MAP_POINTS = <?= json_encode($mapPoints ?? []) ?>;
|
||||||
|
window.appLang = document.documentElement.lang === "ca" ? "ca-ES" : "fr-FR";
|
||||||
|
|
||||||
|
window.I18N = {
|
||||||
|
...(window.I18N || {}),
|
||||||
'hdl_js_search_loading': "<?= tr('hdl_js_search_loading') ?>",
|
'hdl_js_search_loading': "<?= tr('hdl_js_search_loading') ?>",
|
||||||
'hdl_js_no_result': "<?= tr('hdl_js_no_result') ?>",
|
'hdl_js_no_result': "<?= tr('hdl_js_no_result') ?>",
|
||||||
'hdl_js_confirm_del_trip': "<?= tr('hdl_js_confirm_del_trip') ?>",
|
'hdl_js_confirm_del_trip': "<?= tr('hdl_js_confirm_del_trip') ?>",
|
||||||
'hdl_js_confirm_del_step': "<?= tr('hdl_js_confirm_del_step') ?>",
|
'hdl_js_confirm_del_step': "<?= tr('hdl_js_confirm_del_step') ?>",
|
||||||
'hdl_js_step_label': "<?= tr('hdl_js_step_label') ?>",
|
'hdl_js_step_label': "<?= tr('hdl_js_step_label') ?>",
|
||||||
'hdl_js_ph_expense_name': "<?= tr('hdl_js_ph_expense_name') ?>",
|
'hdl_js_ph_expense_name': "<?= tr('hdl_js_ph_expense_name') ?>",
|
||||||
'hdl_js_ph_amount': "0.00",
|
'hdl_js_delete_line': "<?= tr('btn_delete') ?>",
|
||||||
'hdl_js_delete_line': "<?= tr('btn_delete') ?>"
|
'hdl_planning_title': "<?= tr('hdl_planning_title') ?>",
|
||||||
};
|
'hdl_to_place': "<?= tr('hdl_to_place') ?>",
|
||||||
|
'hdl_js_missing_dates_title': "<?= tr('hdl_js_missing_dates_title') ?>",
|
||||||
|
'hdl_js_missing_dates_msg': "<?= tr('hdl_js_missing_dates_msg') ?>",
|
||||||
|
'hdl_modal_title': "<?= tr('hdl_modal_title') ?>",
|
||||||
|
'hdl_js_edit_step': "<?= tr('hdl_js_edit_step') ?>",
|
||||||
|
'hdl_ph_notes': "<?= tr('hdl_ph_notes') ?>",
|
||||||
|
'hdl_btn_add_step': "<?= tr('hdl_btn_add_step') ?>",
|
||||||
|
'hdl_quick_edit_title': "<?= tr('hdl_quick_edit_title') ?>",
|
||||||
|
|
||||||
|
// --- NOUVELLES CLÉS MÉTÉO ICI ---
|
||||||
|
'weather_sunny': "<?= tr('weather_sunny') ?>",
|
||||||
|
'weather_cloudy': "<?= tr('weather_cloudy') ?>",
|
||||||
|
'weather_rainy': "<?= tr('weather_rainy') ?>",
|
||||||
|
'weather_snowy': "<?= tr('weather_snowy') ?>",
|
||||||
|
'weather_forecast': "<?= tr('weather_forecast') ?>"
|
||||||
|
};
|
||||||
|
|
||||||
|
// Fallback de sécurité pour s'assurer que les modales peuvent toujours se fermer
|
||||||
|
window.closeCheckpointModal = window.closeCheckpointModal || function() {
|
||||||
|
const modal = document.getElementById('checkpointModal');
|
||||||
|
if(modal) modal.style.display = 'none';
|
||||||
|
document.body.classList.remove('no-scroll');
|
||||||
|
};
|
||||||
|
|
||||||
|
window.closePlanningModal = window.closePlanningModal || function() {
|
||||||
|
const modal = document.getElementById('planningModal');
|
||||||
|
if(modal) modal.style.display = 'none';
|
||||||
|
document.body.classList.remove('no-scroll');
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<script src="/modules/holidays/holidays.js"></script>
|
||||||
@@ -90,6 +90,37 @@ foreach ($active as $h) {
|
|||||||
|
|
||||||
<?php include __DIR__ . '/modal.php'; ?>
|
<?php include __DIR__ . '/modal.php'; ?>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// --- 1. SÉCURISATION TRADUCTIONS ET LANGUE ---
|
||||||
|
window.appLang = document.documentElement.lang === "ca" ? "ca-ES" : "fr-FR";
|
||||||
|
|
||||||
|
window.I18N = {
|
||||||
|
...(window.I18N || {}),
|
||||||
|
'hdl_js_search_loading': "<?= tr('hdl_js_search_loading') ?>",
|
||||||
|
'hdl_js_no_result': "<?= tr('hdl_js_no_result') ?>",
|
||||||
|
'hdl_js_confirm_del_trip': "<?= tr('hdl_js_confirm_del_trip') ?>",
|
||||||
|
'hdl_js_confirm_del_step': "<?= tr('hdl_js_confirm_del_step') ?>",
|
||||||
|
'hdl_js_step_label': "<?= tr('hdl_js_step_label') ?>",
|
||||||
|
'hdl_js_ph_expense_name': "<?= tr('hdl_js_ph_expense_name') ?>",
|
||||||
|
'hdl_js_delete_line': "<?= tr('btn_delete') ?>",
|
||||||
|
'hdl_planning_title': "<?= tr('hdl_planning_title') ?>",
|
||||||
|
'hdl_to_place': "<?= tr('hdl_to_place') ?>",
|
||||||
|
'hdl_js_missing_dates_title': "<?= tr('hdl_js_missing_dates_title') ?>",
|
||||||
|
'hdl_js_missing_dates_msg': "<?= tr('hdl_js_missing_dates_msg') ?>",
|
||||||
|
'hdl_modal_title': "<?= tr('hdl_modal_title') ?>",
|
||||||
|
'hdl_quick_edit_title': "<?= tr('hdl_quick_edit_title') ?>"
|
||||||
|
};
|
||||||
|
|
||||||
|
// Fallback de sécurité pour s'assurer que la modale peut toujours se fermer
|
||||||
|
window.closeHolidayModal = window.closeHolidayModal || function() {
|
||||||
|
const modal = document.getElementById('holidayModal');
|
||||||
|
if(modal) modal.style.display = 'none';
|
||||||
|
document.body.classList.remove('no-scroll');
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script src="/modules/holidays/holidays.js"></script>
|
||||||
|
|
||||||
<?php
|
<?php
|
||||||
function renderHolidayCard($h, $pdo) {
|
function renderHolidayCard($h, $pdo) {
|
||||||
$stmt = $pdo->prepare("SELECT * FROM pf_holidays_items WHERE holiday_id = ?");
|
$stmt = $pdo->prepare("SELECT * FROM pf_holidays_items WHERE holiday_id = ?");
|
||||||
@@ -119,7 +150,6 @@ function renderHolidayCard($h, $pdo) {
|
|||||||
$pctPaid = $cost > 0 ? min(100, ($paid / $cost) * 100) : 0;
|
$pctPaid = $cost > 0 ? min(100, ($paid / $cost) * 100) : 0;
|
||||||
$pctSaved = $cost > 0 ? min(100 - $pctPaid, ($saved / $cost) * 100) : 0;
|
$pctSaved = $cost > 0 ? min(100 - $pctPaid, ($saved / $cost) * 100) : 0;
|
||||||
|
|
||||||
// Traduction dynamique du statut
|
|
||||||
$statusLabel = tr('hdl_status_' . $h['status']);
|
$statusLabel = tr('hdl_status_' . $h['status']);
|
||||||
|
|
||||||
echo "
|
echo "
|
||||||
|
|||||||
Reference in New Issue
Block a user