// assets/js/pages/admin/useAdminHandlers.js - WITH ARCHIVES HANDLERS const useAdminHandlers = (state) => { const { setToast, setLoading, setStats, setUsers, setTotalPages, setTotalRecords, setItems, setSelectedItemDetail, setShowItemDetailModal, setSelectedUser, setShowEditModal, setShowCreateItemModal, setShowEditItemModal, setSelectedItemToEdit, setPhotoPreview, currentPage, // Claims States setClaims, setSelectedClaim, setShowClaimDetailModal, setShowCreateClaimModal, setShowEditClaimModal, setSelectedClaimToEdit, setCategories, setSelectedCategory, // ✅ Archives States setArchives, setSelectedArchive, setShowArchiveDetailModal, setAuditLogs, setLostItems, setSelectedLostItemDetail, setShowLostItemDetailModal, setShowCreateLostItemModal, setShowEditLostItemModal, setSelectedLostItemToEdit, } = state; const showToast = (message, type = "info") => { setToast({ message, type }); }; const loadData = async () => { try { const [statsData, usersData] = await Promise.all([ ApiUtils.get(CONFIG.API_ENDPOINTS.ADMIN.DASHBOARD), ApiUtils.get( `${CONFIG.API_ENDPOINTS.ADMIN.USERS}?page=${currentPage}&limit=${CONFIG.PAGINATION.LIMIT}` ), ]); setStats(statsData.data || {}); setUsers(usersData.data || []); if (usersData.pagination) { setTotalPages(usersData.pagination.total_pages); setTotalRecords(usersData.pagination.total_records); } } catch (error) { showToast("Gagal memuat data", "error"); } }; // NEW: Load Lost Items const loadLostItems = async (page = 1) => { try { setLoading(true); const { lostItemSearchTerm, lostItemStatusFilter, lostItemCategoryFilter, } = state; const queryParams = new URLSearchParams({ page: page, limit: 10, search: lostItemSearchTerm || "", status: lostItemStatusFilter || "", category: lostItemCategoryFilter || "", }); const response = await ApiUtils.get( `${CONFIG.API_ENDPOINTS.LOST_ITEMS}?${queryParams.toString()}` ); setLostItems(response.data || []); if (response.pagination) { state.setLostItemPage(response.pagination.current_page); state.setLostItemTotalPages(response.pagination.total_pages); state.setLostItemTotalRecords(response.pagination.total_records); } state.setFilteredLostItems(response.data || []); } catch (error) { showToast("Gagal memuat data laporan barang hilang", "error"); console.error(error); } finally { setLoading(false); } }; // NEW: View Lost Item Detail const handleViewLostItemDetail = async (lostItem) => { try { const response = await ApiUtils.get( `${CONFIG.API_ENDPOINTS.LOST_ITEMS}/${lostItem.id}` ); setSelectedLostItemDetail(response.data || response); setShowLostItemDetailModal(true); } catch (error) { showToast("Gagal memuat detail laporan", "error"); } }; // NEW: Create Lost Item const handleCreateLostItem = async (e) => { e.preventDefault(); const formData = new FormData(e.target); try { setLoading(true); showToast("Memproses pembuatan laporan...", "info"); const dateLost = formData.get("date_lost"); const dateLostISO = new Date(dateLost + "T00:00:00Z").toISOString(); const lostItemData = { user_id: parseInt(formData.get("user_id")), name: formData.get("name"), category_id: parseInt(formData.get("category_id")), color: formData.get("color") || "", location: formData.get("location") || "", description: formData.get("description"), date_lost: dateLostISO, }; await ApiUtils.post(CONFIG.API_ENDPOINTS.LOST_ITEMS, lostItemData); showToast("Laporan berhasil ditambahkan!", "success"); setShowCreateLostItemModal(false); loadLostItems(); loadData(); } catch (error) { showToast("Gagal menambahkan laporan: " + error.message, "error"); } finally { setLoading(false); } }; // NEW: Edit Lost Item Click const handleEditLostItemClick = async (lostItem) => { try { const response = await ApiUtils.get( `${CONFIG.API_ENDPOINTS.LOST_ITEMS}/${lostItem.id}` ); setSelectedLostItemToEdit(response.data || response); setShowEditLostItemModal(true); } catch (error) { showToast("Gagal memuat data laporan", "error"); } }; // NEW: Update Lost Item const handleUpdateLostItem = async (e) => { e.preventDefault(); const formData = new FormData(e.target); try { setLoading(true); showToast("Memproses update laporan...", "info"); const dateLost = formData.get("date_lost"); const dateLostISO = new Date(dateLost + "T00:00:00Z").toISOString(); // ✅ PERBAIKAN: Pastikan category_id dikirim sebagai integer const categoryId = parseInt(formData.get("category_id")); // ✅ VALIDASI: Cek apakah category_id valid if (!categoryId || isNaN(categoryId)) { showToast("Error: Category harus dipilih!", "error"); setLoading(false); return; } const lostItemData = { name: formData.get("name"), category_id: categoryId, // ✅ Gunakan integer, bukan string color: formData.get("color") || "", location: formData.get("location") || "", description: formData.get("description"), date_lost: dateLostISO, status: formData.get("status"), reason: formData.get("reason") || "Admin update", }; // ✅ DEBUG LOG console.log("📤 Data yang dikirim ke API:", lostItemData); console.log("🎯 Lost Item ID:", state.selectedLostItemToEdit.id); const response = await ApiUtils.put( `${CONFIG.API_ENDPOINTS.LOST_ITEMS}/${state.selectedLostItemToEdit.id}`, lostItemData ); // ✅ DEBUG LOG response console.log("✅ Response dari API:", response); showToast("Laporan berhasil diupdate!", "success"); setShowEditLostItemModal(false); setSelectedLostItemToEdit(null); // Reload data await loadLostItems(); await loadData(); } catch (error) { console.error("❌ Update error:", error); showToast("Gagal update laporan: " + error.message, "error"); } finally { setLoading(false); } }; // NEW: Delete Lost Item const handleDeleteLostItem = async (lostItemId) => { try { setLoading(true); await ApiUtils.delete(`${CONFIG.API_ENDPOINTS.LOST_ITEMS}/${lostItemId}`); showToast("Laporan berhasil dihapus!", "success"); loadLostItems(); loadData(); } catch (error) { showToast("Gagal menghapus laporan: " + error.message, "error"); } finally { setLoading(false); } }; // ✅ UPDATE: loadItems dengan Pagination & Filter Server-side const loadItems = async (page = 1) => { try { setLoading(true); // Ambil filter dari state saat ini const { itemSearchTerm, itemStatusFilter, itemCategoryFilter } = state; // Susun Query Params const queryParams = new URLSearchParams({ page: page, limit: 10, // ✅ Batasi 10 barang per halaman search: itemSearchTerm || "", status: itemStatusFilter || "", category: itemCategoryFilter || "", // Backend butuh slug kategori }); const response = await ApiUtils.get( `${CONFIG.API_ENDPOINTS.ITEMS}?${queryParams.toString()}` ); // Set Data Items setItems(response.data || []); // Set Data Pagination Barang if (response.pagination) { state.setItemPage(response.pagination.current_page); state.setItemTotalPages(response.pagination.total_pages); state.setItemTotalRecords(response.pagination.total_records); } // Update filteredItems langsung dengan data yang diterima (karena filter sudah di server) state.setFilteredItems(response.data || []); } catch (error) { showToast("Gagal memuat data barang", "error"); console.error(error); } finally { setLoading(false); } }; const loadClaims = async () => { try { setLoading(true); const response = await ApiUtils.get( `${CONFIG.API_ENDPOINTS.CLAIMS}?page=1&limit=1000` ); setClaims(response.data || []); } catch (error) { showToast("Gagal memuat data klaim", "error"); } finally { setLoading(false); } }; const loadCategories = async () => { try { setLoading(true); const response = await fetch( `${CONFIG.API_URL}${CONFIG.API_ENDPOINTS.CATEGORIES}`, { method: "GET", headers: { Authorization: `Bearer ${AuthUtils.getToken()}`, }, } ); if (!response.ok) { throw new Error("Gagal memuat kategori"); } const result = await response.json(); // PERUBAHAN 1: Jangan pakai || CONFIG.CATEGORIES // Jika data kosong, biarkan array kosong [] setCategories(result.data || []); } catch (error) { console.error("Load categories error:", error); showToast("Gagal memuat kategori", "error"); // PERUBAHAN 2: Hapus fallback di sini // Jangan paksa isi dengan data palsu/statis jika error setCategories([]); } finally { setLoading(false); } }; // ✅ NEW: Create Category const handleCreateCategory = async (e) => { e.preventDefault(); const formData = new FormData(e.target); try { setLoading(true); showToast("Memproses pembuatan kategori...", "info"); const categoryData = { name: formData.get("name"), value: formData.get("value").toLowerCase().replace(/\s+/g, "_"), description: formData.get("description") || "", }; // ✅ PATH: POST /api/categories const response = await fetch( `${CONFIG.API_URL}${CONFIG.API_ENDPOINTS.CATEGORIES}`, { method: "POST", headers: { "Content-Type": "application/json", Authorization: `Bearer ${AuthUtils.getToken()}`, }, body: JSON.stringify(categoryData), } ); if (!response.ok) { const errorData = await response.json(); throw new Error(errorData.error || "Gagal menambahkan kategori"); } await response.json(); showToast("Kategori berhasil ditambahkan!", "success"); state.setShowCreateCategoryModal(false); loadCategories(); loadData(); } catch (error) { console.error("Create category error:", error); showToast("Gagal menambahkan kategori: " + error.message, "error"); } finally { setLoading(false); } }; // ✅ FIXED: Update Category Handler const handleUpdateCategory = async (e) => { e.preventDefault(); const formData = new FormData(e.target); try { setLoading(true); showToast("Memproses update kategori...", "info"); const categoryData = { name: formData.get("name"), value: formData.get("value").toLowerCase().replace(/\s+/g, "_"), description: formData.get("description") || "", }; // ✅ FIX: Tambahkan selectedCategory.id di URL // PATH: PUT /api/categories/:id const response = await fetch( `${CONFIG.API_URL}${CONFIG.API_ENDPOINTS.CATEGORIES}/${state.selectedCategory.id}`, { method: "PUT", headers: { "Content-Type": "application/json", Authorization: `Bearer ${AuthUtils.getToken()}`, }, body: JSON.stringify(categoryData), } ); if (!response.ok) { const errorData = await response.json(); throw new Error(errorData.error || "Gagal update kategori"); } await response.json(); showToast("Kategori berhasil diupdate!", "success"); state.setShowEditCategoryModal(false); setSelectedCategory(null); loadCategories(); loadData(); } catch (error) { console.error("Update category error:", error); showToast("Gagal update kategori: " + error.message, "error"); } finally { setLoading(false); } }; const loadRolesAndPermissions = async () => { try { setLoading(true); const [rolesData, permsData] = await Promise.all([ ApiUtils.get(CONFIG.API_ENDPOINTS.ROLES), // ✅ Benar (Sesuai config.js) ApiUtils.get(CONFIG.API_ENDPOINTS.PERMISSIONS), // ✅ Benar (Sesuai config.js) ]); state.setRoles(rolesData.data || []); state.setPermissions(permsData.data || []); } catch (error) { showToast("Gagal memuat roles/permissions", "error"); } finally { setLoading(false); } }; const handleCreateRole = async (formData) => { try { setLoading(true); await ApiUtils.post(CONFIG.API_ENDPOINTS.ROLES, formData); showToast("Role berhasil dibuat", "success"); state.setShowCreateRoleModal(false); loadRolesAndPermissions(); } catch (error) { showToast("Gagal membuat role: " + error.message, "error"); } finally { setLoading(false); } }; const handleUpdateRole = async (formData) => { try { setLoading(true); // GANTI DARI: CONFIG.API_ENDPOINTS.ADMIN.ROLES // MENJADI: CONFIG.API_ENDPOINTS.ROLES await ApiUtils.put( `${CONFIG.API_ENDPOINTS.ROLES}/${state.selectedRole.id}`, formData ); showToast("Role berhasil diupdate", "success"); state.setShowEditRoleModal(false); state.setSelectedRole(null); loadRolesAndPermissions(); } catch (error) { showToast("Gagal update role: " + error.message, "error"); } finally { setLoading(false); } }; const handleDeleteRole = async (id) => { if (!confirm("Yakin hapus role ini?")) return; try { // GANTI DARI: CONFIG.API_ENDPOINTS.ADMIN.ROLES // MENJADI: CONFIG.API_ENDPOINTS.ROLES await ApiUtils.delete(`${CONFIG.API_ENDPOINTS.ROLES}/${id}`); showToast("Role dihapus", "success"); loadRolesAndPermissions(); } catch (error) { showToast("Gagal hapus role: " + error.message, "error"); } }; const handleEditRole = (role) => { state.setSelectedRole(role); state.setShowEditRoleModal(true); }; // ✅ NEW: Delete Category const handleDeleteCategory = async (categoryId) => { if (!confirm("⚠️ Yakin ingin menghapus kategori ini?")) return; try { setLoading(true); showToast("Menghapus kategori...", "info"); // ✅ FIX: Tambahkan categoryId di URL // PATH: DELETE /api/categories/:id const response = await fetch( `${CONFIG.API_URL}${CONFIG.API_ENDPOINTS.CATEGORIES}/${categoryId}`, { method: "DELETE", headers: { Authorization: `Bearer ${AuthUtils.getToken()}`, }, } ); if (!response.ok) { const errorData = await response.json(); throw new Error(errorData.error || "Gagal menghapus kategori"); } await response.json(); showToast("Kategori berhasil dihapus!", "success"); loadCategories(); loadData(); } catch (error) { console.error("Delete category error:", error); showToast("Gagal menghapus kategori: " + error.message, "error"); } finally { setLoading(false); } }; // ✅ NEW: Load Archives const loadArchives = async () => { try { setLoading(true); const response = await ApiUtils.get( `${CONFIG.API_ENDPOINTS.ITEMS}?status=case_closed&page=1&limit=1000` ); setArchives(response.data || []); } catch (error) { showToast("Gagal memuat data arsip", "error"); } finally { setLoading(false); } }; // Load Audit Logs const loadAuditLogs = async (page = 1) => { try { setLoading(true); // Ambil filter dari state const { auditLogActionFilter, auditLogUserFilter } = state; // Susun Query Params const queryParams = new URLSearchParams({ page: page, limit: 10, // ✅ Set limit 10 per halaman action: auditLogActionFilter || "", // Kirim filter lain jika backend mendukung (misal user_id atau search generic) // search: state.auditLogSearchTerm || "" }); // Jika ada filter user (asumsi backend menerima user_id atau username) if (auditLogUserFilter) { queryParams.append("user_id", auditLogUserFilter); // Sesuaikan dengan parameter backend } const response = await ApiUtils.get( `${CONFIG.API_ENDPOINTS.ADMIN.AUDIT_LOGS}?${queryParams.toString()}` ); // Set Data setAuditLogs(response.data || []); // ✅ Update State Pagination (Generic State di useAdminState) if (response.pagination) { setTotalPages(response.pagination.total_pages); setTotalRecords(response.pagination.total_records); state.setCurrentPage(response.pagination.current_page); } // Karena pagination sekarang di server, filteredAuditLogs sama dengan data yang diterima state.setFilteredAuditLogs(response.data || []); } catch (error) { showToast("Gagal memuat audit log", "error"); console.error(error); } finally { setLoading(false); } }; // ✅ NEW: View Archive Detail const handleViewArchiveDetail = async (archive) => { try { const response = await ApiUtils.get( `${CONFIG.API_ENDPOINTS.ITEMS}/${archive.id}` ); setSelectedArchive(response.data || response); setShowArchiveDetailModal(true); } catch (error) { showToast("Gagal memuat detail arsip", "error"); } }; const handleCreateClaim = async (e) => { e.preventDefault(); const formData = new FormData(e.target); try { setLoading(true); showToast("Memproses pembuatan klaim...", "info"); const claimData = { item_id: parseInt(formData.get("item_id")), user_id: parseInt(formData.get("user_id")), description: formData.get("description"), contact: formData.get("contact"), admin_notes: formData.get("admin_notes") || "", }; await ApiUtils.post(CONFIG.API_ENDPOINTS.CLAIMS, claimData); showToast("Klaim berhasil ditambahkan!", "success"); setShowCreateClaimModal(false); loadClaims(); loadData(); } catch (error) { showToast("Gagal menambahkan klaim: " + error.message, "error"); } finally { setLoading(false); } }; const handleEditClaimClick = async (claim) => { try { const response = await ApiUtils.get( `${CONFIG.API_ENDPOINTS.CLAIMS}/${claim.id}` ); setSelectedClaimToEdit(response.data || response); setShowEditClaimModal(true); } catch (error) { showToast("Gagal memuat data klaim", "error"); } }; const handleUpdateClaim = async (e) => { e.preventDefault(); const formData = new FormData(e.target); try { setLoading(true); showToast("Memproses update klaim...", "info"); const claimData = { description: formData.get("description"), contact: formData.get("contact"), reason: formData.get("reason") || "Admin update", }; await ApiUtils.patch( `${CONFIG.API_ENDPOINTS.CLAIMS}/${state.selectedClaimToEdit.id}`, claimData ); showToast("Klaim berhasil diupdate!", "success"); setShowEditClaimModal(false); setSelectedClaimToEdit(null); loadClaims(); loadData(); } catch (error) { showToast("Gagal update klaim: " + error.message, "error"); } finally { setLoading(false); } }; const handleViewClaimDetail = async (claim) => { try { const response = await ApiUtils.get( `${CONFIG.API_ENDPOINTS.CLAIMS}/${claim.id}` ); setSelectedClaim(response.data || response); setShowClaimDetailModal(true); } catch (error) { showToast("Gagal memuat detail klaim", "error"); } }; const handleDeleteClaim = async (claimId) => { if (!confirm("⚠️ Yakin ingin menghapus klaim ini?")) return; try { setLoading(true); await ApiUtils.delete(`${CONFIG.API_ENDPOINTS.CLAIMS}/${claimId}`); showToast("Klaim berhasil dihapus!", "success"); loadClaims(); loadData(); } catch (error) { showToast("Gagal menghapus klaim: " + error.message, "error"); } finally { setLoading(false); } }; const handleViewItemDetail = async (item) => { try { const response = await ApiUtils.get( `${CONFIG.API_ENDPOINTS.ITEMS}/${item.id}` ); setSelectedItemDetail(response.data || response); setShowItemDetailModal(true); } catch (error) { showToast("Gagal memuat detail barang", "error"); } }; const handleCreateItem = async (e) => { e.preventDefault(); const formData = new FormData(e.target); try { setLoading(true); showToast("Memproses pembuatan barang...", "info"); let photoUrl = ""; const photoFile = formData.get("photo"); if (photoFile && photoFile.size > 0) { showToast("Mengupload foto...", "info"); const uploadFormData = new FormData(); uploadFormData.append("image", photoFile); const uploadData = await ApiUtils.uploadFile( CONFIG.API_ENDPOINTS.UPLOAD, uploadFormData ); photoUrl = uploadData.data.url; } const dateFound = formData.get("date_found"); const dateFoundISO = new Date(dateFound + "T00:00:00Z").toISOString(); const itemData = { name: formData.get("name"), category_id: parseInt(formData.get("category_id")), photo_url: photoUrl, location: formData.get("location"), description: formData.get("description"), secret_details: formData.get("secret_details"), date_found: dateFoundISO, reporter_name: formData.get("reporter_name"), reporter_contact: formData.get("reporter_contact"), }; await ApiUtils.post(CONFIG.API_ENDPOINTS.ITEMS, itemData); showToast("Barang berhasil ditambahkan!", "success"); setShowCreateItemModal(false); setPhotoPreview(null); loadItems(); loadData(); } catch (error) { showToast("Gagal menambahkan barang: " + error.message, "error"); } finally { setLoading(false); } }; const handleEditItemClick = async (item) => { try { const response = await ApiUtils.get( `${CONFIG.API_ENDPOINTS.ITEMS}/${item.id}` ); setSelectedItemToEdit(response.data || response); setShowEditItemModal(true); } catch (error) { showToast("Gagal memuat data barang", "error"); } }; const handleUpdateItem = async (e) => { e.preventDefault(); const formData = new FormData(e.target); try { setLoading(true); showToast("Memproses update barang...", "info"); // 🔧 FIX 1: Upload foto baru jika ada let photoUrl = state.selectedItemToEdit.photo_url; // Gunakan foto lama sebagai default const photoFile = formData.get("photo"); if (photoFile && photoFile.size > 0) { showToast("Mengupload foto baru...", "info"); const uploadFormData = new FormData(); uploadFormData.append("image", photoFile); try { const uploadData = await ApiUtils.uploadFile( CONFIG.API_ENDPOINTS.UPLOAD, uploadFormData ); photoUrl = uploadData.data.url; } catch (uploadError) { console.error("Upload error:", uploadError); showToast( "Gagal upload foto, melanjutkan dengan foto lama", "warning" ); } } const dateFound = formData.get("date_found"); const dateFoundISO = new Date(dateFound + "T00:00:00Z").toISOString(); const categoryId = parseInt(formData.get("category_id")); if (isNaN(categoryId)) { showToast("Error: Category ID tidak valid!", "error"); return; } // 🔧 FIX 2: Selalu kirim photo_url const itemData = { name: formData.get("name"), category_id: categoryId, photo_url: photoUrl, // ✅ TAMBAHKAN INI location: formData.get("location"), description: formData.get("description"), secret_details: formData.get("secret_details"), date_found: dateFoundISO, reporter_name: formData.get("reporter_name"), reporter_contact: formData.get("reporter_contact"), status: formData.get("status"), reason: formData.get("reason") || "Admin update", }; console.log("📤 Data yang akan dikirim:", itemData); console.log("📤 Item yang sedang diedit:", state.selectedItemToEdit); await ApiUtils.put( `${CONFIG.API_ENDPOINTS.ITEMS}/${state.selectedItemToEdit.id}`, itemData ); showToast("Barang berhasil diupdate!", "success"); setShowEditItemModal(false); setSelectedItemToEdit(null); setPhotoPreview(null); // Reset preview loadItems(); loadData(); } catch (error) { console.error("❌ Update error:", error); showToast("Gagal update barang: " + error.message, "error"); } finally { setLoading(false); } }; const handleDeleteItem = async (itemId) => { if (!confirm("⚠️ Yakin ingin menghapus barang ini?")) return; try { setLoading(true); await ApiUtils.delete(`${CONFIG.API_ENDPOINTS.ITEMS}/${itemId}`); showToast("Barang berhasil dihapus!", "success"); loadItems(); loadData(); } catch (error) { showToast("Gagal menghapus barang: " + error.message, "error"); } finally { setLoading(false); } }; const handlePhotoChange = (e) => { const file = e.target.files[0]; if (file) { const reader = new FileReader(); reader.onloadend = () => { setPhotoPreview(reader.result); }; reader.readAsDataURL(file); } }; const handleExport = async (format) => { try { setLoading(true); const period = document.querySelector('select[name="period"]')?.value || "month"; const reportType = document.querySelector('select[name="report_type"]')?.value || "all"; const endDate = new Date(); const startDate = new Date(); switch (period) { case "month": startDate.setMonth(startDate.getMonth() - 1); break; case "semester": startDate.setMonth(startDate.getMonth() - 6); break; case "year": startDate.setFullYear(startDate.getFullYear() - 1); break; } const requestBody = { type: reportType, format: format, start_date: startDate.toISOString(), end_date: endDate.toISOString(), }; showToast(`Generating ${format.toUpperCase()} report...`, "info"); const response = await fetch( `${CONFIG.API_URL}${CONFIG.API_ENDPOINTS.ADMIN.EXPORT}`, { method: "POST", headers: { "Content-Type": "application/json", Authorization: `Bearer ${AuthUtils.getToken()}`, }, body: JSON.stringify(requestBody), } ); if (!response.ok) { const errorText = await response.text(); throw new Error(`Export failed: ${errorText}`); } const contentDisposition = response.headers.get("Content-Disposition"); let filename = `report_${Date.now()}.${ format === "pdf" ? "pdf" : "xlsx" }`; if (contentDisposition) { const filenameMatch = contentDisposition.match(/filename="?(.+)"?/); if (filenameMatch) { filename = filenameMatch[1]; } } const blob = await response.blob(); const url = window.URL.createObjectURL(blob); const a = document.createElement("a"); a.href = url; a.download = filename; document.body.appendChild(a); a.click(); window.URL.revokeObjectURL(url); document.body.removeChild(a); showToast(`${format.toUpperCase()} exported successfully!`, "success"); } catch (error) { showToast(`Failed to export: ${error.message}`, "error"); } finally { setLoading(false); } }; const handleLogout = () => { if (Helpers.showConfirm("Apakah Anda yakin ingin logout?")) { AuthUtils.clearAuth(); window.location.href = "/login"; } }; const handleEditUser = (userData) => { setSelectedUser(userData); setShowEditModal(true); }; const handleUpdateUser = async (e) => { e.preventDefault(); const formData = new FormData(e.target); const role = formData.get("role"); const roleMapping = { user: 3, manager: 2, admin: 1, }; const role_id = roleMapping[role]; try { setLoading(true); await ApiUtils.patch( `${CONFIG.API_ENDPOINTS.ADMIN.USERS}/${state.selectedUser.id}/role`, { role_id } ); showToast("User berhasil diupdate!", "success"); setShowEditModal(false); loadData(); } catch (error) { showToast(`Gagal update user: ${error.message}`, "error"); } finally { setLoading(false); } }; const handleBlockUser = async (userId) => { if (!Helpers.showConfirm("Block user ini?")) return; try { await ApiUtils.post( `${CONFIG.API_ENDPOINTS.ADMIN.USERS}/${userId}/block`, {} ); showToast("User berhasil diblock!", "success"); loadData(); } catch (error) { showToast("Gagal block user", "error"); } }; const handleUnblockUser = async (userId) => { if (!Helpers.showConfirm("Unblock user ini?")) return; try { await ApiUtils.post( `${CONFIG.API_ENDPOINTS.ADMIN.USERS}/${userId}/unblock`, {} ); showToast("User berhasil di-unblock!", "success"); loadData(); } catch (error) { showToast("Gagal unblock user", "error"); } }; return { showToast, loadData, loadItems, handleViewItemDetail, handleExport, handleLogout, handleEditUser, handleUpdateUser, handleBlockUser, handleUnblockUser, handleCreateItem, handleEditItemClick, handleUpdateItem, handleDeleteItem, handlePhotoChange, // Claims Handlers loadClaims, handleViewClaimDetail, handleDeleteClaim, handleCreateClaim, handleEditClaimClick, handleUpdateClaim, loadCategories, handleCreateCategory, handleUpdateCategory, handleDeleteCategory, // ✅ NEW: Archives Handlers loadArchives, handleViewArchiveDetail, loadAuditLogs, loadRolesAndPermissions, handleCreateRole, handleUpdateRole, handleDeleteRole, handleEditRole, loadLostItems, handleViewLostItemDetail, handleCreateLostItem, handleEditLostItemClick, handleUpdateLostItem, handleDeleteLostItem, }; };