diff --git a/bun.lock b/bun.lock old mode 100755 new mode 100644 index fc8ef387..348ae19e --- a/bun.lock +++ b/bun.lock @@ -1,5 +1,5 @@ { - "lockfileVersion": 0, + "lockfileVersion": 1, "workspaces": { "": { "dependencies": { @@ -58,6 +58,8 @@ "next-dev": "^1.1.9", "next-scroll-loader": "^1.0.9", "p-limit": "^6.2.0", + "pdf-lib": "^1.17.1", + "pdf2pic": "^3.1.3", "pdfjs-dist": "^4.6.82", "postcss": "8.4.27", "prisma": "^6.3.0", @@ -717,6 +719,10 @@ "@oven/bun-windows-x64-baseline": ["@oven/bun-windows-x64-baseline@1.2.2", "", { "os": "win32", "cpu": "x64" }, "sha512-bYopMWSCjjjCKjANv7xxAXQoabVUxLZxTw0iC1bGYD9VZGo48nGaJXPn7DsPfeCXGyl+CY3Cy4QIEn+3gNRS2A=="], + "@pdf-lib/standard-fonts": ["@pdf-lib/standard-fonts@1.0.0", "", { "dependencies": { "pako": "^1.0.6" } }, "sha512-hU30BK9IUN/su0Mn9VdlVKsWBS6GyhVfqjwl1FjZN4TxP6cCw0jP2w7V3Hf5uX7M0AZJ16vey9yE0ny7Sa59ZA=="], + + "@pdf-lib/upng": ["@pdf-lib/upng@1.0.1", "", { "dependencies": { "pako": "^1.0.10" } }, "sha512-dQK2FUMQtowVP00mtIksrlZhdFXQZPC+taih1q4CvPZ5vqdxR/LKBaFg0oAfzd1GlHZXXSPdQfzQnt+ViGvEIQ=="], + "@peculiar/asn1-schema": ["@peculiar/asn1-schema@2.3.15", "", { "dependencies": { "asn1js": "^3.0.5", "pvtsutils": "^1.3.6", "tslib": "^2.8.1" } }, "sha512-QPeD8UA8axQREpgR5UTAfu2mqQmm97oUqahDtNdBcfj3qAnoXzFdQW+aNf/tD2WVXF8Fhmftxoj0eMIT++gX2w=="], "@peculiar/json-schema": ["@peculiar/json-schema@1.1.12", "", { "dependencies": { "tslib": "^2.0.0" } }, "sha512-coUfuoMeIB7B8/NMekxaDzLhaYmp0HZNPEjYRm9goRou8UZIC3z21s0sL9AWoCw4EG876QyO3kYrc61WNF9B/w=="], @@ -1151,6 +1157,10 @@ "array-includes": ["array-includes@3.1.8", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-abstract": "^1.23.2", "es-object-atoms": "^1.0.0", "get-intrinsic": "^1.2.4", "is-string": "^1.0.7" } }, "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ=="], + "array-parallel": ["array-parallel@0.1.3", "", {}, "sha512-TDPTwSWW5E4oiFiKmz6RGJ/a80Y91GuLgUYuLd49+XBS75tYo8PNgaT2K/OxuQYqkoI852MDGBorg9OcUSTQ8w=="], + + "array-series": ["array-series@0.1.5", "", {}, "sha512-L0XlBwfx9QetHOsbLDrE/vh2t018w9462HM3iaFfxRiK83aJjAt/Ja3NMkOW7FICwWTlQBa3ZbL5FKhuQWkDrg=="], + "array-union": ["array-union@2.1.0", "", {}, "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw=="], "array.prototype.findlast": ["array.prototype.findlast@1.2.5", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-abstract": "^1.23.2", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "es-shim-unscopables": "^1.0.2" } }, "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ=="], @@ -1815,6 +1825,8 @@ "globby": ["globby@11.1.0", "", { "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", "fast-glob": "^3.2.9", "ignore": "^5.2.0", "merge2": "^1.4.1", "slash": "^3.0.0" } }, "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g=="], + "gm": ["gm@1.25.1", "", { "dependencies": { "array-parallel": "~0.1.3", "array-series": "~0.1.5", "cross-spawn": "^7.0.5", "debug": "^3.1.0" } }, "sha512-jgcs2vKir9hFogGhXIfs0ODhJTfIrbECCehg38tqFgHm8zqXx7kAJyCYAFK4jTjx71AxrkFtkJBawbAxYUPX9A=="], + "gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="], "gpt-3-encoder": ["gpt-3-encoder@1.1.4", "", {}, "sha512-fSQRePV+HUAhCn7+7HL7lNIXNm6eaFWFbNLOOGtmSJ0qJycyQvj60OvRlH7mee8xAMjBDNRdMXlMwjAbMTDjkg=="], @@ -2457,6 +2469,10 @@ "pbf": ["pbf@3.3.0", "", { "dependencies": { "ieee754": "^1.1.12", "resolve-protobuf-schema": "^2.1.0" }, "bin": { "pbf": "bin/pbf" } }, "sha512-XDF38WCH3z5OV/OVa8GKUNtLAyneuzbCisx7QUCF8Q6Nutx0WnJrQe5O+kOtBlLfRNUws98Y58Lblp+NJG5T4Q=="], + "pdf-lib": ["pdf-lib@1.17.1", "", { "dependencies": { "@pdf-lib/standard-fonts": "^1.0.0", "@pdf-lib/upng": "^1.0.1", "pako": "^1.0.11", "tslib": "^1.11.1" } }, "sha512-V/mpyJAoTsN4cnP31vc0wfNA1+p20evqqnap0KLoRUN0Yk/p3wN52DOEsL4oBFcLdb76hlpKPtzJIgo67j/XLw=="], + + "pdf2pic": ["pdf2pic@3.1.3", "", { "dependencies": { "gm": "^1.25.0" } }, "sha512-KbW4Qb7iHw2fBRWtA9FTc4pZg9cokiFIzc6cE7dzelTrhXWolfQuG1fYVC0E2BRmK/w7xfBjQ+OEsPZPO3QEew=="], + "pdfjs-dist": ["pdfjs-dist@4.10.38", "", { "optionalDependencies": { "@napi-rs/canvas": "^0.1.65" } }, "sha512-/Y3fcFrXEAsMjJXeL9J8+ZG9U01LbuWaYypvDW2ycW1jL269L3js3DVBjDJ0Up9Np1uqDXsDrRihHANhZOlwdQ=="], "peerjs": ["peerjs@1.5.4", "", { "dependencies": { "@msgpack/msgpack": "^2.8.0", "eventemitter3": "^4.0.7", "peerjs-js-binarypack": "^2.1.0", "webrtc-adapter": "^9.0.0" } }, "sha512-yFsoLMnurJKlQbx6kVSBpOp+AlNldY1JQS2BrSsHLKCZnq6t7saHleuHM5svuLNbQkUJXHLF3sKOJB1K0xulOw=="], @@ -3467,6 +3483,8 @@ "formdata-node/web-streams-polyfill": ["web-streams-polyfill@4.0.0-beta.3", "", {}, "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug=="], + "gm/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="], + "has-ansi/ansi-regex": ["ansi-regex@2.1.1", "", {}, "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA=="], "html-tokenize/readable-stream": ["readable-stream@1.0.34", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.1", "isarray": "0.0.1", "string_decoder": "~0.10.x" } }, "sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg=="], @@ -3555,6 +3573,8 @@ "password-prompt/ansi-escapes": ["ansi-escapes@4.3.2", "", { "dependencies": { "type-fest": "^0.21.3" } }, "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ=="], + "pdf-lib/tslib": ["tslib@1.14.1", "", {}, "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="], + "peerjs/eventemitter3": ["eventemitter3@4.0.7", "", {}, "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="], "pkg-dir/find-up": ["find-up@3.0.0", "", { "dependencies": { "locate-path": "^3.0.0" } }, "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg=="], diff --git a/logs/backend/.31d2357fa2026a78b8cb786880c7c733460d7dbe-audit.json b/logs/backend/.31d2357fa2026a78b8cb786880c7c733460d7dbe-audit.json index 877fc566..aea69c9f 100644 --- a/logs/backend/.31d2357fa2026a78b8cb786880c7c733460d7dbe-audit.json +++ b/logs/backend/.31d2357fa2026a78b8cb786880c7c733460d7dbe-audit.json @@ -5,11 +5,6 @@ }, "auditLog": "logs/backend/.31d2357fa2026a78b8cb786880c7c733460d7dbe-audit.json", "files": [ - { - "date": 1739242050497, - "name": "logs/backend/combined-2025-02-11.log", - "hash": "13ef770bd22a1c0c4412156ffbf32e0a38fa2d61caa14054dc71d579374e8f56" - }, { "date": 1739327386336, "name": "logs/backend/combined-2025-02-12.log", @@ -64,6 +59,11 @@ "date": 1740450562875, "name": "logs/backend/combined-2025-02-25.log", "hash": "1ab2165b4d456ebed03006c88d9ce4b4f7be61bd38246e306fecbc73f72f8fdd" + }, + { + "date": 1740536165848, + "name": "logs/backend/combined-2025-02-26.log", + "hash": "428aedb3a3a248ad2c7069fcb8c6e0d669c23eae0dc3db08914886cce8d2cad9" } ], "hashType": "sha256" diff --git a/logs/backend/.5d9a990e0c6075347623def466341a14f8ba4a12-audit.json b/logs/backend/.5d9a990e0c6075347623def466341a14f8ba4a12-audit.json index b805d8d1..8b75d721 100644 --- a/logs/backend/.5d9a990e0c6075347623def466341a14f8ba4a12-audit.json +++ b/logs/backend/.5d9a990e0c6075347623def466341a14f8ba4a12-audit.json @@ -5,11 +5,6 @@ }, "auditLog": "logs/backend/.5d9a990e0c6075347623def466341a14f8ba4a12-audit.json", "files": [ - { - "date": 1739242050493, - "name": "logs/backend/error-2025-02-11.log", - "hash": "a346dd5f2327d9f40439c851473199450ec0918d7f0bd4b280343540a0b5ccb0" - }, { "date": 1739327386330, "name": "logs/backend/error-2025-02-12.log", @@ -64,6 +59,11 @@ "date": 1740450562872, "name": "logs/backend/error-2025-02-25.log", "hash": "189996570b83d8dbc20aac1eaf0583edf1472e1d1ac0dc83be0fb9b20a20ee07" + }, + { + "date": 1740536165843, + "name": "logs/backend/error-2025-02-26.log", + "hash": "fc1b904017c0517b4aa4138d2edb5dd58474ef723a17cab177d0605026a23c11" } ], "hashType": "sha256" diff --git a/package.json b/package.json index 5d92a2a6..c6651c3e 100644 --- a/package.json +++ b/package.json @@ -70,6 +70,8 @@ "next-dev": "^1.1.9", "next-scroll-loader": "^1.0.9", "p-limit": "^6.2.0", + "pdf-lib": "^1.17.1", + "pdf2pic": "^3.1.3", "pdfjs-dist": "^4.6.82", "postcss": "8.4.27", "prisma": "^6.3.0", diff --git a/src/app/api/pdf-to-image/route.ts b/src/app/api/pdf-to-image/route.ts new file mode 100644 index 00000000..26274157 --- /dev/null +++ b/src/app/api/pdf-to-image/route.ts @@ -0,0 +1,283 @@ +// // app/api/pdf-to-image/route.ts +import { execSync } from 'child_process'; +import { NextResponse } from 'next/server'; +import { PDFDocument } from 'pdf-lib'; +import { fromBuffer } from 'pdf2pic'; + +// // Tambahkan custom error +// class PDFConversionError extends Error { +// constructor(message: string, public statusCode: number = 500) { +// super(message); +// this.name = 'PDFConversionError'; +// } +// } + +// // Improve fungsi check dependencies +// async function checkDependencies() { +// const dependencies = [ +// { cmd: 'gm version', name: 'GraphicsMagick' }, +// { cmd: 'gs --version', name: 'Ghostscript' } +// ]; + +// for (const dep of dependencies) { +// try { +// execSync(dep.cmd); +// } catch (error) { +// throw new PDFConversionError(`${dep.name} tidak terinstall`, 500); +// } +// } +// } + +// // Tambah konstanta +// const MAX_PDF_SIZE_MB = 50; +// const MAX_IMAGE_DIMENSION = 2000; +// const CONVERSION_TIMEOUT_MS = 30000; +// const MAX_PAGES = 10; // Batasan jumlah halaman +// const DEFAULT_PAGE = 1; + +// // Modifikasi validateParams +// function validateParams(pdfUrl: string | null, pages: number[]) { +// if (!pdfUrl) { +// throw new PDFConversionError('URL parameter wajib diisi', 400); +// } +// if (pages.some(p => p < 1)) { +// throw new PDFConversionError('Nomor halaman tidak valid', 400); +// } +// if (pages.length > MAX_PAGES) { +// throw new PDFConversionError(`Maksimal ${MAX_PAGES} halaman per request`, 400); +// } +// } + +// interface ConversionResult { +// buffer: Buffer; +// text: string; +// density: number; +// width: number; +// height: number; +// } + +// // Fungsi untuk validasi dan fetch PDF +// async function fetchPDF(url: string) { +// const controller = new AbortController(); +// const timeout = setTimeout(() => controller.abort(), 10000); + +// try { +// // Validasi URL +// const validUrl = new URL(url); +// if (!validUrl.protocol.startsWith('http')) { +// throw new PDFConversionError('URL tidak valid', 400); +// } + +// const response = await fetch(url, { +// signal: controller.signal, +// headers: { +// 'Accept': 'application/pdf', +// 'User-Agent': 'Mozilla/5.0 (compatible; PDFConverter/1.0)' +// } +// }); + +// if (!response.ok) { +// throw new PDFConversionError( +// `Gagal mengakses PDF: ${response.status} ${response.statusText}`, +// response.status +// ); +// } + +// const contentType = response.headers.get('content-type'); +// if (!contentType?.includes('pdf')) { +// throw new PDFConversionError('URL bukan file PDF', 400); +// } + +// return response; + +// } catch (error: unknown) { +// if (error instanceof PDFConversionError) throw error; +// if (error instanceof Error && error.name === 'AbortError') { +// throw new PDFConversionError('Timeout saat mengunduh PDF', 504); +// } +// const message = error instanceof Error ? error.message : 'Unknown error'; +// throw new PDFConversionError('Gagal mengunduh PDF: ' + message, 500); +// } finally { +// clearTimeout(timeout); +// } +// } + +// // Tambahkan error SVG template +// const errorImageSvg = ` +// +// +// +// +// +// PDF Conversion Failed +// +// `; + +// // Tambahkan SVG untuk end of page +// const endOfPageSvg = ` +// +// +// +// End of PDF +// +// +// No more pages available +// +// +// `; + +// // Fungsi helper untuk set common headers +// function setCommonHeaders(headers: Headers) { +// headers.set('Access-Control-Allow-Origin', '*'); +// headers.set('Access-Control-Allow-Methods', 'GET, OPTIONS'); +// headers.set('Content-Security-Policy', "default-src 'self'; img-src 'self' data: blob:;"); +// headers.set('X-Content-Type-Options', 'nosniff'); +// } + +// // Fungsi helper untuk return error image +// function returnErrorImage(message: string = 'Conversion failed') { +// const response = new NextResponse(errorImageSvg, { +// headers: { +// 'Content-Type': 'image/svg+xml', +// 'Cache-Control': 'no-store', +// 'X-Error-Message': message +// } +// }); +// setCommonHeaders(response.headers); +// return response; +// } + +// // Fungsi helper untuk return end of page image +// function returnEndOfPageImage() { +// const response = new NextResponse(endOfPageSvg, { +// headers: { +// 'Content-Type': 'image/svg+xml', +// 'Cache-Control': 'public, max-age=31536000', +// 'X-Error-Message': 'End of PDF pages' +// } +// }); +// setCommonHeaders(response.headers); +// return response; +// } + +// // Fungsi untuk get total pages menggunakan pdf-lib +// async function getPDFPageCount(buffer: Buffer): Promise { +// try { +// const pdfDoc = await PDFDocument.load(buffer); +// return pdfDoc.getPageCount(); +// } catch (error) { +// console.error('Error getting PDF page count:', error); +// throw new Error('Failed to get PDF page count'); +// } +// } + +// export async function GET(request: Request) { +// let pdfBuffer: Buffer | null = null; +// const { searchParams } = new URL(request.url); + +// try { +// // Validasi parameter wajib +// const pdfUrl = searchParams.get('url'); +// if (!pdfUrl) { +// return NextResponse.json({ +// error: 'URL parameter wajib diisi' +// }, { status: 400 }); +// } + +// // Decode URL jika perlu +// const decodedUrl = decodeURIComponent(pdfUrl); + +// await checkDependencies(); + +// const getTotalPages = searchParams.get('total') === 'true'; + +// // Single fetch PDF dengan URL yang sudah di-decode +// const pdfResponse = await fetchPDF(decodedUrl); + +// const arrayBuffer = await pdfResponse.arrayBuffer(); +// pdfBuffer = Buffer.from(arrayBuffer); + +// // Get total pages +// if (getTotalPages) { +// try { +// const pageCount = await getPDFPageCount(pdfBuffer); +// return Response.json({ +// totalPages: pageCount, +// message: 'Success get total pages' +// }); +// } catch (error) { +// console.error('PDF parse error:', error); +// return Response.json({ +// error: 'Gagal membaca total halaman PDF', +// totalPages: 0 +// }, { status: 500 }); +// } +// } + +// // Parse page parameter dengan lebih baik +// const pageStr = searchParams.get('page'); +// let pageNum = 1; // Default ke halaman 1 + +// if (pageStr) { +// pageNum = parseInt(pageStr); +// if (isNaN(pageNum) || pageNum < 1) { +// return returnErrorImage('Invalid page number'); +// } + +// // Validasi halaman tidak melebihi total +// const totalPages = await getPDFPageCount(pdfBuffer); +// if (pageNum > totalPages) { +// return returnEndOfPageImage(); +// } +// } + +// const options = { +// density: 300, +// format: "png", +// width: Math.min(1200, MAX_IMAGE_DIMENSION), +// height: Math.min(1700, MAX_IMAGE_DIMENSION), +// preserveAspectRatio: true, +// saveFilename: "", +// savePath: "", +// returnBuffer: true +// }; + +// // Konversi single page +// const convert = fromBuffer(pdfBuffer, options); +// const result = await Promise.race([ +// convert(pageNum, { responseType: "buffer" }), +// new Promise((_, reject) => +// setTimeout(() => reject(new PDFConversionError('Konversi timeout', 504)), +// CONVERSION_TIMEOUT_MS) +// ) +// ]) as ConversionResult; + +// if (!result?.buffer) { +// return returnErrorImage('Konversi gagal: tidak ada output'); +// } + +// // Return image buffer +// const response = new NextResponse(result.buffer, { +// headers: { +// 'Content-Type': 'image/png', +// 'Content-Length': result.buffer.length.toString(), +// 'Cache-Control': 'public, max-age=31536000' +// } +// }); +// setCommonHeaders(response.headers); +// return response; + +// } catch (error) { +// console.error('PDF conversion error:', error); + +// // Return appropriate error response +// const errorMessage = error instanceof Error ? error.message : 'Unknown error'; +// const statusCode = error instanceof PDFConversionError ? error.statusCode : 500; + +// return !searchParams.get('pages') ? +// returnErrorImage(errorMessage) : +// NextResponse.json({ error: errorMessage }, { status: statusCode }); +// } finally { +// pdfBuffer = null; +// } +// } \ No newline at end of file diff --git a/src/app/dev/investasi/file-view/dokumen/[id]/page.tsx b/src/app/dev/investasi/file-view/dokumen/[id]/page.tsx index 446fef71..22aa6e7c 100644 --- a/src/app/dev/investasi/file-view/dokumen/[id]/page.tsx +++ b/src/app/dev/investasi/file-view/dokumen/[id]/page.tsx @@ -1,11 +1,9 @@ import { Investasi_UiFileViewDokumen } from "@/app_modules/investasi/_ui"; -export default async function Page({ params }: { params: { id: string } }) { - const dokumenId = params.id; - +export default async function Page() { return ( <> - + ); } diff --git a/src/app/dev/investasi/file-view/prospektus/[id]/page.tsx b/src/app/dev/investasi/file-view/prospektus/[id]/page.tsx index 25de80fd..dd56c9a0 100644 --- a/src/app/dev/investasi/file-view/prospektus/[id]/page.tsx +++ b/src/app/dev/investasi/file-view/prospektus/[id]/page.tsx @@ -1,12 +1,9 @@ -import { investasi_funGetProspekById } from "@/app_modules/investasi/_fun"; import { Investasi_UiFileView } from "@/app_modules/investasi/_ui"; -export default async function Page({ params }: { params: { id: string } }) { - const pospektusId = params.id; - +export default async function Page() { return ( <> - + ); } diff --git a/src/app_modules/_global/lib/api_fetch_global.ts b/src/app_modules/_global/lib/api_fetch_global.ts new file mode 100644 index 00000000..bea0d5b4 --- /dev/null +++ b/src/app_modules/_global/lib/api_fetch_global.ts @@ -0,0 +1,55 @@ +export { + apiGetPdfToImage, +} + +export interface PageData { + imageUrl: string; + pageNumber: number; +} + +interface PdfResponse { + pages: PageData[]; + totalPages: number; +} +const apiGetPdfToImage = async ({id}: {id: string}) => { + try { + // Fetch token from cookie + // const { token } = await fetch("/api/get-cookie").then((res) => res.json()); + // if (!token) { + // console.error("No token found"); + // return null; + // } + + const token = + "eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjp7ImlkIjoiY20wdXIxeXh3MDAwMDU2bnNqbHI2MTg3cCIsIm5hbWUiOiJiYWdhcyIsImVtYWlsIjoiYmFnYXNAZ21haWwuY29tIn0sImlhdCI6MTcyNTg3MTAzNiwiZXhwIjo0ODgxNjMxMDM2fQ.wFQLcrJj66wFeqIMYk2esMx3ULaHK6RFxkiToaLCuko"; + + + // Anda bisa menggunakan prospektusId di URL jika diperlukan + const pdfUrl = `https://wibu-storage.wibudev.com/api/pdf-to-image?url=https://wibu-storage.wibudev.com/api/files/${id}`; + + const response = await fetch(pdfUrl, { + method: "GET", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${token}`, + }, + }); + + // Check if the response is OK + if (!response.ok) { + const errorData = await response.json().catch(() => null); + console.error( + "Error get admin contact:", + errorData?.message || "Unknown error" + ); + + return null; + } + + const jsonData: PdfResponse = await response.json(); + return jsonData; + } catch (error) { + console.error("Error get admin contact:", error); + throw error; // Re-throw the error to handle it in the calling function + } +}; diff --git a/src/app_modules/investasi/_component/detail/comp_card_daftar_document.tsx b/src/app_modules/investasi/_component/detail/comp_card_daftar_document.tsx index 5e9d6b15..bcb30abf 100644 --- a/src/app_modules/investasi/_component/detail/comp_card_daftar_document.tsx +++ b/src/app_modules/investasi/_component/detail/comp_card_daftar_document.tsx @@ -22,10 +22,9 @@ export function Investasi_ComponentCardDaftarDocument({ justify="center" h={"100%"} onClick={() => { - router.push( - NEW_RouterInvestasi.file_prospektus({ id: data.fileId }), - { scroll: false } - ); + router.push(NEW_RouterInvestasi.file_dokumen({ id: data.fileId }), { + scroll: false, + }); setVisible(true); }} > diff --git a/src/app_modules/investasi/_component/detail/comp_card_rekap_document.tsx b/src/app_modules/investasi/_component/detail/comp_card_rekap_document.tsx index b2727e20..9bfa2458 100644 --- a/src/app_modules/investasi/_component/detail/comp_card_rekap_document.tsx +++ b/src/app_modules/investasi/_component/detail/comp_card_rekap_document.tsx @@ -97,7 +97,7 @@ export function Investasi_ComponentCardRekapDocument({ span={"auto"} onClick={() => { router.push( - NEW_RouterInvestasi.file_prospektus({ id: data.fileId }), + NEW_RouterInvestasi.file_dokumen({ id: data.fileId }), { scroll: false } ); setVisible(true); diff --git a/src/app_modules/investasi/_ui/file_view/ui_file_view_dokumen.tsx b/src/app_modules/investasi/_ui/file_view/ui_file_view_dokumen.tsx index c29c745b..df3c745d 100644 --- a/src/app_modules/investasi/_ui/file_view/ui_file_view_dokumen.tsx +++ b/src/app_modules/investasi/_ui/file_view/ui_file_view_dokumen.tsx @@ -3,27 +3,85 @@ import { APIs } from "@/lib"; import UIGlobal_LayoutHeaderTamplate from "@/app_modules/_global/ui/ui_header_tamplate"; import UIGlobal_LayoutTamplate from "@/app_modules/_global/ui/ui_layout_tamplate"; -import { Box } from "@mantine/core"; +import { Box, Stack } from "@mantine/core"; import { IconX } from "@tabler/icons-react"; import dynamic from "next/dynamic"; -const PdfToImage = dynamic( - () => - import("../../_view/file_view/view_file_viewer").then((mod) => mod.default), - { ssr: false } -); +import { apiGetPdfToImage, PageData } from "@/app_modules/_global/lib/api_fetch_global"; +import { useParams } from "next/navigation"; +import { useState, useRef, useEffect } from "react"; +import PdfToImage from "../../_view/file_view/view_file_viewer"; +import Image from "next/image"; +import CustomSkeleton from "@/app_modules/components/CustomSkeleton"; +import ComponentGlobal_IsEmptyData from "@/app_modules/_global/component/is_empty_data"; + + +export function Investasi_UiFileViewDokumen() { + const param = useParams<{ id: string }>(); + const dokumenId = param.id; + + const [pdfPages, setPdfPages] = useState(null); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); + const pdfsRef = useRef(null); + + useEffect(() => { + const fetchPdfData = async () => { + try { + setLoading(true); + const response = await apiGetPdfToImage({ id: dokumenId }); + + if (response) { + setPdfPages(response.pages as any); + setLoading(false); + } + } catch (err) { + console.error("Error fetching PDF:", err); + setError( + err instanceof Error ? err.message : "Unknown error occurred" + ); + setLoading(false); + } + }; + + fetchPdfData(); + }, [dokumenId]); + -export function Investasi_UiFileViewDokumen({ - dokumenId, -}: { - dokumenId: string; -}) { return ( <> } />} + header={} />} > - - + + {loading ? ( + + ) : error ? ( + + + + + ) : ( +
+ {pdfPages?.map((page, index) => ( + {`Page + ))} +
+ )}
diff --git a/src/app_modules/investasi/_ui/file_view/ui_file_view_prospektus.tsx b/src/app_modules/investasi/_ui/file_view/ui_file_view_prospektus.tsx index adb3cae5..8c822a7b 100644 --- a/src/app_modules/investasi/_ui/file_view/ui_file_view_prospektus.tsx +++ b/src/app_modules/investasi/_ui/file_view/ui_file_view_prospektus.tsx @@ -1,33 +1,90 @@ "use client"; -import { APIs } from "@/lib"; -import { RouterInvestasi_OLD } from "@/lib/router_hipmi/router_investasi"; +import ComponentGlobal_IsEmptyData from "@/app_modules/_global/component/is_empty_data"; +import { + apiGetPdfToImage, + PageData, +} from "@/app_modules/_global/lib/api_fetch_global"; import UIGlobal_LayoutHeaderTamplate from "@/app_modules/_global/ui/ui_header_tamplate"; import UIGlobal_LayoutTamplate from "@/app_modules/_global/ui/ui_layout_tamplate"; -import { Box } from "@mantine/core"; +import CustomSkeleton from "@/app_modules/components/CustomSkeleton"; +import { Box, Stack } from "@mantine/core"; import { IconX } from "@tabler/icons-react"; -import dynamic from "next/dynamic"; -const PdfToImage = dynamic( - () => - import("../../_view/file_view/view_file_viewer").then((mod) => mod.default), - { ssr: false } -); +import Image from "next/image"; +import { useParams } from "next/navigation"; +import { useEffect, useRef, useState } from "react"; + +export function Investasi_UiFileViewProspektus() { + const param = useParams<{ id: string }>(); + const prospektusId = param.id; + + const [pdfPages, setPdfPages] = useState(null); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); + const pdfsRef = useRef(null); + + useEffect(() => { + const fetchPdfData = async () => { + try { + setLoading(true); + const response = await apiGetPdfToImage({ id: prospektusId }); + + console.log("res:", response) + + if (response) { + setPdfPages(response.pages as any); + setLoading(false); + } + } catch (err) { + console.error("Error fetching PDF:", err); + setError(err instanceof Error ? err.message : "Unknown error occurred"); + setLoading(false); + } + }; + + fetchPdfData(); + }, [prospektusId]); -export function Investasi_UiFileViewProspektus({ - pospektusId, -}: { - pospektusId: string; -}) { return ( <> } />} - > - - } /> + } + > + + {loading ? ( + + ) : error ? ( + + + + + ) : ( +
+ {pdfPages?.map((page, index) => ( + {`Page + ))} +
+ )}
diff --git a/src/app_modules/katalog/portofolio/component/button_more_new.tsx b/src/app_modules/katalog/portofolio/component/button_more_new.tsx index 33b325bc..dd641880 100644 --- a/src/app_modules/katalog/portofolio/component/button_more_new.tsx +++ b/src/app_modules/katalog/portofolio/component/button_more_new.tsx @@ -118,18 +118,13 @@ export default function ComponentPortofolio_ButtonMoreNew({ return ( <> - { - userLoginId === authorId && ( - setOpenDrawer(true)}> - - - ) - // : ( - // - // - // - // ) - } + {userLoginId === authorId ? ( + setOpenDrawer(true)}> + + + ) : ( + + )} `/dev/investasi/main/portofolio/${id}`, + portofolio: ({ id }: { id: "1" | "2" | "3" | "4" }) => + `/dev/investasi/main/portofolio/${id}`, // portofolio: ({ id }: { id?: string }) => `/dev/investasi/main/portofolio/${id}`, // TRANSAKSI @@ -24,6 +25,8 @@ export const NEW_RouterInvestasi = { // FILE VIEW file_prospektus: ({ id }: { id: string }) => `/dev/investasi/file-view/prospektus/${id}`, + file_dokumen: ({ id }: { id: string }) => + `/dev/investasi/file-view/dokumen/${id}`, OLD_file_view_prospektus: "/dev/investasi/file-view/prospektus/", OLD_file_view_dokumen: "/dev/investasi/file-view/dokumen/", diff --git a/x-example-show-pdf/index.html b/x-example-show-pdf/index.html index 23e750a9..3aeee7f1 100644 --- a/x-example-show-pdf/index.html +++ b/x-example-show-pdf/index.html @@ -20,7 +20,7 @@ const token = "eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjp7ImlkIjoiY20wdXIxeXh3MDAwMDU2bnNqbHI2MTg3cCIsIm5hbWUiOiJiYWdhcyIsImVtYWlsIjoiYmFnYXNAZ21haWwuY29tIn0sImlhdCI6MTcyNTg3MTAzNiwiZXhwIjo0ODgxNjMxMDM2fQ.wFQLcrJj66wFeqIMYk2esMx3ULaHK6RFxkiToaLCuko"; const res = await fetch( - "https://wibu-storage.wibudev.com/api/pdf-to-image?url=https://wibu-storage.wibudev.com/api/files/cm5jgzg7d001dxpugxseb2ua0", + "https://wibu-storage.wibudev.com/api/pdf-to-image?url=https://wibu-storage.wibudev.com/api/files/cm7liew81000t3y8ax1v6yo02", { method: "GET", headers: {