diff --git a/modules/holidays/holidays.css b/modules/holidays/holidays.css index 6adac49..94b35ed 100644 --- a/modules/holidays/holidays.css +++ b/modules/holidays/holidays.css @@ -186,6 +186,7 @@ color: #64748b; display: -webkit-box; -webkit-line-clamp: 2; + line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; margin: 0; @@ -488,3 +489,204 @@ input[type="date"]::-webkit-calendar-picker-indicator { input[type="date"]::-webkit-calendar-picker-indicator:hover { opacity: 1; } + +/* ========================================================================== + 12. PAGE DE DÉTAIL DU VOYAGE (detail.php) + ========================================================================== */ + +/* Structure principale de la page détail */ +.pf-holidays-detail { + padding-top: 10px; +} + +/* En-tête de la page détail */ +.hol-detail-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 20px; + flex-wrap: wrap; + gap: 15px; +} + +.hol-detail-title-group { + display: flex; + align-items: center; + gap: 15px; + flex-wrap: wrap; +} + +.hol-detail-title-group h1 { + margin: 0; + font-size: 1.5rem; + color: var(--text-main); +} + +.hol-badge-status { + font-size: 0.75rem; + padding: 4px 10px; + border-radius: 12px; + font-weight: bold; + background: #e0f2fe; + color: #0369a1; +} + +/* Bloc Résumé Financier */ +.hol-summary-card { + background: white; + padding: 20px; + border-radius: var(--radius-l); + box-shadow: var(--shadow-sm); + border: 1px solid #e2e8f0; + margin-bottom: 24px; +} + +.hol-summary-grid { + display: flex; + justify-content: space-between; + margin-bottom: 15px; + flex-wrap: wrap; + gap: 15px; +} + +.hol-summary-item { + min-width: 150px; +} + +.hol-summary-label { + font-size: 0.85rem; + color: var(--text-muted); + margin-bottom: 4px; +} + +.hol-summary-value { + font-weight: 600; + color: var(--text-main); + font-size: 1.1rem; +} + +.hol-summary-value.total { + font-size: 1.4rem; + font-weight: bold; + color: #0f172a; +} + +/* Grille principale : Carte + Timeline */ +.hol-layout-grid { + display: grid; + grid-template-columns: 2fr 1fr; + gap: 20px; + align-items: stretch; +} + +/* Panneaux (Carte et Timeline) */ +.hol-panel { + background: white; + border-radius: var(--radius-l); + box-shadow: var(--shadow-sm); + border: 1px solid #e2e8f0; + display: flex; + flex-direction: column; + height: 600px; + overflow: hidden; +} + +.hol-panel-header { + padding: 15px 20px; + border-bottom: 1px solid #e2e8f0; + display: flex; + justify-content: space-between; + align-items: center; + background: #f8fafc; +} + +.hol-panel-header h3 { + margin: 0; + font-size: 1.1rem; + color: var(--text-main); +} + +.hol-panel-body { + padding: 15px; + overflow-y: auto; + flex: 1; +} + +/* Styles des Checkpoints (Timeline) */ +.hol-checkpoint { + border: 1px solid #e2e8f0; + border-radius: 8px; + margin-bottom: 15px; + overflow: hidden; + background: white; +} + +.hol-cp-header { + background: #f8fafc; + padding: 10px 15px; + display: flex; + justify-content: space-between; + align-items: center; + border-bottom: 1px solid #e2e8f0; +} + +.hol-cp-title { + color: #0f172a; + font-size: 1rem; + font-weight: bold; + cursor: pointer; + transition: color 0.2s; +} + +.hol-cp-title:hover { + color: var(--primary); +} + +.hol-cp-total { + font-size: 0.8rem; + color: var(--text-muted); +} + +.hol-cp-body { + padding: 10px 15px; +} + +.hol-expense-line { + display: flex; + justify-content: space-between; + font-size: 0.85rem; + margin-bottom: 5px; + border-bottom: 1px dashed #f1f5f9; + padding-bottom: 5px; +} + +.hol-expense-line:last-child { + border-bottom: none; + margin-bottom: 0; + padding-bottom: 0; +} + +.hol-notes-panel { + padding: 15px; + border-top: 1px solid #e2e8f0; + background: #fffbeb; +} + +/* --- RESPONSIVE DETAIL PAGE --- */ +@media (max-width: 992px) { + .hol-layout-grid { + grid-template-columns: 1fr; /* Sur tablette/mobile, la carte et la liste s'empilent */ + } + + .hol-panel { + height: 500px; /* On réduit un peu la hauteur pour que ce soit agréable sur mobile */ + } + + .hol-summary-grid { + flex-direction: column; /* Les infos financières s'empilent */ + } + + .hol-summary-item { + text-align: left !important; /* On annule l'alignement à droite du total */ + } +} diff --git a/modules/holidays/views/detail.php b/modules/holidays/views/detail.php index 6dcc46f..c882638 100644 --- a/modules/holidays/views/detail.php +++ b/modules/holidays/views/detail.php @@ -66,30 +66,29 @@ $pctSaved = $cost > 0 ? min(100 - $pctPaid, ($saved / $cost) * 100) : 0;
-
-
+ +
+
◀ Retour -

- - - +

+
- +
-
-
-
-
Période
-
+
+
+
+
Période
+
-
-
Budget Food & Extras
-
🍔 € | 🎁
+
+
Budget Food & Extras
+
🍔 € | 🎁
-
-
Coût Total Estimé
-
+
+
Coût Total Estimé
+
@@ -104,53 +103,54 @@ $pctSaved = $cost > 0 ? min(100 - $pctPaid, ($saved / $cost) * 100) : 0;
-
-
-
-

🗺️ Itinéraire & Checkpoints

- +
+ +
+
+

🗺️ Itinéraire & Checkpoints

+
-
-
-

📝 Détail des étapes

+
+
+

📝 Détail des étapes

-
+
-

Aucune étape planifiée.

+

Aucune étape planifiée.

-
-
+
+
- 📍 -
Total Étape :
+
📍
+
Total Étape :
- +
-
+
'🚗', 'accommodation' => '🏨', 'activity' => '🎫', default => '🏷️' }; ?> -
+
- +
-
Point de passage (Aucune dépense)
+
Point de passage (Aucune dépense)
@@ -160,7 +160,7 @@ $pctSaved = $cost > 0 ? min(100 - $pctPaid, ($saved / $cost) * 100) : 0;
-
+

Notes du voyage :

@@ -170,7 +170,7 @@ $pctSaved = $cost > 0 ? min(100 - $pctPaid, ($saved / $cost) * 100) : 0;
-
+

📍 Placer une étape

@@ -190,7 +190,7 @@ $pctSaved = $cost > 0 ? min(100 - $pctPaid, ($saved / $cost) * 100) : 0;
- +
@@ -203,12 +203,12 @@ $pctSaved = $cost > 0 ? min(100 - $pctPaid, ($saved / $cost) * 100) : 0;
- +
- +
@@ -225,7 +225,6 @@ $pctSaved = $cost > 0 ? min(100 - $pctPaid, ($saved / $cost) * 100) : 0;
-
diff --git a/modules/holidays/views/list.php b/modules/holidays/views/list.php index 3071f4e..116fe47 100644 --- a/modules/holidays/views/list.php +++ b/modules/holidays/views/list.php @@ -1,7 +1,27 @@ query("SELECT DISTINCT YEAR(start_date) as yr FROM pf_holidays WHERE start_date IS NOT NULL ORDER BY yr DESC"); +$availableYears = $yearStmt->fetchAll(PDO::FETCH_COLUMN); +if (!in_array(date('Y'), $availableYears)) { + $availableYears[] = date('Y'); + rsort($availableYears); // Trie par ordre décroissant +} + +// Construction de la condition de filtrage SQL +$whereSQL = ""; +$params = []; +if ($selectedYear !== 'all') { + // On affiche les voyages de l'année OU les voyages sans date (pour ne pas perdre les brouillons) + $whereSQL = "WHERE YEAR(h.start_date) = ? OR h.start_date IS NULL"; + $params[] = $selectedYear; +} + +// 2. Récupération des voyages + Calculs $sql = " SELECT h.*, ( @@ -12,32 +32,58 @@ $sql = " (SELECT COALESCE(SUM(ABS(amount)), 0) FROM pf_expenses WHERE holiday_id = h.id) as total_paid, (SELECT COALESCE(SUM(amount), 0) FROM pf_savings WHERE holiday_id = h.id) as total_saved FROM pf_holidays h + $whereSQL ORDER BY - -- COALESCE permet de rejeter les voyages sans date tout à la fin de la liste (ex: l'an 2999) COALESCE(start_date, '2999-12-31') ASC, - FIELD(status, 'booked', 'planned', 'draft', 'passed', 'archived') "; -$holidays = $pdo->query($sql)->fetchAll(PDO::FETCH_ASSOC); +$stmt = $pdo->prepare($sql); +$stmt->execute($params); +$holidays = $stmt->fetchAll(PDO::FETCH_ASSOC); -// Tri par statut +// 3. Tri par statut $active = array_filter($holidays, fn($h) => in_array($h['status'], ['draft', 'planned', 'booked'])); $history = array_filter($holidays, fn($h) => in_array($h['status'], ['passed', 'archived'])); + +// 4. Calcul du Reste à Payer Global (uniquement sur les voyages Actifs affichés) +$globalLeftToPay = 0; +foreach ($active as $h) { + $cost = (float)$h['total_cost']; + $paid = (float)$h['total_paid']; + $globalLeftToPay += max(0, $cost - $paid); +} ?>
-
-

Mes Vacances ✈️

-
- +
+ +
+

Mes Vacances ✈️

+ + + +
+ ⏳ Reste à payer () : + +
+ +
+ +
+
-

Aucun voyage en cours. Planifions quelque chose !

+

Aucun voyage en cours pour cette période. Planifions quelque chose !

@@ -62,6 +108,7 @@ $history = array_filter($holidays, fn($h) => in_array($h['status'], ['passed', ' prepare("SELECT * FROM pf_holidays_items WHERE holiday_id = ?"); $stmt->execute([$h['id']]); @@ -82,14 +129,12 @@ function renderHolidayCard($h, $pdo) { default => 'bg-yellow-50 text-yellow-800' }; - // --- Calcul des métriques financières --- $cost = (float)$h['total_cost']; $paid = (float)$h['total_paid']; $saved = (float)$h['total_saved']; $leftToPay = max(0, $cost - $paid); - // Calculs pour la barre de progression bicolore $pctPaid = $cost > 0 ? min(100, ($paid / $cost) * 100) : 0; $pctSaved = $cost > 0 ? min(100 - $pctPaid, ($saved / $cost) * 100) : 0;