Compare commits
59 Commits
amalia/22-
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| d6abc163fb | |||
| 9c08980bf1 | |||
| a2af3fbe36 | |||
| ec8722ffba | |||
| b0752dac8d | |||
| a8d3a3a9ff | |||
| f86703e7d1 | |||
| d8bb33cc93 | |||
| 5807e98069 | |||
| 59b4f1d73f | |||
| 8bd552ac22 | |||
| 5d48d06513 | |||
| 3da163ea1d | |||
| 57e4f34eb6 | |||
| 3348cbe8e3 | |||
| 727984a076 | |||
| a7a0ad7e37 | |||
| 9fed41cbe8 | |||
| fc387fe8e6 | |||
| 80df579499 | |||
| 5bbbc15c27 | |||
| 82765f6ef0 | |||
| e8b5720118 | |||
| 01334ec573 | |||
| 98ad9b0d72 | |||
| c0471f47f3 | |||
| 3d641d2035 | |||
| 694115dbfb | |||
| 7de5078868 | |||
| 7a3faa5719 | |||
| ea5072d9ab | |||
| e8bb4f5a41 | |||
| d63bf024d3 | |||
| 46f7dbf7bb | |||
| 1adea29990 | |||
| 2a5b6e7b7c | |||
| 2117612337 | |||
| 8f33ec2ffa | |||
| 411f61ec15 | |||
| 476319945e | |||
| 8480cec6ae | |||
| 4ca5e4c4f3 | |||
| 75758bcbe6 | |||
| 2d336ea467 | |||
| 112e931bad | |||
| 487395bdb3 | |||
| 3944e1ee82 | |||
| a9b34547f0 | |||
| 211aac3d5f | |||
| 73a2a4367c | |||
| a01f394e43 | |||
| 7dde0a4eb9 | |||
| 6debbf8c64 | |||
| c074e2bc0a | |||
| bab832b87f | |||
| 8bafb88086 | |||
| 777f2c04f1 | |||
| a81f6c4255 | |||
| 0f1b0196e7 |
146
bak/ModalSurat.tsx.txt
Normal file
146
bak/ModalSurat.tsx.txt
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
import apiFetch from "@/lib/apiFetch";
|
||||||
|
import { ActionIcon, Flex, Modal } from "@mantine/core";
|
||||||
|
import { useShallowEffect } from "@mantine/hooks";
|
||||||
|
import { IconDownload, IconX } from "@tabler/icons-react";
|
||||||
|
import html2canvas from "html2canvas";
|
||||||
|
import jsPDF from "jspdf";
|
||||||
|
import { useRef } from "react";
|
||||||
|
import useSWR from "swr";
|
||||||
|
import SKBedaBiodataDiri from "./surat/SKBedaBiodataDiri";
|
||||||
|
import SKBelumKawin from "./surat/SKBelumKawin";
|
||||||
|
import SKDomisiliOrganisasi from "./surat/SKDomisiliOrganisasi";
|
||||||
|
import SKKelahiran from "./surat/SKKelahiran";
|
||||||
|
import SKKelakuanBaik from "./surat/SKKelakuanBaik";
|
||||||
|
import SKKematian from "./surat/SKKematian";
|
||||||
|
import SKPenghasilan from "./surat/SKPenghasilan";
|
||||||
|
import SKTempatUsaha from "./surat/SKTempatUsaha";
|
||||||
|
import SKTidakMampu from "./surat/SKTidakMampu";
|
||||||
|
import SKUsaha from "./surat/SKUsaha";
|
||||||
|
import SKYatim from "./surat/SKYatimPiatu";
|
||||||
|
|
||||||
|
export default function ModalSurat({
|
||||||
|
open,
|
||||||
|
onClose,
|
||||||
|
surat,
|
||||||
|
}: {
|
||||||
|
open: boolean;
|
||||||
|
onClose: () => void;
|
||||||
|
surat: string;
|
||||||
|
}) {
|
||||||
|
const A4Style = {
|
||||||
|
width: "210mm",
|
||||||
|
height: "297mm",
|
||||||
|
padding: "20mm",
|
||||||
|
background: "#fff",
|
||||||
|
color: "#000",
|
||||||
|
fontSize: "14px",
|
||||||
|
fontFamily: "Times New Roman",
|
||||||
|
};
|
||||||
|
const hiddenRef = useRef<any>(null);
|
||||||
|
const { data, mutate, isLoading } = useSWR("surat", () =>
|
||||||
|
apiFetch.api.surat.detail.get({
|
||||||
|
query: {
|
||||||
|
id: surat,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
useShallowEffect(() => {
|
||||||
|
mutate();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const downloadPDF = async () => {
|
||||||
|
const element = hiddenRef.current;
|
||||||
|
const canvas = await html2canvas(element, {
|
||||||
|
scale: 2,
|
||||||
|
useCORS: true,
|
||||||
|
allowTaint: true,
|
||||||
|
width: element.offsetWidth,
|
||||||
|
height: element.offsetHeight,
|
||||||
|
});
|
||||||
|
|
||||||
|
const imgData = canvas.toDataURL("image/jpeg", 1.0);
|
||||||
|
|
||||||
|
const pdf = new jsPDF("p", "mm", "a4");
|
||||||
|
const pageWidth = 210; // A4 width mm
|
||||||
|
const pageHeight = 297; // A4 height mm
|
||||||
|
|
||||||
|
const imgWidth = pageWidth;
|
||||||
|
const imgHeight = (canvas.height * pageWidth) / canvas.width;
|
||||||
|
|
||||||
|
pdf.addImage(imgData, "JPEG", 0, 0, imgWidth, imgHeight);
|
||||||
|
|
||||||
|
pdf.save(`${data?.data?.surat?.nameCategory}.pdf`);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Modal
|
||||||
|
opened={open}
|
||||||
|
onClose={() => onClose()}
|
||||||
|
overlayProps={{ backgroundOpacity: 0.55, blur: 3 }}
|
||||||
|
size="auto"
|
||||||
|
withCloseButton={false}
|
||||||
|
removeScrollProps={{ allowPinchZoom: true }}
|
||||||
|
styles={{
|
||||||
|
header: {
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
alignItems: "center",
|
||||||
|
padding: "12px 16px",
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
width: "100%",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
title={
|
||||||
|
<Flex justify="space-between" align="center" w="100%">
|
||||||
|
<div style={{ fontSize: 18, fontWeight: 600 }}>Preview Surat</div>
|
||||||
|
|
||||||
|
<Flex gap={8}>
|
||||||
|
<ActionIcon size={32} variant="default">
|
||||||
|
<IconDownload size={20} onClick={downloadPDF} />
|
||||||
|
</ActionIcon>
|
||||||
|
|
||||||
|
<ActionIcon size={32} variant="default" onClick={onClose}>
|
||||||
|
<IconX size={20} />
|
||||||
|
</ActionIcon>
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div ref={hiddenRef} style={A4Style}>
|
||||||
|
{data && data.data ? (
|
||||||
|
data.data.surat.idCategory == "skusaha" ? (
|
||||||
|
<SKUsaha data={data.data} />
|
||||||
|
) : data.data.surat.idCategory == "skkelahiran" ? (
|
||||||
|
<SKKelahiran data={data.data} />
|
||||||
|
) : data.data.surat.idCategory == "skkelakuanbaik" ? (
|
||||||
|
<SKKelakuanBaik data={data.data} />
|
||||||
|
) : data.data.surat.idCategory == "skpenghasilan" ? (
|
||||||
|
<SKPenghasilan data={data.data} />
|
||||||
|
) : data.data.surat.idCategory == "sktidakmampu" ? (
|
||||||
|
<SKTidakMampu data={data.data} />
|
||||||
|
) : data.data.surat.idCategory == "skyatimpiatu" ? (
|
||||||
|
<SKYatim data={data.data} />
|
||||||
|
) : data.data.surat.idCategory == "skdomisiliorganisasi" ? (
|
||||||
|
<SKDomisiliOrganisasi data={data.data} />
|
||||||
|
) : data.data.surat.idCategory == "skbedabiodata" ? (
|
||||||
|
<SKBedaBiodataDiri data={data.data} />
|
||||||
|
) : data.data.surat.idCategory == "sktempatusaha" ? (
|
||||||
|
<SKTempatUsaha data={data.data} />
|
||||||
|
) : data.data.surat.idCategory == "skbelumkawin" ? (
|
||||||
|
<SKBelumKawin data={data.data} />
|
||||||
|
) : data.data.surat.idCategory == "skkematian" ? (
|
||||||
|
<SKKematian data={data.data} />
|
||||||
|
) : (
|
||||||
|
<></>
|
||||||
|
)
|
||||||
|
) : (
|
||||||
|
<></>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
310
bak/listPermission.json.txt
Normal file
310
bak/listPermission.json.txt
Normal file
@@ -0,0 +1,310 @@
|
|||||||
|
{
|
||||||
|
"menus": [
|
||||||
|
{
|
||||||
|
"key": "dashboard",
|
||||||
|
"label": "Dashboard",
|
||||||
|
"default": true,
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"key": "dashboard.view",
|
||||||
|
"label": "Melihat Dashboard",
|
||||||
|
"default": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "pengaduan",
|
||||||
|
"label": "Pengaduan",
|
||||||
|
"default": true,
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"key": "pengaduan.view",
|
||||||
|
"label": "Melihat List & Detail",
|
||||||
|
"default": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "pengaduan.antrian",
|
||||||
|
"label": "Detail pengaduan dengan status antrian",
|
||||||
|
"default": true,
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"key": "pengaduan.antrian.tolak",
|
||||||
|
"label": "Menolak pengaduan",
|
||||||
|
"default": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "pengaduan.antrian.terima",
|
||||||
|
"label": "Menerima pengaduan",
|
||||||
|
"default": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "pengaduan.diterima",
|
||||||
|
"label": "Detail pengaduan dengan status diterima",
|
||||||
|
"default": true,
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"key": "pengaduan.diterima.dikerjakan",
|
||||||
|
"label": "Menegerjakan pengaduan",
|
||||||
|
"default": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "pengaduan.dikerjakan",
|
||||||
|
"label": "Detail pengaduan dengan status dikerjakan",
|
||||||
|
"default": true,
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"key": "pengaduan.dikerjakan.selesai",
|
||||||
|
"label": "Menyelesaikan pengaduan",
|
||||||
|
"default": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "pelayanan",
|
||||||
|
"label": "Pelayanan",
|
||||||
|
"default": true,
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"key": "pelayanan.view",
|
||||||
|
"label": "Melihat List & Detail",
|
||||||
|
"default": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "pelayanan.antrian",
|
||||||
|
"label": "Detail pelayanan dengan status antrian",
|
||||||
|
"default": true,
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"key": "pelayanan.antrian.tolak",
|
||||||
|
"label": "Menolak pelayanan",
|
||||||
|
"default": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "pelayanan.antrian.terima",
|
||||||
|
"label": "Menerima pelayanan",
|
||||||
|
"default": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "pelayanan.diterima",
|
||||||
|
"label": "Detail pelayanan dengan status diterima",
|
||||||
|
"default": true,
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"key": "pelayanan.diterima.tolak",
|
||||||
|
"label": "Menolak pelayanan",
|
||||||
|
"default": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "pelayanan.diterima.setujui",
|
||||||
|
"label": "Menyetujui pelayanan",
|
||||||
|
"default": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "warga",
|
||||||
|
"label": "Warga",
|
||||||
|
"default": true,
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"key": "warga.view",
|
||||||
|
"label": "Melihat List & Detail",
|
||||||
|
"default": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "setting",
|
||||||
|
"label": "Setting",
|
||||||
|
"default": true,
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"key": "setting.profile",
|
||||||
|
"label": "Profile",
|
||||||
|
"default": true,
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"key": "setting.profile.view",
|
||||||
|
"label": "View",
|
||||||
|
"default": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "setting.profile.edit",
|
||||||
|
"label": "Edit",
|
||||||
|
"default": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "setting.profile.password",
|
||||||
|
"label": "Ubah Password",
|
||||||
|
"default": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "setting.user",
|
||||||
|
"label": "User",
|
||||||
|
"default": true,
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"key": "setting.user.view",
|
||||||
|
"label": "View List",
|
||||||
|
"default": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "setting.user.tambah",
|
||||||
|
"label": "Tambah",
|
||||||
|
"default": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "setting.user.edit",
|
||||||
|
"label": "Edit",
|
||||||
|
"default": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "setting.user.delete",
|
||||||
|
"label": "Delete",
|
||||||
|
"default": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "setting.user_role",
|
||||||
|
"label": "User Role",
|
||||||
|
"default": true,
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"key": "setting.user_role.view",
|
||||||
|
"label": "View List",
|
||||||
|
"default": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "setting.user_role.tambah",
|
||||||
|
"label": "Tambah",
|
||||||
|
"default": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "setting.user_role.edit",
|
||||||
|
"label": "Edit",
|
||||||
|
"default": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "setting.user_role.delete",
|
||||||
|
"label": "Delete",
|
||||||
|
"default": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "setting.kategori_pengaduan",
|
||||||
|
"label": "Kategori Pengaduan",
|
||||||
|
"default": true,
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"key": "setting.kategori_pengaduan.view",
|
||||||
|
"label": "View List",
|
||||||
|
"default": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "setting.kategori_pengaduan.tambah",
|
||||||
|
"label": "Tambah",
|
||||||
|
"default": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "setting.kategori_pengaduan.edit",
|
||||||
|
"label": "Edit",
|
||||||
|
"default": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "setting.kategori_pengaduan.delete",
|
||||||
|
"label": "Delete",
|
||||||
|
"default": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "setting.kategori_pelayanan",
|
||||||
|
"label": "Kategori Pelayanan Surat",
|
||||||
|
"default": true,
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"key": "setting.kategori_pelayanan.view",
|
||||||
|
"label": "View List",
|
||||||
|
"default": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "setting.kategori_pelayanan.detail",
|
||||||
|
"label": "View Detail",
|
||||||
|
"default": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "setting.kategori_pelayanan.tambah",
|
||||||
|
"label": "Tambah",
|
||||||
|
"default": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "setting.kategori_pelayanan.edit",
|
||||||
|
"label": "Edit",
|
||||||
|
"default": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "setting.kategori_pelayanan.delete",
|
||||||
|
"label": "Delete",
|
||||||
|
"default": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "setting.desa",
|
||||||
|
"label": "Desa",
|
||||||
|
"default": true,
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"key": "setting.desa.view",
|
||||||
|
"label": "View List",
|
||||||
|
"default": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "setting.desa.edit",
|
||||||
|
"label": "Edit",
|
||||||
|
"default": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "api_key",
|
||||||
|
"label": "API Key",
|
||||||
|
"default": true,
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"key": "api_key.view",
|
||||||
|
"label": "View List",
|
||||||
|
"default": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "credential",
|
||||||
|
"label": "Credential",
|
||||||
|
"default": true,
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"key": "credential.view",
|
||||||
|
"label": "View List",
|
||||||
|
"default": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
1
bun.lock
1
bun.lock
@@ -22,6 +22,7 @@
|
|||||||
"@types/lodash": "^4.17.20",
|
"@types/lodash": "^4.17.20",
|
||||||
"@types/uuid": "^11.0.0",
|
"@types/uuid": "^11.0.0",
|
||||||
"add": "^2.0.6",
|
"add": "^2.0.6",
|
||||||
|
"dayjs": "^1.11.19",
|
||||||
"echarts": "^6.0.0",
|
"echarts": "^6.0.0",
|
||||||
"echarts-for-react": "^3.0.5",
|
"echarts-for-react": "^3.0.5",
|
||||||
"elysia": "^1.4.15",
|
"elysia": "^1.4.15",
|
||||||
|
|||||||
@@ -28,6 +28,7 @@
|
|||||||
"@types/lodash": "^4.17.20",
|
"@types/lodash": "^4.17.20",
|
||||||
"@types/uuid": "^11.0.0",
|
"@types/uuid": "^11.0.0",
|
||||||
"add": "^2.0.6",
|
"add": "^2.0.6",
|
||||||
|
"dayjs": "^1.11.19",
|
||||||
"echarts": "^6.0.0",
|
"echarts": "^6.0.0",
|
||||||
"echarts-for-react": "^3.0.5",
|
"echarts-for-react": "^3.0.5",
|
||||||
"elysia": "^1.4.15",
|
"elysia": "^1.4.15",
|
||||||
|
|||||||
@@ -187,6 +187,7 @@ model SuratPelayanan {
|
|||||||
Warga Warga @relation(fields: [idWarga], references: [id])
|
Warga Warga @relation(fields: [idWarga], references: [id])
|
||||||
idWarga String
|
idWarga String
|
||||||
noSurat String
|
noSurat String
|
||||||
|
file String?
|
||||||
dateExpired DateTime? @db.Date
|
dateExpired DateTime? @db.Date
|
||||||
status Int @default(0)
|
status Int @default(0)
|
||||||
isActive Boolean @default(true)
|
isActive Boolean @default(true)
|
||||||
|
|||||||
44
src/components/BreadCrumbs.tsx
Normal file
44
src/components/BreadCrumbs.tsx
Normal 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>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -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>
|
||||||
|
|||||||
@@ -4,9 +4,7 @@ import {
|
|||||||
Button,
|
Button,
|
||||||
Divider,
|
Divider,
|
||||||
Flex,
|
Flex,
|
||||||
Grid,
|
|
||||||
Group,
|
Group,
|
||||||
Input,
|
|
||||||
List,
|
List,
|
||||||
Modal,
|
Modal,
|
||||||
Stack,
|
Stack,
|
||||||
@@ -16,7 +14,7 @@ import {
|
|||||||
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";
|
||||||
@@ -190,7 +188,10 @@ export default function KategoriPelayananSurat({
|
|||||||
function handleAddSyarat() {
|
function handleAddSyarat() {
|
||||||
setDataChoose({
|
setDataChoose({
|
||||||
...dataChoose,
|
...dataChoose,
|
||||||
syaratDokumen: [...dataChoose.syaratDokumen, { key: "", name: "", desc: "" }],
|
syaratDokumen: [
|
||||||
|
...dataChoose.syaratDokumen,
|
||||||
|
{ key: "", name: "", desc: "" },
|
||||||
|
],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,7 +217,7 @@ export default function KategoriPelayananSurat({
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{/* Modal Edit */}
|
{/* Modal Edit */}
|
||||||
<Modal
|
{/* <Modal
|
||||||
opened={opened}
|
opened={opened}
|
||||||
onClose={close}
|
onClose={close}
|
||||||
title={"Edit"}
|
title={"Edit"}
|
||||||
@@ -232,15 +233,85 @@ export default function KategoriPelayananSurat({
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</Input.Wrapper>
|
</Input.Wrapper>
|
||||||
{/* <TagsInput
|
<Flex direction={"column"} gap={"md"}>
|
||||||
label="Data Pelengkap"
|
<Group>
|
||||||
placeholder="Tambah data pelengkap"
|
<Text size="sm" c={"white"}>
|
||||||
splitChars={[","]}
|
Data Pelengkap
|
||||||
value={dataChoose.dataPelengkap}
|
</Text>
|
||||||
onChange={(value) =>
|
<Tooltip label="Tambah Data Pelengkap">
|
||||||
setDataChoose({ ...dataChoose, dataPelengkap: value })
|
<ActionIcon
|
||||||
}
|
variant="light"
|
||||||
/> */}
|
size="sm"
|
||||||
|
color="blue"
|
||||||
|
style={{ boxShadow: "0 0 8px rgba(0,255,200,0.2)" }}
|
||||||
|
onClick={handleAddSyarat}
|
||||||
|
>
|
||||||
|
<IconPlus size={20} />
|
||||||
|
</ActionIcon>
|
||||||
|
</Tooltip>
|
||||||
|
</Group>
|
||||||
|
{dataChoose?.dataPelengkap?.map((v: any, i: number) => (
|
||||||
|
<Grid
|
||||||
|
key={i}
|
||||||
|
style={{
|
||||||
|
borderBottom: "1px solid gray",
|
||||||
|
paddingBottom: "10px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Grid.Col
|
||||||
|
span={1}
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Tooltip label="Delete Syarat Dokumen">
|
||||||
|
<ActionIcon
|
||||||
|
variant="light"
|
||||||
|
size="sm"
|
||||||
|
color="red"
|
||||||
|
style={{ boxShadow: "0 0 8px rgba(0,255,200,0.2)" }}
|
||||||
|
onClick={() => {
|
||||||
|
handleDeleteSyarat(i);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<IconTrash size={20} />
|
||||||
|
</ActionIcon>
|
||||||
|
</Tooltip>
|
||||||
|
</Grid.Col>
|
||||||
|
<Grid.Col span={5}>
|
||||||
|
<Input.Wrapper label="Label">
|
||||||
|
<Input
|
||||||
|
value={v.name}
|
||||||
|
onChange={(e) =>
|
||||||
|
handleEditSyarat(i, {
|
||||||
|
key: v.key,
|
||||||
|
name: e.target.value,
|
||||||
|
desc: v.desc,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Input.Wrapper>
|
||||||
|
</Grid.Col>
|
||||||
|
<Grid.Col span={6}>
|
||||||
|
<Input.Wrapper label="Deskripsi">
|
||||||
|
<Input
|
||||||
|
value={v.desc}
|
||||||
|
onChange={(e) =>
|
||||||
|
handleEditSyarat(i, {
|
||||||
|
key: v.key,
|
||||||
|
name: v.name,
|
||||||
|
desc: e.target.value,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Input.Wrapper>
|
||||||
|
</Grid.Col>
|
||||||
|
</Grid>
|
||||||
|
))}
|
||||||
|
</Flex>
|
||||||
|
|
||||||
<Flex direction={"column"} gap={"md"}>
|
<Flex direction={"column"} gap={"md"}>
|
||||||
<Group>
|
<Group>
|
||||||
<Text size="sm" c={"white"}>
|
<Text size="sm" c={"white"}>
|
||||||
@@ -289,7 +360,7 @@ export default function KategoriPelayananSurat({
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
</Grid.Col>
|
</Grid.Col>
|
||||||
<Grid.Col span={5}>
|
<Grid.Col span={5}>
|
||||||
<Input.Wrapper label="Nama">
|
<Input.Wrapper label="Label">
|
||||||
<Input
|
<Input
|
||||||
value={v.name}
|
value={v.name}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
@@ -329,10 +400,10 @@ export default function KategoriPelayananSurat({
|
|||||||
</Button>
|
</Button>
|
||||||
</Group>
|
</Group>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Modal>
|
</Modal> */}
|
||||||
|
|
||||||
{/* Modal Tambah */}
|
{/* Modal Tambah */}
|
||||||
<Modal
|
{/* <Modal
|
||||||
opened={openedTambah}
|
opened={openedTambah}
|
||||||
onClose={closeTambah}
|
onClose={closeTambah}
|
||||||
title={"Tambah"}
|
title={"Tambah"}
|
||||||
@@ -348,15 +419,6 @@ export default function KategoriPelayananSurat({
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</Input.Wrapper>
|
</Input.Wrapper>
|
||||||
{/* <TagsInput
|
|
||||||
label="Data Pelengkap"
|
|
||||||
placeholder="Tambah data pelengkap"
|
|
||||||
splitChars={[","]}
|
|
||||||
value={dataTambah.dataText}
|
|
||||||
onChange={(value) =>
|
|
||||||
setDataTambah({ ...dataTambah, dataText: value })
|
|
||||||
}
|
|
||||||
/> */}
|
|
||||||
<Flex direction={"column"} gap={"md"}>
|
<Flex direction={"column"} gap={"md"}>
|
||||||
<Group>
|
<Group>
|
||||||
<Text size="sm" c={"white"}>
|
<Text size="sm" c={"white"}>
|
||||||
@@ -466,7 +528,7 @@ export default function KategoriPelayananSurat({
|
|||||||
</Button>
|
</Button>
|
||||||
</Group>
|
</Group>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Modal>
|
</Modal> */}
|
||||||
|
|
||||||
{/* Modal Delete */}
|
{/* Modal Delete */}
|
||||||
<Modal
|
<Modal
|
||||||
@@ -539,7 +601,7 @@ export default function KategoriPelayananSurat({
|
|||||||
<Title order={4} c="gray.2">
|
<Title order={4} c="gray.2">
|
||||||
Kategori Pelayanan Surat
|
Kategori Pelayanan Surat
|
||||||
</Title>
|
</Title>
|
||||||
{permissions.includes("setting.kategori_pelayanan.tambah") && (
|
{/* {permissions.includes("setting.kategori_pelayanan.tambah") && (
|
||||||
<Tooltip label="Tambah Kategori Pelayanan Surat">
|
<Tooltip label="Tambah Kategori Pelayanan Surat">
|
||||||
<Button
|
<Button
|
||||||
variant="light"
|
variant="light"
|
||||||
@@ -549,7 +611,7 @@ export default function KategoriPelayananSurat({
|
|||||||
Tambah
|
Tambah
|
||||||
</Button>
|
</Button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)}
|
)} */}
|
||||||
</Flex>
|
</Flex>
|
||||||
<Divider my={0} />
|
<Divider my={0} />
|
||||||
<Stack gap={"md"}>
|
<Stack gap={"md"}>
|
||||||
@@ -561,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>
|
||||||
@@ -580,7 +642,7 @@ export default function KategoriPelayananSurat({
|
|||||||
<IconEye size={20} />
|
<IconEye size={20} />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip
|
{/* <Tooltip
|
||||||
label={
|
label={
|
||||||
permissions.includes(
|
permissions.includes(
|
||||||
"setting.kategori_pelayanan.edit",
|
"setting.kategori_pelayanan.edit",
|
||||||
@@ -605,7 +667,7 @@ export default function KategoriPelayananSurat({
|
|||||||
>
|
>
|
||||||
<IconEdit size={20} />
|
<IconEdit size={20} />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
</Tooltip>
|
</Tooltip> */}
|
||||||
<Tooltip
|
<Tooltip
|
||||||
label={
|
label={
|
||||||
permissions.includes(
|
permissions.includes(
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
import apiFetch from "@/lib/apiFetch";
|
import apiFetch from "@/lib/apiFetch";
|
||||||
import { ActionIcon, Flex, Modal } from "@mantine/core";
|
import { Flex, Modal, Progress, Stack, Text } from "@mantine/core";
|
||||||
import { useShallowEffect } from "@mantine/hooks";
|
import { useShallowEffect } from "@mantine/hooks";
|
||||||
import { IconDownload, IconX } from "@tabler/icons-react";
|
|
||||||
import html2canvas from "html2canvas";
|
import html2canvas from "html2canvas";
|
||||||
import jsPDF from "jspdf";
|
import jsPDF from "jspdf";
|
||||||
import { useRef } from "react";
|
import { useRef, useState } from "react";
|
||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
import SKBedaBiodataDiri from "./surat/SKBedaBiodataDiri";
|
import SKBedaBiodataDiri from "./surat/SKBedaBiodataDiri";
|
||||||
import SKBelumKawin from "./surat/SKBelumKawin";
|
import SKBelumKawin from "./surat/SKBelumKawin";
|
||||||
@@ -24,7 +23,7 @@ export default function ModalSurat({
|
|||||||
surat,
|
surat,
|
||||||
}: {
|
}: {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
onClose: () => void;
|
onClose: (val: { success: boolean, data: string }) => void;
|
||||||
surat: string;
|
surat: string;
|
||||||
}) {
|
}) {
|
||||||
const A4Style = {
|
const A4Style = {
|
||||||
@@ -36,6 +35,7 @@ export default function ModalSurat({
|
|||||||
fontSize: "14px",
|
fontSize: "14px",
|
||||||
fontFamily: "Times New Roman",
|
fontFamily: "Times New Roman",
|
||||||
};
|
};
|
||||||
|
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,42 +45,97 @@ export default function ModalSurat({
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
useShallowEffect(() => {
|
useShallowEffect(() => {
|
||||||
mutate();
|
mutate();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const downloadPDF = async () => {
|
const uploadPdf = async () => {
|
||||||
const element = hiddenRef.current;
|
try {
|
||||||
const canvas = await html2canvas(element, {
|
if (data && data.data && data.data.surat && (data.data.surat.file == "" || data.data.surat.file == null)) {
|
||||||
scale: 2,
|
setUploading({ text: "Mengupload", value: 75 });
|
||||||
useCORS: true,
|
const element = hiddenRef.current;
|
||||||
allowTaint: true,
|
const canvas = await html2canvas(element, {
|
||||||
width: element.offsetWidth,
|
scale: 2,
|
||||||
height: element.offsetHeight,
|
useCORS: true,
|
||||||
});
|
allowTaint: true,
|
||||||
|
width: element.offsetWidth,
|
||||||
|
height: element.offsetHeight,
|
||||||
|
});
|
||||||
|
|
||||||
const imgData = canvas.toDataURL("image/jpeg", 1.0);
|
const imgData = canvas.toDataURL("image/jpeg", 1.0);
|
||||||
|
|
||||||
const pdf = new jsPDF("p", "mm", "a4");
|
const pdf = new jsPDF("p", "mm", "a4");
|
||||||
const pageWidth = 210; // A4 width mm
|
const pageWidth = 210; // A4 width mm
|
||||||
const pageHeight = 297; // A4 height mm
|
const pageHeight = 297; // A4 height mm
|
||||||
|
|
||||||
const imgWidth = pageWidth;
|
const imgWidth = pageWidth;
|
||||||
const imgHeight = (canvas.height * pageWidth) / canvas.width;
|
const imgHeight = (canvas.height * pageWidth) / canvas.width;
|
||||||
|
|
||||||
pdf.addImage(imgData, "JPEG", 0, 0, imgWidth, imgHeight);
|
pdf.addImage(imgData, "JPEG", 0, 0, imgWidth, imgHeight);
|
||||||
|
|
||||||
pdf.save(`${data?.data?.surat?.nameCategory}.pdf`);
|
// ⬇️ ambil sebagai Blob
|
||||||
};
|
const pdfBlob = pdf.output("blob");
|
||||||
|
|
||||||
|
const pdfFile = new File(
|
||||||
|
[pdfBlob],
|
||||||
|
`${data?.data?.surat?.nameCategory}.pdf`,
|
||||||
|
{
|
||||||
|
type: "application/pdf",
|
||||||
|
lastModified: Date.now(),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const resImg = await apiFetch.api.pengaduan.upload.post({
|
||||||
|
file: pdfFile,
|
||||||
|
folder: "surat",
|
||||||
|
});
|
||||||
|
|
||||||
|
const resUpdate = await apiFetch.api.surat.update.post({
|
||||||
|
id: surat,
|
||||||
|
filename: resImg.data?.filename!,
|
||||||
|
});
|
||||||
|
|
||||||
|
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(() => {
|
||||||
|
onClose({ success: false, data: "" });
|
||||||
|
}, 1000)
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error uploading PDF:", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useShallowEffect(() => {
|
||||||
|
if (open) {
|
||||||
|
setTimeout(() => {
|
||||||
|
uploadPdf();
|
||||||
|
}, 3000);
|
||||||
|
}
|
||||||
|
}, [surat, open]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Modal
|
<Modal
|
||||||
opened={open}
|
opened={open}
|
||||||
onClose={() => onClose()}
|
onClose={() => { }}
|
||||||
overlayProps={{ backgroundOpacity: 0.55, blur: 3 }}
|
overlayProps={{ backgroundOpacity: 0.55, blur: 3 }}
|
||||||
size="auto"
|
size="auto"
|
||||||
withCloseButton={false}
|
withCloseButton={false}
|
||||||
|
closeOnClickOutside={false}
|
||||||
removeScrollProps={{ allowPinchZoom: true }}
|
removeScrollProps={{ allowPinchZoom: true }}
|
||||||
styles={{
|
styles={{
|
||||||
header: {
|
header: {
|
||||||
@@ -94,19 +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}>
|
{/* <Flex gap={8} align="center">
|
||||||
<ActionIcon size={32} variant="default">
|
<Loader color="blue" size="xs" />
|
||||||
<IconDownload size={20} onClick={downloadPDF} />
|
<Text size="sm">{uploading.text}</Text>
|
||||||
</ActionIcon>
|
</Flex> */}
|
||||||
|
|
||||||
<ActionIcon size={32} variant="default" onClick={onClose}>
|
|
||||||
<IconX size={20} />
|
|
||||||
</ActionIcon>
|
|
||||||
</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}>
|
||||||
|
|||||||
45
src/components/NotFoundPengajuanSurat.tsx
Normal file
45
src/components/NotFoundPengajuanSurat.tsx
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
import { Button, Center, Group, Stack, Text, Title } from "@mantine/core";
|
||||||
|
import { IconSearch } from "@tabler/icons-react";
|
||||||
|
|
||||||
|
export function DataNotFound({
|
||||||
|
onRetry,
|
||||||
|
backTo,
|
||||||
|
}: {
|
||||||
|
onRetry?: () => void;
|
||||||
|
backTo?: () => void;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<Center mih={320}>
|
||||||
|
<Stack align="center" gap="sm">
|
||||||
|
<IconSearch size={64} opacity={0.5} />
|
||||||
|
|
||||||
|
<Title order={4}>Data Pengajuan Tidak Ditemukan</Title>
|
||||||
|
|
||||||
|
<Text size="sm" c="dimmed" ta="center" maw={380}>
|
||||||
|
Kami tidak dapat menemukan data pengajuan dengan nomor pengajuan yg
|
||||||
|
diinputkan. Silakan periksa kembali data Anda.
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
<Group mt="md">
|
||||||
|
{/* {onRetry && (
|
||||||
|
<Button
|
||||||
|
variant="light"
|
||||||
|
leftSection={<IconSearch size={16} />}
|
||||||
|
onClick={onRetry}
|
||||||
|
>
|
||||||
|
Cari Ulang
|
||||||
|
</Button>
|
||||||
|
)} */}
|
||||||
|
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
// leftSection={<IconArrowLeft size={16} />}
|
||||||
|
onClick={backTo}
|
||||||
|
>
|
||||||
|
Cari Kembali
|
||||||
|
</Button>
|
||||||
|
</Group>
|
||||||
|
</Stack>
|
||||||
|
</Center>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -4,13 +4,13 @@ import { IconCheck } from "@tabler/icons-react";
|
|||||||
type SuccessPengajuanProps = {
|
type SuccessPengajuanProps = {
|
||||||
noPengajuan: string;
|
noPengajuan: string;
|
||||||
onClose?: () => void;
|
onClose?: () => void;
|
||||||
category?: 'create' | 'update';
|
category?: "create" | "update";
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function SuccessPengajuan({
|
export default function SuccessPengajuan({
|
||||||
noPengajuan,
|
noPengajuan,
|
||||||
onClose,
|
onClose,
|
||||||
category
|
category,
|
||||||
}: SuccessPengajuanProps) {
|
}: SuccessPengajuanProps) {
|
||||||
return (
|
return (
|
||||||
<Center h="100vh">
|
<Center h="100vh">
|
||||||
@@ -19,11 +19,15 @@ export default function SuccessPengajuan({
|
|||||||
<IconCheck size={56} color="green" />
|
<IconCheck size={56} color="green" />
|
||||||
|
|
||||||
<Title order={3} ta="center">
|
<Title order={3} ta="center">
|
||||||
{category == 'create' ? 'Pengajuan Berhasil Dibuat' : 'Pengajuan Berhasil Diupdate'}
|
{category == "create"
|
||||||
|
? "Pengajuan Berhasil Dibuat"
|
||||||
|
: "Pengajuan Berhasil Diupdate"}
|
||||||
</Title>
|
</Title>
|
||||||
|
|
||||||
<Text ta="center" size="sm" c="dimmed">
|
<Text ta="center" size="sm" c="dimmed">
|
||||||
{category == 'create' ? 'Pengajuan layanan surat sudah dibuat dengan nomor:' : 'Pengajuan layanan surat sudah diupdate dengan nomor:'}
|
{category == "create"
|
||||||
|
? "Pengajuan layanan surat sudah dibuat dengan nomor:"
|
||||||
|
: "Pengajuan layanan surat sudah diupdate dengan nomor:"}
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<Badge size="xl" variant="light" color="green">
|
<Badge size="xl" variant="light" color="green">
|
||||||
|
|||||||
@@ -108,12 +108,12 @@ export default function SKBedaBiodataDiri({ data }: { data: any }) {
|
|||||||
<tr>
|
<tr>
|
||||||
<td>Tempat/Tanggal Lahir</td>
|
<td>Tempat/Tanggal Lahir</td>
|
||||||
<td>:</td>
|
<td>:</td>
|
||||||
<td>{getValue("tempat tanggal lahir")}</td>
|
<td>{`${getValue("tempat_lahir")}, ${getValue("tanggal_lahir")}`}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Jenis Kelamin</td>
|
<td>Jenis Kelamin</td>
|
||||||
<td>:</td>
|
<td>:</td>
|
||||||
<td>{getValue("jenis kelamin")}</td>
|
<td>{getValue("jenis_kelamin")}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Alamat</td>
|
<td>Alamat</td>
|
||||||
@@ -144,36 +144,36 @@ export default function SKBedaBiodataDiri({ data }: { data: any }) {
|
|||||||
<table style={{ width: "100%", marginTop: "5px" }}>
|
<table style={{ width: "100%", marginTop: "5px" }}>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td style={{ width: "160px" }}>1. Nama</td>
|
<td style={{ width: "160px" }}>1. {getValue("data_dokumen")}</td>
|
||||||
<td style={{ width: "10px" }}>:</td>
|
<td style={{ width: "10px" }}></td>
|
||||||
<td>{getValue("nama")}</td>
|
<td>{/* {getValue("nama")} */}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Tertulis pada dokumen A</td>
|
<td>Tertulis pada dokumen A</td>
|
||||||
<td>:</td>
|
<td>:</td>
|
||||||
<td>{getValue("tertulis pada dokumen a")}</td>
|
<td>{getValue("dokumen_a")}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Tertulis pada dokumen B</td>
|
<td>Tertulis pada dokumen B</td>
|
||||||
<td>:</td>
|
<td>:</td>
|
||||||
<td>{getValue("tertulis pada dokumen b")}</td>
|
<td>{getValue("dokumen_b")}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style={{ marginTop: "15px" }}>
|
{/* <div style={{ marginTop: "15px" }}>
|
||||||
<table style={{ width: "100%", marginTop: "5px" }}>
|
<table style={{ width: "100%", marginTop: "5px" }}>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td style={{ width: "160px" }}>2. Tempat/Tanggal Lahir</td>
|
<td style={{ width: "160px" }}>2. Tempat/Tanggal Lahir</td>
|
||||||
<td style={{ width: "10px" }}>:</td>
|
<td style={{ width: "10px" }}>:</td>
|
||||||
<td>{getValue("tempat tanggal lahir")}</td>
|
<td>{getValue("tempat_lahir")}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Tertulis pada dokumen A</td>
|
<td>Tertulis pada dokumen A</td>
|
||||||
<td>:</td>
|
<td>:</td>
|
||||||
<td>{getValue("tertulis pada dokumen a")}</td>
|
<td>{getValue("dokumen_a")}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Tertulis pada dokumen B</td>
|
<td>Tertulis pada dokumen B</td>
|
||||||
@@ -204,7 +204,7 @@ export default function SKBedaBiodataDiri({ data }: { data: any }) {
|
|||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div> */}
|
||||||
|
|
||||||
<div style={{ marginTop: "15px" }}>
|
<div style={{ marginTop: "15px" }}>
|
||||||
Perbedaan tersebut terjadi karena{" "}
|
Perbedaan tersebut terjadi karena{" "}
|
||||||
|
|||||||
@@ -87,12 +87,12 @@ export default function SKBelumKawin({ data }: { data: any }) {
|
|||||||
<tr>
|
<tr>
|
||||||
<td>Tempat/Tanggal Lahir</td>
|
<td>Tempat/Tanggal Lahir</td>
|
||||||
<td>:</td>
|
<td>:</td>
|
||||||
<td>{getValue("tempat tanggal lahir")}</td>
|
<td>{`${getValue("tempat_lahir")}, ${getValue("tanggal_lahir")}`}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Jenis Kelamin</td>
|
<td>Jenis Kelamin</td>
|
||||||
<td>:</td>
|
<td>:</td>
|
||||||
<td>{getValue("jenis kelamin")}</td>
|
<td>{getValue("jenis_kelamin")}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Agama</td>
|
<td>Agama</td>
|
||||||
|
|||||||
@@ -95,27 +95,27 @@ export default function SKDomisiliOrganisasi({ data }: { data: any }) {
|
|||||||
<tr>
|
<tr>
|
||||||
<td style={{ width: "160px" }}>Nama Organisasi</td>
|
<td style={{ width: "160px" }}>Nama Organisasi</td>
|
||||||
<td style={{ width: "10px" }}>:</td>
|
<td style={{ width: "10px" }}>:</td>
|
||||||
<td>{getValue("nama")}</td>
|
<td>{getValue("nama_organisasi")}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Jenis Organisasi</td>
|
<td>Jenis Organisasi</td>
|
||||||
<td>:</td>
|
<td>:</td>
|
||||||
<td>{getValue("jenis kelamin")}</td>
|
<td>{getValue("jenis_organisasi")}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Alamat</td>
|
<td>Alamat</td>
|
||||||
<td>:</td>
|
<td>:</td>
|
||||||
<td>{getValue("tempat tanggal lahir")}</td>
|
<td>{getValue("alamat_organisasi")}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Nomor Telepon</td>
|
<td>Nomor Telepon</td>
|
||||||
<td>:</td>
|
<td>:</td>
|
||||||
<td>{getValue("negara")}</td>
|
<td>{getValue("no_telepon")}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Nama Pimpinan</td>
|
<td>Nama Pimpinan</td>
|
||||||
<td>:</td>
|
<td>:</td>
|
||||||
<td>{getValue("agama")}</td>
|
<td>{getValue("nama_pimpinan")}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
@@ -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 () => {
|
||||||
@@ -78,32 +78,32 @@ export default function SKKelahiran({ data }: { data: any }) {
|
|||||||
<tr>
|
<tr>
|
||||||
<td style={{ width: "200px" }}>Tanggal Lahir</td>
|
<td style={{ width: "200px" }}>Tanggal Lahir</td>
|
||||||
<td>:</td>
|
<td>:</td>
|
||||||
<td>{getValue("tanggal lahir anak")}</td>
|
<td>{getValue("tanggal_lahir_anak")}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Pukul</td>
|
<td>Pukul</td>
|
||||||
<td>:</td>
|
<td>:</td>
|
||||||
<td>{getValue("pukul lahir anak")}</td>
|
<td>{getValue("pukul_lahir")}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Tempat Kelahiran</td>
|
<td>Tempat Kelahiran</td>
|
||||||
<td>:</td>
|
<td>:</td>
|
||||||
<td>{getValue("tempat lahir anak")}</td>
|
<td>{getValue("tempat_lahir")}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Jenis Kelamin</td>
|
<td>Jenis Kelamin</td>
|
||||||
<td>:</td>
|
<td>:</td>
|
||||||
<td>{getValue("jenis kelamin anak")}</td>
|
<td>{getValue("jenis_kelamin")}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Anak ke</td>
|
<td>Anak ke</td>
|
||||||
<td>:</td>
|
<td>:</td>
|
||||||
<td>{getValue("anak ke")}</td>
|
<td>{getValue("anak_ke")}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Nama Anak</td>
|
<td>Nama Anak</td>
|
||||||
<td>:</td>
|
<td>:</td>
|
||||||
<td>{getValue("nama anak")}</td>
|
<td>{getValue("nama_anak")}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@@ -117,27 +117,27 @@ export default function SKKelahiran({ data }: { data: any }) {
|
|||||||
<tr>
|
<tr>
|
||||||
<td style={{ width: "200px" }}>Nama Lengkap Ibu</td>
|
<td style={{ width: "200px" }}>Nama Lengkap Ibu</td>
|
||||||
<td>:</td>
|
<td>:</td>
|
||||||
<td>{getValue("nama ibu")}</td>
|
<td>{getValue("nama_ibu")}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>NIK</td>
|
<td>NIK</td>
|
||||||
<td>:</td>
|
<td>:</td>
|
||||||
<td>{getValue("nik ibu")}</td>
|
<td>{getValue("nik_ibu")}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Tempat & Tanggal Lahir</td>
|
<td>Tempat & Tanggal Lahir</td>
|
||||||
<td>:</td>
|
<td>:</td>
|
||||||
<td>{getValue("tempat tanggal lahir ibu")}</td>
|
<td>{`${getValue("tempat_lahir_ibu")}, ${getValue("tanggal_lahir_ibu")}`}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Pekerjaan</td>
|
<td>Pekerjaan</td>
|
||||||
<td>:</td>
|
<td>:</td>
|
||||||
<td>{getValue("pekerjaan ibu")}</td>
|
<td>{getValue("pekerjaan_ibu")}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Alamat</td>
|
<td>Alamat</td>
|
||||||
<td>:</td>
|
<td>:</td>
|
||||||
<td>{getValue("alamat ibu")}</td>
|
<td>{getValue("alamat_ibu")}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@@ -151,27 +151,27 @@ export default function SKKelahiran({ data }: { data: any }) {
|
|||||||
<tr>
|
<tr>
|
||||||
<td style={{ width: "200px" }}>Nama Lengkap Ayah</td>
|
<td style={{ width: "200px" }}>Nama Lengkap Ayah</td>
|
||||||
<td>:</td>
|
<td>:</td>
|
||||||
<td>{getValue("nama ayah")}</td>
|
<td>{getValue("nama_ayah")}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>NIK</td>
|
<td>NIK</td>
|
||||||
<td>:</td>
|
<td>:</td>
|
||||||
<td>{getValue("nik ayah")}</td>
|
<td>{getValue("nik_ayah")}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Tempat & Tanggal Lahir</td>
|
<td>Tempat & Tanggal Lahir</td>
|
||||||
<td>:</td>
|
<td>:</td>
|
||||||
<td>{getValue("tempat tanggal lahir ayah")}</td>
|
<td>{`${getValue("tempat_lahir_ayah")}, ${getValue("tanggal_lahir_ayah")}`}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Pekerjaan</td>
|
<td>Pekerjaan</td>
|
||||||
<td>:</td>
|
<td>:</td>
|
||||||
<td>{getValue("pekerjaan ayah")}</td>
|
<td>{getValue("pekerjaan_ayah")}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Alamat</td>
|
<td>Alamat</td>
|
||||||
<td>:</td>
|
<td>:</td>
|
||||||
<td>{getValue("alamat ayah")}</td>
|
<td>{getValue("alamat_ayah")}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@@ -185,17 +185,17 @@ export default function SKKelahiran({ data }: { data: any }) {
|
|||||||
<tr>
|
<tr>
|
||||||
<td style={{ width: "200px" }}>Nama Pelapor</td>
|
<td style={{ width: "200px" }}>Nama Pelapor</td>
|
||||||
<td>:</td>
|
<td>:</td>
|
||||||
<td>{getValue("nama pelapor")}</td>
|
<td>{getValue("nama_pelapor")}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Hubungan dengan Anak</td>
|
<td>Hubungan dengan Anak</td>
|
||||||
<td>:</td>
|
<td>:</td>
|
||||||
<td>{getValue("hubungan pelapor")}</td>
|
<td>{getValue("hubungan_pelapor")}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Alamat</td>
|
<td>Alamat</td>
|
||||||
<td>:</td>
|
<td>:</td>
|
||||||
<td>{getValue("alamat pelapor")}</td>
|
<td>{getValue("alamat_pelapor")}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
@@ -71,12 +71,12 @@ export default function SKKelakuanBaik({ data }: { data: any }) {
|
|||||||
<tr>
|
<tr>
|
||||||
<td>Tempat/Tgl Lahir</td>
|
<td>Tempat/Tgl Lahir</td>
|
||||||
<td>:</td>
|
<td>:</td>
|
||||||
<td>{getValue("tempat tanggal lahir")}</td>
|
<td>{`${getValue("tempat_lahir")}, ${getValue("tanggal_lahir")}`}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Jenis Kelamin</td>
|
<td>Jenis Kelamin</td>
|
||||||
<td>:</td>
|
<td>:</td>
|
||||||
<td>{getValue("jenis kelamin")}</td>
|
<td>{getValue("jenis_kelamin")}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Agama</td>
|
<td>Agama</td>
|
||||||
|
|||||||
@@ -71,27 +71,27 @@ export default function SKKematian({ data }: { data: any }) {
|
|||||||
<tr>
|
<tr>
|
||||||
<td style={{ width: "160px" }}>Nama</td>
|
<td style={{ width: "160px" }}>Nama</td>
|
||||||
<td style={{ width: "10px" }}>:</td>
|
<td style={{ width: "10px" }}>:</td>
|
||||||
<td>{getValue("nama")}</td>
|
<td>{getValue("nama_pelapor")}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>NIK</td>
|
<td>NIK</td>
|
||||||
<td>:</td>
|
<td>:</td>
|
||||||
<td>{getValue("nik")}</td>
|
<td>{getValue("nik_pelapor")}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Pekerjaan</td>
|
<td>Pekerjaan</td>
|
||||||
<td>:</td>
|
<td>:</td>
|
||||||
<td>{getValue("pekerjaan")}</td>
|
<td>{getValue("pekerjaan_pelapor")}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Alamat</td>
|
<td>Alamat</td>
|
||||||
<td>:</td>
|
<td>:</td>
|
||||||
<td>{getValue("alamat")}</td>
|
<td>{getValue("alamat_pelapor")}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Hubungan dengan almarhum/almarhumah</td>
|
<td>Hubungan dengan almarhum/almarhumah</td>
|
||||||
<td>:</td>
|
<td>:</td>
|
||||||
<td>{getValue("hubungan dengan almarhum")}</td>
|
<td>{getValue("hubungan_pelapor")}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@@ -104,32 +104,32 @@ export default function SKKematian({ data }: { data: any }) {
|
|||||||
<tr>
|
<tr>
|
||||||
<td style={{ width: "160px" }}>Nama</td>
|
<td style={{ width: "160px" }}>Nama</td>
|
||||||
<td style={{ width: "10px" }}>:</td>
|
<td style={{ width: "10px" }}>:</td>
|
||||||
<td>{getValue("nama")}</td>
|
<td>{getValue("nama_almarhum")}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>NIK</td>
|
<td>NIK</td>
|
||||||
<td>:</td>
|
<td>:</td>
|
||||||
<td>{getValue("nik")}</td>
|
<td>{getValue("nik_almarhum")}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Jenis Kelamin</td>
|
<td>Jenis Kelamin</td>
|
||||||
<td>:</td>
|
<td>:</td>
|
||||||
<td>{getValue("jenis kelamin")}</td>
|
<td>{getValue("jenis_kelamin_almarhum")}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Tempat/Tanggal Lahir</td>
|
<td>Tempat/Tanggal Lahir</td>
|
||||||
<td>:</td>
|
<td>:</td>
|
||||||
<td>{getValue("tempat tanggal lahir")}</td>
|
<td>{`${getValue("tempat_lahir_almarhum")}, ${getValue("tanggal_lahir_almarhum")}`}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Agama</td>
|
<td>Agama</td>
|
||||||
<td>:</td>
|
<td>:</td>
|
||||||
<td>{getValue("agama")}</td>
|
<td>{getValue("agama_almarhum")}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Alamat</td>
|
<td>Alamat</td>
|
||||||
<td>:</td>
|
<td>:</td>
|
||||||
<td>{getValue("alamat")}</td>
|
<td>{getValue("alamat_almarhum")}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@@ -142,22 +142,22 @@ export default function SKKematian({ data }: { data: any }) {
|
|||||||
<tr>
|
<tr>
|
||||||
<td style={{ width: "160px" }}>Tanggal Kematian</td>
|
<td style={{ width: "160px" }}>Tanggal Kematian</td>
|
||||||
<td style={{ width: "10px" }}>:</td>
|
<td style={{ width: "10px" }}>:</td>
|
||||||
<td>{getValue("tanggal kematian")}</td>
|
<td>{getValue("tanggal_kematian")}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Waktu Kematian</td>
|
<td>Waktu Kematian</td>
|
||||||
<td>:</td>
|
<td>:</td>
|
||||||
<td>{getValue("waktu kematian")}</td>
|
<td>{getValue("waktu_kematian")}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Tempat Kematian</td>
|
<td>Tempat Kematian</td>
|
||||||
<td>:</td>
|
<td>:</td>
|
||||||
<td>{getValue("tempat kematian")}</td>
|
<td>{getValue("tempat_kematian")}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Penyebab Kematian</td>
|
<td>Penyebab Kematian</td>
|
||||||
<td>:</td>
|
<td>:</td>
|
||||||
<td>{getValue("penyebab kematian")}</td>
|
<td>{getValue("penyebab_kematian")}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@@ -185,7 +185,7 @@ export default function SKKematian({ data }: { data: any }) {
|
|||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
<br /> <br />
|
<br /> <br />
|
||||||
<u>{getValue("nama")}</u> <br />
|
<u>{getValue("nama_pelapor")}</u> <br />
|
||||||
</div>
|
</div>
|
||||||
<div style={{ textAlign: "center" }}>
|
<div style={{ textAlign: "center" }}>
|
||||||
<br />
|
<br />
|
||||||
|
|||||||
@@ -105,12 +105,12 @@ export default function SKPenghasilan({ data }: { data: any }) {
|
|||||||
<tr>
|
<tr>
|
||||||
<td>Jenis Kelamin</td>
|
<td>Jenis Kelamin</td>
|
||||||
<td>:</td>
|
<td>:</td>
|
||||||
<td>{getValue("jenis kelamin")}</td>
|
<td>{getValue("jenis_kelamin")}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Tempat / Tanggal Lahir</td>
|
<td>Tempat / Tanggal Lahir</td>
|
||||||
<td>:</td>
|
<td>:</td>
|
||||||
<td>{getValue("tempat tanggal lahir")}</td>
|
<td>{`${getValue("tempat_lahir")}, ${getValue("tanggal_lahir")}`}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Pekerjaan</td>
|
<td>Pekerjaan</td>
|
||||||
@@ -135,10 +135,7 @@ export default function SKPenghasilan({ data }: { data: any }) {
|
|||||||
<tr>
|
<tr>
|
||||||
<td style={{ width: "160px" }}>Penghasilan</td>
|
<td style={{ width: "160px" }}>Penghasilan</td>
|
||||||
<td style={{ width: "10px" }}>:</td>
|
<td style={{ width: "10px" }}>:</td>
|
||||||
<td>
|
<td>Rp. {getValue("penghasilan")} per bulan</td>
|
||||||
Rp {getValue("penghasilan")} (
|
|
||||||
{getValue("penghasilan terbilang")}) per bulan
|
|
||||||
</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@@ -146,8 +143,8 @@ export default function SKPenghasilan({ data }: { data: any }) {
|
|||||||
|
|
||||||
{/* KEPERLUAN */}
|
{/* KEPERLUAN */}
|
||||||
<div style={{ marginTop: "20px" }}>
|
<div style={{ marginTop: "20px" }}>
|
||||||
Surat keterangan ini dibuat untuk keperluan:{" "}
|
Surat keterangan ini dibuat untuk keperluan: <b>{getValue("alasan")}</b>
|
||||||
<b>{getValue("alasan permohonan")}</b>.
|
.
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style={{ marginTop: "20px" }}>
|
<div style={{ marginTop: "20px" }}>
|
||||||
|
|||||||
@@ -66,12 +66,15 @@ export default function SKTempatUsaha({ data }: { data: any }) {
|
|||||||
|
|
||||||
{/* DATA WARGA */}
|
{/* DATA WARGA */}
|
||||||
<div>
|
<div>
|
||||||
<Row label="Nama Pemilik Usaha" value={getValue("nama")} />
|
<Row label="Nama Pemilik Usaha" value={getValue("nama_pemilik")} />
|
||||||
<Row
|
<Row
|
||||||
label="Tempat/Tanggal Lahir"
|
label="Tempat/Tanggal Lahir"
|
||||||
value={getValue("tempat tanggal lahir")}
|
value={`${getValue("tempat_lahir")}, ${getValue("tanggal_lahir")}`}
|
||||||
|
/>
|
||||||
|
<Row
|
||||||
|
label="Alamat Pemilik Usaha"
|
||||||
|
value={getValue("alamat_pemilik")}
|
||||||
/>
|
/>
|
||||||
<Row label="Alamat Pemilik Usaha" value={getValue("alamat")} />
|
|
||||||
<Row label="Nomor KTP" value={getValue("nik")} />
|
<Row label="Nomor KTP" value={getValue("nik")} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -83,23 +86,17 @@ export default function SKTempatUsaha({ data }: { data: any }) {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<Row label="Nama Usaha" value={getValue("nama usaha")} />
|
<Row label="Nama Usaha" value={getValue("nama_usaha")} />
|
||||||
<Row label="Bidang Usaha" value={getValue("bidang usaha")} />
|
<Row label="Bidang Usaha" value={getValue("bidang_usaha")} />
|
||||||
<Row label="Alamat Usaha" value={getValue("alamat usaha")} />
|
<Row label="Alamat Usaha" value={getValue("alamat_usaha")} />
|
||||||
<Row
|
<Row label="Status Tempat Usaha" value={getValue("status_tempat")} />
|
||||||
label="Status Tempat Usaha"
|
<Row label="Luas Tempat Usaha" value={getValue("luas_usaha") + " m2"} />
|
||||||
value={getValue("status tempat usaha")}
|
<Row label="Jumlah Karyawan" value={getValue("jumlah_karyawan")} />
|
||||||
/>
|
|
||||||
<Row
|
|
||||||
label="Luas Tempat Usaha"
|
|
||||||
value={getValue("luas tempat usaha")}
|
|
||||||
/>
|
|
||||||
<Row label="Jumlah Karyawan" value={getValue("jumlah karyawan")} />
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p style={{ textAlign: "justify" }}>
|
<p style={{ textAlign: "justify" }}>
|
||||||
Surat keterangan ini dibuat untuk keperluan{" "}
|
Surat keterangan ini dibuat untuk keperluan{" "}
|
||||||
<b>{getValue("alasan permohonan")}.</b>
|
<b>{getValue("tujuan")}.</b>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p style={{ textAlign: "justify" }}>
|
<p style={{ textAlign: "justify" }}>
|
||||||
|
|||||||
@@ -66,13 +66,13 @@ export default function SKTidakMampu({ data }: { data: any }) {
|
|||||||
|
|
||||||
{/* DATA WARGA */}
|
{/* DATA WARGA */}
|
||||||
<div>
|
<div>
|
||||||
|
<Row label="NIK" value={getValue("nik")} />
|
||||||
<Row label="Nama" value={getValue("nama")} />
|
<Row label="Nama" value={getValue("nama")} />
|
||||||
<Row
|
<Row
|
||||||
label="Tempat Tgl Lahir"
|
label="Tempat Tgl Lahir"
|
||||||
value={getValue("tempat tanggal lahir")}
|
value={`${getValue("tempat_lahir")}, ${getValue("tanggal_lahir")}`}
|
||||||
/>
|
/>
|
||||||
<Row label="Alamat" value={getValue("alamat")} />
|
<Row label="Alamat" value={getValue("alamat")} />
|
||||||
<Row label="NIK" value={getValue("nik")} />
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<br />
|
<br />
|
||||||
@@ -80,7 +80,7 @@ export default function SKTidakMampu({ data }: { data: any }) {
|
|||||||
<p style={{ textAlign: "justify" }}>
|
<p style={{ textAlign: "justify" }}>
|
||||||
Orang tersebut benar-benar penduduk desa {data.setting.desaNama} dan
|
Orang tersebut benar-benar penduduk desa {data.setting.desaNama} dan
|
||||||
termasuk keluarga tidak mampu. Surat keterangan ini dipergunakan untuk
|
termasuk keluarga tidak mampu. Surat keterangan ini dipergunakan untuk
|
||||||
<b>{getValue("alasan permohonan")}.</b>
|
<b>{getValue("alasan")}.</b>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p style={{ textAlign: "justify" }}>
|
<p style={{ textAlign: "justify" }}>
|
||||||
|
|||||||
@@ -105,12 +105,12 @@ export default function SKUsaha({ data }: { data: any }) {
|
|||||||
<tr>
|
<tr>
|
||||||
<td>Jenis Kelamin</td>
|
<td>Jenis Kelamin</td>
|
||||||
<td>:</td>
|
<td>:</td>
|
||||||
<td>{getValue("jenis kelamin")}</td>
|
<td>{getValue("jenis_kelamin")}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Tempat / Tanggal Lahir</td>
|
<td>Tempat / Tanggal Lahir</td>
|
||||||
<td>:</td>
|
<td>:</td>
|
||||||
<td>{getValue("tempat tanggal lahir")}</td>
|
<td>{`${getValue("tempat_lahir")}, ${getValue("tanggal_lahir")}`}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Warga Negara</td>
|
<td>Warga Negara</td>
|
||||||
@@ -125,7 +125,7 @@ export default function SKUsaha({ data }: { data: any }) {
|
|||||||
<tr>
|
<tr>
|
||||||
<td>Status</td>
|
<td>Status</td>
|
||||||
<td>:</td>
|
<td>:</td>
|
||||||
<td>{getValue("status perkawinan")}</td>
|
<td>{getValue("status_perkawinan")}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Pekerjaan</td>
|
<td>Pekerjaan</td>
|
||||||
@@ -173,12 +173,12 @@ export default function SKUsaha({ data }: { data: any }) {
|
|||||||
<tr>
|
<tr>
|
||||||
<td style={{ width: "160px" }}>Jenis Usaha</td>
|
<td style={{ width: "160px" }}>Jenis Usaha</td>
|
||||||
<td style={{ width: "10px" }}>:</td>
|
<td style={{ width: "10px" }}>:</td>
|
||||||
<td>{getValue("jenis usaha")}</td>
|
<td>{getValue("jenis_usaha")}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Alamat Usaha</td>
|
<td>Alamat Usaha</td>
|
||||||
<td>:</td>
|
<td>:</td>
|
||||||
<td>{getValue("alamat usaha")}</td>
|
<td>{getValue("alamat_usaha")}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
@@ -88,26 +88,28 @@ export default function SKYatim({ data }: { data: any }) {
|
|||||||
|
|
||||||
<table style={{ width: "100%", marginTop: "5px" }}>
|
<table style={{ width: "100%", marginTop: "5px" }}>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>NIK</td>
|
||||||
|
<td>: {getValue("nik")}</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td style={{ width: "180px" }}>Nama</td>
|
<td style={{ width: "180px" }}>Nama</td>
|
||||||
<td>: {getValue("nama")}</td>
|
<td>: {getValue("nama")}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Tempat/Tanggal Lahir</td>
|
<td>Tempat/Tanggal Lahir</td>
|
||||||
<td>: {getValue("tempat tanggal lahir")}</td>
|
<td>
|
||||||
|
: {`${getValue("tempat_lahir")}, ${getValue("tanggal_lahir")}`}
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Jenis Kelamin</td>
|
<td>Jenis Kelamin</td>
|
||||||
<td>: {getValue("jenis kelamin")}</td>
|
<td>: {getValue("jenis_kelamin")}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Alamat</td>
|
<td>Alamat</td>
|
||||||
<td>: {getValue("alamat")}</td>
|
<td>: {getValue("alamat")}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
|
||||||
<td>NIK</td>
|
|
||||||
<td>: {getValue("nik")}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
<tr>
|
||||||
<td>Pekerjaan</td>
|
<td>Pekerjaan</td>
|
||||||
<td>: {getValue("pekerjaan")}</td>
|
<td>: {getValue("pekerjaan")}</td>
|
||||||
@@ -133,11 +135,11 @@ export default function SKYatim({ data }: { data: any }) {
|
|||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td style={{ width: "180px" }}>Nama Ayah</td>
|
<td style={{ width: "180px" }}>Nama Ayah</td>
|
||||||
<td>: {getValue("nama ayah")}</td>
|
<td>: {getValue("nama_ayah")}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Status</td>
|
<td>Status</td>
|
||||||
<td>: {getValue("status ayah")}</td>
|
<td>: {getValue("status_ayah")}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@@ -151,11 +153,11 @@ export default function SKYatim({ data }: { data: any }) {
|
|||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td style={{ width: "180px" }}>Nama Ibu</td>
|
<td style={{ width: "180px" }}>Nama Ibu</td>
|
||||||
<td>: {getValue("nama ibu")}</td>
|
<td>: {getValue("nama_ibu")}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Status</td>
|
<td>Status</td>
|
||||||
<td>: {getValue("status ibu")}</td>
|
<td>: {getValue("status_ibu")}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import LayananRoute from "./server/routes/layanan_route";
|
|||||||
import { MCPRoute } from "./server/routes/mcp_route";
|
import { MCPRoute } from "./server/routes/mcp_route";
|
||||||
import PelayananRoute from "./server/routes/pelayanan_surat_route";
|
import PelayananRoute from "./server/routes/pelayanan_surat_route";
|
||||||
import PengaduanRoute from "./server/routes/pengaduan_route";
|
import PengaduanRoute from "./server/routes/pengaduan_route";
|
||||||
|
import SendWaRoute from "./server/routes/send_wa_route";
|
||||||
import SuratRoute from "./server/routes/surat_route";
|
import SuratRoute from "./server/routes/surat_route";
|
||||||
import TestPengaduanRoute from "./server/routes/test_pengaduan";
|
import TestPengaduanRoute from "./server/routes/test_pengaduan";
|
||||||
import UserRoute from "./server/routes/user_route";
|
import UserRoute from "./server/routes/user_route";
|
||||||
@@ -45,7 +46,8 @@ const Api = new Elysia({
|
|||||||
.use(CredentialRoute)
|
.use(CredentialRoute)
|
||||||
.use(UserRoute)
|
.use(UserRoute)
|
||||||
.use(LayananRoute)
|
.use(LayananRoute)
|
||||||
.use(AduanRoute);
|
.use(AduanRoute)
|
||||||
|
.use(SendWaRoute);
|
||||||
|
|
||||||
const app = new Elysia()
|
const app = new Elysia()
|
||||||
.use(Api)
|
.use(Api)
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { enumAgama, enumJenisKelamin, enumStatusHidup, enumStatusPerkawinan, enumStatusTempatUsaha } from "./valueEnum";
|
||||||
|
|
||||||
export const categoryPelayananSurat = [
|
export const categoryPelayananSurat = [
|
||||||
{
|
{
|
||||||
id: "skbedabiodata",
|
id: "skbedabiodata",
|
||||||
@@ -6,366 +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, satuan: null
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
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, satuan: null
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
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, satuan: null
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
dataText: [],
|
dataText: [],
|
||||||
dataPelengkap: [
|
dataPelengkap: [
|
||||||
{ key: "nik", name: "NIK", desc: "Nomor Induk Kependudukan" },
|
{ key: "nik", name: "NIK", desc: "Nomor Induk Kependudukan", type: "number", required: true, satuan: null },
|
||||||
{ key: "nama", name: "Nama Lengkap", desc: "Nama sesuai KTP" },
|
{ key: "nama", name: "Nama Lengkap", desc: "Nama sesuai KTP", type: "text", required: true, satuan: null },
|
||||||
{ key: "ttl", name: "Tempat & Tanggal Lahir", desc: "Tempat dan tanggal lahir pemohon" },
|
{ key: "tempat_lahir", name: "Tempat Lahir", desc: "Tempat lahir pemohon", type: "text", required: true, satuan: null },
|
||||||
{ key: "jenis_kelamin", name: "Jenis Kelamin", desc: "Jenis kelamin pemohon" },
|
{ key: "tanggal_lahir", name: "Tanggal Lahir", desc: "Tanggal lahir pemohon", type: "date", required: true, satuan: null },
|
||||||
{ key: "alamat", name: "Alamat", desc: "Alamat lengkap tempat tinggal" },
|
{
|
||||||
{ key: "pekerjaan", name: "Pekerjaan", desc: "Pekerjaan pemohon" },
|
key: "jenis_kelamin",
|
||||||
{ key: "dokumen", name: "Nama Dokumen", desc: "Jenis dokumen yang mengalami perbedaan biodata" },
|
name: "Jenis Kelamin",
|
||||||
{ key: "dokumen_a", name: "Data pada Dokumen A", desc: "Data biodata yang tertulis pada dokumen pertama" },
|
desc: "Jenis kelamin pemohon",
|
||||||
{ key: "dokumen_b", name: "Data pada Dokumen B", desc: "Data biodata yang tertulis pada dokumen kedua" }
|
type: "enum",
|
||||||
|
options: enumJenisKelamin,
|
||||||
|
required: true, satuan: null
|
||||||
|
},
|
||||||
|
{ key: "alamat", name: "Alamat", desc: "Alamat lengkap tempat tinggal", type: "text", required: true, satuan: null },
|
||||||
|
{ key: "pekerjaan", name: "Pekerjaan", desc: "Pekerjaan pemohon", type: "text", required: true, satuan: null },
|
||||||
|
{
|
||||||
|
key: "dokumen",
|
||||||
|
name: "Nama Dokumen",
|
||||||
|
desc: "Jenis dokumen yang mengalami perbedaan biodata",
|
||||||
|
type: "text",
|
||||||
|
required: true, satuan: null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "data_dokumen",
|
||||||
|
name: "Data Dokumen",
|
||||||
|
desc: "Data dokumen yg berbeda",
|
||||||
|
type: "text",
|
||||||
|
required: true, satuan: null
|
||||||
|
},
|
||||||
|
{ key: "dokumen_a", name: "Data pada Dokumen A", desc: "Data biodata pada dokumen pertama", type: "text", required: true, satuan: null },
|
||||||
|
{ key: "dokumen_b", name: "Data pada Dokumen B", desc: "Data biodata pada dokumen kedua", type: "text", required: true, satuan: null }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
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, satuan: null },
|
||||||
key: "pengantar_kelian",
|
{ key: "ktp_kk", name: "KTP / KK", desc: "Fotokopi KTP atau Kartu Keluarga", required: true, satuan: null },
|
||||||
name: "Pengantar Kelian",
|
{ key: "akta_cerai", name: "Akta Cerai", desc: "Fotokopi akta cerai (jika berstatus janda/duda)", required: false, satuan: null }
|
||||||
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" },
|
{ key: "nik", name: "NIK", desc: "Nomor Induk Kependudukan", type: "number", required: true, satuan: null },
|
||||||
{ key: "nama", name: "Nama Lengkap", desc: "Nama sesuai KTP" },
|
{ key: "nama", name: "Nama Lengkap", desc: "Nama sesuai KTP", type: "text", required: true, satuan: null },
|
||||||
{ key: "ttl", name: "Tempat & Tanggal Lahir", desc: "Tempat dan tanggal lahir" },
|
{ key: "tempat_lahir", name: "Tempat Lahir", desc: "Tempat lahir pemohon", type: "text", required: true, satuan: null },
|
||||||
{ key: "jenis_kelamin", name: "Jenis Kelamin", desc: "Jenis kelamin pemohon" },
|
{ key: "tanggal_lahir", name: "Tanggal Lahir", desc: "Tanggal lahir pemohon", type: "date", required: true, satuan: null },
|
||||||
{ key: "alamat", name: "Alamat", desc: "Alamat tempat tinggal" },
|
{
|
||||||
{ key: "agama", name: "Agama", desc: "Agama pemohon" },
|
key: "jenis_kelamin",
|
||||||
{ key: "pekerjaan", name: "Pekerjaan", desc: "Pekerjaan pemohon" }
|
name: "Jenis Kelamin",
|
||||||
|
desc: "Jenis kelamin pemohon",
|
||||||
|
type: "enum",
|
||||||
|
options: enumJenisKelamin,
|
||||||
|
required: true, satuan: null
|
||||||
|
},
|
||||||
|
{ key: "alamat", name: "Alamat", desc: "Alamat tempat tinggal", type: "text", required: true, satuan: null },
|
||||||
|
{
|
||||||
|
key: "agama",
|
||||||
|
name: "Agama",
|
||||||
|
desc: "Agama pemohon",
|
||||||
|
type: "enum",
|
||||||
|
options: enumAgama,
|
||||||
|
required: true, satuan: null
|
||||||
|
},
|
||||||
|
{ key: "pekerjaan", name: "Pekerjaan", desc: "Pekerjaan pemohon", type: "text", required: true, satuan: null }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
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, satuan: null },
|
||||||
key: "pengantar_kelian",
|
{ key: "skt_organisasi", name: "SKT Organisasi", desc: "Fotokopi SKT Organisasi", required: true, satuan: null },
|
||||||
name: "Pengantar Kelian",
|
{ key: "susunan_pengurus", name: "Susunan Pengurus", desc: "Susunan pengurus organisasi", required: true, satuan: null }
|
||||||
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" },
|
{ key: "nama_organisasi", name: "Nama Organisasi", desc: "Nama resmi organisasi", type: "text", required: true, satuan: null },
|
||||||
{ key: "jenis_organisasi", name: "Jenis Organisasi", desc: "Jenis atau bentuk organisasi" },
|
{ key: "jenis_organisasi", name: "Jenis Organisasi", desc: "Jenis organisasi", type: "text", required: true, satuan: null },
|
||||||
{ key: "alamat_organisasi", name: "Alamat Organisasi", desc: "Alamat sekretariat organisasi" },
|
{ key: "alamat_organisasi", name: "Alamat Organisasi", desc: "Alamat sekretariat", type: "text", required: true, satuan: null },
|
||||||
{ key: "no_telepon", name: "Nomor Telepon", desc: "Nomor telepon organisasi" },
|
{ key: "no_telepon", name: "Nomor Telepon", desc: "Nomor telepon organisasi", type: "text", required: true, satuan: null },
|
||||||
{ key: "nama_pimpinan", name: "Nama Pimpinan", desc: "Nama pimpinan organisasi" },
|
{ key: "nama_pimpinan", name: "Nama Pimpinan", desc: "Nama pimpinan", type: "text", required: true, satuan: null },
|
||||||
{ key: "keperluan", name: "Keperluan", desc: "Keperluan pembuatan surat" }
|
{ key: "keperluan", name: "Keperluan", desc: "Keperluan pembuatan surat", type: "text", required: true, satuan: null }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
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, satuan: null },
|
||||||
key: "pengantar_kelian",
|
{ key: "surat_lahir", name: "Surat Keterangan Lahir", desc: "Surat keterangan lahir dari bidan/dokter (jika ada)", required: false, satuan: null }
|
||||||
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_ayah", name: "Nama Ayah", desc: "Nama lengkap ayah" },
|
{ key: "nama_anak", name: "Nama Anak", desc: "Nama bayi/anak", type: "text", required: true, satuan: null },
|
||||||
{ key: "nama_ibu", name: "Nama Ibu", desc: "Nama lengkap ibu" },
|
{ key: "tanggal_lahir_anak", name: "Tanggal Lahir Anak", desc: "Tanggal lahir anak", type: "date", required: true, satuan: null },
|
||||||
{ key: "nama_anak", name: "Nama Anak", desc: "Nama bayi/anak" },
|
{ key: "pukul_lahir", name: "Pukul Lahir", desc: "Waktu kelahiran", type: "text", required: true, satuan: null },
|
||||||
{ key: "tanggal_lahir_anak", name: "Tanggal Lahir Anak", desc: "Tanggal lahir anak" },
|
{ key: "tempat_lahir", name: "Tempat Lahir", desc: "Tempat kelahiran", type: "text", required: true, satuan: null },
|
||||||
{ key: "pukul_lahir", name: "Pukul Lahir", desc: "Waktu kelahiran anak" },
|
{
|
||||||
{ key: "tempat_lahir", name: "Tempat Lahir", desc: "Tempat kelahiran anak" },
|
key: "jenis_kelamin",
|
||||||
{ key: "jenis_kelamin", name: "Jenis Kelamin Anak", desc: "Jenis kelamin anak" },
|
name: "Jenis Kelamin Anak",
|
||||||
{ key: "anak_ke", name: "Anak Ke-", desc: "Urutan kelahiran anak" },
|
desc: "Jenis kelamin anak",
|
||||||
{ key: "nik_ibu", name: "NIK Ibu", desc: "NIK ibu kandung" },
|
type: "enum",
|
||||||
{ key: "nik_ayah", name: "NIK Ayah", desc: "NIK ayah kandung" },
|
options: enumJenisKelamin,
|
||||||
{ key: "nama_pelapor", name: "Nama Pelapor", desc: "Nama pihak yang melaporkan" },
|
required: true, satuan: null
|
||||||
{ key: "hubungan_pelapor", name: "Hubungan Pelapor", desc: "Hubungan pelapor dengan anak" },
|
},
|
||||||
{ key: "alamat_pelapor", name: "Alamat Pelapor", desc: "Alamat pelapor" }
|
{ key: "anak_ke", name: "Anak Ke-", desc: "Urutan kelahiran", type: "number", required: true, satuan: null },
|
||||||
|
{ key: "nik_ibu", name: "NIK Ibu", desc: "NIK ibu kandung", type: "number", required: true, satuan: null },
|
||||||
|
{ key: "nama_ibu", name: "Nama Ibu", desc: "Nama ibu kandung", type: "text", required: true, satuan: null },
|
||||||
|
{ key: "tempat_lahir_ibu", name: "Tempat Lahir Ibu", desc: "Tempat lahir ibu", type: "text", required: true, satuan: null },
|
||||||
|
{ key: "tanggal_lahir_ibu", name: "Tanggal Lahir Ibu", desc: "Tanggal lahir ibu", type: "date", required: true, satuan: null },
|
||||||
|
{ key: "pekerjaan_ibu", name: "Pekerjaan Ibu", desc: "Pekerjaan ibu", type: "text", required: true, satuan: null },
|
||||||
|
{ key: "alamat_ibu", name: "Alamat Ibu", desc: "Alamat ibu", type: "text", required: true, satuan: null },
|
||||||
|
{ key: "nama_ayah", name: "Nama Ayah", desc: "Nama ayah kandung", type: "text", required: true, satuan: null },
|
||||||
|
{ key: "nik_ayah", name: "NIK Ayah", desc: "NIK ayah kandung", type: "number", required: true, satuan: null },
|
||||||
|
{ key: "tempat_lahir_ayah", name: "Tempat Lahir Ayah", desc: "Tempat lahir ayah", type: "text", required: true, satuan: null },
|
||||||
|
{ key: "tanggal_lahir_ayah", name: "Tanggal Lahir Ayah", desc: "Tanggal lahir ayah", type: "date", required: true, satuan: null },
|
||||||
|
{ key: "pekerjaan_ayah", name: "Pekerjaan Ayah", desc: "Pekerjaan ayah", type: "text", required: true, satuan: null },
|
||||||
|
{ key: "alamat_ayah", name: "Alamat Ayah", desc: "Alamat ayah", type: "text", required: true, satuan: null },
|
||||||
|
{ key: "nama_pelapor", name: "Nama Pelapor", desc: "Nama pelapor", type: "text", required: true, satuan: null },
|
||||||
|
{ key: "hubungan_pelapor", name: "Hubungan Pelapor", desc: "Hubungan dengan anak", type: "text", required: true, satuan: null },
|
||||||
|
{ key: "alamat_pelapor", name: "Alamat Pelapor", desc: "Alamat pelapor", type: "text", required: true, satuan: null }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
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, satuan: null },
|
||||||
key: "pengantar_kelian",
|
{ key: "ktp_kk", name: "KTP / KK", desc: "Fotokopi KTP atau KK", required: true, satuan: null }
|
||||||
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" },
|
{ key: "nik", name: "NIK", desc: "Nomor Induk Kependudukan", type: "number", required: true, satuan: null },
|
||||||
{ key: "nama", name: "Nama Lengkap", desc: "Nama sesuai KTP" },
|
{ key: "nama", name: "Nama Lengkap", desc: "Nama sesuai KTP", type: "text", required: true, satuan: null },
|
||||||
{ key: "ttl", name: "Tempat & Tanggal Lahir", desc: "Tempat dan tanggal lahir" },
|
{ key: "tempat_lahir", name: "Tempat Lahir", desc: "Tempat lahir", type: "text", required: true, satuan: null },
|
||||||
{ key: "jenis_kelamin", name: "Jenis Kelamin", desc: "Jenis kelamin pemohon" },
|
{ key: "tanggal_lahir", name: "Tanggal Lahir", desc: "Tanggal lahir", type: "date", required: true, satuan: null },
|
||||||
{ key: "agama", name: "Agama", desc: "Agama pemohon" },
|
{
|
||||||
{ key: "alamat", name: "Alamat", desc: "Alamat tempat tinggal" },
|
key: "jenis_kelamin",
|
||||||
{ key: "pekerjaan", name: "Pekerjaan", desc: "Pekerjaan pemohon" },
|
name: "Jenis Kelamin",
|
||||||
{ key: "polsek", name: "Polsek Tujuan", desc: "Polsek tujuan pembuatan SKCK" }
|
desc: "Jenis kelamin",
|
||||||
|
type: "enum",
|
||||||
|
options: enumJenisKelamin,
|
||||||
|
required: true, satuan: null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "agama",
|
||||||
|
name: "Agama",
|
||||||
|
desc: "Agama",
|
||||||
|
type: "enum",
|
||||||
|
options: enumAgama,
|
||||||
|
required: true, satuan: null
|
||||||
|
},
|
||||||
|
{ key: "alamat", name: "Alamat", desc: "Alamat tempat tinggal", type: "text", required: true, satuan: null },
|
||||||
|
{ key: "pekerjaan", name: "Pekerjaan", desc: "Pekerjaan", type: "text", required: true, satuan: null },
|
||||||
|
{ key: "polsek", name: "Polsek Tujuan", desc: "Polsek tujuan", type: "text", required: true, satuan: null }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
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, satuan: null },
|
||||||
key: "pengantar_kelian",
|
{ key: "ktp_kk", name: "KTP / KK", desc: "Fotokopi KTP atau KK", required: true, satuan: null },
|
||||||
name: "Pengantar Kelian",
|
{ key: "surat_kematian", name: "Surat Keterangan Kematian", desc: "Surat keterangan kematian dari rumah sakit/dokter (jika ada)", required: false, satuan: null }
|
||||||
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" },
|
{ key: "nik_pelapor", name: "NIK Pelapor", desc: "NIK pelapor", type: "number", required: true, satuan: null },
|
||||||
{ key: "nama_pelapor", name: "Nama Pelapor", desc: "Nama lengkap pelapor" },
|
{ key: "nama_pelapor", name: "Nama Pelapor", desc: "Nama pelapor", type: "text", required: true, satuan: null },
|
||||||
{ key: "pekerjaan_pelapor", name: "Pekerjaan Pelapor", desc: "Pekerjaan pelapor" },
|
{ key: "pekerjaan_pelapor", name: "Pekerjaan Pelapor", desc: "Pekerjaan pelapor", type: "text", required: true, satuan: null },
|
||||||
{ key: "alamat_pelapor", name: "Alamat Pelapor", desc: "Alamat tempat tinggal pelapor" },
|
{ key: "alamat_pelapor", name: "Alamat Pelapor", desc: "Alamat pelapor", type: "text", required: true, satuan: null },
|
||||||
{ key: "hubungan_pelapor", name: "Hubungan dengan Almarhum", desc: "Hubungan pelapor dengan almarhum" },
|
{ key: "hubungan_pelapor", name: "Hubungan Pelapor", desc: "Hubungan dengan almarhum", type: "text", required: true, satuan: null },
|
||||||
{ key: "nama_almarhum", name: "Nama Almarhum", desc: "Nama lengkap almarhum" },
|
{ key: "nama_almarhum", name: "Nama Almarhum", desc: "Nama almarhum", type: "text", required: true, satuan: null },
|
||||||
{ key: "nik_almarhum", name: "NIK Almarhum", desc: "Nomor Induk Kependudukan almarhum" },
|
{ key: "nik_almarhum", name: "NIK Almarhum", desc: "NIK almarhum", type: "number", required: true, satuan: null },
|
||||||
{ key: "ttl_almarhum", name: "Tempat & Tanggal Lahir Almarhum", desc: "Tempat dan tanggal lahir almarhum" },
|
{ key: "tempat_lahir_almarhum", name: "Tempat Lahir", desc: "Tempat lahir almarhum", type: "text", required: true, satuan: null },
|
||||||
{ key: "alamat_almarhum", name: "Alamat Almarhum", desc: "Alamat terakhir almarhum" },
|
{ key: "tanggal_lahir_almarhum", name: "Tanggal Lahir", desc: "Tanggal lahir almarhum", type: "date", required: true, satuan: null },
|
||||||
{ key: "agama_almarhum", name: "Agama Almarhum", desc: "Agama almarhum" },
|
{ key: "alamat_almarhum", name: "Alamat", desc: "Alamat terakhir", type: "text", required: true, satuan: null },
|
||||||
{ key: "tanggal_kematian", name: "Tanggal Kematian", desc: "Tanggal meninggal dunia" },
|
{
|
||||||
{ key: "waktu_kematian", name: "Waktu Kematian", desc: "Waktu meninggal dunia" },
|
key: "agama_almarhum",
|
||||||
{ key: "tempat_kematian", name: "Tempat Kematian", desc: "Tempat meninggal dunia" },
|
name: "Agama Almarhum",
|
||||||
{ key: "penyebab_kematian", name: "Penyebab Kematian", desc: "Penyebab meninggal dunia" }
|
desc: "Agama almarhum",
|
||||||
|
type: "enum",
|
||||||
|
options: enumAgama,
|
||||||
|
required: true, satuan: null
|
||||||
|
},
|
||||||
|
{ key: "tanggal_kematian", name: "Tanggal Kematian", desc: "Tanggal meninggal dunia", type: "date", required: true, satuan: null },
|
||||||
|
{ key: "waktu_kematian", name: "Waktu Kematian", desc: "Waktu meninggal dunia", type: "text", required: true, satuan: null },
|
||||||
|
{ key: "tempat_kematian", name: "Tempat Kematian", desc: "Tempat meninggal dunia", type: "text", required: true, satuan: null },
|
||||||
|
{ key: "penyebab_kematian", name: "Penyebab Kematian", desc: "Penyebab meninggal dunia", type: "text", required: true, satuan: null }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
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, satuan: null },
|
||||||
key: "pengantar_kelian",
|
{ key: "ktp_ortu_kk", name: "KTP Orang Tua / KK", desc: "Fotokopi KTP orang tua/KK", required: true, satuan: null },
|
||||||
name: "Pengantar Kelian",
|
{ key: "surat_pernyataan", name: "Surat Pernyataan Penghasilan", desc: "Surat pernyataan penghasilan bermaterai", required: true, satuan: null }
|
||||||
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" },
|
{ key: "nama", name: "Nama Lengkap", desc: "Nama pemohon", type: "text", required: true, satuan: null },
|
||||||
{ key: "ttl", name: "Tempat & Tanggal Lahir", desc: "Tempat dan tanggal lahir" },
|
{ key: "tempat_lahir", name: "Tempat Lahir", desc: "Tempat lahir", type: "text", required: true, satuan: null },
|
||||||
{ key: "jenis_kelamin", name: "Jenis Kelamin", desc: "Jenis kelamin pemohon" },
|
{ key: "tanggal_lahir", name: "Tanggal Lahir", desc: "Tanggal lahir", type: "date", required: true, satuan: null },
|
||||||
{ key: "alamat", name: "Alamat", desc: "Alamat tempat tinggal" },
|
{
|
||||||
{ key: "pekerjaan", name: "Pekerjaan", desc: "Pekerjaan pemohon/orang tua" },
|
key: "jenis_kelamin",
|
||||||
{ key: "penghasilan", name: "Penghasilan", desc: "Jumlah penghasilan per bulan" },
|
name: "Jenis Kelamin",
|
||||||
{ key: "alasan", name: "Alasan Permohonan", desc: "Alasan pengajuan surat penghasilan" }
|
desc: "Jenis kelamin",
|
||||||
|
type: "enum",
|
||||||
|
options: enumJenisKelamin,
|
||||||
|
required: true, satuan: null
|
||||||
|
},
|
||||||
|
{ key: "alamat", name: "Alamat", desc: "Alamat tempat tinggal", type: "text", required: true, satuan: null },
|
||||||
|
{ key: "pekerjaan", name: "Pekerjaan", desc: "Pekerjaan pemohon", type: "text", required: true, satuan: null },
|
||||||
|
{ key: "penghasilan", name: "Penghasilan", desc: "Jumlah penghasilan per bulan", type: "number", required: true, satuan: "/Bulan" },
|
||||||
|
{ key: "alasan", name: "Alasan Permohonan", desc: "Alasan pengajuan surat penghasilan", type: "text", required: true, satuan: null }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
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, satuan: null },
|
||||||
key: "pengantar_kelian",
|
{ key: "ktp_kk", name: "KTP / KK", desc: "Fotokopi KTP/KK", required: true, satuan: null },
|
||||||
name: "Pengantar Kelian",
|
{ key: "foto_lokasi", name: "Foto Lokasi Usaha", desc: "Foto lokasi usaha", required: true, satuan: null },
|
||||||
desc: "Surat Pengantar Kelian Banjar Dinas"
|
{ key: "dokumen_lahan", name: "Dokumen Lahan", desc: "SPPT/Sertifikat/surat sewa tempat usaha", required: true, satuan: null }
|
||||||
},
|
|
||||||
{
|
|
||||||
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" },
|
{ key: "nik", name: "NIK", desc: "NIK pemilik", type: "number", required: true, satuan: null },
|
||||||
{ key: "nama_pemilik", name: "Nama Pemilik", desc: "Nama pemilik usaha" },
|
{ key: "nama_pemilik", name: "Nama Pemilik", desc: "Nama pemilik usaha", type: "text", required: true, satuan: null },
|
||||||
{ key: "ttl", name: "Tempat & Tanggal Lahir", desc: "Tempat dan tanggal lahir" },
|
{ key: "tempat_lahir", name: "Tempat Lahir", desc: "Tempat lahir", type: "text", required: true, satuan: null },
|
||||||
{ key: "alamat_pemilik", name: "Alamat Pemilik", desc: "Alamat pemilik usaha" },
|
{ key: "tanggal_lahir", name: "Tanggal Lahir", desc: "Tanggal lahir", type: "date", required: true, satuan: null },
|
||||||
{ key: "nama_usaha", name: "Nama Usaha", desc: "Nama usaha" },
|
{ key: "alamat_pemilik", name: "Alamat Pemilik", desc: "Alamat pemilik", type: "text", required: true, satuan: null },
|
||||||
{ key: "bidang_usaha", name: "Bidang Usaha", desc: "Bidang atau jenis usaha" },
|
{ key: "nama_usaha", name: "Nama Usaha", desc: "Nama usaha", type: "text", required: true, satuan: null },
|
||||||
{ key: "alamat_usaha", name: "Alamat Usaha", desc: "Alamat lokasi usaha" },
|
{ key: "bidang_usaha", name: "Bidang Usaha", desc: "Bidang usaha", type: "text", required: true, satuan: null },
|
||||||
{ key: "status_tempat", name: "Status Tempat Usaha", desc: "Status kepemilikan tempat usaha" },
|
{ key: "alamat_usaha", name: "Alamat Usaha", desc: "Alamat usaha", type: "text", required: true, satuan: null },
|
||||||
{ key: "luas_usaha", name: "Luas Tempat Usaha", desc: "Luas tempat usaha (m²)" },
|
{
|
||||||
{ key: "jumlah_karyawan", name: "Jumlah Karyawan", desc: "Jumlah tenaga kerja" },
|
key: "status_tempat",
|
||||||
{ key: "tujuan", name: "Tujuan Pembuatan Surat", desc: "Tujuan pembuatan surat keterangan" }
|
name: "Status Tempat Usaha",
|
||||||
|
desc: "Status kepemilikan tempat usaha",
|
||||||
|
type: "enum",
|
||||||
|
options: enumStatusTempatUsaha,
|
||||||
|
required: true, satuan: null
|
||||||
|
},
|
||||||
|
{ key: "luas_usaha", name: "Luas Tempat Usaha", desc: "Luas tempat usaha (m²)", type: "number", required: true, satuan: "m²" },
|
||||||
|
{ key: "jumlah_karyawan", name: "Jumlah Karyawan", desc: "Jumlah karyawan", type: "number", required: true, satuan: null },
|
||||||
|
{ key: "tujuan", name: "Tujuan Pembuatan Surat", desc: "Tujuan pembuatan surat keterangan", type: "text", required: true, satuan: null }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
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, satuan: null },
|
||||||
key: "pengantar_kelian",
|
{ key: "ktp_kia_kk", name: "KTP / KIA / KK", desc: "Fotokopi KTP/KIA/KK", required: true, satuan: null }
|
||||||
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: "NIK pemohon", type: "number", required: true, satuan: null },
|
||||||
key: "nik",
|
{ key: "nama Lengkap", name: "Nama", desc: "Nama pemohon", type: "text", required: true, satuan: null },
|
||||||
name: "NIK",
|
{ key: "tempat_lahir", name: "Tempat Lahir", desc: "Tempat lahir", type: "text", required: true, satuan: null },
|
||||||
desc: "Nomor Induk Kependudukan pemohon"
|
{ key: "tanggal_lahir", name: "Tanggal Lahir", desc: "Tanggal lahir", type: "date", required: true, satuan: null },
|
||||||
},
|
{ key: "alamat", name: "Alamat", desc: "Alamat pemohon", type: "text", required: true, satuan: null },
|
||||||
{
|
{ key: "alasan", name: "Alasan Permohonan", desc: "Alasan permohonan", type: "text", required: true, satuan: null }
|
||||||
key: "nama",
|
|
||||||
name: "Nama Lengkap",
|
|
||||||
desc: "Nama lengkap pemohon"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "ttl",
|
|
||||||
name: "Tempat & Tanggal Lahir",
|
|
||||||
desc: "Tempat dan tanggal lahir pemohon"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "alamat",
|
|
||||||
name: "Alamat",
|
|
||||||
desc: "Alamat tempat tinggal pemohon"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "alasan",
|
|
||||||
name: "Alasan Permohonan",
|
|
||||||
desc: "Alasan pengajuan Surat Keterangan Tidak Mampu"
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
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, satuan: null },
|
||||||
key: "pengantar_kelian",
|
{ key: "ktp_kk", name: "KTP / KK", desc: "Fotokopi KTP/KK", required: true, satuan: null },
|
||||||
name: "Pengantar Kelian",
|
{ key: "foto_lokasi", name: "Foto Lokasi Usaha", desc: "Foto lokasi usaha", required: true, satuan: null }
|
||||||
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" },
|
{ key: "nama", name: "Nama Lengkap", desc: "Nama pemilik usaha", type: "text", required: true, satuan: null },
|
||||||
{ key: "jenis_kelamin", name: "Jenis Kelamin", desc: "Jenis kelamin pemilik usaha" },
|
{
|
||||||
{ key: "ttl", name: "Tempat & Tanggal Lahir", desc: "Tempat dan tanggal lahir" },
|
key: "jenis_kelamin",
|
||||||
{ key: "negara", name: "Kewarganegaraan", desc: "Kewarganegaraan pemilik usaha" },
|
name: "Jenis Kelamin",
|
||||||
{ key: "agama", name: "Agama", desc: "Agama pemilik usaha" },
|
desc: "Jenis kelamin pemilik usaha",
|
||||||
{ key: "status_perkawinan", name: "Status Perkawinan", desc: "Status perkawinan" },
|
type: "enum",
|
||||||
{ key: "alamat", name: "Alamat", desc: "Alamat tempat tinggal" },
|
options: enumJenisKelamin,
|
||||||
{ key: "pekerjaan", name: "Pekerjaan", desc: "Pekerjaan pemilik usaha" },
|
required: true, satuan: null
|
||||||
{ key: "jenis_usaha", name: "Jenis Usaha", desc: "Jenis usaha yang dijalankan" },
|
},
|
||||||
{ key: "alamat_usaha", name: "Alamat Usaha", desc: "Alamat lokasi usaha" }
|
{ key: "tempat_lahir", name: "Tempat Lahir", desc: "Tempat lahir", type: "text", required: true, satuan: null },
|
||||||
|
{ key: "tanggal_lahir", name: "Tanggal Lahir", desc: "Tanggal lahir", type: "date", required: true, satuan: null },
|
||||||
|
{ key: "negara", name: "Kewarganegaraan", desc: "Kewarganegaraan", type: "text", required: true, satuan: null },
|
||||||
|
{
|
||||||
|
key: "agama",
|
||||||
|
name: "Agama",
|
||||||
|
desc: "Agama",
|
||||||
|
type: "enum",
|
||||||
|
options: enumAgama,
|
||||||
|
required: true, satuan: null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "status_perkawinan",
|
||||||
|
name: "Status Perkawinan",
|
||||||
|
desc: "Status perkawinan",
|
||||||
|
type: "enum",
|
||||||
|
options: enumStatusPerkawinan,
|
||||||
|
required: true, satuan: null
|
||||||
|
},
|
||||||
|
{ key: "alamat", name: "Alamat", desc: "Alamat", type: "text", required: true, satuan: null },
|
||||||
|
{ key: "pekerjaan", name: "Pekerjaan", desc: "Pekerjaan", type: "text", required: true, satuan: null },
|
||||||
|
{ key: "jenis_usaha", name: "Jenis Usaha", desc: "Jenis usaha", type: "text", required: true, satuan: null },
|
||||||
|
{ key: "alamat_usaha", name: "Alamat Usaha", desc: "Alamat usaha", type: "text", required: true, satuan: null }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
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, satuan: null },
|
||||||
key: "pengantar_kelian",
|
{ key: "ktp_kia_kk", name: "KTP / KIA / KK", desc: "Fotokopi KTP/KIA/KK", required: true, satuan: null }
|
||||||
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" },
|
{ key: "nik", name: "NIK", desc: "NIK anak", type: "number", required: true, satuan: null },
|
||||||
{ key: "nama", name: "Nama Lengkap", desc: "Nama anak" },
|
{ key: "nama", name: "Nama", desc: "Nama anak", type: "text", required: true, satuan: null },
|
||||||
{ key: "ttl", name: "Tempat & Tanggal Lahir", desc: "Tempat dan tanggal lahir anak" },
|
{ key: "tempat_lahir", name: "Tempat Lahir", desc: "Tempat lahir", type: "text", required: true, satuan: null },
|
||||||
{ key: "jenis_kelamin", name: "Jenis Kelamin", desc: "Jenis kelamin anak" },
|
{ key: "tanggal_lahir", name: "Tanggal Lahir", desc: "Tanggal lahir", type: "date", required: true, satuan: null },
|
||||||
{ key: "alamat", name: "Alamat", desc: "Alamat tempat tinggal" },
|
{
|
||||||
{ key: "pekerjaan", name: "Pekerjaan", desc: "Pekerjaan (jika ada)" },
|
key: "jenis_kelamin",
|
||||||
{ key: "nama_ayah", name: "Nama Ayah", desc: "Nama ayah kandung" },
|
name: "Jenis Kelamin",
|
||||||
{ key: "status_ayah", name: "Status Ayah", desc: "Status ayah (hidup / meninggal)" },
|
desc: "Jenis kelamin anak",
|
||||||
{ key: "nama_ibu", name: "Nama Ibu", desc: "Nama ibu kandung" },
|
type: "enum",
|
||||||
{ key: "status_ibu", name: "Status Ibu", desc: "Status ibu (hidup / meninggal)" }
|
options: enumJenisKelamin,
|
||||||
|
required: true, satuan: null
|
||||||
|
},
|
||||||
|
{ key: "alamat", name: "Alamat", desc: "Alamat", type: "text", required: true, satuan: null },
|
||||||
|
{ key: "pekerjaan", name: "Pekerjaan", desc: "Pekerjaan (jika ada)", type: "text", required: false, satuan: null },
|
||||||
|
{ key: "nama_ayah", name: "Nama Ayah", desc: "Nama ayah", type: "text", required: true, satuan: null },
|
||||||
|
{
|
||||||
|
key: "status_ayah",
|
||||||
|
name: "Status Ayah",
|
||||||
|
desc: "Status ayah",
|
||||||
|
type: "enum",
|
||||||
|
options: enumStatusHidup,
|
||||||
|
required: true, satuan: null
|
||||||
|
},
|
||||||
|
{ key: "nama_ibu", name: "Nama Ibu", desc: "Nama ibu", type: "text", required: true, satuan: null },
|
||||||
|
{
|
||||||
|
key: "status_ibu",
|
||||||
|
name: "Status Ibu",
|
||||||
|
desc: "Status ibu",
|
||||||
|
type: "enum",
|
||||||
|
options: enumStatusHidup,
|
||||||
|
required: true, satuan: null
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -246,16 +246,6 @@
|
|||||||
"label": "View Detail",
|
"label": "View Detail",
|
||||||
"default": true
|
"default": true
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"key": "setting.kategori_pelayanan.tambah",
|
|
||||||
"label": "Tambah",
|
|
||||||
"default": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "setting.kategori_pelayanan.edit",
|
|
||||||
"label": "Edit",
|
|
||||||
"default": true
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"key": "setting.kategori_pelayanan.delete",
|
"key": "setting.kategori_pelayanan.delete",
|
||||||
"label": "Delete",
|
"label": "Delete",
|
||||||
|
|||||||
31
src/lib/valueEnum.ts
Normal file
31
src/lib/valueEnum.ts
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
export const enumJenisKelamin = [
|
||||||
|
{ label: "Laki-laki", value: "Laki-laki" },
|
||||||
|
{ label: "Perempuan", value: "Perempuan" }
|
||||||
|
];
|
||||||
|
|
||||||
|
export const enumAgama = [
|
||||||
|
{ label: "Islam", value: "Islam" },
|
||||||
|
{ label: "Kristen", value: "Kristen" },
|
||||||
|
{ label: "Katolik", value: "Katolik" },
|
||||||
|
{ label: "Hindu", value: "Hindu" },
|
||||||
|
{ label: "Buddha", value: "Buddha" },
|
||||||
|
{ label: "Konghucu", value: "Konghucu" }
|
||||||
|
];
|
||||||
|
|
||||||
|
export const enumStatusHidup = [
|
||||||
|
{ label: "Hidup", value: "Hidup" },
|
||||||
|
{ label: "Meninggal", value: "Meninggal" }
|
||||||
|
];
|
||||||
|
|
||||||
|
export const enumStatusPerkawinan = [
|
||||||
|
{ label: "Belum Kawin", value: "Belum Kawin" },
|
||||||
|
{ label: "Kawin", value: "Kawin" },
|
||||||
|
{ label: "Cerai Hidup", value: "Cerai Hidup" },
|
||||||
|
{ label: "Cerai Mati", value: "Cerai Mati" }
|
||||||
|
];
|
||||||
|
|
||||||
|
export const enumStatusTempatUsaha = [
|
||||||
|
{ label: "Milik Sendiri", value: "Milik Sendiri" },
|
||||||
|
{ label: "Sewa", value: "Sewa" },
|
||||||
|
{ label: "Pinjam", value: "Pinjam" }
|
||||||
|
];
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
import clientRoutes from "@/clientRoutes";
|
import clientRoutes from "@/clientRoutes";
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
Container,
|
Center,
|
||||||
Group,
|
Paper,
|
||||||
PasswordInput,
|
PasswordInput,
|
||||||
Stack,
|
Stack,
|
||||||
Text,
|
Text,
|
||||||
TextInput,
|
TextInput
|
||||||
} from "@mantine/core";
|
} from "@mantine/core";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import apiFetch from "../lib/apiFetch";
|
import apiFetch from "../lib/apiFetch";
|
||||||
@@ -73,25 +73,73 @@ export default function Login() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container>
|
<Center
|
||||||
<Stack>
|
h="100vh"
|
||||||
<Text>Login</Text>
|
style={{
|
||||||
<TextInput
|
background:
|
||||||
placeholder="Email"
|
"radial-gradient(circle at top, #1f2d2b 0%, #0b0f0e 60%)",
|
||||||
value={email}
|
}}
|
||||||
onChange={(e) => setEmail(e.target.value)}
|
>
|
||||||
/>
|
<Paper
|
||||||
<PasswordInput
|
radius="lg"
|
||||||
placeholder="Password"
|
p="xl"
|
||||||
value={password}
|
w={420}
|
||||||
onChange={(e) => setPassword(e.target.value)}
|
style={{
|
||||||
/>
|
background: "rgba(20, 20, 20, 0.75)",
|
||||||
<Group justify="right">
|
backdropFilter: "blur(12px)",
|
||||||
<Button onClick={handleSubmit} disabled={loading}>
|
border: "1px solid rgba(255, 255, 255, 0.08)",
|
||||||
|
boxShadow: "0 20px 60px rgba(0,0,0,0.6)",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Stack>
|
||||||
|
<Text
|
||||||
|
size="xl"
|
||||||
|
fw={700}
|
||||||
|
ta="center"
|
||||||
|
c="white"
|
||||||
|
>
|
||||||
|
Welcome Back
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
<Text
|
||||||
|
size="sm"
|
||||||
|
ta="center"
|
||||||
|
c="dimmed"
|
||||||
|
>
|
||||||
|
Sign in to continue to your dashboard
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
<TextInput
|
||||||
|
label="Email"
|
||||||
|
placeholder="Email"
|
||||||
|
value={email}
|
||||||
|
onChange={(e) => setEmail(e.target.value)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<PasswordInput
|
||||||
|
label="Password"
|
||||||
|
placeholder="Password"
|
||||||
|
value={password}
|
||||||
|
onChange={(e) => setPassword(e.target.value)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
fullWidth
|
||||||
|
mt="md"
|
||||||
|
radius="md"
|
||||||
|
size="md"
|
||||||
|
variant="gradient"
|
||||||
|
gradient={{ from: "teal", to: "cyan", deg: 45 }}
|
||||||
|
style={{
|
||||||
|
transition: "all 0.2s ease",
|
||||||
|
}}
|
||||||
|
onClick={handleSubmit}
|
||||||
|
disabled={loading}
|
||||||
|
>
|
||||||
Login
|
Login
|
||||||
</Button>
|
</Button>
|
||||||
</Group>
|
</Stack>
|
||||||
</Stack>
|
</Paper>
|
||||||
</Container>
|
</Center>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,13 +22,19 @@ import {
|
|||||||
TextInput,
|
TextInput,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
} from "@mantine/core";
|
} from "@mantine/core";
|
||||||
|
import { DateInput } from "@mantine/dates";
|
||||||
import { useDisclosure, useShallowEffect } from "@mantine/hooks";
|
import { useDisclosure, useShallowEffect } from "@mantine/hooks";
|
||||||
import {
|
import {
|
||||||
IconBuildingCommunity,
|
IconBuildingCommunity,
|
||||||
|
IconCategory,
|
||||||
|
IconFiles,
|
||||||
IconInfoCircle,
|
IconInfoCircle,
|
||||||
IconUpload,
|
IconNotes,
|
||||||
IconUser,
|
IconPhone,
|
||||||
|
IconUpload
|
||||||
} from "@tabler/icons-react";
|
} from "@tabler/icons-react";
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
import "dayjs/locale/id";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { useLocation, useNavigate } from "react-router-dom";
|
import { useLocation, useNavigate } from "react-router-dom";
|
||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
@@ -36,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 = {
|
||||||
@@ -46,7 +53,10 @@ type FormSurat = {
|
|||||||
syaratDokumen: DataItem[];
|
syaratDokumen: DataItem[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type ErrorState = Record<string, string | null>;
|
||||||
|
|
||||||
export default function FormSurat() {
|
export default function FormSurat() {
|
||||||
|
const [errors, setErrors] = useState<ErrorState>({});
|
||||||
const [opened, { open, close }] = useDisclosure(false);
|
const [opened, { open, close }] = useDisclosure(false);
|
||||||
const [noPengajuan, setNoPengajuan] = useState("");
|
const [noPengajuan, setNoPengajuan] = useState("");
|
||||||
const [submitLoading, setSubmitLoading] = useState(false);
|
const [submitLoading, setSubmitLoading] = useState(false);
|
||||||
@@ -87,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);
|
||||||
}
|
}
|
||||||
@@ -110,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
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
@@ -144,22 +156,24 @@ export default function FormSurat() {
|
|||||||
}, [jenisSuratFix.id]);
|
}, [jenisSuratFix.id]);
|
||||||
|
|
||||||
function onChecking() {
|
function onChecking() {
|
||||||
|
const hasError = Object.values(errors).some((v) => v);
|
||||||
|
|
||||||
|
if (hasError) {
|
||||||
|
return notification({
|
||||||
|
title: "Gagal",
|
||||||
|
message: "Masih ada form yang belum valid",
|
||||||
|
type: "error",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const isFormKosong = Object.values(formSurat).some((value) => {
|
const isFormKosong = Object.values(formSurat).some((value) => {
|
||||||
if (Array.isArray(value)) {
|
if (Array.isArray(value)) {
|
||||||
return (
|
return value.some(
|
||||||
value.length === 0 ||
|
(item) =>
|
||||||
value.some(
|
(typeof item.value === "string" && item.value.trim() === "" && item.required) || (typeof item.value === "object" && item.value === null && item.required),
|
||||||
(item) =>
|
|
||||||
typeof item.value === "string" && item.value.trim() === "",
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
return typeof value === "string" && value.trim() === "";
|
||||||
if (typeof value === "string") {
|
|
||||||
return value.trim() === "";
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (isFormKosong) {
|
if (isFormKosong) {
|
||||||
@@ -168,9 +182,9 @@ export default function FormSurat() {
|
|||||||
message: "Silahkan lengkapi form surat",
|
message: "Silahkan lengkapi form surat",
|
||||||
type: "error",
|
type: "error",
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
open();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
open();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function onSubmit() {
|
async function onSubmit() {
|
||||||
@@ -233,6 +247,30 @@ export default function FormSurat() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function validateField(key: string, value: any) {
|
||||||
|
const stringValue = String(value ?? "").trim();
|
||||||
|
|
||||||
|
// wajib diisi
|
||||||
|
if (!stringValue) {
|
||||||
|
return "Field wajib diisi";
|
||||||
|
}
|
||||||
|
|
||||||
|
// 🔥 semua key yang mengandung "nik"
|
||||||
|
if (key.toLowerCase().includes("nik")) {
|
||||||
|
if (!/^\d+$/.test(stringValue)) {
|
||||||
|
return "NIK harus berupa angka";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stringValue.length !== 16) {
|
||||||
|
return "NIK harus 16 digit";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function validationForm({
|
function validationForm({
|
||||||
key,
|
key,
|
||||||
value,
|
value,
|
||||||
@@ -240,12 +278,28 @@ export default function FormSurat() {
|
|||||||
key: "nama" | "phone" | "dataPelengkap" | "syaratDokumen";
|
key: "nama" | "phone" | "dataPelengkap" | "syaratDokumen";
|
||||||
value: any;
|
value: any;
|
||||||
}) {
|
}) {
|
||||||
if (key == "dataPelengkap" || key == "syaratDokumen") {
|
if (key === "dataPelengkap" || key === "syaratDokumen") {
|
||||||
|
if (value.required == true) {
|
||||||
|
const errorMsg = validateField(value.key, value.value);
|
||||||
|
|
||||||
|
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),
|
||||||
}));
|
}));
|
||||||
} else {
|
} else {
|
||||||
|
const keyFix = key == "nama" ? "nama_kontak" : key;
|
||||||
|
const errorMsg = validateField(keyFix, value);
|
||||||
|
|
||||||
|
setErrors((prev) => ({
|
||||||
|
...prev,
|
||||||
|
[keyFix]: errorMsg,
|
||||||
|
}));
|
||||||
|
|
||||||
setFormSurat({
|
setFormSurat({
|
||||||
...formSurat,
|
...formSurat,
|
||||||
[key]: value,
|
[key]: value,
|
||||||
@@ -253,6 +307,7 @@ export default function FormSurat() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container size="md" w={"100%"} pb={"lg"}>
|
<Container size="md" w={"100%"} pb={"lg"}>
|
||||||
<Modal
|
<Modal
|
||||||
@@ -262,9 +317,7 @@ export default function FormSurat() {
|
|||||||
overlayProps={{ backgroundOpacity: 0.55, blur: 3 }}
|
overlayProps={{ backgroundOpacity: 0.55, blur: 3 }}
|
||||||
>
|
>
|
||||||
<Stack gap="sm">
|
<Stack gap="sm">
|
||||||
<Text>
|
<Text>Apakah anda yakin ingin mengirim pengajuan surat ini?</Text>
|
||||||
Apakah anda yakin ingin mengirim pengajuan surat ini?
|
|
||||||
</Text>
|
|
||||||
<Group justify="center" grow>
|
<Group justify="center" grow>
|
||||||
<Button variant="light" onClick={close}>
|
<Button variant="light" onClick={close}>
|
||||||
Tidak
|
Tidak
|
||||||
@@ -292,8 +345,7 @@ export default function FormSurat() {
|
|||||||
}}
|
}}
|
||||||
category="create"
|
category="create"
|
||||||
/>
|
/>
|
||||||
)
|
) : (
|
||||||
:
|
|
||||||
<Box>
|
<Box>
|
||||||
<Stack gap="lg">
|
<Stack gap="lg">
|
||||||
<Group justify="space-between" align="center">
|
<Group justify="space-between" align="center">
|
||||||
@@ -310,46 +362,18 @@ export default function FormSurat() {
|
|||||||
</div>
|
</div>
|
||||||
</Group>
|
</Group>
|
||||||
<Group>
|
<Group>
|
||||||
<Badge radius="sm">Form Length: 3 Sections</Badge>
|
<Badge radius="sm">Form Length: 4 Sections</Badge>
|
||||||
</Group>
|
</Group>
|
||||||
</Group>
|
</Group>
|
||||||
<Stack gap="lg">
|
<Stack gap="lg">
|
||||||
{/* Header Section */}
|
|
||||||
<FormSection
|
<FormSection
|
||||||
title="Pemohon"
|
title="Jenis Surat Pengajuan"
|
||||||
icon={<IconUser size={16} />}
|
icon={<IconCategory size={16} />}
|
||||||
description="Informasi identitas pemohon"
|
|
||||||
>
|
>
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.Col span={6}>
|
|
||||||
<TextInput
|
|
||||||
label={<FieldLabel label="Nama" hint="Nama pemohon" />}
|
|
||||||
placeholder="Budi Setiawan"
|
|
||||||
value={formSurat.nama}
|
|
||||||
onChange={(e) =>
|
|
||||||
validationForm({ key: "nama", value: e.target.value })
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</Grid.Col>
|
|
||||||
|
|
||||||
<Grid.Col span={6}>
|
|
||||||
<TextInput
|
|
||||||
label={
|
|
||||||
<FieldLabel
|
|
||||||
label="Nomor Telephone"
|
|
||||||
hint="Nomor telephone yang dapat dihubungi / terhubung dengan whatsapp"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
placeholder="08123456789"
|
|
||||||
value={formSurat.phone}
|
|
||||||
onChange={(e) =>
|
|
||||||
validationForm({ key: "phone", value: e.target.value })
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</Grid.Col>
|
|
||||||
|
|
||||||
<Grid.Col span={12}>
|
<Grid.Col span={12}>
|
||||||
<Select
|
<Select
|
||||||
|
allowDeselect={false}
|
||||||
label={
|
label={
|
||||||
<FieldLabel
|
<FieldLabel
|
||||||
label="Jenis Surat"
|
label="Jenis Surat"
|
||||||
@@ -361,7 +385,7 @@ export default function FormSurat() {
|
|||||||
value: item.name,
|
value: item.name,
|
||||||
label: item.name,
|
label: item.name,
|
||||||
}))}
|
}))}
|
||||||
value={jenisSuratFix.name}
|
value={jenisSuratFix.name == "" ? null : jenisSuratFix.name}
|
||||||
onChange={(value) => {
|
onChange={(value) => {
|
||||||
const slug = toSlug(String(value));
|
const slug = toSlug(String(value));
|
||||||
navigate("/darmasaba/surat?jenis=" + slug);
|
navigate("/darmasaba/surat?jenis=" + slug);
|
||||||
@@ -371,83 +395,209 @@ export default function FormSurat() {
|
|||||||
</Grid>
|
</Grid>
|
||||||
</FormSection>
|
</FormSection>
|
||||||
|
|
||||||
{jenisSuratFix.id != "" && dataSurat && dataSurat.dataPelengkap && (
|
{/* Kontak Section */}
|
||||||
<>
|
<FormSection
|
||||||
<FormSection
|
title="Kontak"
|
||||||
title="Data Pelengkap"
|
icon={<IconPhone size={16} />}
|
||||||
description="Data pelengkap yang diperlukan"
|
description="Informasi kontak yg dapat dihubungi"
|
||||||
>
|
>
|
||||||
<Grid>
|
<Grid>
|
||||||
{dataSurat.dataPelengkap.map((item: any, index: number) => (
|
<Grid.Col span={6}>
|
||||||
<Grid.Col span={6} key={index}>
|
<TextInput
|
||||||
<TextInput
|
label={<FieldLabel label="Nama" hint="Nama kontak" required />}
|
||||||
label={
|
placeholder="Budi Setiawan"
|
||||||
<FieldLabel label={item.name} hint={item.desc} />
|
value={formSurat.nama}
|
||||||
}
|
error={errors.nama_kontak}
|
||||||
placeholder={item.name}
|
onChange={(e) =>
|
||||||
onChange={(e) =>
|
validationForm({ key: "nama", value: e.target.value })
|
||||||
validationForm({
|
}
|
||||||
key: "dataPelengkap",
|
/>
|
||||||
value: { key: item.key, value: e.target.value },
|
</Grid.Col>
|
||||||
})
|
|
||||||
}
|
|
||||||
value={
|
|
||||||
formSurat.dataPelengkap.find(
|
|
||||||
(n: any) => n.key == item.key,
|
|
||||||
)?.value
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</Grid.Col>
|
|
||||||
))}
|
|
||||||
</Grid>
|
|
||||||
</FormSection>
|
|
||||||
|
|
||||||
<FormSection
|
<Grid.Col span={6}>
|
||||||
title="Syarat Dokumen"
|
<TextInput
|
||||||
description="Syarat dokumen yang diperlukan"
|
label={
|
||||||
>
|
<FieldLabel
|
||||||
<Grid>
|
required
|
||||||
{dataSurat.syaratDokumen.map((item: any, index: number) => (
|
label="Nomor Telephone"
|
||||||
<Grid.Col span={6} key={index}>
|
hint="Nomor telephone yang dapat dihubungi / terhubung dengan whatsapp"
|
||||||
<FileInputWrapper
|
/>
|
||||||
label={item.desc}
|
}
|
||||||
placeholder={"Upload file "}
|
placeholder="08123456789"
|
||||||
accept="image/*,application/pdf"
|
value={formSurat.phone}
|
||||||
onChange={(file) =>
|
error={errors.phone}
|
||||||
validationForm({
|
type="number"
|
||||||
key: "syaratDokumen",
|
onChange={(e) =>
|
||||||
value: { key: item.key, value: file },
|
validationForm({ key: "phone", value: e.target.value })
|
||||||
})
|
}
|
||||||
}
|
/>
|
||||||
name={item.name}
|
</Grid.Col>
|
||||||
/>
|
</Grid>
|
||||||
</Grid.Col>
|
</FormSection>
|
||||||
))}
|
|
||||||
</Grid>
|
|
||||||
</FormSection>
|
|
||||||
|
|
||||||
{/* Actions */}
|
{jenisSuratFix.id != "" &&
|
||||||
<Group justify="right" mt="md">
|
dataSurat &&
|
||||||
{/* <Button variant="default" onClick={() => { }}>
|
dataSurat.dataPelengkap && (
|
||||||
|
<>
|
||||||
|
<FormSection
|
||||||
|
title="Data Yang Diperlukan"
|
||||||
|
description="Data yang diperlukan untuk mengajukan surat"
|
||||||
|
icon={<IconNotes size={16} />}
|
||||||
|
>
|
||||||
|
<Grid>
|
||||||
|
{dataSurat.dataPelengkap.map(
|
||||||
|
(item: any, index: number) => (
|
||||||
|
<Grid.Col span={6} key={index}>
|
||||||
|
{item.type == "enum" ? (
|
||||||
|
<Select
|
||||||
|
allowDeselect={false}
|
||||||
|
label={
|
||||||
|
<FieldLabel
|
||||||
|
label={item.name}
|
||||||
|
hint={item.desc}
|
||||||
|
required={item.required}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
data={item.options ?? []}
|
||||||
|
placeholder={item.name}
|
||||||
|
onChange={(e) => {
|
||||||
|
validationForm({
|
||||||
|
key: "dataPelengkap",
|
||||||
|
value: { key: item.key, value: e, required: item.required },
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
value={
|
||||||
|
formSurat.dataPelengkap.find(
|
||||||
|
(n: any) => n.key == item.key,
|
||||||
|
)?.value
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
) : item.type == "date" ? (
|
||||||
|
<DateInput
|
||||||
|
locale="id"
|
||||||
|
valueFormat="DD MMMM YYYY"
|
||||||
|
label={
|
||||||
|
<FieldLabel
|
||||||
|
label={item.name}
|
||||||
|
hint={item.desc}
|
||||||
|
required={item.required}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
placeholder={item.name}
|
||||||
|
onChange={(e) => {
|
||||||
|
const formatted = e
|
||||||
|
? dayjs(e)
|
||||||
|
.locale("id")
|
||||||
|
.format("DD MMMM YYYY")
|
||||||
|
: "";
|
||||||
|
validationForm({
|
||||||
|
key: "dataPelengkap",
|
||||||
|
value: {
|
||||||
|
key: item.key,
|
||||||
|
value: formatted,
|
||||||
|
required: item.required,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<TextInput
|
||||||
|
error={errors[item.key]}
|
||||||
|
type={item.type}
|
||||||
|
label={
|
||||||
|
<FieldLabel
|
||||||
|
label={item.name}
|
||||||
|
hint={item.desc}
|
||||||
|
required={item.required}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
placeholder={item.name}
|
||||||
|
onChange={(e) =>
|
||||||
|
validationForm({
|
||||||
|
key: "dataPelengkap",
|
||||||
|
value: {
|
||||||
|
key: item.key,
|
||||||
|
value: e.target.value,
|
||||||
|
required: item.required,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
value={
|
||||||
|
formSurat.dataPelengkap.find(
|
||||||
|
(n: any) => n.key == item.key,
|
||||||
|
)?.value
|
||||||
|
}
|
||||||
|
rightSection={
|
||||||
|
item.satuan != null &&
|
||||||
|
<Text mr={"lg"}>{item.satuan}</Text>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Grid.Col>
|
||||||
|
),
|
||||||
|
)}
|
||||||
|
</Grid>
|
||||||
|
</FormSection>
|
||||||
|
|
||||||
|
<FormSection
|
||||||
|
title="Syarat Dokumen"
|
||||||
|
description="Syarat dokumen yang diperlukan"
|
||||||
|
icon={<IconFiles size={16} />}
|
||||||
|
>
|
||||||
|
<Grid>
|
||||||
|
{dataSurat.syaratDokumen.map(
|
||||||
|
(item: any, index: number) => (
|
||||||
|
<Grid.Col span={6} key={index}>
|
||||||
|
<FileInputWrapper
|
||||||
|
label={item.desc}
|
||||||
|
placeholder={"Upload file "}
|
||||||
|
accept="image/*,application/pdf"
|
||||||
|
onChange={(file) =>
|
||||||
|
validationForm({
|
||||||
|
key: "syaratDokumen",
|
||||||
|
value: { key: item.key, value: file },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
name={item.name}
|
||||||
|
required={item.required}
|
||||||
|
/>
|
||||||
|
</Grid.Col>
|
||||||
|
),
|
||||||
|
)}
|
||||||
|
</Grid>
|
||||||
|
</FormSection>
|
||||||
|
|
||||||
|
{/* Actions */}
|
||||||
|
<Group justify="right" mt="md">
|
||||||
|
{/* <Button variant="default" onClick={() => { }}>
|
||||||
Reset
|
Reset
|
||||||
</Button> */}
|
</Button> */}
|
||||||
<Button onClick={onChecking}>Kirim</Button>
|
<Button onClick={onChecking}>Kirim</Button>
|
||||||
</Group>
|
</Group>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</Stack>
|
</Stack>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Box>
|
</Box>
|
||||||
}
|
)}
|
||||||
|
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
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">
|
||||||
@@ -459,6 +609,7 @@ function FieldLabel({ label, hint }: { label: string; hint?: string }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function FormSection({
|
function FormSection({
|
||||||
title,
|
title,
|
||||||
icon,
|
icon,
|
||||||
@@ -494,6 +645,7 @@ function FileInputWrapper({
|
|||||||
preview,
|
preview,
|
||||||
name,
|
name,
|
||||||
description,
|
description,
|
||||||
|
required = false,
|
||||||
}: {
|
}: {
|
||||||
label: string;
|
label: string;
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
@@ -502,12 +654,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 }}>
|
||||||
@@ -523,6 +683,7 @@ function FileInputWrapper({
|
|||||||
leftSection={<IconUpload />}
|
leftSection={<IconUpload />}
|
||||||
aria-label={label}
|
aria-label={label}
|
||||||
name={name}
|
name={name}
|
||||||
|
clearable={true}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{preview ? (
|
{preview ? (
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -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",
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
|
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";
|
||||||
import apiFetch from "@/lib/apiFetch";
|
import apiFetch from "@/lib/apiFetch";
|
||||||
|
import { parseTanggalID } from "@/server/lib/stringToDate";
|
||||||
import {
|
import {
|
||||||
|
ActionIcon,
|
||||||
Anchor,
|
Anchor,
|
||||||
Badge,
|
Badge,
|
||||||
Button,
|
Button,
|
||||||
@@ -14,23 +18,31 @@ import {
|
|||||||
Group,
|
Group,
|
||||||
List,
|
List,
|
||||||
Modal,
|
Modal,
|
||||||
|
Select,
|
||||||
|
Spoiler,
|
||||||
Stack,
|
Stack,
|
||||||
Table,
|
Table,
|
||||||
Text,
|
Text,
|
||||||
Textarea,
|
Textarea,
|
||||||
|
TextInput,
|
||||||
ThemeIcon,
|
ThemeIcon,
|
||||||
Title,
|
Title,
|
||||||
|
Tooltip
|
||||||
} from "@mantine/core";
|
} from "@mantine/core";
|
||||||
|
import { DateInput } from "@mantine/dates";
|
||||||
import { useDisclosure, useShallowEffect } from "@mantine/hooks";
|
import { useDisclosure, useShallowEffect } from "@mantine/hooks";
|
||||||
import {
|
import {
|
||||||
IconAlignJustified,
|
IconAlignJustified,
|
||||||
IconCheck,
|
IconCheck,
|
||||||
|
IconEdit,
|
||||||
IconFileCertificate,
|
IconFileCertificate,
|
||||||
IconFileCheck,
|
IconFileCheck,
|
||||||
|
IconInfoCircle,
|
||||||
IconMessageReport,
|
IconMessageReport,
|
||||||
IconPhone,
|
IconPhone,
|
||||||
IconUser,
|
IconUser,
|
||||||
} from "@tabler/icons-react";
|
} from "@tabler/icons-react";
|
||||||
|
import dayjs from "dayjs";
|
||||||
import type { User } from "generated/prisma";
|
import type { User } from "generated/prisma";
|
||||||
import type { JsonValue } from "generated/prisma/runtime/library";
|
import type { JsonValue } from "generated/prisma/runtime/library";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
@@ -39,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");
|
||||||
@@ -57,10 +74,14 @@ 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
|
||||||
data={data?.data?.pengajuan}
|
data={data?.data?.pengajuan}
|
||||||
|
warga={data && data.data && data.data.warga ? data.data.warga : undefined}
|
||||||
syaratDokumen={data?.data?.syaratDokumen}
|
syaratDokumen={data?.data?.syaratDokumen}
|
||||||
dataText={data?.data?.dataText}
|
dataText={data?.data?.dataText}
|
||||||
onAction={() => {
|
onAction={() => {
|
||||||
@@ -80,15 +101,18 @@ export default function DetailPengajuanPage() {
|
|||||||
|
|
||||||
function DetailDataPengajuan({
|
function DetailDataPengajuan({
|
||||||
data,
|
data,
|
||||||
|
warga,
|
||||||
syaratDokumen,
|
syaratDokumen,
|
||||||
dataText,
|
dataText,
|
||||||
onAction,
|
onAction,
|
||||||
}: {
|
}: {
|
||||||
data: any;
|
data: any;
|
||||||
|
warga?: { phone?: string | null } | null;
|
||||||
syaratDokumen: any;
|
syaratDokumen: any;
|
||||||
dataText: any;
|
dataText: any;
|
||||||
onAction: () => void;
|
onAction: () => void;
|
||||||
}) {
|
}) {
|
||||||
|
|
||||||
const [opened, { open, close }] = useDisclosure(false);
|
const [opened, { open, close }] = useDisclosure(false);
|
||||||
const [catModal, setCatModal] = useState<"tolak" | "terima">("tolak");
|
const [catModal, setCatModal] = useState<"tolak" | "terima">("tolak");
|
||||||
const [keterangan, setKeterangan] = useState("");
|
const [keterangan, setKeterangan] = useState("");
|
||||||
@@ -97,7 +121,12 @@ function DetailDataPengajuan({
|
|||||||
const [openedPreview, setOpenedPreview] = useState(false);
|
const [openedPreview, setOpenedPreview] = useState(false);
|
||||||
const [openedPreviewFile, setOpenedPreviewFile] = useState(false);
|
const [openedPreviewFile, setOpenedPreviewFile] = useState(false);
|
||||||
const [permissions, setPermissions] = useState<JsonValue[]>([]);
|
const [permissions, setPermissions] = useState<JsonValue[]>([]);
|
||||||
const [viewImg, setViewImg] = useState("");
|
const [viewImg, setViewImg] = useState({ file: "", folder: "" });
|
||||||
|
const [uploading, setUploading] = useState({ ok: false, file: "" });
|
||||||
|
const [editValue, setEditValue] = useState({ id: "", jenis: "", val: "", satuan: null as string | null, option: null as any, type: "", key: "" })
|
||||||
|
const [openEdit, setOpenEdit] = useState(false)
|
||||||
|
const [loadingUpdate, setLoadingUpdate] = useState(false)
|
||||||
|
const [loadingFS, setLoadingFS] = useState({ value: false, text: "" })
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function fetchHost() {
|
async function fetchHost() {
|
||||||
@@ -114,22 +143,88 @@ function DetailDataPengajuan({
|
|||||||
fetchHost();
|
fetchHost();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
async function sendWA({ status, linkSurat, linkUpdate }: { status: string, linkSurat: string, linkUpdate: string }) {
|
||||||
|
try {
|
||||||
|
setLoadingFS({ value: true, text: "Sending message to warga" })
|
||||||
|
const resWA = await apiFetch.api["send-wa"]["pengajuan-surat"].post({
|
||||||
|
noPengajuan: data?.noPengajuan ?? "",
|
||||||
|
jenisSurat: data?.category ?? "",
|
||||||
|
alasan: keterangan,
|
||||||
|
status,
|
||||||
|
linkSurat,
|
||||||
|
linkUpdate,
|
||||||
|
tlp: warga?.phone ?? "",
|
||||||
|
})
|
||||||
|
|
||||||
|
if (resWA?.status === 200) {
|
||||||
|
if (resWA.data?.success) {
|
||||||
|
notification({
|
||||||
|
title: "Success",
|
||||||
|
message: "Success send message to warga",
|
||||||
|
type: "success",
|
||||||
|
});
|
||||||
|
|
||||||
|
if (status == "selesai") {
|
||||||
|
onAction()
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
notification({
|
||||||
|
title: "Failed",
|
||||||
|
message: "Failed send message to warga",
|
||||||
|
type: "error",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
notification({
|
||||||
|
title: "Failed",
|
||||||
|
message: "Failed send message to warga",
|
||||||
|
type: "error",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
notification({
|
||||||
|
title: "Failed",
|
||||||
|
message: "Failed send message to warga",
|
||||||
|
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"
|
||||||
|
? "ditolak"
|
||||||
|
: data.status == "antrian"
|
||||||
|
? "diterima"
|
||||||
|
: "selesai"
|
||||||
|
|
||||||
const res = await apiFetch.api.pelayanan["update-status"].post({
|
const res = await apiFetch.api.pelayanan["update-status"].post({
|
||||||
id: data?.id,
|
id: data?.id,
|
||||||
status:
|
status: statusFix,
|
||||||
cat == "tolak"
|
|
||||||
? "ditolak"
|
|
||||||
: data.status == "antrian"
|
|
||||||
? "diterima"
|
|
||||||
: "selesai",
|
|
||||||
keterangan: keterangan,
|
keterangan: keterangan,
|
||||||
idUser: host?.id ?? "",
|
idUser: host?.id ?? "",
|
||||||
noSurat: noSurat,
|
noSurat: noSurat,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (res?.status === 200) {
|
if (res?.status === 200) {
|
||||||
|
if (statusFix == "selesai") {
|
||||||
|
setTimeout(() => {
|
||||||
|
setOpenedPreview(true)
|
||||||
|
}, 1000)
|
||||||
|
} else {
|
||||||
|
sendWA({
|
||||||
|
status: statusFix,
|
||||||
|
linkSurat: "",
|
||||||
|
linkUpdate: statusFix == "ditolak" ? res.data?.linkUpdate ?? '' : '',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
onAction();
|
onAction();
|
||||||
close();
|
close();
|
||||||
notification({
|
notification({
|
||||||
@@ -151,24 +246,158 @@ function DetailDataPengajuan({
|
|||||||
message: "Failed to update pengajuan surat",
|
message: "Failed to update pengajuan surat",
|
||||||
type: "error",
|
type: "error",
|
||||||
});
|
});
|
||||||
|
} finally {
|
||||||
|
setLoadingFS({ value: false, text: "" })
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
async function updateDataText() {
|
||||||
|
try {
|
||||||
|
setLoadingUpdate(true)
|
||||||
|
const res = await apiFetch.api.pelayanan["update-data-pelengkap"].post({
|
||||||
|
id: editValue.id,
|
||||||
|
value: editValue.val,
|
||||||
|
jenis: editValue.key,
|
||||||
|
idUser: host?.id ?? "",
|
||||||
|
})
|
||||||
|
|
||||||
|
if (res?.status === 200) {
|
||||||
|
notification({
|
||||||
|
title: "Success",
|
||||||
|
message: "Success update data",
|
||||||
|
type: "success",
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
notification({
|
||||||
|
title: "Error",
|
||||||
|
message: "Failed to update data",
|
||||||
|
type: "error",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
notification({
|
||||||
|
title: "Error",
|
||||||
|
message: "Failed to update data",
|
||||||
|
type: "error",
|
||||||
|
})
|
||||||
|
} finally {
|
||||||
|
setLoadingUpdate(false)
|
||||||
|
setOpenEdit(false)
|
||||||
|
onAction()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
useShallowEffect(() => {
|
useShallowEffect(() => {
|
||||||
if (viewImg) {
|
if (viewImg) {
|
||||||
setOpenedPreviewFile(true);
|
setOpenedPreviewFile(true);
|
||||||
}
|
}
|
||||||
}, [viewImg]);
|
}, [viewImg]);
|
||||||
|
|
||||||
|
useShallowEffect(() => {
|
||||||
|
if (uploading.ok && uploading.file) {
|
||||||
|
sendWA({
|
||||||
|
status: "selesai",
|
||||||
|
linkSurat: uploading.file,
|
||||||
|
linkUpdate: "",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [uploading]);
|
||||||
|
|
||||||
|
function FieldLabel({ label, hint }: { label: string; hint?: string }) {
|
||||||
|
return (
|
||||||
|
<Group justify="apart" gap="xs" align="center">
|
||||||
|
<Text fw={600}>{label}</Text>
|
||||||
|
{hint && (
|
||||||
|
<Tooltip label={hint} withArrow>
|
||||||
|
<ActionIcon size={24} variant="subtle">
|
||||||
|
<IconInfoCircle size={16} />
|
||||||
|
</ActionIcon>
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
|
</Group>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
||||||
|
<FullScreenLoading visible={loadingFS.value} text={loadingFS.text} />
|
||||||
|
{/* MODAL EDIT DATA PELENGKAP */}
|
||||||
|
<Modal
|
||||||
|
opened={openEdit}
|
||||||
|
onClose={() => setOpenEdit(false)}
|
||||||
|
title={"Edit"}
|
||||||
|
overlayProps={{ backgroundOpacity: 0.55, blur: 3 }}
|
||||||
|
>
|
||||||
|
<Stack gap="ld">
|
||||||
|
{editValue.type == "enum" ? (
|
||||||
|
<Select
|
||||||
|
allowDeselect={false}
|
||||||
|
label={<FieldLabel label={editValue.jenis} />}
|
||||||
|
data={editValue.option ?? []}
|
||||||
|
placeholder={editValue.jenis}
|
||||||
|
onChange={(e) => { setEditValue({ ...editValue, val: e ?? "" }) }}
|
||||||
|
value={editValue.val}
|
||||||
|
/>
|
||||||
|
) : editValue.type == "date" ? (
|
||||||
|
<DateInput
|
||||||
|
locale="id"
|
||||||
|
valueFormat="DD MMMM YYYY"
|
||||||
|
label={<FieldLabel label={editValue.jenis} />}
|
||||||
|
placeholder={editValue.jenis}
|
||||||
|
onChange={(e) => {
|
||||||
|
const formatted = e
|
||||||
|
? dayjs(e).locale("id").format("DD MMMM YYYY")
|
||||||
|
: "";
|
||||||
|
setEditValue({
|
||||||
|
...editValue,
|
||||||
|
val: formatted
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
value={
|
||||||
|
editValue.val
|
||||||
|
? parseTanggalID(editValue.val)
|
||||||
|
: parseTanggalID(editValue.val)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<TextInput
|
||||||
|
label={<FieldLabel label={editValue.jenis} />}
|
||||||
|
placeholder={editValue.jenis}
|
||||||
|
type={editValue.type}
|
||||||
|
onChange={(e) => { setEditValue({ ...editValue, val: e.target.value }) }}
|
||||||
|
value={editValue.val}
|
||||||
|
rightSection={
|
||||||
|
editValue.satuan != null &&
|
||||||
|
<Text mr={"lg"}>{editValue.satuan}</Text>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<Group justify="center" grow>
|
||||||
|
<Button variant="light" onClick={() => { setOpenEdit(false) }}>
|
||||||
|
Batal
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="filled"
|
||||||
|
onClick={updateDataText}
|
||||||
|
disabled={loadingUpdate || !editValue.val}
|
||||||
|
loading={loadingUpdate}
|
||||||
|
>
|
||||||
|
Simpan
|
||||||
|
</Button>
|
||||||
|
</Group>
|
||||||
|
</Stack>
|
||||||
|
</Modal>
|
||||||
|
|
||||||
<ModalFile
|
<ModalFile
|
||||||
open={openedPreviewFile && !_.isEmpty(viewImg)}
|
open={openedPreviewFile && !_.isEmpty(viewImg.file)}
|
||||||
onClose={() => {
|
onClose={() => {
|
||||||
setOpenedPreviewFile(false);
|
setOpenedPreviewFile(false);
|
||||||
|
setViewImg({ file: "", folder: "" })
|
||||||
}}
|
}}
|
||||||
folder="syarat-dokumen"
|
folder={viewImg.folder}
|
||||||
fileName={viewImg}
|
fileName={viewImg.file}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* MODAL KONFIRMASI */}
|
{/* MODAL KONFIRMASI */}
|
||||||
@@ -240,10 +469,15 @@ function DetailDataPengajuan({
|
|||||||
)}
|
)}
|
||||||
</Stack>
|
</Stack>
|
||||||
</Modal>
|
</Modal>
|
||||||
{data?.status == "selesai" && (
|
|
||||||
|
{/* MODAL PREVIEW SURAT */}
|
||||||
|
{data?.status == "selesai" && !data?.fileSurat && (
|
||||||
<ModalSurat
|
<ModalSurat
|
||||||
open={openedPreview}
|
open={openedPreview}
|
||||||
onClose={() => setOpenedPreview(false)}
|
onClose={(val) => {
|
||||||
|
setOpenedPreview(false)
|
||||||
|
setUploading({ ok: val.success, file: val.data })
|
||||||
|
}}
|
||||||
surat={data?.idSurat}
|
surat={data?.idSurat}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
@@ -311,7 +545,7 @@ function DetailDataPengajuan({
|
|||||||
<List.Item key={v.id}>
|
<List.Item key={v.id}>
|
||||||
<Anchor
|
<Anchor
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setViewImg(v.value);
|
setViewImg({ file: v.value, folder: "syarat-dokumen" });
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{v.jenis}
|
{v.jenis}
|
||||||
@@ -338,7 +572,25 @@ function DetailDataPengajuan({
|
|||||||
</Table.Td>
|
</Table.Td>
|
||||||
<Table.Td>:</Table.Td>
|
<Table.Td>:</Table.Td>
|
||||||
<Table.Td style={{ width: "85%" }}>
|
<Table.Td style={{ width: "85%" }}>
|
||||||
{_.upperFirst(item.value)}
|
<Flex
|
||||||
|
gap="md"
|
||||||
|
justify="flex-start"
|
||||||
|
align="center"
|
||||||
|
direction="row"
|
||||||
|
>
|
||||||
|
<Text>
|
||||||
|
{_.upperFirst(item.value)} {item.satuan}
|
||||||
|
</Text>
|
||||||
|
<ActionIcon
|
||||||
|
variant="subtle"
|
||||||
|
aria-label="Edit"
|
||||||
|
onClick={() => {
|
||||||
|
setEditValue({ id: item.id, val: item.value, type: item.type, satuan: item.satuan, option: item.options, jenis: item.jenis, key: item.key })
|
||||||
|
setOpenEdit(true)
|
||||||
|
}}>
|
||||||
|
<IconEdit size={16} />
|
||||||
|
</ActionIcon>
|
||||||
|
</Flex>
|
||||||
</Table.Td>
|
</Table.Td>
|
||||||
</Table.Tr>
|
</Table.Tr>
|
||||||
))}
|
))}
|
||||||
@@ -396,18 +648,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={() => setOpenedPreview(!openedPreview)}
|
<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>
|
||||||
@@ -432,41 +697,48 @@ function DetailDataHistori({ data }: { data: any }) {
|
|||||||
<Stack gap="md">
|
<Stack gap="md">
|
||||||
<Flex align="center" justify="space-between">
|
<Flex align="center" justify="space-between">
|
||||||
<Title order={4} c="gray.2">
|
<Title order={4} c="gray.2">
|
||||||
Histori Pengajuan Surat
|
Riwayat Pengajuan Surat
|
||||||
</Title>
|
</Title>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Divider my={0} />
|
<Divider my={0} />
|
||||||
<Table>
|
<Spoiler
|
||||||
<Table.Thead>
|
maxHeight={200}
|
||||||
<Table.Tr>
|
showLabel="Show more"
|
||||||
<Table.Th>Tanggal</Table.Th>
|
hideLabel="Hide"
|
||||||
<Table.Th>Deskripsi</Table.Th>
|
transitionDuration={1000}
|
||||||
<Table.Th>Status</Table.Th>
|
>
|
||||||
<Table.Th>User</Table.Th>
|
<Table>
|
||||||
</Table.Tr>
|
<Table.Thead>
|
||||||
</Table.Thead>
|
<Table.Tr>
|
||||||
<Table.Tbody>
|
<Table.Th>Tanggal</Table.Th>
|
||||||
{data?.map((item: any) => (
|
<Table.Th>Deskripsi</Table.Th>
|
||||||
<Table.Tr key={item.id}>
|
<Table.Th>Status</Table.Th>
|
||||||
<Table.Td style={{ whiteSpace: "nowrap" }}>
|
<Table.Th>User</Table.Th>
|
||||||
{item.createdAt.toLocaleString("id-ID", {
|
|
||||||
day: "2-digit",
|
|
||||||
month: "short",
|
|
||||||
year: "numeric",
|
|
||||||
hour: "2-digit",
|
|
||||||
minute: "2-digit",
|
|
||||||
hour12: false,
|
|
||||||
})}
|
|
||||||
</Table.Td>
|
|
||||||
<Table.Td>{item.deskripsi}</Table.Td>
|
|
||||||
<Table.Td>{item.status}</Table.Td>
|
|
||||||
<Table.Td style={{ whiteSpace: "nowrap" }}>
|
|
||||||
{item.nameUser ? item.nameUser : "-"}
|
|
||||||
</Table.Td>
|
|
||||||
</Table.Tr>
|
</Table.Tr>
|
||||||
))}
|
</Table.Thead>
|
||||||
</Table.Tbody>
|
<Table.Tbody>
|
||||||
</Table>
|
{data?.map((item: any) => (
|
||||||
|
<Table.Tr key={item.id}>
|
||||||
|
<Table.Td style={{ whiteSpace: "nowrap" }}>
|
||||||
|
{item.createdAt.toLocaleString("id-ID", {
|
||||||
|
day: "2-digit",
|
||||||
|
month: "short",
|
||||||
|
year: "numeric",
|
||||||
|
hour: "2-digit",
|
||||||
|
minute: "2-digit",
|
||||||
|
hour12: false,
|
||||||
|
})}
|
||||||
|
</Table.Td>
|
||||||
|
<Table.Td>{item.deskripsi}</Table.Td>
|
||||||
|
<Table.Td>{item.status}</Table.Td>
|
||||||
|
<Table.Td style={{ whiteSpace: "nowrap" }}>
|
||||||
|
{item.nameUser ? item.nameUser : "-"}
|
||||||
|
</Table.Td>
|
||||||
|
</Table.Tr>
|
||||||
|
))}
|
||||||
|
</Table.Tbody>
|
||||||
|
</Table>
|
||||||
|
</Spoiler>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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";
|
||||||
@@ -12,6 +13,7 @@ import {
|
|||||||
Grid,
|
Grid,
|
||||||
Group,
|
Group,
|
||||||
Modal,
|
Modal,
|
||||||
|
Spoiler,
|
||||||
Stack,
|
Stack,
|
||||||
Table,
|
Table,
|
||||||
Text,
|
Text,
|
||||||
@@ -37,7 +39,13 @@ import { useEffect, useState } from "react";
|
|||||||
import { useLocation } from "react-router-dom";
|
import { useLocation } from "react-router-dom";
|
||||||
import useSwr from "swr";
|
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");
|
||||||
@@ -56,10 +64,14 @@ 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
|
||||||
data={data?.data?.pengaduan}
|
data={data?.data?.pengaduan}
|
||||||
|
phone={data && data.data && data.data.warga ? data.data.warga.phone : null}
|
||||||
onAction={() => {
|
onAction={() => {
|
||||||
mutate();
|
mutate();
|
||||||
}}
|
}}
|
||||||
@@ -77,9 +89,11 @@ export default function DetailPengaduanPage() {
|
|||||||
|
|
||||||
function DetailDataPengaduan({
|
function DetailDataPengaduan({
|
||||||
data,
|
data,
|
||||||
|
phone,
|
||||||
onAction,
|
onAction,
|
||||||
}: {
|
}: {
|
||||||
data: any | null;
|
data: any | null;
|
||||||
|
phone?: string | null;
|
||||||
onAction: () => void;
|
onAction: () => void;
|
||||||
}) {
|
}) {
|
||||||
const [opened, { open, close }] = useDisclosure(false);
|
const [opened, { open, close }] = useDisclosure(false);
|
||||||
@@ -88,6 +102,7 @@ function DetailDataPengaduan({
|
|||||||
const [keterangan, setKeterangan] = useState("");
|
const [keterangan, setKeterangan] = useState("");
|
||||||
const [host, setHost] = useState<User | null>(null);
|
const [host, setHost] = useState<User | null>(null);
|
||||||
const [permissions, setPermissions] = useState<JsonValue[]>([]);
|
const [permissions, setPermissions] = useState<JsonValue[]>([]);
|
||||||
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function fetchHost() {
|
async function fetchHost() {
|
||||||
@@ -106,6 +121,7 @@ function DetailDataPengaduan({
|
|||||||
|
|
||||||
const handleKonfirmasi = async (cat: "terima" | "tolak") => {
|
const handleKonfirmasi = async (cat: "terima" | "tolak") => {
|
||||||
try {
|
try {
|
||||||
|
setIsLoading(true);
|
||||||
const res = await apiFetch.api.pengaduan["update-status"].post({
|
const res = await apiFetch.api.pengaduan["update-status"].post({
|
||||||
id: data?.id,
|
id: data?.id,
|
||||||
status:
|
status:
|
||||||
@@ -121,6 +137,21 @@ function DetailDataPengaduan({
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (res?.status === 200) {
|
if (res?.status === 200) {
|
||||||
|
const resWA = await apiFetch.api["send-wa"].pengaduan.post({
|
||||||
|
noPengaduan: data?.noPengaduan,
|
||||||
|
judulPengaduan: data?.title,
|
||||||
|
status:
|
||||||
|
cat == "tolak"
|
||||||
|
? "ditolak"
|
||||||
|
: data.status == "antrian"
|
||||||
|
? "diterima"
|
||||||
|
: data.status == "diterima"
|
||||||
|
? "dikerjakan"
|
||||||
|
: "selesai",
|
||||||
|
alasan: keterangan,
|
||||||
|
tlp: String(phone),
|
||||||
|
})
|
||||||
|
|
||||||
onAction();
|
onAction();
|
||||||
close();
|
close();
|
||||||
notification({
|
notification({
|
||||||
@@ -128,6 +159,28 @@ function DetailDataPengaduan({
|
|||||||
message: "Success update pengaduan",
|
message: "Success update pengaduan",
|
||||||
type: "success",
|
type: "success",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (resWA?.status === 200) {
|
||||||
|
if (resWA.data?.success) {
|
||||||
|
notification({
|
||||||
|
title: "Success",
|
||||||
|
message: "Success send message to warga",
|
||||||
|
type: "success",
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
notification({
|
||||||
|
title: "Failed",
|
||||||
|
message: "Failed send message to warga",
|
||||||
|
type: "error",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
notification({
|
||||||
|
title: "Failed",
|
||||||
|
message: "Failed send message to warga",
|
||||||
|
type: "error",
|
||||||
|
});
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
notification({
|
notification({
|
||||||
title: "Error",
|
title: "Error",
|
||||||
@@ -142,6 +195,8 @@ function DetailDataPengaduan({
|
|||||||
message: "Failed to update pengaduan",
|
message: "Failed to update pengaduan",
|
||||||
type: "error",
|
type: "error",
|
||||||
});
|
});
|
||||||
|
} finally {
|
||||||
|
setIsLoading(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -176,6 +231,7 @@ function DetailDataPengaduan({
|
|||||||
color="red"
|
color="red"
|
||||||
disabled={keterangan.length < 1}
|
disabled={keterangan.length < 1}
|
||||||
onClick={() => handleKonfirmasi("tolak")}
|
onClick={() => handleKonfirmasi("tolak")}
|
||||||
|
loading={isLoading}
|
||||||
>
|
>
|
||||||
Tolak
|
Tolak
|
||||||
</Button>
|
</Button>
|
||||||
@@ -200,6 +256,7 @@ function DetailDataPengaduan({
|
|||||||
variant="filled"
|
variant="filled"
|
||||||
color="green"
|
color="green"
|
||||||
onClick={() => handleKonfirmasi("terima")}
|
onClick={() => handleKonfirmasi("terima")}
|
||||||
|
loading={isLoading}
|
||||||
>
|
>
|
||||||
Ya
|
Ya
|
||||||
</Button>
|
</Button>
|
||||||
@@ -420,41 +477,48 @@ function DetailDataHistori({ data }: { data: any }) {
|
|||||||
<Stack gap="md">
|
<Stack gap="md">
|
||||||
<Flex align="center" justify="space-between">
|
<Flex align="center" justify="space-between">
|
||||||
<Title order={4} c="gray.2">
|
<Title order={4} c="gray.2">
|
||||||
Histori Pengaduan
|
Riwayat Pengaduan
|
||||||
</Title>
|
</Title>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Divider my={0} />
|
<Divider my={0} />
|
||||||
<Table>
|
<Spoiler
|
||||||
<Table.Thead>
|
maxHeight={200}
|
||||||
<Table.Tr>
|
showLabel="Show more"
|
||||||
<Table.Th>Tanggal</Table.Th>
|
hideLabel="Hide"
|
||||||
<Table.Th>Deskripsi</Table.Th>
|
transitionDuration={1000}
|
||||||
<Table.Th>Status</Table.Th>
|
>
|
||||||
<Table.Th>User</Table.Th>
|
<Table>
|
||||||
</Table.Tr>
|
<Table.Thead>
|
||||||
</Table.Thead>
|
<Table.Tr>
|
||||||
<Table.Tbody>
|
<Table.Th>Tanggal</Table.Th>
|
||||||
{data?.map((item: any) => (
|
<Table.Th>Deskripsi</Table.Th>
|
||||||
<Table.Tr key={item.id}>
|
<Table.Th>Status</Table.Th>
|
||||||
<Table.Td style={{ whiteSpace: "nowrap" }}>
|
<Table.Th>User</Table.Th>
|
||||||
{item.createdAt.toLocaleString("id-ID", {
|
|
||||||
day: "2-digit",
|
|
||||||
month: "short",
|
|
||||||
year: "numeric",
|
|
||||||
hour: "2-digit",
|
|
||||||
minute: "2-digit",
|
|
||||||
hour12: false,
|
|
||||||
})}
|
|
||||||
</Table.Td>
|
|
||||||
<Table.Td>{item.deskripsi}</Table.Td>
|
|
||||||
<Table.Td>{item.status}</Table.Td>
|
|
||||||
<Table.Td style={{ whiteSpace: "nowrap" }}>
|
|
||||||
{item.nameUser ? item.nameUser : "-"}
|
|
||||||
</Table.Td>
|
|
||||||
</Table.Tr>
|
</Table.Tr>
|
||||||
))}
|
</Table.Thead>
|
||||||
</Table.Tbody>
|
<Table.Tbody>
|
||||||
</Table>
|
{data?.map((item: any) => (
|
||||||
|
<Table.Tr key={item.id}>
|
||||||
|
<Table.Td style={{ whiteSpace: "nowrap" }}>
|
||||||
|
{item.createdAt.toLocaleString("id-ID", {
|
||||||
|
day: "2-digit",
|
||||||
|
month: "short",
|
||||||
|
year: "numeric",
|
||||||
|
hour: "2-digit",
|
||||||
|
minute: "2-digit",
|
||||||
|
hour12: false,
|
||||||
|
})}
|
||||||
|
</Table.Td>
|
||||||
|
<Table.Td>{item.deskripsi}</Table.Td>
|
||||||
|
<Table.Td>{item.status}</Table.Td>
|
||||||
|
<Table.Td style={{ whiteSpace: "nowrap" }}>
|
||||||
|
{item.nameUser ? item.nameUser : "-"}
|
||||||
|
</Table.Td>
|
||||||
|
</Table.Tr>
|
||||||
|
))}
|
||||||
|
</Table.Tbody>
|
||||||
|
</Table>
|
||||||
|
</Spoiler>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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={
|
||||||
|
|||||||
@@ -1,62 +1,75 @@
|
|||||||
|
import BreadCrumbs from "@/components/BreadCrumbs";
|
||||||
|
import notification from "@/components/notificationGlobal";
|
||||||
import apiFetch from "@/lib/apiFetch";
|
import apiFetch from "@/lib/apiFetch";
|
||||||
import {
|
import {
|
||||||
Avatar,
|
Avatar,
|
||||||
Box,
|
Box,
|
||||||
Button,
|
Button,
|
||||||
Card,
|
Card,
|
||||||
|
CloseButton,
|
||||||
Container,
|
Container,
|
||||||
Divider,
|
Divider,
|
||||||
Flex,
|
Flex,
|
||||||
Grid,
|
Grid,
|
||||||
Group,
|
Group,
|
||||||
|
Input,
|
||||||
LoadingOverlay,
|
LoadingOverlay,
|
||||||
|
Pagination,
|
||||||
Stack,
|
Stack,
|
||||||
Table,
|
Table,
|
||||||
Text,
|
Text,
|
||||||
Title,
|
Title,
|
||||||
} from "@mantine/core";
|
} from "@mantine/core";
|
||||||
import { useShallowEffect } from "@mantine/hooks";
|
import { useShallowEffect } from "@mantine/hooks";
|
||||||
import { IconPhone } from "@tabler/icons-react";
|
import { IconPhone, IconSearch } from "@tabler/icons-react";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
|
import { useState } from "react";
|
||||||
import { useLocation, useNavigate } from "react-router-dom";
|
import { useLocation, useNavigate } from "react-router-dom";
|
||||||
import useSwr from "swr";
|
|
||||||
|
|
||||||
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");
|
||||||
const { data, mutate, isLoading } = useSwr("/", () =>
|
// const { data, mutate, isLoading } = useSwr("/", () =>
|
||||||
apiFetch.api.warga.detail.get({
|
// apiFetch.api.warga.detail.get({
|
||||||
query: {
|
// query: {
|
||||||
id: id!,
|
// id: id!,
|
||||||
},
|
// },
|
||||||
}),
|
// }),
|
||||||
);
|
// );
|
||||||
|
|
||||||
useShallowEffect(() => {
|
// useShallowEffect(() => {
|
||||||
mutate();
|
// mutate();
|
||||||
}, []);
|
// }, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<LoadingOverlay
|
<LoadingOverlay
|
||||||
visible={isLoading}
|
// visible={isLoading}
|
||||||
zIndex={1000}
|
zIndex={1000}
|
||||||
overlayProps={{ radius: "sm", blur: 2 }}
|
overlayProps={{ radius: "sm", blur: 2 }}
|
||||||
/>
|
/>
|
||||||
<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 data={data?.data?.warga} />
|
<DetailWarga id={id!} />
|
||||||
</Grid.Col>
|
</Grid.Col>
|
||||||
<Grid.Col span={8}>
|
<Grid.Col span={8}>
|
||||||
<Stack gap={"xl"}>
|
<Stack gap={"xl"}>
|
||||||
<DetailDataHistori
|
<DetailDataHistori
|
||||||
data={data?.data?.pengaduan}
|
id={id!}
|
||||||
kategori="pengaduan"
|
kategori="pengaduan"
|
||||||
/>
|
/>
|
||||||
<DetailDataHistori
|
<DetailDataHistori
|
||||||
data={data?.data?.pelayanan}
|
id={id!}
|
||||||
kategori="pelayanan"
|
kategori="pelayanan"
|
||||||
/>
|
/>
|
||||||
</Stack>
|
</Stack>
|
||||||
@@ -68,13 +81,66 @@ export default function DetailWargaPage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function DetailDataHistori({
|
function DetailDataHistori({
|
||||||
data,
|
id,
|
||||||
kategori,
|
kategori,
|
||||||
}: {
|
}: {
|
||||||
data: any;
|
id: string;
|
||||||
kategori: "pengaduan" | "pelayanan";
|
kategori: "pengaduan" | "pelayanan";
|
||||||
}) {
|
}) {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
const [data, setData] = useState<any>([]);
|
||||||
|
const [totalPages, setTotalPages] = useState(1);
|
||||||
|
const [totalRows, setTotalRows] = useState(0);
|
||||||
|
const [page, setPage] = useState(1);
|
||||||
|
const [search, setSearch] = useState("");
|
||||||
|
|
||||||
|
async function getData() {
|
||||||
|
try {
|
||||||
|
const res = await apiFetch.api.warga.detail.get({
|
||||||
|
query: {
|
||||||
|
id,
|
||||||
|
category: kategori,
|
||||||
|
page: String(page),
|
||||||
|
search
|
||||||
|
}
|
||||||
|
}) as { data: { success: boolean; data: any[]; totalPages: number, totalRows: number } };
|
||||||
|
|
||||||
|
if (res?.data?.success) {
|
||||||
|
setData(res.data.data)
|
||||||
|
setTotalPages(res?.data?.totalPages)
|
||||||
|
setTotalRows(res?.data?.totalRows)
|
||||||
|
} else {
|
||||||
|
setData([])
|
||||||
|
setTotalPages(1)
|
||||||
|
setTotalRows(0)
|
||||||
|
notification({
|
||||||
|
title: "Failed",
|
||||||
|
message: "Failed to get data",
|
||||||
|
type: "error",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
notification({
|
||||||
|
title: "Failed",
|
||||||
|
message: "Failed to get data",
|
||||||
|
type: "error",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useShallowEffect(() => {
|
||||||
|
getData()
|
||||||
|
}, [page])
|
||||||
|
|
||||||
|
|
||||||
|
useShallowEffect(() => {
|
||||||
|
setPage(1)
|
||||||
|
if (page == 1) {
|
||||||
|
getData()
|
||||||
|
}
|
||||||
|
}, [search]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
@@ -93,6 +159,36 @@ function DetailDataHistori({
|
|||||||
<Title order={4} c="gray.2">
|
<Title order={4} c="gray.2">
|
||||||
Histori {_.upperFirst(kategori)}
|
Histori {_.upperFirst(kategori)}
|
||||||
</Title>
|
</Title>
|
||||||
|
<Flex
|
||||||
|
gap="md"
|
||||||
|
justify="flex-start"
|
||||||
|
align="center"
|
||||||
|
direction="row"
|
||||||
|
>
|
||||||
|
<Input
|
||||||
|
value={search}
|
||||||
|
placeholder="Cari data..."
|
||||||
|
onChange={(event) => setSearch(event.currentTarget.value)}
|
||||||
|
leftSection={<IconSearch size={16} />}
|
||||||
|
rightSectionPointerEvents="all"
|
||||||
|
rightSection={
|
||||||
|
<CloseButton
|
||||||
|
aria-label="Clear input"
|
||||||
|
onClick={() => setSearch("")}
|
||||||
|
style={{ display: search ? undefined : "none" }}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<Text size="sm" c="gray.5" >
|
||||||
|
{`${5 * (page - 1) + 1} – ${Math.min(totalRows, 5 * page)} of ${totalRows}`}
|
||||||
|
</Text>
|
||||||
|
<Pagination
|
||||||
|
total={totalPages}
|
||||||
|
value={page}
|
||||||
|
onChange={setPage}
|
||||||
|
withPages={false}
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Divider my={0} />
|
<Divider my={0} />
|
||||||
<Table>
|
<Table>
|
||||||
@@ -110,7 +206,7 @@ function DetailDataHistori({
|
|||||||
{data?.length > 0 ? (
|
{data?.length > 0 ? (
|
||||||
data?.map((item: any, index: number) => (
|
data?.map((item: any, index: number) => (
|
||||||
<Table.Tr key={index}>
|
<Table.Tr key={index}>
|
||||||
<Table.Td>{item.noPengaduan}</Table.Td>
|
<Table.Td w={"180"}>{item.noPengaduan}</Table.Td>
|
||||||
<Table.Td>
|
<Table.Td>
|
||||||
{kategori == "pengaduan" ? item.title : item.category}
|
{kategori == "pengaduan" ? item.title : item.category}
|
||||||
</Table.Td>
|
</Table.Td>
|
||||||
@@ -121,11 +217,11 @@ function DetailDataHistori({
|
|||||||
onClick={() => {
|
onClick={() => {
|
||||||
kategori == "pengaduan"
|
kategori == "pengaduan"
|
||||||
? navigate(
|
? navigate(
|
||||||
`/scr/dashboard/pengaduan/detail?id=${item.id}`,
|
`/scr/dashboard/pengaduan/detail?id=${item.id}`,
|
||||||
)
|
)
|
||||||
: navigate(
|
: navigate(
|
||||||
`/scr/dashboard/pelayanan-surat/detail-pelayanan?id=${item.id}`,
|
`/scr/dashboard/pelayanan-surat/detail-pelayanan?id=${item.id}`,
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Detail
|
Detail
|
||||||
@@ -147,7 +243,33 @@ function DetailDataHistori({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function DetailWarga({ data }: { data: any }) {
|
function DetailWarga({ id }: { id: string }) {
|
||||||
|
const [data, setData] = useState<any>(null);
|
||||||
|
|
||||||
|
async function getWarga() {
|
||||||
|
try {
|
||||||
|
const res = await apiFetch.api.warga.detail.get({
|
||||||
|
query: {
|
||||||
|
id: id,
|
||||||
|
category: "warga",
|
||||||
|
page: "1",
|
||||||
|
search: "",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
setData(res.data);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
notification({
|
||||||
|
title: "Failed",
|
||||||
|
message: "Failed to get data warga",
|
||||||
|
type: "error",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useShallowEffect(() => {
|
||||||
|
getWarga();
|
||||||
|
}, []);
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
radius="md"
|
radius="md"
|
||||||
|
|||||||
@@ -8,16 +8,19 @@ export async function createSurat({ idPengajuan, idCategory, idWarga, noSurat }:
|
|||||||
idCategory,
|
idCategory,
|
||||||
idWarga,
|
idWarga,
|
||||||
noSurat,
|
noSurat,
|
||||||
|
},
|
||||||
|
select: {
|
||||||
|
id: true
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!surat.id) {
|
if (!surat.id) {
|
||||||
return { success: false, message: 'gagal membuat surat' }
|
return { success: false, message: 'gagal membuat surat', idSurat: '' }
|
||||||
}
|
}
|
||||||
|
|
||||||
return { success: true, message: 'surat sudah dibuat' }
|
return { success: true, message: 'surat sudah dibuat', idSurat: surat.id }
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error)
|
console.error(error)
|
||||||
return { success: false, message: 'gagal membuat surat' }
|
return { success: false, message: 'gagal membuat surat' }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -248,14 +248,23 @@ export async function moveFile(config: Config, oldName: string, newName: string)
|
|||||||
return `✏️ Renamed ${oldName} → ${newName}`
|
return `✏️ Renamed ${oldName} → ${newName}`
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function downloadFile(config: Config, remoteFile: string, localFile?: string): Promise<string> {
|
export async function downloadFile(config: Config, fileName: string, folder: string, localFile?: string): Promise<string> {
|
||||||
const localName = localFile || remoteFile;
|
const localName = localFile || fileName;
|
||||||
const downloadUrlResponse = await fetchWithAuth(config, `${config.URL}/${config.REPO}/file/?p=/${remoteFile}`);
|
// 🔹 gabungkan path folder + file
|
||||||
const downloadUrl = (await downloadUrlResponse.text()).replace(/"/g, '');
|
const filePath = `/${folder}/${fileName}`.replace(/\/+/g, "/");
|
||||||
|
|
||||||
|
// 🔹 encode path agar aman (spasi, dll)
|
||||||
|
const params = new URLSearchParams({
|
||||||
|
p: filePath,
|
||||||
|
});
|
||||||
|
|
||||||
|
const downloadUrlResponse = await fetchWithAuth(config, `${config.URL}/${config.REPO}/file/?${params.toString()}`);
|
||||||
|
if(!downloadUrlResponse.ok)
|
||||||
|
return 'gagal'
|
||||||
|
const downloadUrl = (await downloadUrlResponse.text()).replace(/"/g, '');
|
||||||
const buffer = Buffer.from(await (await fetchWithAuth(config, downloadUrl)).arrayBuffer());
|
const buffer = Buffer.from(await (await fetchWithAuth(config, downloadUrl)).arrayBuffer());
|
||||||
await fs.writeFile(localName, buffer);
|
await fs.writeFile(localName, buffer);
|
||||||
return `⬇️ Downloaded ${remoteFile} → ${localName}`
|
return `⬇️ Downloaded ${fileName} → ${localName}`
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getFileLink(config: Config, fileName: string): Promise<string> {
|
export async function getFileLink(config: Config, fileName: string): Promise<string> {
|
||||||
|
|||||||
11
src/server/lib/stringToDate.ts
Normal file
11
src/server/lib/stringToDate.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import dayjs from "dayjs";
|
||||||
|
import customParseFormat from "dayjs/plugin/customParseFormat";
|
||||||
|
import "dayjs/locale/id";
|
||||||
|
dayjs.extend(customParseFormat);
|
||||||
|
|
||||||
|
export function parseTanggalID( value: string ): Date | null {
|
||||||
|
if (!value) return null;
|
||||||
|
|
||||||
|
const parsed = dayjs(value, "DD MMMM YYYY", "id", true);
|
||||||
|
return parsed.isValid() ? parsed.toDate() : null;
|
||||||
|
}
|
||||||
@@ -39,7 +39,7 @@ const PelayananRoute = new Elysia({
|
|||||||
}, {
|
}, {
|
||||||
detail: {
|
detail: {
|
||||||
summary: "List Kategori Pelayanan Surat",
|
summary: "List Kategori Pelayanan Surat",
|
||||||
description: `tool untuk mendapatkan list kategori pelayanan surat beserta syaratnya untuk memenuhi syarat dokumen sesuai kategori yg dipilih saat melakukan pengajuan surat`,
|
description: `tool untuk mendapatkan list kategori pelayanan surat dan juga berisi link form pengajuan surat`,
|
||||||
tags: ["mcp"]
|
tags: ["mcp"]
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -265,6 +265,7 @@ const PelayananRoute = new Elysia({
|
|||||||
select: {
|
select: {
|
||||||
id: true,
|
id: true,
|
||||||
idCategory: true,
|
idCategory: true,
|
||||||
|
file: true
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -307,9 +308,14 @@ const PelayananRoute = new Elysia({
|
|||||||
})
|
})
|
||||||
|
|
||||||
const dataTextCategory = (data?.CategoryPelayanan?.dataPelengkap ?? []) as {
|
const dataTextCategory = (data?.CategoryPelayanan?.dataPelengkap ?? []) as {
|
||||||
name: string;
|
type: string;
|
||||||
|
options?: {
|
||||||
|
label: string,
|
||||||
|
value: string
|
||||||
|
}[]; name: string;
|
||||||
desc: string;
|
desc: string;
|
||||||
key: string;
|
key: string;
|
||||||
|
satuan?: string;
|
||||||
}[];
|
}[];
|
||||||
|
|
||||||
const refMap = new Map(
|
const refMap = new Map(
|
||||||
@@ -326,13 +332,18 @@ const PelayananRoute = new Elysia({
|
|||||||
return {
|
return {
|
||||||
id: item.id,
|
id: item.id,
|
||||||
jenis: nama,
|
jenis: nama,
|
||||||
|
key: ref?.key,
|
||||||
value: item.value,
|
value: item.value,
|
||||||
|
type: ref?.type ?? "",
|
||||||
|
options: ref?.options ?? [],
|
||||||
order: ref?.order ?? Infinity,
|
order: ref?.order ?? Infinity,
|
||||||
|
satuan: ref?.satuan ?? null
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
.sort((a, b) => a.order - b.order)
|
.sort((a, b) => a.order - b.order)
|
||||||
.map(({ order, ...rest }) => rest); // hapus order
|
.map(({ order, ...rest }) => rest); // hapus order
|
||||||
|
|
||||||
|
|
||||||
const dataHistory = await prisma.historyPelayanan.findMany({
|
const dataHistory = await prisma.historyPelayanan.findMany({
|
||||||
where: {
|
where: {
|
||||||
idPengajuanLayanan: data?.id,
|
idPengajuanLayanan: data?.id,
|
||||||
@@ -348,6 +359,9 @@ const PelayananRoute = new Elysia({
|
|||||||
name: true,
|
name: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
orderBy: {
|
||||||
|
createdAt: "desc"
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -377,6 +391,7 @@ const PelayananRoute = new Elysia({
|
|||||||
createdAt: data?.createdAt,
|
createdAt: data?.createdAt,
|
||||||
updatedAt: data?.updatedAt,
|
updatedAt: data?.updatedAt,
|
||||||
idSurat: dataSurat?.id,
|
idSurat: dataSurat?.id,
|
||||||
|
fileSurat: dataSurat?.file,
|
||||||
}
|
}
|
||||||
|
|
||||||
const datafix = {
|
const datafix = {
|
||||||
@@ -589,7 +604,10 @@ const PelayananRoute = new Elysia({
|
|||||||
const { nomerPengajuan } = body
|
const { nomerPengajuan } = body
|
||||||
const data = await prisma.pelayananAjuan.findFirst({
|
const data = await prisma.pelayananAjuan.findFirst({
|
||||||
where: {
|
where: {
|
||||||
noPengajuan: nomerPengajuan
|
noPengajuan: {
|
||||||
|
equals: nomerPengajuan,
|
||||||
|
mode: "insensitive"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
select: {
|
select: {
|
||||||
id: true,
|
id: true,
|
||||||
@@ -669,24 +687,34 @@ 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
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const dataPelengkapList = (data?.CategoryPelayanan?.dataPelengkap ?? []) as {
|
const dataPelengkapList = (data?.CategoryPelayanan?.dataPelengkap ?? []) as {
|
||||||
|
type: string;
|
||||||
|
options?: {
|
||||||
|
label: string,
|
||||||
|
value: string
|
||||||
|
}[];
|
||||||
name: string;
|
name: string;
|
||||||
desc: string;
|
desc: string;
|
||||||
key: string;
|
key: string;
|
||||||
|
required: boolean;
|
||||||
|
satuan?: string;
|
||||||
}[];
|
}[];
|
||||||
|
|
||||||
const refMap = new Map(
|
const refMap = new Map(
|
||||||
@@ -706,7 +734,11 @@ const PelayananRoute = new Elysia({
|
|||||||
value: item.value,
|
value: item.value,
|
||||||
desc: ref?.desc ?? "",
|
desc: ref?.desc ?? "",
|
||||||
name: ref?.name ?? "",
|
name: ref?.name ?? "",
|
||||||
|
type: ref?.type ?? "",
|
||||||
|
options: ref?.options ?? [],
|
||||||
order: ref?.order ?? Infinity,
|
order: ref?.order ?? Infinity,
|
||||||
|
required: ref?.required ?? true,
|
||||||
|
satuan: ref?.satuan ?? null
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
.sort((a, b) => a.order - b.order)
|
.sort((a, b) => a.order - b.order)
|
||||||
@@ -731,6 +763,19 @@ const PelayananRoute = new Elysia({
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const alasanDitolak = await prisma.historyPelayanan.findFirst({
|
||||||
|
where: {
|
||||||
|
idPengajuanLayanan: data?.id,
|
||||||
|
status: "ditolak"
|
||||||
|
},
|
||||||
|
select: {
|
||||||
|
keteranganAlasan: true,
|
||||||
|
},
|
||||||
|
orderBy: {
|
||||||
|
createdAt: "desc"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const dataHistoryFix = dataHistory.map((item) => {
|
const dataHistoryFix = dataHistory.map((item) => {
|
||||||
return {
|
return {
|
||||||
id: item.id,
|
id: item.id,
|
||||||
@@ -757,12 +802,14 @@ const PelayananRoute = new Elysia({
|
|||||||
createdAt: data?.createdAt,
|
createdAt: data?.createdAt,
|
||||||
updatedAt: data?.updatedAt,
|
updatedAt: data?.updatedAt,
|
||||||
idSurat: dataSurat?.id,
|
idSurat: dataSurat?.id,
|
||||||
|
alasan: alasanDitolak?.keteranganAlasan,
|
||||||
}
|
}
|
||||||
|
|
||||||
const datafix = {
|
const datafix = {
|
||||||
success: true,
|
success: true,
|
||||||
message: 'sukses',
|
message: 'sukses',
|
||||||
pengajuan: dataPengajuan,
|
pengajuan: dataPengajuan,
|
||||||
|
linkUpdate: `${process.env.BUN_PUBLIC_BASE_URL}/darmasaba/update-data-surat?pengajuan=${data.noPengajuan}`,
|
||||||
history: dataHistoryFix,
|
history: dataHistoryFix,
|
||||||
warga: warga,
|
warga: warga,
|
||||||
syaratDokumen: dataSyaratFix,
|
syaratDokumen: dataSyaratFix,
|
||||||
@@ -805,9 +852,14 @@ const PelayananRoute = new Elysia({
|
|||||||
})
|
})
|
||||||
|
|
||||||
if (!pengajuan) {
|
if (!pengajuan) {
|
||||||
return { success: false, message: 'gagal update status pengajuan surat' }
|
return { success: false, message: 'gagal update status pengajuan surat', linkUpdate: '', idSurat: '' }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const dataPengajuan = await prisma.pelayananAjuan.findUnique({
|
||||||
|
where: { id: pengajuan.id },
|
||||||
|
select: { noPengajuan: true }
|
||||||
|
});
|
||||||
|
|
||||||
if (status === "diterima") {
|
if (status === "diterima") {
|
||||||
deskripsi = "Pengajuan surat diterima"
|
deskripsi = "Pengajuan surat diterima"
|
||||||
} else if (status === "ditolak") {
|
} else if (status === "ditolak") {
|
||||||
@@ -826,11 +878,19 @@ const PelayananRoute = new Elysia({
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
let idSurat = "";
|
||||||
if (status === "selesai") {
|
if (status === "selesai") {
|
||||||
await createSurat({ idPengajuan: pengajuan.id, idCategory: pengajuan.idCategory, idWarga: pengajuan.idWarga, noSurat })
|
const result = await createSurat({ idPengajuan: pengajuan.id, idCategory: pengajuan.idCategory, idWarga: pengajuan.idWarga, noSurat })
|
||||||
|
idSurat = result.idSurat ?? "";
|
||||||
}
|
}
|
||||||
|
|
||||||
return { success: true, message: 'pengajuan surat sudah diperbarui' }
|
return {
|
||||||
|
success: true,
|
||||||
|
message: 'pengajuan surat sudah diperbarui',
|
||||||
|
linkUpdate: status == "ditolak" ? `${process.env.BUN_PUBLIC_BASE_URL}/darmasaba/update-data-surat?pengajuan=${dataPengajuan?.noPengajuan}` : '',
|
||||||
|
idSurat: idSurat,
|
||||||
|
}
|
||||||
}, {
|
}, {
|
||||||
body: t.Object({
|
body: t.Object({
|
||||||
id: t.String({ minLength: 1, error: "id harus diisi" }),
|
id: t.String({ minLength: 1, error: "id harus diisi" }),
|
||||||
@@ -1006,6 +1066,73 @@ const PelayananRoute = new Elysia({
|
|||||||
description: `tool untuk update data pengajuan pelayanan surat`,
|
description: `tool untuk update data pengajuan pelayanan surat`,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
.post("/update-data-pelengkap", async ({ body }) => {
|
||||||
|
const { id, value, jenis, idUser } = body
|
||||||
|
|
||||||
|
const dataPelengkap = await prisma.dataTextPelayanan.findUnique({
|
||||||
|
where: {
|
||||||
|
id
|
||||||
|
},
|
||||||
|
select: {
|
||||||
|
idPengajuanLayanan: true,
|
||||||
|
PelayananAjuan: {
|
||||||
|
select: {
|
||||||
|
status: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!dataPelengkap) {
|
||||||
|
return { success: false, message: 'data pelengkap surat tidak ditemukan' }
|
||||||
|
}
|
||||||
|
|
||||||
|
const upd = await prisma.dataTextPelayanan.update({
|
||||||
|
where: {
|
||||||
|
id
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
value: value,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const history = await prisma.historyPelayanan.create({
|
||||||
|
data: {
|
||||||
|
idPengajuanLayanan: dataPelengkap.idPengajuanLayanan,
|
||||||
|
deskripsi: `Pengajuan surat diupdate oleh user (data yg diupdate: ${jenis})`,
|
||||||
|
status: dataPelengkap.PelayananAjuan.status,
|
||||||
|
idUser
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
return { success: true, message: 'data pelengkap surat sudah diperbarui' }
|
||||||
|
|
||||||
|
}, {
|
||||||
|
body: t.Object({
|
||||||
|
id: t.String({
|
||||||
|
error: "id harus diisi",
|
||||||
|
description: "ID yang ingin diupdate"
|
||||||
|
}),
|
||||||
|
value: t.String({
|
||||||
|
error: "value harus diisi",
|
||||||
|
description: "Value yang ingin diupdate"
|
||||||
|
}),
|
||||||
|
jenis: t.String({
|
||||||
|
error: "jenis harus diisi",
|
||||||
|
description: "Jenis data yang ingin diupdate"
|
||||||
|
}),
|
||||||
|
idUser: t.String({
|
||||||
|
error: "idUser harus diisi",
|
||||||
|
description: "ID user yang melakukan update"
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
detail: {
|
||||||
|
summary: "Update Data Pelengkap Pengajuan Pelayanan Surat oleh user admin",
|
||||||
|
description: `tool untuk update data pelengkap pengajuan pelayanan surat oleh user admin`,
|
||||||
|
}
|
||||||
|
})
|
||||||
.get("/list", async ({ query }) => {
|
.get("/list", async ({ query }) => {
|
||||||
const { take, page, search, status } = query
|
const { take, page, search, status } = query
|
||||||
const skip = !page ? 0 : (Number(page) - 1) * (!take ? 10 : Number(take))
|
const skip = !page ? 0 : (Number(page) - 1) * (!take ? 10 : Number(take))
|
||||||
|
|||||||
@@ -1,14 +1,16 @@
|
|||||||
import Elysia, { t } from "elysia"
|
import Elysia, { t } from "elysia";
|
||||||
import type { StatusPengaduan } from "generated/prisma"
|
import fs from 'fs';
|
||||||
import _ from "lodash"
|
import type { StatusPengaduan } from "generated/prisma";
|
||||||
import { v4 as uuidv4 } from "uuid"
|
import _ from "lodash";
|
||||||
import { getLastUpdated } from "../lib/get-last-updated"
|
import path from "path";
|
||||||
import { mimeToExtension } from "../lib/mimetypeToExtension"
|
import { v4 as uuidv4 } from "uuid";
|
||||||
import { generateNoPengaduan } from "../lib/no-pengaduan"
|
import { getLastUpdated } from "../lib/get-last-updated";
|
||||||
import { isValidPhone, normalizePhoneNumber } from "../lib/normalizePhone"
|
import { mimeToExtension } from "../lib/mimetypeToExtension";
|
||||||
import { prisma } from "../lib/prisma"
|
import { generateNoPengaduan } from "../lib/no-pengaduan";
|
||||||
import { renameFile } from "../lib/rename-file"
|
import { isValidPhone, normalizePhoneNumber } from "../lib/normalizePhone";
|
||||||
import { catFile, defaultConfigSF, removeFile, uploadFile, uploadFileToFolder } from "../lib/seafile"
|
import { prisma } from "../lib/prisma";
|
||||||
|
import { renameFile } from "../lib/rename-file";
|
||||||
|
import { catFile, defaultConfigSF, downloadFile, removeFile, uploadFile, uploadFileToFolder } from "../lib/seafile";
|
||||||
|
|
||||||
const PengaduanRoute = new Elysia({
|
const PengaduanRoute = new Elysia({
|
||||||
prefix: "pengaduan",
|
prefix: "pengaduan",
|
||||||
@@ -415,7 +417,7 @@ const PengaduanRoute = new Elysia({
|
|||||||
const datafix = {
|
const datafix = {
|
||||||
pengaduan: {},
|
pengaduan: {},
|
||||||
history: [],
|
history: [],
|
||||||
warga: {},
|
warga: null,
|
||||||
}
|
}
|
||||||
|
|
||||||
return datafix
|
return datafix
|
||||||
@@ -436,6 +438,9 @@ const PengaduanRoute = new Elysia({
|
|||||||
name: true,
|
name: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
orderBy: {
|
||||||
|
createdAt: "desc"
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -602,6 +607,43 @@ const PengaduanRoute = new Elysia({
|
|||||||
consumes: ["multipart/form-data"]
|
consumes: ["multipart/form-data"]
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
.get("/download", async ({ query, set }) => {
|
||||||
|
const { file, folder } = query;
|
||||||
|
|
||||||
|
// Validasi file
|
||||||
|
if (!file) {
|
||||||
|
return { success: false, message: "File tidak ditemukan" };
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (!folder) {
|
||||||
|
// return { success: false, message: "Folder tidak ditemukan" };
|
||||||
|
// }
|
||||||
|
|
||||||
|
const localPath = path.join("/tmp", file);
|
||||||
|
|
||||||
|
// Upload ke Seafile (pastikan uploadFile menerima Blob atau ArrayBuffer)
|
||||||
|
// const buffer = await file.arrayBuffer();
|
||||||
|
const result = await downloadFile(defaultConfigSF, file, 'surat', localPath);
|
||||||
|
|
||||||
|
if(result=="gagal") {
|
||||||
|
return { success: false, message: "Download gagal" };
|
||||||
|
}
|
||||||
|
|
||||||
|
set.headers["Content-Type"] = "application/pdf";
|
||||||
|
set.headers["Content-Disposition"] = `attachment; filename="${file}"`;
|
||||||
|
|
||||||
|
// 🔹 kirim file ke browser
|
||||||
|
return fs.createReadStream(localPath);
|
||||||
|
}, {
|
||||||
|
body: t.Object({
|
||||||
|
file: t.Any(),
|
||||||
|
folder: t.String(),
|
||||||
|
}),
|
||||||
|
detail: {
|
||||||
|
summary: "Download Surat",
|
||||||
|
description: "Tool untuk download surat dari Seafile",
|
||||||
|
},
|
||||||
|
})
|
||||||
.post("/upload-file-form-data", async ({ body }) => {
|
.post("/upload-file-form-data", async ({ body }) => {
|
||||||
const { file } = body;
|
const { file } = body;
|
||||||
|
|
||||||
|
|||||||
153
src/server/routes/send_wa_route.ts
Normal file
153
src/server/routes/send_wa_route.ts
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
import Elysia, { t } from "elysia";
|
||||||
|
|
||||||
|
const SendWaRoute = new Elysia({
|
||||||
|
prefix: "send-wa",
|
||||||
|
tags: ["send-wa"],
|
||||||
|
})
|
||||||
|
|
||||||
|
// --- KATEGORI PENGADUAN ---
|
||||||
|
.post("/pengaduan", async ({ body }) => {
|
||||||
|
const { noPengaduan, judulPengaduan, status, alasan, tlp } = body
|
||||||
|
|
||||||
|
let text = ""
|
||||||
|
|
||||||
|
if (status === "ditolak") {
|
||||||
|
text = `Pemberitahuan Aduan
|
||||||
|
|
||||||
|
Aduan dengan Nomor Pengaduan: ${noPengaduan}
|
||||||
|
Judul Pengaduan: ${judulPengaduan}
|
||||||
|
Kami informasikan bahwa aduan tersebut tidak dapat ditindaklanjuti (ditolak).
|
||||||
|
Alasan penolakan:${alasan}
|
||||||
|
|
||||||
|
Terima kasih atas pengertian Bapak/Ibu.`
|
||||||
|
} else if (status == "diterima") {
|
||||||
|
text = `Pemberitahuan Aduan
|
||||||
|
|
||||||
|
Aduan dengan Nomor Pengaduan: ${noPengaduan}
|
||||||
|
Judul Pengaduan: ${judulPengaduan}
|
||||||
|
Telah kami terima dan akan segera diproses sesuai ketentuan yang berlaku.
|
||||||
|
|
||||||
|
Terima kasih atas laporan Bapak/Ibu.`
|
||||||
|
} else if (status == "dikerjakan") {
|
||||||
|
text = `Pemberitahuan Aduan
|
||||||
|
|
||||||
|
Aduan dengan Nomor Pengaduan: ${noPengaduan}
|
||||||
|
Judul Pengaduan: ${judulPengaduan}
|
||||||
|
Saat ini sedang dalam proses penanganan oleh petugas terkait.
|
||||||
|
|
||||||
|
Mohon menunggu informasi selanjutnya.`
|
||||||
|
} else if (status == "selesai") {
|
||||||
|
text = `Pemberitahuan Aduan
|
||||||
|
|
||||||
|
Aduan dengan Nomor Pengaduan: ${noPengaduan}
|
||||||
|
Judul Pengaduan: ${judulPengaduan}
|
||||||
|
Telah selesai ditindaklanjuti.
|
||||||
|
|
||||||
|
Terima kasih atas partisipasi dan kepercayaan Bapak/Ibu.`
|
||||||
|
}
|
||||||
|
|
||||||
|
const textFix = encodeURIComponent(text)
|
||||||
|
|
||||||
|
const res = await fetch(
|
||||||
|
`https://cld-dkr-prod-wajs-server.wibudev.com/api/wa/code?nom=${tlp}&text=${textFix}`,
|
||||||
|
{
|
||||||
|
cache: "no-cache",
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${process.env.WA_SERVER_TOKEN}`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (res.status !== 200)
|
||||||
|
return { success: false, message: "Nomor Whatsapp Tidak Aktif" }
|
||||||
|
|
||||||
|
|
||||||
|
return { success: true, message: 'Pemberitahuan berhasil dikirim ke warga' }
|
||||||
|
}, {
|
||||||
|
body: t.Object({
|
||||||
|
noPengaduan: t.String({ minLength: 1, error: "nomer pengaduan harus diisi" }),
|
||||||
|
judulPengaduan: t.String({ minLength: 1, error: "judul pengaduan harus diisi" }),
|
||||||
|
status: t.String({ minLength: 1, error: "status harus diisi" }),
|
||||||
|
alasan: t.String({ optional: true }),
|
||||||
|
tlp: t.String({ minLength: 1, error: "nomor telepon harus diisi" }),
|
||||||
|
}),
|
||||||
|
detail: {
|
||||||
|
summary: "Send pemberitahuan pengaduan lewat WA",
|
||||||
|
description: `tool untuk send pemberitahuan pengaduan lewat WA`
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.post("/pengajuan-surat", async ({ body }) => {
|
||||||
|
const { noPengajuan, jenisSurat, status, alasan, tlp, linkSurat, linkUpdate } = body
|
||||||
|
|
||||||
|
let text = ""
|
||||||
|
|
||||||
|
if (status === "ditolak") {
|
||||||
|
text = `Pemberitahuan Pengajuan Surat
|
||||||
|
|
||||||
|
Nomor Pengajuan: ${noPengajuan}
|
||||||
|
Surat: ${jenisSurat}
|
||||||
|
Kami informasikan bahwa pengajuan surat tersebut tidak dapat diproses (ditolak).
|
||||||
|
Alasan penolakan: ${alasan}
|
||||||
|
|
||||||
|
Bapak/Ibu dapat melakukan perbaikan atau pembaruan data melalui tautan berikut:
|
||||||
|
👉 ${linkUpdate}
|
||||||
|
Setelah data diperbarui, pengajuan akan diproses kembali sesuai ketentuan yang berlaku.
|
||||||
|
|
||||||
|
Terima kasih atas pengertian Bapak/Ibu.`
|
||||||
|
} else if (status == "diterima") {
|
||||||
|
text = `Pemberitahuan Pengajuan Surat
|
||||||
|
|
||||||
|
Nomor Pengajuan: ${noPengajuan}
|
||||||
|
Surat: ${jenisSurat}
|
||||||
|
Kami informasikan bahwa pengajuan surat yang Bapak/Ibu ajukan telah kami terima dan sedang menunggu proses verifikasi serta penanganan lebih lanjut.
|
||||||
|
|
||||||
|
Terima kasih atas kesabaran Bapak/Ibu.`
|
||||||
|
} else if (status == "selesai") {
|
||||||
|
text = `Pemberitahuan Pengajuan Surat
|
||||||
|
|
||||||
|
Nomor Pengajuan: ${noPengajuan}
|
||||||
|
Surat: ${jenisSurat}
|
||||||
|
Kami informasikan bahwa pengajuan surat tersebut telah selesai diproses.
|
||||||
|
|
||||||
|
Bapak/Ibu dapat mengunduh surat melalui tautan berikut:
|
||||||
|
👉 ${linkSurat}
|
||||||
|
|
||||||
|
Terima kasih atas kepercayaan Bapak/Ibu.`
|
||||||
|
}
|
||||||
|
|
||||||
|
const textFix = encodeURIComponent(text)
|
||||||
|
|
||||||
|
|
||||||
|
const res = await fetch(
|
||||||
|
`https://cld-dkr-prod-wajs-server.wibudev.com/api/wa/code?nom=${tlp}&text=${textFix}`,
|
||||||
|
{
|
||||||
|
cache: "no-cache",
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${process.env.WA_SERVER_TOKEN}`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (res.status !== 200)
|
||||||
|
return { success: false, message: "Nomor Whatsapp Tidak Aktif" }
|
||||||
|
|
||||||
|
|
||||||
|
return { success: true, message: 'Pemberitahuan berhasil dikirim ke warga' }
|
||||||
|
}, {
|
||||||
|
body: t.Object({
|
||||||
|
noPengajuan: t.String({ minLength: 1, error: "nomer pengajuan harus diisi" }),
|
||||||
|
jenisSurat: t.String({ minLength: 1, error: "jenis surat harus diisi" }),
|
||||||
|
status: t.String({ minLength: 1, error: "status harus diisi" }),
|
||||||
|
alasan: t.String({ optional: true }),
|
||||||
|
linkSurat: t.String({ optional: true }),
|
||||||
|
linkUpdate: t.String({ optional: true }),
|
||||||
|
tlp: t.String({ minLength: 1, error: "nomor telepon harus diisi" }),
|
||||||
|
}),
|
||||||
|
detail: {
|
||||||
|
summary: "Send pemberitahuan pengajuan surat lewat WA",
|
||||||
|
description: `tool untuk send pemberitahuan pengajuan surat lewat WA`
|
||||||
|
}
|
||||||
|
})
|
||||||
|
;
|
||||||
|
|
||||||
|
export default SendWaRoute
|
||||||
@@ -17,6 +17,7 @@ const SuratRoute = new Elysia({
|
|||||||
noSurat: true,
|
noSurat: true,
|
||||||
idCategory: true,
|
idCategory: true,
|
||||||
createdAt: true,
|
createdAt: true,
|
||||||
|
file: true,
|
||||||
PelayananAjuan: {
|
PelayananAjuan: {
|
||||||
select: {
|
select: {
|
||||||
DataTextPelayanan: true,
|
DataTextPelayanan: true,
|
||||||
@@ -44,6 +45,7 @@ const SuratRoute = new Elysia({
|
|||||||
idCategory: dataSurat?.idCategory,
|
idCategory: dataSurat?.idCategory,
|
||||||
nameCategory: dataSurat?.CategoryPelayanan?.name,
|
nameCategory: dataSurat?.CategoryPelayanan?.name,
|
||||||
noSurat: dataSurat?.noSurat,
|
noSurat: dataSurat?.noSurat,
|
||||||
|
file: dataSurat?.file,
|
||||||
dataText: dataSurat?.PelayananAjuan?.DataTextPelayanan,
|
dataText: dataSurat?.PelayananAjuan?.DataTextPelayanan,
|
||||||
createdAt: dataSurat?.createdAt.toLocaleDateString("id-ID", { day: "numeric", month: "long", year: "numeric" }),
|
createdAt: dataSurat?.createdAt.toLocaleDateString("id-ID", { day: "numeric", month: "long", year: "numeric" }),
|
||||||
},
|
},
|
||||||
@@ -60,6 +62,33 @@ const SuratRoute = new Elysia({
|
|||||||
}
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
|
.post("/update", async ({ body }) => {
|
||||||
|
const { id, filename } = body
|
||||||
|
|
||||||
|
await prisma.suratPelayanan.update({
|
||||||
|
where: {
|
||||||
|
id,
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
file: filename,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
message: 'surat sudah diperbarui',
|
||||||
|
link: `${process.env.BUN_PUBLIC_BASE_URL}/api/pengaduan/download?file=${filename}`
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
body: t.Object({
|
||||||
|
id: t.String({ minLength: 1, error: "id harus diisi" }),
|
||||||
|
filename: t.String({ minLength: 1, error: "filename harus diisi" }),
|
||||||
|
}),
|
||||||
|
detail: {
|
||||||
|
summary: "update file surat",
|
||||||
|
description: `tool untuk update file surat`
|
||||||
|
}
|
||||||
|
})
|
||||||
;
|
;
|
||||||
|
|
||||||
export default SuratRoute
|
export default SuratRoute
|
||||||
|
|||||||
@@ -97,68 +97,137 @@ const WargaRoute = new Elysia({
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.get("/detail", async ({ query }) => {
|
.get("/detail", async ({ query }) => {
|
||||||
const { id } = query
|
const { id, category, search, page } = query
|
||||||
|
const skip = !page ? 0 : (Number(page) - 1) * 5
|
||||||
|
|
||||||
const dataWarga = await prisma.warga.findUnique({
|
const dataWarga = await prisma.warga.findUnique({
|
||||||
where: {
|
where: {
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const dataPengaduan = await prisma.pengaduan.findMany({
|
if (!dataWarga)
|
||||||
orderBy: {
|
return { success: false, message: "data warga tidak ditemukan", data: null, totalPages: 1, totalRows: 0 }
|
||||||
createdAt: "desc"
|
|
||||||
},
|
if (category == "warga") {
|
||||||
where: {
|
return dataWarga
|
||||||
|
} else if (category == "pengaduan") {
|
||||||
|
const where: any = {
|
||||||
isActive: true,
|
isActive: true,
|
||||||
idWarga: id
|
idWarga: id,
|
||||||
},
|
OR: [
|
||||||
select: {
|
{
|
||||||
id: true,
|
title: {
|
||||||
status: true,
|
contains: search ?? "",
|
||||||
noPengaduan: true,
|
mode: "insensitive"
|
||||||
title: true
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
noPengaduan: {
|
||||||
|
contains: search ?? "",
|
||||||
|
mode: "insensitive"
|
||||||
|
},
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
|
||||||
|
const totalData = await prisma.pengaduan.count({
|
||||||
|
where
|
||||||
|
});
|
||||||
|
const dataPengaduan = await prisma.pengaduan.findMany({
|
||||||
|
skip,
|
||||||
|
take: 5,
|
||||||
|
orderBy: {
|
||||||
|
createdAt: "desc"
|
||||||
|
},
|
||||||
|
where,
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
status: true,
|
||||||
|
noPengaduan: true,
|
||||||
|
title: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const dataReturn = {
|
||||||
|
success: true,
|
||||||
|
message: "data pengaduan berhasil diambil",
|
||||||
|
data: dataPengaduan,
|
||||||
|
totalRows: totalData,
|
||||||
|
totalPages: Math.ceil(totalData / 5)
|
||||||
|
}
|
||||||
|
|
||||||
const dataPelayanan = await prisma.pelayananAjuan.findMany({
|
return dataReturn
|
||||||
orderBy: {
|
} else if (category == "pelayanan") {
|
||||||
createdAt: "desc"
|
const where: any = {
|
||||||
},
|
|
||||||
where: {
|
|
||||||
isActive: true,
|
isActive: true,
|
||||||
idWarga: id
|
idWarga: id,
|
||||||
},
|
OR: [
|
||||||
select: {
|
{
|
||||||
id: true,
|
CategoryPelayanan: {
|
||||||
noPengajuan: true,
|
name: {
|
||||||
status: true,
|
contains: search ?? "",
|
||||||
CategoryPelayanan: {
|
mode: "insensitive"
|
||||||
select: {
|
},
|
||||||
name: true
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
noPengajuan: {
|
||||||
|
contains: search ?? "",
|
||||||
|
mode: "insensitive"
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
const totalData = await prisma.pelayananAjuan.count({
|
||||||
|
where
|
||||||
|
});
|
||||||
|
|
||||||
|
const dataPelayanan = await prisma.pelayananAjuan.findMany({
|
||||||
|
skip,
|
||||||
|
take: 5,
|
||||||
|
orderBy: {
|
||||||
|
createdAt: "desc"
|
||||||
|
},
|
||||||
|
where,
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
noPengajuan: true,
|
||||||
|
status: true,
|
||||||
|
CategoryPelayanan: {
|
||||||
|
select: {
|
||||||
|
name: true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const dataPelayanFix = dataPelayanan.map((v: any) => ({
|
||||||
|
..._.omit(v, ["CategoryPelayanan"]),
|
||||||
|
id: v.id,
|
||||||
|
noPengaduan: v.noPengajuan,
|
||||||
|
status: v.status,
|
||||||
|
category: v.CategoryPelayanan.name
|
||||||
|
}))
|
||||||
|
|
||||||
|
const dataReturn = {
|
||||||
|
success: true,
|
||||||
|
message: "data pelayanan berhasil diambil",
|
||||||
|
data: dataPelayanFix,
|
||||||
|
totalRows: totalData,
|
||||||
|
totalPages: Math.ceil(totalData / 5)
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
|
||||||
const dataPelayanFix = dataPelayanan.map((v: any) => ({
|
return dataReturn
|
||||||
..._.omit(v, ["CategoryPelayanan"]),
|
|
||||||
id: v.id,
|
|
||||||
noPengaduan: v.noPengajuan,
|
|
||||||
status: v.status,
|
|
||||||
category: v.CategoryPelayanan.name
|
|
||||||
}))
|
|
||||||
|
|
||||||
return {
|
|
||||||
warga: dataWarga,
|
|
||||||
pengaduan: dataPengaduan,
|
|
||||||
pelayanan: dataPelayanFix
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}, {
|
}, {
|
||||||
query: t.Object({
|
query: t.Object({
|
||||||
id: t.String({ minLength: 1, error: "id harus diisi" })
|
id: t.String({ minLength: 1, error: "id harus diisi" }),
|
||||||
|
category: t.String({ minLength: 1, error: "kategori harus diisi" }),
|
||||||
|
page: t.String({ optional: true }),
|
||||||
|
search: t.String({ optional: true }),
|
||||||
}),
|
}),
|
||||||
detail: {
|
detail: {
|
||||||
summary: "Detail Warga",
|
summary: "Detail Warga",
|
||||||
|
|||||||
Reference in New Issue
Block a user