fix inputan edit menu: desa, ekonomi, inovasi, keamanan, kesehatan, landing-page, & lingkungan

This commit is contained in:
2025-09-30 21:41:26 +08:00
parent c2f1ab8179
commit 63054cedf0
67 changed files with 3056 additions and 2989 deletions

View File

@@ -1,6 +1,6 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
'use client'
/* eslint-disable react-hooks/exhaustive-deps */
'use client'
import PendapatanAsliDesa from '@/app/admin/(dashboard)/_state/ekonomi/PADesa';
import colors from '@/con/colors';
import {
@@ -29,13 +29,13 @@ function EditAPBDesa() {
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 || [],
tahun: '',
pendapatanIds: [] as string[],
belanjaIds: [] as string[],
pembiayaanIds: [] as string[],
});
// Load APB desa by id
// Load APB desa by id → hanya update formData, bukan global state
useEffect(() => {
const loadAPBdesa = async () => {
const id = params?.id as string;
@@ -45,7 +45,7 @@ function EditAPBDesa() {
const data = await apbState.update.load(id);
if (data) {
setFormData({
tahun: data.tahun || 0,
tahun: String(data.tahun || ''),
pendapatanIds: data.pendapatan?.map((p: any) => p.id) || [],
belanjaIds: data.belanja?.map((b: any) => b.id) || [],
pembiayaanIds: data.pembiayaan?.map((p: any) => p.id) || [],
@@ -60,8 +60,13 @@ function EditAPBDesa() {
loadAPBdesa();
}, [params?.id]);
const handleChange = (field: keyof typeof formData, value: any) => {
setFormData(prev => ({ ...prev, [field]: value }));
};
const handleSubmit = async () => {
try {
// update global state cuma pas submit
apbState.update.form = {
...apbState.update.form,
tahun: Number(formData.tahun),
@@ -111,10 +116,8 @@ function EditAPBDesa() {
{/* Tahun */}
<TextInput
type="number"
defaultValue={formData.tahun}
onChange={(e) =>
setFormData({ ...formData, tahun: e.target.value })
}
value={formData.tahun}
onChange={(e) => handleChange("tahun", e.target.value)}
label={<Text fz="sm" fw="bold">Tahun</Text>}
placeholder="Masukkan tahun anggaran"
required
@@ -123,23 +126,17 @@ function EditAPBDesa() {
{/* Selects */}
<SelectPendapatan
selectedIds={formData.pendapatanIds}
onSelectionChange={(ids) =>
setFormData({ ...formData, pendapatanIds: ids })
}
onSelectionChange={(ids) => handleChange("pendapatanIds", ids)}
/>
<SelectBelanja
selectedIds={formData.belanjaIds}
onSelectionChange={(ids) =>
setFormData({ ...formData, belanjaIds: ids })
}
onSelectionChange={(ids) => handleChange("belanjaIds", ids)}
/>
<SelectPembiayaan
selectedIds={formData.pembiayaanIds}
onSelectionChange={(ids) =>
setFormData({ ...formData, pembiayaanIds: ids })
}
onSelectionChange={(ids) => handleChange("pembiayaanIds", ids)}
/>
{/* Save Button */}
@@ -164,7 +161,13 @@ function EditAPBDesa() {
/* --- Sub Components --- */
function SelectPendapatan({ selectedIds, onSelectionChange }: { selectedIds: string[]; onSelectionChange: (ids: string[]) => void }) {
function SelectPendapatan({
selectedIds,
onSelectionChange,
}: {
selectedIds: string[];
onSelectionChange: (ids: string[]) => void;
}) {
const pendapatanState = useProxy(PendapatanAsliDesa.pendapatan);
useShallowEffect(() => {
@@ -192,7 +195,13 @@ function EditAPBDesa() {
);
}
function SelectBelanja({ selectedIds, onSelectionChange }: { selectedIds: string[]; onSelectionChange: (ids: string[]) => void }) {
function SelectBelanja({
selectedIds,
onSelectionChange,
}: {
selectedIds: string[];
onSelectionChange: (ids: string[]) => void;
}) {
const belanjaState = useProxy(PendapatanAsliDesa.belanja);
useShallowEffect(() => {
@@ -220,7 +229,13 @@ function EditAPBDesa() {
);
}
function SelectPembiayaan({ selectedIds, onSelectionChange }: { selectedIds: string[]; onSelectionChange: (ids: string[]) => void }) {
function SelectPembiayaan({
selectedIds,
onSelectionChange,
}: {
selectedIds: string[];
onSelectionChange: (ids: string[]) => void;
}) {
const pembiayaanState = useProxy(PendapatanAsliDesa.pembiayaan);
useShallowEffect(() => {

View File

@@ -1,5 +1,6 @@
/* eslint-disable react-hooks/exhaustive-deps */
'use client'
import PendapatanAsliDesa from '@/app/admin/(dashboard)/_state/ekonomi/PADesa';
import colors from '@/con/colors';
import {
@@ -24,12 +25,16 @@ function EditBelanja() {
const params = useParams();
const [formData, setFormData] = useState({
name: belanjaState.update.form.name || '',
value: belanjaState.update.form.value || '',
name: '',
value: '',
});
// format angka ke rupiah
const formatRupiah = (value: number | string) => {
const number = typeof value === 'number' ? value : Number(value.replace(/\D/g, ''));
const number =
typeof value === 'number'
? value
: Number(value.replace(/\D/g, '')) || 0;
return new Intl.NumberFormat('id-ID', {
style: 'currency',
currency: 'IDR',
@@ -37,8 +42,9 @@ function EditBelanja() {
}).format(number);
};
// buang semua simbol jadi angka murni
const unformatRupiah = (value: string) => {
return Number(value.replace(/\D/g, ''));
return Number(value.replace(/\D/g, '')) || 0;
};
useEffect(() => {
@@ -51,7 +57,7 @@ function EditBelanja() {
if (data) {
setFormData({
name: data.name || '',
value: data.value || '',
value: String(data.value || ''),
});
}
} catch (error) {
@@ -69,7 +75,7 @@ function EditBelanja() {
...belanjaState.update.form,
name: formData.name,
value: Number(formData.value),
}
};
await belanjaState.update.update();
toast.success("Jenis Belanja berhasil diperbarui!");
@@ -78,7 +84,7 @@ function EditBelanja() {
console.error("Error updating jenis belanja:", error);
toast.error("Terjadi kesalahan saat memperbarui jenis belanja");
}
}
};
return (
<Box px={{ base: 'sm', md: 'lg' }} py="md">
@@ -112,19 +118,21 @@ function EditBelanja() {
<TextInput
label="Nama Jenis Belanja"
placeholder="Masukkan nama jenis belanja"
defaultValue={formData.name}
onChange={(e) => setFormData({ ...formData, name: e.target.value })}
value={formData.name}
onChange={(e) =>
setFormData({ ...formData, name: e.target.value })
}
required
/>
<TextInput
label="Nilai"
placeholder="Masukkan nilai"
defaultValue={formatRupiah(formData.value)}
value={formData.value ? formatRupiah(formData.value) : ''}
onChange={(e) => {
const raw = e.currentTarget.value;
const cleanValue = unformatRupiah(raw);
setFormData({ ...formData, value: cleanValue });
setFormData({ ...formData, value: String(cleanValue) });
}}
required
/>

View File

@@ -24,12 +24,15 @@ function EditPembiayaan() {
const params = useParams();
const [formData, setFormData] = useState({
name: pembiayaanState.update.form.name || '',
value: pembiayaanState.update.form.value || '',
name: '',
value: '',
});
const formatRupiah = (value: number | string) => {
const number = typeof value === 'number' ? value : Number(value.toString().replace(/\D/g, ''));
const number =
typeof value === 'number'
? value
: Number(value.toString().replace(/\D/g, '')) || 0;
return new Intl.NumberFormat('id-ID', {
style: 'currency',
currency: 'IDR',
@@ -38,7 +41,7 @@ function EditPembiayaan() {
};
const unformatRupiah = (value: string) => {
return Number(value.replace(/\D/g, ''));
return Number(value.replace(/\D/g, '')) || 0;
};
useEffect(() => {
@@ -51,7 +54,7 @@ function EditPembiayaan() {
if (data) {
setFormData({
name: data.name || '',
value: data.value || '',
value: String(data.value || ''),
});
}
} catch (error) {
@@ -68,7 +71,7 @@ function EditPembiayaan() {
pembiayaanState.update.form = {
...pembiayaanState.update.form,
name: formData.name,
value: Number(formData.value),
value: unformatRupiah(formData.value),
};
await pembiayaanState.update.update();
@@ -82,7 +85,7 @@ function EditPembiayaan() {
return (
<Box px={{ base: 'sm', md: 'lg' }} py="md">
{/* Header dengan Back Button */}
{/* Header */}
<Group mb="md">
<Tooltip label="Kembali ke halaman sebelumnya" withArrow>
<Button
@@ -112,19 +115,21 @@ function EditPembiayaan() {
<TextInput
label="Nama Jenis Pembiayaan"
placeholder="Masukkan nama jenis pembiayaan"
defaultValue={formData.name}
onChange={(e) => setFormData({ ...formData, name: e.target.value })}
value={formData.name}
onChange={(e) =>
setFormData((prev) => ({ ...prev, name: e.target.value }))
}
required
/>
<TextInput
label="Nilai"
placeholder="Masukkan nilai"
defaultValue={formatRupiah(formData.value)}
value={formData.value ? formatRupiah(formData.value) : ''}
onChange={(e) => {
const raw = e.currentTarget.value;
const cleanValue = unformatRupiah(raw);
setFormData({ ...formData, value: cleanValue });
setFormData((prev) => ({ ...prev, value: String(cleanValue) }));
}}
required
/>

View File

@@ -24,12 +24,16 @@ function EditPendapatan() {
const params = useParams();
const [formData, setFormData] = useState({
name: pendapatanState.update.form.name || '',
value: pendapatanState.update.form.value || '',
name: '',
value: '',
});
// helper format
const formatRupiah = (value: number | string) => {
const number = typeof value === 'number' ? value : Number(value.toString().replace(/\D/g, ''));
const number = typeof value === 'number'
? value
: Number(value.toString().replace(/\D/g, ''));
return new Intl.NumberFormat('id-ID', {
style: 'currency',
currency: 'IDR',
@@ -39,6 +43,7 @@ function EditPendapatan() {
const unformatRupiah = (value: string) => Number(value.replace(/\D/g, ''));
// load data once
useEffect(() => {
const id = params?.id as string;
if (!id) return;
@@ -48,8 +53,8 @@ function EditPendapatan() {
const data = await pendapatanState.update.load(id);
if (data) {
setFormData({
name: data.name || '',
value: data.value || '',
name: data.name ?? '',
value: data.value?.toString() ?? '',
});
}
} catch (error) {
@@ -61,6 +66,13 @@ function EditPendapatan() {
loadPendapatan();
}, [params?.id]);
const handleChange = (field: string, value: string) => {
setFormData((prev) => ({
...prev,
[field]: value,
}));
};
const handleSubmit = async () => {
try {
pendapatanState.update.form = {
@@ -110,19 +122,19 @@ function EditPendapatan() {
<TextInput
label="Nama Jenis Pendapatan"
placeholder="Masukkan nama jenis pendapatan"
defaultValue={formData.name}
onChange={(e) => setFormData({ ...formData, name: e.target.value })}
value={formData.name}
onChange={(e) => handleChange('name', e.target.value)}
required
/>
<TextInput
label="Nilai"
placeholder="Masukkan nilai"
defaultValue={formatRupiah(formData.value)}
value={formData.value ? formatRupiah(formData.value) : ''}
onChange={(e) => {
const raw = e.currentTarget.value;
const cleanValue = unformatRupiah(raw);
setFormData({ ...formData, value: cleanValue });
const cleanValue = unformatRupiah(raw).toString();
handleChange('value', cleanValue);
}}
required
/>