translate

This commit is contained in:
2026-04-02 17:41:50 +02:00
parent 7df7144147
commit 97a8fb546e
5 changed files with 210 additions and 51 deletions
+31 -12
View File
@@ -1,13 +1,26 @@
<?php
if (session_status() === PHP_SESSION_NONE) session_start();
// 1. Inclusion du moteur de traduction
require_once __DIR__ . '/includes/i18n.php';
// Petite fonction pour changer de langue sans perdre les paramètres de l'URL (ex: id=5)
function getLangUrl($newLang) {
$params = $_GET;
$params['lang'] = $newLang;
return '?' . http_build_query($params);
}
$pageTitle = $pageTitle ?? "PachaFamily";
$activePage = $activePage ?? "";
$currentLang = $_SESSION['app_lang'] ?? 'fr'; // Récupération de la langue active
?>
<!DOCTYPE html>
<html lang="fr">
<html lang="<?= htmlspecialchars($currentLang) ?>">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title><?= htmlspecialchars($pageTitle) ?></title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?= htmlspecialchars($pageTitle) ?></title>
<link rel="icon" type="image/png" href="/favicon.png">
<link rel="apple-touch-icon" href="/favicon.png">
<link rel="stylesheet" href="/global.css">
@@ -21,14 +34,20 @@ $activePage = $activePage ?? "";
<a href="/index.php" class="pf-logo">PachaFamily</a>
<nav class="pf-nav">
<a href="/index.php" class="pf-nav-link <?= $activePage === 'home' ? 'pf-nav-link--active' : '' ?>">Accueil</a>
<a href="/family-calendar.php" class="pf-nav-link <?= $activePage === 'family-calendar' ? 'pf-nav-link--active' : '' ?>">Calendrier</a>
<a href="/budget.php" class="pf-nav-link <?= $activePage === 'budget' ? 'pf-nav-link--active' : '' ?>">Budget</a>
<a href="/holidays.php" class="pf-nav-link <?= $activePage === 'holidays' ? 'pf-nav-link--active' : '' ?>">Vacances</a>
<a href="/gift-list.php" class="pf-nav-link <?= $activePage === 'gift-list' ? 'pf-nav-link--active' : '' ?>">Cadeaux</a>
<a href="/index.php" class="pf-nav-link <?= $activePage === 'home' ? 'pf-nav-link--active' : '' ?>"><?= tr('menu_home') ?></a>
<a href="/family-calendar.php" class="pf-nav-link <?= $activePage === 'family-calendar' ? 'pf-nav-link--active' : '' ?>"><?= tr('menu_calendar') ?></a>
<a href="/budget.php" class="pf-nav-link <?= $activePage === 'budget' ? 'pf-nav-link--active' : '' ?>"><?= tr('menu_budget') ?></a>
<a href="/holidays.php" class="pf-nav-link <?= $activePage === 'holidays' ? 'pf-nav-link--active' : '' ?>"><?= tr('menu_holidays') ?></a>
<a href="/gift-list.php" class="pf-nav-link <?= $activePage === 'gift-list' ? 'pf-nav-link--active' : '' ?>"><?= tr('menu_gifts') ?></a>
</nav>
<div class="pf-header-actions">
<div style="display: flex; align-items: center; gap: 8px; margin-right: 15px; border-right: 1px solid #cbd5e1; padding-right: 15px;">
<a href="<?= getLangUrl('fr') ?>" style="text-decoration:none; font-weight:bold; color: <?= $currentLang === 'fr' ? '#2563eb' : '#94a3b8' ?>;" title="Français">FR</a>
<span style="color: #cbd5e1;">|</span>
<a href="<?= getLangUrl('ca') ?>" style="text-decoration:none; font-weight:bold; color: <?= $currentLang === 'ca' ? '#f59e0b' : '#94a3b8' ?>;" title="Català">CA</a>
</div>
<?php if (isset($_SESSION['user'])): ?>
<div class="pf-user-badge">
<?= htmlspecialchars($_SESSION['user']['display_name'] ?? $_SESSION['user']['username']) ?>
@@ -43,11 +62,11 @@ $activePage = $activePage ?? "";
</header>
<div class="pf-mobile-menu">
<a href="/index.php" class="pf-mobile-nav-link">Accueil</a>
<a href="/family-calendar.php" class="pf-mobile-nav-link">Calendrier</a>
<a href="/budget.php" class="pf-mobile-nav-link">Budget</a>
<a href="/holidays.php" class="pf-mobile-nav-link">Vacances</a>
<a href="/gift-list.php" class="pf-mobile-nav-link">Cadeaux</a>
<a href="/index.php" class="pf-mobile-nav-link"><?= tr('menu_home') ?></a>
<a href="/family-calendar.php" class="pf-mobile-nav-link"><?= tr('menu_calendar') ?></a>
<a href="/budget.php" class="pf-mobile-nav-link"><?= tr('menu_budget') ?></a>
<a href="/holidays.php" class="pf-mobile-nav-link"><?= tr('menu_holidays') ?></a>
<a href="/gift-list.php" class="pf-mobile-nav-link"><?= tr('menu_gifts') ?></a>
<?php if (isset($_SESSION['user'])): ?>
<a href="/logout.php" class="pf-mobile-nav-link pf-mobile-logout">Se déconnecter</a>
<?php else: ?>
+29
View File
@@ -0,0 +1,29 @@
<?php
// Démarrer la session si ce n'est pas déjà fait (souvent fait dans auth.php, mais on sécurise)
if (session_status() === PHP_SESSION_NONE) {
session_start();
}
// 1. Changement de langue si l'utilisateur a cliqué sur un drapeau (?lang=ca ou ?lang=fr)
if (isset($_GET['lang']) && in_array($_GET['lang'], ['fr', 'ca'])) {
$_SESSION['app_lang'] = $_GET['lang'];
}
// 2. Langue par défaut = Français
$current_lang = $_SESSION['app_lang'] ?? 'fr';
// 3. Chargement du bon dictionnaire
$lang_file = __DIR__ . '/lang/' . $current_lang . '.php';
if (file_exists($lang_file)) {
$GLOBALS['translations'] = include $lang_file;
} else {
$GLOBALS['translations'] = [];
}
// 4. La fonction magique de traduction
// Si le mot existe dans le dictionnaire on l'affiche, sinon on affiche la clé par défaut
if (!function_exists('tr')) {
function tr($key) {
return $GLOBALS['translations'][$key] ?? $key;
}
}
+55
View File
@@ -0,0 +1,55 @@
<?php
// Dictionnaire Catalan
return [
'menu_home' => 'Inici',
'menu_budget' => 'Pressupost',
'menu_calendar' => 'Calendari',
'menu_gifts' => 'Regals',
'menu_holidays' => 'Viatges',
'outbound_trip' => 'Anada',
'return_trip' => 'Tornada',
'btn_back' => '◀ Tornar',
'btn_edit_bases' => '⚙️ Modificar les bases',
'period' => 'Període',
'budget_food' => 'Pressupost Menjar i Extres',
'total_cost' => 'Cost Total Estimat',
'paid' => 'Pagat',
'provisioned' => 'Provisionat',
'left_to_pay' => 'Pendent de pagament',
'map_itinerary' => '🗺️ Itinerari',
'outbound_trip' => 'Anada',
'return_trip' => 'Tornada',
'place_step' => '📍 Afegir una etapa',
'step_details' => '📝 Detall de les etapes',
'no_steps' => 'Cap etapa planificada.',
'travel_notes' => '📝 Notes del viatge',
'edit' => 'Modificar',
// --- Paraules diverses & Tooltips ---
'error' => 'Error.',
'to_be_defined' => 'A definir',
'funded' => 'Finançat (Provisió)',
'view_planning' => 'Veure el planning',
'to_pay' => 'A pagar',
'from_date' => 'Del',
'to_date' => 'al',
'passing_point' => 'Punt de pas (Cap despesa)',
// --- Modal : Afegir / Editar una etapa ---
'search_location' => 'Cercar una ubicació geogràfica',
'search_placeholder' => 'Ex: París, Ibis Barcelona...',
'step_name' => 'Nom de l\'etapa',
'arrival_optional' => 'Arribada el (Opcional)',
'departure_optional' => 'Sortida el (Opcional)',
'planned_expenses' => 'Despeses previstes',
'add_expense' => '+ Afegir una despesa',
'save_favorite' => 'Guardar als meus preferits',
// --- Botons genèrics ---
'btn_delete' => 'Eliminar',
'btn_cancel' => 'Cancel·lar',
'btn_save' => 'Guardar',
'btn_close' => 'Tancar',
'planning_title' => 'Planning',
];
+54
View File
@@ -0,0 +1,54 @@
<?php
// Dictionnaire Français
return [
'menu_home' => 'Accueil',
'menu_budget' => 'Budget',
'menu_calendar' => 'Calendrier',
'menu_gifts' => 'Cadeaux',
'menu_holidays' => 'Voyages',
'outbound_trip' => 'Aller',
'btn_back' => '◀ Retour',
'btn_edit_bases' => '⚙️ Modifier les bases',
'period' => 'Période',
'budget_food' => 'Budget Food & Extras',
'total_cost' => 'Coût Total Estimé',
'paid' => 'Payé',
'provisioned' => 'Provisionné',
'left_to_pay' => 'Reste à payer',
'map_itinerary' => '🗺️ Itinéraire',
'outbound_trip' => 'Aller',
'return_trip' => 'Retour',
'place_step' => '📍 Placer une étape',
'step_details' => '📝 Détail des étapes',
'no_steps' => 'Aucune étape planifiée.',
'travel_notes' => '📝 Notes du voyage',
'edit' => 'Modifier',
// --- Mots divers & Infobulles ---
'error' => 'Erreur.',
'to_be_defined' => 'À définir',
'funded' => 'Financé (Provision)',
'view_planning' => 'Voir le planning',
'to_pay' => 'À payer',
'from_date' => 'Du',
'to_date' => 'au',
'passing_point' => 'Point de passage (Aucune dépense)',
// --- Modale : Placer / Éditer une étape ---
'search_location' => 'Rechercher un lieu géographique',
'search_placeholder' => 'Ex: Paris, Ibis Barcelone...',
'step_name' => 'Nom de l\'étape',
'arrival_optional' => 'Arrivée le (Optionnel)',
'departure_optional' => 'Départ le (Optionnel)',
'planned_expenses' => 'Dépenses prévues',
'add_expense' => '+ Ajouter une dépense',
'save_favorite' => 'Sauvegarder dans mes favoris',
// --- Boutons génériques ---
'btn_delete' => 'Supprimer',
'btn_cancel' => 'Annuler',
'btn_save' => 'Enregistrer',
'btn_close' => 'Fermer',
'planning_title' => 'Planning',
];
+41 -39
View File
@@ -3,7 +3,7 @@
$id = isset($_GET['id']) ? (int)$_GET['id'] : 0;
if ($id === 0) { echo "<div class='pf-section'><p>Erreur.</p></div>"; exit; }
if ($id === 0) { echo "<div class='pf-section'><p><p>".tr('error')."</p></p></div>"; exit; }
$stmt = $pdo->prepare("
SELECT h.*,
@@ -75,7 +75,7 @@ $pctSaved = $cost > 0 ? min(100 - $pctPaid, ($saved / $cost) * 100) : 0;
<div style="display: flex; justify-content: space-between; align-items: flex-end; margin-bottom: 20px; flex-wrap: wrap; gap: 15px;">
<div style="display: flex; flex-direction: column; gap: 12px;">
<a href="?tab=list" class="pf-btn btn-secondary pf-btn-small" style="width: fit-content; text-decoration: none;">◀ Retour</a>
<a href="?tab=list" class="pf-btn btn-secondary pf-btn-small" style="width: fit-content; text-decoration: none;"><?= tr('btn_back') ?></a>
<div style="display: flex; align-items: center; gap: 15px;">
<h1 style="margin: 0; font-size: 1.8rem;"><?= htmlspecialchars($holiday['title']) ?></h1>
<span class="hol-badge-status"><?= strtoupper($holiday['status']) ?></span>
@@ -87,7 +87,7 @@ $pctSaved = $cost > 0 ? min(100 - $pctPaid, ($saved / $cost) * 100) : 0;
<?= json_encode(['main' => $holiday, 'items' => $generalItems], JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP) ?>
</script>
<button type="button" class="pf-btn btn-secondary pf-btn-small" onclick="editHoliday(JSON.parse(document.getElementById('holidayDataJson').textContent))">
⚙️ Modifier les bases
<?= tr('btn_edit_bases') ?>
</button>
</div>
</div>
@@ -95,27 +95,27 @@ $pctSaved = $cost > 0 ? min(100 - $pctPaid, ($saved / $cost) * 100) : 0;
<div class="hol-summary-card" style="width: 100%; display: block; clear: both;">
<div class="hol-summary-grid">
<div class="hol-summary-item">
<div class="hol-summary-label">Période</div>
<div class="hol-summary-value"><?= $dateDisplay ?: 'À définir' ?></div>
<div class="hol-summary-label"><?= tr('period') ?></div>
<div class="hol-summary-value"><?= $dateDisplay ?: tr('to_be_defined') ?></div>
</div>
<div class="hol-summary-item">
<div class="hol-summary-label">Budget Food & Extras</div>
<div class="hol-summary-label"><?= tr('budget_food') ?></div>
<div class="hol-summary-value">🍔 <?= number_format($holiday['budget_food'], 0) ?> € | 🎁 <?= number_format($holiday['budget_extra'], 0) ?> €</div>
</div>
<div class="hol-summary-item">
<div class="hol-summary-label">Coût Total Estimé</div>
<div class="hol-summary-label"><?= tr('total_cost') ?></div>
<div class="hol-summary-value total"><?= number_format($cost, 0, ',', ' ') ?> €</div>
</div>
</div>
<div class="hol-progress-bar">
<div class="hol-progress-paid" style="width:<?= $pctPaid ?>%;" title="Payé"></div>
<div class="hol-progress-saved" style="width:<?= $pctSaved ?>%;" title="Financé (Provision)"></div>
<div class="hol-progress-paid" style="width:<?= $pctPaid ?>%;" title="<?= tr('paid') ?>"></div>
<div class="hol-progress-saved" style="width:<?= $pctSaved ?>%;" title="<?= tr('funded') ?>"></div>
</div>
<div class="hol-progress-labels">
<span class="hol-label-paid">✓ Payé : <?= number_format($paid, 0, ',', ' ') ?> €</span>
<span class="hol-label-saved">💼 Provision : <?= number_format($saved, 0, ',', ' ') ?> €</span>
<span class="hol-label-left">⏳ Reste à payer : <?= number_format($leftToPay, 0, ',', ' ') ?> €</span>
<span class="hol-label-paid">✓ <?= tr('paid') ?> : <?= number_format($paid, 0, ',', ' ') ?> €</span>
<span class="hol-label-saved">💼 <?= tr('provisioned') ?> : <?= number_format($saved, 0, ',', ' ') ?> €</span>
<span class="hol-label-left">⏳ <?= tr('left_to_pay') ?> : <?= number_format($leftToPay, 0, ',', ' ') ?> €</span>
</div>
</div>
@@ -124,25 +124,25 @@ $pctSaved = $cost > 0 ? min(100 - $pctPaid, ($saved / $cost) * 100) : 0;
<div class="hol-panel">
<div class="hol-panel-header" style="flex-wrap: wrap; gap: 10px;">
<div class="hol-panel-header-group">
<h3 style="margin:0;">🗺️ Itinéraire</h3>
<h3 style="margin:0;"><?= tr('map_itinerary') ?></h3>
<div class="hol-map-legend">
<span class="hol-legend-item" title="Trajet aller"><span class="hol-legend-color aller"></span> Aller</span>
<span class="hol-legend-item" title="Trajet retour"><span class="hol-legend-color retour"></span> Retour</span>
<span class="hol-legend-item" title="<?= tr('outbound_trip') ?>"><span class="hol-legend-color aller"></span> <?= tr('outbound_trip') ?></span>
<span class="hol-legend-item" title="<?= tr('return_trip') ?>"><span class="hol-legend-color retour"></span> <?= tr('return_trip') ?></span>
</div>
</div>
<button class="pf-btn pf-btn-small" onclick="openCheckpointModal('add')">📍 Placer une étape</button>
<button class="pf-btn pf-btn-small" onclick="openCheckpointModal('add')"><?= tr('place_step') ?></button>
</div>
<div id="tripMap" style="flex:1; width:100%; background:#f1f5f9;"></div>
</div>
<div class="hol-panel">
<div class="hol-panel-header">
<h3 style="margin:0;">📝 Détail des étapes</h3>
<h3 style="margin:0;"><?= tr('step_details') ?></h3>
</div>
<div class="hol-panel-body">
<?php if (empty($steps)): ?>
<p style="color:var(--text-muted); font-style:italic; text-align:center; margin-top:40px;">Aucune étape planifiée.</p>
<p style="color:var(--text-muted); font-style:italic; text-align:center; margin-top:40px;"><?= tr('no_steps') ?></p>
<?php else: ?>
<?php foreach ($steps as $step): ?>
<div id="step-card-<?= $step['sort_order'] ?>" class="hol-checkpoint hol-checkpoint-draggable" draggable="true" data-location="<?= htmlspecialchars($step['location_name']) ?>">
@@ -152,19 +152,19 @@ $pctSaved = $cost > 0 ? min(100 - $pctPaid, ($saved / $cost) * 100) : 0;
<div class="hol-cp-title" onclick="panMapTo(<?= $step['lat'] ?>, <?= $step['lng'] ?>)" title="<?= htmlspecialchars($step['location_name']) ?>">
📍 <?= htmlspecialchars($step['location_name']) ?>
<?php if (!empty($step['is_return'])): ?>
<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;">🏁 Retour</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('return_trip') ?></span>
<?php endif; ?>
<?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;">
Du <?= date('d/m', strtotime($step['step_start_date'])) ?> au <?= date('d/m', strtotime($step['step_end_date'])) ?>
<?= tr('from_date') ?> <?= date('d/m', strtotime($step['step_start_date'])) ?> <?= tr('to_date') ?> <?= date('d/m', strtotime($step['step_end_date'])) ?>
</div>
<?php endif; ?>
</div>
</div>
<div class="hol-cp-actions-group">
<div class="hol-cp-total"><?= number_format($step['total_amount'], 2, ',', ' ') ?> €</div>
<button onclick='openPlanningModal(<?= htmlspecialchars(json_encode($step), ENT_QUOTES, "UTF-8") ?>)' class="btn-icon-small" title="Voir le planning">📅</button>
<button onclick='openCheckpointModal("edit", <?= htmlspecialchars(json_encode($step), ENT_QUOTES, "UTF-8") ?>)' class="btn-icon-small" title="Modifier">✏️</button>
<button onclick='openPlanningModal(<?= htmlspecialchars(json_encode($step), ENT_QUOTES, "UTF-8") ?>)' class="btn-icon-small" title="<?= tr('view_planning') ?>">📅</button>
<button onclick='openCheckpointModal("edit", <?= htmlspecialchars(json_encode($step), ENT_QUOTES, "UTF-8") ?>)' class="btn-icon-small" title="<?= tr('edit') ?>">✏️</button>
</div>
</div>
@@ -181,14 +181,14 @@ $pctSaved = $cost > 0 ? min(100 - $pctPaid, ($saved / $cost) * 100) : 0;
<span class="hol-expense-name"><?= $icon ?> <?= htmlspecialchars($it['name']) ?></span>
<span>
<strong class="hol-expense-amount"><?= number_format($it['amount'], 2, ',', ' ') ?> €</strong>
<span class="<?= $it['is_paid'] ? 'status-paid' : 'status-pending' ?>" title="<?= $it['is_paid'] ? 'Payé' : 'À payer' ?>"><?= $it['is_paid'] ? '✓' : '⏳' ?></span>
<span class="<?= $it['is_paid'] ? 'status-paid' : 'status-pending' ?>" title="<?= $it['is_paid'] ? tr('paid') : tr('to_pay') ?>"><?= $it['is_paid'] ? '✓' : '⏳' ?></span>
</span>
</div>
</div>
<?php endforeach; ?>
<?php if ($visibleItemsCount === 0): ?>
<div class="hol-empty-step">📍 Point de passage (Aucune dépense)</div>
<div class="hol-empty-step">📍 <?= tr('passing_point') ?></div>
<?php endif; ?>
</div>
</div>
@@ -199,7 +199,7 @@ $pctSaved = $cost > 0 ? min(100 - $pctPaid, ($saved / $cost) * 100) : 0;
</div> <?php if (!empty($holiday['notes'])): ?>
<div class="hol-summary-card" style="margin-top: 24px; padding: 25px; border-left: 5px solid #f59e0b;">
<h3 style="margin: 0 0 15px 0; font-size: 1.2rem; color: #0f172a; display: flex; align-items: center; gap: 8px;">
📝 Notes du voyage
<?= tr('travel_notes') ?>
</h3>
<div style="font-size: 0.95rem; color: #334155; white-space: pre-wrap; line-height: 1.6; font-family: 'Segoe UI', system-ui, sans-serif;">
<?= htmlspecialchars($holiday['notes']) ?>
@@ -213,7 +213,7 @@ $pctSaved = $cost > 0 ? min(100 - $pctPaid, ($saved / $cost) * 100) : 0;
<div id="checkpointModal" class="pf-modal">
<div class="pf-modal-content" style="max-width: 600px;">
<div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:20px;">
<h3 id="cpModalTitle" style="margin:0;">📍 Placer une étape</h3>
<h3 id="cpModalTitle" style="margin:0;">📍 <?= tr('place_step') ?></h3>
<button type="button" onclick="document.getElementById('checkpointModal').style.display='none'; document.body.classList.remove('no-scroll');" style="border:none; background:none; font-size:1.8rem; cursor:pointer;">&times;</button> </div>
<div id="cpSearchBlock" style="margin-bottom:20px;">
@@ -227,9 +227,9 @@ $pctSaved = $cost > 0 ? min(100 - $pctPaid, ($saved / $cost) * 100) : 0;
</div>
<?php endif; ?>
<label class="pf-label">Rechercher un lieu géographique</label>
<label class="pf-label"><?= tr('search_location') ?></label>
<div style="display:flex; gap:10px;">
<input type="text" id="searchPlaceInput" class="pf-input" placeholder="Ex: Paris, Ibis Barcelone..." onkeypress="if(event.key === 'Enter') { searchPlace(); return false; }">
<input type="text" id="searchPlaceInput" class="pf-input" placeholder="<?= tr('search_placeholder') ?>" onkeypress="if(event.key === 'Enter') { searchPlace(); return false; }">
<button type="button" class="pf-btn btn-secondary" onclick="searchPlace()" style="width:auto; margin:0;">🔍</button>
</div>
<div id="searchResults" style="margin-top:10px; max-height:200px; overflow-y:auto; display:flex; flex-direction:column; gap:5px;"></div>
@@ -243,29 +243,29 @@ $pctSaved = $cost > 0 ? min(100 - $pctPaid, ($saved / $cost) * 100) : 0;
<input type="hidden" name="old_sort_order" id="cp_old_sort_order">
<div class="form-group" style="margin-bottom:15px;">
<label class="pf-label">Nom de l'étape</label>
<label class="pf-label"><?= tr('step_name') ?></label>
<input type="text" name="location_name" id="cp_name" class="pf-input" style="font-weight:bold; color:var(--primary);" required>
</div>
<div style="display:flex; gap:15px; margin-bottom:15px; background:#f8fafc; padding:12px; border-radius:8px; border:1px solid #e2e8f0;">
<div class="form-group" style="flex:1; margin:0;">
<label class="pf-label">Arrivée le (Optionnel)</label>
<label class="pf-label"><?= tr('arrival_optional') ?></label>
<input type="date" name="step_start_date" id="cp_start_date" class="pf-input">
</div>
<div class="form-group" style="flex:1; margin:0;">
<label class="pf-label">Départ le (Optionnel)</label>
<label class="pf-label"><?= tr('departure_optional') ?></label>
<input type="date" name="step_end_date" id="cp_end_date" class="pf-input">
</div>
<div style="margin-bottom: 15px; padding-left: 5px;">
<label style="display:flex; align-items:center; cursor:pointer; font-size:0.9rem; color:#d97706; font-weight:600;">
<input type="checkbox" name="is_return" id="cp_is_return" value="1" style="margin-right:8px; width:16px; height:16px;">
🏁 Trajet retour
🏁 <?= tr('return_trip') ?>
</label>
</div>
</div>
<div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:10px;">
<label class="pf-label" style="margin:0;">Dépenses prévues</label>
<button type="button" class="pf-btn btn-secondary" onclick="addCpExpenseLine()" style="padding:4px 8px; font-size:0.8rem; height:auto; width:auto; margin:0;">+ Ajouter une dépense</button>
<label class="pf-label" style="margin:0;"><?= tr('planned_expenses') ?></label>
<button type="button" class="pf-btn btn-secondary" onclick="addCpExpenseLine()" style="padding:4px 8px; font-size:0.8rem; height:auto; width:auto; margin:0;"><?= tr('add_expense') ?></button>
</div>
<div id="cpExpensesContainer" style="margin-bottom:15px; display:flex; flex-direction:column; gap:10px; max-height:350px; overflow-y:auto; overflow-x:hidden;">
@@ -274,16 +274,17 @@ $pctSaved = $cost > 0 ? min(100 - $pctPaid, ($saved / $cost) * 100) : 0;
<div style="margin-bottom: 20px; padding-left: 5px;">
<label style="display:flex; align-items:center; cursor:pointer; font-size:0.85rem; color:#475569;">
<input type="checkbox" name="save_favorite" value="1" style="margin-right:8px;">
Sauvegarder dans mes favoris
<?= tr('save_favorite') ?>
</label>
</div>
<div style="display:flex; justify-content:space-between; align-items:center; border-top:1px solid #e2e8f0; padding-top:15px;">
<div>
<button type="button" onclick="deleteCheckpoint()" id="btnDeleteCp" class="pf-btn btn-secondary" style="color:#ef4444; border-color:#fca5a5; display:none; width:auto; margin:0;">🗑️ Supprimer</button>
<button type="button" onclick="deleteCheckpoint()" id="btnDeleteCp" class="pf-btn btn-secondary" style="color:#ef4444; border-color:#fca5a5; display:none; width:auto; margin:0;">🗑️ <?= tr('btn_delete') ?></button>
</div>
<div style="display:flex; gap:10px;">
<button type="button" onclick="document.getElementById('checkpointModal').style.display='none'; document.body.classList.remove('no-scroll');" class="pf-btn btn-secondary" style="width:auto; margin:0;">Annuler</button> <button type="submit" class="pf-btn" style="width:auto; margin:0;">Enregistrer</button>
<button type="button" onclick="document.getElementById('checkpointModal').style.display='none'; document.body.classList.remove('no-scroll');" class="pf-btn btn-secondary" style="width:auto; margin:0;"><?= tr('btn_cancel') ?></button>
<button type="submit" class="pf-btn" style="width:auto; margin:0;"><?= tr('btn_save') ?></button>
</div>
</div>
</form>
@@ -293,13 +294,14 @@ $pctSaved = $cost > 0 ? min(100 - $pctPaid, ($saved / $cost) * 100) : 0;
<div id="planningModal" class="pf-modal">
<div class="pf-modal-content" style="max-width: 550px;">
<div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:20px;">
<h3 id="planningModalTitle" style="margin:0; color:var(--primary);">📅 Planning</h3>
<h3 id="planningModalTitle" style="margin:0; color:var(--primary);">📅 <?= tr('planning_title') ?></h3>
<button type="button" onclick="document.getElementById('planningModal').style.display='none'; document.body.classList.remove('no-scroll');" style="border:none; background:none; font-size:1.8rem; cursor:pointer;">&times;</button> </div>
<div id="planningContainer" style="width: 100%;">
<div style="margin-top:20px; display:flex; justify-content:flex-end;">
<button type="button" onclick="document.getElementById('planningModal').style.display='none'; document.body.classList.remove('no-scroll');" class="pf-btn btn-secondary">Fermer</button> </div>
<button type="button" onclick="document.getElementById('planningModal').style.display='none'; document.body.classList.remove('no-scroll');" class="pf-btn btn-secondary"><?= tr('btn_close') ?></button>
</div>
</div>
</div>