const useUserHandlers = (state) => { const { setToast, setLoading, setStats, setItems, setMyFoundItems, setMyLostItems, setPublicLostItems, setMyClaims, setSelectedItem, setShowDetailModal, setShowClaimModal, setShowReportFoundModal, setPhotoPreview, setSuggestedLostItems, setShowSelectLostItemModal, setClaimInitialData, myLostItems, } = state; const showToast = (message, type = "info") => { setToast({ message, type }); }; const loadData = async () => { try { state.setLoading(true); const [ itemsResponse, myFoundResponse, myLostResponse, publicLostResponse, myClaimsResponse, categoriesResponse, ] = await Promise.all([ ApiUtils.get(`${CONFIG.API_ENDPOINTS.ITEMS}?page=1&limit=100`), ApiUtils.get(CONFIG.API_ENDPOINTS.USER.ITEMS).catch(() => ({ data: [], })), ApiUtils.get(CONFIG.API_ENDPOINTS.USER.LOST_ITEMS).catch(() => ({ data: [], })), ApiUtils.get(CONFIG.API_ENDPOINTS.LOST_ITEMS).catch(() => ({ data: [], })), ApiUtils.get(CONFIG.API_ENDPOINTS.USER.CLAIMS).catch(() => ({ data: [], })), ApiUtils.get( CONFIG.API_ENDPOINTS.CATEGORIES || "/api/categories" ).catch(() => ({ data: [] })), ]); state.setStats({ lost_items: myLostResponse.data?.length || 0, found_items: myFoundResponse.data?.length || 0, claims: myClaimsResponse.data?.length || 0, }); state.setItems(itemsResponse.data || []); state.setMyFoundItems(myFoundResponse.data || []); state.setMyLostItems(myLostResponse.data || []); state.setPublicLostItems(publicLostResponse.data || []); state.setMyClaims(myClaimsResponse.data || []); if (state.setCategories) { state.setCategories(categoriesResponse.data || []); } } catch (error) { console.error("Error loading data:", error); showToast("Gagal memuat data. Cek koneksi database.", "error"); } finally { state.setLoading(false); } }; const handleLogout = () => { if (Helpers.showConfirm("Apakah Anda yakin ingin logout?")) { AuthUtils.clearAuth(); window.location.href = "/login"; } }; const handleViewDetail = async (item) => { try { const response = await ApiUtils.get( `${CONFIG.API_ENDPOINTS.ITEMS}/${item.id}` ); setSelectedItem(response.data || response); setShowDetailModal(true); } catch (error) { showToast("Gagal memuat detail", "error"); } }; const handleUserRespondClaim = async (claimId, action) => { const confirmMsg = action === "approve" ? 'āœ… Yakin ini barang Anda?\n\nJika approve:\n- Status akan menjadi "Verified"\n- Anda bisa koordinasi pengambilan dengan penemu\n- Setelah terima barang, konfirmasi untuk case closed' : "āŒ Yakin menolak?\n\nJika reject:\n- Klaim akan ditolak\n- Barang kembali dalam status pencarian\n- Orang lain bisa mengajukan klaim"; if (!confirm(confirmMsg)) return; try { state.setLoading(true); // FIXED: URL endpoint sesuai controller await ApiUtils.post(`/api/claims/${claimId}/respond`, { action: action, }); showToast( action === "approve" ? "āœ… Berhasil! Silakan koordinasi pengambilan dengan penemu." : "āŒ Klaim ditolak. Barang kembali dalam pencarian.", "success" ); // Reload data agar tampilan tombol berubah await loadData(); } catch (error) { console.error("Error responding:", error); showToast( "Gagal memproses: " + (error.response?.data?.message || error.message), "error" ); } finally { state.setLoading(false); } }; const handleOpenDirectClaimModal = (lostItem) => { console.log("Membuka direct claim modal untuk:", lostItem.name); state.setSelectedLostItemForFound(lostItem); state.setShowDirectClaimModal(true); }; const handleClaim = (item) => { setSelectedItem(item); const matches = myLostItems.filter( (lostItem) => lostItem.status === "active" && lostItem.category_id === item.category_id ); if (matches.length > 0) { setSuggestedLostItems(matches); setShowSelectLostItemModal(true); } else { setClaimInitialData(null); setShowClaimModal(true); } }; const handleSelectLostItemForClaim = (lostItem) => { const initialData = { description: `[Berdasarkan Laporan Hilang #${lostItem.id} - ${lostItem.name}]\n${lostItem.description}`, contact: state.user?.phone || "", }; setClaimInitialData(initialData); setShowSelectLostItemModal(false); setShowClaimModal(true); }; const handleManualClaimEntry = () => { setClaimInitialData(null); setShowSelectLostItemModal(false); setShowClaimModal(true); }; const submitClaim = async (e) => { e.preventDefault(); const formData = new FormData(e.target); if (!formData.get("description") || !formData.get("contact")) { showToast("Deskripsi dan Kontak harus diisi", "error"); return; } try { setLoading(true); showToast("Memproses klaim...", "info"); let proofUrl = ""; const proofFile = formData.get("proof"); if (proofFile && proofFile.size > 0) { showToast("Mengupload bukti...", "info"); const uploadFormData = new FormData(); uploadFormData.append("proof", proofFile); const uploadResponse = await ApiUtils.uploadFile( "/api/upload/claim-proof", uploadFormData ); proofUrl = uploadResponse.data.url; } const payload = { item_id: parseInt(state.selectedItem.id), description: formData.get("description"), contact: formData.get("contact"), proof_url: proofUrl, }; await ApiUtils.post(CONFIG.API_ENDPOINTS.CLAIMS, payload); showToast("Klaim berhasil disubmit!", "success"); state.setShowClaimModal(false); loadData(); } catch (error) { showToast(error.message || "Gagal submit klaim", "error"); } finally { setLoading(false); } }; const submitReportLost = async (e) => { e.preventDefault(); const formData = new FormData(e.target); try { setLoading(true); const dateLost = formData.get("date_lost"); const dateLostISO = new Date(dateLost + "T00:00:00Z").toISOString(); const data = { 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, data); showToast("Laporan kehilangan berhasil!", "success"); state.setShowReportLostModal(false); loadData(); } catch (error) { showToast("Gagal submit laporan: " + error.message, "error"); } finally { setLoading(false); } }; const submitReportFound = async (e) => { e.preventDefault(); const formData = new FormData(e.target); try { setLoading(true); 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 payload = { 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"), }; if ( state.selectedLostItemForFound && state.foundReportMethod === "direct" ) { payload.lost_item_id = state.selectedLostItemForFound.id; payload.verification_flow = "direct"; payload.is_direct_to_owner = true; } await ApiUtils.post(CONFIG.API_ENDPOINTS.ITEMS, payload); if ( state.foundReportMethod === "direct" && state.selectedLostItemForFound ) { showToast("Laporan terkirim ke PEMILIK untuk disetujui!", "success"); } else { showToast("Laporan terkirim ke MANAGER untuk verifikasi.", "success"); } setShowReportFoundModal(false); setPhotoPreview(null); state.setSelectedLostItemForFound(null); loadData(); } catch (error) { showToast("Gagal mengirim laporan: " + error.message, "error"); } finally { setLoading(false); } }; const handleOpenFoundOption = (lostItem) => { console.log("Membuka opsi penemuan untuk:", lostItem.name); state.setSelectedLostItemForFound(lostItem); state.setShowFoundOptionModal(true); }; const handleSelectFoundOption = (method) => { console.log("Metode dipilih:", method); state.setFoundReportMethod(method); state.setShowFoundOptionModal(false); if (method === "direct") { handleDirectClaimFlow(); } else { state.setShowReportFoundModal(true); } }; const handleDirectClaimFlow = () => { if (!state.selectedLostItemForFound) { showToast("Tidak ada lost item yang dipilih", "error"); return; } state.setShowDirectClaimModal(true); }; const handlePhotoChange = (e) => { const file = e.target.files[0]; if (file) { const reader = new FileReader(); reader.onloadend = () => { setPhotoPreview(reader.result); }; reader.readAsDataURL(file); } }; const handleUserCompleteCase = async (claimId) => { const confirmMsg = 'šŸŽ‰ Konfirmasi Penerimaan Barang\n\nApakah Anda sudah menerima barang fisik ini?\n\nāœ… Jika Ya:\n- Status akan menjadi "Completed"\n- Kasus ditutup secara permanen\n- Tidak bisa dibatalkan\n\nāš ļø Pastikan barang sudah di tangan Anda!'; if (!confirm(confirmMsg)) return; try { state.setLoading(true); // FIXED: Gunakan /api/claims/:id/complete (bukan /api/user/claims/:id/complete) await ApiUtils.post(`/api/claims/${claimId}/complete`, {}); showToast( "šŸŽ‰ Selamat! Barang Anda telah kembali. Kasus selesai.", "success" ); loadData(); } catch (error) { console.error("Error completing case:", error); showToast("Gagal menyelesaikan: " + error.message, "error"); } finally { state.setLoading(false); } }; const handleDirectClaimSubmit = async (e) => { e.preventDefault(); const formData = new FormData(e.target); if (!state.selectedLostItemForFound) { showToast("Tidak ada lost item yang dipilih", "error"); return; } try { state.setLoading(true); const payload = { description: formData.get("description"), contact: formData.get("contact"), proof_url: formData.get("proof_url") || "", }; await ApiUtils.post( `/api/lost-items/${state.selectedLostItemForFound.id}/direct-claim`, payload ); showToast("āœ… Klaim terkirim ke pemilik untuk persetujuan!", "success"); state.setShowDirectClaimModal(false); state.setSelectedLostItemForFound(null); loadData(); } catch (error) { console.error("Direct claim error:", error); showToast("Gagal mengirim klaim: " + error.message, "error"); } finally { state.setLoading(false); } }; return { showToast, loadData, handleLogout, handleViewDetail, handleClaim, submitClaim, submitReportLost, submitReportFound, handlePhotoChange, handleSelectLostItemForClaim, handleManualClaimEntry, handleOpenFoundOption, handleSelectFoundOption, handleUserRespondClaim, handleUserCompleteCase, handleDirectClaimSubmit, handleDirectClaimFlow, handleOpenDirectClaimModal, }; }; window.useUserHandlers = useUserHandlers;