diff --git a/components/case/representation/representationElements.js b/components/case/representation/representationElements.js
index 65c38700..db0675b3 100644
--- a/components/case/representation/representationElements.js
+++ b/components/case/representation/representationElements.js
@@ -1042,7 +1042,9 @@ export const RenderFileUpload = (field) => {
});
};
+ const [errorMessage, setErrorMessage] = useState(null);
const [rejectedFiles, setRejectedFiles] = useState([]); // Store rejected files
+
const [completedUploadFiles, setCompletedUploadFiles] = useState(false);
const [uploadCountMessage, setUploadCountMessage] = useState("");
@@ -1060,6 +1062,15 @@ export const RenderFileUpload = (field) => {
"myrepresentations:fileupload-file-error-invalid-type-label"
)}`;
}
+
+ if (error.code === "filename-invalid-chars") {
+ return (
+ error.message ||
+ `${file.name} ${t(
+ "newappeal:new-appeal-fileupload-file-error-invalid-filename-label"
+ )}`
+ );
+ }
return `${file.name} ${t(
"myrepresentations:fileupload-file-error-invalid-label"
)}`;
@@ -1076,6 +1087,44 @@ export const RenderFileUpload = (field) => {
setRejectedFiles([]); // Clear any previously rejected file errorsss
};
+ const FILENAME_ALLOWED = /^[A-Za-z0-9 ._\-()]+$/;
+
+ const validateFilename = (file, t) => {
+ const name = file.name;
+
+ // block #
+ if (name.includes("#")) {
+ return {
+ code: "filename-invalid-chars",
+ message: `${name} ${t(
+ "myrepresentations:fileupload-file-error-invalid-filename-label"
+ )}`,
+ };
+ }
+
+ // broader blocklist (optional but recommended)
+ if (!FILENAME_ALLOWED.test(name)) {
+ return {
+ code: "filename-invalid-chars",
+ message: `${name} ${t(
+ "myrepresentations:fileupload-file-error-invalid-filename-label"
+ )}`,
+ };
+ }
+
+ // block characters < > : " / \ | ? *
+ if (/[<>:"/\\|?*]/.test(name)) {
+ return {
+ code: "filename-invalid-chars",
+ message: `${name} ${t(
+ "myrepresentations:fileupload-file-error-invalid-filename-label"
+ )}`,
+ };
+ }
+
+ return null; // valid
+ };
+
return (
<>
{
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":
[".xlsx"],
}}
- onDrop={(filesToUpload, e) => {
+ validator={(file) => validateFilename(file, t)}
+ onDrop={(acceptedFiles, fileRejections, e) => {
+ // build + display rejected messages (ALWAYS, even if some accepted)
+ if (fileRejections?.length) {
+ handleDropRejected(fileRejections);
+ } else {
+ // only clear rejections when nothing was rejected on this drop
+ setRejectedFiles([]);
+ setErrorMessage(null);
+ }
+
+ // if nothing accepted, stop (prevents showing only "uploading" when all invalid)
+ if (!acceptedFiles || acceptedFiles.length === 0) {
+ setCompletedUploadFiles(true); // optional: depends on your UX
+ setUploadCountMessage(0);
+ return;
+ }
+
setCompletedUploadFiles(false);
- const renamedAcceptedFiles = filesToUpload.map(
+
+ const renamedAcceptedFiles = acceptedFiles.map(
(file) =>
new File(
[file],
@@ -1115,7 +1182,16 @@ export const RenderFileUpload = (field) => {
}
)
);
+
field.input.onChange(renamedAcceptedFiles);
+
+ if (typeof field.setFileCount === "function") {
+ field.setFileCount(
+ (field.uploadCount || 0) +
+ renamedAcceptedFiles.length
+ );
+ }
+
setUploadCountMessage(renamedAcceptedFiles.length);
uploadSingleFile(
@@ -1196,8 +1272,6 @@ export const RenderFileUpload = (field) => {
});
});
}}
- onDropRejected={handleDropRejected}
- onDropAccepted={handleDropAccepted}
>
{({ getRootProps, getInputProps }) => (
<>
@@ -1224,7 +1298,7 @@ export const RenderFileUpload = (field) => {
>
)}
- {rejectedFiles.length > 0 && completedUploadFiles == true && (
+ {rejectedFiles.length > 0 && (
{
};
export function FileUploadField(props) {
+ const uploadCount =
+ typeof props.uploadCount === "number" ? props.uploadCount : 0;
+ const setFileCount =
+ typeof props.setFileCount === "function"
+ ? props.setFileCount
+ : () => {};
+
return (
<>
@@ -2144,6 +2151,14 @@ const RenderFileUpload = (field) => {
"newappeal:new-appeal-fileupload-file-error-invalid-type-label"
)}`;
}
+ if (error.code === "filename-invalid-chars") {
+ return (
+ error.message ||
+ `${file.name} ${t(
+ "newappeal:new-appeal-fileupload-file-error-invalid-filename-label"
+ )}`
+ );
+ }
return `${file.name} ${t(
"newappeal:new-appeal-fileupload-file-error-invalid-label"
)}`;
@@ -2160,6 +2175,44 @@ const RenderFileUpload = (field) => {
setRejectedFiles([]); // Clear any previously rejected file errorsss
};
+ const FILENAME_ALLOWED = /^[A-Za-z0-9 ._\-()]+$/;
+
+ const validateFilename = (file, t) => {
+ const name = file.name;
+
+ // block #
+ if (name.includes("#")) {
+ return {
+ code: "filename-invalid-chars",
+ message: `${name} ${t(
+ "newappeal:new-appeal-fileupload-file-error-invalid-filename-label"
+ )}`,
+ };
+ }
+
+ // broader blocklist (optional but recommended)
+ if (!FILENAME_ALLOWED.test(name)) {
+ return {
+ code: "filename-invalid-chars",
+ message: `${name} ${t(
+ "newappeal:new-appeal-fileupload-file-error-invalid-filename-label"
+ )}`,
+ };
+ }
+
+ // block characters < > : " / \ | ? *
+ if (/[<>:"/\\|?*]/.test(name)) {
+ return {
+ code: "filename-invalid-chars",
+ message: `${name} ${t(
+ "newappeal:new-appeal-fileupload-file-error-invalid-filename-label"
+ )}`,
+ };
+ }
+
+ return null; // valid
+ };
+
return (
<>
{
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":
[".xlsx"],
}}
- onDrop={(filesToUpload, e) => {
+ validator={(file) => validateFilename(file, t)}
+ onDrop={(acceptedFiles, fileRejections, e) => {
+ // build + display rejected messages (ALWAYS, even if some accepted)
+ if (fileRejections?.length) {
+ handleDropRejected(fileRejections);
+ } else {
+ // only clear rejections when nothing was rejected on this drop
+ setRejectedFiles([]);
+ setErrorMessage(null);
+ }
+
+ // if nothing accepted, stop (prevents showing only "uploading" when all invalid)
+ if (!acceptedFiles || acceptedFiles.length === 0) {
+ setCompletedUploadFiles(true); // optional: depends on your UX
+ setUploadCountMessage(0);
+ return;
+ }
+
+ // continue with your existing upload logic for accepted files
setCompletedUploadFiles(false);
- const renamedAcceptedFiles = filesToUpload.map(
+
+ const renamedAcceptedFiles = acceptedFiles.map(
(file) =>
new File(
[file],
`${getDocumentType(field.documentTypeCode)}_-_${
file.name
}`,
- {
- type: file.type,
- }
+ { type: file.type }
)
);
+
field.input.onChange(renamedAcceptedFiles);
- field.setFileCount(
- field.uploadCount + renamedAcceptedFiles.length
- );
+ if (typeof field.setFileCount === "function") {
+ field.setFileCount(
+ (field.uploadCount || 0) +
+ renamedAcceptedFiles.length
+ );
+ }
setUploadCountMessage(renamedAcceptedFiles.length);
@@ -2202,66 +2276,68 @@ const RenderFileUpload = (field) => {
renamedAcceptedFiles,
field.containerID,
field.ticketnumber
- ).then((data) => {
- console.log(data);
- let buildAppealFilesArray = [];
- let values = field.form.appealForm.values;
- let filesUploadObj = renamedAcceptedFiles;
+ )
+ .then((data) => {
+ let buildAppealFilesArray = [];
+ let values = field.form.appealForm.values;
+ let filesUploadObj = renamedAcceptedFiles;
- for (let key in filesUploadObj) {
- typeof filesUploadObj[key].name != "undefined" &&
- buildAppealFilesArray.push({
- "name": filesUploadObj[key].name,
- "size": filesUploadObj[key].size,
+ for (let key in filesUploadObj) {
+ typeof filesUploadObj[key].name !==
+ "undefined" &&
+ buildAppealFilesArray.push({
+ name: filesUploadObj[key].name,
+ size: filesUploadObj[key].size,
+ });
+ }
+
+ function removeDuplicates(arr, key) {
+ const seen = new Set();
+ return arr.filter((item) => {
+ const value = item[key];
+ if (seen.has(value)) return false;
+ seen.add(value);
+ return true;
});
- }
+ }
- //console.log(buildAppealFilesArray);
- function removeDuplicates(arr, key) {
- const seen = new Set();
- return arr.filter((item) => {
- const value = item[key];
- if (seen.has(value)) {
- return false; // Duplicate found
- } else {
- seen.add(value); // Add value to the set
- return true; // Keep the item
- }
+ buildAppealFilesArray = values.hasOwnProperty(
+ "filesList"
+ )
+ ? buildAppealFilesArray.concat(values.filesList)
+ : buildAppealFilesArray;
+
+ buildAppealFilesArray = removeDuplicates(
+ buildAppealFilesArray,
+ "name"
+ );
+
+ Object.assign(values, {
+ filesList: buildAppealFilesArray,
});
- }
- buildAppealFilesArray = values.hasOwnProperty(
- "filesList"
- )
- ? buildAppealFilesArray.concat(values.filesList)
- : buildAppealFilesArray;
+ // keep your existing server-side invalid handling
+ if (data.invalidFiles?.length > 0) {
+ setRejectedFiles((prev) => [
+ ...prev,
+ ...data.invalidFiles,
+ ]);
+ setUploadCountMessage(
+ renamedAcceptedFiles.length -
+ data.invalidFiles.length
+ );
+ }
- buildAppealFilesArray = removeDuplicates(
- buildAppealFilesArray,
- "name"
- );
-
- Object.assign(values, {
- "filesList": buildAppealFilesArray,
- });
- data.invalidFiles.length > 0 &&
- (setRejectedFiles(data.invalidFiles),
- setUploadCountMessage(
- renamedAcceptedFiles.length -
- data.invalidFiles.length
- ));
- getFilesFromBlobproxy(
- field.containerID,
- field.ticketnumber
- ).then((data) => {
- field.input.value == null;
+ return getFilesFromBlobproxy(
+ field.containerID,
+ field.ticketnumber
+ );
+ })
+ .then((data) => {
field.setFilesForAppeal(data);
setCompletedUploadFiles(true);
});
- });
}}
- onDropRejected={handleDropRejected}
- onDropAccepted={handleDropAccepted}
>
{({ getRootProps, getInputProps }) => (
<>
@@ -2288,7 +2364,7 @@ const RenderFileUpload = (field) => {
>
)}
- {rejectedFiles.length > 0 && completedUploadFiles == true && (
+ {rejectedFiles.length > 0 && (
);
// } else {
diff --git a/pages/myportal/representation.js b/pages/myportal/representation.js
index f48fbcea..d344e0a8 100644
--- a/pages/myportal/representation.js
+++ b/pages/myportal/representation.js
@@ -304,6 +304,7 @@ export const getServerSideProps = wrapper.getServerSideProps(
"incidentid": result.incidentID,
"appealType": result.appealType,
"repDetails": result,
+ "filesList": result.filesList,
})
);
@@ -318,7 +319,7 @@ export const getServerSideProps = wrapper.getServerSideProps(
const repsFileListObj = await getRepsFilesBlobs(
result.containerID,
- result.ticketnumber,
+ result.ticketnumber || result.caseRef,
result.repfile_name
);