// Settings Management JavaScript let currentSettings = {}; let mediaLibraryModal; let currentMediaTarget = null; let selectedMediaUrl = null; let allMedia = []; document.addEventListener("DOMContentLoaded", function () { // Initialize modal const modalElement = document.getElementById("mediaLibraryModal"); if (modalElement) { mediaLibraryModal = new bootstrap.Modal(modalElement); } // Setup media search const searchInput = document.getElementById("mediaSearch"); if (searchInput) { searchInput.addEventListener("input", filterMedia); } const typeFilter = document.getElementById("mediaTypeFilter"); if (typeFilter) { typeFilter.addEventListener("change", filterMedia); } // Load saved theme loadTheme(); checkAuth().then((authenticated) => { if (authenticated) { loadSettings(); } }); }); // Toast Notification System - Make global for onclick handlers window.showToast = function (message, type = "success") { const container = document.getElementById("toastContainer"); if (!container) { console.error("Toast container not found!"); return; } const icons = { success: "bi-check-circle-fill", error: "bi-x-circle-fill", warning: "bi-exclamation-triangle-fill", info: "bi-info-circle-fill", }; const toast = document.createElement("div"); toast.className = `toast toast-${type}`; toast.innerHTML = `
${message}
`; container.appendChild(toast); // Trigger animation setTimeout(() => toast.classList.add("toast-show"), 10); // Add visual feedback for success saves if (type === "success" && message.includes("saved")) { const saveBtn = document.querySelector('button[onclick*="saveSettings"]'); if (saveBtn) { const originalBg = saveBtn.style.background; const originalTransform = saveBtn.style.transform; saveBtn.style.background = "linear-gradient(135deg, #10b981 0%, #059669 100%)"; saveBtn.style.transform = "scale(1.05)"; saveBtn.innerHTML = ' Saved!'; setTimeout(() => { saveBtn.style.background = originalBg; saveBtn.style.transform = originalTransform; saveBtn.innerHTML = ' Save All Settings'; }, 2000); } } // Auto remove after 5 seconds setTimeout(() => { toast.classList.add("toast-hide"); setTimeout(() => toast.remove(), 300); }, 5000); }; window.closeToast = function (button) { const toast = button.closest(".toast"); toast.classList.add("toast-hide"); setTimeout(() => toast.remove(), 300); }; // Theme Management - Make global for onclick handlers function loadTheme() { const savedTheme = localStorage.getItem("adminTheme") || "light"; applyTheme(savedTheme); } window.selectTheme = function (theme) { console.log("selectTheme called with:", theme); // Update UI document.querySelectorAll(".theme-selector .theme-option").forEach((el) => { el.classList.remove("active"); }); event.target.closest(".theme-option").classList.add("active"); // Save and apply theme localStorage.setItem("adminTheme", theme); applyTheme(theme); window.showToast(`Theme changed to ${theme} mode`, "success"); }; function applyTheme(theme) { console.log("applyTheme called with:", theme); const body = document.body; if (theme === "dark") { body.classList.add("dark-mode"); body.classList.remove("light-mode"); } else if (theme === "light") { body.classList.add("light-mode"); body.classList.remove("dark-mode"); } else if (theme === "auto") { // Check system preference const prefersDark = window.matchMedia( "(prefers-color-scheme: dark)" ).matches; if (prefersDark) { body.classList.add("dark-mode"); body.classList.remove("light-mode"); } else { body.classList.add("light-mode"); body.classList.remove("dark-mode"); } } // Update active state in UI const themeOptions = document.querySelectorAll( ".theme-selector .theme-option" ); themeOptions.forEach((option, index) => { const themes = ["light", "dark", "auto"]; if (themes[index] === theme) { option.classList.add("active"); } else { option.classList.remove("active"); } }); } async function loadSettings() { try { const response = await fetch("/api/admin/settings", { credentials: "include", }); const data = await response.json(); if (data.success) { currentSettings = data.settings || {}; populateSettings(); } } catch (error) { console.error("Failed to load settings:", error); } } function populateSettings() { // General Settings if (currentSettings.general) { document.getElementById("siteName").value = currentSettings.general.siteName || ""; document.getElementById("siteTagline").value = currentSettings.general.siteTagline || ""; document.getElementById("siteEmail").value = currentSettings.general.siteEmail || ""; document.getElementById("sitePhone").value = currentSettings.general.sitePhone || ""; document.getElementById("timezone").value = currentSettings.general.timezone || "UTC"; // Logo and Favicon if (currentSettings.general.siteLogo) { document.getElementById("siteLogo").value = currentSettings.general.siteLogo; document.getElementById( "logoPreview" ).innerHTML = `Logo`; } if (currentSettings.general.siteFavicon) { document.getElementById("siteFavicon").value = currentSettings.general.siteFavicon; document.getElementById( "faviconPreview" ).innerHTML = `Favicon`; } } // Homepage Settings if (currentSettings.homepage) { document.getElementById("showHero").checked = currentSettings.homepage.showHero !== false; document.getElementById("showPromotions").checked = currentSettings.homepage.showPromotions !== false; document.getElementById("showPortfolio").checked = currentSettings.homepage.showPortfolio !== false; document.getElementById("showBlog").checked = currentSettings.homepage.showBlog !== false; } // Product Settings if (currentSettings.product) { document.getElementById("defaultProductStatus").value = currentSettings.product.defaultStatus || "active"; document.getElementById("productsPerPage").value = currentSettings.product.perPage || 12; document.getElementById("bestSellerLogic").value = currentSettings.product.bestSellerLogic || "manual"; document.getElementById("enableInventory").checked = currentSettings.product.enableInventory !== false; document.getElementById("showOutOfStock").checked = currentSettings.product.showOutOfStock !== false; } // Security Settings if (currentSettings.security) { document.getElementById("passwordExpiration").value = currentSettings.security.passwordExpiration || 90; document.getElementById("sessionTimeout").value = currentSettings.security.sessionTimeout || 60; document.getElementById("loginAttempts").value = currentSettings.security.loginAttempts || 5; document.getElementById("requireStrongPassword").checked = currentSettings.security.requireStrongPassword !== false; document.getElementById("enableTwoFactor").checked = currentSettings.security.enableTwoFactor || false; } // Appearance Settings if (currentSettings.appearance) { document.getElementById("accentColor").value = currentSettings.appearance.accentColor || "#667eea"; updateColorPreview(); } } // Media Library Functions - Make global for onclick handlers window.openMediaLibrary = async function (targetField) { console.log("openMediaLibrary called for:", targetField); currentMediaTarget = targetField; selectedMediaUrl = null; // Load media files try { const response = await fetch("/api/admin/uploads", { credentials: "include", }); const data = await response.json(); if (data.success) { allMedia = data.files || []; renderMediaGrid(allMedia); mediaLibraryModal.show(); } else { showToast(data.message || "Failed to load media library", "error"); } } catch (error) { console.error("Failed to load media library:", error); showToast("Failed to load media library. Please try again.", "error"); } }; function renderMediaGrid(media) { const grid = document.getElementById("mediaGrid"); if (media.length === 0) { grid.innerHTML = `

No media files found

`; return; } grid.innerHTML = media .map( (file) => `
${ file.mimetype?.startsWith("image/") ? `${
              file.originalName || file.filename
            }` : `
` }
${ file.originalName || file.filename }
${formatFileSize( file.size )}
` ) .join(""); // Add click listeners to all media items document.querySelectorAll(".media-item").forEach((item) => { item.addEventListener("click", function () { selectMedia(this.dataset.url); }); }); } function selectMedia(url) { // Remove previous selection document.querySelectorAll(".media-item").forEach((el) => { el.style.border = "3px solid transparent"; }); // Mark current selection - find the clicked item document.querySelectorAll(".media-item").forEach((el) => { if (el.dataset.url === url) { el.style.border = "3px solid #667eea"; el.style.background = "#f8f9fa"; } }); selectedMediaUrl = url; } window.selectMediaFile = function () { if (!selectedMediaUrl) { window.showToast("Please select a media file", "warning"); return; } // Set the selected URL to the target field document.getElementById(currentMediaTarget).value = selectedMediaUrl; // Update preview if (currentMediaTarget === "siteLogo") { document.getElementById( "logoPreview" ).innerHTML = `Logo`; } else if (currentMediaTarget === "siteFavicon") { document.getElementById( "faviconPreview" ).innerHTML = `Favicon`; } // Close modal mediaLibraryModal.hide(); window.showToast("Image selected successfully", "success"); }; function filterMedia() { const searchTerm = document.getElementById("mediaSearch").value.toLowerCase(); const typeFilter = document.getElementById("mediaTypeFilter").value; let filtered = allMedia; // Filter by search term if (searchTerm) { filtered = filtered.filter( (file) => file.filename.toLowerCase().includes(searchTerm) || file.originalName?.toLowerCase().includes(searchTerm) ); } // Filter by type if (typeFilter !== "all") { filtered = filtered.filter((file) => { if (typeFilter === "image") return file.mimetype?.startsWith("image/"); if (typeFilter === "video") return file.mimetype?.startsWith("video/"); if (typeFilter === "document") return ( file.mimetype?.includes("pdf") || file.mimetype?.includes("document") || file.mimetype?.includes("text") ); return true; }); } renderMediaGrid(filtered); } function formatFileSize(bytes) { if (!bytes) return "0 B"; const k = 1024; const sizes = ["B", "KB", "MB", "GB"]; const i = Math.floor(Math.log(bytes) / Math.log(k)); return Math.round((bytes / Math.pow(k, i)) * 100) / 100 + " " + sizes[i]; } function previewLogo() { const url = document.getElementById("siteLogo").value; const preview = document.getElementById("logoPreview"); if (url) { preview.innerHTML = `Logo`; } } function previewFavicon() { const url = document.getElementById("siteFavicon").value; const preview = document.getElementById("faviconPreview"); if (url) { preview.innerHTML = `Favicon`; } } window.selectLayout = function (layout) { document.querySelectorAll(".theme-selector .theme-option").forEach((el) => { el.classList.remove("active"); }); event.target.closest(".theme-option").classList.add("active"); }; function updateColorPreview() { const color = document.getElementById("accentColor").value; document.getElementById("colorPreview").style.backgroundColor = color; document.getElementById("colorValue").textContent = color; } window.saveSettings = async function () { console.log("saveSettings called"); const settings = { general: { siteName: document.getElementById("siteName").value, siteTagline: document.getElementById("siteTagline").value, siteEmail: document.getElementById("siteEmail").value, sitePhone: document.getElementById("sitePhone").value, timezone: document.getElementById("timezone").value, siteLogo: document.getElementById("siteLogo").value, siteFavicon: document.getElementById("siteFavicon").value, }, homepage: { showHero: document.getElementById("showHero").checked, showPromotions: document.getElementById("showPromotions").checked, showPortfolio: document.getElementById("showPortfolio").checked, showBlog: document.getElementById("showBlog").checked, }, product: { defaultStatus: document.getElementById("defaultProductStatus").value, perPage: parseInt(document.getElementById("productsPerPage").value), bestSellerLogic: document.getElementById("bestSellerLogic").value, enableInventory: document.getElementById("enableInventory").checked, showOutOfStock: document.getElementById("showOutOfStock").checked, }, security: { passwordExpiration: parseInt( document.getElementById("passwordExpiration").value ), sessionTimeout: parseInt(document.getElementById("sessionTimeout").value), loginAttempts: parseInt(document.getElementById("loginAttempts").value), requireStrongPassword: document.getElementById("requireStrongPassword") .checked, enableTwoFactor: document.getElementById("enableTwoFactor").checked, }, appearance: { accentColor: document.getElementById("accentColor").value, }, }; console.log("Settings to save:", settings); try { const response = await fetch("/api/admin/settings", { method: "POST", headers: { "Content-Type": "application/json" }, credentials: "include", body: JSON.stringify(settings), }); const data = await response.json(); console.log("Save response:", data); if (data.success) { window.showToast("Settings saved successfully!", "success"); currentSettings = settings; } else { window.showToast(data.message || "Failed to save settings", "error"); } } catch (error) { console.error("Failed to save settings:", error); window.showToast("Failed to save settings. Please try again.", "error"); } };