Compare commits

...

18 Commits

Author SHA1 Message Date
a8d3a3a9ff fix: pelayanan surat
Deskripsi:
- mandatory pada form tambah pelayanan surat
- mandatory pada form update pelayanan surat

No Issues
2026-01-20 17:15:16 +08:00
f86703e7d1 rev: button cancel
Deskripsi:
- tambah button clear pada form file tambah pengajuan surat
- tambah button clear pada form file update data pengajuan surat

NO Issues
2026-01-20 10:48:37 +08:00
d8bb33cc93 Merge pull request 'amalia/15-jan-26' (#112) from amalia/15-jan-26 into main
Reviewed-on: http://wibugit.wibudev.com/wibu/jenna-mcp/pulls/112
2026-01-15 14:33:16 +08:00
5807e98069 fix: tambah pengajuan surat pengantar skck
Deskripsi:
- link nya

No Issues
2026-01-15 14:32:28 +08:00
59b4f1d73f fix: surat keterangan kelahiran
Deskripsi:
- update value tanggal_lahir_ayah

No Issues
2026-01-15 14:19:05 +08:00
8bd552ac22 fix: pelayanan surat
Deskripsi:
- link surat

NO Issues
2026-01-15 14:09:32 +08:00
5d48d06513 Merge pull request 'fix : error surat' (#111) from amalia/15-jan-26 into main
Reviewed-on: http://wibugit.wibudev.com/wibu/jenna-mcp/pulls/111
2026-01-15 11:54:25 +08:00
3da163ea1d fix : error surat 2026-01-15 11:53:10 +08:00
57e4f34eb6 Merge pull request 'amalia/14-jan-26' (#110) from amalia/14-jan-26 into main
Reviewed-on: http://wibugit.wibudev.com/wibu/jenna-mcp/pulls/110
2026-01-14 17:43:11 +08:00
3348cbe8e3 fix: pelayanan surat
Deskripsi:
- pelayanan surat

No Issues
2026-01-14 17:41:27 +08:00
727984a076 fix: update data pengajuan surat
Deskripsi:
- loading saat melakukan pencarian
- disable select dan input date saat status selesai

No Issues
2026-01-14 15:58:51 +08:00
a7a0ad7e37 Merge pull request 'amalia/13-jan-26' (#109) from amalia/13-jan-26 into main
Reviewed-on: http://wibugit.wibudev.com/wibu/jenna-mcp/pulls/109
2026-01-13 17:18:01 +08:00
9fed41cbe8 fix: testing surat 2026-01-13 17:10:59 +08:00
fc387fe8e6 fix: menu setting
deskiripsi:
- navigate
- list length

No Issues
2026-01-13 15:38:29 +08:00
80df579499 qc: nomer 2 dan 4
Deskripsi:
- button back
- breadcrumb
- active menu

No Issues
2026-01-13 15:10:08 +08:00
5bbbc15c27 Merge pull request 'fix: qc' (#108) from amalia/12-jan-26 into main
Reviewed-on: http://wibugit.wibudev.com/wibu/jenna-mcp/pulls/108
2026-01-12 17:47:04 +08:00
82765f6ef0 fix: qc
Deskripsi:
- breadcumbs
- back
- active menu

nb: blm selesai

No Issues
2026-01-12 17:43:04 +08:00
e8b5720118 Merge pull request 'amalia/09-jan-26' (#107) from amalia/09-jan-26 into main
Reviewed-on: http://wibugit.wibudev.com/wibu/jenna-mcp/pulls/107
2026-01-09 17:23:26 +08:00
14 changed files with 552 additions and 418 deletions

View File

@@ -0,0 +1,44 @@
import { ActionIcon, Anchor, Breadcrumbs, Card, Group } from "@mantine/core";
import { IconChevronLeft } from "@tabler/icons-react";
import { useNavigate } from "react-router-dom";
export default function BreadCrumbs({ dataLink, back, linkBack }: { dataLink: { title: string, link: string, active: boolean }[], back?: boolean, linkBack?: string }) {
const navigate = useNavigate();
return (
<Card
radius="md"
p="sm"
withBorder
style={{
background:
"linear-gradient(145deg, rgba(25,25,25,0.95), rgba(45,45,45,0.85))",
borderColor: "rgba(100,100,100,0.2)",
boxShadow: "0 0 20px rgba(0,255,200,0.08)",
}}
>
<Group>
{
back &&
<ActionIcon variant="outline" aria-label="Settings" radius={"lg"} onClick={() => window.history.back()}>
<IconChevronLeft size={20} stroke={1.5} />
</ActionIcon>
}
<Breadcrumbs>
{
dataLink.map((item, index) => (
<Anchor
c={item.active ? "gray.0" : "gray.5"}
onClick={() => item.active || item.link == "#" ? null : navigate(item.link)}
key={index}
>
{item.title}
</Anchor>
))
}
</Breadcrumbs>
</Group>
</Card>
)
}

View File

@@ -207,7 +207,7 @@ export default function DesaSetting({
</Table.Tr> </Table.Tr>
</Table.Thead> </Table.Thead>
<Table.Tbody> <Table.Tbody>
{list?.map((v: any) => ( {list.length > 0 && list?.map((v: any) => (
<Table.Tr key={v.id}> <Table.Tr key={v.id}>
<Table.Td>{v.name}</Table.Td> <Table.Td>{v.name}</Table.Td>
<Table.Td> <Table.Td>

View File

@@ -4,19 +4,17 @@ import {
Button, Button,
Divider, Divider,
Flex, Flex,
Grid,
Group, Group,
Input,
List, List,
Modal, Modal,
Stack, Stack,
Table, Table,
Text, Text,
Title, Title,
Tooltip, Tooltip
} from "@mantine/core"; } from "@mantine/core";
import { useDisclosure, useShallowEffect } from "@mantine/hooks"; import { useDisclosure, useShallowEffect } from "@mantine/hooks";
import { IconEdit, IconEye, IconPlus, IconTrash } from "@tabler/icons-react"; import { IconEye, IconTrash } from "@tabler/icons-react";
import type { JsonValue } from "generated/prisma/runtime/library"; import type { JsonValue } from "generated/prisma/runtime/library";
import { useState } from "react"; import { useState } from "react";
import useSWR from "swr"; import useSWR from "swr";
@@ -625,7 +623,7 @@ export default function KategoriPelayananSurat({
</Table.Tr> </Table.Tr>
</Table.Thead> </Table.Thead>
<Table.Tbody> <Table.Tbody>
{list?.map((v: any) => ( {list.length > 0 && list?.map((v: any) => (
<Table.Tr key={v.id}> <Table.Tr key={v.id}>
<Table.Td>{v.name}</Table.Td> <Table.Td>{v.name}</Table.Td>
<Table.Td> <Table.Td>

View File

@@ -1,5 +1,5 @@
import apiFetch from "@/lib/apiFetch"; import apiFetch from "@/lib/apiFetch";
import { Flex, Loader, Modal, Text } from "@mantine/core"; import { Flex, Modal, Progress, Stack, Text } from "@mantine/core";
import { useShallowEffect } from "@mantine/hooks"; import { useShallowEffect } from "@mantine/hooks";
import html2canvas from "html2canvas"; import html2canvas from "html2canvas";
import jsPDF from "jspdf"; import jsPDF from "jspdf";
@@ -23,7 +23,7 @@ export default function ModalSurat({
surat, surat,
}: { }: {
open: boolean; open: boolean;
onClose: (val: any) => void; onClose: (val: { success: boolean, data: string }) => void;
surat: string; surat: string;
}) { }) {
const A4Style = { const A4Style = {
@@ -35,7 +35,7 @@ export default function ModalSurat({
fontSize: "14px", fontSize: "14px",
fontFamily: "Times New Roman", fontFamily: "Times New Roman",
}; };
const [uploading, setUploading] = useState<"Menyiapkan" | "Mengupload" | "Selesai">("Menyiapkan") const [uploading, setUploading] = useState<{ text: "Menyiapkan" | "Mengupload" | "Selesai" | "Gagal", value: number }>({ text: "Menyiapkan", value: 10 })
const hiddenRef = useRef<any>(null); const hiddenRef = useRef<any>(null);
const { data, mutate, isLoading } = useSWR("surat", () => const { data, mutate, isLoading } = useSWR("surat", () =>
apiFetch.api.surat.detail.get({ apiFetch.api.surat.detail.get({
@@ -45,6 +45,7 @@ export default function ModalSurat({
}), }),
); );
useShallowEffect(() => { useShallowEffect(() => {
mutate(); mutate();
}, []); }, []);
@@ -52,7 +53,7 @@ export default function ModalSurat({
const uploadPdf = async () => { const uploadPdf = async () => {
try { try {
if (data && data.data && data.data.surat && (data.data.surat.file == "" || data.data.surat.file == null)) { if (data && data.data && data.data.surat && (data.data.surat.file == "" || data.data.surat.file == null)) {
setUploading("Mengupload"); setUploading({ text: "Mengupload", value: 75 });
const element = hiddenRef.current; const element = hiddenRef.current;
const canvas = await html2canvas(element, { const canvas = await html2canvas(element, {
scale: 2, scale: 2,
@@ -95,9 +96,21 @@ export default function ModalSurat({
filename: resImg.data?.filename!, filename: resImg.data?.filename!,
}); });
setUploading("Selesai"); if (resUpdate?.data?.success) {
setUploading({ text: "Selesai", value: 100 });
setTimeout(() => {
onClose({ success: true, data: resUpdate.data?.link });
}, 1000)
} else {
setUploading({ text: "Gagal", value: 100 });
setTimeout(() => {
onClose({ success: false, data: "" });
}, 1000)
}
} else {
setUploading({ text: "Gagal", value: 100 });
setTimeout(() => { setTimeout(() => {
onClose(resUpdate.data?.link); onClose({ success: false, data: "" });
}, 1000) }, 1000)
} }
@@ -110,7 +123,7 @@ export default function ModalSurat({
if (open) { if (open) {
setTimeout(() => { setTimeout(() => {
uploadPdf(); uploadPdf();
}, 5000); }, 3000);
} }
}, [surat, open]); }, [surat, open]);
@@ -136,14 +149,24 @@ export default function ModalSurat({
}, },
}} }}
title={ title={
<Flex justify="space-between" align="center" w="100%"> <>
<div style={{ fontSize: 18, fontWeight: 600 }}>Preview Surat</div> <Flex justify="space-between" align="center" w="100%">
<div style={{ fontSize: 18, fontWeight: 600 }}>Preview Surat</div>
<Flex gap={8} align="center"> {/* <Flex gap={8} align="center">
<Loader color="blue" size="xs" /> <Loader color="blue" size="xs" />
<Text size="sm">{uploading}</Text> <Text size="sm">{uploading.text}</Text>
</Flex> */}
</Flex> </Flex>
</Flex> <Stack
align="stretch"
justify="center"
gap="xs"
>
<Text size="sm" ta="center">{uploading.text} - Harap menunggu sampai selesai</Text>
<Progress radius="md" value={uploading.value} animated size="lg" />
</Stack>
</>
} }
> >
<div ref={hiddenRef} style={A4Style}> <div ref={hiddenRef} style={A4Style}>

View File

@@ -7,7 +7,7 @@ export default function SKKelahiran({ data }: { data: any }) {
const getValue = (jenis: string) => const getValue = (jenis: string) =>
_.upperFirst( _.upperFirst(
data.surat.dataText.find((item: any) => item.jenis === jenis)?.value || data.surat.dataText.find((item: any) => item.jenis === jenis)?.value ||
"", "",
); );
const loadImage = async () => { const loadImage = async () => {
@@ -161,7 +161,7 @@ export default function SKKelahiran({ data }: { data: any }) {
<tr> <tr>
<td>Tempat & Tanggal Lahir</td> <td>Tempat & Tanggal Lahir</td>
<td>:</td> <td>:</td>
<td>{`${getValue("tempat_lahir_ayah")}, ${"tanggal_lahir_ayah"}`}</td> <td>{`${getValue("tempat_lahir_ayah")}, ${getValue("tanggal_lahir_ayah")}`}</td>
</tr> </tr>
<tr> <tr>
<td>Pekerjaan</td> <td>Pekerjaan</td>

View File

@@ -8,472 +8,377 @@ export const categoryPelayananSurat = [
{ {
key: "pengantar_kelian", key: "pengantar_kelian",
name: "Pengantar Kelian", name: "Pengantar Kelian",
desc: "Surat Pengantar Kelian Banjar Dinas di Wilayah Masing-masing" desc: "Surat Pengantar Kelian Banjar Dinas di Wilayah Masing-masing",
required: true
}, },
{ {
key: "ktp_kk", key: "ktp_kk",
name: "KTP / KK", name: "KTP / KK",
desc: "Fotokopi KTP atau Kartu Keluarga" desc: "Fotokopi KTP atau Kartu Keluarga",
required: true
}, },
{ {
key: "dokumen_beda", key: "dokumen_beda",
name: "Dokumen Pendukung", name: "Dokumen Pendukung",
desc: "Fotokopi dokumen yang terdapat perbedaan biodata (ijazah, sertifikat, dll)" desc: "Fotokopi dokumen yang terdapat perbedaan biodata (ijazah, sertifikat, dll)",
required: true
} }
], ],
dataText: [], dataText: [],
dataPelengkap: [ dataPelengkap: [
{ key: "nik", name: "NIK", desc: "Nomor Induk Kependudukan", type: "number" }, { key: "nik", name: "NIK", desc: "Nomor Induk Kependudukan", type: "number", required: true },
{ key: "nama", name: "Nama Lengkap", desc: "Nama sesuai KTP", type: "text" }, { key: "nama", name: "Nama Lengkap", desc: "Nama sesuai KTP", type: "text", required: true },
{ key: "tempat_lahir", name: "Tempat Lahir", desc: "Tempat lahir pemohon", type: "text" }, { key: "tempat_lahir", name: "Tempat Lahir", desc: "Tempat lahir pemohon", type: "text", required: true },
{ key: "tanggal_lahir", name: "Tanggal Lahir", desc: "Tanggal lahir pemohon", type: "date" }, { key: "tanggal_lahir", name: "Tanggal Lahir", desc: "Tanggal lahir pemohon", type: "date", required: true },
{ {
key: "jenis_kelamin", key: "jenis_kelamin",
name: "Jenis Kelamin", name: "Jenis Kelamin",
desc: "Jenis kelamin pemohon", desc: "Jenis kelamin pemohon",
type: "enum", type: "enum",
options: enumJenisKelamin options: enumJenisKelamin,
required: true
}, },
{ key: "alamat", name: "Alamat", desc: "Alamat lengkap tempat tinggal", type: "text" }, { key: "alamat", name: "Alamat", desc: "Alamat lengkap tempat tinggal", type: "text", required: true },
{ key: "pekerjaan", name: "Pekerjaan", desc: "Pekerjaan pemohon", type: "text" }, { key: "pekerjaan", name: "Pekerjaan", desc: "Pekerjaan pemohon", type: "text", required: true },
{ {
key: "dokumen", key: "dokumen",
name: "Nama Dokumen", name: "Nama Dokumen",
desc: "Jenis dokumen yang mengalami perbedaan biodata (cth : ijazah, sertifikat, dll)", desc: "Jenis dokumen yang mengalami perbedaan biodata",
type: "text" type: "text",
required: true
}, },
{ {
key: "data_dokumen", key: "data_dokumen",
name: "Data Dokumen", name: "Data Dokumen",
desc: "Data dokumen yg berbeda (cth : nama, tempat lahir, tanggal lahir, jenis kelamin, alamat, pekerjaan)", desc: "Data dokumen yg berbeda",
type: "text" type: "text",
required: true
}, },
{ { key: "dokumen_a", name: "Data pada Dokumen A", desc: "Data biodata pada dokumen pertama", type: "text", required: true },
key: "dokumen_a", { key: "dokumen_b", name: "Data pada Dokumen B", desc: "Data biodata pada dokumen kedua", type: "text", required: true }
name: "Data pada Dokumen A",
desc: "Data biodata yang tertulis pada dokumen pertama",
type: "text"
},
{
key: "dokumen_b",
name: "Data pada Dokumen B",
desc: "Data biodata yang tertulis pada dokumen kedua",
type: "text"
}
] ]
}, },
{ {
id: "skbelumkawin", id: "skbelumkawin",
name: "Surat Keterangan Belum Kawin", name: "Surat Keterangan Belum Kawin",
syaratDokumen: [ syaratDokumen: [
{ { key: "pengantar_kelian", name: "Pengantar Kelian", desc: "Surat Pengantar Kelian Banjar Dinas", required: true },
key: "pengantar_kelian", { key: "ktp_kk", name: "KTP / KK", desc: "Fotokopi KTP atau Kartu Keluarga", required: true },
name: "Pengantar Kelian", { key: "akta_cerai", name: "Akta Cerai", desc: "Fotokopi akta cerai (jika berstatus janda/duda)", required: false }
desc: "Surat Pengantar Kelian Banjar Dinas"
},
{
key: "ktp_kk",
name: "KTP / KK",
desc: "Fotokopi KTP atau Kartu Keluarga"
},
{
key: "akta_cerai",
name: "Akta Cerai",
desc: "Fotokopi akta cerai (jika berstatus janda/duda)"
}
], ],
dataText: [], dataText: [],
dataPelengkap: [ dataPelengkap: [
{ key: "nik", name: "NIK", desc: "Nomor Induk Kependudukan", type: "number" }, { key: "nik", name: "NIK", desc: "Nomor Induk Kependudukan", type: "number", required: true },
{ key: "nama", name: "Nama Lengkap", desc: "Nama sesuai KTP", type: "text" }, { key: "nama", name: "Nama Lengkap", desc: "Nama sesuai KTP", type: "text", required: true },
{ key: "tempat_lahir", name: "Tempat Lahir", desc: "Tempat lahir pemohon", type: "text" }, { key: "tempat_lahir", name: "Tempat Lahir", desc: "Tempat lahir pemohon", type: "text", required: true },
{ key: "tanggal_lahir", name: "Tanggal Lahir", desc: "Tanggal lahir pemohon", type: "date" }, { key: "tanggal_lahir", name: "Tanggal Lahir", desc: "Tanggal lahir pemohon", type: "date", required: true },
{ {
key: "jenis_kelamin", key: "jenis_kelamin",
name: "Jenis Kelamin", name: "Jenis Kelamin",
desc: "Jenis kelamin pemohon", desc: "Jenis kelamin pemohon",
type: "enum", type: "enum",
options: enumJenisKelamin options: enumJenisKelamin,
required: true
}, },
{ key: "alamat", name: "Alamat", desc: "Alamat tempat tinggal", type: "text" }, { key: "alamat", name: "Alamat", desc: "Alamat tempat tinggal", type: "text", required: true },
{ {
key: "agama", key: "agama",
name: "Agama", name: "Agama",
desc: "Agama pemohon", desc: "Agama pemohon",
type: "enum", type: "enum",
options: enumAgama options: enumAgama,
required: true
}, },
{ key: "pekerjaan", name: "Pekerjaan", desc: "Pekerjaan pemohon", type: "text" } { key: "pekerjaan", name: "Pekerjaan", desc: "Pekerjaan pemohon", type: "text", required: true }
] ]
}, },
{ {
id: "skdomisiliorganisasi", id: "skdomisiliorganisasi",
name: "Surat Keterangan Domisili Organisasi", name: "Surat Keterangan Domisili Organisasi",
syaratDokumen: [ syaratDokumen: [
{ { key: "pengantar_kelian", name: "Pengantar Kelian", desc: "Surat Pengantar Kelian Banjar Dinas", required: true },
key: "pengantar_kelian", { key: "skt_organisasi", name: "SKT Organisasi", desc: "Fotokopi SKT Organisasi", required: true },
name: "Pengantar Kelian", { key: "susunan_pengurus", name: "Susunan Pengurus", desc: "Susunan pengurus organisasi", required: true }
desc: "Surat Pengantar Kelian Banjar Dinas"
},
{
key: "skt_organisasi",
name: "SKT Organisasi",
desc: "Fotokopi SKT Organisasi atau pengukuhan kelompok"
},
{
key: "susunan_pengurus",
name: "Susunan Pengurus",
desc: "Susunan pengurus lengkap dengan kop organisasi"
}
], ],
dataText: [], dataText: [],
dataPelengkap: [ dataPelengkap: [
{ key: "nama_organisasi", name: "Nama Organisasi", desc: "Nama resmi organisasi", type: "text" }, { key: "nama_organisasi", name: "Nama Organisasi", desc: "Nama resmi organisasi", type: "text", required: true },
{ key: "jenis_organisasi", name: "Jenis Organisasi", desc: "Jenis atau bentuk organisasi", type: "text" }, { key: "jenis_organisasi", name: "Jenis Organisasi", desc: "Jenis organisasi", type: "text", required: true },
{ key: "alamat_organisasi", name: "Alamat Organisasi", desc: "Alamat sekretariat organisasi", type: "text" }, { key: "alamat_organisasi", name: "Alamat Organisasi", desc: "Alamat sekretariat", type: "text", required: true },
{ key: "no_telepon", name: "Nomor Telepon", desc: "Nomor telepon organisasi", type: "text" }, { key: "no_telepon", name: "Nomor Telepon", desc: "Nomor telepon organisasi", type: "text", required: true },
{ key: "nama_pimpinan", name: "Nama Pimpinan", desc: "Nama pimpinan organisasi", type: "text" }, { key: "nama_pimpinan", name: "Nama Pimpinan", desc: "Nama pimpinan", type: "text", required: true },
{ key: "keperluan", name: "Keperluan", desc: "Keperluan pembuatan surat", type: "text" } { key: "keperluan", name: "Keperluan", desc: "Keperluan pembuatan surat", type: "text", required: true }
] ]
}, },
{ {
id: "skkelahiran", id: "skkelahiran",
name: "Surat Keterangan Kelahiran", name: "Surat Keterangan Kelahiran",
syaratDokumen: [ syaratDokumen: [
{ { key: "pengantar_kelian", name: "Pengantar Kelian", desc: "Surat Pengantar Kelian Banjar Dinas", required: true },
key: "pengantar_kelian", { key: "surat_lahir", name: "Surat Keterangan Lahir", desc: "Surat keterangan lahir dari bidan/dokter (jika ada)", required: false }
name: "Pengantar Kelian",
desc: "Surat Pengantar Kelian Banjar Dinas"
},
{
key: "surat_lahir",
name: "Surat Keterangan Lahir",
desc: "Surat keterangan lahir dari bidan/dokter (jika ada)"
}
], ],
dataText: [], dataText: [],
dataPelengkap: [ dataPelengkap: [
{ key: "nama_anak", name: "Nama Anak", desc: "Nama bayi/anak", type: "text" }, { key: "nama_anak", name: "Nama Anak", desc: "Nama bayi/anak", type: "text", required: true },
{ key: "tanggal_lahir_anak", name: "Tanggal Lahir Anak", desc: "Tanggal lahir anak", type: "date" }, { key: "tanggal_lahir_anak", name: "Tanggal Lahir Anak", desc: "Tanggal lahir anak", type: "date", required: true },
{ key: "pukul_lahir", name: "Pukul Lahir", desc: "Waktu kelahiran anak", type: "text" }, { key: "pukul_lahir", name: "Pukul Lahir", desc: "Waktu kelahiran", type: "text", required: true },
{ key: "tempat_lahir", name: "Tempat Lahir", desc: "Tempat kelahiran anak", type: "text" }, { key: "tempat_lahir", name: "Tempat Lahir", desc: "Tempat kelahiran", type: "text", required: true },
{ {
key: "jenis_kelamin", key: "jenis_kelamin",
name: "Jenis Kelamin Anak", name: "Jenis Kelamin Anak",
desc: "Jenis kelamin anak", desc: "Jenis kelamin anak",
type: "enum", type: "enum",
options: enumJenisKelamin options: enumJenisKelamin,
required: true
}, },
{ key: "anak_ke", name: "Anak Ke-", desc: "Urutan kelahiran anak", type: "number" }, { key: "anak_ke", name: "Anak Ke-", desc: "Urutan kelahiran", type: "number", required: true },
{ key: "nik_ibu", name: "NIK Ibu", desc: "NIK ibu kandung", type: "number" }, { key: "nik_ibu", name: "NIK Ibu", desc: "NIK ibu kandung", type: "number", required: true },
{ key: "nama_ibu", name: "Nama Ibu", desc: "Nama lengkap ibu", type: "text" }, { key: "nama_ibu", name: "Nama Ibu", desc: "Nama ibu kandung", type: "text", required: true },
{ key: "tempat_lahir_ibu", name: "Tempat Lahir Ibu", desc: "Tempat lahir ibu kandung", type: "text" }, { key: "tempat_lahir_ibu", name: "Tempat Lahir Ibu", desc: "Tempat lahir ibu", type: "text", required: true },
{ key: "tanggal_lahir_ibu", name: "Tanggal Lahir Ibu", desc: "Tanggal lahir ibu kandung", type: "date" }, { key: "tanggal_lahir_ibu", name: "Tanggal Lahir Ibu", desc: "Tanggal lahir ibu", type: "date", required: true },
{ key: "pekerjaan_ibu", name: "Pekerjaan Ibu", desc: "Pekerjaan ibu kandung", type: "text" }, { key: "pekerjaan_ibu", name: "Pekerjaan Ibu", desc: "Pekerjaan ibu", type: "text", required: true },
{ key: "alamat_ibu", name: "Alamat Ibu", desc: "Alamat ibu kandung", type: "text" }, { key: "alamat_ibu", name: "Alamat Ibu", desc: "Alamat ibu", type: "text", required: true },
{ key: "nama_ayah", name: "Nama Ayah", desc: "Nama lengkap ayah", type: "text" }, { key: "nama_ayah", name: "Nama Ayah", desc: "Nama ayah kandung", type: "text", required: true },
{ key: "nik_ayah", name: "NIK Ayah", desc: "NIK ayah kandung", type: "number" }, { key: "nik_ayah", name: "NIK Ayah", desc: "NIK ayah kandung", type: "number", required: true },
{ key: "tempat_lahir_ayah", name: "Tempat Lahir Ayah", desc: "Tempat lahir ayah kandung", type: "text" }, { key: "tempat_lahir_ayah", name: "Tempat Lahir Ayah", desc: "Tempat lahir ayah", type: "text", required: true },
{ key: "tanggal_lahir_ayah", name: "Tanggal Lahir Ayah", desc: "Tanggal lahir ayah kandung", type: "date" }, { key: "tanggal_lahir_ayah", name: "Tanggal Lahir Ayah", desc: "Tanggal lahir ayah", type: "date", required: true },
{ key: "pekerjaan_ayah", name: "Pekerjaan Ayah", desc: "Pekerjaan ayah kandung", type: "text" }, { key: "pekerjaan_ayah", name: "Pekerjaan Ayah", desc: "Pekerjaan ayah", type: "text", required: true },
{ key: "alamat_ayah", name: "Alamat Ayah", desc: "Alamat ayah kandung", type: "text" }, { key: "alamat_ayah", name: "Alamat Ayah", desc: "Alamat ayah", type: "text", required: true },
{ key: "nama_pelapor", name: "Nama Pelapor", desc: "Nama pihak yang melaporkan", type: "text" }, { key: "nama_pelapor", name: "Nama Pelapor", desc: "Nama pelapor", type: "text", required: true },
{ key: "hubungan_pelapor", name: "Hubungan Pelapor", desc: "Hubungan pelapor dengan anak", type: "text" }, { key: "hubungan_pelapor", name: "Hubungan Pelapor", desc: "Hubungan dengan anak", type: "text", required: true },
{ key: "alamat_pelapor", name: "Alamat Pelapor", desc: "Alamat pelapor", type: "text" } { key: "alamat_pelapor", name: "Alamat Pelapor", desc: "Alamat pelapor", type: "text", required: true }
] ]
}, },
{ {
id: "skkelakuanbaik", id: "skkelakuanbaik",
name: "Surat Keterangan Kelakuan Baik (Pengantar SKCK)", name: "Surat Keterangan Kelakuan Baik (Pengantar SKCK)",
syaratDokumen: [ syaratDokumen: [
{ { key: "pengantar_kelian", name: "Pengantar Kelian", desc: "Surat Pengantar Kelian Banjar Dinas", required: true },
key: "pengantar_kelian", { key: "ktp_kk", name: "KTP / KK", desc: "Fotokopi KTP atau KK", required: true }
name: "Pengantar Kelian",
desc: "Surat Pengantar Kelian Banjar Dinas"
},
{
key: "ktp_kk",
name: "KTP / KK",
desc: "Fotokopi KTP atau Kartu Keluarga"
}
], ],
dataText: [], dataText: [],
dataPelengkap: [ dataPelengkap: [
{ key: "nik", name: "NIK", desc: "Nomor Induk Kependudukan", type: "number" }, { key: "nik", name: "NIK", desc: "Nomor Induk Kependudukan", type: "number", required: true },
{ key: "nama", name: "Nama Lengkap", desc: "Nama sesuai KTP", type: "text" }, { key: "nama", name: "Nama Lengkap", desc: "Nama sesuai KTP", type: "text", required: true },
{ key: "tempat_lahir", name: "Tempat Lahir", desc: "Tempat lahir", type: "text" }, { key: "tempat_lahir", name: "Tempat Lahir", desc: "Tempat lahir", type: "text", required: true },
{ key: "tanggal_lahir", name: "Tanggal Lahir", desc: "Tanggal lahir", type: "date" }, { key: "tanggal_lahir", name: "Tanggal Lahir", desc: "Tanggal lahir", type: "date", required: true },
{ {
key: "jenis_kelamin", key: "jenis_kelamin",
name: "Jenis Kelamin", name: "Jenis Kelamin",
desc: "Jenis kelamin pemohon", desc: "Jenis kelamin",
type: "enum", type: "enum",
options: enumJenisKelamin options: enumJenisKelamin,
required: true
}, },
{ {
key: "agama", key: "agama",
name: "Agama", name: "Agama",
desc: "Agama pemohon", desc: "Agama",
type: "enum", type: "enum",
options: enumAgama options: enumAgama,
required: true
}, },
{ key: "alamat", name: "Alamat", desc: "Alamat tempat tinggal", type: "text" }, { key: "alamat", name: "Alamat", desc: "Alamat tempat tinggal", type: "text", required: true },
{ key: "pekerjaan", name: "Pekerjaan", desc: "Pekerjaan pemohon", type: "text" }, { key: "pekerjaan", name: "Pekerjaan", desc: "Pekerjaan", type: "text", required: true },
{ key: "polsek", name: "Polsek Tujuan", desc: "Polsek tujuan pembuatan SKCK", type: "text" } { key: "polsek", name: "Polsek Tujuan", desc: "Polsek tujuan", type: "text", required: true }
] ]
}, },
{ {
id: "skkematian", id: "skkematian",
name: "Surat Keterangan Kematian", name: "Surat Keterangan Kematian",
syaratDokumen: [ syaratDokumen: [
{ { key: "pengantar_kelian", name: "Pengantar Kelian", desc: "Surat Pengantar Kelian Banjar Dinas", required: true },
key: "pengantar_kelian", { key: "ktp_kk", name: "KTP / KK", desc: "Fotokopi KTP atau KK", required: true },
name: "Pengantar Kelian", { key: "surat_kematian", name: "Surat Keterangan Kematian", desc: "Surat keterangan kematian dari rumah sakit/dokter (jika ada)", required: false }
desc: "Surat Pengantar Kelian Banjar Dinas"
},
{
key: "ktp_kk",
name: "KTP / KK",
desc: "Fotokopi KTP atau Kartu Keluarga"
},
{
key: "surat_kematian",
name: "Surat Keterangan Kematian",
desc: "Surat keterangan kematian dari rumah sakit/dokter (jika ada)"
}
], ],
dataText: [], dataText: [],
dataPelengkap: [ dataPelengkap: [
{ key: "nik_pelapor", name: "NIK Pelapor", desc: "Nomor Induk Kependudukan pelapor", type: "number" }, { key: "nik_pelapor", name: "NIK Pelapor", desc: "NIK pelapor", type: "number", required: true },
{ key: "nama_pelapor", name: "Nama Pelapor", desc: "Nama lengkap pelapor", type: "text" }, { key: "nama_pelapor", name: "Nama Pelapor", desc: "Nama pelapor", type: "text", required: true },
{ key: "pekerjaan_pelapor", name: "Pekerjaan Pelapor", desc: "Pekerjaan pelapor", type: "text" }, { key: "pekerjaan_pelapor", name: "Pekerjaan Pelapor", desc: "Pekerjaan pelapor", type: "text", required: true },
{ key: "alamat_pelapor", name: "Alamat Pelapor", desc: "Alamat tempat tinggal pelapor", type: "text" }, { key: "alamat_pelapor", name: "Alamat Pelapor", desc: "Alamat pelapor", type: "text", required: true },
{ key: "hubungan_pelapor", name: "Hubungan dengan Almarhum", desc: "Hubungan pelapor dengan almarhum", type: "text" }, { key: "hubungan_pelapor", name: "Hubungan Pelapor", desc: "Hubungan dengan almarhum", type: "text", required: true },
{ key: "nama_almarhum", name: "Nama Almarhum", desc: "Nama lengkap almarhum", type: "text" }, { key: "nama_almarhum", name: "Nama Almarhum", desc: "Nama almarhum", type: "text", required: true },
{ key: "nik_almarhum", name: "NIK Almarhum", desc: "Nomor Induk Kependudukan almarhum", type: "number" }, { key: "nik_almarhum", name: "NIK Almarhum", desc: "NIK almarhum", type: "number", required: true },
{ key: "tempat_lahir_almarhum", name: "Tempat Lahir Almarhum", desc: "Tempat lahir almarhum", type: "text" }, { key: "tempat_lahir_almarhum", name: "Tempat Lahir", desc: "Tempat lahir almarhum", type: "text", required: true },
{ key: "tanggal_lahir_almarhum", name: "Tanggal Lahir Almarhum", desc: "Tanggal lahir almarhum", type: "date" }, { key: "tanggal_lahir_almarhum", name: "Tanggal Lahir", desc: "Tanggal lahir almarhum", type: "date", required: true },
{ key: "alamat_almarhum", name: "Alamat Almarhum", desc: "Alamat terakhir almarhum", type: "text" }, { key: "alamat_almarhum", name: "Alamat", desc: "Alamat terakhir", type: "text", required: true },
{ {
key: "agama_almarhum", key: "agama_almarhum",
name: "Agama Almarhum", name: "Agama Almarhum",
desc: "Agama almarhum", desc: "Agama almarhum",
type: "enum", type: "enum",
options: enumAgama options: enumAgama,
required: true
}, },
{ key: "tanggal_kematian", name: "Tanggal Kematian", desc: "Tanggal meninggal dunia", type: "date" }, { key: "tanggal_kematian", name: "Tanggal Kematian", desc: "Tanggal meninggal dunia", type: "date", required: true },
{ key: "waktu_kematian", name: "Waktu Kematian", desc: "Waktu meninggal dunia", type: "text" }, { key: "waktu_kematian", name: "Waktu Kematian", desc: "Waktu meninggal dunia", type: "text", required: true },
{ key: "tempat_kematian", name: "Tempat Kematian", desc: "Tempat meninggal dunia", type: "text" }, { key: "tempat_kematian", name: "Tempat Kematian", desc: "Tempat meninggal dunia", type: "text", required: true },
{ key: "penyebab_kematian", name: "Penyebab Kematian", desc: "Penyebab meninggal dunia", type: "text" } { key: "penyebab_kematian", name: "Penyebab Kematian", desc: "Penyebab meninggal dunia", type: "text", required: true }
] ]
}, },
{ {
id: "skpenghasilan", id: "skpenghasilan",
name: "Surat Keterangan Penghasilan", name: "Surat Keterangan Penghasilan",
syaratDokumen: [ syaratDokumen: [
{ { key: "pengantar_kelian", name: "Pengantar Kelian", desc: "Surat Pengantar Kelian Banjar Dinas", required: true },
key: "pengantar_kelian", { key: "ktp_ortu_kk", name: "KTP Orang Tua / KK", desc: "Fotokopi KTP orang tua/KK", required: true },
name: "Pengantar Kelian", { key: "surat_pernyataan", name: "Surat Pernyataan Penghasilan", desc: "Surat pernyataan penghasilan bermaterai", required: true }
desc: "Surat Pengantar Kelian Banjar Dinas"
},
{
key: "ktp_ortu_kk",
name: "KTP Orang Tua / KK",
desc: "Fotokopi KTP orang tua atau Kartu Keluarga"
},
{
key: "surat_pernyataan",
name: "Surat Pernyataan",
desc: "Surat pernyataan penghasilan bermaterai"
}
], ],
dataText: [], dataText: [],
dataPelengkap: [ dataPelengkap: [
{ key: "nama", name: "Nama Lengkap", desc: "Nama pemohon", type: "text" }, { key: "nama", name: "Nama Lengkap", desc: "Nama pemohon", type: "text", required: true },
{ key: "tempat_lahir", name: "Tempat Lahir", desc: "Tempat lahir", type: "text" }, { key: "tempat_lahir", name: "Tempat Lahir", desc: "Tempat lahir", type: "text", required: true },
{ key: "tanggal_lahir", name: "Tanggal Lahir", desc: "Tanggal lahir", type: "date" }, { key: "tanggal_lahir", name: "Tanggal Lahir", desc: "Tanggal lahir", type: "date", required: true },
{ {
key: "jenis_kelamin", key: "jenis_kelamin",
name: "Jenis Kelamin", name: "Jenis Kelamin",
desc: "Jenis kelamin pemohon", desc: "Jenis kelamin",
type: "enum", type: "enum",
options: enumJenisKelamin options: enumJenisKelamin,
required: true
}, },
{ key: "alamat", name: "Alamat", desc: "Alamat tempat tinggal", type: "text" }, { key: "alamat", name: "Alamat", desc: "Alamat tempat tinggal", type: "text", required: true },
{ key: "pekerjaan", name: "Pekerjaan", desc: "Pekerjaan pemohon/orang tua", type: "text" }, { key: "pekerjaan", name: "Pekerjaan", desc: "Pekerjaan pemohon", type: "text", required: true },
{ key: "penghasilan", name: "Penghasilan", desc: "Jumlah penghasilan per bulan", type: "number" }, { key: "penghasilan", name: "Penghasilan", desc: "Jumlah penghasilan per bulan", type: "number", required: true },
{ key: "alasan", name: "Alasan Permohonan", desc: "Alasan pengajuan surat penghasilan", type: "text" } { key: "alasan", name: "Alasan Permohonan", desc: "Alasan pengajuan surat penghasilan", type: "text", required: true }
] ]
}, },
{ {
id: "sktempatusaha", id: "sktempatusaha",
name: "Surat Keterangan Tempat Usaha", name: "Surat Keterangan Tempat Usaha",
syaratDokumen: [ syaratDokumen: [
{ { key: "pengantar_kelian", name: "Pengantar Kelian", desc: "Surat Pengantar Kelian Banjar Dinas", required: true },
key: "pengantar_kelian", { key: "ktp_kk", name: "KTP / KK", desc: "Fotokopi KTP/KK", required: true },
name: "Pengantar Kelian", { key: "foto_lokasi", name: "Foto Lokasi Usaha", desc: "Foto lokasi usaha", required: true },
desc: "Surat Pengantar Kelian Banjar Dinas" { key: "dokumen_lahan", name: "Dokumen Lahan", desc: "SPPT/Sertifikat/surat sewa tempat usaha", required: true }
},
{
key: "ktp_kk",
name: "KTP / KK",
desc: "Fotokopi KTP atau Kartu Keluarga"
},
{
key: "foto_lokasi",
name: "Foto Lokasi Usaha",
desc: "Foto lokasi usaha dicetak dan distempel oleh Kelian"
},
{
key: "dokumen_lahan",
name: "Dokumen Lahan",
desc: "SPPT, Sertifikat, atau surat sewa tempat usaha"
}
], ],
dataText: [], dataText: [],
dataPelengkap: [ dataPelengkap: [
{ key: "nik", name: "NIK", desc: "Nomor Induk Kependudukan", type: "number" }, { key: "nik", name: "NIK", desc: "NIK pemilik", type: "number", required: true },
{ key: "nama_pemilik", name: "Nama Pemilik", desc: "Nama pemilik usaha", type: "text" }, { key: "nama_pemilik", name: "Nama Pemilik", desc: "Nama pemilik usaha", type: "text", required: true },
{ key: "tempat_lahir", name: "Tempat Lahir", desc: "Tempat lahir", type: "text" }, { key: "tempat_lahir", name: "Tempat Lahir", desc: "Tempat lahir", type: "text", required: true },
{ key: "tanggal_lahir", name: "Tanggal Lahir", desc: "Tanggal lahir", type: "date" }, { key: "tanggal_lahir", name: "Tanggal Lahir", desc: "Tanggal lahir", type: "date", required: true },
{ key: "alamat_pemilik", name: "Alamat Pemilik", desc: "Alamat pemilik usaha", type: "text" }, { key: "alamat_pemilik", name: "Alamat Pemilik", desc: "Alamat pemilik", type: "text", required: true },
{ key: "nama_usaha", name: "Nama Usaha", desc: "Nama usaha", type: "text" }, { key: "nama_usaha", name: "Nama Usaha", desc: "Nama usaha", type: "text", required: true },
{ key: "bidang_usaha", name: "Bidang Usaha", desc: "Bidang atau jenis usaha", type: "text" }, { key: "bidang_usaha", name: "Bidang Usaha", desc: "Bidang usaha", type: "text", required: true },
{ key: "alamat_usaha", name: "Alamat Usaha", desc: "Alamat lokasi usaha", type: "text" }, { key: "alamat_usaha", name: "Alamat Usaha", desc: "Alamat usaha", type: "text", required: true },
{ key: "status_tempat", name: "Status Tempat Usaha", desc: "Status kepemilikan tempat usaha", type: "enum", options: enumStatusTempatUsaha }, {
{ key: "luas_usaha", name: "Luas Tempat Usaha", desc: "Luas tempat usaha (m²)", type: "number" }, key: "status_tempat",
{ key: "jumlah_karyawan", name: "Jumlah Karyawan", desc: "Jumlah tenaga kerja", type: "number" }, name: "Status Tempat Usaha",
{ key: "tujuan", name: "Tujuan Pembuatan Surat", desc: "Tujuan pembuatan surat keterangan", type: "text" } desc: "Status kepemilikan tempat usaha",
type: "enum",
options: enumStatusTempatUsaha,
required: true
},
{ key: "luas_usaha", name: "Luas Tempat Usaha", desc: "Luas tempat usaha (m²)", type: "number", required: true },
{ key: "jumlah_karyawan", name: "Jumlah Karyawan", desc: "Jumlah karyawan", type: "number", required: true },
{ key: "tujuan", name: "Tujuan Pembuatan Surat", desc: "Tujuan pembuatan surat keterangan", type: "text", required: true }
] ]
}, },
{ {
id: "sktidakmampu", id: "sktidakmampu",
name: "Surat Keterangan Tidak Mampu", name: "Surat Keterangan Tidak Mampu",
syaratDokumen: [ syaratDokumen: [
{ { key: "pengantar_kelian", name: "Pengantar Kelian", desc: "Surat Pengantar Kelian Banjar Dinas", required: true },
key: "pengantar_kelian", { key: "ktp_kia_kk", name: "KTP / KIA / KK", desc: "Fotokopi KTP/KIA/KK", required: true }
name: "Pengantar Kelian",
desc: "Surat Pengantar Kelian Banjar Dinas"
},
{
key: "ktp_kia_kk",
name: "KTP / KIA / KK",
desc: "Fotokopi KTP, KIA, atau Kartu Keluarga"
}
], ],
dataText: [], dataText: [],
dataPelengkap: [ dataPelengkap: [
{ key: "nik", name: "NIK", desc: "Nomor Induk Kependudukan pemohon", type: "number" }, { key: "nik", name: "NIK", desc: "NIK pemohon", type: "number", required: true },
{ key: "nama", name: "Nama Lengkap", desc: "Nama lengkap pemohon", type: "text" }, { key: "nama Lengkap", name: "Nama", desc: "Nama pemohon", type: "text", required: true },
{ key: "tempat_lahir", name: "Tempat Lahir", desc: "Tempat lahir pemohon", type: "text" }, { key: "tempat_lahir", name: "Tempat Lahir", desc: "Tempat lahir", type: "text", required: true },
{ key: "tanggal_lahir", name: "Tanggal Lahir", desc: "Tanggal lahir pemohon", type: "date" }, { key: "tanggal_lahir", name: "Tanggal Lahir", desc: "Tanggal lahir", type: "date", required: true },
{ key: "alamat", name: "Alamat", desc: "Alamat tempat tinggal pemohon", type: "text" }, { key: "alamat", name: "Alamat", desc: "Alamat pemohon", type: "text", required: true },
{ key: "alasan", name: "Alasan Permohonan", desc: "Alasan pengajuan Surat Keterangan Tidak Mampu", type: "text" } { key: "alasan", name: "Alasan Permohonan", desc: "Alasan permohonan", type: "text", required: true }
] ]
}, },
{ {
id: "skusaha", id: "skusaha",
name: "Surat Keterangan Usaha", name: "Surat Keterangan Usaha",
syaratDokumen: [ syaratDokumen: [
{ { key: "pengantar_kelian", name: "Pengantar Kelian", desc: "Surat Pengantar Kelian Banjar Dinas", required: true },
key: "pengantar_kelian", { key: "ktp_kk", name: "KTP / KK", desc: "Fotokopi KTP/KK", required: true },
name: "Pengantar Kelian", { key: "foto_lokasi", name: "Foto Lokasi Usaha", desc: "Foto lokasi usaha", required: true }
desc: "Surat Pengantar Kelian Banjar Dinas"
},
{
key: "ktp_kk",
name: "KTP / KK",
desc: "Fotokopi KTP atau Kartu Keluarga"
},
{
key: "foto_lokasi",
name: "Foto Lokasi Usaha",
desc: "Foto lokasi usaha dicetak dan distempel oleh Kelian"
}
], ],
dataText: [], dataText: [],
dataPelengkap: [ dataPelengkap: [
{ key: "nama", name: "Nama Lengkap", desc: "Nama pemilik usaha", type: "text" }, { key: "nama", name: "Nama Lengkap", desc: "Nama pemilik usaha", type: "text", required: true },
{ {
key: "jenis_kelamin", key: "jenis_kelamin",
name: "Jenis Kelamin", name: "Jenis Kelamin",
desc: "Jenis kelamin pemilik usaha", desc: "Jenis kelamin pemilik usaha",
type: "enum", type: "enum",
options: enumJenisKelamin options: enumJenisKelamin,
required: true
}, },
{ key: "tempat_lahir", name: "Tempat Lahir", desc: "Tempat lahir", type: "text" }, { key: "tempat_lahir", name: "Tempat Lahir", desc: "Tempat lahir", type: "text", required: true },
{ key: "tanggal_lahir", name: "Tanggal Lahir", desc: "Tanggal lahir", type: "date" }, { key: "tanggal_lahir", name: "Tanggal Lahir", desc: "Tanggal lahir", type: "date", required: true },
{ key: "negara", name: "Kewarganegaraan", desc: "Kewarganegaraan pemilik usaha", type: "text" }, { key: "negara", name: "Kewarganegaraan", desc: "Kewarganegaraan", type: "text", required: true },
{ {
key: "agama", key: "agama",
name: "Agama", name: "Agama",
desc: "Agama pemilik usaha", desc: "Agama",
type: "enum", type: "enum",
options: enumAgama options: enumAgama,
required: true
}, },
{ {
key: "status_perkawinan", key: "status_perkawinan",
name: "Status Perkawinan", name: "Status Perkawinan",
desc: "Status perkawinan", desc: "Status perkawinan",
type: "enum", type: "enum",
options: enumStatusPerkawinan options: enumStatusPerkawinan,
required: true
}, },
{ key: "alamat", name: "Alamat", desc: "Alamat tempat tinggal", type: "text" }, { key: "alamat", name: "Alamat", desc: "Alamat", type: "text", required: true },
{ key: "pekerjaan", name: "Pekerjaan", desc: "Pekerjaan pemilik usaha", type: "text" }, { key: "pekerjaan", name: "Pekerjaan", desc: "Pekerjaan", type: "text", required: true },
{ key: "jenis_usaha", name: "Jenis Usaha", desc: "Jenis usaha yang dijalankan", type: "text" }, { key: "jenis_usaha", name: "Jenis Usaha", desc: "Jenis usaha", type: "text", required: true },
{ key: "alamat_usaha", name: "Alamat Usaha", desc: "Alamat lokasi usaha", type: "text" } { key: "alamat_usaha", name: "Alamat Usaha", desc: "Alamat usaha", type: "text", required: true }
] ]
}, },
{ {
id: "skyatimpiatu", id: "skyatimpiatu",
name: "Surat Keterangan Yatim / Piatu / Yatim Piatu", name: "Surat Keterangan Yatim / Piatu / Yatim Piatu",
syaratDokumen: [ syaratDokumen: [
{ { key: "pengantar_kelian", name: "Pengantar Kelian", desc: "Surat Pengantar Kelian Banjar Dinas", required: true },
key: "pengantar_kelian", { key: "ktp_kia_kk", name: "KTP / KIA / KK", desc: "Fotokopi KTP/KIA/KK", required: true }
name: "Pengantar Kelian",
desc: "Surat Pengantar Kelian Banjar Dinas"
},
{
key: "ktp_kia_kk",
name: "KTP / KIA / KK",
desc: "Fotokopi KTP, KIA, atau Kartu Keluarga"
}
], ],
dataText: [], dataText: [],
dataPelengkap: [ dataPelengkap: [
{ key: "nik", name: "NIK", desc: "Nomor Induk Kependudukan", type: "number" }, { key: "nik", name: "NIK", desc: "NIK anak", type: "number", required: true },
{ key: "nama", name: "Nama Lengkap", desc: "Nama anak", type: "text" }, { key: "nama", name: "Nama", desc: "Nama anak", type: "text", required: true },
{ key: "tempat_lahir", name: "Tempat Lahir Anak", desc: "Tempat lahir anak", type: "text" }, { key: "tempat_lahir", name: "Tempat Lahir", desc: "Tempat lahir", type: "text", required: true },
{ key: "tanggal_lahir", name: "Tanggal Lahir Anak", desc: "Tanggal lahir anak", type: "date" }, { key: "tanggal_lahir", name: "Tanggal Lahir", desc: "Tanggal lahir", type: "date", required: true },
{ {
key: "jenis_kelamin", key: "jenis_kelamin",
name: "Jenis Kelamin", name: "Jenis Kelamin",
desc: "Jenis kelamin anak", desc: "Jenis kelamin anak",
type: "enum", type: "enum",
options: enumJenisKelamin options: enumJenisKelamin,
required: true
}, },
{ key: "alamat", name: "Alamat", desc: "Alamat tempat tinggal", type: "text" }, { key: "alamat", name: "Alamat", desc: "Alamat", type: "text", required: true },
{ key: "pekerjaan", name: "Pekerjaan", desc: "Pekerjaan (jika ada)", type: "text" }, { key: "pekerjaan", name: "Pekerjaan", desc: "Pekerjaan (jika ada)", type: "text", required: false },
{ key: "nama_ayah", name: "Nama Ayah", desc: "Nama ayah", type: "text", required: true },
{ key: "nama_ayah", name: "Nama Ayah", desc: "Nama ayah kandung", type: "text" },
{ {
key: "status_ayah", key: "status_ayah",
name: "Status Ayah", name: "Status Ayah",
desc: "Status ayah (hidup / meninggal)", desc: "Status ayah",
type: "enum", type: "enum",
options: enumStatusHidup options: enumStatusHidup,
required: true
}, },
{ key: "nama_ibu", name: "Nama Ibu", desc: "Nama ibu kandung", type: "text" }, { key: "nama_ibu", name: "Nama Ibu", desc: "Nama ibu", type: "text", required: true },
{ {
key: "status_ibu", key: "status_ibu",
name: "Status Ibu", name: "Status Ibu",
desc: "Status ibu (hidup / meninggal)", desc: "Status ibu",
type: "enum", type: "enum",
options: enumStatusHidup options: enumStatusHidup,
required: true
} }
] ]
} }
]; ];

View File

@@ -42,6 +42,7 @@ import useSWR from "swr";
type DataItem = { type DataItem = {
key: string; key: string;
value: string; value: string;
required: boolean;
}; };
type FormSurat = { type FormSurat = {
@@ -96,7 +97,7 @@ export default function FormSurat() {
setJenisSuratFix({ name: "", id: "" }); setJenisSuratFix({ name: "", id: "" });
} else { } else {
const namaJenis = fromSlug(jenisSurat); const namaJenis = fromSlug(jenisSurat);
const data = listCategory.find((item: any) => item.name == namaJenis); const data = listCategory.find((item: any) => item.name.toUpperCase() == namaJenis.toUpperCase());
if (!data) return; if (!data) return;
setJenisSuratFix(data); setJenisSuratFix(data);
} }
@@ -119,15 +120,17 @@ export default function FormSurat() {
nama: "", nama: "",
phone: "", phone: "",
dataPelengkap: (get.data?.dataPelengkap || []).map( dataPelengkap: (get.data?.dataPelengkap || []).map(
(item: { key: string }) => ({ (item: { key: string, required: boolean }) => ({
key: item.key, key: item.key,
value: "", value: "",
required: item.required
}), }),
), ),
syaratDokumen: (get.data?.syaratDokumen || []).map( syaratDokumen: (get.data?.syaratDokumen || []).map(
(item: { key: string }) => ({ (item: { key: string, required: boolean }) => ({
key: item.key, key: item.key,
value: "", value: "",
required: item.required
}), }),
), ),
}); });
@@ -167,10 +170,10 @@ export default function FormSurat() {
if (Array.isArray(value)) { if (Array.isArray(value)) {
return value.some( return value.some(
(item) => (item) =>
typeof item.value === "string" && item.value.trim() === "", (typeof item.value === "string" && item.value.trim() === "" && item.required) || (typeof item.value === "object" && item.value === null && item.required),
); );
} }
return typeof value === "string" && value.trim() === ""; return typeof value === "string" && value.trim() === "" ;
}); });
if (isFormKosong) { if (isFormKosong) {
@@ -276,13 +279,14 @@ export default function FormSurat() {
value: any; value: any;
}) { }) {
if (key === "dataPelengkap" || key === "syaratDokumen") { if (key === "dataPelengkap" || key === "syaratDokumen") {
const errorMsg = validateField(value.key, value.value); if (value.required == true) {
const errorMsg = validateField(value.key, value.value);
setErrors((prev) => ({
...prev,
[value.key]: errorMsg,
}));
setErrors((prev) => ({
...prev,
[value.key]: errorMsg,
}));
}
setFormSurat((prev) => ({ setFormSurat((prev) => ({
...prev, ...prev,
[key]: updateArrayByKey(prev[key], value.key, value.value), [key]: updateArrayByKey(prev[key], value.key, value.value),
@@ -400,7 +404,7 @@ export default function FormSurat() {
<Grid> <Grid>
<Grid.Col span={6}> <Grid.Col span={6}>
<TextInput <TextInput
label={<FieldLabel label="Nama" hint="Nama kontak" />} label={<FieldLabel label="Nama" hint="Nama kontak" required />}
placeholder="Budi Setiawan" placeholder="Budi Setiawan"
value={formSurat.nama} value={formSurat.nama}
error={errors.nama_kontak} error={errors.nama_kontak}
@@ -414,6 +418,7 @@ export default function FormSurat() {
<TextInput <TextInput
label={ label={
<FieldLabel <FieldLabel
required
label="Nomor Telephone" label="Nomor Telephone"
hint="Nomor telephone yang dapat dihubungi / terhubung dengan whatsapp" hint="Nomor telephone yang dapat dihubungi / terhubung dengan whatsapp"
/> />
@@ -450,6 +455,7 @@ export default function FormSurat() {
<FieldLabel <FieldLabel
label={item.name} label={item.name}
hint={item.desc} hint={item.desc}
required={item.required}
/> />
} }
data={item.options ?? []} data={item.options ?? []}
@@ -457,7 +463,7 @@ export default function FormSurat() {
onChange={(e) => { onChange={(e) => {
validationForm({ validationForm({
key: "dataPelengkap", key: "dataPelengkap",
value: { key: item.key, value: e }, value: { key: item.key, value: e, required: item.required },
}); });
}} }}
value={ value={
@@ -474,6 +480,7 @@ export default function FormSurat() {
<FieldLabel <FieldLabel
label={item.name} label={item.name}
hint={item.desc} hint={item.desc}
required={item.required}
/> />
} }
placeholder={item.name} placeholder={item.name}
@@ -488,6 +495,7 @@ export default function FormSurat() {
value: { value: {
key: item.key, key: item.key,
value: formatted, value: formatted,
required: item.required,
}, },
}); });
}} }}
@@ -500,6 +508,7 @@ export default function FormSurat() {
<FieldLabel <FieldLabel
label={item.name} label={item.name}
hint={item.desc} hint={item.desc}
required={item.required}
/> />
} }
placeholder={item.name} placeholder={item.name}
@@ -509,6 +518,7 @@ export default function FormSurat() {
value: { value: {
key: item.key, key: item.key,
value: e.target.value, value: e.target.value,
required: item.required,
}, },
}) })
} }
@@ -545,6 +555,7 @@ export default function FormSurat() {
}) })
} }
name={item.name} name={item.name}
required={item.required}
/> />
</Grid.Col> </Grid.Col>
), ),
@@ -569,10 +580,20 @@ export default function FormSurat() {
); );
} }
function FieldLabel({ label, hint }: { label: string; hint?: string }) { function FieldLabel({ label, hint, required = false, }: { label: string; hint?: string; required?: boolean; }) {
return ( return (
<Group justify="apart" gap="xs" align="center"> <Group justify="apart" gap="xs" align="center">
<Text fw={600}>{label}</Text> <Group gap={4} align="center">
<Text fw={600}>
{label}
{required && (
<Text span c="red" ml={4}>
*
</Text>
)}
</Text>
</Group>
{hint && ( {hint && (
<Tooltip label={hint} withArrow> <Tooltip label={hint} withArrow>
<ActionIcon size={24} variant="subtle"> <ActionIcon size={24} variant="subtle">
@@ -584,6 +605,7 @@ function FieldLabel({ label, hint }: { label: string; hint?: string }) {
); );
} }
function FormSection({ function FormSection({
title, title,
icon, icon,
@@ -619,6 +641,7 @@ function FileInputWrapper({
preview, preview,
name, name,
description, description,
required = false,
}: { }: {
label: string; label: string;
placeholder?: string; placeholder?: string;
@@ -627,12 +650,20 @@ function FileInputWrapper({
preview?: string | null; preview?: string | null;
name: string; name: string;
description?: string; description?: string;
required?: boolean;
}) { }) {
return ( return (
<Stack gap="xs"> <Stack gap="xs">
<Flex direction={"column"}> <Flex direction={"column"}>
<Group justify="apart" align="center"> <Group justify="apart" align="center">
<Text fw={500}>{label}</Text> <Text fw={500}>
{label}
{required && (
<Text span c="red" ml={4}>
*
</Text>
)}
</Text>
</Group> </Group>
{description && ( {description && (
<Text size="sm" c="dimmed" mt={4} style={{ lineHeight: 1.2 }}> <Text size="sm" c="dimmed" mt={4} style={{ lineHeight: 1.2 }}>
@@ -648,6 +679,7 @@ function FileInputWrapper({
leftSection={<IconUpload />} leftSection={<IconUpload />}
aria-label={label} aria-label={label}
name={name} name={name}
clearable={true}
/> />
{preview ? ( {preview ? (

View File

@@ -50,6 +50,7 @@ type UpdateDataItem = {
id: string; id: string;
key: string; key: string;
value: any; value: any;
required: boolean;
}; };
type FormSurat = { type FormSurat = {
@@ -125,10 +126,20 @@ export default function UpdateDataSurat() {
); );
} }
function FieldLabel({ label, hint }: { label: string; hint?: string }) { function FieldLabel({ label, hint, required = false, }: { label: string; hint?: string; required?: boolean; }) {
return ( return (
<Group justify="apart" gap="xs" align="center"> <Group justify="apart" gap="xs" align="center">
<Text fw={600}>{label}</Text> <Group gap={4} align="center">
<Text fw={600}>
{label}
{required && (
<Text span c="red" ml={4}>
*
</Text>
)}
</Text>
</Group>
{hint && ( {hint && (
<Tooltip label={hint} withArrow> <Tooltip label={hint} withArrow>
<ActionIcon size={24} variant="subtle"> <ActionIcon size={24} variant="subtle">
@@ -139,7 +150,6 @@ function FieldLabel({ label, hint }: { label: string; hint?: string }) {
</Group> </Group>
); );
} }
function FormSection({ function FormSection({
title, title,
icon, icon,
@@ -185,6 +195,8 @@ function FileInputWrapper({
description, description,
linkView, linkView,
disabled, disabled,
required = false,
}: { }: {
label: string; label: string;
placeholder?: string; placeholder?: string;
@@ -195,6 +207,7 @@ function FileInputWrapper({
name: string; name: string;
description?: string; description?: string;
disabled?: boolean; disabled?: boolean;
required?: boolean;
}) { }) {
const [viewImg, setViewImg] = useState(""); const [viewImg, setViewImg] = useState("");
const [openedPreviewFile, setOpenedPreviewFile] = useState(false); const [openedPreviewFile, setOpenedPreviewFile] = useState(false);
@@ -219,7 +232,14 @@ function FileInputWrapper({
<Stack gap="xs"> <Stack gap="xs">
<Flex direction={"column"}> <Flex direction={"column"}>
<Group justify="apart" align="center"> <Group justify="apart" align="center">
<Text fw={500}>{label}</Text> <Text fw={500}>
{label}
{required && (
<Text span c="red" ml={4}>
*
</Text>
)}
</Text>
</Group> </Group>
{description && ( {description && (
<Text size="sm" c="dimmed" mt={4} style={{ lineHeight: 1.2 }}> <Text size="sm" c="dimmed" mt={4} style={{ lineHeight: 1.2 }}>
@@ -241,6 +261,7 @@ function FileInputWrapper({
aria-label={label} aria-label={label}
name={name} name={name}
disabled={disabled} disabled={disabled}
clearable={true}
/> />
{preview ? ( {preview ? (
@@ -317,57 +338,60 @@ function SearchData() {
} }
return ( return (
<FormSection <>
title="Cari Pengajuan Surat" <FullScreenLoading visible={submitLoading} text="Mencari Data" />
info="Masukkan nomor pengajuan dan nomor telepon yang digunakan saat pengajuan surat." <FormSection
> title="Cari Pengajuan Surat"
<Grid> info="Masukkan nomor pengajuan dan nomor telepon yang digunakan saat pengajuan surat."
<Grid.Col span={6}> >
<TextInput <Grid>
label={ <Grid.Col span={6}>
<FieldLabel <TextInput
label="Nomor Pengajuan" label={
hint="Nomor pengajuan surat" <FieldLabel
/> label="Nomor Pengajuan"
} hint="Nomor pengajuan surat"
placeholder="PS-2025-000123" />
onChange={(e) => { }
setSearchPengajuan(e.target.value); placeholder="PS-2025-000123"
}} onChange={(e) => {
/> setSearchPengajuan(e.target.value);
</Grid.Col> }}
/>
</Grid.Col>
<Grid.Col span={6}> <Grid.Col span={6}>
<TextInput <TextInput
label={ label={
<FieldLabel <FieldLabel
label="Nomor Telephone" label="Nomor Telephone"
hint="Nomor telephone yang dapat dihubungi / terhubung dengan whatsapp" hint="Nomor telephone yang dapat dihubungi / terhubung dengan whatsapp"
/> />
} }
placeholder="08123456789" placeholder="08123456789"
type="number" type="number"
onChange={(e) => { onChange={(e) => {
setSearchPengajuanPhone(e.target.value); setSearchPengajuanPhone(e.target.value);
}} }}
/> />
</Grid.Col> </Grid.Col>
<Grid.Col span={12}> <Grid.Col span={12}>
<Button <Button
fullWidth fullWidth
variant="light" variant="light"
color="blue" color="blue"
onClick={() => { onClick={() => {
handleSearch(); handleSearch();
}} }}
loading={submitLoading} loading={submitLoading}
> >
Cari Pengajuan Cari Pengajuan
</Button> </Button>
</Grid.Col> </Grid.Col>
</Grid> </Grid>
</FormSection> </FormSection>
</>
); );
} }
@@ -387,6 +411,7 @@ function DataUpdate({
const [dataSyaratDokumen, setDataSyaratDokumen] = useState<DataItem[]>([]); const [dataSyaratDokumen, setDataSyaratDokumen] = useState<DataItem[]>([]);
const [dataPengajuan, setDataPengajuan] = useState<DataPengajuan | {}>({}); const [dataPengajuan, setDataPengajuan] = useState<DataPengajuan | {}>({});
const [status, setStatus] = useState(""); const [status, setStatus] = useState("");
const [loadingFetchData, setLoadingFetchData] = useState(false);
const [formSurat, setFormSurat] = useState<FormUpdateSurat>({ const [formSurat, setFormSurat] = useState<FormUpdateSurat>({
dataPelengkap: [], dataPelengkap: [],
syaratDokumen: [], syaratDokumen: [],
@@ -394,6 +419,7 @@ function DataUpdate({
async function fetchData() { async function fetchData() {
try { try {
setLoadingFetchData(true);
const res = await apiFetch.api.pelayanan["detail-data"].post({ const res = await apiFetch.api.pelayanan["detail-data"].post({
nomerPengajuan: noPengajuan, nomerPengajuan: noPengajuan,
}); });
@@ -421,6 +447,8 @@ function DataUpdate({
} }
} catch (error) { } catch (error) {
console.error("Error fetching data:", error); console.error("Error fetching data:", error);
} finally {
setLoadingFetchData(false);
} }
} }
@@ -470,21 +498,33 @@ function DataUpdate({
kategori: "dataPelengkap" | "syaratDokumen"; kategori: "dataPelengkap" | "syaratDokumen";
value: UpdateDataItem; value: UpdateDataItem;
}) { }) {
const errorMsg = validateField(value.key, value.value); if (kategori == "syaratDokumen" && value.value == null) {
setFormSurat((prev) => ({
...prev,
syaratDokumen: prev.syaratDokumen.filter(
(item) => item.id !== value.id
),
}));
} else {
if (value.required == true) {
const errorMsg = validateField(value.key, value.value);
setErrors((prev) => ({
...prev,
[value.id]: errorMsg,
}));
}
setErrors((prev) => ({
...prev,
[value.id]: errorMsg,
}));
setFormSurat((prev) => ({ setFormSurat((prev) => ({
...prev, ...prev,
[kategori]: upsertById(prev[kategori], { [kategori]: upsertById(prev[kategori], {
id: value.id, id: value.id,
key: value.key, key: value.key,
value: value.value, value: value.value,
}), required: value.required,
})); }),
}));
}
} }
@@ -521,7 +561,7 @@ function DataUpdate({
if (Array.isArray(value)) { if (Array.isArray(value)) {
return value.some( return value.some(
(item) => (item) =>
typeof item.value === "string" && item.value.trim() === "", (typeof item.value === "string" && item.value.trim() === "" && item.required) || (typeof item.value === "object" && item.value === null && item.required),
); );
} }
@@ -600,7 +640,7 @@ function DataUpdate({
return ( return (
<> <>
<FullScreenLoading visible={submitLoading} /> <FullScreenLoading visible={submitLoading || loadingFetchData} />
<Modal <Modal
opened={opened} opened={opened}
onClose={close} onClose={close}
@@ -667,14 +707,15 @@ function DataUpdate({
<Grid.Col span={6} key={index}> <Grid.Col span={6} key={index}>
{item.type == "enum" ? ( {item.type == "enum" ? (
<Select <Select
disabled={status != "ditolak" && status != "antrian"}
allowDeselect={false} allowDeselect={false}
label={<FieldLabel label={item.name} hint={item.desc} />} label={<FieldLabel label={item.name} hint={item.desc} required={item.required} />}
data={item.options ?? []} data={item.options ?? []}
placeholder={item.name} placeholder={item.name}
onChange={(e) => { onChange={(e) => {
validationForm({ validationForm({
kategori: "dataPelengkap", kategori: "dataPelengkap",
value: { id: item.id, key: item.key, value: e }, value: { id: item.id, key: item.key, value: e, required: item.required },
}); });
}} }}
value={ value={
@@ -686,9 +727,10 @@ function DataUpdate({
/> />
) : item.type == "date" ? ( ) : item.type == "date" ? (
<DateInput <DateInput
disabled={status != "ditolak" && status != "antrian"}
locale="id" locale="id"
valueFormat="DD MMMM YYYY" valueFormat="DD MMMM YYYY"
label={<FieldLabel label={item.name} hint={item.desc} />} label={<FieldLabel label={item.name} hint={item.desc} required={item.required} />}
placeholder={item.name} placeholder={item.name}
onChange={(e) => { onChange={(e) => {
const formatted = e const formatted = e
@@ -700,6 +742,7 @@ function DataUpdate({
id: item.id, id: item.id,
key: item.key, key: item.key,
value: formatted, value: formatted,
required: item.required
}, },
}); });
}} }}
@@ -712,13 +755,13 @@ function DataUpdate({
(n: any) => n.key === item.key, (n: any) => n.key === item.key,
)?.value, )?.value,
) )
: parseTanggalID(item.value) : parseTanggalID(item.value)
} }
/> />
) : ( ) : (
<TextInput <TextInput
error={errors[item.id]} error={errors[item.id]}
label={<FieldLabel label={item.name} hint={item.desc} />} label={<FieldLabel label={item.name} hint={item.desc} required={item.required} />}
placeholder={item.name} placeholder={item.name}
type={item.type} type={item.type}
onChange={(e) => onChange={(e) =>
@@ -728,6 +771,7 @@ function DataUpdate({
id: item.id, id: item.id,
key: item.key, key: item.key,
value: e.target.value, value: e.target.value,
required: item.required,
}, },
}) })
} }
@@ -753,6 +797,7 @@ function DataUpdate({
{dataSyaratDokumen.map((item: any, index: number) => ( {dataSyaratDokumen.map((item: any, index: number) => (
<Grid.Col span={6} key={index}> <Grid.Col span={6} key={index}>
<FileInputWrapper <FileInputWrapper
required={item.required}
label={item.desc} label={item.desc}
placeholder={"Upload file terbaru untuk mengupdate"} placeholder={"Upload file terbaru untuk mengupdate"}
accept="image/*,application/pdf" accept="image/*,application/pdf"
@@ -760,7 +805,7 @@ function DataUpdate({
onChange={(file) => onChange={(file) =>
validationForm({ validationForm({
kategori: "syaratDokumen", kategori: "syaratDokumen",
value: { id: item.id, key: item.key, value: file }, value: { id: item.id, key: item.key, value: file, required: item.required },
}) })
} }
name={item.name} name={item.name}

View File

@@ -73,7 +73,7 @@ export default function DashboardLayout() {
<AppShell <AppShell
padding="lg" padding="lg"
navbar={{ navbar={{
width: 260, width: 300,
breakpoint: "sm", breakpoint: "sm",
collapsed: { mobile: !opened, desktop: !opened }, collapsed: { mobile: !opened, desktop: !opened },
}} }}
@@ -290,22 +290,31 @@ function NavigationDashboard() {
.map((item) => ( .map((item) => (
<NavLink <NavLink
key={item.path} key={item.path}
active={isActive(item.path as keyof typeof clientRoute)} active={isActive(item.path as keyof typeof clientRoute) ||
(location.pathname == "/scr/dashboard/pelayanan-surat/detail-pelayanan" && item.path == "/scr/dashboard/pelayanan-surat/list-pelayanan") ||
(location.pathname == "/scr/dashboard/pengaduan/detail" && item.path == "/scr/dashboard/pengaduan/list") ||
(location.pathname == "/scr/dashboard/warga/detail-warga" && item.path == "/scr/dashboard/warga/list-warga")}
leftSection={item.icon} leftSection={item.icon}
label={ label={
<Flex align="center" gap={6}> <Flex align="center" gap={6}>
<Text fw={500}>{item.label}</Text> <Text fw={500}>{item.label}</Text>
{isActive(item.path as keyof typeof clientRoute) && ( {(
<Badge isActive(item.path as keyof typeof clientRoute) ||
variant="light" (location.pathname == "/scr/dashboard/pelayanan-surat/detail-pelayanan" && item.path == "/scr/dashboard/pelayanan-surat/list-pelayanan") ||
color="teal" (location.pathname == "/scr/dashboard/pengaduan/detail" && item.path == "/scr/dashboard/pengaduan/list") ||
radius="sm" (location.pathname == "/scr/dashboard/warga/detail-warga" && item.path == "/scr/dashboard/warga/list-warga")
size="xs" )
style={{ textTransform: "none" }} && (
> <Badge
Active variant="light"
</Badge> color="teal"
)} radius="sm"
size="xs"
style={{ textTransform: "none" }}
>
Active
</Badge>
)}
</Flex> </Flex>
} }
description={item.description} description={item.description}
@@ -313,7 +322,10 @@ function NavigationDashboard() {
navigate(clientRoutes[item.path as keyof typeof clientRoute]) navigate(clientRoutes[item.path as keyof typeof clientRoute])
} }
style={{ style={{
backgroundColor: isActive(item.path as keyof typeof clientRoute) backgroundColor: isActive(item.path as keyof typeof clientRoute) ||
(location.pathname == "/scr/dashboard/pelayanan-surat/detail-pelayanan" && item.path == "/scr/dashboard/pelayanan-surat/list-pelayanan") ||
(location.pathname == "/scr/dashboard/pengaduan/detail" && item.path == "/scr/dashboard/pengaduan/list") ||
(location.pathname == "/scr/dashboard/warga/detail-warga" && item.path == "/scr/dashboard/warga/list-warga")
? "rgba(0,255,200,0.1)" ? "rgba(0,255,200,0.1)"
: "transparent", : "transparent",
borderRadius: "8px", borderRadius: "8px",

View File

@@ -1,3 +1,5 @@
import BreadCrumbs from "@/components/BreadCrumbs";
import FullScreenLoading from "@/components/FullScreenLoading";
import ModalFile from "@/components/ModalFile"; import ModalFile from "@/components/ModalFile";
import ModalSurat from "@/components/ModalSurat"; import ModalSurat from "@/components/ModalSurat";
import notification from "@/components/notificationGlobal"; import notification from "@/components/notificationGlobal";
@@ -49,6 +51,11 @@ import { useLocation } from "react-router-dom";
import useSwr from "swr"; import useSwr from "swr";
export default function DetailPengajuanPage() { export default function DetailPengajuanPage() {
const dataMenu = [
{ title: "Dashboard", link: "/scr/dashboard/dashboard-home", active: false },
{ title: "Pelayanan Surat", link: "/scr/dashboard/pelayanan-surat/list-pelayanan", active: false },
{ title: "Detail Pengajuan Surat", link: "#", active: true },
];
const { search } = useLocation(); const { search } = useLocation();
const query = new URLSearchParams(search); const query = new URLSearchParams(search);
const id = query.get("id"); const id = query.get("id");
@@ -67,6 +74,9 @@ export default function DetailPengajuanPage() {
return ( return (
<Container size="xl" py="xl" w={"100%"}> <Container size="xl" py="xl" w={"100%"}>
<Grid> <Grid>
<Grid.Col span={12}>
<BreadCrumbs dataLink={dataMenu} back />
</Grid.Col>
<Grid.Col span={8}> <Grid.Col span={8}>
<Stack gap={"xl"}> <Stack gap={"xl"}>
<DetailDataPengajuan <DetailDataPengajuan
@@ -116,6 +126,7 @@ function DetailDataPengajuan({
const [editValue, setEditValue] = useState({ id: "", jenis: "", val: "", option: null as any, type: "", key: "" }) const [editValue, setEditValue] = useState({ id: "", jenis: "", val: "", option: null as any, type: "", key: "" })
const [openEdit, setOpenEdit] = useState(false) const [openEdit, setOpenEdit] = useState(false)
const [loadingUpdate, setLoadingUpdate] = useState(false) const [loadingUpdate, setLoadingUpdate] = useState(false)
const [loadingFS, setLoadingFS] = useState({ value: false, text: "" })
useEffect(() => { useEffect(() => {
async function fetchHost() { async function fetchHost() {
@@ -134,6 +145,7 @@ function DetailDataPengajuan({
async function sendWA({ status, linkSurat, linkUpdate }: { status: string, linkSurat: string, linkUpdate: string }) { async function sendWA({ status, linkSurat, linkUpdate }: { status: string, linkSurat: string, linkUpdate: string }) {
try { try {
setLoadingFS({ value: true, text: "Sending message to warga" })
const resWA = await apiFetch.api["send-wa"]["pengajuan-surat"].post({ const resWA = await apiFetch.api["send-wa"]["pengajuan-surat"].post({
noPengajuan: data?.noPengajuan ?? "", noPengajuan: data?.noPengajuan ?? "",
jenisSurat: data?.category ?? "", jenisSurat: data?.category ?? "",
@@ -151,6 +163,11 @@ function DetailDataPengajuan({
message: "Success send message to warga", message: "Success send message to warga",
type: "success", type: "success",
}); });
if (status == "selesai") {
onAction()
}
} else { } else {
notification({ notification({
title: "Failed", title: "Failed",
@@ -172,10 +189,14 @@ function DetailDataPengajuan({
type: "error", type: "error",
}); });
} }
finally {
setLoadingFS({ value: false, text: "" })
}
} }
const handleKonfirmasi = async (cat: "terima" | "tolak") => { const handleKonfirmasi = async (cat: "terima" | "tolak") => {
try { try {
setLoadingFS({ value: true, text: "Updating status" })
const statusFix = cat == "tolak" const statusFix = cat == "tolak"
? "ditolak" ? "ditolak"
: data.status == "antrian" : data.status == "antrian"
@@ -225,6 +246,8 @@ function DetailDataPengajuan({
message: "Failed to update pengajuan surat", message: "Failed to update pengajuan surat",
type: "error", type: "error",
}); });
} finally {
setLoadingFS({ value: false, text: "" })
} }
}; };
@@ -298,6 +321,8 @@ function DetailDataPengajuan({
return ( return (
<> <>
<FullScreenLoading visible={loadingFS.value} text={loadingFS.text} />
{/* MODAL EDIT DATA PELENGKAP */} {/* MODAL EDIT DATA PELENGKAP */}
<Modal <Modal
opened={openEdit} opened={openEdit}
@@ -365,6 +390,7 @@ function DetailDataPengajuan({
open={openedPreviewFile && !_.isEmpty(viewImg.file)} open={openedPreviewFile && !_.isEmpty(viewImg.file)}
onClose={() => { onClose={() => {
setOpenedPreviewFile(false); setOpenedPreviewFile(false);
setViewImg({ file: "", folder: "" })
}} }}
folder={viewImg.folder} folder={viewImg.folder}
fileName={viewImg.file} fileName={viewImg.file}
@@ -439,12 +465,14 @@ function DetailDataPengajuan({
)} )}
</Stack> </Stack>
</Modal> </Modal>
{/* MODAL PREVIEW SURAT */}
{data?.status == "selesai" && !data?.fileSurat && ( {data?.status == "selesai" && !data?.fileSurat && (
<ModalSurat <ModalSurat
open={openedPreview} open={openedPreview}
onClose={(val) => { onClose={(val) => {
setOpenedPreview(false) setOpenedPreview(false)
setUploading({ ok: true, file: val }) setUploading({ ok: val.success, file: val.data })
}} }}
surat={data?.idSurat} surat={data?.idSurat}
/> />
@@ -616,18 +644,31 @@ function DetailDataPengajuan({
Setujui Setujui
</Button> </Button>
</Group> </Group>
) : data?.status === "selesai" ? ( ) : data?.status === "selesai" ?
<Group justify="center" grow> !data?.fileSurat ?
<Button (
variant="light" <Group justify="center" grow>
onClick={() => { setViewImg({ file: data?.fileSurat, folder: "surat" }) }} <Button
> variant="light"
Surat onClick={() => { setOpenedPreview(true) }}
</Button> >
</Group> Kirim Ulang Surat
) : ( </Button>
<></> </Group>
)} )
:
(
<Group justify="center" grow>
<Button
variant="light"
onClick={() => { setViewImg({ file: data?.fileSurat, folder: "surat" }) }}
>
Surat
</Button>
</Group>
) : (
<></>
)}
</Grid.Col> </Grid.Col>
</Grid> </Grid>
</Stack> </Stack>

View File

@@ -1,3 +1,4 @@
import BreadCrumbs from "@/components/BreadCrumbs";
import ModalFile from "@/components/ModalFile"; import ModalFile from "@/components/ModalFile";
import notification from "@/components/notificationGlobal"; import notification from "@/components/notificationGlobal";
import apiFetch from "@/lib/apiFetch"; import apiFetch from "@/lib/apiFetch";
@@ -40,6 +41,11 @@ import useSwr from "swr";
export default function DetailPengaduanPage() { export default function DetailPengaduanPage() {
const dataMenu = [
{ title: "Dashboard", link: "/scr/dashboard/dashboard-home", active: false },
{ title: "Pengaduan", link: "/scr/dashboard/pengaduan/list", active: false },
{ title: "Detail Pengaduan", link: "#", active: true },
];
const { search } = useLocation(); const { search } = useLocation();
const query = new URLSearchParams(search); const query = new URLSearchParams(search);
const id = query.get("id"); const id = query.get("id");
@@ -58,6 +64,9 @@ export default function DetailPengaduanPage() {
return ( return (
<Container size="xl" py="xl" w={"100%"}> <Container size="xl" py="xl" w={"100%"}>
<Grid> <Grid>
<Grid.Col span={12}>
<BreadCrumbs dataLink={dataMenu} back />
</Grid.Col>
<Grid.Col span={8}> <Grid.Col span={8}>
<Stack gap={"xl"}> <Stack gap={"xl"}>
<DetailDataPengaduan <DetailDataPengaduan

View File

@@ -1,3 +1,4 @@
import BreadCrumbs from "@/components/BreadCrumbs";
import DesaSetting from "@/components/DesaSetting"; import DesaSetting from "@/components/DesaSetting";
import KategoriPelayananSurat from "@/components/KategoriPelayananSurat"; import KategoriPelayananSurat from "@/components/KategoriPelayananSurat";
import KategoriPengaduan from "@/components/KategoriPengaduan"; import KategoriPengaduan from "@/components/KategoriPengaduan";
@@ -15,14 +16,21 @@ import {
IconUsersGroup, IconUsersGroup,
} from "@tabler/icons-react"; } from "@tabler/icons-react";
import type { JsonValue } from "generated/prisma/runtime/library"; import type { JsonValue } from "generated/prisma/runtime/library";
import _ from "lodash";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { useLocation } from "react-router-dom"; import { useLocation, useNavigate } from "react-router-dom";
export default function DetailSettingPage() { export default function DetailSettingPage() {
const { search } = useLocation(); const { search } = useLocation();
const query = new URLSearchParams(search); const query = new URLSearchParams(search);
const type = query.get("type"); const type = query.get("type");
const navigate = useNavigate();
const [permissions, setPermissions] = useState<JsonValue[]>([]); const [permissions, setPermissions] = useState<JsonValue[]>([]);
const dataMenu = [
{ title: "Dashboard", link: "/scr/dashboard/dashboard-home", active: false },
{ title: "Setting", link: "#", active: false },
{ title: type == "cat-pengaduan" ? "Kategori Pengaduan" : type == "cat-pelayanan" ? "Kategori Pelayanan Surat" : type ? _.upperFirst(type) : "Profile", link: "#", active: true },
];
useEffect(() => { useEffect(() => {
async function fetchPermissions() { async function fetchPermissions() {
@@ -87,6 +95,9 @@ export default function DetailSettingPage() {
return ( return (
<Container size="xl" py="xl" w={"100%"}> <Container size="xl" py="xl" w={"100%"}>
<Grid> <Grid>
<Grid.Col span={12}>
<BreadCrumbs dataLink={dataMenu} back />
</Grid.Col>
<Grid.Col span={3}> <Grid.Col span={3}>
<Card <Card
radius="md" radius="md"
@@ -104,7 +115,7 @@ export default function DetailSettingPage() {
.map((item) => ( .map((item) => (
<NavLink <NavLink
key={item.key} key={item.key}
href={"?type=" + item.path} onClick={()=>{navigate("?type=" + item.path)}}
label={item.label} label={item.label}
leftSection={item.icon} leftSection={item.icon}
active={ active={

View File

@@ -1,3 +1,4 @@
import BreadCrumbs from "@/components/BreadCrumbs";
import notification from "@/components/notificationGlobal"; import notification from "@/components/notificationGlobal";
import apiFetch from "@/lib/apiFetch"; import apiFetch from "@/lib/apiFetch";
import { import {
@@ -26,6 +27,11 @@ import { useState } from "react";
import { useLocation, useNavigate } from "react-router-dom"; import { useLocation, useNavigate } from "react-router-dom";
export default function DetailWargaPage() { export default function DetailWargaPage() {
const dataMenu = [
{ title: "Dashboard", link: "/scr/dashboard/dashboard-home", active: false },
{ title: "Warga", link: "/scr/dashboard/warga/list-warga", active: false },
{ title: "Detail Warga", link: "#", active: true },
];
const { search } = useLocation(); const { search } = useLocation();
const query = new URLSearchParams(search); const query = new URLSearchParams(search);
const id = query.get("id"); const id = query.get("id");
@@ -50,6 +56,9 @@ export default function DetailWargaPage() {
/> />
<Container size="xl" py="xl" w={"100%"}> <Container size="xl" py="xl" w={"100%"}>
<Grid> <Grid>
<Grid.Col span={12}>
<BreadCrumbs dataLink={dataMenu} back />
</Grid.Col>
<Grid.Col span={4}> <Grid.Col span={4}>
<DetailWarga id={id!} /> <DetailWarga id={id!} />
</Grid.Col> </Grid.Col>

View File

@@ -685,17 +685,20 @@ const PelayananRoute = new Elysia({
name: string; name: string;
desc: string; desc: string;
key: string; key: string;
required: boolean;
}[]; }[];
const dataSyaratFix = dataSyarat.map((item) => { const dataSyaratFix = dataSyarat.map((item) => {
const desc = syaratDokumen.find((v) => v.key == item.jenis)?.desc const desc = syaratDokumen.find((v) => v.key == item.jenis)?.desc
const name = syaratDokumen.find((v) => v.key == item.jenis)?.name const name = syaratDokumen.find((v) => v.key == item.jenis)?.name
const required = syaratDokumen.find((v) => v.key == item.jenis)?.required
return { return {
id: item.id, id: item.id,
key: item.jenis, key: item.jenis,
value: item.value, value: item.value,
name: name ?? '', name: name ?? '',
desc: desc ?? '' desc: desc ?? '',
required: required ?? true
} }
}) })
@@ -708,6 +711,7 @@ const PelayananRoute = new Elysia({
name: string; name: string;
desc: string; desc: string;
key: string; key: string;
required: boolean;
}[]; }[];
const refMap = new Map( const refMap = new Map(
@@ -730,6 +734,7 @@ const PelayananRoute = new Elysia({
type: ref?.type ?? "", type: ref?.type ?? "",
options: ref?.options ?? [], options: ref?.options ?? [],
order: ref?.order ?? Infinity, order: ref?.order ?? Infinity,
required: ref?.required ?? true
}; };
}) })
.sort((a, b) => a.order - b.order) .sort((a, b) => a.order - b.order)