From ca9c7744220c7d90992fb1ab5fefd771dfc80cc0 Mon Sep 17 00:00:00 2001 From: "fefe.clochette" Date: Mon, 30 Mar 2026 12:33:57 +0200 Subject: [PATCH] css drag and drop --- modules/holidays/holidays.css | 62 ++++++++++----- modules/holidays/holidays.js | 76 +++++++++++++++++++ .../includes/api/reorder_checkpoints.php | 27 +++++++ modules/holidays/views/detail.php | 34 ++++++--- 4 files changed, 169 insertions(+), 30 deletions(-) create mode 100644 modules/holidays/includes/api/reorder_checkpoints.php diff --git a/modules/holidays/holidays.css b/modules/holidays/holidays.css index 94b35ed..a3f4cd2 100644 --- a/modules/holidays/holidays.css +++ b/modules/holidays/holidays.css @@ -110,21 +110,27 @@ /* Petit bouton + pour les colonnes */ .btn-icon-small { - background: transparent; - border: 1px dashed #cbd5e1; - border-radius: 4px; - padding: 6px 12px; - font-size: 0.8rem; - color: var(--text-muted); + background: white !important; + border: 1px solid #e2e8f0 !important; + border-radius: 6px !important; + width: 32px !important; + height: 32px !important; + min-width: 32px !important; + padding: 0 !important; + margin: 0 !important; + display: flex !important; + align-items: center; + justify-content: center; + font-size: 0.9rem; cursor: pointer; - width: 100%; - margin-top: 10px; - transition: 0.2s; + transition: all 0.2s; + box-shadow: var(--shadow-sm); } + .btn-icon-small:hover { - background: #f1f5f9; - color: var(--text-main); - border-color: var(--text-muted); + background: #f1f5f9 !important; + border-color: #cbd5e1 !important; + transform: scale(1.05); } /* --- 4. CARTES --- */ @@ -623,28 +629,48 @@ input[type="date"]::-webkit-calendar-picker-indicator:hover { .hol-cp-header { background: #f8fafc; - padding: 10px 15px; + padding: 12px 15px; display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid #e2e8f0; + gap: 12px; +} + +.hol-cp-info-group { + display: flex; + align-items: center; + gap: 12px; + flex: 1; + min-width: 0; } .hol-cp-title { color: #0f172a; - font-size: 1rem; - font-weight: bold; + font-size: 0.95rem; + font-weight: 700; cursor: pointer; - transition: color 0.2s; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; } .hol-cp-title:hover { color: var(--primary); } +.hol-cp-actions-group { + display: flex; + align-items: center; + gap: 10px; + flex-shrink: 0; +} + .hol-cp-total { - font-size: 0.8rem; - color: var(--text-muted); + font-size: 0.9rem; + font-weight: 700; + color: var(--primary); + white-space: nowrap; } .hol-cp-body { diff --git a/modules/holidays/holidays.js b/modules/holidays/holidays.js index d4007e2..75180a0 100644 --- a/modules/holidays/holidays.js +++ b/modules/holidays/holidays.js @@ -413,3 +413,79 @@ function deleteCheckpoint() { form.appendChild(input); form.submit(); } + +// ============================================================================ +// 5. GLISSER-DÉPOSER POUR RÉORDONNER LES ÉTAPES (ROADTRIP) +// ============================================================================ +document.addEventListener("DOMContentLoaded", () => { + const checkpoints = document.querySelectorAll(".hol-checkpoint-draggable"); + const container = checkpoints[0]?.parentElement; + if (!container) return; + + let draggedItem = null; + + checkpoints.forEach((item) => { + item.addEventListener("dragstart", function (e) { + draggedItem = this; + setTimeout(() => (this.style.opacity = "0.4"), 0); + }); + + item.addEventListener("dragend", function () { + setTimeout(() => { + this.style.opacity = "1"; + draggedItem = null; + saveCheckpointOrder(); // On sauvegarde quand on lâche ! + }, 0); + }); + + item.addEventListener("dragover", function (e) { + e.preventDefault(); + const afterElement = getDragAfterElement(container, e.clientY); + if (afterElement == null) { + container.appendChild(draggedItem); + } else { + container.insertBefore(draggedItem, afterElement); + } + }); + }); + + function getDragAfterElement(container, y) { + const draggableElements = [ + ...container.querySelectorAll( + '.hol-checkpoint-draggable:not([style*="opacity: 0.4"])', + ), + ]; + return draggableElements.reduce( + (closest, child) => { + const box = child.getBoundingClientRect(); + const offset = y - box.top - box.height / 2; + if (offset < 0 && offset > closest.offset) { + return { offset: offset, element: child }; + } else { + return closest; + } + }, + { offset: Number.NEGATIVE_INFINITY }, + ).element; + } + + function saveCheckpointOrder() { + // On récupère le nom des lieux dans le nouvel ordre de haut en bas + const locations = [ + ...document.querySelectorAll(".hol-checkpoint-draggable"), + ].map((el) => el.getAttribute("data-location")); + const holidayId = document.querySelector('input[name="holiday_id"]').value; // Input caché dans la modale + + const formData = new FormData(); + formData.append("holiday_id", holidayId); + formData.append("locations", JSON.stringify(locations)); + + fetch("/modules/holidays/includes/api/reorder_checkpoints.php", { + method: "POST", + body: formData, + }).then(() => { + // Recharge la page pour que la carte redessine le trait bleu dans le bon ordre ! + window.location.reload(); + }); + } +}); diff --git a/modules/holidays/includes/api/reorder_checkpoints.php b/modules/holidays/includes/api/reorder_checkpoints.php new file mode 100644 index 0000000..a521d02 --- /dev/null +++ b/modules/holidays/includes/api/reorder_checkpoints.php @@ -0,0 +1,27 @@ + 0 && is_array($locations)) { + try { + $pdo->beginTransaction(); + $stmt = $pdo->prepare("UPDATE pf_holidays_items SET sort_order = ? WHERE holiday_id = ? AND location_name = ?"); + + foreach ($locations as $index => $loc) { + // On met à jour toutes les dépenses de ce lieu avec son nouveau rang (0, 1, 2...) + $stmt->execute([$index, $holiday_id, $loc]); + } + + $pdo->commit(); + echo json_encode(['success' => true]); + } catch (Exception $e) { + $pdo->rollBack(); + http_response_code(500); + echo json_encode(['error' => $e->getMessage()]); + } +} \ No newline at end of file diff --git a/modules/holidays/views/detail.php b/modules/holidays/views/detail.php index c882638..642599e 100644 --- a/modules/holidays/views/detail.php +++ b/modules/holidays/views/detail.php @@ -15,7 +15,8 @@ $stmt = $pdo->prepare(" $stmt->execute([$id]); $holiday = $stmt->fetch(PDO::FETCH_ASSOC); -$stmtItems = $pdo->prepare("SELECT * FROM pf_holidays_items WHERE holiday_id = ? ORDER BY id ASC"); +// 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); @@ -123,16 +124,24 @@ $pctSaved = $cost > 0 ? min(100 - $pctPaid, ($saved / $cost) * 100) : 0;

Aucune étape planifiée.

-
+
-
-
📍
-
Total Étape :
+ +
+ +
+ 📍 +
- -
-
+
+
+ +
+ +
+ +
0 ? min(100 - $pctPaid, ($saved / $cost) * 100) : 0;
- - + +
-
Point de passage (Aucune dépense)
+
+ 📍 Point de passage (Aucune dépense) +
-