Merge pull request 'amalia/14-jan-26' (#110) from amalia/14-jan-26 into main

Reviewed-on: http://wibugit.wibudev.com/wibu/jenna-mcp/pulls/110
This commit is contained in:
2026-01-14 17:43:11 +08:00
3 changed files with 90 additions and 61 deletions

View File

@@ -1,5 +1,5 @@
import apiFetch from "@/lib/apiFetch"; import apiFetch from "@/lib/apiFetch";
import { Flex, Loader, Modal, Text } from "@mantine/core"; import { Flex, Modal, Progress, Stack, Text } from "@mantine/core";
import { useShallowEffect } from "@mantine/hooks"; import { useShallowEffect } from "@mantine/hooks";
import html2canvas from "html2canvas"; import html2canvas from "html2canvas";
import jsPDF from "jspdf"; import jsPDF from "jspdf";
@@ -35,7 +35,7 @@ export default function ModalSurat({
fontSize: "14px", fontSize: "14px",
fontFamily: "Times New Roman", fontFamily: "Times New Roman",
}; };
const [uploading, setUploading] = useState<"Menyiapkan" | "Mengupload" | "Selesai">("Menyiapkan") const [uploading, setUploading] = useState<{ text: "Menyiapkan" | "Mengupload" | "Selesai", 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({
@@ -52,7 +52,7 @@ export default function ModalSurat({
const uploadPdf = async () => { const uploadPdf = async () => {
try { try {
if (data && data.data && data.data.surat && (data.data.surat.file == "" || data.data.surat.file == null)) { if (data && data.data && data.data.surat && (data.data.surat.file == "" || data.data.surat.file == null)) {
setUploading("Mengupload"); setUploading({ text: "Mengupload", value: 75 });
const element = hiddenRef.current; const element = hiddenRef.current;
const canvas = await html2canvas(element, { const canvas = await html2canvas(element, {
scale: 2, scale: 2,
@@ -95,7 +95,7 @@ export default function ModalSurat({
filename: resImg.data?.filename!, filename: resImg.data?.filename!,
}); });
setUploading("Selesai"); setUploading({ text: "Selesai", value: 100 });
setTimeout(() => { setTimeout(() => {
onClose(resUpdate.data?.link); onClose(resUpdate.data?.link);
}, 1000) }, 1000)
@@ -136,14 +136,24 @@ export default function ModalSurat({
}, },
}} }}
title={ title={
<Flex justify="space-between" align="center" w="100%"> <>
<div style={{ fontSize: 18, fontWeight: 600 }}>Preview Surat</div> <Flex justify="space-between" align="center" w="100%">
<div style={{ fontSize: 18, fontWeight: 600 }}>Preview Surat</div>
<Flex gap={8} align="center"> {/* <Flex gap={8} align="center">
<Loader color="blue" size="xs" /> <Loader color="blue" size="xs" />
<Text size="sm">{uploading}</Text> <Text size="sm">{uploading.text}</Text>
</Flex> */}
</Flex> </Flex>
</Flex> <Stack
align="stretch"
justify="center"
gap="xs"
>
<Text size="sm" ta="center">{uploading.text} - Harap menunggu sampai selesai</Text>
<Progress radius="md" value={uploading.value} animated size="lg" />
</Stack>
</>
} }
> >
<div ref={hiddenRef} style={A4Style}> <div ref={hiddenRef} style={A4Style}>

View File

@@ -317,57 +317,60 @@ function SearchData() {
} }
return ( return (
<FormSection <>
title="Cari Pengajuan Surat" <FullScreenLoading visible={submitLoading} text="Mencari Data" />
info="Masukkan nomor pengajuan dan nomor telepon yang digunakan saat pengajuan surat." <FormSection
> title="Cari Pengajuan Surat"
<Grid> info="Masukkan nomor pengajuan dan nomor telepon yang digunakan saat pengajuan surat."
<Grid.Col span={6}> >
<TextInput <Grid>
label={ <Grid.Col span={6}>
<FieldLabel <TextInput
label="Nomor Pengajuan" label={
hint="Nomor pengajuan surat" <FieldLabel
/> label="Nomor Pengajuan"
} hint="Nomor pengajuan surat"
placeholder="PS-2025-000123" />
onChange={(e) => { }
setSearchPengajuan(e.target.value); placeholder="PS-2025-000123"
}} onChange={(e) => {
/> setSearchPengajuan(e.target.value);
</Grid.Col> }}
/>
</Grid.Col>
<Grid.Col span={6}> <Grid.Col span={6}>
<TextInput <TextInput
label={ label={
<FieldLabel <FieldLabel
label="Nomor Telephone" label="Nomor Telephone"
hint="Nomor telephone yang dapat dihubungi / terhubung dengan whatsapp" hint="Nomor telephone yang dapat dihubungi / terhubung dengan whatsapp"
/> />
} }
placeholder="08123456789" placeholder="08123456789"
type="number" type="number"
onChange={(e) => { onChange={(e) => {
setSearchPengajuanPhone(e.target.value); setSearchPengajuanPhone(e.target.value);
}} }}
/> />
</Grid.Col> </Grid.Col>
<Grid.Col span={12}> <Grid.Col span={12}>
<Button <Button
fullWidth fullWidth
variant="light" variant="light"
color="blue" color="blue"
onClick={() => { onClick={() => {
handleSearch(); handleSearch();
}} }}
loading={submitLoading} loading={submitLoading}
> >
Cari Pengajuan Cari Pengajuan
</Button> </Button>
</Grid.Col> </Grid.Col>
</Grid> </Grid>
</FormSection> </FormSection>
</>
); );
} }
@@ -387,6 +390,7 @@ function DataUpdate({
const [dataSyaratDokumen, setDataSyaratDokumen] = useState<DataItem[]>([]); const [dataSyaratDokumen, setDataSyaratDokumen] = useState<DataItem[]>([]);
const [dataPengajuan, setDataPengajuan] = useState<DataPengajuan | {}>({}); const [dataPengajuan, setDataPengajuan] = useState<DataPengajuan | {}>({});
const [status, setStatus] = useState(""); const [status, setStatus] = useState("");
const [loadingFetchData, setLoadingFetchData] = useState(false);
const [formSurat, setFormSurat] = useState<FormUpdateSurat>({ const [formSurat, setFormSurat] = useState<FormUpdateSurat>({
dataPelengkap: [], dataPelengkap: [],
syaratDokumen: [], syaratDokumen: [],
@@ -394,6 +398,7 @@ function DataUpdate({
async function fetchData() { async function fetchData() {
try { try {
setLoadingFetchData(true);
const res = await apiFetch.api.pelayanan["detail-data"].post({ const res = await apiFetch.api.pelayanan["detail-data"].post({
nomerPengajuan: noPengajuan, nomerPengajuan: noPengajuan,
}); });
@@ -421,6 +426,8 @@ function DataUpdate({
} }
} catch (error) { } catch (error) {
console.error("Error fetching data:", error); console.error("Error fetching data:", error);
} finally {
setLoadingFetchData(false);
} }
} }
@@ -600,7 +607,7 @@ function DataUpdate({
return ( return (
<> <>
<FullScreenLoading visible={submitLoading} /> <FullScreenLoading visible={submitLoading || loadingFetchData} />
<Modal <Modal
opened={opened} opened={opened}
onClose={close} onClose={close}
@@ -667,6 +674,7 @@ function DataUpdate({
<Grid.Col span={6} key={index}> <Grid.Col span={6} key={index}>
{item.type == "enum" ? ( {item.type == "enum" ? (
<Select <Select
disabled={status != "ditolak" && status != "antrian"}
allowDeselect={false} allowDeselect={false}
label={<FieldLabel label={item.name} hint={item.desc} />} label={<FieldLabel label={item.name} hint={item.desc} />}
data={item.options ?? []} data={item.options ?? []}
@@ -686,6 +694,7 @@ function DataUpdate({
/> />
) : item.type == "date" ? ( ) : item.type == "date" ? (
<DateInput <DateInput
disabled={status != "ditolak" && status != "antrian"}
locale="id" locale="id"
valueFormat="DD MMMM YYYY" valueFormat="DD MMMM YYYY"
label={<FieldLabel label={item.name} hint={item.desc} />} label={<FieldLabel label={item.name} hint={item.desc} />}
@@ -712,7 +721,7 @@ function DataUpdate({
(n: any) => n.key === item.key, (n: any) => n.key === item.key,
)?.value, )?.value,
) )
: parseTanggalID(item.value) : parseTanggalID(item.value)
} }
/> />
) : ( ) : (

View File

@@ -1,4 +1,5 @@
import BreadCrumbs from "@/components/BreadCrumbs"; 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";
@@ -125,6 +126,7 @@ function DetailDataPengajuan({
const [editValue, setEditValue] = useState({ id: "", jenis: "", val: "", option: null as any, type: "", key: "" }) const [editValue, setEditValue] = useState({ id: "", jenis: "", val: "", option: null as any, type: "", key: "" })
const [openEdit, setOpenEdit] = useState(false) const [openEdit, setOpenEdit] = useState(false)
const [loadingUpdate, setLoadingUpdate] = useState(false) const [loadingUpdate, setLoadingUpdate] = useState(false)
const [loadingFS, setLoadingFS] = useState({ value: false, text: "" })
useEffect(() => { useEffect(() => {
async function fetchHost() { async function fetchHost() {
@@ -143,6 +145,7 @@ function DetailDataPengajuan({
async function sendWA({ status, linkSurat, linkUpdate }: { status: string, linkSurat: string, linkUpdate: string }) { async function sendWA({ status, linkSurat, linkUpdate }: { status: string, linkSurat: string, linkUpdate: string }) {
try { try {
setLoadingFS({ value: true, text: "Sending message to warga" })
const resWA = await apiFetch.api["send-wa"]["pengajuan-surat"].post({ const resWA = await apiFetch.api["send-wa"]["pengajuan-surat"].post({
noPengajuan: data?.noPengajuan ?? "", noPengajuan: data?.noPengajuan ?? "",
jenisSurat: data?.category ?? "", jenisSurat: data?.category ?? "",
@@ -181,10 +184,14 @@ function DetailDataPengajuan({
type: "error", type: "error",
}); });
} }
finally {
setLoadingFS({ value: false, text: "" })
}
} }
const handleKonfirmasi = async (cat: "terima" | "tolak") => { const handleKonfirmasi = async (cat: "terima" | "tolak") => {
try { try {
setLoadingFS({ value: true, text: "Updating status" })
const statusFix = cat == "tolak" const statusFix = cat == "tolak"
? "ditolak" ? "ditolak"
: data.status == "antrian" : data.status == "antrian"
@@ -234,6 +241,8 @@ function DetailDataPengajuan({
message: "Failed to update pengajuan surat", message: "Failed to update pengajuan surat",
type: "error", type: "error",
}); });
} finally {
setLoadingFS({ value: false, text: "" })
} }
}; };
@@ -275,7 +284,6 @@ function DetailDataPengajuan({
} }
useShallowEffect(() => { useShallowEffect(() => {
console.log('jalan', viewImg)
if (viewImg) { if (viewImg) {
setOpenedPreviewFile(true); setOpenedPreviewFile(true);
} }
@@ -308,6 +316,8 @@ function DetailDataPengajuan({
return ( return (
<> <>
<FullScreenLoading visible={loadingFS.value} text={loadingFS.text} />
{/* MODAL EDIT DATA PELENGKAP */} {/* MODAL EDIT DATA PELENGKAP */}
<Modal <Modal
opened={openEdit} opened={openEdit}