| @@ -10,7 +10,11 @@ import { | |||||
| import EditIcon from '@mui/icons-material/Edit'; | import EditIcon from '@mui/icons-material/Edit'; | ||||
| import UploadFileIcon from '@mui/icons-material/UploadFile'; | import UploadFileIcon from '@mui/icons-material/UploadFile'; | ||||
| import CheckCircleIcon from '@mui/icons-material/CheckCircle'; | 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 FileDownloadIcon from '@mui/icons-material/FileDownload'; | ||||
| import DownloadDoneIcon from '@mui/icons-material/DownloadDone'; | |||||
| import { | import { | ||||
| Dialog, | Dialog, | ||||
| DialogTitle, | DialogTitle, | ||||
| @@ -96,9 +100,12 @@ export default function PdfTable({recordList}) { | |||||
| setIsDialogOpen(true); | setIsDialogOpen(true); | ||||
| }; | }; | ||||
| /** | |||||
| * Handles the standard download (fillable file, endpoint: /download-ff/{id}) | |||||
| */ | |||||
| const handleDownloadClick = (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}`; | const downloadUrl = `${apiPath}/pdf/download-ff/${id}`; | ||||
| // Use axios to fetch the PDF as a Blob | // Use axios to fetch the PDF as a Blob | ||||
| @@ -113,7 +120,6 @@ export default function PdfTable({recordList}) { | |||||
| if (contentDisposition) { | if (contentDisposition) { | ||||
| // Regex to find filename="name.pdf" or filename*=UTF-8''name.pdf | // 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\*?=['"]?([^'"]+)/); | const filenameMatch = contentDisposition.match(/filename\*?=['"]?([^'"]+)/); | ||||
| if (filenameMatch && filenameMatch[1]) { | if (filenameMatch && filenameMatch[1]) { | ||||
| // Decode URI component and remove extra quotes | // 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 = () => { | const handleCloseDialog = () => { | ||||
| setIsDialogOpen(false); | setIsDialogOpen(false); | ||||
| setCurrentUploadRow(initialUploadState); // Reset the current row | setCurrentUploadRow(initialUploadState); // Reset the current row | ||||
| @@ -203,7 +257,7 @@ export default function PdfTable({recordList}) { | |||||
| // Function to handle file selection and API submission | // Function to handle file selection and API submission | ||||
| const handleFileChange = async (event) => { | const handleFileChange = async (event) => { | ||||
| const file = event.target.files[0]; | 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; | if (!file || !id || !refType) return; | ||||
| @@ -327,16 +381,16 @@ export default function PdfTable({recordList}) { | |||||
| cellClassName: 'actions', | cellClassName: 'actions', | ||||
| getActions: ({ id, row }) => { | 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 isUploaded1 = !!row.upload1FileId; | ||||
| const isUploaded2 = !!row.upload2FileId; // <<< ADD THIS LINE <<< | |||||
| const isUploaded2 = !!row.upload2FileId; | |||||
| const templateName = row.templateName; | const templateName = row.templateName; | ||||
| const formCode = row.formCode; | 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 | const upload1Icon = isUploaded1 | ||||
| ? <CheckCircleIcon sx={{fontSize: 25, color: 'success.main'}} /> // Green tick if uploaded | ? <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"; | const upload1Label = isUploaded1 ? "Update Signature" : "Upload Signature"; | ||||
| @@ -347,29 +401,29 @@ export default function PdfTable({recordList}) { | |||||
| icon={upload1Icon} // Use the dynamic icon | icon={upload1Icon} // Use the dynamic icon | ||||
| label={upload1Label} // Use the dynamic label | label={upload1Label} // Use the dynamic label | ||||
| className="textPrimary" | 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> | </ThemeProvider> | ||||
| ]; | ]; | ||||
| // Conditional rendering logic for Upload 2 | // Conditional rendering logic for Upload 2 | ||||
| if (row.formCode === "MLB03S" || row.formCode === "SLGII" || row.formCode === "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 <<< | |||||
| // FIX 5: Use conditional colors for Upload 2 | |||||
| const upload2Icon = isUploaded2 | const upload2Icon = isUploaded2 | ||||
| ? <CheckCircleIcon sx={{fontSize: 25, color: 'success.main'}} /> // Green tick if uploaded | ? <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"; | const upload2Label = isUploaded2 ? "Update 2" : "Upload 2"; | ||||
| // >>> END CHANGES HERE <<< | |||||
| actions.push( | actions.push( | ||||
| <ThemeProvider key="UploadSign2" theme={LIONER_BUTTON_THEME}> | <ThemeProvider key="UploadSign2" theme={LIONER_BUTTON_THEME}> | ||||
| <GridActionsCellItem | <GridActionsCellItem | ||||
| icon={upload2Icon} // <<< USE DYNAMIC ICON <<< | |||||
| label={upload2Label} // <<< USE DYNAMIC LABEL <<< | |||||
| icon={upload2Icon} | |||||
| label={upload2Label} | |||||
| className="textPrimary" | className="textPrimary" | ||||
| onClick={handleUpload2Click(id, templateName, formCode)} // Pass templateName here | |||||
| onClick={handleUpload2Click(id, templateName, formCode)} | |||||
| color="upload" | color="upload" | ||||
| /> | /> | ||||
| </ThemeProvider> | </ThemeProvider> | ||||
| @@ -380,7 +434,7 @@ export default function PdfTable({recordList}) { | |||||
| }, | }, | ||||
| }, | }, | ||||
| { | { | ||||
| field: 'actions2', | |||||
| field: 'download_live', | |||||
| type: 'actions', | type: 'actions', | ||||
| headerName: 'Download', | headerName: 'Download', | ||||
| width: 100, | width: 100, | ||||
| @@ -393,7 +447,34 @@ export default function PdfTable({recordList}) { | |||||
| label="Download" | label="Download" | ||||
| className="textPrimary" | className="textPrimary" | ||||
| onClick={handleDownloadClick(id)} | 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> | </ThemeProvider> | ||||
| ] | ] | ||||