| @@ -10,7 +10,11 @@ import { | |||
| import EditIcon from '@mui/icons-material/Edit'; | |||
| import UploadFileIcon from '@mui/icons-material/UploadFile'; | |||
| import CheckCircleIcon from '@mui/icons-material/CheckCircle'; | |||
| // FIX 1: Correctly import both download icons from their respective paths | |||
| import FileDownloadIcon from '@mui/icons-material/FileDownload'; | |||
| import DownloadDoneIcon from '@mui/icons-material/DownloadDone'; | |||
| import { | |||
| Dialog, | |||
| DialogTitle, | |||
| @@ -96,9 +100,12 @@ export default function PdfTable({recordList}) { | |||
| setIsDialogOpen(true); | |||
| }; | |||
| /** | |||
| * Handles the standard download (fillable file, endpoint: /download-ff/{id}) | |||
| */ | |||
| const handleDownloadClick = (id) => () => { | |||
| // 1. Construct the download URL with the ID query parameter | |||
| // 1. Construct the download URL for the FILLABLE file | |||
| const downloadUrl = `${apiPath}/pdf/download-ff/${id}`; | |||
| // Use axios to fetch the PDF as a Blob | |||
| @@ -113,7 +120,6 @@ export default function PdfTable({recordList}) { | |||
| 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 | |||
| @@ -142,6 +148,54 @@ export default function PdfTable({recordList}) { | |||
| }); | |||
| }; | |||
| /** | |||
| * Handles the flat download (finalized file, endpoint: /download-flat/{id}) | |||
| */ | |||
| const handleFlatDownloadClick = (id) => () => { | |||
| // 1. Construct the download URL for the FLATTENED file | |||
| const downloadUrl = `${apiPath}/pdf/download-flat/${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-flat-${id}.pdf`; // Fallback filename | |||
| if (contentDisposition) { | |||
| // Regex to find filename="name.pdf" or filename*=UTF-8''name.pdf | |||
| 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(`Flat 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 flattened PDF file. Check server logs.'); | |||
| }); | |||
| }; | |||
| const handleCloseDialog = () => { | |||
| setIsDialogOpen(false); | |||
| setCurrentUploadRow(initialUploadState); // Reset the current row | |||
| @@ -203,7 +257,7 @@ export default function PdfTable({recordList}) { | |||
| // Function to handle file selection and API submission | |||
| const handleFileChange = async (event) => { | |||
| const file = event.target.files[0]; | |||
| const { id, templateName, refType } = currentUploadRow; | |||
| const { id, refType } = currentUploadRow; // Removed templateName as it's not needed for FormData | |||
| if (!file || !id || !refType) return; | |||
| @@ -327,16 +381,16 @@ export default function PdfTable({recordList}) { | |||
| cellClassName: 'actions', | |||
| getActions: ({ id, row }) => { | |||
| // Check if a file ID exists to determine if a file is present for Upload 1 | |||
| // Check upload status | |||
| const isUploaded1 = !!row.upload1FileId; | |||
| const isUploaded2 = !!row.upload2FileId; // <<< ADD THIS LINE <<< | |||
| const isUploaded2 = !!row.upload2FileId; | |||
| const templateName = row.templateName; | |||
| const formCode = row.formCode; | |||
| // Determine the icon and label based on upload status for Upload 1 | |||
| // FIX 5: Use conditional colors 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 | |||
| : <UploadFileIcon sx={{fontSize: 25, color: 'warning.main'}} />; // Warning color if not uploaded | |||
| const upload1Label = isUploaded1 ? "Update Signature" : "Upload Signature"; | |||
| @@ -347,29 +401,29 @@ export default function PdfTable({recordList}) { | |||
| icon={upload1Icon} // Use the dynamic icon | |||
| label={upload1Label} // Use the dynamic label | |||
| className="textPrimary" | |||
| onClick={handleUploadClick(id, templateName, formCode)} // Pass templateName here | |||
| color="upload" // Use 'upload' color which will apply to the button | |||
| onClick={handleUploadClick(id, templateName, formCode)} | |||
| color="upload" | |||
| /> | |||
| </ThemeProvider> | |||
| ]; | |||
| // Conditional rendering logic for Upload 2 | |||
| 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 <<< | |||
| // FIX 5: Use conditional colors for Upload 2 | |||
| const upload2Icon = isUploaded2 | |||
| ? <CheckCircleIcon sx={{fontSize: 25, color: 'success.main'}} /> // Green tick if uploaded | |||
| : <UploadFileIcon sx={{fontSize: 25}}/>; // Upload icon if not uploaded | |||
| : <UploadFileIcon sx={{fontSize: 25, color: 'warning.main'}} />; // Warning color if not uploaded | |||
| const upload2Label = isUploaded2 ? "Update 2" : "Upload 2"; | |||
| // >>> END CHANGES HERE <<< | |||
| actions.push( | |||
| <ThemeProvider key="UploadSign2" theme={LIONER_BUTTON_THEME}> | |||
| <GridActionsCellItem | |||
| icon={upload2Icon} // <<< USE DYNAMIC ICON <<< | |||
| label={upload2Label} // <<< USE DYNAMIC LABEL <<< | |||
| icon={upload2Icon} | |||
| label={upload2Label} | |||
| className="textPrimary" | |||
| onClick={handleUpload2Click(id, templateName, formCode)} // Pass templateName here | |||
| onClick={handleUpload2Click(id, templateName, formCode)} | |||
| color="upload" | |||
| /> | |||
| </ThemeProvider> | |||
| @@ -380,7 +434,7 @@ export default function PdfTable({recordList}) { | |||
| }, | |||
| }, | |||
| { | |||
| field: 'actions2', | |||
| field: 'download_live', | |||
| type: 'actions', | |||
| headerName: 'Download', | |||
| width: 100, | |||
| @@ -393,7 +447,34 @@ export default function PdfTable({recordList}) { | |||
| label="Download" | |||
| className="textPrimary" | |||
| onClick={handleDownloadClick(id)} | |||
| color="download" | |||
| // CHANGED: Use a standard MUI color like "primary" | |||
| color="primary" | |||
| /> | |||
| </ThemeProvider> | |||
| ] | |||
| }, | |||
| }, | |||
| { | |||
| field: 'download_flat', // Unique field name | |||
| type: 'actions', | |||
| headerName: ( | |||
| <div style={{ lineHeight: '1.2' }}> | |||
| Download | |||
| <br /> | |||
| without signature | |||
| </div> | |||
| ), | |||
| width: 100, | |||
| cellClassName: 'actionsFlatDownload', | |||
| getActions: ({id}) => { | |||
| return [ | |||
| <ThemeProvider key="DownloadFlatFile" theme={LIONER_BUTTON_THEME}> | |||
| <GridActionsCellItem | |||
| icon={<FileDownloadIcon sx={{fontSize: 25}}/>} | |||
| label="Download flat" | |||
| className="textPrimary" | |||
| onClick={handleFlatDownloadClick(id)} | |||
| color="default" | |||
| /> | |||
| </ThemeProvider> | |||
| ] | |||