satupeta-main/app/(modules)/admin/mapset-upload/_hooks/use-pdf-viewer.ts

322 lines
10 KiB
TypeScript

// "use client";
// import { useState, useEffect } from "react";
// import { useUploadContext } from "../_context/upload-context";
// // Sesuaikan import ini dengan lokasi service API Anda yang sebenarnya
// import uploadApi from "@/shared/services/map-upload";
// import { toast } from "sonner";
// // --- 1. Helper Load PDF.js via CDN (Sama seperti di use-upload.ts) ---
// const loadPdfJs = async () => {
// return new Promise<any>((resolve, reject) => {
// // Cek jika global variable sudah ada
// if ((window as any).pdfjsLib) {
// resolve((window as any).pdfjsLib);
// return;
// }
// const script = document.createElement("script");
// // Gunakan versi yang sama agar konsisten
// script.src = "https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.min.js";
// script.async = true;
// script.onload = () => {
// const pdfjsLib = (window as any).pdfjsLib;
// // Set worker
// pdfjsLib.GlobalWorkerOptions.workerSrc =
// "https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.worker.min.js";
// resolve(pdfjsLib);
// };
// script.onerror = (err) => reject(err);
// document.body.appendChild(script);
// });
// };
// export function usePdfViewer() {
// const { state, setState, goToStep } = useUploadContext();
// const [pages, setPages] = useState<{ pageNum: number; imageUrl: string }[]>([]);
// const [loading, setLoading] = useState(false);
// const [localSelectedPages, setLocalSelectedPages] = useState<number[]>([]);
// // Load PDF saat component mount atau file berubah
// useEffect(() => {
// if (state.file && state.step === "PDF_VIEWER") {
// renderPdfPages(state.file);
// }
// // eslint-disable-next-line react-hooks/exhaustive-deps
// }, [state.file, state.step]);
// const renderPdfPages = async (pdfFile: File) => {
// setLoading(true);
// setPages([]); // Reset halaman lama
// try {
// // 1. Load Library dari CDN
// const pdfjsLib = await loadPdfJs();
// // 2. Baca File
// const arrayBuffer = await pdfFile.arrayBuffer();
// const pdf = await pdfjsLib.getDocument({ data: arrayBuffer }).promise;
// const totalPages = pdf.numPages;
// const pageImages = [];
// // 3. Render Setiap Halaman ke Canvas -> Image URL
// for (let pageNum = 1; pageNum <= totalPages; pageNum++) {
// const page = await pdf.getPage(pageNum);
// const viewport = page.getViewport({ scale: 1 }); // Scale 1 cukup untuk thumbnail
// const canvas = document.createElement("canvas");
// const ctx = canvas.getContext("2d");
// if (ctx) {
// canvas.height = viewport.height;
// canvas.width = viewport.width;
// await page.render({
// canvasContext: ctx,
// viewport: viewport,
// }).promise;
// pageImages.push({
// pageNum,
// imageUrl: canvas.toDataURL("image/jpeg", 0.8), // Gunakan JPEG kompresi agar ringan
// });
// }
// }
// setPages(pageImages);
// } catch (err) {
// console.error("PDF Error:", err);
// toast.error("Gagal memuat halaman PDF. Pastikan file tidak korup.");
// } finally {
// setLoading(false);
// }
// };
// const toggleSelectPage = (pageNum: number) => {
// setLocalSelectedPages((prev) => {
// if (prev.includes(pageNum)) {
// return prev.filter((p) => p !== pageNum);
// } else {
// if (prev.length >= 20) {
// toast.warning("Maksimal pilih 20 halaman.");
// return prev;
// }
// return [...prev, pageNum];
// }
// });
// };
// const handleProcessPdf = async () => {
// if (localSelectedPages.length === 0) {
// toast.warning("Pilih minimal 1 halaman.");
// return;
// }
// setLoading(true);
// try {
// // Panggil API dengan halaman yang DIPILIH SAJA
// const res = await uploadApi.uploadFile(
// state.file!,
// localSelectedPages,
// null,
// state.fileDesc
// );
// setState(prev => ({ ...prev, result: res }));
// // Routing Logic setelah upload PDF selesai
// if (!res.tables) {
// goToStep("VALIDATE");
// } else if (res.tables.length > 1) {
// goToStep("TABLE_PICKER");
// toast.success("Beberapa tabel terdeteksi. Silakan pilih tabel.");
// } else {
// goToStep("TABLE_PICKER"); // Atau langsung validate tergantung kebutuhan
// }
// } catch (err: any) {
// toast.error(err.message || "Gagal memproses halaman PDF");
// } finally {
// setLoading(false);
// }
// };
// // 🔥 PENTING: Wajib me-return object ini agar tidak "undefined" di component
// return {
// pages,
// loading,
// localSelectedPages,
// toggleSelectPage,
// handleProcessPdf,
// };
// }
"use client";
import { useState, useEffect } from "react";
import { useUploadContext } from "../_context/upload-context";
// Pastikan path ini sesuai dengan lokasi service API upload Anda
import uploadApi from "@/shared/services/map-upload";
import { toast } from "sonner";
// --- HELPER: Load PDF.js via CDN (Bypassing Webpack agar tidak Error) ---
const loadPdfJs = async () => {
return new Promise<any>((resolve, reject) => {
// 1. Cek jika library sudah ada di window
if ((window as any).pdfjsLib) {
resolve((window as any).pdfjsLib);
return;
}
// 2. Inject Script jika belum ada
const script = document.createElement("script");
script.src = "https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.min.js";
script.async = true;
script.onload = () => {
const pdfjsLib = (window as any).pdfjsLib;
// Set worker source ke versi yang sama
pdfjsLib.GlobalWorkerOptions.workerSrc =
"https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.worker.min.js";
resolve(pdfjsLib);
};
script.onerror = (err) => reject(err);
document.body.appendChild(script);
});
};
export function usePdfViewer() {
const { state, setState, goToStep } = useUploadContext();
const [pages, setPages] = useState<{ pageNum: number; imageUrl: string }[]>([]);
const [loading, setLoading] = useState(false);
const [localSelectedPages, setLocalSelectedPages] = useState<number[]>([]);
// Efek untuk memuat halaman PDF saat komponen dipasang
useEffect(() => {
if (state.file && state.step === "PDF_VIEWER") {
renderPdfPages(state.file);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [state.file, state.step]);
// --- FUNGSI RENDER PDF KE GAMBAR ---
const renderPdfPages = async (pdfFile: File) => {
setLoading(true);
setPages([]); // Bersihkan halaman sebelumnya
try {
// Load library dari CDN
const pdfjsLib = await loadPdfJs();
// Baca ArrayBuffer
const arrayBuffer = await pdfFile.arrayBuffer();
const pdf = await pdfjsLib.getDocument({ data: arrayBuffer }).promise;
const totalPages = pdf.numPages;
const pageImages = [];
// Render setiap halaman ke Canvas -> DataURL
for (let pageNum = 1; pageNum <= totalPages; pageNum++) {
const page = await pdf.getPage(pageNum);
const viewport = page.getViewport({ scale: 1 }); // Skala thumbnail
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
if (ctx) {
canvas.height = viewport.height;
canvas.width = viewport.width;
await page.render({
canvasContext: ctx,
viewport: viewport,
}).promise;
pageImages.push({
pageNum,
imageUrl: canvas.toDataURL("image/jpeg", 0.7), // Kompresi JPEG biar ringan
});
}
}
setPages(pageImages);
} catch (err) {
console.error("PDF Render Error:", err);
toast.error("Gagal memuat visualisasi PDF.");
} finally {
setLoading(false);
}
};
// --- FUNGSI PILIH HALAMAN ---
const toggleSelectPage = (pageNum: number) => {
setLocalSelectedPages((prev) => {
if (prev.includes(pageNum)) {
return prev.filter((p) => p !== pageNum);
} else {
if (prev.length >= 20) {
toast.warning("Maksimal 20 halaman yang dapat dipilih.");
return prev;
}
return [...prev, pageNum];
}
});
};
// --- LOGIKA PROSES UPLOAD & ROUTING YANG ANDA MINTA ---
const handleProcessPdf = async () => {
if (localSelectedPages.length === 0) {
toast.warning("Harap pilih minimal 1 halaman untuk diproses.");
return;
}
setLoading(true);
try {
// 1. Kirim ke API dengan parameter 'pages' (localSelectedPages)
const res = await uploadApi.uploadFile(
state.file!,
localSelectedPages, // Kirim array halaman: [1, 2, 5]
null, // sheet null karena ini PDF
state.fileDesc
);
// 2. Simpan hasil response ke context global
setState(prev => ({ ...prev, result: res }));
// 3. Cek Logic Routing
if (res.data.tables && res.data.tables.length > 0) {
// Jika ada tabel terdeteksi -> Step 3 (Table Picker)
goToStep("TABLE_PICKER");
toast.success(`Ditemukan ${res.data.tables.length} tabel. Silakan pilih tabel.`);
} else if (!res.data.tables) {
// Jika TIDAK ada tabel (mungkin teks biasa/gambar) -> Step 4 (Validate/Preview Raw)
goToStep("VALIDATE");
toast.info("Tabel tidak terdeteksi spesifik, lanjut ke validasi.");
} else {
toast.warning(res.message);
}
} catch (err: any) {
console.error(err);
toast.error(err.message || "Gagal memproses halaman PDF terpilih.");
} finally {
setLoading(false);
}
};
// 🔥 Return wajib agar tidak error destructuring undefined
return {
pages,
loading,
localSelectedPages,
toggleSelectPage,
handleProcessPdf,
};
}