From b1916ca3a3793c354bf7088a6f68c80789092fc5 Mon Sep 17 00:00:00 2001 From: nico Date: Fri, 24 Apr 2026 11:46:08 +0800 Subject: [PATCH] feat(admin): implement edit and delete functionality for UMKM and Produk modules - Added update and del methods to UMKM Valtio state - Wired up edit and delete buttons in UMKM and Produk list pages - Integrated ModalKonfirmasiHapus for deletion safety - Created UMKM and Produk edit pages with data loading and image previews - Cleaned up unused imports and fixed useEffect dependencies - Bumped version to 0.1.21 --- package.json | 2 +- .../(dashboard)/_state/ekonomi/umkm/umkm.ts | 92 +++++++ .../ekonomi/umkm/data-umkm/[id]/edit/page.tsx | 245 ++++++++++++++++++ .../ekonomi/umkm/data-umkm/page.tsx | 40 ++- .../ekonomi/umkm/produk/[id]/edit/page.tsx | 236 +++++++++++++++++ .../(dashboard)/ekonomi/umkm/produk/page.tsx | 39 ++- 6 files changed, 646 insertions(+), 8 deletions(-) create mode 100644 src/app/admin/(dashboard)/ekonomi/umkm/data-umkm/[id]/edit/page.tsx create mode 100644 src/app/admin/(dashboard)/ekonomi/umkm/produk/[id]/edit/page.tsx diff --git a/package.json b/package.json index e7c8ee09..8d615e4a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "desa-darmasaba", - "version": "0.1.20", + "version": "0.1.21", "private": true, "scripts": { "dev": "next dev", diff --git a/src/app/admin/(dashboard)/_state/ekonomi/umkm/umkm.ts b/src/app/admin/(dashboard)/_state/ekonomi/umkm/umkm.ts index 349308cf..64224734 100644 --- a/src/app/admin/(dashboard)/_state/ekonomi/umkm/umkm.ts +++ b/src/app/admin/(dashboard)/_state/ekonomi/umkm/umkm.ts @@ -124,6 +124,57 @@ export const umkmState = proxy({ return false; } }, + update: { + form: { ...defaultUmkmForm }, + loading: false, + async submit(id: string) { + const cek = umkmFormSchema.safeParse(this.form); + if (!cek.success) return toast.error("Cek kembali form anda"); + this.loading = true; + try { + const res = await fetch(`/api/ekonomi/umkm/update/${id}`, { + method: "PUT", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(this.form) + }); + const result = await res.json(); + if (result.success) { + toast.success("UMKM berhasil diperbarui"); + umkmState.umkm.findMany.load(); + return true; + } + toast.error(result.message); + } catch (e) { + toast.error("Gagal memperbarui UMKM"); + } finally { + this.loading = false; + } + return false; + } + }, + del: { + loading: false, + async submit(id: string) { + this.loading = true; + try { + const res = await fetch(`/api/ekonomi/umkm/delete/${id}`, { + method: "DELETE" + }); + const result = await res.json(); + if (result.success) { + toast.success("UMKM berhasil dihapus"); + umkmState.umkm.findMany.load(); + return true; + } + toast.error(result.message); + } catch (e) { + toast.error("Gagal menghapus UMKM"); + } finally { + this.loading = false; + } + return false; + } + }, findUnique: { data: null as any, loading: false, @@ -203,6 +254,47 @@ export const umkmState = proxy({ } catch (e) { toast.error("Gagal membuat produk"); } finally { this.loading = false; } return false; } + }, + update: { + form: { ...defaultProdukForm }, + loading: false, + async submit(id: string) { + const cek = produkFormSchema.safeParse(this.form); + if (!cek.success) return toast.error("Cek kembali form anda"); + this.loading = true; + try { + const res = await fetch(`/api/ekonomi/umkm/produk/update/${id}`, { + method: "PUT", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(this.form) + }); + const result = await res.json(); + if (result.success) { + toast.success("Produk berhasil diperbarui"); + umkmState.produk.findMany.load(); + return true; + } + } catch (e) { toast.error("Gagal memperbarui produk"); } finally { this.loading = false; } + return false; + } + }, + del: { + loading: false, + async submit(id: string) { + this.loading = true; + try { + const res = await fetch(`/api/ekonomi/umkm/produk/delete/${id}`, { + method: "DELETE" + }); + const result = await res.json(); + if (result.success) { + toast.success("Produk berhasil dihapus"); + umkmState.produk.findMany.load(); + return true; + } + } catch (e) { toast.error("Gagal menghapus produk"); } finally { this.loading = false; } + return false; + } } }, diff --git a/src/app/admin/(dashboard)/ekonomi/umkm/data-umkm/[id]/edit/page.tsx b/src/app/admin/(dashboard)/ekonomi/umkm/data-umkm/[id]/edit/page.tsx new file mode 100644 index 00000000..a1e11d8f --- /dev/null +++ b/src/app/admin/(dashboard)/ekonomi/umkm/data-umkm/[id]/edit/page.tsx @@ -0,0 +1,245 @@ +'use client'; +import { + Box, + Button, + Group, + Paper, + Stack, + TextInput, + Title, + Text, + Select, + ActionIcon, + Image, + Loader, + Center +} from '@mantine/core'; +import { Dropzone, IMAGE_MIME_TYPE } from '@mantine/dropzone'; +import { IconArrowBack, IconPhoto, IconUpload, IconX } from '@tabler/icons-react'; +import { useRouter, useParams } from 'next/navigation'; +import { useEffect, useState } from 'react'; +import { toast } from 'react-toastify'; +import { useProxy } from 'valtio/utils'; +import umkmState from '../../../../../_state/ekonomi/umkm/umkm'; +import CreateEditor from '@/app/admin/(dashboard)/_com/createEditor'; +import ApiFetch from '@/lib/api-fetch'; + +export default function EditDataUmkm() { + const router = useRouter(); + const params = useParams(); + const id = params.id as string; + const state = useProxy(umkmState.umkm); + + const [previewImage, setPreviewImage] = useState(null); + const [file, setFile] = useState(null); + const [isSubmitting, setIsSubmitting] = useState(false); + const [isInitialLoading, setIsInitialLoading] = useState(true); + + useEffect(() => { + const init = async () => { + await Promise.all([ + umkmState.kategoriProduk.findManyAll.load(), + state.findUnique.load(id) + ]); + + if (state.findUnique.data) { + const data = state.findUnique.data; + state.update.form = { + nama: data.nama || "", + pemilik: data.pemilik || "", + kategoriId: data.kategoriId || "", + deskripsi: data.deskripsi || "", + alamat: data.alamat || "", + kontak: data.kontak || "", + imageId: data.imageId || "", + isActive: data.isActive ?? true, + }; + + if (data.image?.url) { + setPreviewImage(data.image.url); + } + } + setIsInitialLoading(false); + }; + init(); + }, [id, state.findUnique, state.update]); + + const handleUpdate = async () => { + setIsSubmitting(true); + try { + // 1. Upload image if new file selected + let uploadedImageId = state.update.form.imageId; + if (file) { + const res = await ApiFetch.api.fileStorage.create.post({ + file, + name: file.name + }); + + const uploaded = res.data?.data; + if (uploaded?.id) { + uploadedImageId = uploaded.id; + } else { + setIsSubmitting(false); + return toast.error("Gagal mengunggah logo UMKM"); + } + } + + // 2. Submit UMKM data + state.update.form.imageId = uploadedImageId; + const success = await state.update.submit(id); + + if (success) { + router.push('/admin/ekonomi/umkm/data-umkm'); + } + } catch (error) { + console.error(error); + toast.error("Terjadi kesalahan sistem"); + } finally { + setIsSubmitting(false); + } + }; + + if (isInitialLoading) { + return ( +
+ +
+ ); + } + + return ( + + + + Edit Data UMKM + + + + + {/* Logo / Image UMKM */} + + Logo / Foto UMKM + {!previewImage ? ( + { + const file = files[0]; + setFile(file); + setPreviewImage(URL.createObjectURL(file)); + }} + maxSize={3 * 1024 ** 2} + accept={IMAGE_MIME_TYPE} + radius="md" + > + + + + + + + + + + + + + + Klik atau tarik gambar di sini + + + Maksimal 3MB + + + + + ) : ( + + Preview + { + setPreviewImage(null); + setFile(null); + state.update.form.imageId = ""; + }} + > + + + + )} + + + + (state.update.form.nama = e.target.value)} + /> + (state.update.form.pemilik = e.target.value)} + /> + + + + ({ + value: v.id, label: v.nama + })) || []} + value={state.update.form.umkmId} + onChange={(val) => (state.update.form.umkmId = val || "")} + /> + + (state.update.form.nama = e.target.value)} + /> + + + (state.update.form.harga = Number(val))} + /> + (state.update.form.stok = Number(val))} + /> + + +