"use client"; import { useState, useRef, useEffect } from "react"; declare global { interface Window { pdfjsLib: any; } } export default function PDFViewerClient() { const [pdfData, setPdfData] = useState(null); const [pdfName, setPdfName] = useState(""); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const [numPages, setNumPages] = useState(0); const [currentPage, setCurrentPage] = useState(1); const [scale, setScale] = useState(1.5); const [pdfjsLoaded, setPdfjsLoaded] = useState(false); const canvasRef = useRef(null); const pdfDocRef = useRef(null); useEffect(() => { // Load PDF.js from CDN 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 = () => { try { window.pdfjsLib = window.pdfjsLib; // Disable worker to avoid CSP issues window.pdfjsLib.GlobalWorkerOptions.workerSrc = ""; window.pdfjsLib.GlobalWorkerOptions.workerPort = null; setPdfjsLoaded(true); } catch (e) { setError("Failed to initialize PDF.js"); } }; script.onerror = () => { setError("Failed to load PDF.js library"); }; document.body.appendChild(script); }, []); const renderPage = async (pageNum: number) => { if (!pdfDocRef.current || !canvasRef.current || !window.pdfjsLib) return; try { const page = await pdfDocRef.current.getPage(pageNum); const viewport = page.getViewport({ scale }); const canvas = canvasRef.current; const context = canvas.getContext("2d"); canvas.height = viewport.height; canvas.width = viewport.width; // Use synchronous rendering to avoid worker const renderContext = { canvasContext: context, viewport: viewport, }; // For older pdf.js without worker, use direct render await page.render(renderContext).promise; } catch (err) { console.error("Error rendering page:", err); } }; useEffect(() => { if (pdfDocRef.current && currentPage && pdfjsLoaded) { renderPage(currentPage); } }, [currentPage, scale, pdfjsLoaded]); const handleFileUpload = async (e: React.ChangeEvent) => { const file = e.target.files?.[0]; if (!file || !window.pdfjsLib) return; if (file.type !== "application/pdf") { setError("Please select a PDF file"); return; } setLoading(true); setError(null); setPdfName(file.name); setCurrentPage(1); try { const arrayBuffer = await file.arrayBuffer(); // Disable worker for this load const loadingTask = window.pdfjsLib.getDocument({ data: arrayBuffer, disableWorker: true, verbosity: 0 }); const pdf = await loadingTask.promise; pdfDocRef.current = pdf; setNumPages(pdf.numPages); setPdfData("local"); await renderPage(1); } catch (err) { setError("Failed to load PDF. Try using 'Load from URL' instead."); console.error(err); } setLoading(false); }; const handleUrlSubmit = async () => { const input = prompt("Enter PDF URL:"); if (!input || !window.pdfjsLib) return; setLoading(true); setError(null); setCurrentPage(1); try { new URL(input); setPdfName(input.split("/").pop() || "document.pdf"); // Use Google Docs viewer for external URLs setPdfData(`https://docs.google.com/gview?url=${encodeURIComponent(input)}&embedded=true`); setNumPages(1); // We don't know the page count for external URLs } catch (err) { setError("Failed to load PDF from URL."); console.error(err); } setLoading(false); }; const goToPrevPage = () => { if (currentPage > 1) setCurrentPage(currentPage - 1); }; const goToNextPage = () => { if (currentPage < numPages) setCurrentPage(currentPage + 1); }; return (
{/* Toolbar */}
{!pdfjsLoaded && ( Loading PDF.js... )} {pdfData && ( <>
Page {currentPage} of {numPages}
{Math.round(scale * 100)}% )}
{/* Error */} {error && (

Error

{error}

)} {/* Content */}
{!pdfData && !loading && (
📄

No PDF Loaded

Upload a PDF or enter a URL

💡 Tip: For best results, use "Load from URL" with a public PDF link

)} {loading && (

Loading PDF...

)} {pdfData && !loading && (
{pdfData.startsWith("https://docs.google.com") ? ( // Google Docs viewer for external URLs