// ===================================================== // Admin Utilities - Shared Functions for Admin Panel // ===================================================== /** * Show a custom confirmation dialog instead of browser confirm() * @param {string} message - The confirmation message * @param {Function} onConfirm - Callback when confirmed * @param {Object} options - Optional configuration */ function showDeleteConfirm(message, onConfirm, options = {}) { const { title = "Confirm Delete", confirmText = "Delete", cancelText = "Cancel", type = "danger", } = options; // Check if modal already exists, if not create it let modal = document.getElementById("adminConfirmModal"); if (!modal) { modal = document.createElement("div"); modal.id = "adminConfirmModal"; modal.className = "admin-confirm-modal"; modal.innerHTML = `

${title}

${message}

`; document.body.appendChild(modal); // Add styles if not already present if (!document.getElementById("adminConfirmStyles")) { const styles = document.createElement("style"); styles.id = "adminConfirmStyles"; styles.textContent = ` .admin-confirm-modal { position: fixed; top: 0; left: 0; right: 0; bottom: 0; z-index: 10000; display: flex; align-items: center; justify-content: center; opacity: 0; visibility: hidden; transition: all 0.2s ease; } .admin-confirm-modal.show { opacity: 1; visibility: visible; } .admin-confirm-overlay { position: absolute; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 0, 0, 0.5); backdrop-filter: blur(4px); } .admin-confirm-dialog { position: relative; background: white; border-radius: 16px; box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3); max-width: 400px; width: 90%; transform: scale(0.9) translateY(-20px); transition: transform 0.2s ease; overflow: hidden; } .admin-confirm-modal.show .admin-confirm-dialog { transform: scale(1) translateY(0); } .admin-confirm-header { padding: 24px 24px 16px; text-align: center; } .admin-confirm-icon { width: 60px; height: 60px; border-radius: 50%; display: flex; align-items: center; justify-content: center; margin: 0 auto 16px; font-size: 28px; } .admin-confirm-icon.danger { background: #fee2e2; color: #dc2626; } .admin-confirm-icon.warning { background: #fef3c7; color: #d97706; } .admin-confirm-icon.info { background: #dbeafe; color: #2563eb; } .admin-confirm-title { margin: 0; font-size: 1.25rem; font-weight: 600; color: #1a1a2e; } .admin-confirm-body { padding: 0 24px 20px; text-align: center; } .admin-confirm-message { margin: 0; color: #666; font-size: 0.95rem; line-height: 1.5; } .admin-confirm-footer { display: flex; gap: 12px; padding: 16px 24px 24px; justify-content: center; } .admin-confirm-btn { padding: 10px 24px; border-radius: 8px; font-weight: 500; font-size: 0.9rem; cursor: pointer; transition: all 0.2s ease; border: none; } .admin-confirm-btn.cancel { background: #f3f4f6; color: #374151; } .admin-confirm-btn.cancel:hover { background: #e5e7eb; } .admin-confirm-btn.confirm { color: white; } .admin-confirm-btn.confirm.danger { background: #dc2626; } .admin-confirm-btn.confirm.danger:hover { background: #b91c1c; } .admin-confirm-btn.confirm.warning { background: #d97706; } .admin-confirm-btn.confirm.warning:hover { background: #b45309; } .admin-confirm-btn.confirm.info { background: #2563eb; } .admin-confirm-btn.confirm.info:hover { background: #1d4ed8; } `; document.head.appendChild(styles); } } else { // Update existing modal content modal.querySelector( ".admin-confirm-icon" ).className = `admin-confirm-icon ${type}`; modal.querySelector(".admin-confirm-title").textContent = title; modal.querySelector(".admin-confirm-message").textContent = message; modal.querySelector(".admin-confirm-btn.confirm").textContent = confirmText; modal.querySelector( ".admin-confirm-btn.confirm" ).className = `admin-confirm-btn confirm ${type}`; modal.querySelector(".admin-confirm-btn.cancel").textContent = cancelText; } // Show modal requestAnimationFrame(() => { modal.classList.add("show"); }); // Get buttons const confirmBtn = modal.querySelector(".admin-confirm-btn.confirm"); const cancelBtn = modal.querySelector(".admin-confirm-btn.cancel"); const overlay = modal.querySelector(".admin-confirm-overlay"); // Close function const closeModal = () => { modal.classList.remove("show"); }; // Remove old listeners by cloning const newConfirmBtn = confirmBtn.cloneNode(true); const newCancelBtn = cancelBtn.cloneNode(true); confirmBtn.parentNode.replaceChild(newConfirmBtn, confirmBtn); cancelBtn.parentNode.replaceChild(newCancelBtn, cancelBtn); // Add new listeners newConfirmBtn.addEventListener("click", () => { closeModal(); onConfirm(); }); newCancelBtn.addEventListener("click", closeModal); overlay.addEventListener("click", closeModal); // Escape key to close const escHandler = (e) => { if (e.key === "Escape") { closeModal(); document.removeEventListener("keydown", escHandler); } }; document.addEventListener("keydown", escHandler); } /** * Show a success notification toast * @param {string} message - The success message */ function showAdminToast(message, type = "success") { // Create toast container if it doesn't exist let container = document.getElementById("adminToastContainer"); if (!container) { container = document.createElement("div"); container.id = "adminToastContainer"; container.style.cssText = ` position: fixed; top: 20px; right: 20px; z-index: 10001; display: flex; flex-direction: column; gap: 10px; `; document.body.appendChild(container); } const toast = document.createElement("div"); toast.style.cssText = ` display: flex; align-items: center; gap: 12px; padding: 14px 20px; background: white; border-radius: 12px; box-shadow: 0 10px 40px rgba(0, 0, 0, 0.15); transform: translateX(120%); transition: transform 0.3s ease; min-width: 280px; border-left: 4px solid ${ type === "success" ? "#10b981" : type === "error" ? "#ef4444" : "#3b82f6" }; `; const icons = { success: '', error: '', info: '', }; toast.innerHTML = ` ${icons[type] || icons.info} ${message} `; container.appendChild(toast); // Animate in requestAnimationFrame(() => { toast.style.transform = "translateX(0)"; }); // Auto remove after 4 seconds setTimeout(() => { toast.style.transform = "translateX(120%)"; setTimeout(() => { toast.remove(); }, 300); }, 4000); } /** * Notify frontend that data has changed * This updates a timestamp in localStorage that frontend pages check * @param {string} dataType - Type of data changed (products, pages, settings, etc.) */ function notifyFrontendChange(dataType = "all") { const timestamp = Date.now(); const changeKey = `skyartshop_change_${dataType}`; // Store in localStorage for cross-tab communication localStorage.setItem(changeKey, timestamp.toString()); localStorage.setItem("skyartshop_last_change", timestamp.toString()); // Also broadcast to any open frontend tabs via BroadcastChannel try { const channel = new BroadcastChannel("skyartshop_updates"); channel.postMessage({ type: dataType, timestamp }); channel.close(); } catch (e) { // BroadcastChannel not supported in some browsers } console.log(`[Admin] Notified frontend of ${dataType} change`); } // Export for use in other files window.showDeleteConfirm = showDeleteConfirm; window.showAdminToast = showAdminToast; window.notifyFrontendChange = notifyFrontendChange;