|
|
|
@@ -9,36 +9,44 @@ import { |
|
|
|
} from "@mui/x-data-grid"; |
|
|
|
import EditIcon from '@mui/icons-material/Edit'; |
|
|
|
import UploadFileIcon from '@mui/icons-material/UploadFile'; |
|
|
|
import CheckCircleIcon from '@mui/icons-material/CheckCircle'; |
|
|
|
import CheckCircleIcon from '@mui/icons-material/CheckCircle'; |
|
|
|
import FileDownloadIcon from '@mui/icons-material/FileDownload'; |
|
|
|
import { |
|
|
|
Dialog, |
|
|
|
DialogTitle, |
|
|
|
DialogContent, |
|
|
|
DialogActions, |
|
|
|
Button, |
|
|
|
Dialog, |
|
|
|
DialogTitle, |
|
|
|
DialogContent, |
|
|
|
DialogActions, |
|
|
|
Button, |
|
|
|
Typography, |
|
|
|
Box, // for centering and layout |
|
|
|
CircularProgress, // Import for loading indicator |
|
|
|
Box, |
|
|
|
CircularProgress, |
|
|
|
} from '@mui/material'; |
|
|
|
import {useContext, useEffect} from "react"; |
|
|
|
import {useNavigate} from "react-router-dom"; |
|
|
|
// Note: Assuming these utility functions/components are defined elsewhere |
|
|
|
import {CustomNoRowsOverlay, dateComparator, getDateString} from "../../../utils/CommonFunction"; |
|
|
|
import {CustomNoRowsOverlay, dateComparator, getDateString} from "../../../utils/CommonFunction"; |
|
|
|
import AbilityContext from "../../../components/AbilityProvider"; |
|
|
|
import {LIONER_BUTTON_THEME} from "../../../themes/colorConst"; |
|
|
|
import {ThemeProvider} from "@emotion/react"; |
|
|
|
|
|
|
|
// ==============================|| PDF TABLE ||============================== // |
|
|
|
|
|
|
|
// Define the structure for the row data stored in state |
|
|
|
const initialUploadState = { |
|
|
|
id: null, |
|
|
|
templateName: null, // This will be the formCode |
|
|
|
refType: null, // To differentiate between upload1 and upload2 if needed |
|
|
|
} |
|
|
|
|
|
|
|
export default function PdfTable({recordList}) { |
|
|
|
const [rows, setRows] = React.useState(recordList); |
|
|
|
const [rowModesModel] = React.useState({}); |
|
|
|
|
|
|
|
// State for Dialog visibility, row ID, and Loading state |
|
|
|
// State for Dialog visibility and Loading state |
|
|
|
const [isDialogOpen, setIsDialogOpen] = React.useState(false); |
|
|
|
const [currentRowId, setCurrentRowId] = React.useState(null); |
|
|
|
const [isUploading, setIsUploading] = React.useState(false); |
|
|
|
// State to hold the ID, templateName, and refType for the current upload operation |
|
|
|
const [currentUploadRow, setCurrentUploadRow] = React.useState(initialUploadState); |
|
|
|
const [isUploading, setIsUploading] = React.useState(false); |
|
|
|
|
|
|
|
const navigate = useNavigate() |
|
|
|
const ability = useContext(AbilityContext); |
|
|
|
@@ -47,7 +55,7 @@ export default function PdfTable({recordList}) { |
|
|
|
page: 0, |
|
|
|
pageSize:10 |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
// Ref for the hidden file input |
|
|
|
const fileInputRef = React.useRef(null); |
|
|
|
|
|
|
|
@@ -60,21 +68,36 @@ export default function PdfTable({recordList}) { |
|
|
|
navigate(`/pdf/maintain/${id}`); |
|
|
|
}; |
|
|
|
|
|
|
|
// Opens the upload dialog and sets the current row ID |
|
|
|
const handleUploadClick = (id) => () => { |
|
|
|
setCurrentRowId(id); |
|
|
|
/** |
|
|
|
* Opens the upload dialog and sets the current row details for Upload 1 |
|
|
|
*/ |
|
|
|
const handleUploadClick = (id, templateName, formCode) => () => { |
|
|
|
setCurrentUploadRow({ |
|
|
|
id: id, |
|
|
|
templateName: templateName, |
|
|
|
formCode: formCode, |
|
|
|
refType: "upload1" |
|
|
|
}); |
|
|
|
setIsDialogOpen(true); |
|
|
|
}; |
|
|
|
|
|
|
|
const handleUpload2Click = (id, templateName) => () => { |
|
|
|
/** |
|
|
|
* Opens the upload dialog and sets the current row details for Upload 2 |
|
|
|
*/ |
|
|
|
const handleUpload2Click = (id, templateName, formCode) => () => { |
|
|
|
// Placeholder for Upload 2 |
|
|
|
console.log(`Uploading for row ID ${id} (Upload 2)`); |
|
|
|
setCurrentRowId(id); |
|
|
|
setCurrentUploadRow({ |
|
|
|
id: id, |
|
|
|
templateName: templateName, |
|
|
|
formCode: formCode, |
|
|
|
refType: "upload2" // A different refType for a different upload logic/API |
|
|
|
}); |
|
|
|
setIsDialogOpen(true); |
|
|
|
}; |
|
|
|
|
|
|
|
const handleDownloadClick = (id) => () => { |
|
|
|
|
|
|
|
|
|
|
|
// 1. Construct the download URL with the ID query parameter |
|
|
|
const downloadUrl = `${apiPath}/pdf/download-ff/${id}`; |
|
|
|
|
|
|
|
@@ -83,7 +106,7 @@ export default function PdfTable({recordList}) { |
|
|
|
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 |
|
|
|
@@ -102,12 +125,12 @@ export default function PdfTable({recordList}) { |
|
|
|
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); |
|
|
|
link.setAttribute('download', filename); |
|
|
|
document.body.appendChild(link); |
|
|
|
link.click(); |
|
|
|
|
|
|
|
|
|
|
|
// 4. Clean up |
|
|
|
document.body.removeChild(link); |
|
|
|
window.URL.revokeObjectURL(url); |
|
|
|
@@ -121,17 +144,68 @@ export default function PdfTable({recordList}) { |
|
|
|
|
|
|
|
const handleCloseDialog = () => { |
|
|
|
setIsDialogOpen(false); |
|
|
|
setCurrentRowId(null); |
|
|
|
setCurrentUploadRow(initialUploadState); // Reset the current row |
|
|
|
if (fileInputRef.current) { |
|
|
|
fileInputRef.current.value = ""; // Clear the file input |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
// Function to generate the dynamic dialog title |
|
|
|
const getUploadDialogTitle = (formCode, refType) => { |
|
|
|
console.log("formCode:" + formCode + " refType:" + refType); |
|
|
|
if (refType === 'upload1') { |
|
|
|
switch (formCode) { |
|
|
|
case "IDA": |
|
|
|
return "Upload Page 12"; |
|
|
|
case "FNA": |
|
|
|
return "Upload Page 7"; |
|
|
|
case "HSBCFIN": |
|
|
|
return "Upload Page 11"; |
|
|
|
case "HSBCA31": |
|
|
|
return "Upload Page 28-29"; |
|
|
|
case "MLB03S": |
|
|
|
return "Upload Page 7"; |
|
|
|
case "MLFNA_EN": |
|
|
|
return "Upload Page 4"; |
|
|
|
case "MLFNA_CHI": |
|
|
|
return "Upload Page 4"; |
|
|
|
case "SLGII": |
|
|
|
return "Upload Page 13"; |
|
|
|
case "SLAPP": |
|
|
|
return "Upload Page 16"; |
|
|
|
case "SLFNA_EN": |
|
|
|
return "Upload Page 5"; |
|
|
|
case "SLFNA_CHI": |
|
|
|
return "Upload Page 5"; |
|
|
|
default: |
|
|
|
return "Unknown Form"; |
|
|
|
} |
|
|
|
}else if (refType === 'upload2') { |
|
|
|
switch (formCode) { |
|
|
|
case "MLB03S": |
|
|
|
return "Upload Page 12"; |
|
|
|
case "SLGII": |
|
|
|
return "Upload Page 15-16"; |
|
|
|
case "SLAPP": |
|
|
|
return "Upload Page 18-19"; |
|
|
|
default: |
|
|
|
return "Unknown Form"; |
|
|
|
} |
|
|
|
} |
|
|
|
// Handle other refTypes if needed, e.g., 'upload2' |
|
|
|
if (refType === 'upload2') { |
|
|
|
return `Upload Template 2 for ${formCode}`; |
|
|
|
} |
|
|
|
|
|
|
|
return "Upload File"; // Fallback |
|
|
|
}; |
|
|
|
|
|
|
|
// Function to handle file selection and API submission |
|
|
|
const handleFileChange = async (event) => { |
|
|
|
const file = event.target.files[0]; |
|
|
|
|
|
|
|
if (!file) return; |
|
|
|
const { id, templateName, refType } = currentUploadRow; |
|
|
|
|
|
|
|
if (!file || !id || !refType) return; |
|
|
|
|
|
|
|
if (file.type !== "application/pdf") { |
|
|
|
alert("Please select a PDF file."); |
|
|
|
@@ -139,43 +213,58 @@ export default function PdfTable({recordList}) { |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
const uploadUrl = apiPath + '/pdf/upload1'; |
|
|
|
// The URL should potentially change based on refType if upload2 uses a different endpoint |
|
|
|
const uploadUrl = `${apiPath}${POST_SIG_UPLOAD1}`; // Assuming POST_SIG_UPLOAD1 is used for both for now |
|
|
|
|
|
|
|
// 1. Create FormData |
|
|
|
const formData = new FormData(); |
|
|
|
formData.append('file', file); |
|
|
|
formData.append('refId', currentRowId); |
|
|
|
formData.append('refType', "upload1"); |
|
|
|
formData.append('refId', id); |
|
|
|
formData.append('refType', refType); // Pass the refType to the backend |
|
|
|
setIsUploading(true); |
|
|
|
|
|
|
|
try { |
|
|
|
axios.post(`${apiPath}${POST_SIG_UPLOAD1}`, |
|
|
|
const response = await axios.post( |
|
|
|
uploadUrl, |
|
|
|
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}!`); |
|
|
|
); |
|
|
|
|
|
|
|
if (response.status === 200) { |
|
|
|
alert('Upload success'); |
|
|
|
console.log(`PDF file ${file.name} successfully uploaded for record ID: ${id} with refType: ${refType}!`); |
|
|
|
|
|
|
|
// --- START: Update local state to show the green tick --- |
|
|
|
const uploadedFileId = response.data?.fileId || 'temp-id-' + Date.now(); // Assume the response has a fileId or use a temp one |
|
|
|
|
|
|
|
setRows(prevRows => |
|
|
|
prevRows.map(row => { |
|
|
|
if (row.id === id) { |
|
|
|
// Update the relevant file ID field based on refType |
|
|
|
const updateField = refType === 'upload1' ? 'upload1FileId' : 'upload2FileId'; |
|
|
|
return { |
|
|
|
...row, |
|
|
|
[updateField]: uploadedFileId // Set the file ID to trigger the icon |
|
|
|
}; |
|
|
|
} |
|
|
|
return row; |
|
|
|
}) |
|
|
|
); |
|
|
|
// --- END: Update local state to show the green tick --- |
|
|
|
|
|
|
|
} else { |
|
|
|
throw new Error(`Upload failed with status: ${response.status}`); |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
setIsUploading(false); |
|
|
|
}) |
|
|
|
.catch((error) => { |
|
|
|
setIsUploading(false); |
|
|
|
console.log(error); |
|
|
|
return false; |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
} catch (error) { |
|
|
|
console.error('Upload error:', error); |
|
|
|
alert(`Error uploading file: ${error.message}`); |
|
|
|
// Check if the error has a response and use its message if available |
|
|
|
const errorMessage = error.response?.data?.message || error.message; |
|
|
|
alert(`Error uploading file: ${errorMessage}`); |
|
|
|
} finally { |
|
|
|
// 3. Cleanup and close |
|
|
|
setIsUploading(false); |
|
|
|
@@ -189,7 +278,7 @@ export default function PdfTable({recordList}) { |
|
|
|
fileInputRef.current.click(); |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
const columns = [ |
|
|
|
{ |
|
|
|
field: 'actions', |
|
|
|
@@ -211,7 +300,7 @@ export default function PdfTable({recordList}) { |
|
|
|
] |
|
|
|
}, |
|
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
{ |
|
|
|
id: 'templateName', |
|
|
|
field: 'templateName', |
|
|
|
@@ -237,16 +326,19 @@ export default function PdfTable({recordList}) { |
|
|
|
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 |
|
|
|
|
|
|
|
// Check if a file ID exists to determine if a file is present for Upload 1 |
|
|
|
const isUploaded1 = !!row.upload1FileId; |
|
|
|
const isUploaded2 = !!row.upload2FileId; // <<< ADD THIS LINE <<< |
|
|
|
const templateName = row.templateName; |
|
|
|
const formCode = row.formCode; |
|
|
|
|
|
|
|
// Determine the icon and label based on upload status for Upload 1 |
|
|
|
const upload1Icon = isUploaded1 |
|
|
|
? <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"; |
|
|
|
|
|
|
|
const upload1Label = isUploaded1 ? "Update Signature" : "Upload Signature"; |
|
|
|
|
|
|
|
// Define the actions |
|
|
|
const actions = [ |
|
|
|
@@ -255,21 +347,29 @@ export default function PdfTable({recordList}) { |
|
|
|
icon={upload1Icon} // Use the dynamic icon |
|
|
|
label={upload1Label} // Use the dynamic label |
|
|
|
className="textPrimary" |
|
|
|
onClick={handleUploadClick(id)} |
|
|
|
onClick={handleUploadClick(id, templateName, formCode)} // Pass templateName here |
|
|
|
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") { |
|
|
|
if (row.formCode === "MLB03S" || row.formCode === "SLGII" || row.formCode === "SLAPP") { |
|
|
|
// Determine the icon and label based on upload status for Upload 2 <<< START CHANGES HERE <<< |
|
|
|
const upload2Icon = isUploaded2 |
|
|
|
? <CheckCircleIcon sx={{fontSize: 25, color: 'success.main'}} /> // Green tick if uploaded |
|
|
|
: <UploadFileIcon sx={{fontSize: 25}}/>; // Upload icon if not uploaded |
|
|
|
|
|
|
|
const upload2Label = isUploaded2 ? "Update 2" : "Upload 2"; |
|
|
|
// >>> END CHANGES HERE <<< |
|
|
|
|
|
|
|
actions.push( |
|
|
|
<ThemeProvider key="UploadSign2" theme={LIONER_BUTTON_THEME}> |
|
|
|
<GridActionsCellItem |
|
|
|
icon={<UploadFileIcon sx={{fontSize: 25}}/>} |
|
|
|
label="Upload2" |
|
|
|
icon={upload2Icon} // <<< USE DYNAMIC ICON <<< |
|
|
|
label={upload2Label} // <<< USE DYNAMIC LABEL <<< |
|
|
|
className="textPrimary" |
|
|
|
onClick={handleUpload2Click(id, row.templateName)} |
|
|
|
onClick={handleUpload2Click(id, templateName, formCode)} // Pass templateName here |
|
|
|
color="upload" |
|
|
|
/> |
|
|
|
</ThemeProvider> |
|
|
|
@@ -292,7 +392,7 @@ export default function PdfTable({recordList}) { |
|
|
|
icon={<FileDownloadIcon sx={{fontSize: 25}}/>} |
|
|
|
label="Download" |
|
|
|
className="textPrimary" |
|
|
|
onClick={handleDownloadClick(id, "{params.row.templateName}")} |
|
|
|
onClick={handleDownloadClick(id)} |
|
|
|
color="download" |
|
|
|
/> |
|
|
|
</ThemeProvider> |
|
|
|
@@ -344,7 +444,7 @@ export default function PdfTable({recordList}) { |
|
|
|
rows={rows} |
|
|
|
columns={columns} |
|
|
|
// Increased height to accommodate the multi-line header |
|
|
|
columnHeaderHeight={70} |
|
|
|
columnHeaderHeight={70} |
|
|
|
editMode="row" |
|
|
|
rowModesModel={rowModesModel} |
|
|
|
getRowHeight={() => 'auto'} |
|
|
|
@@ -358,25 +458,22 @@ export default function PdfTable({recordList}) { |
|
|
|
pageSizeOptions={[10]} |
|
|
|
autoHeight |
|
|
|
/> |
|
|
|
|
|
|
|
|
|
|
|
{/* The Upload Dialog Box */} |
|
|
|
<Dialog |
|
|
|
open={isDialogOpen} |
|
|
|
onClose={handleCloseDialog} |
|
|
|
fullWidth |
|
|
|
<Dialog |
|
|
|
open={isDialogOpen} |
|
|
|
onClose={handleCloseDialog} |
|
|
|
fullWidth |
|
|
|
maxWidth="sm" |
|
|
|
// Prevent closing when upload is active |
|
|
|
disableEscapeKeyDown={isUploading} |
|
|
|
disableEscapeKeyDown={isUploading} |
|
|
|
TransitionProps={{ onExited: handleCloseDialog }} |
|
|
|
> |
|
|
|
<DialogTitle> |
|
|
|
Upload Signature Page (1-Page PDF) |
|
|
|
{/* Dynamic Title based on currentUploadRow state */} |
|
|
|
**{getUploadDialogTitle(currentUploadRow.formCode, currentUploadRow.refType)}** |
|
|
|
</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 |
|
|
|
@@ -394,11 +491,11 @@ export default function PdfTable({recordList}) { |
|
|
|
ref={fileInputRef} |
|
|
|
type="file" |
|
|
|
accept="application/pdf" |
|
|
|
onChange={handleFileChange} |
|
|
|
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 }}> |
|
|
|
@@ -406,7 +503,7 @@ export default function PdfTable({recordList}) { |
|
|
|
</Typography> |
|
|
|
)} |
|
|
|
</Box> |
|
|
|
|
|
|
|
|
|
|
|
</DialogContent> |
|
|
|
<DialogActions> |
|
|
|
<Button onClick={handleCloseDialog} color="inherit" disabled={isUploading}> |
|
|
|
|