|
@@ -1,11 +1,15 @@ |
|
|
// src/App.js (Your 'pdfForm' page equivalent) |
|
|
|
|
|
import React, { useEffect, useRef, useState } from 'react'; |
|
|
import React, { useEffect, useRef, useState } from 'react'; |
|
|
// import './App.css'; // For basic styling |
|
|
|
|
|
|
|
|
import { Button, Grid } from '@mui/material'; |
|
|
|
|
|
import { GeneralConfirmWindow } from "../../utils/CommonFunction"; |
|
|
import axios from 'axios'; |
|
|
import axios from 'axios'; |
|
|
import {apiPath} from "../../auth/utils"; |
|
|
import {apiPath} from "../../auth/utils"; |
|
|
import { |
|
|
import { |
|
|
GET_PDF_PATH |
|
|
|
|
|
|
|
|
GET_PDF_PATH, |
|
|
|
|
|
POST_PDF_PATH |
|
|
} from "../../utils/ApiPathConst"; |
|
|
} from "../../utils/ApiPathConst"; |
|
|
|
|
|
import {LIONER_BUTTON_THEME} from "../../themes/colorConst"; |
|
|
|
|
|
import {ThemeProvider} from "@emotion/react"; |
|
|
|
|
|
import {useNavigate} from "react-router-dom"; |
|
|
|
|
|
|
|
|
// Import your chosen commercial PDF SDK (e.g., PSPDFKit) |
|
|
// Import your chosen commercial PDF SDK (e.g., PSPDFKit) |
|
|
import PSPDFKit from 'pspdfkit'; |
|
|
import PSPDFKit from 'pspdfkit'; |
|
@@ -14,74 +18,95 @@ function PDF() { |
|
|
const viewerRef = useRef(null); // Ref for the DOM element where PDF will render |
|
|
const viewerRef = useRef(null); // Ref for the DOM element where PDF will render |
|
|
const instanceRef = useRef(null); // Ref for the PSPDFKit instance |
|
|
const instanceRef = useRef(null); // Ref for the PSPDFKit instance |
|
|
const [pdfLoaded, setPdfLoaded] = useState(false); |
|
|
const [pdfLoaded, setPdfLoaded] = useState(false); |
|
|
|
|
|
const [viewerLoaded, setViewerLoaded] = useState(false); |
|
|
const [template,setTemplate] = useState(); |
|
|
const [template,setTemplate] = useState(); |
|
|
const [viewInstance,setViewInstance] = useState(); |
|
|
const [viewInstance,setViewInstance] = useState(); |
|
|
|
|
|
const navigate = useNavigate() |
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
|
|
const loadPdfViewer = async () => { |
|
|
|
|
|
if (document.getElementById(viewerRef)) { |
|
|
|
|
|
// if (viewerRef.current) { |
|
|
|
|
|
try { |
|
|
|
|
|
//New try |
|
|
|
|
|
axios.get(`${apiPath}${GET_PDF_PATH}`, { |
|
|
|
|
|
responseType: 'arraybuffer', // Essential for binary data |
|
|
|
|
|
}) |
|
|
|
|
|
.then((response) => { |
|
|
|
|
|
if (response.status === 200) { |
|
|
|
|
|
setTemplate(response); |
|
|
|
|
|
} |
|
|
|
|
|
}) |
|
|
|
|
|
.catch(error => { |
|
|
|
|
|
console.log(error); |
|
|
|
|
|
return false; |
|
|
|
|
|
}); |
|
|
|
|
|
// 1. Fetch the blank PDF template from your Spring Boot backend |
|
|
|
|
|
// const response = await axios.get(`${apiPath}${GET_PDF_PATH}`, { |
|
|
|
|
|
// responseType: 'arraybuffer', // Essential for binary data |
|
|
|
|
|
// }); |
|
|
|
|
|
const pdfBlob = new Blob(template, { type: 'application/pdf' }); |
|
|
|
|
|
const pdfUrl = URL.createObjectURL(pdfBlob); |
|
|
|
|
|
|
|
|
|
|
|
// 2. Initialize the PDF SDK (e.g., PSPDFKit) |
|
|
|
|
|
console.log(template); |
|
|
|
|
|
|
|
|
|
|
|
const instance = await PSPDFKit.load({ |
|
|
|
|
|
// setViewInstance(await PSPDFKit.load({ |
|
|
|
|
|
container: document.getElementById(viewerRef),//viewerRef.current, |
|
|
|
|
|
document: pdfUrl, |
|
|
|
|
|
// Remember to add your SDK license key if applicable |
|
|
|
|
|
// licenseKey: "YOUR_PSPDFKIT_LICENSE_KEY", |
|
|
|
|
|
baseUrl: `${process.env.PUBLIC_URL}/pspdfkit-lib/`//, // Path to SDK assets |
|
|
|
|
|
// Enable form filling UI |
|
|
|
|
|
// formDesignerViewMode: PSPDFKit.FormDesignerViewMode.Enabled |
|
|
|
|
|
}); |
|
|
|
|
|
// })); |
|
|
|
|
|
|
|
|
|
|
|
instanceRef.current = instance; |
|
|
|
|
|
|
|
|
const loadPdfTemplate = async () => { |
|
|
|
|
|
// if (!pdfLoaded) { |
|
|
|
|
|
axios.get(`${apiPath}${GET_PDF_PATH}`, { |
|
|
|
|
|
responseType: 'arraybuffer', // Essential for binary data |
|
|
|
|
|
}) |
|
|
|
|
|
.then((response) => { |
|
|
|
|
|
if (response.status === 200) { |
|
|
|
|
|
setTemplate(response.data); |
|
|
setPdfLoaded(true); |
|
|
setPdfLoaded(true); |
|
|
|
|
|
} |
|
|
|
|
|
}) |
|
|
|
|
|
.catch(error => { |
|
|
|
|
|
console.log(error); |
|
|
|
|
|
return false; |
|
|
|
|
|
}); |
|
|
|
|
|
// } |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
const loadPdfViewer = async () => {console.log(`PDF loaded = ${pdfLoaded}`); |
|
|
|
|
|
if (pdfLoaded && viewerRef.current) { |
|
|
|
|
|
try { |
|
|
|
|
|
//New try |
|
|
|
|
|
console.log(typeof(template)); |
|
|
|
|
|
const pdfBlob = new Blob([template], { type: 'application/pdf' }); |
|
|
|
|
|
const pdfUrl = URL.createObjectURL(pdfBlob); |
|
|
|
|
|
|
|
|
|
|
|
console.log('Template: '); |
|
|
|
|
|
console.log(template.data); |
|
|
|
|
|
console.log('URL: '); |
|
|
|
|
|
console.log(pdfUrl); |
|
|
|
|
|
console.log('Viewer: '); |
|
|
|
|
|
console.log(viewerRef.current); |
|
|
|
|
|
PSPDFKit.unload(viewerRef.current); |
|
|
|
|
|
await PSPDFKit.load({//click into load |
|
|
|
|
|
container: viewerRef.current, |
|
|
|
|
|
// container: '#viewer', |
|
|
|
|
|
document: pdfUrl, |
|
|
|
|
|
// baseUrl: `./sdk/`, // Path to SDK assets |
|
|
|
|
|
baseUrl: `http://localhost:3000/sdk/`, // Path to SDK |
|
|
|
|
|
// baseUrl: `${window.location.protocol}//${window.location.host}/${import.meta.env.BASE_URL}`, |
|
|
|
|
|
// baseUrl: `https://cdn.jsdelivr.net/npm/pspdfkit@VERSION/dist/`, // Path to SDK assets so this is work? |
|
|
|
|
|
// baseUrl: `${process.env.PUBLIC_URL}/`, // Path to SDK assets |
|
|
|
|
|
disableWebAssemblyStreaming: true, |
|
|
|
|
|
initialViewState: new PSPDFKit.ViewState({ |
|
|
|
|
|
sidebarMode: PSPDFKit.SidebarMode.THUMBNAILS |
|
|
|
|
|
}) |
|
|
|
|
|
}) |
|
|
|
|
|
.then(instance => { |
|
|
|
|
|
URL.revokeObjectURL(pdfUrl); |
|
|
|
|
|
setViewInstance(instance); |
|
|
|
|
|
console.log('instance: '); |
|
|
|
|
|
console.log(instance); |
|
|
|
|
|
setViewerLoaded(true); |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
// 3. Clean up on component unmount |
|
|
|
|
|
return () => { |
|
|
|
|
|
if (instance) { |
|
|
|
|
|
instance.unload(); // Unload SDK instance |
|
|
|
|
|
} |
|
|
|
|
|
URL.revokeObjectURL(pdfUrl); // Revoke the Blob URL |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
// instanceRef.current = instance; |
|
|
|
|
|
|
|
|
} catch (error) { |
|
|
|
|
|
console.error('Error loading PDF:', error); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
// 3. Clean up on component unmount |
|
|
|
|
|
// return () => { |
|
|
|
|
|
// if (instance) { |
|
|
|
|
|
// instance.unload(); // Unload SDK instance |
|
|
|
|
|
// } |
|
|
|
|
|
// URL.revokeObjectURL(pdfUrl); // Revoke the Blob URL |
|
|
|
|
|
// }; |
|
|
|
|
|
|
|
|
|
|
|
} catch (error) { |
|
|
|
|
|
console.error('Error loading PDF:', error); |
|
|
} |
|
|
} |
|
|
}; |
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
|
|
loadPdfTemplate(); |
|
|
|
|
|
}, []); |
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
loadPdfViewer(); |
|
|
loadPdfViewer(); |
|
|
}, []); // Empty dependency array means this runs once on mount |
|
|
|
|
|
|
|
|
}, [viewerRef, pdfLoaded]); |
|
|
|
|
|
|
|
|
const handleSavePdf = async () => { |
|
|
const handleSavePdf = async () => { |
|
|
if (instanceRef.current) { |
|
|
|
|
|
|
|
|
if (viewInstance.current) {console.log("tetes"); |
|
|
try { |
|
|
try { |
|
|
// Export the filled PDF from the SDK as an ArrayBuffer |
|
|
// Export the filled PDF from the SDK as an ArrayBuffer |
|
|
const arrayBuffer = await instanceRef.current.exportPDF(); |
|
|
|
|
|
|
|
|
const arrayBuffer = await viewInstance.current.exportPDF(); |
|
|
const filledPdfBlob = new Blob([arrayBuffer], { type: 'application/pdf' }); |
|
|
const filledPdfBlob = new Blob([arrayBuffer], { type: 'application/pdf' }); |
|
|
|
|
|
|
|
|
// Create FormData to send the file to Spring Boot |
|
|
// Create FormData to send the file to Spring Boot |
|
@@ -89,7 +114,7 @@ function PDF() { |
|
|
formData.append('file', filledPdfBlob, 'filled_form.pdf'); |
|
|
formData.append('file', filledPdfBlob, 'filled_form.pdf'); |
|
|
|
|
|
|
|
|
// Send the filled PDF to your Spring Boot backend's save endpoint |
|
|
// Send the filled PDF to your Spring Boot backend's save endpoint |
|
|
const response = await axios.post('http://localhost:8090/api/pdf/saveFilled', formData, { |
|
|
|
|
|
|
|
|
const response = await axios.post(`${apiPath}${POST_PDF_PATH}`, formData, { |
|
|
headers: { |
|
|
headers: { |
|
|
'Content-Type': 'multipart/form-data' // Important for file uploads |
|
|
'Content-Type': 'multipart/form-data' // Important for file uploads |
|
|
} |
|
|
} |
|
@@ -104,17 +129,64 @@ function PDF() { |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
const handlePrintPdf = () => { |
|
|
const handlePrintPdf = () => { |
|
|
if (instanceRef.current) { |
|
|
|
|
|
|
|
|
if (viewInstance.current) { |
|
|
// Trigger the SDK's built-in print functionality |
|
|
// Trigger the SDK's built-in print functionality |
|
|
instanceRef.current.print(); |
|
|
|
|
|
|
|
|
viewInstance.current.print(); |
|
|
} |
|
|
} |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
// Confirmation Window // |
|
|
|
|
|
const [isWindowOpen, setIsWindowOpen] = useState(false); |
|
|
|
|
|
|
|
|
|
|
|
const handleClose = () => { |
|
|
|
|
|
setIsWindowOpen(false); |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
const handleBackClick = () => { |
|
|
|
|
|
setIsWindowOpen(true); |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
const handleBack = () => { |
|
|
|
|
|
navigate('/client'); |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
return ( |
|
|
return ( |
|
|
|
|
|
<ThemeProvider theme={LIONER_BUTTON_THEME}> |
|
|
<div className="pdf-form-page"> {/* This is your 'pdfForm' page */} |
|
|
<div className="pdf-form-page"> {/* This is your 'pdfForm' page */} |
|
|
<header className="page-header"> |
|
|
<header className="page-header"> |
|
|
<h1>Fill and Manage Your PDF Form</h1> |
|
|
|
|
|
{pdfLoaded ? ( |
|
|
|
|
|
|
|
|
<Grid item> |
|
|
|
|
|
<Grid container> |
|
|
|
|
|
<Grid item sx={{ml:3, mr:1.5, mb:2}}> |
|
|
|
|
|
<Button |
|
|
|
|
|
variant="contained" |
|
|
|
|
|
type="submit" |
|
|
|
|
|
color="save" |
|
|
|
|
|
disabled={!viewerLoaded} |
|
|
|
|
|
// onClick={handleSavePdf} |
|
|
|
|
|
> |
|
|
|
|
|
Save |
|
|
|
|
|
</Button> |
|
|
|
|
|
</Grid> |
|
|
|
|
|
<Grid item sx={{ml:{xs:1.5, md:1.5, lg:1.5}, mr:1.5, mb:2}}> |
|
|
|
|
|
<Button |
|
|
|
|
|
variant="contained" |
|
|
|
|
|
color="cancel" |
|
|
|
|
|
onClick={viewerLoaded ? handleBackClick : handleBack} |
|
|
|
|
|
> |
|
|
|
|
|
Cancel |
|
|
|
|
|
</Button> |
|
|
|
|
|
<GeneralConfirmWindow |
|
|
|
|
|
isWindowOpen={isWindowOpen} |
|
|
|
|
|
title={"Back to previous page"} |
|
|
|
|
|
//content={`Confirm to delete Event "${clientDetail.name}" ?`} |
|
|
|
|
|
content={`Are you sure to leave this page?\nAny unsaved progress will be lost.`} |
|
|
|
|
|
onNormalClose={handleClose} |
|
|
|
|
|
onConfirmClose={handleBack} |
|
|
|
|
|
/> |
|
|
|
|
|
</Grid> |
|
|
|
|
|
</Grid> |
|
|
|
|
|
</Grid> |
|
|
|
|
|
{/* {pdfLoaded ? ( |
|
|
<div className="action-buttons"> |
|
|
<div className="action-buttons"> |
|
|
<button onClick={handleSavePdf} className="action-button save-button"> |
|
|
<button onClick={handleSavePdf} className="action-button save-button"> |
|
|
Save Filled PDF |
|
|
Save Filled PDF |
|
@@ -125,11 +197,12 @@ function PDF() { |
|
|
</div> |
|
|
</div> |
|
|
) : ( |
|
|
) : ( |
|
|
<p>Loading PDF viewer...</p> |
|
|
<p>Loading PDF viewer...</p> |
|
|
)} |
|
|
|
|
|
|
|
|
)} */} |
|
|
</header> |
|
|
</header> |
|
|
<div |
|
|
<div |
|
|
id={viewerRef} |
|
|
|
|
|
className="pdf-viewer-container" |
|
|
|
|
|
|
|
|
// id={viewerRef} |
|
|
|
|
|
ref={viewerRef} |
|
|
|
|
|
// className="pdf-viewer-container" |
|
|
style={{ |
|
|
style={{ |
|
|
width: '100%', |
|
|
width: '100%', |
|
|
height: 'calc(100vh - 180px)', // Adjust height based on header/footer |
|
|
height: 'calc(100vh - 180px)', // Adjust height based on header/footer |
|
@@ -139,6 +212,7 @@ function PDF() { |
|
|
{/* The PDF SDK will render the PDF viewer here */} |
|
|
{/* The PDF SDK will render the PDF viewer here */} |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
</ThemeProvider> |
|
|
); |
|
|
); |
|
|
} |
|
|
} |
|
|
|
|
|
|