API & UI Admin Menu Ekonomi, Submenu PADesa
This commit is contained in:
@@ -105,8 +105,22 @@ const ApbDesa = proxy({
|
|||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error("Gagal mengambil APB Desa");
|
throw new Error("Gagal mengambil APB Desa");
|
||||||
}
|
}
|
||||||
const data = await response.json();
|
const result = await response.json();
|
||||||
|
|
||||||
|
if (!result.success) {
|
||||||
|
throw new Error(result.message || "Gagal memuat APB Desa");
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = result.data;
|
||||||
|
|
||||||
this.id = id;
|
this.id = id;
|
||||||
|
this.form = {
|
||||||
|
tahun: data.tahun || 0,
|
||||||
|
pendapatanIds: data.pendapatan?.map((p: any) => p.id) || [],
|
||||||
|
belanjaIds: data.belanja?.map((b: any) => b.id) || [],
|
||||||
|
pembiayaanIds: data.pembiayaan?.map((p: any) => p.id) || [],
|
||||||
|
};
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error loading APB Desa:", error);
|
console.error("Error loading APB Desa:", error);
|
||||||
@@ -152,7 +166,7 @@ const ApbDesa = proxy({
|
|||||||
try {
|
try {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
`/api/ekonomi/pendapatanaslidesa/apbdesa/${id}`,
|
`/api/ekonomi/pendapatanaslidesa/apbdesa/del/${id}`,
|
||||||
{
|
{
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,234 @@
|
|||||||
import React from 'react';
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
|
'use client'
|
||||||
|
/* eslint-disable react-hooks/exhaustive-deps */
|
||||||
|
import PendapatanAsliDesa from '@/app/admin/(dashboard)/_state/ekonomi/PADesa';
|
||||||
|
import colors from '@/con/colors';
|
||||||
|
import { Box, Button, MultiSelect, Paper, Skeleton, Stack, Text, TextInput, Title } from '@mantine/core';
|
||||||
|
import { useShallowEffect } from '@mantine/hooks';
|
||||||
|
import { IconArrowBack } 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';
|
||||||
|
|
||||||
|
function EditAPBDesa() {
|
||||||
|
const apbState = useProxy(PendapatanAsliDesa.ApbDesa);
|
||||||
|
const router = useRouter();
|
||||||
|
const params = useParams();
|
||||||
|
|
||||||
|
const [formData, setFormData] = useState({
|
||||||
|
tahun: apbState.update.form.tahun || '',
|
||||||
|
pendapatanIds: apbState.update.form.pendapatanIds || [],
|
||||||
|
belanjaIds: apbState.update.form.belanjaIds || [],
|
||||||
|
pembiayaanIds: apbState.update.form.pembiayaanIds || [],
|
||||||
|
});
|
||||||
|
|
||||||
|
// Load APB desa by id saat pertama kali
|
||||||
|
useEffect(() => {
|
||||||
|
const loadAPBdesa = async () => {
|
||||||
|
const id = params?.id as string;
|
||||||
|
if (!id) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const data = await apbState.update.load(id);
|
||||||
|
if (data) {
|
||||||
|
setFormData({
|
||||||
|
tahun: data.tahun || 0,
|
||||||
|
pendapatanIds: data.pendapatan?.map((p: any) => p.id) || [],
|
||||||
|
belanjaIds: data.belanja?.map((b: any) => b.id) || [],
|
||||||
|
pembiayaanIds: data.pembiayaan?.map((p: any) => p.id) || [],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error loading APBdesa:", error);
|
||||||
|
toast.error("Gagal memuat data APBdesa");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
loadAPBdesa();
|
||||||
|
}, [params?.id]); // ✅ hapus beritaState dari dependency
|
||||||
|
|
||||||
|
const handleSubmit = async () => {
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Update global state with form data
|
||||||
|
apbState.update.form = {
|
||||||
|
...apbState.update.form,
|
||||||
|
tahun: Number(formData.tahun),
|
||||||
|
pendapatanIds: formData.pendapatanIds,
|
||||||
|
belanjaIds: formData.belanjaIds,
|
||||||
|
pembiayaanIds: formData.pembiayaanIds,
|
||||||
|
};
|
||||||
|
|
||||||
|
await apbState.update.update();
|
||||||
|
toast.success("APB Desa berhasil diperbarui!");
|
||||||
|
router.push("/admin/ekonomi/PADesa-pendapatan-asli-desa/apbdesa");
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error updating APBdesa:", error);
|
||||||
|
toast.error("Terjadi kesalahan saat memperbarui APBdesa");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
function Page() {
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<Box>
|
||||||
Page
|
<Box mb={10}>
|
||||||
</div>
|
<Button variant="subtle" onClick={() => router.back()}>
|
||||||
|
<IconArrowBack color={colors["blue-button"]} size={30} />
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
<Paper bg={"white"} p={"md"} w={{ base: "100%", md: "50%" }}>
|
||||||
|
<Stack gap={"xs"}>
|
||||||
|
<Title order={3}>Edit APB Desa</Title>
|
||||||
|
<TextInput
|
||||||
|
type='number'
|
||||||
|
value={formData.tahun}
|
||||||
|
onChange={(val) => {
|
||||||
|
setFormData({ ...formData, tahun: val.target.value });
|
||||||
|
}}
|
||||||
|
label={<Text fz={"sm"} fw={"bold"}>Tahun</Text>}
|
||||||
|
placeholder="masukkan tahun"
|
||||||
|
/>
|
||||||
|
<SelectPendapatan
|
||||||
|
selectedIds={formData.pendapatanIds}
|
||||||
|
onSelectionChange={(ids) => {
|
||||||
|
setFormData({ ...formData, pendapatanIds: ids });
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<SelectBelanja
|
||||||
|
selectedIds={formData.belanjaIds}
|
||||||
|
onSelectionChange={(ids) => {
|
||||||
|
setFormData({ ...formData, belanjaIds: ids });
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<SelectPembiayaan
|
||||||
|
selectedIds={formData.pembiayaanIds}
|
||||||
|
onSelectionChange={(ids) => {
|
||||||
|
setFormData({ ...formData, pembiayaanIds: ids });
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Button onClick={handleSubmit}>Simpan</Button>
|
||||||
|
</Stack>
|
||||||
|
</Paper>
|
||||||
|
</Box>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
/* Select Pendapatan */
|
||||||
|
interface SelectPendapatanProps {
|
||||||
|
selectedIds: string[];
|
||||||
|
onSelectionChange: (ids: string[]) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
function SelectPendapatan({
|
||||||
|
selectedIds = [],
|
||||||
|
onSelectionChange,
|
||||||
|
}: SelectPendapatanProps) {
|
||||||
|
const pendapatanState = useProxy(PendapatanAsliDesa.pendapatan);
|
||||||
|
|
||||||
|
useShallowEffect(() => {
|
||||||
|
pendapatanState.findMany.load().then(() => {
|
||||||
|
console.log("Pendapatan berhasil dimuat:", pendapatanState.findMany.data);
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
if (!pendapatanState.findMany.data) {
|
||||||
|
return <Skeleton height={38} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MultiSelect
|
||||||
|
label={<Text fz={"sm"} fw={"bold"}>Pendapatan</Text>}
|
||||||
|
data={pendapatanState.findMany.data.map(p => ({
|
||||||
|
value: p.id,
|
||||||
|
label: p.name
|
||||||
|
}))}
|
||||||
|
value={selectedIds}
|
||||||
|
onChange={onSelectionChange}
|
||||||
|
searchable
|
||||||
|
clearable
|
||||||
|
placeholder="Pilih pendapatan..."
|
||||||
|
nothingFoundMessage="Tidak ditemukan"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Select Belanja */
|
||||||
|
interface SelectBelanjaProps {
|
||||||
|
selectedIds: string[];
|
||||||
|
onSelectionChange: (ids: string[]) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
function SelectBelanja({
|
||||||
|
selectedIds = [],
|
||||||
|
onSelectionChange,
|
||||||
|
}: SelectBelanjaProps) {
|
||||||
|
const belanjaState = useProxy(PendapatanAsliDesa.belanja);
|
||||||
|
|
||||||
|
useShallowEffect(() => {
|
||||||
|
belanjaState.findMany.load().then(() => {
|
||||||
|
console.log("Belanja berhasil dimuat:", belanjaState.findMany.data);
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
if (!belanjaState.findMany.data) {
|
||||||
|
return <Skeleton height={38} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MultiSelect
|
||||||
|
label={<Text fz={"sm"} fw={"bold"}>Belanja</Text>}
|
||||||
|
data={belanjaState.findMany.data.map(b => ({
|
||||||
|
value: b.id,
|
||||||
|
label: b.name
|
||||||
|
}))}
|
||||||
|
value={selectedIds}
|
||||||
|
onChange={onSelectionChange}
|
||||||
|
searchable
|
||||||
|
clearable
|
||||||
|
placeholder="Pilih belanja..."
|
||||||
|
nothingFoundMessage="Tidak ditemukan"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Select Pembiayaan */
|
||||||
|
interface SelectPembiayaanProps {
|
||||||
|
selectedIds: string[];
|
||||||
|
onSelectionChange: (ids: string[]) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
function SelectPembiayaan({
|
||||||
|
selectedIds = [],
|
||||||
|
onSelectionChange,
|
||||||
|
}: SelectPembiayaanProps) {
|
||||||
|
const pembiayaanState = useProxy(PendapatanAsliDesa.pembiayaan);
|
||||||
|
|
||||||
|
useShallowEffect(() => {
|
||||||
|
pembiayaanState.findMany.load().then(() => {
|
||||||
|
console.log("Pembiayaan berhasil dimuat:", pembiayaanState.findMany.data);
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
if (!pembiayaanState.findMany.data) {
|
||||||
|
return <Skeleton height={38} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MultiSelect
|
||||||
|
label={<Text fz={"sm"} fw={"bold"}>Pembiayaan</Text>}
|
||||||
|
data={pembiayaanState.findMany.data.map(b => ({
|
||||||
|
value: b.id,
|
||||||
|
label: b.name
|
||||||
|
}))}
|
||||||
|
value={selectedIds}
|
||||||
|
onChange={onSelectionChange}
|
||||||
|
searchable
|
||||||
|
clearable
|
||||||
|
placeholder="Pilih pembiayaan..."
|
||||||
|
nothingFoundMessage="Tidak ditemukan"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Page;
|
export default EditAPBDesa;
|
||||||
|
|||||||
@@ -6,36 +6,36 @@ import apbDesaDelete from "./del";
|
|||||||
import apbDesaUpdate from "./updt";
|
import apbDesaUpdate from "./updt";
|
||||||
|
|
||||||
const APBDesa = new Elysia({
|
const APBDesa = new Elysia({
|
||||||
prefix: "/apbdesa",
|
prefix: "/apbdesa",
|
||||||
tags: ["Ekonomi/Pendapatan Asli Desa/APB Desa"],
|
tags: ["Ekonomi/Pendapatan Asli Desa/APB Desa"],
|
||||||
})
|
})
|
||||||
.get("/find-many", apbDesaFindMany)
|
.get("/find-many", apbDesaFindMany)
|
||||||
.get("/:id", async (context) => {
|
.get("/:id", async (context) => {
|
||||||
const response = await apbDesaFindUnique(new Request(context.request));
|
const response = await apbDesaFindUnique(new Request(context.request));
|
||||||
return response;
|
return response;
|
||||||
})
|
})
|
||||||
.post("/create", apbDesaCreate, {
|
.post("/create", apbDesaCreate, {
|
||||||
body: t.Object({
|
body: t.Object({
|
||||||
|
tahun: t.Number(),
|
||||||
|
pendapatanIds: t.Array(t.String()),
|
||||||
|
belanjaIds: t.Array(t.String()),
|
||||||
|
pembiayaanIds: t.Array(t.String()),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
.delete("/del/:id", apbDesaDelete)
|
||||||
|
.put(
|
||||||
|
"/:id",
|
||||||
|
async (context) => {
|
||||||
|
const response = await apbDesaUpdate(context);
|
||||||
|
return response;
|
||||||
|
},
|
||||||
|
{
|
||||||
|
body: t.Object({
|
||||||
tahun: t.Number(),
|
tahun: t.Number(),
|
||||||
pendapatanIds: t.Array(t.String()),
|
pendapatanIds: t.Array(t.String()),
|
||||||
belanjaIds: t.Array(t.String()),
|
belanjaIds: t.Array(t.String()),
|
||||||
pembiayaanIds: t.Array(t.String()),
|
pembiayaanIds: t.Array(t.String()),
|
||||||
}),
|
}),
|
||||||
})
|
|
||||||
.delete("/delete/:id", apbDesaDelete)
|
|
||||||
.put(
|
|
||||||
"/:id",
|
|
||||||
async (context) => {
|
|
||||||
const response = await apbDesaUpdate(context);
|
|
||||||
return response;
|
|
||||||
},
|
|
||||||
{
|
|
||||||
body: t.Object({
|
|
||||||
tahun: t.Number(),
|
|
||||||
pendapatanIds: t.Array(t.String()),
|
|
||||||
belanjaIds: t.Array(t.String()),
|
|
||||||
pembiayaanIds: t.Array(t.String()),
|
|
||||||
}),
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
export default APBDesa;
|
export default APBDesa;
|
||||||
|
|||||||
@@ -41,18 +41,19 @@ export default async function apbDesaUpdate(context: Context) {
|
|||||||
const updated = await prisma.apbDesa.update({
|
const updated = await prisma.apbDesa.update({
|
||||||
where: { id },
|
where: { id },
|
||||||
data: {
|
data: {
|
||||||
tahun,
|
tahun,
|
||||||
pendapatan: {
|
pendapatan: {
|
||||||
connect: pendapatanIds.map((id) => ({ id })),
|
set: pendapatanIds.map((id) => ({ id })),
|
||||||
},
|
},
|
||||||
belanja: {
|
belanja: {
|
||||||
connect: belanjaIds.map((id) => ({ id })),
|
set: belanjaIds.map((id) => ({ id })),
|
||||||
},
|
},
|
||||||
pembiayaan: {
|
pembiayaan: {
|
||||||
connect: pembiayaanIds.map((id) => ({ id })),
|
set: pembiayaanIds.map((id) => ({ id })),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
message: "Success update APB Desa",
|
message: "Success update APB Desa",
|
||||||
|
|||||||
Reference in New Issue
Block a user