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

435 lines
12 KiB
JavaScript

// Dashboard Admin JavaScript - FIXED ENDPOINTS
let allUsers = [];
let allCategories = [];
let allAuditLogs = [];
// Initialize dashboard
window.addEventListener("DOMContentLoaded", async () => {
const user = checkAuth();
if (!user || user.role !== "admin") {
window.location.href = "/login";
return;
}
await loadStats();
await loadUsers();
setupSearchAndFilters();
setupReportFilters();
});
// Load statistics - FIXED
async function loadStats() {
try {
const stats = await apiCall("/api/admin/dashboard");
document.getElementById("statTotalUsers").textContent =
stats.total_users || 0;
document.getElementById("statTotalItems").textContent =
stats.total_items || 0;
document.getElementById("statTotalClaims").textContent =
stats.total_claims || 0;
document.getElementById("statTotalArchive").textContent =
stats.total_archive || 0;
} catch (error) {
console.error("Error loading stats:", error);
}
}
// Load users - CORRECT (sudah sesuai)
async function loadUsers() {
try {
const response = await apiCall("/api/admin/users");
allUsers = response.data || [];
renderUsers(allUsers);
} catch (error) {
console.error("Error loading users:", error);
showAlert("Gagal memuat data user", "danger");
}
}
// Render users
function renderUsers(users) {
const tbody = document.getElementById("usersTableBody");
if (!users || users.length === 0) {
tbody.innerHTML = `
<tr>
<td colspan="6" style="text-align: center; padding: 40px; color: #64748b;">
Belum ada data user
</td>
</tr>
`;
return;
}
tbody.innerHTML = users
.map(
(user) => `
<tr>
<td>${user.name}</td>
<td>${user.email}</td>
<td>${user.nrp}</td>
<td>${getRoleBadge(user.role)}</td>
<td>${getStatusBadge(user.status || "active")}</td>
<td>
<button class="btn btn-warning btn-sm" onclick="editUser(${
user.id
})">Edit</button>
${
user.status === "active"
? `<button class="btn btn-danger btn-sm" onclick="blockUser(${user.id})">Block</button>`
: `<button class="btn btn-success btn-sm" onclick="unblockUser(${user.id})">Unblock</button>`
}
</td>
</tr>
`
)
.join("");
}
// Edit user
async function editUser(userId) {
try {
const user = await apiCall(`/api/admin/users/${userId}`);
const form = document.getElementById("editUserForm");
form.elements.user_id.value = user.id;
form.elements.name.value = user.name;
form.elements.email.value = user.email;
form.elements.nrp.value = user.nrp;
form.elements.phone.value = user.phone || "";
form.elements.role.value = user.role;
openModal("editUserModal");
} catch (error) {
console.error("Error loading user:", error);
showAlert("Gagal memuat data user", "danger");
}
}
// Submit edit user
document
.getElementById("editUserForm")
?.addEventListener("submit", async (e) => {
e.preventDefault();
const formData = new FormData(e.target);
const userId = formData.get("user_id");
const role = formData.get("role");
try {
const submitBtn = e.target.querySelector('button[type="submit"]');
submitBtn.disabled = true;
submitBtn.innerHTML = '<span class="loading"></span> Menyimpan...';
// Update role
await apiCall(`/api/admin/users/${userId}/role`, {
method: "PATCH",
body: JSON.stringify({ role }),
});
showAlert("User berhasil diupdate!", "success");
closeModal("editUserModal");
await loadUsers();
} catch (error) {
console.error("Error updating user:", error);
showAlert(error.message || "Gagal update user", "danger");
} finally {
const submitBtn = e.target.querySelector('button[type="submit"]');
if (submitBtn) {
submitBtn.disabled = false;
submitBtn.textContent = "Update User";
}
}
});
// Block user
async function blockUser(userId) {
if (!confirmAction("Block user ini?")) return;
try {
await apiCall(`/api/admin/users/${userId}/block`, {
method: "POST",
});
showAlert("User berhasil diblock!", "success");
await loadUsers();
} catch (error) {
console.error("Error blocking user:", error);
showAlert(error.message || "Gagal block user", "danger");
}
}
// Unblock user
async function unblockUser(userId) {
if (!confirmAction("Unblock user ini?")) return;
try {
await apiCall(`/api/admin/users/${userId}/unblock`, {
method: "POST",
});
showAlert("User berhasil di-unblock!", "success");
await loadUsers();
} catch (error) {
console.error("Error unblocking user:", error);
showAlert(error.message || "Gagal unblock user", "danger");
}
}
// Load categories
async function loadCategories() {
try {
const response = await apiCall("/api/categories");
allCategories = response.data || [];
renderCategories(allCategories);
} catch (error) {
console.error("Error loading categories:", error);
showAlert("Gagal memuat data kategori", "danger");
}
}
// Render categories
function renderCategories(categories) {
const grid = document.getElementById("categoriesGrid");
if (!categories || categories.length === 0) {
grid.innerHTML = `
<div class="empty-state">
<div class="empty-state-icon">🏷️</div>
<p>Belum ada kategori</p>
</div>
`;
return;
}
const icons = {
pakaian: "👕",
alat_makan: "🍽️",
aksesoris: "👓",
elektronik: "💻",
alat_tulis: "✏️",
lainnya: "📦",
};
grid.innerHTML = categories
.map(
(cat) => `
<div class="category-card">
<div class="category-icon">${icons[cat.slug] || "📦"}</div>
<h3>${cat.name}</h3>
${
cat.description
? `<p style="color: #64748b; font-size: 0.9rem; margin-top: 8px;">${cat.description}</p>`
: ""
}
<div style="display: flex; gap: 8px; margin-top: 15px; justify-content: center;">
<button class="btn btn-warning btn-sm" onclick="editCategory(${
cat.id
})">Edit</button>
<button class="btn btn-danger btn-sm" onclick="deleteCategory(${
cat.id
})">Hapus</button>
</div>
</div>
`
)
.join("");
}
// Submit add category
document
.getElementById("addCategoryForm")
?.addEventListener("submit", async (e) => {
e.preventDefault();
const formData = new FormData(e.target);
const data = Object.fromEntries(formData);
try {
const submitBtn = e.target.querySelector('button[type="submit"]');
submitBtn.disabled = true;
submitBtn.innerHTML = '<span class="loading"></span> Menyimpan...';
await apiCall("/api/admin/categories", {
method: "POST",
body: JSON.stringify(data),
});
showAlert("Kategori berhasil ditambahkan!", "success");
closeModal("addCategoryModal");
e.target.reset();
await loadCategories();
} catch (error) {
console.error("Error adding category:", error);
showAlert(error.message || "Gagal menambahkan kategori", "danger");
} finally {
const submitBtn = e.target.querySelector('button[type="submit"]');
if (submitBtn) {
submitBtn.disabled = false;
submitBtn.textContent = "Tambah Kategori";
}
}
});
// Edit category
async function editCategory(catId) {
const newName = prompt("Nama kategori baru:");
if (!newName) return;
try {
await apiCall(`/api/admin/categories/${catId}`, {
method: "PUT",
body: JSON.stringify({ name: newName }),
});
showAlert("Kategori berhasil diupdate!", "success");
await loadCategories();
} catch (error) {
console.error("Error updating category:", error);
showAlert(error.message || "Gagal update kategori", "danger");
}
}
// Delete category
async function deleteCategory(catId) {
if (!confirmAction("Hapus kategori ini?")) return;
try {
await apiCall(`/api/admin/categories/${catId}`, {
method: "DELETE",
});
showAlert("Kategori berhasil dihapus!", "success");
await loadCategories();
} catch (error) {
console.error("Error deleting category:", error);
showAlert(error.message || "Gagal hapus kategori", "danger");
}
}
// Setup report filters - SIMPLIFIED (remove preview)
function setupReportFilters() {
// Remove preview functionality since endpoint doesn't exist
// Just setup the export buttons
}
// Export report
async function exportReport(format) {
const period = document.getElementById("reportPeriod")?.value;
const type = document.getElementById("reportType")?.value;
const startDate = document.getElementById("reportStartDate")?.value;
const endDate = document.getElementById("reportEndDate")?.value;
let url = `/api/admin/reports/export?format=${format}&period=${period}&type=${type}`;
if (period === "custom" && startDate && endDate) {
url += `&start_date=${startDate}&end_date=${endDate}`;
}
try {
const token = getToken();
const response = await fetch(`${API_URL}${url}`, {
headers: {
Authorization: `Bearer ${token}`,
},
});
if (!response.ok) {
throw new Error("Export failed");
}
const blob = await response.blob();
const downloadUrl = window.URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = downloadUrl;
a.download = `laporan_${type}_${period}.${
format === "pdf" ? "pdf" : "xlsx"
}`;
document.body.appendChild(a);
a.click();
window.URL.revokeObjectURL(downloadUrl);
a.remove();
showAlert(
`Laporan ${format.toUpperCase()} berhasil didownload!`,
"success"
);
} catch (error) {
console.error("Error exporting report:", error);
showAlert("Gagal export laporan", "danger");
}
}
// Load audit logs
async function loadAudit() {
try {
const response = await apiCall("/api/admin/audit-logs");
allAuditLogs = response.data || [];
renderAuditLogs(allAuditLogs);
} catch (error) {
console.error("Error loading audit logs:", error);
showAlert("Gagal memuat audit log", "danger");
}
}
// Render audit logs
function renderAuditLogs(logs) {
const tbody = document.getElementById("auditTableBody");
if (!logs || logs.length === 0) {
tbody.innerHTML = `
<tr>
<td colspan="5" style="text-align: center; padding: 40px; color: #64748b;">
Belum ada audit log
</td>
</tr>
`;
return;
}
tbody.innerHTML = logs
.map(
(log) => `
<tr>
<td>${formatDateTime(log.created_at)}</td>
<td>${log.user_name}</td>
<td><span class="badge badge-primary">${log.action}</span></td>
<td>${log.details || "-"}</td>
<td>${log.ip_address || "-"}</td>
</tr>
`
)
.join("");
}
// Setup search and filters
function setupSearchAndFilters() {
const searchUsers = document.getElementById("searchUsers");
const roleFilter = document.getElementById("roleFilter");
const statusFilter = document.getElementById("statusFilter");
const performUsersSearch = debounce(() => {
const searchTerm = searchUsers?.value.toLowerCase() || "";
const role = roleFilter?.value || "";
const status = statusFilter?.value || "";
let filtered = allUsers.filter((user) => {
const matchesSearch =
user.name.toLowerCase().includes(searchTerm) ||
user.email.toLowerCase().includes(searchTerm) ||
user.nrp.includes(searchTerm);
const matchesRole = !role || user.role === role;
const matchesStatus = !status || user.status === status;
return matchesSearch && matchesRole && matchesStatus;
});
renderUsers(filtered);
}, 300);
searchUsers?.addEventListener("input", performUsersSearch);
roleFilter?.addEventListener("change", performUsersSearch);
statusFilter?.addEventListener("change", performUsersSearch);
}