amalia/02-jan-26 #99
@@ -13,7 +13,7 @@ import {
|
|||||||
Table,
|
Table,
|
||||||
Text,
|
Text,
|
||||||
Title,
|
Title,
|
||||||
Tooltip
|
Tooltip,
|
||||||
} from "@mantine/core";
|
} from "@mantine/core";
|
||||||
import { useDisclosure, useShallowEffect } from "@mantine/hooks";
|
import { useDisclosure, useShallowEffect } from "@mantine/hooks";
|
||||||
import { IconEdit, IconEye, IconPlus, IconTrash } from "@tabler/icons-react";
|
import { IconEdit, IconEye, IconPlus, IconTrash } from "@tabler/icons-react";
|
||||||
@@ -190,7 +190,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: "" },
|
||||||
|
],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,19 +1,12 @@
|
|||||||
import {
|
import { Button, Center, Group, Stack, Text, Title } from "@mantine/core";
|
||||||
Button,
|
import { IconSearch } from "@tabler/icons-react";
|
||||||
Center,
|
|
||||||
Group,
|
|
||||||
Stack,
|
|
||||||
Text,
|
|
||||||
Title
|
|
||||||
} from "@mantine/core"
|
|
||||||
import { IconSearch } from "@tabler/icons-react"
|
|
||||||
|
|
||||||
export function DataNotFound({
|
export function DataNotFound({
|
||||||
onRetry,
|
onRetry,
|
||||||
backTo
|
backTo,
|
||||||
}: {
|
}: {
|
||||||
onRetry?: () => void
|
onRetry?: () => void;
|
||||||
backTo?: () => void
|
backTo?: () => void;
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<Center mih={320}>
|
<Center mih={320}>
|
||||||
@@ -23,7 +16,8 @@ export function DataNotFound({
|
|||||||
<Title order={4}>Data Pengajuan Tidak Ditemukan</Title>
|
<Title order={4}>Data Pengajuan Tidak Ditemukan</Title>
|
||||||
|
|
||||||
<Text size="sm" c="dimmed" ta="center" maw={380}>
|
<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.
|
Kami tidak dapat menemukan data pengajuan dengan nomor pengajuan yg
|
||||||
|
diinputkan. Silakan periksa kembali data Anda.
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<Group mt="md">
|
<Group mt="md">
|
||||||
@@ -47,5 +41,5 @@ export function DataNotFound({
|
|||||||
</Group>
|
</Group>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Center>
|
</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">
|
||||||
|
|||||||
@@ -146,9 +146,7 @@ export default function SKBedaBiodataDiri({ data }: { data: any }) {
|
|||||||
<tr>
|
<tr>
|
||||||
<td style={{ width: "160px" }}>1. {getValue("data_dokumen")}</td>
|
<td style={{ width: "160px" }}>1. {getValue("data_dokumen")}</td>
|
||||||
<td style={{ width: "10px" }}></td>
|
<td style={{ width: "10px" }}></td>
|
||||||
<td>
|
<td>{/* {getValue("nama")} */}</td>
|
||||||
{/* {getValue("nama")} */}
|
|
||||||
</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Tertulis pada dokumen A</td>
|
<td>Tertulis pada dokumen A</td>
|
||||||
|
|||||||
@@ -135,9 +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")} per bulan
|
|
||||||
</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@@ -145,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")}</b>.
|
.
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style={{ marginTop: "20px" }}>
|
<div style={{ marginTop: "20px" }}>
|
||||||
|
|||||||
@@ -71,7 +71,10 @@ export default function SKTempatUsaha({ data }: { data: any }) {
|
|||||||
label="Tempat/Tanggal Lahir"
|
label="Tempat/Tanggal Lahir"
|
||||||
value={`${getValue("tempat_lahir")}, ${getValue("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_pemilik")}
|
||||||
|
/>
|
||||||
<Row label="Nomor KTP" value={getValue("nik")} />
|
<Row label="Nomor KTP" value={getValue("nik")} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -86,14 +89,8 @@ export default function SKTempatUsaha({ data }: { data: any }) {
|
|||||||
<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")} />
|
||||||
value={getValue("status_tempat")}
|
|
||||||
/>
|
|
||||||
<Row
|
|
||||||
label="Luas Tempat Usaha"
|
|
||||||
value={getValue("luas_usaha")}
|
|
||||||
/>
|
|
||||||
<Row label="Jumlah Karyawan" value={getValue("jumlah_karyawan")} />
|
<Row label="Jumlah Karyawan" value={getValue("jumlah_karyawan")} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -98,7 +98,9 @@ export default function SKYatim({ data }: { data: any }) {
|
|||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Tempat/Tanggal Lahir</td>
|
<td>Tempat/Tanggal Lahir</td>
|
||||||
<td>: {`${getValue("tempat_lahir")}, ${getValue("tanggal_lahir")}`}</td>
|
<td>
|
||||||
|
: {`${getValue("tempat_lahir")}, ${getValue("tanggal_lahir")}`}
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Jenis Kelamin</td>
|
<td>Jenis Kelamin</td>
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ import {
|
|||||||
IconInfoCircle,
|
IconInfoCircle,
|
||||||
IconNotes,
|
IconNotes,
|
||||||
IconPhone,
|
IconPhone,
|
||||||
IconUpload
|
IconUpload,
|
||||||
} from "@tabler/icons-react";
|
} from "@tabler/icons-react";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import "dayjs/locale/id";
|
import "dayjs/locale/id";
|
||||||
@@ -268,9 +268,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
|
||||||
@@ -298,8 +296,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">
|
||||||
@@ -348,7 +345,6 @@ export default function FormSurat() {
|
|||||||
</Grid>
|
</Grid>
|
||||||
</FormSection>
|
</FormSection>
|
||||||
|
|
||||||
|
|
||||||
{/* Kontak Section */}
|
{/* Kontak Section */}
|
||||||
<FormSection
|
<FormSection
|
||||||
title="Kontak"
|
title="Kontak"
|
||||||
@@ -385,7 +381,9 @@ export default function FormSurat() {
|
|||||||
</Grid>
|
</Grid>
|
||||||
</FormSection>
|
</FormSection>
|
||||||
|
|
||||||
{jenisSuratFix.id != "" && dataSurat && dataSurat.dataPelengkap && (
|
{jenisSuratFix.id != "" &&
|
||||||
|
dataSurat &&
|
||||||
|
dataSurat.dataPelengkap && (
|
||||||
<>
|
<>
|
||||||
<FormSection
|
<FormSection
|
||||||
title="Data Yang Diperlukan"
|
title="Data Yang Diperlukan"
|
||||||
@@ -393,55 +391,74 @@ export default function FormSurat() {
|
|||||||
icon={<IconNotes size={16} />}
|
icon={<IconNotes size={16} />}
|
||||||
>
|
>
|
||||||
<Grid>
|
<Grid>
|
||||||
{dataSurat.dataPelengkap.map((item: any, index: number) => (
|
{dataSurat.dataPelengkap.map(
|
||||||
|
(item: any, index: number) => (
|
||||||
<Grid.Col span={6} key={index}>
|
<Grid.Col span={6} key={index}>
|
||||||
{
|
{item.type == "enum" ? (
|
||||||
item.type == "enum"
|
|
||||||
?
|
|
||||||
<Select
|
<Select
|
||||||
label={
|
label={
|
||||||
<FieldLabel label={item.name} hint={item.desc} />
|
<FieldLabel
|
||||||
|
label={item.name}
|
||||||
|
hint={item.desc}
|
||||||
|
/>
|
||||||
}
|
}
|
||||||
data={item.options ?? []}
|
data={item.options ?? []}
|
||||||
placeholder={item.name}
|
placeholder={item.name}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
validationForm({
|
validationForm({
|
||||||
key: "dataPelengkap",
|
key: "dataPelengkap",
|
||||||
value: { key: item.key, value: e }
|
value: { key: item.key, value: e },
|
||||||
})
|
});
|
||||||
}}
|
}}
|
||||||
value={formSurat.dataPelengkap.find((n: any) => n.key == item.key)?.value}
|
value={
|
||||||
|
formSurat.dataPelengkap.find(
|
||||||
|
(n: any) => n.key == item.key,
|
||||||
|
)?.value
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
: item.type == "date"
|
) : item.type == "date" ? (
|
||||||
?
|
|
||||||
<DateInput
|
<DateInput
|
||||||
locale="id"
|
locale="id"
|
||||||
valueFormat="DD MMMM YYYY"
|
valueFormat="DD MMMM YYYY"
|
||||||
label={
|
label={
|
||||||
<FieldLabel label={item.name} hint={item.desc} />
|
<FieldLabel
|
||||||
|
label={item.name}
|
||||||
|
hint={item.desc}
|
||||||
|
/>
|
||||||
}
|
}
|
||||||
placeholder={item.name}
|
placeholder={item.name}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
const formatted = e
|
const formatted = e
|
||||||
? dayjs(e).locale("id").format("DD MMMM YYYY")
|
? dayjs(e)
|
||||||
|
.locale("id")
|
||||||
|
.format("DD MMMM YYYY")
|
||||||
: "";
|
: "";
|
||||||
validationForm({
|
validationForm({
|
||||||
key: "dataPelengkap",
|
key: "dataPelengkap",
|
||||||
value: { key: item.key, value: formatted },
|
value: {
|
||||||
})
|
key: item.key,
|
||||||
|
value: formatted,
|
||||||
|
},
|
||||||
|
});
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
:
|
) : (
|
||||||
<TextInput
|
<TextInput
|
||||||
type={item.type}
|
type={item.type}
|
||||||
label={
|
label={
|
||||||
<FieldLabel label={item.name} hint={item.desc} />
|
<FieldLabel
|
||||||
|
label={item.name}
|
||||||
|
hint={item.desc}
|
||||||
|
/>
|
||||||
}
|
}
|
||||||
placeholder={item.name}
|
placeholder={item.name}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
validationForm({
|
validationForm({
|
||||||
key: "dataPelengkap",
|
key: "dataPelengkap",
|
||||||
value: { key: item.key, value: e.target.value },
|
value: {
|
||||||
|
key: item.key,
|
||||||
|
value: e.target.value,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
value={
|
value={
|
||||||
@@ -450,10 +467,10 @@ export default function FormSurat() {
|
|||||||
)?.value
|
)?.value
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
}
|
)}
|
||||||
|
|
||||||
</Grid.Col>
|
</Grid.Col>
|
||||||
))}
|
),
|
||||||
|
)}
|
||||||
</Grid>
|
</Grid>
|
||||||
</FormSection>
|
</FormSection>
|
||||||
|
|
||||||
@@ -463,7 +480,8 @@ export default function FormSurat() {
|
|||||||
icon={<IconFiles size={16} />}
|
icon={<IconFiles size={16} />}
|
||||||
>
|
>
|
||||||
<Grid>
|
<Grid>
|
||||||
{dataSurat.syaratDokumen.map((item: any, index: number) => (
|
{dataSurat.syaratDokumen.map(
|
||||||
|
(item: any, index: number) => (
|
||||||
<Grid.Col span={6} key={index}>
|
<Grid.Col span={6} key={index}>
|
||||||
<FileInputWrapper
|
<FileInputWrapper
|
||||||
label={item.desc}
|
label={item.desc}
|
||||||
@@ -478,7 +496,8 @@ export default function FormSurat() {
|
|||||||
name={item.name}
|
name={item.name}
|
||||||
/>
|
/>
|
||||||
</Grid.Col>
|
</Grid.Col>
|
||||||
))}
|
),
|
||||||
|
)}
|
||||||
</Grid>
|
</Grid>
|
||||||
</FormSection>
|
</FormSection>
|
||||||
|
|
||||||
@@ -494,8 +513,7 @@ export default function FormSurat() {
|
|||||||
</Stack>
|
</Stack>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Box>
|
</Box>
|
||||||
}
|
)}
|
||||||
|
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import {
|
|||||||
Stack,
|
Stack,
|
||||||
Text,
|
Text,
|
||||||
TextInput,
|
TextInput,
|
||||||
Tooltip
|
Tooltip,
|
||||||
} from "@mantine/core";
|
} from "@mantine/core";
|
||||||
import { DateInput } from "@mantine/dates";
|
import { DateInput } from "@mantine/dates";
|
||||||
import { useDisclosure, useShallowEffect } from "@mantine/hooks";
|
import { useDisclosure, useShallowEffect } from "@mantine/hooks";
|
||||||
@@ -33,7 +33,7 @@ import {
|
|||||||
IconFiles,
|
IconFiles,
|
||||||
IconInfoCircle,
|
IconInfoCircle,
|
||||||
IconNotes,
|
IconNotes,
|
||||||
IconUpload
|
IconUpload,
|
||||||
} from "@tabler/icons-react";
|
} from "@tabler/icons-react";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import "dayjs/locale/id";
|
import "dayjs/locale/id";
|
||||||
@@ -73,7 +73,8 @@ type DataPengajuan = {
|
|||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
updatedAt: Date;
|
updatedAt: Date;
|
||||||
idSurat: string | undefined;
|
idSurat: string | undefined;
|
||||||
}
|
alasan: string | undefined | null;
|
||||||
|
};
|
||||||
|
|
||||||
export default function UpdateDataSurat() {
|
export default function UpdateDataSurat() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
@@ -82,13 +83,11 @@ export default function UpdateDataSurat() {
|
|||||||
const noPengajuan = query.get("pengajuan");
|
const noPengajuan = query.get("pengajuan");
|
||||||
const [found, setFound] = useState(true);
|
const [found, setFound] = useState(true);
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container size="md" w={"100%"}>
|
<Container size="md" w={"100%"}>
|
||||||
<Box>
|
<Box>
|
||||||
<Stack gap="lg">
|
<Stack gap="lg">
|
||||||
{
|
{found && (
|
||||||
found &&
|
|
||||||
<Group justify="space-between" align="center" mt={"lg"}>
|
<Group justify="space-between" align="center" mt={"lg"}>
|
||||||
<Group align="center">
|
<Group align="center">
|
||||||
<IconBuildingCommunity size={28} />
|
<IconBuildingCommunity size={28} />
|
||||||
@@ -97,24 +96,28 @@ export default function UpdateDataSurat() {
|
|||||||
Update Data Pengajuan Surat Administrasi
|
Update Data Pengajuan Surat Administrasi
|
||||||
</Text>
|
</Text>
|
||||||
<Text size="sm" c="dimmed">
|
<Text size="sm" c="dimmed">
|
||||||
Formulir ini digunakan untuk memperbarui data pengajuan surat administrasi yang telah diajukan sebelumnya.
|
Formulir ini digunakan untuk memperbarui data pengajuan
|
||||||
|
surat administrasi yang telah diajukan sebelumnya.
|
||||||
</Text>
|
</Text>
|
||||||
</div>
|
</div>
|
||||||
</Group>
|
</Group>
|
||||||
</Group>
|
</Group>
|
||||||
}
|
)}
|
||||||
<Stack gap="lg" mb="lg">
|
<Stack gap="lg" mb="lg">
|
||||||
{
|
{!noPengajuan ? (
|
||||||
!noPengajuan ? (
|
|
||||||
<SearchData />
|
<SearchData />
|
||||||
)
|
) : found ? (
|
||||||
:
|
<DataUpdate
|
||||||
found ? (
|
noPengajuan={noPengajuan}
|
||||||
<DataUpdate noPengajuan={noPengajuan} onValidate={(e) => { setFound(e) }} />
|
onValidate={(e) => {
|
||||||
|
setFound(e);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
) : (
|
) : (
|
||||||
<DataNotFound backTo={() => navigate("/darmasaba/update-data-surat")} />
|
<DataNotFound
|
||||||
)
|
backTo={() => navigate("/darmasaba/update-data-surat")}
|
||||||
}
|
/>
|
||||||
|
)}
|
||||||
</Stack>
|
</Stack>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Box>
|
</Box>
|
||||||
@@ -160,11 +163,13 @@ function FormSection({
|
|||||||
</Group>
|
</Group>
|
||||||
{description && <Badge variant="light">{description}</Badge>}
|
{description && <Badge variant="light">{description}</Badge>}
|
||||||
</Group>
|
</Group>
|
||||||
{info && <Text size="sm" c="dimmed">{info}</Text>}
|
{info && (
|
||||||
|
<Text size="sm" c="dimmed">
|
||||||
|
{info}
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
{
|
{title && <Divider mb="sm" />}
|
||||||
title && <Divider mb="sm" />
|
|
||||||
}
|
|
||||||
<Stack gap="sm">{children}</Stack>
|
<Stack gap="sm">{children}</Stack>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
@@ -179,7 +184,7 @@ function FileInputWrapper({
|
|||||||
name,
|
name,
|
||||||
description,
|
description,
|
||||||
linkView,
|
linkView,
|
||||||
disabled
|
disabled,
|
||||||
}: {
|
}: {
|
||||||
label: string;
|
label: string;
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
@@ -194,7 +199,6 @@ function FileInputWrapper({
|
|||||||
const [viewImg, setViewImg] = useState("");
|
const [viewImg, setViewImg] = useState("");
|
||||||
const [openedPreviewFile, setOpenedPreviewFile] = useState(false);
|
const [openedPreviewFile, setOpenedPreviewFile] = useState(false);
|
||||||
|
|
||||||
|
|
||||||
useShallowEffect(() => {
|
useShallowEffect(() => {
|
||||||
if (viewImg) {
|
if (viewImg) {
|
||||||
setOpenedPreviewFile(true);
|
setOpenedPreviewFile(true);
|
||||||
@@ -222,13 +226,11 @@ function FileInputWrapper({
|
|||||||
{description}
|
{description}
|
||||||
</Text>
|
</Text>
|
||||||
)}
|
)}
|
||||||
{
|
{linkView && (
|
||||||
linkView && (
|
|
||||||
<Anchor onClick={() => setViewImg(linkView)} size="sm">
|
<Anchor onClick={() => setViewImg(linkView)} size="sm">
|
||||||
Lihat dokumen sebelumnya
|
Lihat dokumen sebelumnya
|
||||||
</Anchor>
|
</Anchor>
|
||||||
)
|
)}
|
||||||
}
|
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
<FileInput
|
<FileInput
|
||||||
@@ -257,7 +259,6 @@ function FileInputWrapper({
|
|||||||
) : null}
|
) : null}
|
||||||
</Stack>
|
</Stack>
|
||||||
</>
|
</>
|
||||||
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -274,40 +275,41 @@ function SearchData() {
|
|||||||
notification({
|
notification({
|
||||||
title: "Peringatan",
|
title: "Peringatan",
|
||||||
message: "Silakan isi nomor pengajuan atau nomor telephone",
|
message: "Silakan isi nomor pengajuan atau nomor telephone",
|
||||||
type: "warning"
|
type: "warning",
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await apiFetch.api.pelayanan["get-no-pengajuan"].post({
|
const response = await apiFetch.api.pelayanan["get-no-pengajuan"].post({
|
||||||
phone: searchPengajuanPhone,
|
phone: searchPengajuanPhone,
|
||||||
noPengajuan: searchPengajuan
|
noPengajuan: searchPengajuan,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response.status === 200) {
|
if (response.status === 200) {
|
||||||
if (response.data?.success) {
|
if (response.data?.success) {
|
||||||
navigate(`/darmasaba/update-data-surat?pengajuan=${response.data.nomer}`);
|
navigate(
|
||||||
|
`/darmasaba/update-data-surat?pengajuan=${response.data.nomer}`,
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
notification({
|
notification({
|
||||||
title: "Peringatan",
|
title: "Peringatan",
|
||||||
message: response.data?.message || "Data pengajuan tidak valid",
|
message: response.data?.message || "Data pengajuan tidak valid",
|
||||||
type: "warning"
|
type: "warning",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
notification({
|
notification({
|
||||||
title: "Error",
|
title: "Error",
|
||||||
message: "Pengajuan tidak ditemukan atau gagal memuat data",
|
message: "Pengajuan tidak ditemukan atau gagal memuat data",
|
||||||
type: "error"
|
type: "error",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error searching:", error);
|
console.error("Error searching:", error);
|
||||||
notification({
|
notification({
|
||||||
title: "Error",
|
title: "Error",
|
||||||
message: "Gagal mencari data pengajuan",
|
message: "Gagal mencari data pengajuan",
|
||||||
type: "error"
|
type: "error",
|
||||||
});
|
});
|
||||||
} finally {
|
} finally {
|
||||||
setSubmitLoading(false);
|
setSubmitLoading(false);
|
||||||
@@ -322,9 +324,16 @@ function SearchData() {
|
|||||||
<Grid>
|
<Grid>
|
||||||
<Grid.Col span={6}>
|
<Grid.Col span={6}>
|
||||||
<TextInput
|
<TextInput
|
||||||
label={<FieldLabel label="Nomor Pengajuan" hint="Nomor pengajuan surat" />}
|
label={
|
||||||
|
<FieldLabel
|
||||||
|
label="Nomor Pengajuan"
|
||||||
|
hint="Nomor pengajuan surat"
|
||||||
|
/>
|
||||||
|
}
|
||||||
placeholder="PS-2025-000123"
|
placeholder="PS-2025-000123"
|
||||||
onChange={(e) => { setSearchPengajuan(e.target.value) }}
|
onChange={(e) => {
|
||||||
|
setSearchPengajuan(e.target.value);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</Grid.Col>
|
</Grid.Col>
|
||||||
|
|
||||||
@@ -338,30 +347,45 @@ function SearchData() {
|
|||||||
}
|
}
|
||||||
placeholder="08123456789"
|
placeholder="08123456789"
|
||||||
type="number"
|
type="number"
|
||||||
onChange={(e) => { setSearchPengajuanPhone(e.target.value) }}
|
onChange={(e) => {
|
||||||
|
setSearchPengajuanPhone(e.target.value);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</Grid.Col>
|
</Grid.Col>
|
||||||
|
|
||||||
<Grid.Col span={12}>
|
<Grid.Col span={12}>
|
||||||
<Button fullWidth variant="light" color="blue" onClick={() => { handleSearch() }} loading={submitLoading}>
|
<Button
|
||||||
|
fullWidth
|
||||||
|
variant="light"
|
||||||
|
color="blue"
|
||||||
|
onClick={() => {
|
||||||
|
handleSearch();
|
||||||
|
}}
|
||||||
|
loading={submitLoading}
|
||||||
|
>
|
||||||
Cari Pengajuan
|
Cari Pengajuan
|
||||||
</Button>
|
</Button>
|
||||||
</Grid.Col>
|
</Grid.Col>
|
||||||
</Grid>
|
</Grid>
|
||||||
</FormSection>
|
</FormSection>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function DataUpdate({
|
||||||
function DataUpdate({ noPengajuan, onValidate }: { noPengajuan: string, onValidate: (e: boolean) => void }) {
|
noPengajuan,
|
||||||
const [opened, { open, close }] = useDisclosure(false)
|
onValidate,
|
||||||
const navigate = useNavigate()
|
}: {
|
||||||
const [sukses, setSukses] = useState(false)
|
noPengajuan: string;
|
||||||
const [submitLoading, setSubmitLoading] = useState(false)
|
onValidate: (e: boolean) => void;
|
||||||
const [dataPelengkap, setDataPelengkap] = useState<DataItem[]>([])
|
}) {
|
||||||
const [dataSyaratDokumen, setDataSyaratDokumen] = useState<DataItem[]>([])
|
const [opened, { open, close }] = useDisclosure(false);
|
||||||
const [dataPengajuan, setDataPengajuan] = useState<DataPengajuan | {}>({})
|
const navigate = useNavigate();
|
||||||
const [status, setStatus] = useState("")
|
const [sukses, setSukses] = useState(false);
|
||||||
|
const [submitLoading, setSubmitLoading] = useState(false);
|
||||||
|
const [dataPelengkap, setDataPelengkap] = useState<DataItem[]>([]);
|
||||||
|
const [dataSyaratDokumen, setDataSyaratDokumen] = useState<DataItem[]>([]);
|
||||||
|
const [dataPengajuan, setDataPengajuan] = useState<DataPengajuan | {}>({});
|
||||||
|
const [status, setStatus] = useState("");
|
||||||
const [formSurat, setFormSurat] = useState<FormUpdateSurat>({
|
const [formSurat, setFormSurat] = useState<FormUpdateSurat>({
|
||||||
dataPelengkap: [],
|
dataPelengkap: [],
|
||||||
syaratDokumen: [],
|
syaratDokumen: [],
|
||||||
@@ -369,28 +393,33 @@ function DataUpdate({ noPengajuan, onValidate }: { noPengajuan: string, onValida
|
|||||||
|
|
||||||
async function fetchData() {
|
async function fetchData() {
|
||||||
try {
|
try {
|
||||||
const res = await apiFetch.api.pelayanan["detail-data"].post({ nomerPengajuan: noPengajuan });
|
const res = await apiFetch.api.pelayanan["detail-data"].post({
|
||||||
|
nomerPengajuan: noPengajuan,
|
||||||
|
});
|
||||||
if (res.data && res.data.success === true) {
|
if (res.data && res.data.success === true) {
|
||||||
onValidate(true)
|
onValidate(true);
|
||||||
setDataPelengkap(res.data.dataPelengkap || []);
|
setDataPelengkap(res.data.dataPelengkap || []);
|
||||||
setDataSyaratDokumen(res.data.syaratDokumen || []);
|
setDataSyaratDokumen(res.data.syaratDokumen || []);
|
||||||
setDataPengajuan(res.data.pengajuan || {});
|
setDataPengajuan(res.data.pengajuan || {});
|
||||||
|
|
||||||
setStatus(res.data.pengajuan && 'status' in res.data.pengajuan ? res.data.pengajuan.status : "");
|
setStatus(
|
||||||
|
res.data.pengajuan && "status" in res.data.pengajuan
|
||||||
|
? res.data.pengajuan.status
|
||||||
|
: "",
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
// notification({
|
// notification({
|
||||||
// title: "Error",
|
// title: "Error",
|
||||||
// message: res.data?.message || "Gagal memuat data",
|
// message: res.data?.message || "Gagal memuat data",
|
||||||
// type: "error",
|
// type: "error",
|
||||||
// });
|
// });
|
||||||
onValidate(false)
|
onValidate(false);
|
||||||
setDataPelengkap([]);
|
setDataPelengkap([]);
|
||||||
setDataSyaratDokumen([]);
|
setDataSyaratDokumen([]);
|
||||||
setDataPengajuan({});
|
setDataPengajuan({});
|
||||||
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error fetching data:', error);
|
console.error("Error fetching data:", error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -398,22 +427,18 @@ function DataUpdate({ noPengajuan, onValidate }: { noPengajuan: string, onValida
|
|||||||
fetchData();
|
fetchData();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
function upsertById<T extends { id: string }>(
|
function upsertById<T extends { id: string }>(array: T[], item: T): T[] {
|
||||||
array: T[],
|
const index = array.findIndex((v) => v.id === item.id);
|
||||||
item: T
|
|
||||||
): T[] {
|
|
||||||
const index = array.findIndex((v) => v.id === item.id)
|
|
||||||
|
|
||||||
// ➕ insert
|
// ➕ insert
|
||||||
if (index === -1) {
|
if (index === -1) {
|
||||||
return [...array, item]
|
return [...array, item];
|
||||||
}
|
}
|
||||||
|
|
||||||
// ✏️ update
|
// ✏️ update
|
||||||
return array.map((v, i) => (i === index ? { ...v, ...item } : v))
|
return array.map((v, i) => (i === index ? { ...v, ...item } : v));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function validationForm({
|
function validationForm({
|
||||||
kategori,
|
kategori,
|
||||||
value,
|
value,
|
||||||
@@ -426,8 +451,8 @@ function DataUpdate({ noPengajuan, onValidate }: { noPengajuan: string, onValida
|
|||||||
[kategori]: upsertById(prev[kategori], {
|
[kategori]: upsertById(prev[kategori], {
|
||||||
id: value.id,
|
id: value.id,
|
||||||
key: value.key,
|
key: value.key,
|
||||||
value: value.value
|
value: value.value,
|
||||||
})
|
}),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -436,25 +461,25 @@ function DataUpdate({ noPengajuan, onValidate }: { noPengajuan: string, onValida
|
|||||||
id: string,
|
id: string,
|
||||||
value: any,
|
value: any,
|
||||||
): UpdateDataItem[] {
|
): UpdateDataItem[] {
|
||||||
return list.map((item) =>
|
return list.map((item) => (item.id === id ? { ...item, value } : item));
|
||||||
item.id === id ? { ...item, value } : item,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function onChecking() {
|
function onChecking() {
|
||||||
if (formSurat.dataPelengkap.length == 0 && formSurat.syaratDokumen.length == 0)
|
if (
|
||||||
|
formSurat.dataPelengkap.length == 0 &&
|
||||||
|
formSurat.syaratDokumen.length == 0
|
||||||
|
)
|
||||||
return notification({
|
return notification({
|
||||||
title: "Peringatan",
|
title: "Peringatan",
|
||||||
message: "Tidak ada data yang diupdate",
|
message: "Tidak ada data yang diupdate",
|
||||||
type: "warning",
|
type: "warning",
|
||||||
});
|
});
|
||||||
const isFormKosong = Object.values(formSurat).some((value: UpdateDataItem[] | string) => {
|
const isFormKosong = Object.values(formSurat).some(
|
||||||
|
(value: UpdateDataItem[] | string) => {
|
||||||
if (Array.isArray(value)) {
|
if (Array.isArray(value)) {
|
||||||
return (
|
return value.some(
|
||||||
value.some(
|
|
||||||
(item) =>
|
(item) =>
|
||||||
typeof item.value === "string" && item.value.trim() === "",
|
typeof item.value === "string" && item.value.trim() === "",
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -463,7 +488,8 @@ function DataUpdate({ noPengajuan, onValidate }: { noPengajuan: string, onValida
|
|||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|
||||||
if (isFormKosong) {
|
if (isFormKosong) {
|
||||||
return notification({
|
return notification({
|
||||||
@@ -472,7 +498,7 @@ function DataUpdate({ noPengajuan, onValidate }: { noPengajuan: string, onValida
|
|||||||
type: "error",
|
type: "error",
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
open()
|
open();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -504,7 +530,7 @@ function DataUpdate({ noPengajuan, onValidate }: { noPengajuan: string, onValida
|
|||||||
|
|
||||||
// 4️⃣ SUBMIT KE API
|
// 4️⃣ SUBMIT KE API
|
||||||
const res = await apiFetch.api.pelayanan.update.post({
|
const res = await apiFetch.api.pelayanan.update.post({
|
||||||
id: dataPengajuan && ('id' in dataPengajuan) ? dataPengajuan.id : "",
|
id: dataPengajuan && "id" in dataPengajuan ? dataPengajuan.id : "",
|
||||||
dataPelengkap: finalFormSurat.dataPelengkap,
|
dataPelengkap: finalFormSurat.dataPelengkap,
|
||||||
syaratDokumen: finalFormSurat.syaratDokumen,
|
syaratDokumen: finalFormSurat.syaratDokumen,
|
||||||
});
|
});
|
||||||
@@ -530,7 +556,6 @@ function DataUpdate({ noPengajuan, onValidate }: { noPengajuan: string, onValida
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<FullScreenLoading visible={submitLoading} />
|
<FullScreenLoading visible={submitLoading} />
|
||||||
@@ -541,9 +566,7 @@ function DataUpdate({ noPengajuan, onValidate }: { noPengajuan: string, onValida
|
|||||||
overlayProps={{ backgroundOpacity: 0.55, blur: 3 }}
|
overlayProps={{ backgroundOpacity: 0.55, blur: 3 }}
|
||||||
>
|
>
|
||||||
<Stack gap="sm">
|
<Stack gap="sm">
|
||||||
<Text>
|
<Text>Apakah anda yakin ingin mengupdate pengajuan surat ini?</Text>
|
||||||
Apakah anda yakin ingin mengupdate pengajuan surat ini?
|
|
||||||
</Text>
|
|
||||||
<Group justify="center" grow>
|
<Group justify="center" grow>
|
||||||
<Button variant="light" onClick={close}>
|
<Button variant="light" onClick={close}>
|
||||||
Tidak
|
Tidak
|
||||||
@@ -561,8 +584,7 @@ function DataUpdate({ noPengajuan, onValidate }: { noPengajuan: string, onValida
|
|||||||
</Group>
|
</Group>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Modal>
|
</Modal>
|
||||||
{
|
{sukses ? (
|
||||||
sukses ?
|
|
||||||
<SuccessPengajuan
|
<SuccessPengajuan
|
||||||
noPengajuan={noPengajuan}
|
noPengajuan={noPengajuan}
|
||||||
onClose={() => {
|
onClose={() => {
|
||||||
@@ -570,12 +592,29 @@ function DataUpdate({ noPengajuan, onValidate }: { noPengajuan: string, onValida
|
|||||||
}}
|
}}
|
||||||
category="update"
|
category="update"
|
||||||
/>
|
/>
|
||||||
:
|
) : (
|
||||||
<>
|
<>
|
||||||
{
|
{status != "ditolak" && status != "antrian" && (
|
||||||
(status != "ditolak" && status != "antrian")
|
<Alert
|
||||||
&& <Alert variant="light" color="yellow" radius="lg" title={`Data pengajuan surat ini tidak dapat diupdate karena berstatus ${status}.`} icon={<span style={{ fontSize: '1.2rem' }}>⚠</span>} />
|
variant="light"
|
||||||
}
|
color="yellow"
|
||||||
|
radius="lg"
|
||||||
|
title={`Data pengajuan surat ini tidak dapat diupdate karena berstatus ${status}.`}
|
||||||
|
icon={<span style={{ fontSize: "1.2rem" }}>⚠</span>}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{status == "ditolak" && (
|
||||||
|
<Alert
|
||||||
|
variant="light"
|
||||||
|
color="yellow"
|
||||||
|
radius="lg"
|
||||||
|
title={`Data pengajuan surat ini ditolak, karena ${dataPengajuan && 'alasan' in dataPengajuan && dataPengajuan.alasan
|
||||||
|
? dataPengajuan.alasan
|
||||||
|
: "alasan tidak tersedia"
|
||||||
|
}. Silahkan perbaiki data pengajuan surat ini.`}
|
||||||
|
icon={<span style={{ fontSize: "1.2rem" }}>⚠</span>}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<FormSection
|
<FormSection
|
||||||
title="Data Yang Diperlukan"
|
title="Data Yang Diperlukan"
|
||||||
description="Data yang diperlukan"
|
description="Data yang diperlukan"
|
||||||
@@ -584,31 +623,29 @@ function DataUpdate({ noPengajuan, onValidate }: { noPengajuan: string, onValida
|
|||||||
<Grid>
|
<Grid>
|
||||||
{dataPelengkap.map((item: any, index: number) => (
|
{dataPelengkap.map((item: any, index: number) => (
|
||||||
<Grid.Col span={6} key={index}>
|
<Grid.Col span={6} key={index}>
|
||||||
{
|
{item.type == "enum" ? (
|
||||||
item.type == "enum"
|
|
||||||
?
|
|
||||||
<Select
|
<Select
|
||||||
label={
|
label={<FieldLabel label={item.name} hint={item.desc} />}
|
||||||
<FieldLabel label={item.name} hint={item.desc} />
|
|
||||||
}
|
|
||||||
data={item.options ?? []}
|
data={item.options ?? []}
|
||||||
placeholder={item.name}
|
placeholder={item.name}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
validationForm({
|
validationForm({
|
||||||
kategori: "dataPelengkap",
|
kategori: "dataPelengkap",
|
||||||
value: { id: item.id, key: item.key, value: e }
|
value: { id: item.id, key: item.key, value: e },
|
||||||
})
|
});
|
||||||
}}
|
}}
|
||||||
value={formSurat.dataPelengkap.find((n: any) => n.key == item.key)?.value || dataPelengkap.find((n: any) => n.key == item.key)?.value}
|
value={
|
||||||
|
formSurat.dataPelengkap.find(
|
||||||
|
(n: any) => n.key == item.key,
|
||||||
|
)?.value ||
|
||||||
|
dataPelengkap.find((n: any) => n.key == item.key)?.value
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
: item.type == "date"
|
) : item.type == "date" ? (
|
||||||
?
|
|
||||||
<DateInput
|
<DateInput
|
||||||
locale="id"
|
locale="id"
|
||||||
valueFormat="DD MMMM YYYY"
|
valueFormat="DD MMMM YYYY"
|
||||||
label={
|
label={<FieldLabel label={item.name} hint={item.desc} />}
|
||||||
<FieldLabel label={item.name} hint={item.desc} />
|
|
||||||
}
|
|
||||||
placeholder={item.name}
|
placeholder={item.name}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
const formatted = e
|
const formatted = e
|
||||||
@@ -616,34 +653,47 @@ function DataUpdate({ noPengajuan, onValidate }: { noPengajuan: string, onValida
|
|||||||
: "";
|
: "";
|
||||||
validationForm({
|
validationForm({
|
||||||
kategori: "dataPelengkap",
|
kategori: "dataPelengkap",
|
||||||
value: { id: item.id, key: item.key, value: formatted },
|
value: {
|
||||||
})
|
id: item.id,
|
||||||
|
key: item.key,
|
||||||
|
value: formatted,
|
||||||
|
},
|
||||||
|
});
|
||||||
}}
|
}}
|
||||||
value={
|
value={
|
||||||
formSurat.dataPelengkap.find((n: any) => n.key === item.key)?.value ?
|
formSurat.dataPelengkap.find(
|
||||||
parseTanggalID(
|
(n: any) => n.key === item.key,
|
||||||
formSurat.dataPelengkap.find((n: any) => n.key === item.key)?.value
|
)?.value
|
||||||
) :
|
? parseTanggalID(
|
||||||
parseTanggalID(
|
formSurat.dataPelengkap.find(
|
||||||
item.value
|
(n: any) => n.key === item.key,
|
||||||
|
)?.value,
|
||||||
)
|
)
|
||||||
|
: parseTanggalID(item.value)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
: <TextInput
|
) : (
|
||||||
label={
|
<TextInput
|
||||||
<FieldLabel label={item.name} hint={item.desc} />
|
label={<FieldLabel label={item.name} hint={item.desc} />}
|
||||||
}
|
|
||||||
placeholder={item.name}
|
placeholder={item.name}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
validationForm({
|
validationForm({
|
||||||
kategori: "dataPelengkap",
|
kategori: "dataPelengkap",
|
||||||
value: { id: item.id, key: item.key, value: e.target.value },
|
value: {
|
||||||
|
id: item.id,
|
||||||
|
key: item.key,
|
||||||
|
value: e.target.value,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
value={formSurat.dataPelengkap.find((n) => n.id === item.id)?.value ?? dataPelengkap.find((n: any) => n.key == item.key,)?.value}
|
value={
|
||||||
|
formSurat.dataPelengkap.find((n) => n.id === item.id)
|
||||||
|
?.value ??
|
||||||
|
dataPelengkap.find((n: any) => n.key == item.key)?.value
|
||||||
|
}
|
||||||
disabled={status != "ditolak" && status != "antrian"}
|
disabled={status != "ditolak" && status != "antrian"}
|
||||||
/>
|
/>
|
||||||
}
|
)}
|
||||||
</Grid.Col>
|
</Grid.Col>
|
||||||
))}
|
))}
|
||||||
</Grid>
|
</Grid>
|
||||||
@@ -677,10 +727,17 @@ function DataUpdate({ noPengajuan, onValidate }: { noPengajuan: string, onValida
|
|||||||
</FormSection>
|
</FormSection>
|
||||||
|
|
||||||
<Group justify="right" mt="md">
|
<Group justify="right" mt="md">
|
||||||
<Button onClick={() => { onChecking() }} disabled={status != "ditolak" && status != "antrian"}>Kirim</Button>
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
onChecking();
|
||||||
|
}}
|
||||||
|
disabled={status != "ditolak" && status != "antrian"}
|
||||||
|
>
|
||||||
|
Kirim
|
||||||
|
</Button>
|
||||||
</Group>
|
</Group>
|
||||||
</>
|
</>
|
||||||
}
|
)}
|
||||||
</>
|
</>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -437,7 +437,12 @@ function DetailDataHistori({ data }: { data: any }) {
|
|||||||
</Title>
|
</Title>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Divider my={0} />
|
<Divider my={0} />
|
||||||
<Spoiler maxHeight={200} showLabel="Show more" hideLabel="Hide" transitionDuration={1000}>
|
<Spoiler
|
||||||
|
maxHeight={200}
|
||||||
|
showLabel="Show more"
|
||||||
|
hideLabel="Hide"
|
||||||
|
transitionDuration={1000}
|
||||||
|
>
|
||||||
<Table>
|
<Table>
|
||||||
<Table.Thead>
|
<Table.Thead>
|
||||||
<Table.Tr>
|
<Table.Tr>
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ 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 { search } = useLocation();
|
const { search } = useLocation();
|
||||||
const query = new URLSearchParams(search);
|
const query = new URLSearchParams(search);
|
||||||
@@ -61,6 +62,7 @@ export default function DetailPengaduanPage() {
|
|||||||
<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();
|
||||||
}}
|
}}
|
||||||
@@ -78,9 +80,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);
|
||||||
@@ -122,6 +126,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({
|
||||||
@@ -129,6 +148,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",
|
||||||
@@ -425,7 +466,12 @@ function DetailDataHistori({ data }: { data: any }) {
|
|||||||
</Title>
|
</Title>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Divider my={0} />
|
<Divider my={0} />
|
||||||
<Spoiler maxHeight={200} showLabel="Show more" hideLabel="Hide" transitionDuration={1000}>
|
<Spoiler
|
||||||
|
maxHeight={200}
|
||||||
|
showLabel="Show more"
|
||||||
|
hideLabel="Hide"
|
||||||
|
transitionDuration={1000}
|
||||||
|
>
|
||||||
<Table>
|
<Table>
|
||||||
<Table.Thead>
|
<Table.Thead>
|
||||||
<Table.Tr>
|
<Table.Tr>
|
||||||
|
|||||||
@@ -745,6 +745,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,
|
||||||
@@ -771,6 +784,7 @@ 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 = {
|
||||||
|
|||||||
@@ -415,7 +415,7 @@ const PengaduanRoute = new Elysia({
|
|||||||
const datafix = {
|
const datafix = {
|
||||||
pengaduan: {},
|
pengaduan: {},
|
||||||
history: [],
|
history: [],
|
||||||
warga: {},
|
warga: null,
|
||||||
}
|
}
|
||||||
|
|
||||||
return datafix
|
return datafix
|
||||||
|
|||||||
81
src/server/routes/send_wa_route.ts
Normal file
81
src/server/routes/send_wa_route.ts
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
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`
|
||||||
|
}
|
||||||
|
})
|
||||||
|
;
|
||||||
|
|
||||||
|
export default SendWaRoute
|
||||||
Reference in New Issue
Block a user