// web/js/main.js // Main.js - Shared functions across all dashboards const API_URL = "http://localhost:8080"; // Auth utilities function getToken() { return localStorage.getItem("token"); } function getCurrentUser() { const user = localStorage.getItem("user"); return user ? JSON.parse(user) : null; } function setAuth(token, user) { localStorage.setItem("token", token); localStorage.setItem("user", JSON.stringify(user)); } function clearAuth() { localStorage.removeItem("token"); localStorage.removeItem("user"); } // Check authentication - FIXED function checkAuth() { const token = getToken(); const user = getCurrentUser(); if (!token || !user) { // FIXED: Jangan langsung redirect di sini // Biarkan halaman yang memanggil yang handle redirect return null; } return user; } // Logout - FIXED function logout() { if (confirm("Apakah Anda yakin ingin logout?")) { clearAuth(); window.location.href = "/login"; // FIXED: tambah / } } // API call helper async function apiCall(endpoint, options = {}) { const token = getToken(); const defaultOptions = { headers: { "Content-Type": "application/json", ...(token && { Authorization: `Bearer ${token}` }), }, }; const finalOptions = { ...defaultOptions, ...options, headers: { ...defaultOptions.headers, ...options.headers, }, }; try { const response = await fetch(`${API_URL}${endpoint}`, finalOptions); const data = await response.json(); if (!response.ok) { // Handle 401 Unauthorized if (response.status === 401) { showAlert("Session expired. Please login again.", "danger"); setTimeout(() => { clearAuth(); window.location.href = "/login"; // FIXED: tambah / }, 1500); throw new Error("Unauthorized"); } throw new Error(data.error || "Request failed"); } return data; } catch (error) { console.error("API call error:", error); throw error; } } // API call for file upload - FIXED: support PUT method async function apiUpload(endpoint, formData, method = "POST") { const token = getToken(); try { const response = await fetch(`${API_URL}${endpoint}`, { method: method, // FIXED: bisa POST atau PUT headers: { ...(token && { Authorization: `Bearer ${token}` }), // JANGAN set Content-Type untuk FormData, browser akan set otomatis dengan boundary }, body: formData, }); const data = await response.json(); if (!response.ok) { if (response.status === 401) { showAlert("Session expired. Please login again.", "danger"); setTimeout(() => { clearAuth(); window.location.href = "/login"; // FIXED: tambah / }, 1500); throw new Error("Unauthorized"); } throw new Error(data.error || "Upload failed"); } return data; } catch (error) { console.error("Upload error:", error); throw error; } } // Tab switching function switchTab(tabName) { // Remove active class from all tabs document.querySelectorAll(".tab-btn").forEach((btn) => { btn.classList.remove("active"); }); document.querySelectorAll(".tab-content").forEach((content) => { content.classList.remove("active"); }); // Add active class to selected tab event.target.classList.add("active"); document.getElementById(tabName + "Tab").classList.add("active"); // Trigger load function for specific tab if exists const loadFunctionName = `load${capitalize(tabName)}`; if (typeof window[loadFunctionName] === "function") { window[loadFunctionName](); } } // Modal utilities function openModal(modalId) { document.getElementById(modalId).classList.add("active"); } function closeModal(modalId) { document.getElementById(modalId).classList.remove("active"); } // Close modal when clicking outside window.addEventListener("click", (e) => { if (e.target.classList.contains("modal")) { e.target.classList.remove("active"); } }); // Alert notification function showAlert(message, type = "info") { const alertDiv = document.createElement("div"); alertDiv.className = `alert alert-${type}`; alertDiv.textContent = message; alertDiv.style.cssText = ` position: fixed; top: 80px; right: 20px; padding: 15px 20px; border-radius: 10px; box-shadow: 0 5px 15px rgba(0,0,0,0.2); z-index: 9999; animation: slideInRight 0.3s; `; // Set colors based on type const colors = { success: { bg: "#d1fae5", color: "#10b981", border: "#10b981" }, danger: { bg: "#fee2e2", color: "#ef4444", border: "#ef4444" }, warning: { bg: "#fef3c7", color: "#f59e0b", border: "#f59e0b" }, info: { bg: "#dbeafe", color: "#2563eb", border: "#2563eb" }, }; const colorScheme = colors[type] || colors.info; alertDiv.style.background = colorScheme.bg; alertDiv.style.color = colorScheme.color; alertDiv.style.border = `2px solid ${colorScheme.border}`; document.body.appendChild(alertDiv); setTimeout(() => { alertDiv.style.animation = "slideOutRight 0.3s"; setTimeout(() => alertDiv.remove(), 300); }, 3000); } // Format date function formatDate(dateString) { const date = new Date(dateString); const options = { year: "numeric", month: "long", day: "numeric" }; return date.toLocaleDateString("id-ID", options); } // Format datetime function formatDateTime(dateString) { const date = new Date(dateString); const options = { year: "numeric", month: "long", day: "numeric", hour: "2-digit", minute: "2-digit", }; return date.toLocaleDateString("id-ID", options); } // Capitalize first letter function capitalize(str) { return str.charAt(0).toUpperCase() + str.slice(1); } // Get status badge HTML function getStatusBadge(status) { const statusMap = { unclaimed: { label: "Unclaimed", class: "badge-primary" }, pending_claim: { label: "Pending Claim", class: "badge-warning" }, verified: { label: "Verified", class: "badge-success" }, case_closed: { label: "Case Closed", class: "badge-success" }, expired: { label: "Expired", class: "badge-danger" }, pending: { label: "Pending", class: "badge-warning" }, approved: { label: "Approved", class: "badge-success" }, rejected: { label: "Rejected", class: "badge-danger" }, active: { label: "Active", class: "badge-success" }, blocked: { label: "Blocked", class: "badge-danger" }, }; const statusInfo = statusMap[status] || { label: status, class: "badge-primary", }; return `${statusInfo.label}`; } // Get role badge HTML function getRoleBadge(role) { const roleMap = { admin: { label: "Admin", class: "badge-danger" }, manager: { label: "Manager", class: "badge-warning" }, user: { label: "User", class: "badge-primary" }, }; const roleInfo = roleMap[role] || { label: role, class: "badge-primary" }; return `${roleInfo.label}`; } // Confirm dialog function confirmAction(message) { return confirm(message); } // Loading state function setLoading(elementId, isLoading) { const element = document.getElementById(elementId); if (!element) return; if (isLoading) { element.innerHTML = `
Loading...
${message}