From 2608a5ffdd5dae11ea76e6636369bf933fca1c08 Mon Sep 17 00:00:00 2001 From: nico Date: Tue, 18 Nov 2025 16:26:09 +0800 Subject: [PATCH] Fix Edit di Admin APbdes, dan fix data real di apbdes user --- .../(dashboard)/_state/landing-page/apbdes.ts | 65 ++--------- .../landing-page/apbdes/[id]/edit/page.tsx | 37 +++--- .../landing-page/apbdes/create/page.tsx | 4 +- .../_lib/landing_page/apbdes/create.ts | 2 +- .../_lib/landing_page/apbdes/index.ts | 2 +- .../_lib/landing_page/apbdes/updt.ts | 4 +- .../darmasaba/_com/main-page/apbdes/index.tsx | 105 ++++-------------- 7 files changed, 56 insertions(+), 163 deletions(-) diff --git a/src/app/admin/(dashboard)/_state/landing-page/apbdes.ts b/src/app/admin/(dashboard)/_state/landing-page/apbdes.ts index af8388f4..dcf07589 100644 --- a/src/app/admin/(dashboard)/_state/landing-page/apbdes.ts +++ b/src/app/admin/(dashboard)/_state/landing-page/apbdes.ts @@ -7,14 +7,14 @@ import { z } from "zod"; // --- Zod Schema --- const ApbdesItemSchema = z.object({ - kode: z.string().min(1), - uraian: z.string().min(1), + kode: z.string().min(1, "Kode wajib diisi"), + uraian: z.string().min(1, "Uraian wajib diisi"), anggaran: z.number().min(0), realisasi: z.number().min(0), selisih: z.number(), - persentase: z.number().min(0).max(1000), // allow >100% if overbudget + persentase: z.number(), level: z.number().int().min(1).max(3), - tipe: z.string().min(1), // "pendapatan" | "belanja" + tipe: z.enum(['pendapatan', 'belanja', 'pembiayaan']).nullable().optional(), }); const ApbdesFormSchema = z.object({ @@ -37,6 +37,9 @@ const defaultApbdesForm = { function normalizeItem(item: Partial>): z.infer { const anggaran = item.anggaran ?? 0; const realisasi = item.realisasi ?? 0; + + + // ✅ Formula yang benar const selisih = anggaran - realisasi; // positif = sisa anggaran, negatif = over budget @@ -56,58 +59,6 @@ function normalizeItem(item: Partial>): z.infer // --- State Utama --- const apbdes = proxy({ - // create: { - // form: { ...defaultApbdesForm }, - // loading: false, - - // addItem(item: Partial>) { - // const normalized = normalizeItem(item); - // this.form.items.push(normalized); - // }, - - // removeItem(index: number) { - // this.form.items.splice(index, 1); - // }, - - // updateItem(index: number, updates: Partial>) { - // const current = this.form.items[index]; - // if (current) { - // const updated = normalizeItem({ ...current, ...updates }); - // this.form.items[index] = updated; - // } - // }, - - // reset() { - // this.form = { ...defaultApbdesForm }; - // }, - - // async create() { - // const parsed = ApbdesFormSchema.safeParse(this.form); - // if (!parsed.success) { - // const errors = parsed.error.issues.map((issue) => `${issue.path.join(".")} - ${issue.message}`); - // toast.error(`Validasi gagal:\n${errors.join("\n")}`); - // return; - // } - - // try { - // this.loading = true; - // const res = await ApiFetch.api.landingpage.apbdes["create"].post(parsed.data); - - // if (res.data?.success) { - // toast.success("APBDes berhasil dibuat"); - // apbdes.findMany.load(); - // this.reset(); - // } else { - // toast.error(res.data?.message || "Gagal membuat APBDes"); - // } - // } catch (error: any) { - // console.error("Create APBDes error:", error); - // toast.error(error?.message || "Terjadi kesalahan saat membuat APBDes"); - // } finally { - // this.loading = false; - // } - // }, - // }, create: { form: { ...defaultApbdesForm }, loading: false, @@ -305,7 +256,7 @@ const apbdes = proxy({ selisih: item.selisih, persentase: item.persentase, level: item.level, - tipe: item.tipe, + tipe: item.tipe || 'pendapatan', })), }; return data; diff --git a/src/app/admin/(dashboard)/landing-page/apbdes/[id]/edit/page.tsx b/src/app/admin/(dashboard)/landing-page/apbdes/[id]/edit/page.tsx index 45c8f4d9..63455fae 100644 --- a/src/app/admin/(dashboard)/landing-page/apbdes/[id]/edit/page.tsx +++ b/src/app/admin/(dashboard)/landing-page/apbdes/[id]/edit/page.tsx @@ -115,20 +115,22 @@ function EditAPBDes() { if (!kode || !uraian) { return toast.warn('Kode dan uraian wajib diisi'); } + const finalTipe = level === 1 ? 'pendapatan' : tipe; // Berikan default - const selisih = realisasi - anggaran; - const persentase = anggaran > 0 ? (realisasi / anggaran) * 100 : 0; + const selisih = realisasi - anggaran; + const persentase = anggaran > 0 ? (realisasi / anggaran) * 100 : 0; + + apbdesState.edit.addItem({ + kode, + uraian, + anggaran, + realisasi, + selisih, + persentase, + level, + tipe: finalTipe, // ✅ Tidak akan undefined + }); - apbdesState.edit.addItem({ - kode, - uraian, - anggaran, - realisasi, - selisih, - persentase, - level, - tipe, - }); setNewItem({ kode: '', @@ -374,6 +376,7 @@ function EditAPBDes() { data={[ { value: 'pendapatan', label: 'Pendapatan' }, { value: 'belanja', label: 'Belanja' }, + { value: 'pembiayaan', label: 'Pembiayaan' }, ]} value={newItem.tipe} onChange={(val) => setNewItem({ ...newItem, tipe: (val as any) || 'pendapatan' })} @@ -447,9 +450,13 @@ function EditAPBDes() { - - {item.tipe} - + {item.tipe ? ( + + {item.tipe} + + ) : ( + '-' + )} handleRemoveItem(idx)}> 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 ed98e097..85b61242 100644 --- a/src/app/admin/(dashboard)/landing-page/apbdes/create/page.tsx +++ b/src/app/admin/(dashboard)/landing-page/apbdes/create/page.tsx @@ -123,6 +123,8 @@ function CreateAPBDes() { return toast.warn("Kode dan uraian wajib diisi"); } + const finalTipe = level === 1 ? 'pendapatan' : tipe; // Berikan default + const selisih = realisasi - anggaran; const persentase = anggaran > 0 ? (realisasi / anggaran) * 100 : 0; @@ -134,7 +136,7 @@ function CreateAPBDes() { selisih, persentase, level, - tipe, + tipe: finalTipe, }); // Reset form input diff --git a/src/app/api/[[...slugs]]/_lib/landing_page/apbdes/create.ts b/src/app/api/[[...slugs]]/_lib/landing_page/apbdes/create.ts index 55937f89..8715cf2b 100644 --- a/src/app/api/[[...slugs]]/_lib/landing_page/apbdes/create.ts +++ b/src/app/api/[[...slugs]]/_lib/landing_page/apbdes/create.ts @@ -12,7 +12,7 @@ type APBDesItemInput = { selisih: number; persentase: number; level: number; - tipe: string; + tipe?: string | null; }; type FormCreate = { diff --git a/src/app/api/[[...slugs]]/_lib/landing_page/apbdes/index.ts b/src/app/api/[[...slugs]]/_lib/landing_page/apbdes/index.ts index 7b24c45d..9e558f6d 100644 --- a/src/app/api/[[...slugs]]/_lib/landing_page/apbdes/index.ts +++ b/src/app/api/[[...slugs]]/_lib/landing_page/apbdes/index.ts @@ -15,7 +15,7 @@ const ApbdesItemSchema = t.Object({ selisih: t.Number(), persentase: t.Number(), level: t.Number(), - tipe: t.String(), // misal: "pendapatan" atau "belanja" + tipe: t.Optional(t.Union([t.String(), t.Null()])) // misal: "pendapatan" atau "belanja" }); const APBDes = new Elysia({ diff --git a/src/app/api/[[...slugs]]/_lib/landing_page/apbdes/updt.ts b/src/app/api/[[...slugs]]/_lib/landing_page/apbdes/updt.ts index d1aca338..154b3502 100644 --- a/src/app/api/[[...slugs]]/_lib/landing_page/apbdes/updt.ts +++ b/src/app/api/[[...slugs]]/_lib/landing_page/apbdes/updt.ts @@ -10,7 +10,7 @@ type APBDesItemInput = { selisih: number; persentase: number; level: number; - tipe: string; + tipe?: string | null; }; type FormUpdateBody = { @@ -54,7 +54,7 @@ export default async function apbdesUpdate(context: Context) { selisih: item.anggaran - item.realisasi, persentase: item.anggaran > 0 ? (item.realisasi / item.anggaran) * 100 : 0, level: item.level, - tipe: item.tipe, + tipe: item.tipe || null, isActive: true, })), }); diff --git a/src/app/darmasaba/_com/main-page/apbdes/index.tsx b/src/app/darmasaba/_com/main-page/apbdes/index.tsx index 907a3d56..03cd7219 100644 --- a/src/app/darmasaba/_com/main-page/apbdes/index.tsx +++ b/src/app/darmasaba/_com/main-page/apbdes/index.tsx @@ -1,25 +1,15 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable react-hooks/exhaustive-deps */ 'use client' import apbdes from '@/app/admin/(dashboard)/_state/landing-page/apbdes' +import APBDesProgress from '@/app/darmasaba/(tambahan)/apbdes/lib/apbDesaProgress' import colors from '@/con/colors' -import { BarChart } from '@mantine/charts' -import { ActionIcon, BackgroundImage, Box, Button, Center, Flex, Group, Loader, Paper, SimpleGrid, Stack, Text, Title } from '@mantine/core' +import { ActionIcon, BackgroundImage, Box, Button, Center, Flex, Group, Loader, SimpleGrid, Stack, Text } from '@mantine/core' import { IconDownload } from '@tabler/icons-react' import Link from 'next/link' import { useEffect, useState } from 'react' import { useProxy } from 'valtio/utils' -import parseJumlah from './lib/convert' function Apbdes() { - type APBDes = { - id: string - name: string - jumlah: number - }; - - const [chartData, setChartData] = useState([]) - const [mounted, setMounted] = useState(false); const state = useProxy(apbdes) const [loading, setLoading] = useState(false) @@ -28,22 +18,9 @@ function Apbdes() { des: 'Transparansi APBDes Darmasaba adalah langkah nyata menuju tata kelola desa yang bersih, terbuka, dan bertanggung jawab.' } - useEffect(() => { - if (state.findMany.data) { - setChartData( - state.findMany.data.map((item: any) => ({ - id: item.id, - name: item.name, - jumlah: parseJumlah(item.jumlah), - })) - ); - } - }, [state.findMany.data]); - useEffect(() => { const loadData = async () => { try { - setMounted(true); setLoading(true) await state.findMany.load() } catch (error) { @@ -70,56 +47,23 @@ function Apbdes() { - {/* Chart */} - - - - - Grafik APBDes - - {mounted && chartData.length > 0 ? ( - { - if (value >= 1_000_000_000_000) - return `Rp ${(value / 1_000_000_000_000).toFixed(1)} T`; - if (value >= 1_000_000_000) - return `Rp ${(value / 1_000_000_000).toFixed(1)} M`; - if (value >= 1_000_000) - return `Rp ${(value / 1_000_000).toFixed(1)} JT`; - if (value >= 1_000) - return `Rp ${(value / 1_000).toFixed(1)} RB`; - return `Rp ${value}`; - }} - series={[ - { - name: 'jumlah', - color: colors['blue-button'], - label: 'Jumlah', - }, - ]} - /> - ) : ( - Belum ada data untuk ditampilkan dalam grafik - )} - - - - - Jumlah - - - - - - + + + - + {/* Chart */} + + + {loading ? (
@@ -185,18 +129,7 @@ function Apbdes() { )} - - - + ) }