maj MAP
This commit is contained in:
@@ -18,22 +18,19 @@ $stmt = $pdo->prepare("
|
||||
$stmt->execute([$id]);
|
||||
$holiday = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
// IMPORTANT : Le tri se fait maintenant sur "sort_order" pour que le glisser-déposer fonctionne
|
||||
$stmtItems = $pdo->prepare("SELECT * FROM pf_holidays_items WHERE holiday_id = ? ORDER BY sort_order ASC, id ASC");
|
||||
$stmtItems->execute([$id]);
|
||||
$items = $stmtItems->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
// Récupération des favoris géographiques
|
||||
$stmtFav = $pdo->query("SELECT content FROM pf_notes WHERE note_type = 'holiday_favorites'");
|
||||
$favorites = json_decode($stmtFav->fetchColumn() ?: '[]', true);
|
||||
|
||||
// GROUPEMENT PAR INDEX D'ORDRE (Pour autoriser les doublons de lieux comme "Maison")
|
||||
$steps = [];
|
||||
$generalItems = [];
|
||||
|
||||
foreach ($items as $it) {
|
||||
if ($it['location_name'] !== null) {
|
||||
$orderKey = $it['sort_order']; // On utilise l'ordre comme clé unique de l'étape
|
||||
$orderKey = $it['sort_order'];
|
||||
if (!isset($steps[$orderKey])) {
|
||||
$steps[$orderKey] = [
|
||||
'location_name' => $it['location_name'],
|
||||
@@ -53,7 +50,6 @@ foreach ($items as $it) {
|
||||
ksort($steps);
|
||||
$mapPoints = array_values($steps);
|
||||
|
||||
// Calculs d'affichage (Dates & Finances)
|
||||
$dateDisplay = htmlspecialchars($holiday['period_hint'] ?? '');
|
||||
if (empty($dateDisplay) && $holiday['start_date']) {
|
||||
$dateDisplay = date('d/m/Y', strtotime($holiday['start_date']));
|
||||
@@ -75,11 +71,11 @@ $pctSaved = $cost > 0 ? min(100 - $pctPaid, ($saved / $cost) * 100) : 0;
|
||||
|
||||
<div class="hol-detail-header">
|
||||
<div class="hol-detail-title-group">
|
||||
<a href="?tab=list" class="pf-btn btn-secondary" style="padding:6px 12px; height:auto; width:auto; text-decoration:none;">◀ Retour</a>
|
||||
<a href="?tab=list" class="pf-btn btn-secondary">◀ Retour</a>
|
||||
<h1><?= htmlspecialchars($holiday['title']) ?></h1>
|
||||
<span class="hol-badge-status"><?= strtoupper($holiday['status']) ?></span>
|
||||
</div>
|
||||
<button onclick='editHoliday(<?= htmlspecialchars(json_encode(['main' => $holiday, 'items' => $generalItems]), ENT_QUOTES, 'UTF-8') ?>)' class="pf-btn btn-secondary" style="width:auto; margin:0;">⚙️ Modifier les bases</button>
|
||||
<button onclick='editHoliday(<?= htmlspecialchars(json_encode(['main' => $holiday, 'items' => $generalItems]), ENT_QUOTES, 'UTF-8') ?>)' class="pf-btn btn-secondary">⚙️ Modifier les bases</button>
|
||||
</div>
|
||||
|
||||
<div class="hol-summary-card">
|
||||
@@ -92,36 +88,43 @@ $pctSaved = $cost > 0 ? min(100 - $pctPaid, ($saved / $cost) * 100) : 0;
|
||||
<div class="hol-summary-label">Budget Food & Extras</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" style="text-align:right;">
|
||||
<div class="hol-summary-item">
|
||||
<div class="hol-summary-label">Coût Total Estimé</div>
|
||||
<div class="hol-summary-value total"><?= number_format($cost, 0, ',', ' ') ?> €</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="width:100%; height:12px; background:#e2e8f0; border-radius:6px; margin-bottom:10px; display:flex; overflow:hidden;">
|
||||
<div style="width:<?= $pctPaid ?>%; background:#10b981;" title="Payé"></div>
|
||||
<div style="width:<?= $pctSaved ?>%; background:#3b82f6;" title="Financé (Provision)"></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>
|
||||
<div style="display:flex; justify-content:space-between; font-size:0.85rem;">
|
||||
<span style="color:#10b981; font-weight:600;">✓ Payé : <?= number_format($paid, 0, ',', ' ') ?> €</span>
|
||||
<span style="color:#3b82f6; font-weight:600;">💼 Provisionné : <?= number_format($saved, 0, ',', ' ') ?> €</span>
|
||||
<span style="color:#ef4444; font-weight:700;">⏳ Reste à payer : <?= number_format($leftToPay, 0, ',', ' ') ?> €</span>
|
||||
<div class="hol-progress-labels">
|
||||
<span class="hol-label-paid">✓ Payé : <?= number_format($paid, 0, ',', ' ') ?> €</span>
|
||||
<span class="hol-label-saved">💼 Provisionné : <?= number_format($saved, 0, ',', ' ') ?> €</span>
|
||||
<span class="hol-label-left">⏳ Reste à payer : <?= number_format($leftToPay, 0, ',', ' ') ?> €</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="hol-layout-grid">
|
||||
|
||||
<div class="hol-panel">
|
||||
<div class="hol-panel-header">
|
||||
<h3>🗺️ Itinéraire & Checkpoints</h3>
|
||||
<button class="pf-btn" onclick="openCheckpointModal('add')" style="padding:6px 12px; height:auto; width:auto; font-size:0.85rem; margin:0;">📍 Placer une étape</button>
|
||||
<div class="hol-panel-header" style="flex-wrap: wrap; gap: 10px;">
|
||||
<div class="hol-panel-header-group">
|
||||
<h3 style="margin:0;">🗺️ Itinéraire</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="Étapes intermédiaires"><span class="hol-legend-color interm"></span> Interm.</span>
|
||||
<span class="hol-legend-item" title="Trajet retour"><span class="hol-legend-color retour"></span> Retour</span>
|
||||
</div>
|
||||
</div>
|
||||
<button class="pf-btn pf-btn-small" onclick="openCheckpointModal('add')">📍 Placer une étape</button>
|
||||
</div>
|
||||
<div id="tripMap" style="flex:1; width:100%; background:#f1f5f9;"></div>
|
||||
</div>
|
||||
|
||||
<div class="hol-panel">
|
||||
<div class="hol-panel-header">
|
||||
<h3>📝 Détail des étapes</h3>
|
||||
<h3 style="margin:0;">📝 Détail des étapes</h3>
|
||||
</div>
|
||||
|
||||
<div class="hol-panel-body">
|
||||
@@ -129,7 +132,7 @@ $pctSaved = $cost > 0 ? min(100 - $pctPaid, ($saved / $cost) * 100) : 0;
|
||||
<p style="color:var(--text-muted); font-style:italic; text-align:center; margin-top:40px;">Aucune étape planifiée.</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']) ?>">
|
||||
<div id="step-card-<?= $step['sort_order'] ?>" class="hol-checkpoint hol-checkpoint-draggable" draggable="true" data-location="<?= htmlspecialchars($step['location_name']) ?>">
|
||||
<div class="hol-cp-header">
|
||||
<div class="hol-cp-info-group">
|
||||
<span style="color:#94a3b8; font-size:1.1rem; cursor:grab; user-select:none;">☰</span>
|
||||
@@ -137,12 +140,10 @@ $pctSaved = $cost > 0 ? min(100 - $pctPaid, ($saved / $cost) * 100) : 0;
|
||||
📍 <?= htmlspecialchars($step['location_name']) ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="hol-cp-actions-group">
|
||||
<div class="hol-cp-total"><?= number_format($step['total_amount'], 2, ',', ' ') ?> €</div>
|
||||
<button onclick='openCheckpointModal("edit", <?= htmlspecialchars(json_encode($step), ENT_QUOTES, "UTF-8") ?>)' class="btn-icon-small" title="Modifier">✏️</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="hol-cp-body">
|
||||
@@ -153,18 +154,18 @@ $pctSaved = $cost > 0 ? min(100 - $pctPaid, ($saved / $cost) * 100) : 0;
|
||||
$visibleItemsCount++;
|
||||
$icon = match($it['category']) { 'transport' => '🚗', 'accommodation' => '🏨', 'activity' => '🎫', default => '🏷️' };
|
||||
?>
|
||||
<div class="hol-expense-line" style="display:flex; flex-direction:column; align-items:flex-start; gap:4px;">
|
||||
<div style="display:flex; justify-content:space-between; width:100%;">
|
||||
<span style="color:#475569; font-weight:500;"><?= $icon ?> <?= htmlspecialchars($it['name']) ?></span>
|
||||
<div class="hol-expense-wrapper">
|
||||
<div class="hol-expense-main">
|
||||
<span class="hol-expense-name"><?= $icon ?> <?= htmlspecialchars($it['name']) ?></span>
|
||||
<span>
|
||||
<strong style="color:var(--text-main);"><?= number_format($it['amount'], 2, ',', ' ') ?> €</strong>
|
||||
<span style="margin-left:5px; color:<?= $it['is_paid'] ? '#10b981' : '#f59e0b' ?>;"><?= $it['is_paid'] ? '✓' : '⏳' ?></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>
|
||||
</div>
|
||||
<?php if (!empty($it['notes'])): ?>
|
||||
<div style="font-size:0.75rem; color:#94a3b8; padding-left: 24px; word-break: break-all;">
|
||||
<div class="hol-expense-note">
|
||||
<?php if (filter_var($it['notes'], FILTER_VALIDATE_URL)): ?>
|
||||
🔗 <a href="<?= htmlspecialchars($it['notes']) ?>" target="_blank" style="color:#3b82f6; text-decoration:none;">Voir le lien</a>
|
||||
🔗 <a href="<?= htmlspecialchars($it['notes']) ?>" target="_blank" class="hol-expense-link">Voir le lien</a>
|
||||
<?php else: ?>
|
||||
📝 <?= htmlspecialchars($it['notes']) ?>
|
||||
<?php endif; ?>
|
||||
@@ -174,7 +175,7 @@ $pctSaved = $cost > 0 ? min(100 - $pctPaid, ($saved / $cost) * 100) : 0;
|
||||
<?php endforeach; ?>
|
||||
|
||||
<?php if ($visibleItemsCount === 0): ?>
|
||||
<div style="font-size:0.8rem; color:var(--text-muted); font-style:italic; padding: 5px 0;">
|
||||
<div class="hol-empty-step">
|
||||
📍 Point de passage (Aucune dépense)
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
@@ -205,7 +206,7 @@ $pctSaved = $cost > 0 ? min(100 - $pctPaid, ($saved / $cost) * 100) : 0;
|
||||
<?php if (!empty($favorites)): ?>
|
||||
<div style="margin-bottom:15px; display:flex; gap:8px; flex-wrap:wrap;">
|
||||
<?php foreach($favorites as $fav): ?>
|
||||
<button type="button" class="pf-btn btn-secondary" style="padding:4px 10px; font-size:0.8rem; height:auto; width:auto; border-radius:20px; background:#f0f9ff; color:#0369a1; border-color:#bae6fd;" onclick="selectPlace(<?= $fav['lat'] ?>, <?= $fav['lng'] ?>, '<?= htmlspecialchars(addslashes($fav['name'])) ?>')">
|
||||
<button type="button" class="pf-btn btn-secondary" style="padding:4px 10px; font-size:0.8rem; height:auto; width:auto; border-radius:20px;" onclick="selectPlace(<?= $fav['lat'] ?>, <?= $fav['lng'] ?>, '<?= htmlspecialchars(addslashes($fav['name'])) ?>')">
|
||||
⭐ <?= htmlspecialchars($fav['name']) ?>
|
||||
</button>
|
||||
<?php endforeach; ?>
|
||||
@@ -228,12 +229,12 @@ $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 (Ce qui s'affichera sur la carte)</label>
|
||||
<label class="pf-label">Nom de l'étape</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; justify-content:space-between; align-items:center; margin-bottom:10px;">
|
||||
<label class="pf-label" style="margin:0;">Dépenses prévues à cette étape</label>
|
||||
<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>
|
||||
</div>
|
||||
|
||||
@@ -242,18 +243,18 @@ $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; cursor:pointer; width:16px; height:16px;">
|
||||
⭐ Sauvegarder cette adresse dans mes favoris rapides
|
||||
<input type="checkbox" name="save_favorite" value="1" style="margin-right:8px;">
|
||||
⭐ Sauvegarder dans mes favoris
|
||||
</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 l'étape</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;">🗑️ Supprimer</button>
|
||||
</div>
|
||||
<div style="display:flex; gap:10px;">
|
||||
<button type="button" onclick="document.getElementById('checkpointModal').style.display='none'" class="pf-btn btn-secondary" style="width:auto; margin:0;">Annuler</button>
|
||||
<button type="submit" class="pf-btn" style="width:auto; margin:0;">Enregistrer l'étape</button>
|
||||
<button type="submit" class="pf-btn" style="width:auto; margin:0;">Enregistrer</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
Reference in New Issue
Block a user