diff --git a/src/components/ModalSurat.tsx b/src/components/ModalSurat.tsx index 1ca5374..cd07704 100644 --- a/src/components/ModalSurat.tsx +++ b/src/components/ModalSurat.tsx @@ -44,7 +44,6 @@ export default function ModalSurat({ open, onClose, surat }: { open: boolean, on const downloadPDF = async () => { const element = hiddenRef.current; - const canvas = await html2canvas(element, { scale: 2, useCORS: true, @@ -64,7 +63,7 @@ export default function ModalSurat({ open, onClose, surat }: { open: boolean, on pdf.addImage(imgData, "JPEG", 0, 0, imgWidth, imgHeight); - pdf.save("surat-keterangan-usaha.pdf"); + pdf.save(`${data?.data?.surat?.nameCategory}.pdf`); }; return ( diff --git a/src/components/surat/SKBedaBiodataDiri.tsx b/src/components/surat/SKBedaBiodataDiri.tsx index 2c0278d..641ec66 100644 --- a/src/components/surat/SKBedaBiodataDiri.tsx +++ b/src/components/surat/SKBedaBiodataDiri.tsx @@ -1,11 +1,42 @@ import _ from "lodash"; +import { useEffect, useState } from "react"; +import notification from "../notificationGlobal"; export default function SKBedaBiodataDiri({ data }: { data: any }) { + const [viewImg, setViewImg] = useState(); const getValue = (jenis: string) => _.upperFirst( data.surat.dataText.find((item: any) => item.jenis === jenis)?.value || "" ); + const loadImage = async () => { + try { + setViewImg(""); + if (!data.setting.perbekelTTD) return; + + const urlApi = '/api/pengaduan/image?folder=syarat-dokumen&fileName=' + data.setting.perbekelTTD; + // Fetch manual agar mendapatkan Response asli + const res = await fetch(urlApi); + if (!res.ok) + return notification({ + title: "Error", + message: "Failed to load image sign", + type: "error", + }); + const blob = await res.blob(); + const url = URL.createObjectURL(blob); + + setViewImg(url); + } catch (err) { + console.error("Gagal load gambar:", err); + } + }; + + useEffect(() => { + loadImage(); + }, [data]); + + return (
{/* HEADER */} @@ -113,13 +144,12 @@ export default function SKBedaBiodataDiri({ data }: { data: any }) {
{/* TANDA TANGAN */} -
+
- -

Kepala Desa / Lurah {data.setting.desaNama} -



- {data.setting.perbekelNama}
+

+ ttd perbekel
+ {data.setting.perbekelNama}
NIP. {data.setting.perbekelNIP}
diff --git a/src/components/surat/SKBelumKawin.tsx b/src/components/surat/SKBelumKawin.tsx index add1172..8b8f5b2 100644 --- a/src/components/surat/SKBelumKawin.tsx +++ b/src/components/surat/SKBelumKawin.tsx @@ -1,11 +1,41 @@ import _ from "lodash"; +import { useEffect, useState } from "react"; +import notification from "../notificationGlobal"; export default function SKBelumKawin({ data }: { data: any }) { + const [viewImg, setViewImg] = useState(); const getValue = (jenis: string) => _.upperFirst( data.surat.dataText.find((item: any) => item.jenis === jenis)?.value || "" ); + const loadImage = async () => { + try { + setViewImg(""); + if (!data.setting.perbekelTTD) return; + + const urlApi = '/api/pengaduan/image?folder=syarat-dokumen&fileName=' + data.setting.perbekelTTD; + // Fetch manual agar mendapatkan Response asli + const res = await fetch(urlApi); + if (!res.ok) + return notification({ + title: "Error", + message: "Failed to load image sign", + type: "error", + }); + const blob = await res.blob(); + const url = URL.createObjectURL(blob); + + setViewImg(url); + } catch (err) { + console.error("Gagal load gambar:", err); + } + }; + + useEffect(() => { + loadImage(); + }, [data]); + return (
{/* HEADER */} @@ -62,13 +92,14 @@ export default function SKBelumKawin({ data }: { data: any }) {


Pemohon -



+





{getValue("nama")}


Kepala Desa / Lurah {data.setting.desaNama} -



+

+ ttd perbekel
{data.setting.perbekelNama}
NIP. {data.setting.perbekelNIP}
diff --git a/src/components/surat/SKDomisiliOrganisasi.tsx b/src/components/surat/SKDomisiliOrganisasi.tsx index e4994ea..ea408eb 100644 --- a/src/components/surat/SKDomisiliOrganisasi.tsx +++ b/src/components/surat/SKDomisiliOrganisasi.tsx @@ -1,11 +1,41 @@ import _ from "lodash"; +import { useEffect, useState } from "react"; +import notification from "../notificationGlobal"; export default function SKDomisiliOrganisasi({ data }: { data: any }) { + const [viewImg, setViewImg] = useState(""); const getValue = (jenis: string) => _.upperFirst( data.surat.dataText.find((item: any) => item.jenis === jenis)?.value || "" ); + const loadImage = async () => { + try { + setViewImg(""); + if (!data.setting.perbekelTTD) return; + + const urlApi = '/api/pengaduan/image?folder=syarat-dokumen&fileName=' + data.setting.perbekelTTD; + // Fetch manual agar mendapatkan Response asli + const res = await fetch(urlApi); + if (!res.ok) + return notification({ + title: "Error", + message: "Failed to load image sign", + type: "error", + }); + const blob = await res.blob(); + const url = URL.createObjectURL(blob); + + setViewImg(url); + } catch (err) { + console.error("Gagal load gambar:", err); + } + }; + + useEffect(() => { + loadImage(); + }, [data]); + return (
{/* HEADER */} @@ -79,11 +109,11 @@ export default function SKDomisiliOrganisasi({ data }: { data: any }) { {/* TANDA TANGAN */}
- -

+
Kepala Desa / Lurah {data.setting.desaNama} -



- {data.setting.perbekelNama}
+

+ ttd perbekel
+ {data.setting.perbekelNama}
NIP. {data.setting.perbekelNIP}
diff --git a/src/components/surat/SKKelahiran.tsx b/src/components/surat/SKKelahiran.tsx index 08b58d3..d52cec3 100644 --- a/src/components/surat/SKKelahiran.tsx +++ b/src/components/surat/SKKelahiran.tsx @@ -1,11 +1,41 @@ import _ from "lodash"; +import { useEffect, useState } from "react"; +import notification from "../notificationGlobal"; export default function SKKelahiran({ data }: { data: any }) { + const [viewImg, setViewImg] = useState(""); const getValue = (jenis: string) => _.upperFirst( data.surat.dataText.find((item: any) => item.jenis === jenis)?.value || "" ); + const loadImage = async () => { + try { + setViewImg(""); + if (!data.setting.perbekelTTD) return; + + const urlApi = '/api/pengaduan/image?folder=syarat-dokumen&fileName=' + data.setting.perbekelTTD; + // Fetch manual agar mendapatkan Response asli + const res = await fetch(urlApi); + if (!res.ok) + return notification({ + title: "Error", + message: "Failed to load image sign", + type: "error", + }); + const blob = await res.blob(); + const url = URL.createObjectURL(blob); + + setViewImg(url); + } catch (err) { + console.error("Gagal load gambar:", err); + } + }; + + useEffect(() => { + loadImage(); + }, [data]); + return (
@@ -102,8 +132,9 @@ export default function SKKelahiran({ data }: { data: any }) {
Kepala Desa / Lurah {data.setting.desaNama} -



- {data.setting.perbekelNama}
+
+ ttd perbekel
+ {data.setting.perbekelNama}
NIP. {data.setting.perbekelNIP}
diff --git a/src/components/surat/SKKelakuanBaik.tsx b/src/components/surat/SKKelakuanBaik.tsx index 876e55c..faf4397 100644 --- a/src/components/surat/SKKelakuanBaik.tsx +++ b/src/components/surat/SKKelakuanBaik.tsx @@ -1,11 +1,41 @@ import _ from "lodash"; +import { useEffect, useState } from "react"; +import notification from "../notificationGlobal"; export default function SKKelakuanBaik({ data }: { data: any }) { + const [viewImg, setViewImg] = useState(""); const getValue = (jenis: string) => _.upperFirst( data.surat.dataText.find((item: any) => item.jenis === jenis)?.value || "" ); + const loadImage = async () => { + try { + setViewImg(""); + if (!data.setting.perbekelTTD) return; + + const urlApi = '/api/pengaduan/image?folder=syarat-dokumen&fileName=' + data.setting.perbekelTTD; + // Fetch manual agar mendapatkan Response asli + const res = await fetch(urlApi); + if (!res.ok) + return notification({ + title: "Error", + message: "Failed to load image sign", + type: "error", + }); + const blob = await res.blob(); + const url = URL.createObjectURL(blob); + + setViewImg(url); + } catch (err) { + console.error("Gagal load gambar:", err); + } + }; + + useEffect(() => { + loadImage(); + }, [data]); + return (
@@ -103,8 +133,9 @@ export default function SKKelakuanBaik({ data }: { data: any }) {
Kepala Desa {data.setting.desaNama} -



- {data.setting.perbekelNama}
+

+ ttd perbekel
+ {data.setting.perbekelNama}
NIP. {data.setting.perbekelNIP}
diff --git a/src/components/surat/SKKematian.tsx b/src/components/surat/SKKematian.tsx index eb5e37c..5f5ccc5 100644 --- a/src/components/surat/SKKematian.tsx +++ b/src/components/surat/SKKematian.tsx @@ -1,11 +1,41 @@ import _ from "lodash"; +import { useEffect, useState } from "react"; +import notification from "../notificationGlobal"; export default function SKKematian({ data }: { data: any }) { + const [viewImg, setViewImg] = useState(""); const getValue = (jenis: string) => _.upperFirst( data.surat.dataText.find((item: any) => item.jenis === jenis)?.value || "" ); + const loadImage = async () => { + try { + setViewImg(""); + if (!data.setting.perbekelTTD) return; + + const urlApi = '/api/pengaduan/image?folder=syarat-dokumen&fileName=' + data.setting.perbekelTTD; + // Fetch manual agar mendapatkan Response asli + const res = await fetch(urlApi); + if (!res.ok) + return notification({ + title: "Error", + message: "Failed to load image sign", + type: "error", + }); + const blob = await res.blob(); + const url = URL.createObjectURL(blob); + + setViewImg(url); + } catch (err) { + console.error("Gagal load gambar:", err); + } + }; + + useEffect(() => { + loadImage(); + }, [data]); + return (
{/* HEADER */} @@ -72,13 +102,14 @@ export default function SKKematian({ data }: { data: any }) {


Pemohon -



+




{getValue("nama")}
-

+
Kepala Desa / Lurah {data.setting.desaNama} -



+

+ ttd perbekel
{data.setting.perbekelNama}
NIP. {data.setting.perbekelNIP}
diff --git a/src/components/surat/SKPenghasilan.tsx b/src/components/surat/SKPenghasilan.tsx index d42eb6c..977fa34 100644 --- a/src/components/surat/SKPenghasilan.tsx +++ b/src/components/surat/SKPenghasilan.tsx @@ -1,11 +1,41 @@ import _ from "lodash"; +import { useEffect, useState } from "react"; +import notification from "../notificationGlobal"; export default function SKPenghasilan({ data }: { data: any }) { + const [viewImg, setViewImg] = useState(""); const getValue = (jenis: string) => _.upperFirst( data.surat.dataText.find((item: any) => item.jenis === jenis)?.value || "" ); + const loadImage = async () => { + try { + setViewImg(""); + if (!data.setting.perbekelTTD) return; + + const urlApi = '/api/pengaduan/image?folder=syarat-dokumen&fileName=' + data.setting.perbekelTTD; + // Fetch manual agar mendapatkan Response asli + const res = await fetch(urlApi); + if (!res.ok) + return notification({ + title: "Error", + message: "Failed to load image sign", + type: "error", + }); + const blob = await res.blob(); + const url = URL.createObjectURL(blob); + + setViewImg(url); + } catch (err) { + console.error("Gagal load gambar:", err); + } + }; + + useEffect(() => { + loadImage(); + }, [data]); + return (
{/* HEADER */} @@ -102,8 +132,9 @@ export default function SKPenghasilan({ data }: { data: any }) {
Kepala Desa / Lurah {data.setting.desaNama} -



- {data.setting.perbekelNama}
+

+ ttd perbekel
+ {data.setting.perbekelNama}
NIP. {data.setting.perbekelNIP}
diff --git a/src/components/surat/SKTempatUsaha.tsx b/src/components/surat/SKTempatUsaha.tsx index efae86f..e3c612f 100644 --- a/src/components/surat/SKTempatUsaha.tsx +++ b/src/components/surat/SKTempatUsaha.tsx @@ -1,9 +1,40 @@ import _ from "lodash"; +import { useEffect, useState } from "react"; +import notification from "../notificationGlobal"; export default function SKTempatUsaha({ data }: { data: any }) { + const [viewImg, setViewImg] = useState(""); const getValue = (key: string) => _.upperFirst(data.surat.dataText.find((i: any) => i.jenis === key)?.value || ""); + const loadImage = async () => { + try { + setViewImg(""); + if (!data.setting.perbekelTTD) return; + + const urlApi = '/api/pengaduan/image?folder=syarat-dokumen&fileName=' + data.setting.perbekelTTD; + // Fetch manual agar mendapatkan Response asli + const res = await fetch(urlApi); + if (!res.ok) + return notification({ + title: "Error", + message: "Failed to load image sign", + type: "error", + }); + const blob = await res.blob(); + const url = URL.createObjectURL(blob); + + setViewImg(url); + } catch (err) { + console.error("Gagal load gambar:", err); + } + }; + + useEffect(() => { + loadImage(); + }, [data]); + + return (
{/* TITLE */} @@ -68,8 +99,8 @@ export default function SKTempatUsaha({ data }: { data: any }) { {/* TANDA TANGAN */}
- {data.setting.desaNama}, {data.surat.createdAt}


- + {data.setting.desaKabupaten}, {data.surat.createdAt}

+ ttd perbekel
{data.setting.perbekelNama}
{data.setting.perbekelJabatan + " " + data.setting.desaNama}
diff --git a/src/components/surat/SKTidakMampu.tsx b/src/components/surat/SKTidakMampu.tsx index e0b62ba..ae074c8 100644 --- a/src/components/surat/SKTidakMampu.tsx +++ b/src/components/surat/SKTidakMampu.tsx @@ -1,9 +1,40 @@ import _ from "lodash"; +import { useEffect, useState } from "react"; +import notification from "../notificationGlobal"; export default function SKTidakMampu({ data }: { data: any }) { + const [viewImg, setViewImg] = useState(""); const getValue = (key: string) => _.upperFirst(data.surat.dataText.find((i: any) => i.jenis === key)?.value || ""); + + const loadImage = async () => { + try { + setViewImg(""); + if (!data.setting.perbekelTTD) return; + + const urlApi = '/api/pengaduan/image?folder=syarat-dokumen&fileName=' + data.setting.perbekelTTD; + // Fetch manual agar mendapatkan Response asli + const res = await fetch(urlApi); + if (!res.ok) + return notification({ + title: "Error", + message: "Failed to load image sign", + type: "error", + }); + const blob = await res.blob(); + const url = URL.createObjectURL(blob); + + setViewImg(url); + } catch (err) { + console.error("Gagal load gambar:", err); + } + }; + + useEffect(() => { + loadImage(); + }, [data]); + return (
{/* TITLE */} @@ -59,8 +90,8 @@ export default function SKTidakMampu({ data }: { data: any }) { {/* TANDA TANGAN */}
- {data.setting.desaNama}, {data.surat.createdAt}


- + {data.setting.desaKabupaten}, {data.surat.createdAt}

+ ttd perbekel
{data.setting.perbekelNama}
{data.setting.perbekelJabatan + " " + data.setting.desaNama}
diff --git a/src/components/surat/SKUsaha.tsx b/src/components/surat/SKUsaha.tsx index f1f6738..24f3874 100644 --- a/src/components/surat/SKUsaha.tsx +++ b/src/components/surat/SKUsaha.tsx @@ -132,13 +132,12 @@ export default function SKUsaha({ data }: { data: any }) {
{/* TANDA TANGAN */} -
+
- -

+
Kepala Desa / Lurah {data.setting.desaNama}

- ttd perbekel + ttd perbekel
{data.setting.perbekelNama}
NIP. {data.setting.perbekelNIP} diff --git a/src/components/surat/SKYatimPiatu.tsx b/src/components/surat/SKYatimPiatu.tsx index c80763b..299f913 100644 --- a/src/components/surat/SKYatimPiatu.tsx +++ b/src/components/surat/SKYatimPiatu.tsx @@ -1,10 +1,40 @@ +import { useShallowEffect } from "@mantine/hooks"; import _ from "lodash"; +import { useState } from "react"; +import notification from "../notificationGlobal"; export default function SKYatim({ data }: { data: any }) { - + const [viewImg, setViewImg] = useState(""); const getValue = (key: string) => _.upperFirst(data.surat.dataText.find((i: any) => i.jenis === key)?.value || ""); + const loadImage = async () => { + try { + setViewImg(""); + if (!data.setting.perbekelTTD) return; + + const urlApi = '/api/pengaduan/image?folder=syarat-dokumen&fileName=' + data.setting.perbekelTTD; + // Fetch manual agar mendapatkan Response asli + const res = await fetch(urlApi); + if (!res.ok) + return notification({ + title: "Error", + message: "Failed to load image sign", + type: "error", + }); + const blob = await res.blob(); + const url = URL.createObjectURL(blob); + + setViewImg(url); + } catch (err) { + console.error("Gagal load gambar:", err); + } + }; + + useShallowEffect(() => { + loadImage(); + }, [data]); + return (
@@ -146,14 +176,15 @@ export default function SKYatim({ data }: { data: any }) { -

+
{/* TTD */}
Kepala Desa {data.setting.desaNama} -



- {data.setting.perbekelNama}
+

+ ttd perbekel
+ {data.setting.perbekelNama}
NIP. {data.setting.perbekelNIP}
diff --git a/src/server/routes/surat_route.ts b/src/server/routes/surat_route.ts index 21eacb3..c688522 100644 --- a/src/server/routes/surat_route.ts +++ b/src/server/routes/surat_route.ts @@ -21,6 +21,11 @@ const SuratRoute = new Elysia({ select: { DataTextPelayanan: true, } + }, + CategoryPelayanan: { + select: { + name: true, + } } } }) @@ -37,6 +42,7 @@ const SuratRoute = new Elysia({ surat: { id: dataSurat?.id, idCategory: dataSurat?.idCategory, + nameCategory: dataSurat?.CategoryPelayanan?.name, noSurat: dataSurat?.noSurat, dataText: dataSurat?.PelayananAjuan?.DataTextPelayanan, createdAt: dataSurat?.createdAt.toLocaleDateString("id-ID", { day: "numeric", month: "long", year: "numeric" }), diff --git a/src/server/routes/warga_route.ts b/src/server/routes/warga_route.ts index d5324ed..507b143 100644 --- a/src/server/routes/warga_route.ts +++ b/src/server/routes/warga_route.ts @@ -62,8 +62,8 @@ const WargaRoute = new Elysia({ phone: t.String({ minLength: 1 }) }), detail: { - summary: "edit konfigurasi desa", - description: `tool untuk edit konfigurasi desa` + summary: "Edit Warga", + description: `tool untuk edit warga` } }) .get("/detail", async ({ query }) => {