upd: pengajuan surat
Deskripsi: - send wa penolakan + lik update - send wa diterima - upload ke seafile - blm selesai ngirim link surat ke wa No Issues
This commit is contained in:
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>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,10 +1,9 @@
|
||||
import apiFetch from "@/lib/apiFetch";
|
||||
import { ActionIcon, Flex, Modal } from "@mantine/core";
|
||||
import { Flex, Loader, Modal, Text } 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 { useRef, useState } from "react";
|
||||
import useSWR from "swr";
|
||||
import SKBedaBiodataDiri from "./surat/SKBedaBiodataDiri";
|
||||
import SKBelumKawin from "./surat/SKBelumKawin";
|
||||
@@ -36,6 +35,7 @@ export default function ModalSurat({
|
||||
fontSize: "14px",
|
||||
fontFamily: "Times New Roman",
|
||||
};
|
||||
const [uploading, setUploading] = useState<"Menyiapkan" | "Mengupload" | "Selesai">("Menyiapkan")
|
||||
const hiddenRef = useRef<any>(null);
|
||||
const { data, mutate, isLoading } = useSWR("surat", () =>
|
||||
apiFetch.api.surat.detail.get({
|
||||
@@ -49,7 +49,9 @@ export default function ModalSurat({
|
||||
mutate();
|
||||
}, []);
|
||||
|
||||
const downloadPDF = async () => {
|
||||
const uploadPdf = async () => {
|
||||
try {
|
||||
setUploading("Mengupload");
|
||||
const element = hiddenRef.current;
|
||||
const canvas = await html2canvas(element, {
|
||||
scale: 2,
|
||||
@@ -70,8 +72,39 @@ export default function ModalSurat({
|
||||
|
||||
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",
|
||||
});
|
||||
|
||||
console.log(resImg.data)
|
||||
} catch (error) {
|
||||
console.error("Error uploading PDF:", error);
|
||||
} finally {
|
||||
setUploading("Selesai");
|
||||
setTimeout(() => {
|
||||
onClose();
|
||||
}, 1000)
|
||||
}
|
||||
}
|
||||
|
||||
useShallowEffect(() => {
|
||||
setTimeout(() => {
|
||||
uploadPdf();
|
||||
}, 5000);
|
||||
}, [surat]);
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -97,14 +130,9 @@ export default function ModalSurat({
|
||||
<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 gap={8} align="center">
|
||||
<Loader color="blue" size="xs" />
|
||||
<Text size="sm">{uploading}</Text>
|
||||
</Flex>
|
||||
</Flex>
|
||||
}
|
||||
|
||||
@@ -62,6 +62,7 @@ export default function DetailPengajuanPage() {
|
||||
<Stack gap={"xl"}>
|
||||
<DetailDataPengajuan
|
||||
data={data?.data?.pengajuan}
|
||||
warga={data && data.data && data.data.warga ? data.data.warga : undefined}
|
||||
syaratDokumen={data?.data?.syaratDokumen}
|
||||
dataText={data?.data?.dataText}
|
||||
onAction={() => {
|
||||
@@ -81,11 +82,13 @@ export default function DetailPengajuanPage() {
|
||||
|
||||
function DetailDataPengajuan({
|
||||
data,
|
||||
warga,
|
||||
syaratDokumen,
|
||||
dataText,
|
||||
onAction,
|
||||
}: {
|
||||
data: any;
|
||||
warga?: { phone?: string | null } | null;
|
||||
syaratDokumen: any;
|
||||
dataText: any;
|
||||
onAction: () => void;
|
||||
@@ -99,6 +102,7 @@ function DetailDataPengajuan({
|
||||
const [openedPreviewFile, setOpenedPreviewFile] = useState(false);
|
||||
const [permissions, setPermissions] = useState<JsonValue[]>([]);
|
||||
const [viewImg, setViewImg] = useState("");
|
||||
const [uploading, setUploading] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
async function fetchHost() {
|
||||
@@ -115,22 +119,78 @@ function DetailDataPengajuan({
|
||||
fetchHost();
|
||||
}, []);
|
||||
|
||||
async function sendWA({ status, linkSurat, linkUpdate }: { status: string, linkSurat: string, linkUpdate: string }) {
|
||||
try {
|
||||
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",
|
||||
});
|
||||
} 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",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const handleKonfirmasi = async (cat: "terima" | "tolak") => {
|
||||
try {
|
||||
const res = await apiFetch.api.pelayanan["update-status"].post({
|
||||
id: data?.id,
|
||||
status:
|
||||
cat == "tolak"
|
||||
const statusFix = cat == "tolak"
|
||||
? "ditolak"
|
||||
: data.status == "antrian"
|
||||
? "diterima"
|
||||
: "selesai",
|
||||
: "selesai"
|
||||
|
||||
const res = await apiFetch.api.pelayanan["update-status"].post({
|
||||
id: data?.id,
|
||||
status: statusFix,
|
||||
keterangan: keterangan,
|
||||
idUser: host?.id ?? "",
|
||||
noSurat: noSurat,
|
||||
});
|
||||
|
||||
if (res?.status === 200) {
|
||||
if (statusFix == "selesai") {
|
||||
setTimeout(() => {
|
||||
setOpenedPreview(true)
|
||||
}, 1000)
|
||||
} else {
|
||||
sendWA({
|
||||
status: statusFix,
|
||||
linkSurat: "",
|
||||
linkUpdate: statusFix == "ditolak" ? res.data?.linkUpdate ?? '' : '',
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
onAction();
|
||||
close();
|
||||
notification({
|
||||
@@ -161,6 +221,17 @@ function DetailDataPengajuan({
|
||||
}
|
||||
}, [viewImg]);
|
||||
|
||||
useShallowEffect(() => {
|
||||
if (uploading) {
|
||||
sendWA({
|
||||
status: "selesai",
|
||||
linkSurat: "",
|
||||
linkUpdate: "",
|
||||
});
|
||||
}
|
||||
}, [uploading]);
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<ModalFile
|
||||
@@ -244,7 +315,10 @@ function DetailDataPengajuan({
|
||||
{data?.status == "selesai" && (
|
||||
<ModalSurat
|
||||
open={openedPreview}
|
||||
onClose={() => setOpenedPreview(false)}
|
||||
onClose={() => {
|
||||
setOpenedPreview(false)
|
||||
setUploading(true)
|
||||
}}
|
||||
surat={data?.idSurat}
|
||||
/>
|
||||
)}
|
||||
@@ -399,12 +473,12 @@ function DetailDataPengajuan({
|
||||
</Group>
|
||||
) : data?.status === "selesai" ? (
|
||||
<Group justify="center" grow>
|
||||
<Button
|
||||
{/* <Button
|
||||
variant="light"
|
||||
onClick={() => setOpenedPreview(!openedPreview)}
|
||||
>
|
||||
Surat
|
||||
</Button>
|
||||
</Button> */}
|
||||
</Group>
|
||||
) : (
|
||||
<></>
|
||||
|
||||
@@ -8,16 +8,19 @@ export async function createSurat({ idPengajuan, idCategory, idWarga, noSurat }:
|
||||
idCategory,
|
||||
idWarga,
|
||||
noSurat,
|
||||
},
|
||||
select: {
|
||||
id: true
|
||||
}
|
||||
})
|
||||
|
||||
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) {
|
||||
console.log(error)
|
||||
console.error(error)
|
||||
return { success: false, message: 'gagal membuat surat' }
|
||||
}
|
||||
|
||||
|
||||
@@ -834,9 +834,14 @@ const PelayananRoute = new Elysia({
|
||||
})
|
||||
|
||||
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") {
|
||||
deskripsi = "Pengajuan surat diterima"
|
||||
} else if (status === "ditolak") {
|
||||
@@ -855,11 +860,19 @@ const PelayananRoute = new Elysia({
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
let idSurat = "";
|
||||
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({
|
||||
id: t.String({ minLength: 1, error: "id harus diisi" }),
|
||||
|
||||
@@ -76,6 +76,78 @@ Terima kasih atas partisipasi dan kepercayaan Bapak/Ibu.`
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user