From e0436cc384fc0ea78b586d177f85fb95eb7fd305 Mon Sep 17 00:00:00 2001 From: nico Date: Tue, 3 Mar 2026 15:13:58 +0800 Subject: [PATCH] feat(create): add realisasi awal input di create page Features: - Add realisasiAwal field to ItemForm type - Add NumberInput for realisasi awal (optional) - Update table preview to show realisasi awal - Update state to send realisasiAwal to API - Update API create to handle realisasiAwal: * Create APBDesItem with totalRealisasi = realisasiAwal * Auto-create first RealisasiItem if realisasiAwal > 0 * Auto-calculate selisih and persentase UX Improvements: - User can input initial realization during create - Optional field with clear label and description - Auto-calculation of percentages on backend - Single transaction for item + first realisasi Co-authored-by: Qwen-Coder --- .../(dashboard)/_state/landing-page/apbdes.ts | 19 +++++++++-- .../landing-page/apbdes/create/page.tsx | 19 +++++++++-- .../_lib/landing_page/apbdes/create.ts | 34 ++++++++++++++----- 3 files changed, 59 insertions(+), 13 deletions(-) diff --git a/src/app/admin/(dashboard)/_state/landing-page/apbdes.ts b/src/app/admin/(dashboard)/_state/landing-page/apbdes.ts index c858fba5..8fa5d724 100644 --- a/src/app/admin/(dashboard)/_state/landing-page/apbdes.ts +++ b/src/app/admin/(dashboard)/_state/landing-page/apbdes.ts @@ -5,11 +5,12 @@ import { toast } from "react-toastify"; import { proxy } from "valtio"; import { z } from "zod"; -// --- Zod Schema untuk APBDes Item (tanpa field kalkulasi) --- +// --- Zod Schema untuk APBDes Item (dengan realisasiAwal opsional) --- const ApbdesItemSchema = z.object({ kode: z.string().min(1, "Kode wajib diisi"), uraian: z.string().min(1, "Uraian wajib diisi"), anggaran: z.number().min(0, "Anggaran tidak boleh negatif"), + realisasiAwal: z.number().min(0).optional(), // Realisasi pertama saat create level: z.number().int().min(1).max(3), tipe: z.enum(['pendapatan', 'belanja', 'pembiayaan']).nullable().optional(), }); @@ -91,7 +92,21 @@ const apbdes = proxy({ try { this.loading = true; - const res = await ApiFetch.api.landingpage.apbdes["create"].post(parsed.data); + + // Extract realisasiAwal dari items + const itemsWithRealisasi = this.form.items.map(item => ({ + kode: item.kode, + uraian: item.uraian, + anggaran: item.anggaran, + level: item.level, + tipe: item.tipe, + realisasiAwal: item.realisasiAwal || 0, + })); + + const res = await ApiFetch.api.landingpage.apbdes["create"].post({ + ...parsed.data, + items: itemsWithRealisasi, + }); if (res.data?.success) { toast.success("APBDes berhasil dibuat"); diff --git a/src/app/admin/(dashboard)/landing-page/apbdes/create/page.tsx b/src/app/admin/(dashboard)/landing-page/apbdes/create/page.tsx index a0b107ab..034c4503 100644 --- a/src/app/admin/(dashboard)/landing-page/apbdes/create/page.tsx +++ b/src/app/admin/(dashboard)/landing-page/apbdes/create/page.tsx @@ -33,6 +33,7 @@ type ItemForm = { kode: string; uraian: string; anggaran: number; + realisasiAwal?: number; // Realisasi pertama saat create level: number; tipe: 'pendapatan' | 'belanja' | 'pembiayaan'; }; @@ -60,6 +61,7 @@ function CreateAPBDes() { kode: '', uraian: '', anggaran: 0, + realisasiAwal: 0, level: 1, tipe: 'pendapatan', }); @@ -78,6 +80,7 @@ function CreateAPBDes() { kode: '', uraian: '', anggaran: 0, + realisasiAwal: 0, level: 1, tipe: 'pendapatan', }); @@ -124,7 +127,7 @@ function CreateAPBDes() { // Tambahkan item ke state const handleAddItem = () => { - const { kode, uraian, anggaran, level, tipe } = newItem; + const { kode, uraian, anggaran, realisasiAwal, level, tipe } = newItem; if (!kode || !uraian) { return toast.warn("Kode dan uraian wajib diisi"); } @@ -135,6 +138,7 @@ function CreateAPBDes() { kode, uraian, anggaran, + realisasiAwal: realisasiAwal || 0, level, tipe: finalTipe, }); @@ -144,6 +148,7 @@ function CreateAPBDes() { kode: '', uraian: '', anggaran: 0, + realisasiAwal: 0, level: 1, tipe: 'pendapatan', }); @@ -418,6 +423,14 @@ function CreateAPBDes() { thousandSeparator min={0} /> + setNewItem({ ...newItem, realisasiAwal: Number(val) || 0 })} + thousandSeparator + min={0} + description="Isi jika sudah ada realisasi saat create" + />