Deskripsi: - satuan luas tempat usaha - satuan pendapatan perbulan - pada tambah, edit, detail surat No Issues
838 lines
23 KiB
TypeScript
838 lines
23 KiB
TypeScript
import FullScreenLoading from "@/components/FullScreenLoading";
|
||
import ModalFile from "@/components/ModalFile";
|
||
import { DataNotFound } from "@/components/NotFoundPengajuanSurat";
|
||
import notification from "@/components/notificationGlobal";
|
||
import SuccessPengajuan from "@/components/SuccessPengajuanSurat";
|
||
import apiFetch from "@/lib/apiFetch";
|
||
import { parseTanggalID } from "@/server/lib/stringToDate";
|
||
import {
|
||
ActionIcon,
|
||
Alert,
|
||
Anchor,
|
||
Badge,
|
||
Box,
|
||
Button,
|
||
Card,
|
||
Container,
|
||
Divider,
|
||
FileInput,
|
||
Flex,
|
||
Grid,
|
||
Group,
|
||
Modal,
|
||
Select,
|
||
Stack,
|
||
Text,
|
||
TextInput,
|
||
Tooltip,
|
||
} from "@mantine/core";
|
||
import { DateInput } from "@mantine/dates";
|
||
import { useDisclosure, useShallowEffect } from "@mantine/hooks";
|
||
import {
|
||
IconBuildingCommunity,
|
||
IconFiles,
|
||
IconInfoCircle,
|
||
IconNotes,
|
||
IconUpload,
|
||
} from "@tabler/icons-react";
|
||
import dayjs from "dayjs";
|
||
import "dayjs/locale/id";
|
||
import _ from "lodash";
|
||
import React, { useState } from "react";
|
||
import { useLocation, useNavigate } from "react-router-dom";
|
||
|
||
type DataItem = {
|
||
key: string;
|
||
value: string;
|
||
};
|
||
|
||
type UpdateDataItem = {
|
||
id: string;
|
||
key: string;
|
||
value: any;
|
||
required: boolean;
|
||
};
|
||
|
||
type FormSurat = {
|
||
kategoriId: string;
|
||
nama: string;
|
||
phone: string;
|
||
dataPelengkap: DataItem[];
|
||
syaratDokumen: DataItem[];
|
||
};
|
||
|
||
type FormUpdateSurat = {
|
||
dataPelengkap: UpdateDataItem[];
|
||
syaratDokumen: UpdateDataItem[];
|
||
};
|
||
|
||
type DataPengajuan = {
|
||
id: string;
|
||
noPengajuan: string;
|
||
category: string;
|
||
status: "antrian" | "diproses" | "selesai" | "ditolak";
|
||
createdAt: Date;
|
||
updatedAt: Date;
|
||
idSurat: string | undefined;
|
||
alasan: string | undefined | null;
|
||
};
|
||
|
||
export default function UpdateDataSurat() {
|
||
const navigate = useNavigate();
|
||
const { search } = useLocation();
|
||
const query = new URLSearchParams(search);
|
||
const noPengajuan = query.get("pengajuan");
|
||
const [found, setFound] = useState(true);
|
||
|
||
return (
|
||
<Container size="md" w={"100%"}>
|
||
<Box>
|
||
<Stack gap="lg">
|
||
{found && (
|
||
<Group justify="space-between" align="center" mt={"lg"}>
|
||
<Group align="center">
|
||
<IconBuildingCommunity size={28} />
|
||
<div>
|
||
<Text fw={800} size="xl">
|
||
Update Data Pengajuan Surat Administrasi
|
||
</Text>
|
||
<Text size="sm" c="dimmed">
|
||
Formulir ini digunakan untuk memperbarui data pengajuan
|
||
surat administrasi yang telah diajukan sebelumnya.
|
||
</Text>
|
||
</div>
|
||
</Group>
|
||
</Group>
|
||
)}
|
||
<Stack gap="lg" mb="lg">
|
||
{!noPengajuan ? (
|
||
<SearchData />
|
||
) : found ? (
|
||
<DataUpdate
|
||
noPengajuan={noPengajuan}
|
||
onValidate={(e) => {
|
||
setFound(e);
|
||
}}
|
||
/>
|
||
) : (
|
||
<DataNotFound
|
||
backTo={() => navigate("/darmasaba/update-data-surat")}
|
||
/>
|
||
)}
|
||
</Stack>
|
||
</Stack>
|
||
</Box>
|
||
</Container>
|
||
);
|
||
}
|
||
|
||
function FieldLabel({ label, hint, required = false, }: { label: string; hint?: string; required?: boolean; }) {
|
||
return (
|
||
<Group justify="apart" gap="xs" align="center">
|
||
<Group gap={4} align="center">
|
||
<Text fw={600}>
|
||
{label}
|
||
{required && (
|
||
<Text span c="red" ml={4}>
|
||
*
|
||
</Text>
|
||
)}
|
||
</Text>
|
||
</Group>
|
||
|
||
{hint && (
|
||
<Tooltip label={hint} withArrow>
|
||
<ActionIcon size={24} variant="subtle">
|
||
<IconInfoCircle size={16} />
|
||
</ActionIcon>
|
||
</Tooltip>
|
||
)}
|
||
</Group>
|
||
);
|
||
}
|
||
function FormSection({
|
||
title,
|
||
icon,
|
||
children,
|
||
description,
|
||
info,
|
||
}: {
|
||
title?: string;
|
||
icon?: React.ReactNode;
|
||
children: React.ReactNode;
|
||
description?: string;
|
||
info?: string;
|
||
}) {
|
||
return (
|
||
<Card radius="md" shadow="sm" withBorder>
|
||
<Box mb="xs">
|
||
<Group justify="apart" align="center">
|
||
<Group align="center" gap="xs">
|
||
{icon}
|
||
{title && <Text fw={700}>{title}</Text>}
|
||
</Group>
|
||
{description && <Badge variant="light">{description}</Badge>}
|
||
</Group>
|
||
{info && (
|
||
<Text size="sm" c="dimmed">
|
||
{info}
|
||
</Text>
|
||
)}
|
||
</Box>
|
||
{title && <Divider mb="sm" />}
|
||
<Stack gap="sm">{children}</Stack>
|
||
</Card>
|
||
);
|
||
}
|
||
|
||
function FileInputWrapper({
|
||
label,
|
||
placeholder,
|
||
accept,
|
||
onChange,
|
||
preview,
|
||
name,
|
||
description,
|
||
linkView,
|
||
disabled,
|
||
required = false,
|
||
|
||
}: {
|
||
label: string;
|
||
placeholder?: string;
|
||
accept?: string;
|
||
linkView?: string;
|
||
onChange: (file: File | null) => void;
|
||
preview?: string | null;
|
||
name: string;
|
||
description?: string;
|
||
disabled?: boolean;
|
||
required?: boolean;
|
||
}) {
|
||
const [viewImg, setViewImg] = useState("");
|
||
const [openedPreviewFile, setOpenedPreviewFile] = useState(false);
|
||
|
||
useShallowEffect(() => {
|
||
if (viewImg) {
|
||
setOpenedPreviewFile(true);
|
||
}
|
||
}, [viewImg]);
|
||
|
||
return (
|
||
<>
|
||
<ModalFile
|
||
open={openedPreviewFile && !_.isEmpty(viewImg)}
|
||
onClose={() => {
|
||
setOpenedPreviewFile(false);
|
||
}}
|
||
folder="syarat-dokumen"
|
||
fileName={viewImg}
|
||
/>
|
||
|
||
<Stack gap="xs">
|
||
<Flex direction={"column"}>
|
||
<Group justify="apart" align="center">
|
||
<Text fw={500}>
|
||
{label}
|
||
{required && (
|
||
<Text span c="red" ml={4}>
|
||
*
|
||
</Text>
|
||
)}
|
||
</Text>
|
||
</Group>
|
||
{description && (
|
||
<Text size="sm" c="dimmed" mt={4} style={{ lineHeight: 1.2 }}>
|
||
{description}
|
||
</Text>
|
||
)}
|
||
{linkView && (
|
||
<Anchor onClick={() => setViewImg(linkView)} size="sm">
|
||
Lihat dokumen sebelumnya
|
||
</Anchor>
|
||
)}
|
||
</Flex>
|
||
|
||
<FileInput
|
||
accept={accept}
|
||
placeholder={placeholder}
|
||
onChange={(f) => onChange(f)}
|
||
leftSection={<IconUpload />}
|
||
aria-label={label}
|
||
name={name}
|
||
disabled={disabled}
|
||
clearable={true}
|
||
/>
|
||
|
||
{preview ? (
|
||
<div>
|
||
<Text size="xs" color="dimmed">
|
||
Preview:
|
||
</Text>
|
||
<div style={{ marginTop: 6 }}>
|
||
<img
|
||
src={preview}
|
||
alt={`${label} preview`}
|
||
style={{ maxWidth: "200px", borderRadius: 4 }}
|
||
/>
|
||
</div>
|
||
</div>
|
||
) : null}
|
||
</Stack>
|
||
</>
|
||
);
|
||
}
|
||
|
||
function SearchData() {
|
||
const [submitLoading, setSubmitLoading] = useState(false);
|
||
const [searchPengajuan, setSearchPengajuan] = useState("");
|
||
const [searchPengajuanPhone, setSearchPengajuanPhone] = useState("");
|
||
const navigate = useNavigate();
|
||
|
||
async function handleSearch() {
|
||
try {
|
||
setSubmitLoading(true);
|
||
if (searchPengajuan == "" || searchPengajuanPhone == "") {
|
||
notification({
|
||
title: "Peringatan",
|
||
message: "Silakan isi nomor pengajuan atau nomor telephone",
|
||
type: "warning",
|
||
});
|
||
return;
|
||
}
|
||
|
||
const response = await apiFetch.api.pelayanan["get-no-pengajuan"].post({
|
||
phone: searchPengajuanPhone,
|
||
noPengajuan: searchPengajuan,
|
||
});
|
||
|
||
if (response.status === 200) {
|
||
if (response.data?.success) {
|
||
navigate(
|
||
`/darmasaba/update-data-surat?pengajuan=${response.data.nomer}`,
|
||
);
|
||
} else {
|
||
notification({
|
||
title: "Peringatan",
|
||
message: response.data?.message || "Data pengajuan tidak valid",
|
||
type: "warning",
|
||
});
|
||
}
|
||
} else {
|
||
notification({
|
||
title: "Error",
|
||
message: "Pengajuan tidak ditemukan atau gagal memuat data",
|
||
type: "error",
|
||
});
|
||
}
|
||
} catch (error) {
|
||
console.error("Error searching:", error);
|
||
notification({
|
||
title: "Error",
|
||
message: "Gagal mencari data pengajuan",
|
||
type: "error",
|
||
});
|
||
} finally {
|
||
setSubmitLoading(false);
|
||
}
|
||
}
|
||
|
||
return (
|
||
<>
|
||
<FullScreenLoading visible={submitLoading} text="Mencari Data" />
|
||
<FormSection
|
||
title="Cari Pengajuan Surat"
|
||
info="Masukkan nomor pengajuan dan nomor telepon yang digunakan saat pengajuan surat."
|
||
>
|
||
<Grid>
|
||
<Grid.Col span={6}>
|
||
<TextInput
|
||
label={
|
||
<FieldLabel
|
||
label="Nomor Pengajuan"
|
||
hint="Nomor pengajuan surat"
|
||
/>
|
||
}
|
||
placeholder="PS-2025-000123"
|
||
onChange={(e) => {
|
||
setSearchPengajuan(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"
|
||
type="number"
|
||
onChange={(e) => {
|
||
setSearchPengajuanPhone(e.target.value);
|
||
}}
|
||
/>
|
||
</Grid.Col>
|
||
|
||
<Grid.Col span={12}>
|
||
<Button
|
||
fullWidth
|
||
variant="light"
|
||
color="blue"
|
||
onClick={() => {
|
||
handleSearch();
|
||
}}
|
||
loading={submitLoading}
|
||
>
|
||
Cari Pengajuan
|
||
</Button>
|
||
</Grid.Col>
|
||
</Grid>
|
||
</FormSection>
|
||
</>
|
||
);
|
||
}
|
||
|
||
function DataUpdate({
|
||
noPengajuan,
|
||
onValidate,
|
||
}: {
|
||
noPengajuan: string;
|
||
onValidate: (e: boolean) => void;
|
||
}) {
|
||
const [opened, { open, close }] = useDisclosure(false);
|
||
const navigate = useNavigate();
|
||
const [errors, setErrors] = useState<Record<string, string | null>>({});
|
||
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 [loadingFetchData, setLoadingFetchData] = useState(false);
|
||
const [formSurat, setFormSurat] = useState<FormUpdateSurat>({
|
||
dataPelengkap: [],
|
||
syaratDokumen: [],
|
||
});
|
||
|
||
async function fetchData() {
|
||
try {
|
||
setLoadingFetchData(true);
|
||
const res = await apiFetch.api.pelayanan["detail-data"].post({
|
||
nomerPengajuan: noPengajuan,
|
||
});
|
||
if (res.data && res.data.success === true) {
|
||
onValidate(true);
|
||
setDataPelengkap(res.data.dataPelengkap || []);
|
||
setDataSyaratDokumen(res.data.syaratDokumen || []);
|
||
setDataPengajuan(res.data.pengajuan || {});
|
||
|
||
setStatus(
|
||
res.data.pengajuan && "status" in res.data.pengajuan
|
||
? res.data.pengajuan.status
|
||
: "",
|
||
);
|
||
} else {
|
||
// notification({
|
||
// title: "Error",
|
||
// message: res.data?.message || "Gagal memuat data",
|
||
// type: "error",
|
||
// });
|
||
onValidate(false);
|
||
setDataPelengkap([]);
|
||
setDataSyaratDokumen([]);
|
||
setDataPengajuan({});
|
||
}
|
||
} catch (error) {
|
||
console.error("Error fetching data:", error);
|
||
} finally {
|
||
setLoadingFetchData(false);
|
||
}
|
||
}
|
||
|
||
useShallowEffect(() => {
|
||
fetchData();
|
||
}, []);
|
||
|
||
function validateField(key: string, value: any) {
|
||
const stringValue = String(value ?? "").trim();
|
||
|
||
// wajib diisi
|
||
if (!stringValue) {
|
||
return "Field wajib diisi";
|
||
}
|
||
|
||
// 🔥 semua key yg 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 upsertById<T extends { id: string }>(array: T[], item: T): T[] {
|
||
const index = array.findIndex((v) => v.id === item.id);
|
||
|
||
// ➕ insert
|
||
if (index === -1) {
|
||
return [...array, item];
|
||
}
|
||
|
||
// ✏️ update
|
||
return array.map((v, i) => (i === index ? { ...v, ...item } : v));
|
||
}
|
||
|
||
function validationForm({
|
||
kategori,
|
||
value,
|
||
}: {
|
||
kategori: "dataPelengkap" | "syaratDokumen";
|
||
value: UpdateDataItem;
|
||
}) {
|
||
if (kategori == "syaratDokumen" && value.value == null) {
|
||
setFormSurat((prev) => ({
|
||
...prev,
|
||
syaratDokumen: prev.syaratDokumen.filter(
|
||
(item) => item.id !== value.id
|
||
),
|
||
}));
|
||
} else {
|
||
if (value.required == true) {
|
||
const errorMsg = validateField(value.key, value.value);
|
||
setErrors((prev) => ({
|
||
...prev,
|
||
[value.id]: errorMsg,
|
||
}));
|
||
}
|
||
|
||
|
||
setFormSurat((prev) => ({
|
||
...prev,
|
||
[kategori]: upsertById(prev[kategori], {
|
||
id: value.id,
|
||
key: value.key,
|
||
value: value.value,
|
||
required: value.required,
|
||
}),
|
||
}));
|
||
}
|
||
}
|
||
|
||
|
||
function updateArrayByKey(
|
||
list: UpdateDataItem[],
|
||
id: string,
|
||
value: any,
|
||
): UpdateDataItem[] {
|
||
return list.map((item) => (item.id === id ? { ...item, value } : item));
|
||
}
|
||
|
||
function onChecking() {
|
||
const hasError = Object.values(errors).some((v) => v);
|
||
|
||
if (hasError) {
|
||
return notification({
|
||
title: "Gagal",
|
||
message: "Masih ada data yang belum valid",
|
||
type: "error",
|
||
});
|
||
}
|
||
|
||
if (
|
||
formSurat.dataPelengkap.length == 0 &&
|
||
formSurat.syaratDokumen.length == 0
|
||
)
|
||
return notification({
|
||
title: "Peringatan",
|
||
message: "Tidak ada data yang diupdate",
|
||
type: "warning",
|
||
});
|
||
const isFormKosong = Object.values(formSurat).some(
|
||
(value: UpdateDataItem[] | string) => {
|
||
if (Array.isArray(value)) {
|
||
return value.some(
|
||
(item) =>
|
||
(typeof item.value === "string" && item.value.trim() === "" && item.required) || (typeof item.value === "object" && item.value === null && item.required),
|
||
);
|
||
}
|
||
|
||
if (typeof value === "string") {
|
||
return value.trim() === "";
|
||
}
|
||
|
||
return false;
|
||
},
|
||
);
|
||
|
||
if (isFormKosong) {
|
||
return notification({
|
||
title: "Gagal",
|
||
message: "Silahkan lengkapi form surat",
|
||
type: "error",
|
||
});
|
||
} else {
|
||
open();
|
||
}
|
||
}
|
||
|
||
async function onSubmit() {
|
||
try {
|
||
setSubmitLoading(true);
|
||
// 🔥 CLONE state SEKALI
|
||
let finalFormSurat = structuredClone(formSurat);
|
||
|
||
// 2️⃣ Upload satu per satu
|
||
for (const itemUpload of finalFormSurat.syaratDokumen) {
|
||
const updImg = await apiFetch.api.pengaduan.upload.post({
|
||
file: itemUpload.value,
|
||
folder: "syarat-dokumen",
|
||
});
|
||
|
||
if (updImg.status === 200) {
|
||
// 🔥 UPDATE OBJECT LOKAL (BUKAN STATE)
|
||
finalFormSurat.syaratDokumen = updateArrayByKey(
|
||
finalFormSurat.syaratDokumen,
|
||
itemUpload.id,
|
||
updImg.data?.filename || "",
|
||
);
|
||
}
|
||
}
|
||
|
||
// 3️⃣ SET STATE SEKALI (optional, untuk UI)
|
||
setFormSurat(finalFormSurat);
|
||
|
||
// 4️⃣ SUBMIT KE API
|
||
const res = await apiFetch.api.pelayanan.update.post({
|
||
id: dataPengajuan && "id" in dataPengajuan ? dataPengajuan.id : "",
|
||
dataPelengkap: finalFormSurat.dataPelengkap,
|
||
syaratDokumen: finalFormSurat.syaratDokumen,
|
||
});
|
||
|
||
if (res.status === 200) {
|
||
setSukses(true);
|
||
} else {
|
||
notification({
|
||
title: "Gagal",
|
||
message:
|
||
"Pengajuan surat gagal dibuat, silahkan coba beberapa saat lagi",
|
||
type: "error",
|
||
});
|
||
}
|
||
} catch (error) {
|
||
notification({
|
||
title: "Gagal",
|
||
message: "Server Error",
|
||
type: "error",
|
||
});
|
||
} finally {
|
||
setSubmitLoading(false);
|
||
}
|
||
}
|
||
|
||
return (
|
||
<>
|
||
<FullScreenLoading visible={submitLoading || loadingFetchData} />
|
||
<Modal
|
||
opened={opened}
|
||
onClose={close}
|
||
title={"Konfirmasi"}
|
||
overlayProps={{ backgroundOpacity: 0.55, blur: 3 }}
|
||
>
|
||
<Stack gap="sm">
|
||
<Text>Apakah anda yakin ingin mengupdate pengajuan surat ini?</Text>
|
||
<Group justify="center" grow>
|
||
<Button variant="light" onClick={close}>
|
||
Tidak
|
||
</Button>
|
||
<Button
|
||
variant="filled"
|
||
color="green"
|
||
onClick={() => {
|
||
onSubmit();
|
||
close();
|
||
}}
|
||
>
|
||
Ya
|
||
</Button>
|
||
</Group>
|
||
</Stack>
|
||
</Modal>
|
||
{sukses ? (
|
||
<SuccessPengajuan
|
||
noPengajuan={noPengajuan}
|
||
onClose={() => {
|
||
navigate("/darmasaba/update-data-surat");
|
||
}}
|
||
category="update"
|
||
/>
|
||
) : (
|
||
<>
|
||
{status != "ditolak" && status != "antrian" && (
|
||
<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>}
|
||
/>
|
||
)}
|
||
{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
|
||
title="Data Yang Diperlukan"
|
||
description="Data yang diperlukan"
|
||
icon={<IconNotes size={16} />}
|
||
>
|
||
<Grid>
|
||
{dataPelengkap.map((item: any, index: number) => (
|
||
<Grid.Col span={6} key={index}>
|
||
{item.type == "enum" ? (
|
||
<Select
|
||
disabled={status != "ditolak" && status != "antrian"}
|
||
allowDeselect={false}
|
||
label={<FieldLabel label={item.name} hint={item.desc} required={item.required} />}
|
||
data={item.options ?? []}
|
||
placeholder={item.name}
|
||
onChange={(e) => {
|
||
validationForm({
|
||
kategori: "dataPelengkap",
|
||
value: { id: item.id, key: item.key, value: e, required: item.required },
|
||
});
|
||
}}
|
||
value={
|
||
formSurat.dataPelengkap.find(
|
||
(n: any) => n.key == item.key,
|
||
)?.value ||
|
||
dataPelengkap.find((n: any) => n.key == item.key)?.value
|
||
}
|
||
/>
|
||
) : item.type == "date" ? (
|
||
<DateInput
|
||
disabled={status != "ditolak" && status != "antrian"}
|
||
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({
|
||
kategori: "dataPelengkap",
|
||
value: {
|
||
id: item.id,
|
||
key: item.key,
|
||
value: formatted,
|
||
required: item.required
|
||
},
|
||
});
|
||
}}
|
||
value={
|
||
formSurat.dataPelengkap.find(
|
||
(n: any) => n.key === item.key,
|
||
)?.value
|
||
? parseTanggalID(
|
||
formSurat.dataPelengkap.find(
|
||
(n: any) => n.key === item.key,
|
||
)?.value,
|
||
)
|
||
: parseTanggalID(item.value)
|
||
}
|
||
/>
|
||
) : (
|
||
<TextInput
|
||
error={errors[item.id]}
|
||
label={<FieldLabel label={item.name} hint={item.desc} required={item.required} />}
|
||
placeholder={item.name}
|
||
type={item.type}
|
||
onChange={(e) =>
|
||
validationForm({
|
||
kategori: "dataPelengkap",
|
||
value: {
|
||
id: item.id,
|
||
key: item.key,
|
||
value: e.target.value,
|
||
required: item.required,
|
||
},
|
||
})
|
||
}
|
||
value={
|
||
formSurat.dataPelengkap.find((n) => n.id === item.id)
|
||
?.value ??
|
||
dataPelengkap.find((n: any) => n.key == item.key)?.value
|
||
}
|
||
disabled={status != "ditolak" && status != "antrian"}
|
||
rightSection={
|
||
item.satuan != null &&
|
||
<Text mr={"lg"}>{item.satuan}</Text>
|
||
}
|
||
/>
|
||
)}
|
||
</Grid.Col>
|
||
))}
|
||
</Grid>
|
||
</FormSection>
|
||
|
||
<FormSection
|
||
title="Syarat Dokumen hjh"
|
||
description="Syarat dokumen yang diperlukan"
|
||
icon={<IconFiles size={16} />}
|
||
>
|
||
<Grid>
|
||
{dataSyaratDokumen.map((item: any, index: number) => (
|
||
<Grid.Col span={6} key={index}>
|
||
<FileInputWrapper
|
||
required={item.required}
|
||
label={item.desc}
|
||
placeholder={"Upload file terbaru untuk mengupdate"}
|
||
accept="image/*,application/pdf"
|
||
linkView={item.value}
|
||
onChange={(file) =>
|
||
validationForm({
|
||
kategori: "syaratDokumen",
|
||
value: { id: item.id, key: item.key, value: file, required: item.required },
|
||
})
|
||
}
|
||
name={item.name}
|
||
disabled={status != "ditolak" && status != "antrian"}
|
||
/>
|
||
</Grid.Col>
|
||
))}
|
||
</Grid>
|
||
</FormSection>
|
||
|
||
<Group justify="right" mt="md">
|
||
<Button
|
||
onClick={() => {
|
||
onChecking();
|
||
}}
|
||
disabled={status != "ditolak" && status != "antrian"}
|
||
>
|
||
Kirim
|
||
</Button>
|
||
</Group>
|
||
</>
|
||
)}
|
||
</>
|
||
);
|
||
}
|