diff --git a/prisma/schema.prisma b/prisma/schema.prisma
index d64f11e..6f75b42 100644
--- a/prisma/schema.prisma
+++ b/prisma/schema.prisma
@@ -187,6 +187,7 @@ model SuratPelayanan {
Warga Warga @relation(fields: [idWarga], references: [id])
idWarga String
noSurat String
+ file String?
dateExpired DateTime? @db.Date
status Int @default(0)
isActive Boolean @default(true)
diff --git a/src/components/ModalSurat.tsx b/src/components/ModalSurat.tsx
index 2c32271..84284c4 100644
--- a/src/components/ModalSurat.tsx
+++ b/src/components/ModalSurat.tsx
@@ -23,7 +23,7 @@ export default function ModalSurat({
surat,
}: {
open: boolean;
- onClose: () => void;
+ onClose: (val: any) => void;
surat: string;
}) {
const A4Style = {
@@ -51,69 +51,78 @@ export default function ModalSurat({
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,
- });
+ if (data && data.data && data.data.surat && (data.data.surat.file == "" || data.data.surat.file == null)) {
+ 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);
- // ⬇️ ambil sebagai Blob
- const pdfBlob = pdf.output("blob");
+ // ⬇️ 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 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",
- });
+ const resImg = await apiFetch.api.pengaduan.upload.post({
+ file: pdfFile,
+ folder: "surat",
+ });
+
+ const resUpdate = await apiFetch.api.surat.update.post({
+ id: surat,
+ filename: resImg.data?.filename!,
+ });
+
+ setUploading("Selesai");
+ setTimeout(() => {
+ onClose(resUpdate.data?.link);
+ }, 1000)
+ }
- console.log(resImg.data)
} catch (error) {
console.error("Error uploading PDF:", error);
- } finally {
- setUploading("Selesai");
- setTimeout(() => {
- onClose();
- }, 1000)
}
}
useShallowEffect(() => {
- setTimeout(() => {
- uploadPdf();
- }, 5000);
- }, [surat]);
+ if (open) {
+ setTimeout(() => {
+ uploadPdf();
+ }, 5000);
+ }
+ }, [surat, open]);
return (
<>
onClose()}
+ onClose={() => { }}
overlayProps={{ backgroundOpacity: 0.55, blur: 3 }}
size="auto"
withCloseButton={false}
+ closeOnClickOutside={false}
removeScrollProps={{ allowPinchZoom: true }}
styles={{
header: {
diff --git a/src/pages/darmasaba/surat.tsx b/src/pages/darmasaba/surat.tsx
index 66223e2..78d9ac0 100644
--- a/src/pages/darmasaba/surat.tsx
+++ b/src/pages/darmasaba/surat.tsx
@@ -324,6 +324,7 @@ export default function FormSurat() {
- {data?.status == "selesai" && (
+ {data?.status == "selesai" && !data?.fileSurat && (
{
+ onClose={(val) => {
setOpenedPreview(false)
- setUploading(true)
+ setUploading({ ok: true, file: val })
}}
surat={data?.idSurat}
/>
@@ -386,7 +386,7 @@ function DetailDataPengajuan({
{
- setViewImg(v.value);
+ setViewImg({ file: v.value, folder: "syarat-dokumen" });
}}
>
{v.jenis}
@@ -473,12 +473,12 @@ function DetailDataPengajuan({
) : data?.status === "selesai" ? (
- {/* */}
+
) : (
<>>
diff --git a/src/server/lib/seafile.ts b/src/server/lib/seafile.ts
index 4343e13..4f14302 100644
--- a/src/server/lib/seafile.ts
+++ b/src/server/lib/seafile.ts
@@ -248,14 +248,23 @@ export async function moveFile(config: Config, oldName: string, newName: string)
return `✏️ Renamed ${oldName} → ${newName}`
}
-export async function downloadFile(config: Config, remoteFile: string, localFile?: string): Promise {
- const localName = localFile || remoteFile;
- const downloadUrlResponse = await fetchWithAuth(config, `${config.URL}/${config.REPO}/file/?p=/${remoteFile}`);
- const downloadUrl = (await downloadUrlResponse.text()).replace(/"/g, '');
+export async function downloadFile(config: Config, fileName: string, folder: string, localFile?: string): Promise {
+ const localName = localFile || fileName;
+ // 🔹 gabungkan path folder + file
+ const filePath = `/${folder}/${fileName}`.replace(/\/+/g, "/");
+ // 🔹 encode path agar aman (spasi, dll)
+ const params = new URLSearchParams({
+ p: filePath,
+ });
+
+ const downloadUrlResponse = await fetchWithAuth(config, `${config.URL}/${config.REPO}/file/?${params.toString()}`);
+ if(!downloadUrlResponse.ok)
+ return 'gagal'
+ const downloadUrl = (await downloadUrlResponse.text()).replace(/"/g, '');
const buffer = Buffer.from(await (await fetchWithAuth(config, downloadUrl)).arrayBuffer());
await fs.writeFile(localName, buffer);
- return `⬇️ Downloaded ${remoteFile} → ${localName}`
+ return `⬇️ Downloaded ${fileName} → ${localName}`
}
export async function getFileLink(config: Config, fileName: string): Promise {
diff --git a/src/server/routes/pelayanan_surat_route.ts b/src/server/routes/pelayanan_surat_route.ts
index f7e491d..ba60a01 100644
--- a/src/server/routes/pelayanan_surat_route.ts
+++ b/src/server/routes/pelayanan_surat_route.ts
@@ -265,6 +265,7 @@ const PelayananRoute = new Elysia({
select: {
id: true,
idCategory: true,
+ file: true
}
})
@@ -381,6 +382,7 @@ const PelayananRoute = new Elysia({
createdAt: data?.createdAt,
updatedAt: data?.updatedAt,
idSurat: dataSurat?.id,
+ fileSurat: dataSurat?.file,
}
const datafix = {
diff --git a/src/server/routes/pengaduan_route.ts b/src/server/routes/pengaduan_route.ts
index 8fb9ade..6e1146d 100644
--- a/src/server/routes/pengaduan_route.ts
+++ b/src/server/routes/pengaduan_route.ts
@@ -1,14 +1,16 @@
-import Elysia, { t } from "elysia"
-import type { StatusPengaduan } from "generated/prisma"
-import _ from "lodash"
-import { v4 as uuidv4 } from "uuid"
-import { getLastUpdated } from "../lib/get-last-updated"
-import { mimeToExtension } from "../lib/mimetypeToExtension"
-import { generateNoPengaduan } from "../lib/no-pengaduan"
-import { isValidPhone, normalizePhoneNumber } from "../lib/normalizePhone"
-import { prisma } from "../lib/prisma"
-import { renameFile } from "../lib/rename-file"
-import { catFile, defaultConfigSF, removeFile, uploadFile, uploadFileToFolder } from "../lib/seafile"
+import Elysia, { t } from "elysia";
+import fs from 'fs';
+import type { StatusPengaduan } from "generated/prisma";
+import _ from "lodash";
+import path from "path";
+import { v4 as uuidv4 } from "uuid";
+import { getLastUpdated } from "../lib/get-last-updated";
+import { mimeToExtension } from "../lib/mimetypeToExtension";
+import { generateNoPengaduan } from "../lib/no-pengaduan";
+import { isValidPhone, normalizePhoneNumber } from "../lib/normalizePhone";
+import { prisma } from "../lib/prisma";
+import { renameFile } from "../lib/rename-file";
+import { catFile, defaultConfigSF, downloadFile, removeFile, uploadFile, uploadFileToFolder } from "../lib/seafile";
const PengaduanRoute = new Elysia({
prefix: "pengaduan",
@@ -605,6 +607,43 @@ const PengaduanRoute = new Elysia({
consumes: ["multipart/form-data"]
},
})
+ .get("/download", async ({ query, set }) => {
+ const { file, folder } = query;
+
+ // Validasi file
+ if (!file) {
+ return { success: false, message: "File tidak ditemukan" };
+ }
+
+ // if (!folder) {
+ // return { success: false, message: "Folder tidak ditemukan" };
+ // }
+
+ const localPath = path.join("/tmp", file);
+
+ // Upload ke Seafile (pastikan uploadFile menerima Blob atau ArrayBuffer)
+ // const buffer = await file.arrayBuffer();
+ const result = await downloadFile(defaultConfigSF, file, 'surat', localPath);
+
+ if(result=="gagal") {
+ return { success: false, message: "Download gagal" };
+ }
+
+ set.headers["Content-Type"] = "application/pdf";
+ set.headers["Content-Disposition"] = `attachment; filename="${file}"`;
+
+ // 🔹 kirim file ke browser
+ return fs.createReadStream(localPath);
+ }, {
+ body: t.Object({
+ file: t.Any(),
+ folder: t.String(),
+ }),
+ detail: {
+ summary: "Download Surat",
+ description: "Tool untuk download surat dari Seafile",
+ },
+ })
.post("/upload-file-form-data", async ({ body }) => {
const { file } = body;
diff --git a/src/server/routes/surat_route.ts b/src/server/routes/surat_route.ts
index c688522..f5e6f64 100644
--- a/src/server/routes/surat_route.ts
+++ b/src/server/routes/surat_route.ts
@@ -17,6 +17,7 @@ const SuratRoute = new Elysia({
noSurat: true,
idCategory: true,
createdAt: true,
+ file: true,
PelayananAjuan: {
select: {
DataTextPelayanan: true,
@@ -44,6 +45,7 @@ const SuratRoute = new Elysia({
idCategory: dataSurat?.idCategory,
nameCategory: dataSurat?.CategoryPelayanan?.name,
noSurat: dataSurat?.noSurat,
+ file: dataSurat?.file,
dataText: dataSurat?.PelayananAjuan?.DataTextPelayanan,
createdAt: dataSurat?.createdAt.toLocaleDateString("id-ID", { day: "numeric", month: "long", year: "numeric" }),
},
@@ -60,6 +62,33 @@ const SuratRoute = new Elysia({
}
})
+ .post("/update", async ({ body }) => {
+ const { id, filename } = body
+
+ await prisma.suratPelayanan.update({
+ where: {
+ id,
+ },
+ data: {
+ file: filename,
+ }
+ })
+
+ return {
+ success: true,
+ message: 'surat sudah diperbarui',
+ link: `${process.env.BUN_PUBLIC_BASE_URL}/api/pengaduan/download?file=${filename}`
+ }
+ }, {
+ body: t.Object({
+ id: t.String({ minLength: 1, error: "id harus diisi" }),
+ filename: t.String({ minLength: 1, error: "filename harus diisi" }),
+ }),
+ detail: {
+ summary: "update file surat",
+ description: `tool untuk update file surat`
+ }
+ })
;
export default SuratRoute