diff --git a/src/applications/simple-forms/40-0247/components/FileField.jsx b/src/applications/simple-forms/40-0247/components/FileField.jsx
index 9747c221f463..e4595ea6daba 100644
--- a/src/applications/simple-forms/40-0247/components/FileField.jsx
+++ b/src/applications/simple-forms/40-0247/components/FileField.jsx
@@ -1,14 +1,12 @@
/* eslint-disable jsx-a11y/no-noninteractive-element-to-interactive-role */
-/* Customized copy of Platform's FileField component
- * - Adds new optional prop `ariaLabelAdditionalText` to append additional
- * text to the upload button's aria-label attribute.
-*/
import PropTypes from 'prop-types';
import React, { useEffect, useState, useRef } from 'react';
import { connect } from 'react-redux';
import classNames from 'classnames';
import { VaModal } from '@department-of-veterans-affairs/component-library/dist/react-bindings';
+import environment from 'platform/utilities/environment';
+
import { toggleValues } from 'platform/site-wide/feature-toggles/selectors';
import get from 'platform/utilities/data/get';
import set from 'platform/utilities/data/set';
@@ -21,6 +19,7 @@ import {
} from 'platform/utilities/ui';
import { FILE_UPLOAD_NETWORK_ERROR_MESSAGE } from 'platform/forms-system/src/js/constants';
+import { ERROR_ELEMENTS } from 'platform/utilities/constants';
import { $ } from 'platform/forms-system/src/js/utilities/ui';
import {
ShowPdfPassword,
@@ -32,6 +31,7 @@ import {
FILE_TYPE_MISMATCH_ERROR,
} from 'platform/forms-system/src/js/utilities/file';
import { usePreviousValue } from 'platform/forms-system/src/js/helpers';
+import { MISSING_PASSWORD_ERROR } from 'platform/forms-system/src/js/validation';
/**
* Modal content callback
@@ -48,7 +48,7 @@ import { usePreviousValue } from 'platform/forms-system/src/js/helpers';
* @property {string} buttonText='Upload' - upload button text
* @property {string} addAnotherLabel='Upload another' - upload another text,
* replaces upload button text when greater than one upload is showing
- * @property {string} ariaLabelAdditionalText='' - additional screen-reader text to be appended to upload button's aria-label attribute.
+ * @property {string} ariaLabelAdditionalText additional screen-reader text to be appended to upload button's aria-label attribute.
* @property {string} tryAgain='Try again' - button in enableShortWorkflow
* @property {string} newFile='Upload a new file' - button in enableShortWorkflow
* @property {string} cancel='Cancel' - button visible while uploading & in enableShortWorkflow
@@ -274,6 +274,18 @@ const FileField = props => {
return;
}
+ // MBMS-66936 prod flag
+ if (!environment.isProduction() && checkResults.checkIsEncryptedPdf) {
+ allFiles[idx] = {
+ file: currentFile,
+ name: 'Upload additional evidence',
+ errorMessage:
+ 'We weren’t able to upload your file. Make sure the file is not encrypted and is an accepted format.',
+ };
+ props.onChange(allFiles);
+ return;
+ }
+
if (!checkResults.checkTypeAndExtensionMatches) {
allFiles[idx] = {
file: currentFile,
@@ -420,6 +432,302 @@ const FileField = props => {
const uploadText = content[files.length > 0 ? 'uploadAnother' : 'upload'];
+ // MBMS-66936 prod flag
+ if (!environment.isProduction()) {
+ return (
+
+
closeRemoveModal({ remove: true })}
+ onSecondaryButtonClick={closeRemoveModal}
+ visible={showRemoveModal}
+ uswds
+ >
+
+ {removeIndex !== null
+ ? content.modalContent(files[removeIndex]?.name)
+ : null}
+
+
+ {files.length > 0 && (
+
+ {files.map((file, index) => {
+ const errors =
+ errorSchema?.[index]?.__errors ||
+ [file.errorMessage].filter(error => error);
+
+ // Don't show missing password error in the card (above the input
+ // label), but we are adding an error for missing password to
+ // prevent page submission without adding an error; see #71406
+ const hasVisibleError =
+ errors.length > 0 && errors[0] !== MISSING_PASSWORD_ERROR;
+
+ const itemClasses = classNames('va-growable-background', {
+ 'schemaform-file-error usa-input-error':
+ hasVisibleError && !file.uploading,
+ });
+ const itemSchema = schema.items[index];
+ const attachmentIdSchema = {
+ $id: `${idSchema.$id}_${index}_attachmentId`,
+ };
+ const attachmentNameSchema = {
+ $id: `${idSchema.$id}_${index}_attachmentName`,
+ };
+ const attachmentIdErrors = get(
+ [index, 'attachmentId'],
+ errorSchema,
+ );
+ const attachmentNameErrors = get([index, 'name'], errorSchema);
+ const showPasswordInput =
+ file.isEncrypted && !file.confirmationCode;
+ const showPasswordSuccess =
+ file.isEncrypted && file.confirmationCode;
+ const description =
+ (!file.uploading && uiOptions.itemDescription) || '';
+
+ const fileListId = getFileListId(index);
+ const fileNameId = `${idSchema.$id}_file_name_${index}`;
+
+ if (hasVisibleError) {
+ setTimeout(() => {
+ scrollToFirstError();
+ if (enableShortWorkflow) {
+ const retryButton = $(`[name="retry_upload_${index}"]`);
+ if (retryButton) {
+ focusElement('button', {}, retryButton?.shadowRoot);
+ }
+ } else if (showPasswordInput) {
+ focusElement(`#${fileListId} .usa-input-error-message`);
+ } else {
+ focusElement(ERROR_ELEMENTS.join(','));
+ }
+ }, 250);
+ } else if (showPasswordInput) {
+ setTimeout(() => {
+ const passwordInput = $(`[name="get_password_${index}"]`);
+ if (passwordInput) {
+ focusElement('input', {}, passwordInput?.shadowRoot);
+ scrollTo(`get_password_${index}"]`);
+ }
+ }, 100);
+ }
+
+ const allowRetry =
+ errors[0] === FILE_UPLOAD_NETWORK_ERROR_MESSAGE;
+
+ const retryButtonText =
+ content[allowRetry ? 'tryAgain' : 'newFile'];
+ const deleteButtonText =
+ content[hasVisibleError ? 'cancel' : 'delete'];
+
+ const getUiSchema = innerUiSchema =>
+ typeof innerUiSchema === 'function'
+ ? innerUiSchema({
+ fileId: fileNameId,
+ index,
+ fileName: file.name,
+ })
+ : innerUiSchema;
+
+ // make index available to widgets in attachment ui schema
+ const indexedRegistry = {
+ ...registry,
+ formContext: {
+ ...registry.formContext,
+ pagePerItemIndex: index,
+ },
+ };
+
+ return (
+ -
+ {file.uploading && (
+
+
+ {file.name}
+
+
+ {/* no USWDS v3 "activity progress bar" */}
+
+ {
+ cancelUpload(index);
+ }}
+ label={content.cancelLabel(file.name)}
+ text={content.cancel}
+ uswds
+ />
+
+ )}
+ {description && {description}
}
+ {!file.uploading && (
+ <>
+
+ {file.name}
+
+ {file?.size && {displayFileSize(file.size)}
}
+ >
+ )}
+ {showPasswordSuccess && }
+ {!hasVisibleError &&
+ !showPasswordInput &&
+ get('properties.attachmentId', itemSchema) && (
+
+ onAttachmentIdChange(index, value)}
+ onBlur={onBlur}
+ registry={indexedRegistry}
+ disabled={props.disabled}
+ readonly={props.readonly}
+ />
+
+ )}
+ {!hasVisibleError &&
+ !showPasswordInput &&
+ uiOptions.attachmentName && (
+
+
+ onAttachmentNameChange(index, value)
+ }
+ onBlur={onBlur}
+ registry={indexedRegistry}
+ disabled={props.disabled}
+ readonly={props.readonly}
+ />
+
+ )}
+ {!file.uploading &&
+ hasVisibleError && (
+
+ Error {errors[0]}
+
+ )}
+ {!formContext.reviewMode &&
+ !isUploading && (
+
+ {hasVisibleError && (
+
+ )}
+ {!showPasswordInput && (
+ {
+ if (hasVisibleError) {
+ // Cancelling with error should not show the remove
+ // file modal
+ removeFile(index);
+ } else {
+ openRemoveModal(index);
+ }
+ }}
+ label={content[
+ hasVisibleError ? 'cancelLabel' : 'deleteLabel'
+ ](file.name)}
+ text={deleteButtonText}
+ uswds
+ />
+ )}
+
+ )}
+
+ );
+ })}
+
+ )}
+ {// Don't render an upload button on review & submit page while in
+ // review mode
+ showButtons && (
+ <>
+ {(maxItems === null || files.length < maxItems) &&
+ // Prevent additional upload if any upload has error state
+ checkUploadVisibility() && (
+ // eslint-disable-next-line jsx-a11y/label-has-associated-control
+
+ )}
+
`.${item}`).join(',')}
+ className="vads-u-display--none"
+ id={idSchema.$id}
+ name={idSchema.$id}
+ onChange={onAddFile}
+ onClick={() => {
+ fileInputRef.current.value = '';
+ }}
+ />
+ >
+ )}
+
+ );
+ }
return (