QC User & Admin Responsive : Menu Kesehatan - Ekonomi

This commit is contained in:
2025-10-03 10:17:06 +08:00
parent 8a6d8ed8db
commit f7fd9be255
55 changed files with 754 additions and 372 deletions

View File

@@ -59,7 +59,7 @@ function PelayananPendudukNonPermanent() {
radius="md"
onClick={() =>
router.push(
'/admin/desa/layanan/pelayanan_penduduk_non_permanent/edit'
`/admin/desa/layanan/pelayanan_penduduk_non_permanent/${data.id}`
)
}
>

View File

@@ -1,5 +1,6 @@
/* eslint-disable react-hooks/exhaustive-deps */
'use client'
import EditEditor from '@/app/admin/(dashboard)/_com/editEditor';
import stateLayananDesa from '@/app/admin/(dashboard)/_state/desa/layananDesa';
import colors from '@/con/colors';
@@ -8,6 +9,7 @@ import {
Button,
Group,
Paper,
Skeleton,
Stack,
TextInput,
Title,
@@ -21,66 +23,82 @@ import { useProxy } from 'valtio/utils';
function EditPelayananPerizinanBerusaha() {
const router = useRouter();
const params = useParams();
const statePerizinanBerusaha = useProxy(
stateLayananDesa.pelayananPerizinanBerusaha
);
const params = useParams<{ id: string }>();
const id = params?.id; // ini langsung string
const state = useProxy(stateLayananDesa.pelayananPerizinanBerusaha);
const [loading, setLoading] = useState(true);
const [formData, setFormData] = useState({
id: '',
name: '',
deskripsi: '',
link: '',
});
// load data pertama kali
// Load data detail
useEffect(() => {
const loadPelayananPerizinan = async () => {
const id = params?.id as string;
if (!id) return;
if (!id) {
toast.error("ID tidak valid");
return;
}
const loadData = async () => {
try {
const data = await statePerizinanBerusaha.update.load(id);
setLoading(true);
const data = await state.findById.load(id);
if (data) {
setFormData({
name: data.name || '',
deskripsi: data.deskripsi || '',
link: data.link || '',
id: data.id,
name: data.name || "",
deskripsi: data.deskripsi || "",
link: data.link || "",
});
} else {
toast.error("Data tidak ditemukan");
}
} catch (error) {
console.error('Error loading pelayanan perizinan berusaha:', error);
toast.error('Gagal memuat data pelayanan perizinan berusaha');
console.error("Error loading data:", error);
toast.error("Gagal memuat data");
} finally {
setLoading(false);
}
};
loadPelayananPerizinan();
}, [params?.id]);
loadData();
}, [id]);
const handleChange =
(field: keyof typeof formData) =>
(value: string) => {
setFormData((prev) => ({
...prev,
[field]: value,
}));
};
(value: string) => {
setFormData((prev) => ({
...prev,
[field]: value,
}));
};
const handleSubmit = async () => {
const { name, deskripsi, link } = formData;
if (statePerizinanBerusaha.findById.data) {
const updatedData = {
...statePerizinanBerusaha.findById.data,
name,
deskripsi,
link,
};
await statePerizinanBerusaha.update.update(updatedData);
try {
await state.update.update(formData);
router.push('/admin/desa/layanan/pelayanan_perizinan_berusaha');
} catch (error) {
console.error('Error updating pelayanan perizinan berusaha:', error);
toast.error('Terjadi kesalahan saat update data');
}
};
if (loading) {
return (
<Stack align="center" justify="center" py="xl">
<Skeleton height={800} radius="md" />
</Stack>
);
}
return (
<Box>
<Stack gap="xs">
{/* Header Section */}
{/* Header */}
<Group mb="md">
<Tooltip label="Kembali ke halaman sebelumnya" withArrow>
<Button
@@ -97,7 +115,7 @@ function EditPelayananPerizinanBerusaha() {
</Title>
</Group>
{/* Form Section */}
{/* Form */}
<Paper
w={{ base: '100%', md: '50%' }}
bg={colors['white-1']}
@@ -109,7 +127,6 @@ function EditPelayananPerizinanBerusaha() {
<Stack gap="xs">
<Title order={3}>Edit Pelayanan Perizinan Berusaha</Title>
{/* Nama Field */}
<TextInput
label="Judul"
placeholder="Masukkan judul"
@@ -118,7 +135,6 @@ function EditPelayananPerizinanBerusaha() {
required
/>
{/* Link Field */}
<TextInput
label="Link"
placeholder="Masukkan link terkait"
@@ -126,7 +142,6 @@ function EditPelayananPerizinanBerusaha() {
onChange={(e) => handleChange('link')(e.target.value)}
/>
{/* Deskripsi Field */}
<Box>
<Title order={6}>Deskripsi</Title>
<EditEditor
@@ -135,23 +150,20 @@ function EditPelayananPerizinanBerusaha() {
/>
</Box>
{/* Action Buttons */}
<Group>
<Button
bg={colors['blue-button']}
onClick={handleSubmit}
loading={statePerizinanBerusaha.update.loading}
loading={state.update.loading}
disabled={!formData.name}
>
{statePerizinanBerusaha.update.loading
? 'Menyimpan...'
: 'Simpan Perubahan'}
{state.update.loading ? 'Menyimpan...' : 'Simpan Perubahan'}
</Button>
<Button
variant="outline"
onClick={() => router.back()}
disabled={statePerizinanBerusaha.update.loading}
disabled={state.update.loading}
>
Batal
</Button>

View File

@@ -1,3 +1,4 @@
/* eslint-disable react-hooks/exhaustive-deps */
'use client'
import colors from '@/con/colors';
import {
@@ -19,35 +20,58 @@ import {
Tooltip,
} from '@mantine/core';
import { IconEdit } from '@tabler/icons-react';
import { useRouter } from 'next/navigation';
import { useState } from 'react';
import { useEffect, useState } from 'react';
import stateLayananDesa from '../../../_state/desa/layananDesa';
import { useProxy } from 'valtio/utils';
import { useShallowEffect } from '@mantine/hooks';
import { useRouter } from 'next/navigation';
function PerizinanBerusaha() {
const router = useRouter();
const pelayananPerizinanBerusaha = useProxy(
stateLayananDesa.pelayananPerizinanBerusaha
);
const [loading, setLoading] = useState(true);
const [error, setError] = useState('');
const [active, setActive] = useState(1);
const nextStep = () =>
setActive((current) => (current < 6 ? current + 1 : current));
const prevStep = () =>
setActive((current) => (current > 0 ? current - 1 : current));
useShallowEffect(() => {
pelayananPerizinanBerusaha.findById.load('1');
useEffect(() => {
const loadData = async () => {
try {
setLoading(true);
// You should get the ID from your router query or params
const id = '1'; // Replace with actual ID or get from URL params
await pelayananPerizinanBerusaha.findById.load(id);
} catch (err) {
setError('Gagal memuat data');
console.error('Error:', err);
} finally {
setLoading(false);
}
};
loadData();
}, []);
if (!pelayananPerizinanBerusaha.findById.data) {
if (loading) {
return (
<Stack align="center" justify="center" py="xl">
<Skeleton radius="md" height={800} />
<Skeleton height={800} radius="md" />
</Stack>
);
}
if (error || !pelayananPerizinanBerusaha.findById.data) {
return (
<Center h={200}>
<Text>{error || 'Data tidak ditemukan'}</Text>
</Center>
);
}
const data = pelayananPerizinanBerusaha.findById.data;
return (
@@ -69,7 +93,7 @@ function PerizinanBerusaha() {
radius="md"
onClick={() =>
router.push(
'/admin/desa/layanan/pelayanan_perizinan_berusaha/edit'
`/admin/desa/layanan/pelayanan_perizinan_berusaha/${data.id}`
)
}
>
@@ -183,3 +207,4 @@ function PerizinanBerusaha() {
}
export default PerizinanBerusaha;

View File

@@ -44,39 +44,37 @@ function EditSuratKeterangan() {
const [previewImage2, setPreviewImage2] = useState<string | null>(null);
// load data awal
useEffect(() => {
const loadSurat = async () => {
const id = params?.id as string;
if (!id) return;
useEffect(() => {
const loadSurat = async () => {
const id = params?.id as string;
if (!id) return;
try {
const data = await stateSurat.edit.load(id);
if (!data) return;
try {
const data = await stateSurat.edit.load(id);
if (data) {
// merge style -> isi hanya field kosong
setFormData((prev) => ({
...prev,
name: prev.name || data.name || '',
deskripsi: prev.deskripsi || data.deskripsi || '',
imageId: prev.imageId || data.imageId || '',
image2Id: prev.image2Id || data.image2Id || '',
...{
name: prev.name || data.name || "",
deskripsi: prev.deskripsi || data.deskripsi || "",
imageId: prev.imageId || data.imageId || "",
image2Id: prev.image2Id || data.image2Id || "",
},
}));
if (data.image?.link && !previewImage) {
setPreviewImage(data.image.link);
}
if (data.image2?.link && !previewImage2) {
setPreviewImage2(data.image2.link);
}
if (data.image?.link && !previewImage) setPreviewImage(data.image.link);
if (data.image2?.link && !previewImage2) setPreviewImage2(data.image2.link);
} catch (error) {
console.error("Error loading surat:", error);
toast.error("Gagal memuat data surat");
}
} catch (error) {
console.error("Error loading surat:", error);
toast.error("Gagal memuat data surat");
}
};
};
loadSurat();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [params?.id]);
loadSurat();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [params?.id]);
// handler untuk submit

View File

@@ -8,17 +8,15 @@ import {
Group,
Paper,
Stack,
Text,
TextInput,
Title,
Tooltip,
Tooltip
} from '@mantine/core';
import { IconArrowBack } from '@tabler/icons-react';
import { useParams, useRouter } from 'next/navigation';
import { useEffect, useState, useCallback } from 'react';
import { useCallback, useEffect, useState } from 'react';
import { toast } from 'react-toastify';
import { useProxy } from 'valtio/utils';
import EditEditor from '@/app/admin/(dashboard)/_com/editEditor';
function EditPelayananTelunjukSakti() {
const stateTelunjukDesa = useProxy(stateLayananDesa.pelayananTelunjukSaktiDesa);
@@ -111,21 +109,19 @@ function EditPelayananTelunjukSakti() {
required
/>
{/* Deskripsi pakai editor */}
<Box>
<Text fz="sm" fw="bold" mb={6}>
Deskripsi
</Text>
<EditEditor
value={formData.deskripsi}
onChange={(htmlContent) => handleChange('deskripsi', htmlContent)}
/>
</Box>
{/* Deskripsi */}
<TextInput
value={formData.deskripsi}
onChange={(e) => handleChange('deskripsi', e.target.value)}
label="Judul Link"
placeholder="Masukkan judul link"
required
/>
{/* Link */}
<TextInput
label="Link"
placeholder="Masukkan link terkait"
placeholder="Masukkan alamat link"
value={formData.link}
onChange={(e) => handleChange('link', e.target.value)}
/>

View File

@@ -82,8 +82,8 @@ function CreatePelayananTelunjukDesa() {
onChange={(val) => {
stateTelunjukDesa.create.form.deskripsi = val.target.value;
}}
label="Deskripsi"
placeholder="Masukkan deskripsi pelayanan"
label="Judul Link"
placeholder="Masukkan judul link"
required
/>