Bläddra i källkod

updated view PDF

updated README
master
kelvinsuen 2 månader sedan
förälder
incheckning
6c9b464266
6 ändrade filer med 166 tillägg och 74 borttagningar
  1. +1
    -0
      .gitignore
  2. +7
    -1
      README.md
  3. +0
    -6
      src/pages/client/ClientMaintainPage/index.js
  4. +14
    -0
      src/pages/client/ClientSearchPage/ClientTable.js
  5. +140
    -66
      src/pages/pdf/index.js
  6. +4
    -1
      src/utils/CommonFunction.js

+ 1
- 0
.gitignore Visa fil

@@ -39,6 +39,7 @@ build/Release

# Dependency directories
node_modules/
/public/sdk
jspm_packages/

# TypeScript v1 declaration files


+ 7
- 1
README.md Visa fil

@@ -10,4 +10,10 @@
- Start the application by the following command:
```
npm start
```
```

## 3. Config the library
- Navigate to "LIONER-frontend\node_modules\pspdfkit\dist"
- Copy the folder "pspdfkit-lib"
- Create a new folder "sdk" in "LIONER-frontend\public"
- Paste the "pspdfkit-lib" inside "sdk" folder

+ 0
- 6
src/pages/client/ClientMaintainPage/index.js Visa fil

@@ -9,13 +9,7 @@ import * as React from "react";
import axios from "axios";
import {apiPath} from "../../../auth/utils";
import {
GET_EVENT_APPLICATION_PATH,
GET_CLIENT_PATH,
GET_REMINDER_BEFORE,
GET_REMINDER_INTERVAL,
GET_REMINDER_LIMIT,
GET_REMINDER_LIMIT_MAX,
GET_SUB_DIVISION_COMBO_LIST,
} from "../../../utils/ApiPathConst";
import LoadingComponent from "../../extra-pages/LoadingComponent";
import {useLocation, useParams} from "react-router-dom";


+ 14
- 0
src/pages/client/ClientSearchPage/ClientTable.js Visa fil

@@ -5,6 +5,7 @@ import {
GridActionsCellItem,
} from "@mui/x-data-grid";
import EditIcon from '@mui/icons-material/Edit';
import PictureAsPdfIcon from '@mui/icons-material/PictureAsPdf';
import {useContext, useEffect} from "react";
import {useNavigate} from "react-router-dom";
import {CustomNoRowsOverlay, dateComparator, getDateString} from "../../../utils/CommonFunction";
@@ -34,6 +35,10 @@ export default function ClientTable({recordList}) {
navigate('/client/maintain/'+ id);
};

const handlePDFClick = () => () => {
navigate('/pdf');
};

const columns = [
{
field: 'actions',
@@ -54,6 +59,15 @@ export default function ClientTable({recordList}) {
// disabled={'true'}
// disabled={!ability.can('VIEW','DASHBOARD')}
/>
<GridActionsCellItem
icon={<PictureAsPdfIcon sx={{fontSize: 25}}/>}
label="Edit PDF"
className="textPrimary"
onClick={handlePDFClick()}
color="edit"
// disabled={'true'}
// disabled={!ability.can('VIEW','DASHBOARD')}
/>
</ThemeProvider>
]
},


+ 140
- 66
src/pages/pdf/index.js Visa fil

@@ -1,11 +1,15 @@
// src/App.js (Your 'pdfForm' page equivalent)
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 {apiPath} from "../../auth/utils";
import {
GET_PDF_PATH
GET_PDF_PATH,
POST_PDF_PATH
} 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 PSPDFKit from 'pspdfkit';
@@ -14,74 +18,95 @@ function PDF() {
const viewerRef = useRef(null); // Ref for the DOM element where PDF will render
const instanceRef = useRef(null); // Ref for the PSPDFKit instance
const [pdfLoaded, setPdfLoaded] = useState(false);
const [viewerLoaded, setViewerLoaded] = useState(false);
const [template,setTemplate] = 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);
}
})
.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();
}, []); // Empty dependency array means this runs once on mount
}, [viewerRef, pdfLoaded]);

const handleSavePdf = async () => {
if (instanceRef.current) {
if (viewInstance.current) {console.log("tetes");
try {
// 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' });

// Create FormData to send the file to Spring Boot
@@ -89,7 +114,7 @@ function PDF() {
formData.append('file', filledPdfBlob, 'filled_form.pdf');

// 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: {
'Content-Type': 'multipart/form-data' // Important for file uploads
}
@@ -104,17 +129,64 @@ function PDF() {
};

const handlePrintPdf = () => {
if (instanceRef.current) {
if (viewInstance.current) {
// 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 (
<ThemeProvider theme={LIONER_BUTTON_THEME}>
<div className="pdf-form-page"> {/* This is your 'pdfForm' page */}
<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">
<button onClick={handleSavePdf} className="action-button save-button">
Save Filled PDF
@@ -125,11 +197,12 @@ function PDF() {
</div>
) : (
<p>Loading PDF viewer...</p>
)}
)} */}
</header>
<div
id={viewerRef}
className="pdf-viewer-container"
// id={viewerRef}
ref={viewerRef}
// className="pdf-viewer-container"
style={{
width: '100%',
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 */}
</div>
</div>
</ThemeProvider>
);
}


+ 4
- 1
src/utils/CommonFunction.js Visa fil

@@ -423,6 +423,9 @@ export function CustomNoRowsOverlay() {
}

export function GeneralConfirmWindow({ isWindowOpen, title, content, onNormalClose, onConfirmClose }) {
const formattedContent = content.split('\n').map((line, index) => (
<span key={index}>{line}<br/></span>
));
return (
<Dialog
open={isWindowOpen}
@@ -444,7 +447,7 @@ export function GeneralConfirmWindow({ isWindowOpen, title, content, onNormalClo
<DialogContent>
<DialogContentText id="alert-dialog-description">
<Typography variant="lionerSize" component="span" color={GENERAL_TEXT_COLOR}>
{content}
{formattedContent}
</Typography>
</DialogContentText>
</DialogContent>


Laddar…
Avbryt
Spara