diff --git a/bak/ModalSurat.tsx.txt b/bak/ModalSurat.tsx.txt new file mode 100644 index 0000000..926aefc --- /dev/null +++ b/bak/ModalSurat.tsx.txt @@ -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(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 ( + <> + 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={ + +
Preview Surat
+ + + + + + + + + + +
+ } + > +
+ {data && data.data ? ( + data.data.surat.idCategory == "skusaha" ? ( + + ) : data.data.surat.idCategory == "skkelahiran" ? ( + + ) : data.data.surat.idCategory == "skkelakuanbaik" ? ( + + ) : data.data.surat.idCategory == "skpenghasilan" ? ( + + ) : data.data.surat.idCategory == "sktidakmampu" ? ( + + ) : data.data.surat.idCategory == "skyatimpiatu" ? ( + + ) : data.data.surat.idCategory == "skdomisiliorganisasi" ? ( + + ) : data.data.surat.idCategory == "skbedabiodata" ? ( + + ) : data.data.surat.idCategory == "sktempatusaha" ? ( + + ) : data.data.surat.idCategory == "skbelumkawin" ? ( + + ) : data.data.surat.idCategory == "skkematian" ? ( + + ) : ( + <> + ) + ) : ( + <> + )} +
+
+ + ); +} diff --git a/src/components/ModalSurat.tsx b/src/components/ModalSurat.tsx index 926aefc..2c32271 100644 --- a/src/components/ModalSurat.tsx +++ b/src/components/ModalSurat.tsx @@ -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(null); const { data, mutate, isLoading } = useSWR("surat", () => apiFetch.api.surat.detail.get({ @@ -49,29 +49,62 @@ export default function ModalSurat({ 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 uploadPdf = async () => { + try { + setUploading("Mengupload"); + 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 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 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; + const imgWidth = pageWidth; + const imgHeight = (canvas.height * pageWidth) / canvas.width; - pdf.addImage(imgData, "JPEG", 0, 0, imgWidth, imgHeight); + pdf.addImage(imgData, "JPEG", 0, 0, imgWidth, imgHeight); - pdf.save(`${data?.data?.surat?.nameCategory}.pdf`); - }; + // ⬇️ ambil sebagai Blob + const pdfBlob = pdf.output("blob"); + + const pdfFile = new File( + [pdfBlob], + `${data?.data?.surat?.nameCategory}.pdf`, + { + type: "application/pdf", + lastModified: Date.now(), + } + ); + + const resImg = await apiFetch.api.pengaduan.upload.post({ + file: pdfFile, + folder: "surat", + }); + + 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({
Preview Surat
- - - - - - - - + + + {uploading} } diff --git a/src/pages/scr/dashboard/pelayanan-surat/detail_pelayanan_page.tsx b/src/pages/scr/dashboard/pelayanan-surat/detail_pelayanan_page.tsx index c834e2f..f62ca0b 100644 --- a/src/pages/scr/dashboard/pelayanan-surat/detail_pelayanan_page.tsx +++ b/src/pages/scr/dashboard/pelayanan-surat/detail_pelayanan_page.tsx @@ -62,6 +62,7 @@ export default function DetailPengajuanPage() { { @@ -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([]); 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 statusFix = cat == "tolak" + ? "ditolak" + : data.status == "antrian" + ? "diterima" + : "selesai" + const res = await apiFetch.api.pelayanan["update-status"].post({ id: data?.id, - status: - cat == "tolak" - ? "ditolak" - : data.status == "antrian" - ? "diterima" - : "selesai", + 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 ( <> setOpenedPreview(false)} + onClose={() => { + setOpenedPreview(false) + setUploading(true) + }} surat={data?.idSurat} /> )} @@ -399,12 +473,12 @@ function DetailDataPengajuan({ ) : data?.status === "selesai" ? ( - + */} ) : ( <> diff --git a/src/server/lib/create-surat.ts b/src/server/lib/create-surat.ts index e595ec4..3b61a9b 100644 --- a/src/server/lib/create-surat.ts +++ b/src/server/lib/create-surat.ts @@ -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' } } diff --git a/src/server/routes/pelayanan_surat_route.ts b/src/server/routes/pelayanan_surat_route.ts index fad9a9e..f7e491d 100644 --- a/src/server/routes/pelayanan_surat_route.ts +++ b/src/server/routes/pelayanan_surat_route.ts @@ -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" }), diff --git a/src/server/routes/send_wa_route.ts b/src/server/routes/send_wa_route.ts index 16b2322..a0516ba 100644 --- a/src/server/routes/send_wa_route.ts +++ b/src/server/routes/send_wa_route.ts @@ -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