|
|
@@ -1,14 +1,30 @@ |
|
|
// material-ui |
|
|
// material-ui |
|
|
import * as React from 'react'; |
|
|
import * as React from 'react'; |
|
|
|
|
|
import {apiPath} from "../../../auth/utils"; |
|
|
|
|
|
import { POST_SIG_UPLOAD1 } from "../../../utils/ApiPathConst"; |
|
|
|
|
|
import axios from 'axios'; |
|
|
import { |
|
|
import { |
|
|
DataGrid, |
|
|
DataGrid, |
|
|
GridActionsCellItem, |
|
|
GridActionsCellItem, |
|
|
} from "@mui/x-data-grid"; |
|
|
} from "@mui/x-data-grid"; |
|
|
import EditIcon from '@mui/icons-material/Edit'; |
|
|
import EditIcon from '@mui/icons-material/Edit'; |
|
|
import PictureAsPdfIcon from '@mui/icons-material/PictureAsPdf'; |
|
|
|
|
|
|
|
|
import UploadFileIcon from '@mui/icons-material/UploadFile'; |
|
|
|
|
|
import CheckCircleIcon from '@mui/icons-material/CheckCircle'; |
|
|
|
|
|
import FileDownloadIcon from '@mui/icons-material/FileDownload'; |
|
|
|
|
|
import { |
|
|
|
|
|
Dialog, |
|
|
|
|
|
DialogTitle, |
|
|
|
|
|
DialogContent, |
|
|
|
|
|
DialogActions, |
|
|
|
|
|
Button, |
|
|
|
|
|
Typography, |
|
|
|
|
|
Box, // for centering and layout |
|
|
|
|
|
CircularProgress, // Import for loading indicator |
|
|
|
|
|
} from '@mui/material'; |
|
|
import {useContext, useEffect} from "react"; |
|
|
import {useContext, useEffect} from "react"; |
|
|
import {useNavigate} from "react-router-dom"; |
|
|
import {useNavigate} from "react-router-dom"; |
|
|
import {CustomNoRowsOverlay, dateComparator, getDateString} from "../../../utils/CommonFunction"; |
|
|
|
|
|
|
|
|
// Note: Assuming these utility functions/components are defined elsewhere |
|
|
|
|
|
import {CustomNoRowsOverlay, dateComparator, getDateString} from "../../../utils/CommonFunction"; |
|
|
import AbilityContext from "../../../components/AbilityProvider"; |
|
|
import AbilityContext from "../../../components/AbilityProvider"; |
|
|
import {LIONER_BUTTON_THEME} from "../../../themes/colorConst"; |
|
|
import {LIONER_BUTTON_THEME} from "../../../themes/colorConst"; |
|
|
import {ThemeProvider} from "@emotion/react"; |
|
|
import {ThemeProvider} from "@emotion/react"; |
|
|
@@ -19,6 +35,11 @@ export default function PdfTable({recordList}) { |
|
|
const [rows, setRows] = React.useState(recordList); |
|
|
const [rows, setRows] = React.useState(recordList); |
|
|
const [rowModesModel] = React.useState({}); |
|
|
const [rowModesModel] = React.useState({}); |
|
|
|
|
|
|
|
|
|
|
|
// State for Dialog visibility, row ID, and Loading state |
|
|
|
|
|
const [isDialogOpen, setIsDialogOpen] = React.useState(false); |
|
|
|
|
|
const [currentRowId, setCurrentRowId] = React.useState(null); |
|
|
|
|
|
const [isUploading, setIsUploading] = React.useState(false); |
|
|
|
|
|
|
|
|
const navigate = useNavigate() |
|
|
const navigate = useNavigate() |
|
|
const ability = useContext(AbilityContext); |
|
|
const ability = useContext(AbilityContext); |
|
|
|
|
|
|
|
|
@@ -26,6 +47,9 @@ export default function PdfTable({recordList}) { |
|
|
page: 0, |
|
|
page: 0, |
|
|
pageSize:10 |
|
|
pageSize:10 |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
// Ref for the hidden file input |
|
|
|
|
|
const fileInputRef = React.useRef(null); |
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
useEffect(() => { |
|
|
setPaginationModel({page:0,pageSize:10}); |
|
|
setPaginationModel({page:0,pageSize:10}); |
|
|
@@ -36,16 +60,141 @@ export default function PdfTable({recordList}) { |
|
|
navigate(`/pdf/maintain/${id}`); |
|
|
navigate(`/pdf/maintain/${id}`); |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
const handleFormUpDownClick = (id) => () => { |
|
|
|
|
|
navigate(`/pdf/form-up-down/${id}`); |
|
|
|
|
|
|
|
|
// Opens the upload dialog and sets the current row ID |
|
|
|
|
|
const handleUploadClick = (id) => () => { |
|
|
|
|
|
setCurrentRowId(id); |
|
|
|
|
|
setIsDialogOpen(true); |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
const handleUpload2Click = (id, templateName) => () => { |
|
|
|
|
|
// Placeholder for Upload 2 |
|
|
|
|
|
console.log(`Uploading for row ID ${id} (Upload 2)`); |
|
|
|
|
|
setCurrentRowId(id); |
|
|
|
|
|
setIsDialogOpen(true); |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
const handleDownloadClick = (id) => () => { |
|
|
|
|
|
|
|
|
|
|
|
// 1. Construct the download URL with the ID query parameter |
|
|
|
|
|
const downloadUrl = `${apiPath}/pdf/download-ff/${id}`; |
|
|
|
|
|
|
|
|
|
|
|
// Use axios to fetch the PDF as a Blob |
|
|
|
|
|
axios.get(downloadUrl, { |
|
|
|
|
|
responseType: 'blob', // IMPORTANT: Tells axios to handle the response as binary data |
|
|
|
|
|
}) |
|
|
|
|
|
.then((response) => { |
|
|
|
|
|
|
|
|
|
|
|
// 2. Extract Filename from Content-Disposition Header |
|
|
|
|
|
const contentDisposition = response.headers['content-disposition']; |
|
|
|
|
|
let filename = `document-${id}.pdf`; // Fallback filename |
|
|
|
|
|
|
|
|
|
|
|
if (contentDisposition) { |
|
|
|
|
|
// Regex to find filename="name.pdf" or filename*=UTF-8''name.pdf |
|
|
|
|
|
// The server should be setting the filename header correctly. |
|
|
|
|
|
const filenameMatch = contentDisposition.match(/filename\*?=['"]?([^'"]+)/); |
|
|
|
|
|
if (filenameMatch && filenameMatch[1]) { |
|
|
|
|
|
// Decode URI component and remove extra quotes |
|
|
|
|
|
filename = decodeURIComponent(filenameMatch[1].replace(/\\"/g, '')); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 3. Create a temporary anchor tag (<a>) to trigger the download |
|
|
|
|
|
const blob = new Blob([response.data], { type: 'application/pdf' }); |
|
|
|
|
|
const url = window.URL.createObjectURL(blob); |
|
|
|
|
|
const link = document.createElement('a'); |
|
|
|
|
|
|
|
|
|
|
|
link.href = url; |
|
|
|
|
|
link.setAttribute('download', filename); |
|
|
|
|
|
document.body.appendChild(link); |
|
|
|
|
|
link.click(); |
|
|
|
|
|
|
|
|
|
|
|
// 4. Clean up |
|
|
|
|
|
document.body.removeChild(link); |
|
|
|
|
|
window.URL.revokeObjectURL(url); |
|
|
|
|
|
}) |
|
|
|
|
|
.catch((error) => { |
|
|
|
|
|
console.error(`Download failed for ID ${id}:`, error); |
|
|
|
|
|
// Handle error response (e.g., if the backend returns a 404 or a JSON error) |
|
|
|
|
|
alert('Failed to download the PDF file. Check server logs.'); |
|
|
|
|
|
}); |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
const handleCloseDialog = () => { |
|
|
|
|
|
setIsDialogOpen(false); |
|
|
|
|
|
setCurrentRowId(null); |
|
|
|
|
|
if (fileInputRef.current) { |
|
|
|
|
|
fileInputRef.current.value = ""; // Clear the file input |
|
|
|
|
|
} |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
// Function to handle file selection and API submission |
|
|
|
|
|
const handleFileChange = async (event) => { |
|
|
|
|
|
const file = event.target.files[0]; |
|
|
|
|
|
|
|
|
|
|
|
if (!file) return; |
|
|
|
|
|
|
|
|
|
|
|
if (file.type !== "application/pdf") { |
|
|
|
|
|
alert("Please select a PDF file."); |
|
|
|
|
|
event.target.value = ""; |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const uploadUrl = apiPath + '/pdf/upload1'; |
|
|
|
|
|
|
|
|
|
|
|
// 1. Create FormData |
|
|
|
|
|
const formData = new FormData(); |
|
|
|
|
|
formData.append('file', file); |
|
|
|
|
|
formData.append('refId', currentRowId); |
|
|
|
|
|
formData.append('refType', "upload1"); |
|
|
|
|
|
setIsUploading(true); |
|
|
|
|
|
|
|
|
|
|
|
try { |
|
|
|
|
|
axios.post(`${apiPath}${POST_SIG_UPLOAD1}`, |
|
|
|
|
|
formData, |
|
|
|
|
|
{ |
|
|
|
|
|
headers: { |
|
|
|
|
|
'Content-Type': 'multipart/form-data', |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
) |
|
|
|
|
|
.then((response) => { |
|
|
|
|
|
if (response.status === 200) { |
|
|
|
|
|
// Optional: Read response if the server returns data |
|
|
|
|
|
alert('Upload success'); |
|
|
|
|
|
console.log(`PDF file ${file.name} successfully uploaded for record ID: ${currentRowId}!`); |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
setIsUploading(false); |
|
|
|
|
|
}) |
|
|
|
|
|
.catch((error) => { |
|
|
|
|
|
setIsUploading(false); |
|
|
|
|
|
console.log(error); |
|
|
|
|
|
return false; |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} catch (error) { |
|
|
|
|
|
console.error('Upload error:', error); |
|
|
|
|
|
alert(`Error uploading file: ${error.message}`); |
|
|
|
|
|
} finally { |
|
|
|
|
|
// 3. Cleanup and close |
|
|
|
|
|
setIsUploading(false); |
|
|
|
|
|
handleCloseDialog(); |
|
|
|
|
|
} |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
const handleChooseFile = () => { |
|
|
|
|
|
// Trigger the hidden file input click |
|
|
|
|
|
if (fileInputRef.current) { |
|
|
|
|
|
fileInputRef.current.click(); |
|
|
|
|
|
} |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
const columns = [ |
|
|
const columns = [ |
|
|
{ |
|
|
{ |
|
|
field: 'actions', |
|
|
field: 'actions', |
|
|
type: 'actions', |
|
|
type: 'actions', |
|
|
headerName: 'Actions', |
|
|
|
|
|
// flex: 0.5, |
|
|
|
|
|
|
|
|
headerName: 'Edit', |
|
|
width: 100, |
|
|
width: 100, |
|
|
cellClassName: 'actions', |
|
|
cellClassName: 'actions', |
|
|
getActions: ({id}) => { |
|
|
getActions: ({id}) => { |
|
|
@@ -57,28 +206,12 @@ export default function PdfTable({recordList}) { |
|
|
className="textPrimary" |
|
|
className="textPrimary" |
|
|
onClick={handleEditClick(id)} |
|
|
onClick={handleEditClick(id)} |
|
|
color="edit" |
|
|
color="edit" |
|
|
// disabled={'true'} |
|
|
|
|
|
// disabled={!ability.can('VIEW','DASHBOARD')} |
|
|
|
|
|
/> |
|
|
/> |
|
|
</ThemeProvider> |
|
|
</ThemeProvider> |
|
|
] |
|
|
] |
|
|
}, |
|
|
}, |
|
|
}, |
|
|
}, |
|
|
// { |
|
|
|
|
|
// id: 'title', |
|
|
|
|
|
// field: 'title', |
|
|
|
|
|
// headerName: 'Title', |
|
|
|
|
|
// // sortComparator: dateComparator, |
|
|
|
|
|
// flex: 0.75, |
|
|
|
|
|
// renderCell: (params) => ( |
|
|
|
|
|
// <div style={{display: 'flex', alignItems: 'center', justifyContent: 'center', whiteSpace: 'normal', wordBreak: 'break-word'}}> |
|
|
|
|
|
// {params.value} |
|
|
|
|
|
// </div> |
|
|
|
|
|
// // <div> |
|
|
|
|
|
// // {getDateString(params.row.pdfFrom,false)} |
|
|
|
|
|
// // </div> |
|
|
|
|
|
// ), |
|
|
|
|
|
// }, |
|
|
|
|
|
|
|
|
|
|
|
{ |
|
|
{ |
|
|
id: 'templateName', |
|
|
id: 'templateName', |
|
|
field: 'templateName', |
|
|
field: 'templateName', |
|
|
@@ -86,11 +219,85 @@ export default function PdfTable({recordList}) { |
|
|
flex: 2, |
|
|
flex: 2, |
|
|
renderCell: (params) => { |
|
|
renderCell: (params) => { |
|
|
return ( |
|
|
return ( |
|
|
<div style={{display: 'flex', alignItems: 'center', justifyContent: 'center', whiteSpace: 'normal', wordBreak: 'break-word'}}> |
|
|
|
|
|
|
|
|
<div style={{display: 'flex', alignItems: 'center', justifyContent: 'center', whiteSpace: 'normal', wordBreak: 'break-word'}}> |
|
|
{params.value} {params.row.vNum} |
|
|
{params.value} {params.row.vNum} |
|
|
</div> |
|
|
|
|
|
|
|
|
</div> |
|
|
); |
|
|
); |
|
|
} |
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
}, |
|
|
|
|
|
{ |
|
|
|
|
|
field: 'upload1', |
|
|
|
|
|
type: 'actions', |
|
|
|
|
|
// Multi-line header |
|
|
|
|
|
headerName: ( |
|
|
|
|
|
<div> |
|
|
|
|
|
Upload Sig. |
|
|
|
|
|
</div> |
|
|
|
|
|
), |
|
|
|
|
|
width: 100, |
|
|
|
|
|
cellClassName: 'actions', |
|
|
|
|
|
getActions: ({ id, row }) => { |
|
|
|
|
|
|
|
|
|
|
|
// Check if a file ID exists to determine if a file is present |
|
|
|
|
|
const isUploaded = !!row.upload1FileId; |
|
|
|
|
|
|
|
|
|
|
|
// Determine the icon and label based on upload status |
|
|
|
|
|
const upload1Icon = isUploaded |
|
|
|
|
|
? <CheckCircleIcon sx={{fontSize: 25, color: 'success.main'}} /> // Green tick if uploaded |
|
|
|
|
|
: <UploadFileIcon sx={{fontSize: 25}}/>; // Upload icon if not uploaded |
|
|
|
|
|
|
|
|
|
|
|
const upload1Label = isUploaded ? "Update Signature" : "Upload Signature"; |
|
|
|
|
|
|
|
|
|
|
|
// Define the actions |
|
|
|
|
|
const actions = [ |
|
|
|
|
|
<ThemeProvider key="UploadSign1" theme={LIONER_BUTTON_THEME}> |
|
|
|
|
|
<GridActionsCellItem |
|
|
|
|
|
icon={upload1Icon} // Use the dynamic icon |
|
|
|
|
|
label={upload1Label} // Use the dynamic label |
|
|
|
|
|
className="textPrimary" |
|
|
|
|
|
onClick={handleUploadClick(id)} |
|
|
|
|
|
color="upload" // Use 'upload' color which will apply to the button |
|
|
|
|
|
/> |
|
|
|
|
|
</ThemeProvider> |
|
|
|
|
|
]; |
|
|
|
|
|
|
|
|
|
|
|
// Conditional rendering logic for Upload 2 |
|
|
|
|
|
if (row.templateName === "MLB03S" || row.templateName === "SLGII" || row.templateName === "SLAPP") { |
|
|
|
|
|
actions.push( |
|
|
|
|
|
<ThemeProvider key="UploadSign2" theme={LIONER_BUTTON_THEME}> |
|
|
|
|
|
<GridActionsCellItem |
|
|
|
|
|
icon={<UploadFileIcon sx={{fontSize: 25}}/>} |
|
|
|
|
|
label="Upload2" |
|
|
|
|
|
className="textPrimary" |
|
|
|
|
|
onClick={handleUpload2Click(id, row.templateName)} |
|
|
|
|
|
color="upload" |
|
|
|
|
|
/> |
|
|
|
|
|
</ThemeProvider> |
|
|
|
|
|
); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return actions; |
|
|
|
|
|
}, |
|
|
|
|
|
}, |
|
|
|
|
|
{ |
|
|
|
|
|
field: 'actions2', |
|
|
|
|
|
type: 'actions', |
|
|
|
|
|
headerName: 'Download', |
|
|
|
|
|
width: 100, |
|
|
|
|
|
cellClassName: 'actions', |
|
|
|
|
|
getActions: ({id}) => { |
|
|
|
|
|
return [ |
|
|
|
|
|
<ThemeProvider key="DownloadFile" theme={LIONER_BUTTON_THEME}> |
|
|
|
|
|
<GridActionsCellItem |
|
|
|
|
|
icon={<FileDownloadIcon sx={{fontSize: 25}}/>} |
|
|
|
|
|
label="Download" |
|
|
|
|
|
className="textPrimary" |
|
|
|
|
|
onClick={handleDownloadClick(id, "{params.row.templateName}")} |
|
|
|
|
|
color="download" |
|
|
|
|
|
/> |
|
|
|
|
|
</ThemeProvider> |
|
|
|
|
|
] |
|
|
|
|
|
}, |
|
|
}, |
|
|
}, |
|
|
{ |
|
|
{ |
|
|
id: 'createDate', |
|
|
id: 'createDate', |
|
|
@@ -129,89 +336,6 @@ export default function PdfTable({recordList}) { |
|
|
</div> |
|
|
</div> |
|
|
), |
|
|
), |
|
|
}, |
|
|
}, |
|
|
// { |
|
|
|
|
|
// id: 'lastname', |
|
|
|
|
|
// field: 'lastname', |
|
|
|
|
|
// headerName: 'Last Name', |
|
|
|
|
|
// flex: 1.5, |
|
|
|
|
|
// sortComparator: dateComparator, |
|
|
|
|
|
// renderCell: (params) => ( |
|
|
|
|
|
// <div style={{display: 'flex', alignItems: 'center', justifyContent: 'center', whiteSpace: 'normal', wordBreak: 'break-word'}}> |
|
|
|
|
|
// {params.value} |
|
|
|
|
|
// </div> |
|
|
|
|
|
// // <div> |
|
|
|
|
|
// // {getDateString(params.row.startDate,false)} |
|
|
|
|
|
// // </div> |
|
|
|
|
|
// ), |
|
|
|
|
|
// }, |
|
|
|
|
|
// { |
|
|
|
|
|
// id: 'firstname', |
|
|
|
|
|
// field: 'firstname', |
|
|
|
|
|
// headerName: 'First Name', |
|
|
|
|
|
// // sortComparator: dateComparator, |
|
|
|
|
|
// flex: 2, |
|
|
|
|
|
// renderCell: (params) => ( |
|
|
|
|
|
// <div style={{display: 'flex', alignItems: 'center', justifyContent: 'center', whiteSpace: 'normal', wordBreak: 'break-word'}}> |
|
|
|
|
|
// {params.value} |
|
|
|
|
|
// </div> |
|
|
|
|
|
// // <div> |
|
|
|
|
|
// // {getDateString(params.row.applicationDeadline,false)} |
|
|
|
|
|
// // </div> |
|
|
|
|
|
// ), |
|
|
|
|
|
// }, |
|
|
|
|
|
// { |
|
|
|
|
|
// id: 'email', |
|
|
|
|
|
// field: 'email', |
|
|
|
|
|
// headerName: 'Email', |
|
|
|
|
|
// flex: 1.5, |
|
|
|
|
|
// renderCell: (params) => { |
|
|
|
|
|
// return ( |
|
|
|
|
|
// <div style={{display: 'flex', alignItems: 'center', justifyContent: 'center', whiteSpace: 'normal', wordBreak: 'break-word'}}> |
|
|
|
|
|
// {params.value} |
|
|
|
|
|
// </div> |
|
|
|
|
|
// ); |
|
|
|
|
|
// } |
|
|
|
|
|
// }, |
|
|
|
|
|
// { |
|
|
|
|
|
// id: 'phone1', |
|
|
|
|
|
// field: 'phone1', |
|
|
|
|
|
// headerName: 'Phone No.', |
|
|
|
|
|
// flex: 1, |
|
|
|
|
|
// renderCell: (params) => { |
|
|
|
|
|
// return ( |
|
|
|
|
|
// <div style={{display: 'flex', alignItems: 'center', justifyContent: 'center', whiteSpace: 'normal', wordBreak: 'break-word'}}> |
|
|
|
|
|
// {params.value} |
|
|
|
|
|
// </div> |
|
|
|
|
|
// ); |
|
|
|
|
|
// } |
|
|
|
|
|
// }, |
|
|
|
|
|
// { |
|
|
|
|
|
// id: 'phone2', |
|
|
|
|
|
// field: 'phone2', |
|
|
|
|
|
// headerName: '2nd Phone No.', |
|
|
|
|
|
// flex: 1, |
|
|
|
|
|
// renderCell: (params) => { |
|
|
|
|
|
// return ( |
|
|
|
|
|
// <div style={{display: 'flex', alignItems: 'center', justifyContent: 'center', whiteSpace: 'normal', wordBreak: 'break-word'}}> |
|
|
|
|
|
// {params.value} |
|
|
|
|
|
// </div> |
|
|
|
|
|
// ); |
|
|
|
|
|
// } |
|
|
|
|
|
// }, |
|
|
|
|
|
// { |
|
|
|
|
|
// id: 'remarks', |
|
|
|
|
|
// field: 'remarks', |
|
|
|
|
|
// headerName: 'Remarks', |
|
|
|
|
|
// flex: 2, |
|
|
|
|
|
// renderCell: (params) => { |
|
|
|
|
|
// return ( |
|
|
|
|
|
// <div style={{display: 'flex', alignItems: 'center', justifyContent: 'center', whiteSpace: 'normal', wordBreak: 'break-word'}}> |
|
|
|
|
|
// {params.value} |
|
|
|
|
|
// </div> |
|
|
|
|
|
// ); |
|
|
|
|
|
// } |
|
|
|
|
|
// }, |
|
|
|
|
|
|
|
|
|
|
|
]; |
|
|
]; |
|
|
|
|
|
|
|
|
return ( |
|
|
return ( |
|
|
@@ -219,9 +343,9 @@ export default function PdfTable({recordList}) { |
|
|
<DataGrid |
|
|
<DataGrid |
|
|
rows={rows} |
|
|
rows={rows} |
|
|
columns={columns} |
|
|
columns={columns} |
|
|
columnHeaderHeight={45} |
|
|
|
|
|
|
|
|
// Increased height to accommodate the multi-line header |
|
|
|
|
|
columnHeaderHeight={70} |
|
|
editMode="row" |
|
|
editMode="row" |
|
|
//autoPageSize |
|
|
|
|
|
rowModesModel={rowModesModel} |
|
|
rowModesModel={rowModesModel} |
|
|
getRowHeight={() => 'auto'} |
|
|
getRowHeight={() => 'auto'} |
|
|
paginationModel={paginationModel} |
|
|
paginationModel={paginationModel} |
|
|
@@ -234,6 +358,62 @@ export default function PdfTable({recordList}) { |
|
|
pageSizeOptions={[10]} |
|
|
pageSizeOptions={[10]} |
|
|
autoHeight |
|
|
autoHeight |
|
|
/> |
|
|
/> |
|
|
|
|
|
|
|
|
|
|
|
{/* The Upload Dialog Box */} |
|
|
|
|
|
<Dialog |
|
|
|
|
|
open={isDialogOpen} |
|
|
|
|
|
onClose={handleCloseDialog} |
|
|
|
|
|
fullWidth |
|
|
|
|
|
maxWidth="sm" |
|
|
|
|
|
// Prevent closing when upload is active |
|
|
|
|
|
disableEscapeKeyDown={isUploading} |
|
|
|
|
|
TransitionProps={{ onExited: handleCloseDialog }} |
|
|
|
|
|
> |
|
|
|
|
|
<DialogTitle> |
|
|
|
|
|
Upload Signature Page (1-Page PDF) |
|
|
|
|
|
</DialogTitle> |
|
|
|
|
|
<DialogContent dividers> |
|
|
|
|
|
<Typography gutterBottom> |
|
|
|
|
|
Please select the single-page PDF file containing the signature for record ID: **{currentRowId}**. |
|
|
|
|
|
</Typography> |
|
|
|
|
|
|
|
|
|
|
|
<Box sx={{ mt: 2, textAlign: 'center' }}> |
|
|
|
|
|
{/* Button to trigger file selection */} |
|
|
|
|
|
<Button |
|
|
|
|
|
variant="contained" |
|
|
|
|
|
color="primary" |
|
|
|
|
|
startIcon={isUploading ? <CircularProgress size={20} color="inherit" /> : <UploadFileIcon />} |
|
|
|
|
|
onClick={handleChooseFile} |
|
|
|
|
|
disabled={isUploading} |
|
|
|
|
|
> |
|
|
|
|
|
{isUploading ? 'Uploading...' : 'Choose PDF File'} |
|
|
|
|
|
</Button> |
|
|
|
|
|
|
|
|
|
|
|
{/* Hidden File Input */} |
|
|
|
|
|
<input |
|
|
|
|
|
ref={fileInputRef} |
|
|
|
|
|
type="file" |
|
|
|
|
|
accept="application/pdf" |
|
|
|
|
|
onChange={handleFileChange} |
|
|
|
|
|
style={{ display: 'none' }} |
|
|
|
|
|
disabled={isUploading} |
|
|
|
|
|
/> |
|
|
|
|
|
|
|
|
|
|
|
{/* Display the selected file name if a file is chosen */} |
|
|
|
|
|
{fileInputRef.current?.files[0] && ( |
|
|
|
|
|
<Typography variant="body2" sx={{ mt: 1 }}> |
|
|
|
|
|
Selected: **{fileInputRef.current.files[0].name}** |
|
|
|
|
|
</Typography> |
|
|
|
|
|
)} |
|
|
|
|
|
</Box> |
|
|
|
|
|
|
|
|
|
|
|
</DialogContent> |
|
|
|
|
|
<DialogActions> |
|
|
|
|
|
<Button onClick={handleCloseDialog} color="inherit" disabled={isUploading}> |
|
|
|
|
|
Cancel |
|
|
|
|
|
</Button> |
|
|
|
|
|
</DialogActions> |
|
|
|
|
|
</Dialog> |
|
|
</div> |
|
|
</div> |
|
|
); |
|
|
); |
|
|
} |
|
|
|
|
|
|
|
|
} |