// Admin dashboard utilities // Format JSON for display in modals function formatJSON(json) { try { const parsed = typeof json === "string" ? JSON.parse(json) : json; return JSON.stringify(parsed, null, 2); } catch (e) { return json; } } // Initialize flatpickr for all date inputs function initFlatpickr() { document.querySelectorAll(".flatpickr-date").forEach(function (input) { if (!input._flatpickr) { flatpickr(input, { dateFormat: "d/m/Y", allowInput: true, }); } }); } // Submit the audit filter form with specific page/perPage/order params function submitAuditFilter(page, perPage, order, orderBy) { const form = document.getElementById("audit-filters-form"); if (!form) return; // Create hidden inputs for pagination/sorting if they don't exist let pageInput = form.querySelector('input[name="page"]'); if (!pageInput) { pageInput = document.createElement("input"); pageInput.type = "hidden"; pageInput.name = "page"; form.appendChild(pageInput); } pageInput.value = page; let perPageInput = form.querySelector('input[name="per_page"]'); if (!perPageInput) { perPageInput = document.createElement("input"); perPageInput.type = "hidden"; perPageInput.name = "per_page"; form.appendChild(perPageInput); } perPageInput.value = perPage; let orderInput = form.querySelector('input[name="order"]'); if (!orderInput) { orderInput = document.createElement("input"); orderInput.type = "hidden"; orderInput.name = "order"; form.appendChild(orderInput); } orderInput.value = order; let orderByInput = form.querySelector('input[name="order_by"]'); if (!orderByInput) { orderByInput = document.createElement("input"); orderByInput.type = "hidden"; orderByInput.name = "order_by"; form.appendChild(orderByInput); } orderByInput.value = orderBy; htmx.trigger(form, "submit"); } // Sort by column - toggle direction if same column function sortAuditColumn(field, currentOrder, currentOrderBy) { const page = 1; // Reset to first page when sorting const perPageSelect = document.getElementById("per-page-select"); const perPage = perPageSelect ? parseInt(perPageSelect.value) || 25 : 25; let newOrder, newOrderBy; if (currentOrderBy === field) { // Toggle order newOrder = currentOrder === "ASC" ? "DESC" : "ASC"; newOrderBy = field; } else { // New column, default to DESC newOrder = "DESC"; newOrderBy = field; } submitAuditFilter(page, perPage, newOrder, newOrderBy); } // Clear all audit filters function clearAuditFilters() { const form = document.getElementById("audit-filters-form"); if (!form) return; form.reset(); // Clear flatpickr instances document.querySelectorAll(".flatpickr-date").forEach(function (input) { var fp = input._flatpickr; if (fp) fp.clear(); }); // Clear multi-select dropdowns document.querySelectorAll(".multi-select-container").forEach(function (container) { var hiddenInput = container.querySelector('input[type="hidden"]'); if (hiddenInput) hiddenInput.value = ""; var selectedDisplay = container.querySelector(".multi-select-selected"); if (selectedDisplay) selectedDisplay.innerHTML = 'Select...'; container.querySelectorAll(".multi-select-option").forEach(function (opt) { opt.classList.remove("bg-blue", "text-mantle"); opt.classList.add("hover:bg-surface1"); }); }); // Trigger form submission with reset pagination submitAuditFilter(1, 25, "DESC", "created_at"); } // Toggle multi-select dropdown visibility function toggleMultiSelect(containerId) { var dropdown = document.getElementById(containerId + "-dropdown"); if (dropdown) { dropdown.classList.toggle("hidden"); } } // Toggle multi-select option selection function toggleMultiSelectOption(containerId, value, label) { var container = document.getElementById(containerId); var hiddenInput = container.querySelector('input[type="hidden"]'); var selectedDisplay = container.querySelector(".multi-select-selected"); var values = hiddenInput.value ? hiddenInput.value.split(",") : []; var index = values.indexOf(value); if (index > -1) { values.splice(index, 1); } else { values.push(value); } hiddenInput.value = values.join(","); var option = container.querySelector('[data-value="' + value + '"]'); if (option) { if (index > -1) { option.classList.remove("bg-blue", "text-mantle"); option.classList.add("hover:bg-surface1"); } else { option.classList.add("bg-blue", "text-mantle"); option.classList.remove("hover:bg-surface1"); } } if (values.length === 0) { selectedDisplay.innerHTML = 'Select...'; } else if (values.length === 1) { selectedDisplay.innerHTML = "" + label + ""; } else { selectedDisplay.innerHTML = "" + values.length + " selected"; } // Trigger form submission document.getElementById("audit-filters-form").requestSubmit(); } // Submit the users page with specific page/perPage/order params function submitUsersPage(page, perPage, order, orderBy) { const formData = new FormData(); formData.append("page", page); formData.append("per_page", perPage); formData.append("order", order); formData.append("order_by", orderBy); htmx.ajax("POST", "/admin/users", { target: "#users-list-container", swap: "outerHTML", values: Object.fromEntries(formData), }); } // Sort users column - toggle direction if same column function sortUsersColumn(field, currentOrder, currentOrderBy) { const page = 1; // Reset to first page when sorting const perPageSelect = document.getElementById("users-per-page-select"); const perPage = perPageSelect ? parseInt(perPageSelect.value) || 25 : 25; let newOrder, newOrderBy; if (currentOrderBy === field) { // Toggle order newOrder = currentOrder === "ASC" ? "DESC" : "ASC"; newOrderBy = field; } else { // New column, default to ASC newOrder = "ASC"; newOrderBy = field; } submitUsersPage(page, perPage, newOrder, newOrderBy); } // Submit the roles page with specific page/perPage/order params function submitRolesPage(page, perPage, order, orderBy) { const formData = new FormData(); formData.append("page", page); formData.append("per_page", perPage); formData.append("order", order); formData.append("order_by", orderBy); htmx.ajax("POST", "/admin/roles", { target: "#roles-list-container", swap: "outerHTML", values: Object.fromEntries(formData), }); } // Sort roles column - toggle direction if same column function sortRolesColumn(field, currentOrder, currentOrderBy) { const page = 1; // Reset to first page when sorting const perPageSelect = document.getElementById("roles-per-page-select"); const perPage = perPageSelect ? parseInt(perPageSelect.value) || 25 : 25; let newOrder, newOrderBy; if (currentOrderBy === field) { // Toggle order newOrder = currentOrder === "ASC" ? "DESC" : "ASC"; newOrderBy = field; } else { // New column, default to ASC newOrder = "ASC"; newOrderBy = field; } submitRolesPage(page, perPage, newOrder, newOrderBy); } // Handle HTMX navigation and initialization // Tab navigation active state is handled by tabs.js (generic). // This file only handles admin-specific concerns (flatpickr, multi-select). document.addEventListener("DOMContentLoaded", function () { // Initialize flatpickr on page load initFlatpickr(); document.body.addEventListener("htmx:afterSwap", function (event) { // Re-initialize flatpickr after admin content swap if ( event.detail.target.id === "admin-content" || event.detail.target.id === "audit-results-container" ) { initFlatpickr(); } }); // Close multi-select dropdowns when clicking outside document.addEventListener("click", function (evt) { if (!evt.target.closest(".multi-select-container")) { document.querySelectorAll(".multi-select-dropdown").forEach(function (d) { d.classList.add("hidden"); }); } }); });