2025-11-17 12:17:44 +07:00

350 lines
8.8 KiB
JavaScript

// 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) {
window.location.href = "/login"; // FIXED: tambah /
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 `<span class="badge ${statusInfo.class}">${statusInfo.label}</span>`;
}
// 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 `<span class="badge ${roleInfo.class}">${roleInfo.label}</span>`;
}
// 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 = `
<div class="empty-state">
<div class="loading" style="width: 50px; height: 50px; border-width: 5px;"></div>
<p style="margin-top: 20px;">Loading...</p>
</div>
`;
}
}
// Empty state
function showEmptyState(elementId, icon, message) {
const element = document.getElementById(elementId);
if (!element) return;
element.innerHTML = `
<div class="empty-state">
<div class="empty-state-icon">${icon}</div>
<h3>Tidak ada data</h3>
<p>${message}</p>
</div>
`;
}
// Debounce function for search
function debounce(func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
}
// Add CSS animation styles
const style = document.createElement("style");
style.textContent = `
@keyframes slideInRight {
from {
transform: translateX(100%);
opacity: 0;
}
to {
transform: translateX(0);
opacity: 1;
}
}
@keyframes slideOutRight {
from {
transform: translateX(0);
opacity: 1;
}
to {
transform: translateX(100%);
opacity: 0;
}
}
`;
document.head.appendChild(style);
// Initialize user info in navbar
function initUserInfo() {
const user = getCurrentUser();
if (!user) return;
const userNameEl = document.getElementById("userName");
const userAvatarEl = document.getElementById("userAvatar");
if (userNameEl) userNameEl.textContent = user.name;
if (userAvatarEl)
userAvatarEl.textContent = user.name.charAt(0).toUpperCase();
}
// Initialize on page load
window.addEventListener("DOMContentLoaded", () => {
initUserInfo();
});