/* eslint-disable react-hooks/exhaustive-deps */ /* eslint-disable @typescript-eslint/no-explicit-any */ 'use client'; import apbdes from '@/app/admin/(dashboard)/_state/landing-page/apbdes'; import colors from '@/con/colors'; import ApiFetch from '@/lib/api-fetch'; import { ActionIcon, Badge, Box, Button, Group, Image, Loader, NumberInput, Paper, Select, Stack, Table, Text, TextInput, Title, } from '@mantine/core'; import { Dropzone } from '@mantine/dropzone'; import { IconArrowBack, IconFile, IconPhoto, IconPlus, IconTrash, IconX } from '@tabler/icons-react'; import { useParams, useRouter } from 'next/navigation'; import { useEffect, useState } from 'react'; import { toast } from 'react-toastify'; import { useProxy } from 'valtio/utils'; // Tipe untuk form item type ItemForm = { kode: string; uraian: string; anggaran: number; level: number; tipe: 'pendapatan' | 'belanja' | 'pembiayaan'; realisasi?: number; selisih?: number; persentase?: number; }; function EditAPBDes() { const apbdesState = useProxy(apbdes); const router = useRouter(); const params = useParams(); const [isSubmitting, setIsSubmitting] = useState(false); // Check if form is valid const isFormValid = () => { return ( apbdesState.edit.form.items.length > 0 ); }; const [previewImage, setPreviewImage] = useState(null); const [previewDoc, setPreviewDoc] = useState(null); const [imageFile, setImageFile] = useState(null); const [docFile, setDocFile] = useState(null); // Form input untuk item baru const [newItem, setNewItem] = useState({ kode: '', uraian: '', anggaran: 0, level: 1, tipe: 'pendapatan', realisasi: 0, selisih: 0, persentase: 0, }); // Simpan data original untuk reset form const [originalData, setOriginalData] = useState({ tahun: 0, name: '', deskripsi: '', jumlah: '', imageId: '', fileId: '', imageUrl: '', fileUrl: '', }); // Load data saat pertama kali useEffect(() => { const id = params?.id as string; if (!id) return; const loadData = async () => { try { const data = await apbdesState.edit.load(id); if (!data) return; // Set preview dari data lama setPreviewImage(data.image?.link || null); setPreviewDoc(data.file?.link || null); // Simpan data original untuk reset setOriginalData({ tahun: data.tahun || new Date().getFullYear(), name: data.name || '', deskripsi: data.deskripsi || '', jumlah: data.jumlah || '', imageId: data.imageId || '', fileId: data.fileId || '', imageUrl: data.image?.link || '', fileUrl: data.file?.link || '', }); // Set form dengan data lama (termasuk imageId dan fileId) apbdesState.edit.form = { tahun: data.tahun || new Date().getFullYear(), name: data.name || '', deskripsi: data.deskripsi || '', jumlah: data.jumlah || '', imageId: data.imageId || '', fileId: data.fileId || '', items: (data.items || []).map((item: any) => ({ kode: item.kode, uraian: item.uraian, anggaran: item.anggaran, realisasi: item.totalRealisasi || 0, selisih: item.selisih || 0, persentase: item.persentase || 0, level: item.level, tipe: item.tipe || 'pendapatan', })), }; } catch (error) { console.error('Error loading APBDes:', error); toast.error('Gagal memuat data APBDes'); } }; loadData(); }, [params?.id]); const handleDrop = (fileType: 'image' | 'doc') => (files: File[]) => { const file = files[0]; if (!file) return; if (fileType === 'image') { setImageFile(file); setPreviewImage(URL.createObjectURL(file)); } else { setDocFile(file); setPreviewDoc(URL.createObjectURL(file)); } }; const handleAddItem = () => { const { kode, uraian, anggaran, level, tipe, realisasi, selisih, persentase } = newItem; if (!kode || !uraian) { return toast.warn('Kode dan uraian wajib diisi'); } const finalTipe = level === 1 ? null : tipe; apbdesState.edit.addItem({ kode, uraian, anggaran, realisasi: realisasi || 0, selisih: selisih || 0, persentase: persentase || 0, level, tipe: finalTipe, }); setNewItem({ kode: '', uraian: '', anggaran: 0, level: 1, tipe: 'pendapatan', realisasi: 0, selisih: 0, persentase: 0, }); }; const handleRemoveItem = (index: number) => { apbdesState.edit.removeItem(index); }; const handleSubmit = async () => { if (apbdesState.edit.form.items.length === 0) { return toast.warn('Minimal harus ada 1 item APBDes'); } try { setIsSubmitting(true); // Upload file baru jika ada perubahan if (imageFile) { const res = await ApiFetch.api.fileStorage.create.post({ file: imageFile, name: imageFile.name, }); const imageId = res.data?.data?.id; if (imageId) { apbdesState.edit.form.imageId = imageId; } } if (docFile) { const res = await ApiFetch.api.fileStorage.create.post({ file: docFile, name: docFile.name, }); const fileId = res.data?.data?.id; if (fileId) { apbdesState.edit.form.fileId = fileId; } } // Image dan file sekarang opsional, tidak perlu validasi const success = await apbdesState.edit.update(); if (success) { router.push('/admin/landing-page/apbdes'); } } catch (err) { console.error('Update error:', err); toast.error('Gagal memperbarui APBDes'); } finally { setIsSubmitting(false); } }; const handleReset = () => { // Reset ke data original (tahun, name, deskripsi, jumlah, imageId, fileId) apbdesState.edit.form = { tahun: originalData.tahun, name: originalData.name, deskripsi: originalData.deskripsi, jumlah: originalData.jumlah, imageId: originalData.imageId, fileId: originalData.fileId, items: [...apbdesState.edit.form.items], // keep existing items }; // Reset preview ke data original setPreviewImage(originalData.imageUrl || null); setPreviewDoc(originalData.fileUrl || null); // Reset file uploads setImageFile(null); setDocFile(null); // Reset new item form setNewItem({ kode: '', uraian: '', anggaran: 0, level: 1, tipe: 'pendapatan', realisasi: 0, selisih: 0, persentase: 0, }); toast.info('Form dikembalikan ke data awal'); }; return ( Edit APBDes {/* Header Form */} (apbdesState.edit.form.name = e.target.value) } description="Opsional - akan diisi otomatis jika kosong" /> (apbdesState.edit.form.deskripsi = e.target.value) } description="Opsional" /> (apbdesState.edit.form.jumlah = e.target.value) } description="Opsional - total keseluruhan anggaran" /> (apbdesState.edit.form.tahun = Number(val) || new Date().getFullYear()) } min={2000} max={2100} required /> {/* Gambar & Dokumen (Opsional) */} Gambar APBDes (Opsional) toast.error('File gambar tidak valid')} maxSize={5 * 1024 ** 2} accept={{ 'image/*': ['.jpeg', '.jpg', '.png', '.webp'] }} radius="md" p="xl" > {previewImage ? 'Ganti gambar' : 'Unggah gambar'} {previewImage && ( Preview { setPreviewImage(null); setImageFile(null); apbdesState.edit.form.imageId = ''; // Clear imageId from form }} > )} Dokumen APBDes (Opsional) toast.error('File dokumen tidak valid')} maxSize={10 * 1024 ** 2} accept={{ 'application/pdf': ['.pdf'], 'application/msword': ['.doc'], 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': ['.docx'], 'application/vnd.ms-excel': ['.xls'], 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': ['.xlsx'], }} radius="md" p="xl" > {previewDoc ? 'Ganti dokumen' : 'Unggah dokumen'} {previewDoc && ( { setPreviewDoc(null); setDocFile(null); apbdesState.edit.form.fileId = ''; // Clear fileId from form }} > )} {/* Input Item Baru */} Tambah Item Pendapatan/Belanja setNewItem({ ...newItem, kode: e.target.value })} required /> setNewItem({ ...newItem, tipe: (val as any) || 'pendapatan' })} /> setNewItem({ ...newItem, uraian: e.target.value })} required /> setNewItem({ ...newItem, anggaran: Number(val) || 0 })} thousandSeparator min={0} /> {/* Tabel Items */} {apbdesState.edit.form.items.length > 0 && ( Daftar Item ({apbdesState.edit.form.items.length}) {apbdesState.edit.form.items.map((item, idx) => ( ))}
Kode Uraian Anggaran Realisasi Selisih % Level Tipe Aksi
{item.kode} {item.uraian} {item.anggaran.toLocaleString('id-ID')} {item.realisasi?.toLocaleString('id-ID') || '0'} 0 ? 'red' : 'green' }}> {item.selisih?.toLocaleString('id-ID') || '0'} {item.persentase?.toFixed(2) || '0'}% L{item.level} {item.tipe ? ( {item.tipe} ) : ( - )} handleRemoveItem(idx)}>
)} {/* Tombol Aksi */}
); } export default EditAPBDes;