Files
HouseHub/gift-list.php
T
2026-06-09 08:56:52 +02:00

702 lines
32 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
// modules/gift-list/gift-list.php
require __DIR__ . '/includes/auth.php';
require_login('/login.php');
require __DIR__ . '/includes/db.php';
require_once __DIR__ . '/includes/i18n.php';
if (session_status() === PHP_SESSION_NONE) { session_start(); }
// --- 1. CONFIGURATION DE BASE ---
$year = (int)date('Y');
$pageTitle = tr('gift_page_title');
$activePage = "gift-list";
$mainClass = "pf-gift-list";
$pageCss = "/modules/gift-list/gift-list.css";
// --- 2. RÉCUPÉRATION DYNAMIQUE DES DONNÉES (Multi-tenant) ---
$stmt = $pdo->query("SELECT name FROM pf_people WHERE role = 'enfant' AND is_active = 1 ORDER BY name ASC");
$children = $stmt->fetchAll(PDO::FETCH_COLUMN) ?: ['Aucun enfant configuré'];
$stmt = $pdo->query("SELECT name FROM pf_people WHERE role NOT IN ('enfant', 'nounou') AND is_active = 1 ORDER BY name ASC");
$allAdultsList = $stmt->fetchAll(PDO::FETCH_COLUMN) ?: ['Aucun adulte configuré'];
$stmt = $pdo->query("SELECT code, name, month_date FROM pf_gift_occasions WHERE is_active = 1 ORDER BY month_date ASC, id ASC");
$activeOccasions = $stmt->fetchAll(PDO::FETCH_ASSOC);
if (empty($activeOccasions)) {
$activeOccasions = [['code' => 'DEMO', 'name' => 'Fête par défaut', 'month_date' => null]];
}
$allowedOccasionCodes = array_column($activeOccasions, 'code');
$occasionIcons = [
'TIO' => '/modules/gift-list/assets/img/tio.png', 'NOEL' => '/modules/gift-list/assets/img/santa.png',
'ROIS' => '/modules/gift-list/assets/img/reis.png', 'ANNIV' => '/modules/gift-list/assets/img/corona.png',
'SANT' => '/modules/gift-list/assets/img/sant.png'
];
// --- 3. CHARGEMENT DES CADEAUX ---
$inMarks = implode(',', array_fill(0, count($allowedOccasionCodes), '?'));
$sql = "SELECT * FROM pf_gifts WHERE year = ? AND occasion IN ($inMarks) ORDER BY occasion ASC, child_name ASC, adult_name ASC";
$stmt = $pdo->prepare($sql);
$stmt->execute(array_merge([$year], $allowedOccasionCodes));
$gifts = $stmt->fetchAll(PDO::FETCH_ASSOC);
$data = [];
$adultsInView = [];
foreach ($gifts as $g) {
$data[$g['occasion']][$g['child_name']]['gifts'][] = $g;
$data[$g['occasion']][$g['child_name']]['totals'][$g['adult_name']] = ($data[$g['occasion']][$g['child_name']]['totals'][$g['adult_name']] ?? 0) + $g['amount'];
$adultsInView[$g['adult_name']] = true;
if (!empty($g['payer_name'])) {
$adultsInView[$g['payer_name']] = true;
}
}
// --- 4. TRICOUNT (Bilan et Remboursements) ---
$people = array_values(array_unique(array_merge($allAdultsList, array_keys($adultsInView))));
$people = array_filter($people);
sort($people);
$matrix = [];
foreach ($people as $p1) { foreach ($people as $p2) $matrix[$p1][$p2] = 0.0; }
foreach ($gifts as $g) {
$adult = $g['adult_name'];
$payer = $g['payer_name'] ?? $g['adult_name'];
$amt = (float)$g['amount'];
if ($amt > 0 && $adult && $payer && $adult !== $payer) {
$matrix[$adult][$payer] += $amt;
}
}
$settlements = [];
$countPeople = count($people);
for ($i = 0; $i < $countPeople; $i++) {
for ($j = $i + 1; $j < $countPeople; $j++) {
$a = $people[$i]; $b = $people[$j];
$net = $matrix[$a][$b] - $matrix[$b][$a];
if ($net > 0.01) { $settlements[] = ['from' => $a, 'to' => $b, 'amount' => $net]; }
elseif ($net < -0.01) { $settlements[] = ['from' => $b, 'to' => $a, 'amount' => -$net]; }
}
}
require __DIR__ . '/header.php';
?>
<div class="pf-container cl-view-dynamic">
<div class="cl-titlebar">
<h1>🎁 <?= sprintf(tr('gift_main_title'), $year) ?></h1>
<button class="btn btn-ghost btn-icon" id="btn-open-gift-settings" title="<?= tr('settings') ?>">⚙️</button>
</div>
<div class="pf-filter-bar">
<span class="pf-filter-icon">🔍</span>
<div class="pf-multi-select" id="ms-child">
<div class="pf-ms-trigger" onclick="toggleMS('ms-child-list', this)">
👦 <span id="ms-child-label"><?= tr('gift_filter_all_children') ?></span>
</div>
<div class="pf-ms-dropdown" id="ms-child-list">
<label class="pf-ms-option is-all">
<input type="checkbox" value="all" checked onchange="handleMSChange(this, 'child')">
<?= tr('gift_filter_all_children') ?>
</label>
<?php foreach($children as $c): ?>
<label class="pf-ms-option"><input type="checkbox" value="<?= htmlspecialchars($c) ?>" onchange="handleMSChange(this, 'child')"> <?= htmlspecialchars($c) ?></label>
<?php endforeach; ?>
</div>
</div>
<div class="pf-multi-select" id="ms-adult">
<div class="pf-ms-trigger" onclick="toggleMS('ms-adult-list', this)">
👤 <span id="ms-adult-label"><?= tr('gift_filter_all_adults') ?></span>
</div>
<div class="pf-ms-dropdown" id="ms-adult-list">
<label class="pf-ms-option is-all">
<input type="checkbox" value="all" checked onchange="handleMSChange(this, 'adult')">
<?= tr('gift_filter_all_adults') ?>
</label>
<?php foreach($allAdultsList as $a): ?>
<label class="pf-ms-option"><input type="checkbox" value="<?= htmlspecialchars($a) ?>" onchange="handleMSChange(this, 'adult')"> <?= htmlspecialchars($a) ?></label>
<?php endforeach; ?>
</div>
</div>
</div>
<section class="pf-section">
<?php foreach ($activeOccasions as $occ):
$occCode = $occ['code'];
$occName = $occ['name'];
?>
<div class="js-occ-section">
<h2 class="cl-occasion-title">
<?php if(!empty($occasionIcons[$occCode])): ?>
<img src="<?= $occasionIcons[$occCode] ?>" class="cl-occasion-icon" alt="">
<?php else: ?>
<span>🎀</span>
<?php endif; ?>
<?= htmlspecialchars($occName) ?>
</h2>
<?php foreach ($children as $child):
$childData = $data[$occCode][$child] ?? ['gifts' => [], 'totals' => []];
?>
<div class="pf-child-section js-child" data-name="<?= htmlspecialchars($child) ?>">
<div class="pf-child-header">
<h3>👦 <?= htmlspecialchars($child) ?></h3>
<button class="pf-btn pf-btn-small btn-add-gift"
data-child="<?= htmlspecialchars($child) ?>"
data-occ="<?= htmlspecialchars($occCode) ?>"
data-adults="<?= htmlspecialchars(json_encode(array_values($allAdultsList))) ?>">
<?= tr('gift_add_gift') ?>
</button>
</div>
<div class="pf-child-totals-bar">
<?php foreach ($childData['totals'] as $adult => $tot): ?>
<span class="pf-summary-pill js-pill-adult" data-adult="<?= htmlspecialchars($adult) ?>">👤 <?= htmlspecialchars($adult) ?> : <strong><?= number_format($tot, 2, ',', '') ?> €</strong></span>
<?php endforeach; ?>
</div>
<?php if (empty($childData['gifts'])): ?>
<p class="js-empty-state gift-empty-state"><?= tr('gift_empty_state_no_gifts') ?></p>
<?php else: ?>
<p class="js-empty-state gift-empty-state pf-hidden"><?= tr('gift_empty_state_no_filter') ?></p>
<div class="pf-gift-feed">
<?php foreach ($childData['gifts'] as $g): ?>
<div class="pf-gift-card-compact js-gift-card" data-adult="<?= htmlspecialchars($g['adult_name']) ?>">
<div>
<h4 class="pf-gift-title">
<?= htmlspecialchars($g['gift_description']) ?>
<?php if($g['product_link']): ?><a href="<?= htmlspecialchars($g['product_link']) ?>" target="_blank" class="pf-gift-link">🔗</a><?php endif; ?>
</h4>
<span class="pf-pill-adult">👤 <?= htmlspecialchars($g['adult_name']) ?></span>
<?php if($g['payer_name'] && $g['payer_name'] !== $g['adult_name']): ?>
<div class="pf-gift-payer"><?= sprintf(tr('gift_paid_by'), htmlspecialchars($g['payer_name'])) ?></div>
<?php endif; ?>
</div>
<div class="pf-gift-footer">
<span class="pf-gift-price"><?= number_format($g['amount'], 2, ',', ' ') ?> €</span>
<div class="pf-gift-actions">
<button class="btn-icon-action edit btn-edit-gift" data-gift="<?= htmlspecialchars(json_encode($g)) ?>">✏️</button>
<button class="btn-icon-action delete btn-delete-gift" data-id="<?= $g['id'] ?>">🗑️</button>
</div>
</div>
</div>
<?php endforeach; ?>
</div>
<?php endif; ?>
</div>
<?php endforeach; ?>
</div>
<?php endforeach; ?>
</section>
<section class="pf-section pf-section--panel gift-tricount-section">
<h2 class="gift-tricount-title">⚖️ <?= tr('gift_liquidations') ?? 'Bilan & Remboursements' ?></h2>
<?php if (empty($settlements)): ?>
<p class="gift-tricount-success">✅ <?= tr('gift_no_debt') ?></p>
<?php else: ?>
<ul class="pf-tricount-list">
<?php foreach ($settlements as $s): ?>
<li class="pf-tricount-item">
<span><strong><?= htmlspecialchars($s['from']) ?></strong> <?= tr('gift_owes') ?> à <?= htmlspecialchars($s['to']) ?></span>
<strong class="gift-tricount-debt-amount"><?= number_format($s['amount'], 2, ',', ' ') ?> €</strong>
</li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
<details class="gift-matrix-details">
<summary class="gift-matrix-summary"><?= tr('gift_view_matrix') ?></summary>
<div class="gift-matrix-wrapper">
<table class="pf-table pf-table--compact cl-debt-matrix">
<thead>
<tr>
<th class="sticky-col bg-header"><?= tr('gift_debtor') ?> \ <?= tr('gift_creditor') ?></th>
<?php foreach ($people as $p): ?><th><?= htmlspecialchars($p) ?></th><?php endforeach; ?>
</tr>
</thead>
<tbody>
<?php foreach ($people as $debtor): ?>
<tr>
<th class="sticky-col bg-body"><?= htmlspecialchars($debtor) ?></th>
<?php foreach ($people as $creditor):
$val = $matrix[$debtor][$creditor] ?? 0;
$display = ($debtor === $creditor) || $val == 0 ? '—' : number_format($val, 2, ',', ' ') . ' €';
$cellClass = $val > 0 ? 'gift-cell-danger' : 'gift-cell-muted';
?>
<td class="<?= $cellClass ?>"><?= $display ?></td>
<?php endforeach; ?>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</details>
</section>
</div>
<div id="pf-gift-modal" class="pf-modal">
<div class="pf-modal-content gift-modal-custom-content">
<div class="gift-modal-custom-header">
<h3 id="modalTitle" class="pf-modal-title gift-modal-custom-title">Cadeau</h3>
<button type="button" class="btn-modal-close gift-modal-close-btn">&times;</button>
</div>
<form method="post" action="/modules/gift-list/save-gift.php" id="giftForm">
<input type="hidden" name="year" value="<?= $year ?>">
<input type="hidden" name="child_name" id="modalChild">
<input type="hidden" name="occasion" id="modalOccasion">
<input type="hidden" name="action" id="modalAction">
<input type="hidden" name="gift_id" id="modalGiftId">
<div class="pf-form-group"><label class="pf-label"><?= tr('gift_col_adult') ?></label><select name="adult_name" id="modalAdult" class="pf-input" required></select></div>
<div class="pf-form-group"><label class="pf-label"><?= tr('gift_modal_payer') ?></label><select name="payer_name" id="modalPayer" class="pf-input" required></select></div>
<div class="pf-form-group"><label class="pf-label"><?= tr('gift_modal_gift_name') ?></label><input type="text" name="gift_description" id="modalDesc" class="pf-input" required></div>
<div class="pf-form-group"><label class="pf-label"><?= tr('gift_modal_price') ?></label><input type="number" step="0.01" name="amount" id="modalAmount" class="pf-input"></div>
<div class="pf-form-group gift-form-group-spaced"><label class="pf-label"><?= tr('gift_modal_link') ?></label><input type="url" name="product_link" id="modalLink" class="pf-input"></div>
<div class="modal-footer gift-modal-custom-footer">
<button type="button" class="pf-btn btn-secondary btn-modal-close"><?= tr('btn_cancel') ?></button>
<button type="submit" class="pf-btn"><?= tr('btn_save') ?></button>
</div>
</form>
</div>
</div>
<!-- 2. Modale Paramètres Fêtes -->
<div class="gift-settings-backdrop" id="modal-gift-settings">
<div class="gift-settings-modal">
<div class="gift-settings-header">
<h3>⚙️ <?= tr('gift_settings_title') ?? 'Configuration' ?></h3>
<button class="gift-settings-close" id="btn-close-gift-settings">×</button>
</div>
<div class="gift-settings-body">
<h4 class="gift-add-subtitle"><?= tr('gift_settings_add_title') ?? '+ Ajouter' ?></h4>
<form id="form-add-occasion" class="gift-add-form">
<input type="text" class="pf-input" name="name" placeholder="<?= tr('gift_settings_name_placeholder') ?? 'Nom' ?>" required style="flex: 1; min-width: 150px; padding: 0.4rem 0.75rem;">
<input type="text" class="pf-input" name="month_date" placeholder="<?= tr('gift_settings_date_placeholder') ?? 'MM-JJ' ?>" style="width: 120px; padding: 0.4rem 0.75rem;">
<button type="submit" class="btn btn-secondary"><?= tr('btn_add') ?? 'Ajouter' ?></button>
</form>
<small class="gift-help-text"><?= tr('gift_settings_date_help') ?? 'Optionnel' ?></small>
<hr style="border:0; border-bottom:1px solid var(--border-light); margin: 1rem 0;">
<form id="form-save-toggles">
<div id="occasions-list-container" class="gift-occasions-list"></div>
<div class="modal-footer gift-modal-custom-footer" style="padding-top: 1rem; border-top: 1px solid var(--border-light);">
<button type="button" class="btn btn-secondary" id="btn-cancel-settings"><?= tr('btn_cancel') ?? 'Annuler' ?></button>
<button type="submit" class="btn btn-primary"><?= tr('btn_save') ?? 'Enregistrer' ?></button>
</div>
</form>
</div>
</div>
</div>
<script>
// ==========================================
// 1. GESTION DU COMPOSANT MULTI-SELECT VANILLA
// ==========================================
function toggleMS(listId, triggerEl) {
document.querySelectorAll('.pf-ms-dropdown').forEach(el => { if (el.id !== listId) el.classList.remove('open'); });
document.querySelectorAll('.pf-ms-trigger').forEach(el => { if (el !== triggerEl) el.classList.remove('active'); });
const list = document.getElementById(listId);
if (list) list.classList.toggle('open');
if (triggerEl) triggerEl.classList.toggle('active');
}
document.addEventListener('click', e => {
if (!e.target.closest('.pf-multi-select')) {
document.querySelectorAll('.pf-ms-dropdown').forEach(el => el.classList.remove('open'));
document.querySelectorAll('.pf-ms-trigger').forEach(el => el.classList.remove('active'));
}
});
function handleMSChange(cb, type) {
const container = document.getElementById('ms-' + type + '-list');
if (!container) return;
if (cb.value === 'all' && cb.checked) {
container.querySelectorAll('input[type="checkbox"]:not([value="all"])').forEach(i => i.checked = false);
} else if (cb.checked) {
const allCb = container.querySelector('input[value="all"]');
if (allCb) allCb.checked = false;
} else {
const checkedSpecifics = container.querySelectorAll('input[type="checkbox"]:checked:not([value="all"])');
if (checkedSpecifics.length === 0) {
const allCb = container.querySelector('input[value="all"]');
if (allCb) allCb.checked = true;
}
}
const checkedSpecifics = container.querySelectorAll('input[type="checkbox"]:checked:not([value="all"])');
const labelEl = document.getElementById('ms-' + type + '-label');
if (labelEl) {
if (checkedSpecifics.length === 0) {
let defaultText = 'Tous';
if (window.I18N) {
if (type === 'child' && window.I18N['gift_filter_all_children']) defaultText = window.I18N['gift_filter_all_children'];
if (type === 'adult' && window.I18N['gift_filter_all_adults']) defaultText = window.I18N['gift_filter_all_adults'];
}
labelEl.innerText = defaultText;
} else if (checkedSpecifics.length === 1) {
labelEl.innerText = checkedSpecifics[0].value;
} else {
labelEl.innerText = checkedSpecifics.length + ' sélections';
}
}
applyGiftFilters();
}
function applyGiftFilters() {
const cList = document.getElementById('ms-child-list');
const aList = document.getElementById('ms-adult-list');
if (!cList || !aList) return;
const allChildCb = cList.querySelector('input[value="all"]');
const cAll = allChildCb ? allChildCb.checked : true;
const cVals = Array.from(cList.querySelectorAll('input[type="checkbox"]:checked:not([value="all"])')).map(i => i.value);
const allAdultCb = aList.querySelector('input[value="all"]');
const aAll = allAdultCb ? allAdultCb.checked : true;
const aVals = Array.from(aList.querySelectorAll('input[type="checkbox"]:checked:not([value="all"])')).map(i => i.value);
document.querySelectorAll('.js-occ-section').forEach(occSec => {
let occHasVisible = false;
occSec.querySelectorAll('.js-child').forEach(childSec => {
const cName = childSec.getAttribute('data-name');
const matchChild = cAll || (cVals.indexOf(cName) !== -1);
let childHasVisibleCard = false;
if (matchChild) {
childSec.querySelectorAll('.js-gift-card').forEach(card => {
const aName = card.getAttribute('data-adult');
const matchAdult = aAll || (aVals.indexOf(aName) !== -1);
card.style.display = matchAdult ? 'flex' : 'none';
if (matchAdult) childHasVisibleCard = true;
});
childSec.querySelectorAll('.js-pill-adult').forEach(pill => {
const aName = pill.getAttribute('data-adult');
const matchAdult = aAll || (aVals.indexOf(aName) !== -1);
pill.style.opacity = matchAdult ? '1' : '0.2';
});
const empty = childSec.querySelector('.js-empty-state');
if (empty) empty.style.display = childHasVisibleCard ? 'none' : 'block';
childSec.style.display = 'block';
occHasVisible = true;
} else {
childSec.style.display = 'none';
}
});
occSec.style.display = occHasVisible ? 'block' : 'none';
});
}
// ==========================================
// 2. GESTION DE LA MODALE CADEAU (AJOUT/ÉDITION)
// ==========================================
const modal = document.getElementById('pf-gift-modal');
const adultSelect = document.getElementById('modalAdult');
const payerSelect = document.getElementById('modalPayer');
if (adultSelect && payerSelect) {
adultSelect.addEventListener('change', function() {
let exists = false;
for(let i = 0; i < payerSelect.options.length; i++) {
if(payerSelect.options[i].value === this.value) exists = true;
}
if (exists) payerSelect.value = this.value;
});
}
function populateSelects(adults) {
if (!adultSelect || !payerSelect) return;
adultSelect.innerHTML = '';
payerSelect.innerHTML = '';
adults.forEach(name => {
adultSelect.appendChild(new Option(name, name));
payerSelect.appendChild(new Option(name, name));
});
}
document.body.addEventListener('click', async function(e) {
if (e.target.closest('.btn-modal-close')) {
if (modal) {
modal.classList.remove('open');
document.body.classList.remove('no-scroll');
}
return;
}
const btnAdd = e.target.closest('.btn-add-gift');
if (btnAdd) {
const childName = btnAdd.dataset.child;
const occCode = btnAdd.dataset.occ;
const adultsList = JSON.parse(btnAdd.dataset.adults || '[]');
document.getElementById('modalAction').value = 'create';
document.getElementById('modalGiftId').value = '';
document.getElementById('modalChild').value = childName;
document.getElementById('modalOccasion').value = occCode;
document.getElementById('modalDesc').value = '';
document.getElementById('modalAmount').value = '';
document.getElementById('modalLink').value = '';
populateSelects(adultsList);
if (adultSelect && payerSelect) {
if (adultsList.indexOf('Laia') !== -1) {
adultSelect.value = 'Laia'; payerSelect.value = 'Laia';
} else if (adultsList.length > 0) {
adultSelect.value = adultsList[0]; payerSelect.value = adultsList[0];
}
}
const titleStr = window.I18N && window.I18N['gift_modal_title_add'] ? window.I18N['gift_modal_title_add'] : 'Ajouter pour %s';
document.getElementById('modalTitle').textContent = titleStr.replace('%s', childName);
if (modal) { modal.classList.add('open'); document.body.classList.add('no-scroll'); }
return;
}
const btnEdit = e.target.closest('.btn-edit-gift');
if (btnEdit) {
const data = JSON.parse(btnEdit.dataset.gift || '{}');
document.getElementById('modalAction').value = 'update';
document.getElementById('modalGiftId').value = data.id;
document.getElementById('modalChild').value = data.child_name;
document.getElementById('modalOccasion').value = data.occasion;
document.getElementById('modalDesc').value = data.gift_description;
document.getElementById('modalAmount').value = data.amount;
document.getElementById('modalLink').value = data.product_link;
const payerVal = data.payer_name || data.adult_name;
if (adultSelect && payerSelect) {
let adultExists = false, payerExists = false;
for(let i=0; i<adultSelect.options.length; i++) { if(adultSelect.options[i].value === data.adult_name) adultExists = true; }
for(let i=0; i<payerSelect.options.length; i++) { if(payerSelect.options[i].value === payerVal) payerExists = true; }
if (!adultExists) adultSelect.appendChild(new Option(data.adult_name, data.adult_name));
if (!payerExists) payerSelect.appendChild(new Option(payerVal, payerVal));
adultSelect.value = data.adult_name;
payerSelect.value = payerVal;
}
document.getElementById('modalTitle').textContent = window.I18N && window.I18N['gift_modal_title_edit'] ? window.I18N['gift_modal_title_edit'] : 'Modifier le cadeau';
if (modal) { modal.classList.add('open'); document.body.classList.add('no-scroll'); }
return;
}
const btnDel = e.target.closest('.btn-delete-gift');
if (btnDel) {
const giftId = btnDel.dataset.id;
const msg = window.I18N && window.I18N['gift_confirm_delete'] ? window.I18N['gift_confirm_delete'] : 'Supprimer ce cadeau ?';
if (!confirm(msg)) return;
const fd = new FormData();
fd.append('action', 'delete');
fd.append('gift_id', giftId);
try {
await fetch('/modules/gift-list/save-gift.php', { method: 'POST', body: fd });
window.location.reload();
} catch(err) {
console.error(err);
}
return;
}
});
const giftForm = document.getElementById('giftForm');
if (giftForm) {
giftForm.addEventListener('submit', async (e) => {
e.preventDefault();
const btn = e.target.querySelector('button[type="submit"]');
const oldText = btn.innerText;
btn.innerText = '...';
btn.disabled = true;
try {
await fetch(e.target.getAttribute('action'), { method: 'POST', body: new FormData(e.target) });
window.location.reload();
} catch(err) {
console.error(err);
btn.innerText = oldText;
btn.disabled = false;
}
});
}
// ==========================================
// GESTION DES PARAMÈTRES (MODALE FÊTES ⚙️)
// ==========================================
// 1. Fonctions d'ouverture / fermeture propres
function closeGiftSettings() {
document.getElementById('modal-gift-settings').classList.remove('show');
document.body.classList.remove('no-scroll');
}
const btnOpenSettings = document.getElementById('btn-open-gift-settings');
if (btnOpenSettings) {
btnOpenSettings.addEventListener('click', async (e) => {
e.preventDefault();
const modalSettings = document.getElementById('modal-gift-settings');
if (modalSettings) {
modalSettings.classList.add('show');
document.body.classList.add('no-scroll');
await loadGiftOccasions();
}
});
}
document.getElementById('btn-close-gift-settings')?.addEventListener('click', closeGiftSettings);
document.getElementById('btn-cancel-settings')?.addEventListener('click', closeGiftSettings);
// Fermeture au clic sur le fond (backdrop)
const modalGiftSettings = document.getElementById('modal-gift-settings');
if (modalGiftSettings) {
modalGiftSettings.addEventListener('click', (e) => {
if (e.target === modalGiftSettings) {
closeGiftSettings();
}
});
}
// 2. Chargement dynamique de la liste
async function loadGiftOccasions() {
const container = document.getElementById('occasions-list-container');
if (!container) return;
const txtLoading = window.I18N && window.I18N['loading'] ? window.I18N['loading'] : '⏳';
const txtEmpty = window.I18N && window.I18N['gift_settings_empty'] ? window.I18N['gift_settings_empty'] : 'Vide';
const txtActive = window.I18N && window.I18N['gift_settings_active'] ? window.I18N['gift_settings_active'] : 'Actif';
container.innerHTML = `<div class="gift-loader">${txtLoading}</div>`;
try {
const res = await fetch('/modules/gift-list/api-settings.php?action=get_occasions');
const text = await res.text();
const data = JSON.parse(text);
if (!data.ok) throw new Error(data.error);
if (data.data.length === 0) {
container.innerHTML = `<em>${txtEmpty}</em>`;
return;
}
let html = '<div class="gift-occasions-grid">';
data.data.forEach(occ => {
const isChecked = occ.is_active == 1 ? 'checked' : '';
const dateBadge = occ.month_date ? `<span class="gift-date-badge">${occ.month_date}</span>` : '';
html += `
<div class="pf-card gift-occasion-card">
<div>
<strong>${occ.name}</strong> ${dateBadge}
</div>
<label class="gift-occasion-toggle">
<input type="checkbox" class="occ-toggle-cb" data-id="${occ.id}" ${isChecked}>
<small>${txtActive}</small>
</label>
</div>
`;
});
html += '</div>';
container.innerHTML = html;
} catch (e) {
container.innerHTML = `<div class="gift-error-msg">Erreur : ${e.message}</div>`;
}
}
// 3. Soumission du formulaire d'AJOUT
const formAddOccasion = document.getElementById('form-add-occasion');
if (formAddOccasion) {
formAddOccasion.addEventListener('submit', async (e) => {
e.preventDefault();
const btn = formAddOccasion.querySelector('button[type="submit"]');
const oldText = btn.innerText;
btn.innerText = '⏳';
btn.disabled = true;
const formData = new FormData(formAddOccasion);
formData.append('action', 'add_occasion');
try {
const res = await fetch('/modules/gift-list/api-settings.php', { method: 'POST', body: formData });
const text = await res.text();
const data = JSON.parse(text);
if (!data.ok) throw new Error(data.error || 'Erreur');
formAddOccasion.reset();
await loadGiftOccasions(); // Rafraîchit juste la liste dans la modale !
} catch (err) {
alert("Erreur: " + err.message);
} finally {
btn.innerText = oldText;
btn.disabled = false;
}
});
}
// 4. Soumission GLOBALE (Bouton Enregistrer) pour les Checkboxes
const formSaveToggles = document.getElementById('form-save-toggles');
if (formSaveToggles) {
formSaveToggles.addEventListener('submit', async (e) => {
e.preventDefault();
const btn = formSaveToggles.querySelector('button[type="submit"]');
const oldText = btn.innerText;
btn.innerText = '⏳';
btn.disabled = true;
// On récolte l'état de toutes les checkboxes
const states = [];
formSaveToggles.querySelectorAll('.occ-toggle-cb').forEach(cb => {
states.push({ id: cb.dataset.id, state: cb.checked ? 1 : 0 });
});
const formData = new FormData();
formData.append('action', 'save_toggles');
formData.append('states', JSON.stringify(states));
try {
const res = await fetch('/modules/gift-list/api-settings.php', { method: 'POST', body: formData });
const text = await res.text();
const data = JSON.parse(text);
if (!data.ok) throw new Error(data.error);
// Succès : on rafraîchit la page pour afficher/masquer les onglets
window.location.reload();
} catch (err) {
alert("Erreur: " + err.message);
btn.innerText = oldText;
btn.disabled = false;
}
});
}
</script>
<?php require __DIR__ . '/footer.php'; ?>