diff --git a/src/applications/appeals/shared/components/FileField.jsx b/src/applications/appeals/shared/components/FileField.jsx index b55592f8cae6..8d01c3c5a03c 100644 --- a/src/applications/appeals/shared/components/FileField.jsx +++ b/src/applications/appeals/shared/components/FileField.jsx @@ -28,8 +28,10 @@ import { focusAddAnotherButton, focusCancelButton } from '../utils/focus'; import { MISSING_PASSWORD_ERROR, INCORRECT_PASSWORD_ERROR, + FILE_NAME_TOO_LONG_ERROR, createContent, reMapErrorMessage, + checkIsFileNameTooLong, hasSomeUploading, checkUploadVisibility, } from '../utils/upload'; @@ -211,6 +213,12 @@ const FileField = props => { name: currentFile.name, }; + if (checkIsFileNameTooLong(currentFile.name)) { + allFiles[idx].errorMessage = FILE_NAME_TOO_LONG_ERROR; + props.onChange(allFiles); + return; + } + if (currentFile.type === 'testing') { // Skip read file for Cypress testing checkResults = { diff --git a/src/applications/appeals/shared/tests/components/FileField.unit.spec.jsx b/src/applications/appeals/shared/tests/components/FileField.unit.spec.jsx index 91300e53a92f..0166182ea3a0 100644 --- a/src/applications/appeals/shared/tests/components/FileField.unit.spec.jsx +++ b/src/applications/appeals/shared/tests/components/FileField.unit.spec.jsx @@ -24,6 +24,8 @@ import FileField from '../../components/FileField'; import { errormessageMaps, + FILE_NAME_TOO_LONG_ERROR, + MAX_FILE_NAME_LENGTH, MISSING_PASSWORD_ERROR, INCORRECT_PASSWORD_ERROR, } from '../../utils/upload'; @@ -537,6 +539,54 @@ describe('Schemaform ', () => { expect($('div.usa-input-error-message', container)).to.exist; }); + it('should render file name too long error', async () => { + const onChangeSpy = sinon.spy(); + const schema = { + additionalItems: {}, + items: [ + { + properties: {}, + }, + ], + }; + const uiSchema = fileUploadUI('Files'); + const fileWithLongName = new File( + ['test 123'], + 'a'.repeat(MAX_FILE_NAME_LENGTH + 1), + { + type: fileTypeSignatures.pdf.mime, + }, + ); + const errorSchema = {}; + const registry = { + fields: { + SchemaField: () =>
, + }, + }; + const { container } = render( + , + ); + + fireEvent.change($('input[type="file"]', container), { + target: { files: [fileWithLongName] }, + }); + + expect(onChangeSpy.calledOnce).to.be.true; + expect(onChangeSpy.args[0][0][0].errorMessage).to.eq( + FILE_NAME_TOO_LONG_ERROR, + ); + }); + it('should remap PDF dimension error', () => { const error = 'exceeds the page size limit'; const schema = { diff --git a/src/applications/appeals/shared/tests/utils/upload.unit.spec.js b/src/applications/appeals/shared/tests/utils/upload.unit.spec.js index 3103940c9d25..b67db20f4138 100644 --- a/src/applications/appeals/shared/tests/utils/upload.unit.spec.js +++ b/src/applications/appeals/shared/tests/utils/upload.unit.spec.js @@ -3,6 +3,8 @@ import { expect } from 'chai'; import { createPayload, parseResponse, + MAX_FILE_NAME_LENGTH, + checkIsFileNameTooLong, hasSomeUploading, checkUploadVisibility, createContent, @@ -47,6 +49,24 @@ describe('parseResponse', () => { }); }); +describe('checkIsFileNameTooLong', () => { + it('should return false for file names under the size limit', () => { + expect(checkIsFileNameTooLong()).to.be.false; + expect(checkIsFileNameTooLong('')).to.be.false; + expect(checkIsFileNameTooLong('abcd')).to.be.false; + expect(checkIsFileNameTooLong('a'.repeat(MAX_FILE_NAME_LENGTH / 2))).to.be + .false; + expect(checkIsFileNameTooLong('a'.repeat(MAX_FILE_NAME_LENGTH - 1))).to.be + .false; + }); + it('should return true for file names over the size limit', () => { + expect(checkIsFileNameTooLong('a'.repeat(MAX_FILE_NAME_LENGTH + 1))).to.be + .true; + expect(checkIsFileNameTooLong('a'.repeat(MAX_FILE_NAME_LENGTH * 2))).to.be + .true; + }); +}); + describe('hasSomeUploading', () => { it('should return false if no files are uploading', () => { expect(hasSomeUploading([])).to.be.false; diff --git a/src/applications/appeals/shared/utils/upload.js b/src/applications/appeals/shared/utils/upload.js index a578537dc5fd..1df68fc75cfb 100644 --- a/src/applications/appeals/shared/utils/upload.js +++ b/src/applications/appeals/shared/utils/upload.js @@ -9,6 +9,10 @@ export const MISSING_PASSWORD_ERROR = [ 'Document is locked with a user password', ]; +// Lighthouse limits file names to 255 characters +export const MAX_FILE_NAME_LENGTH = 255; +export const FILE_NAME_TOO_LONG_ERROR = `Your file name can’t exceed ${MAX_FILE_NAME_LENGTH} characters. Rename your file and try again.`; + export const INCORRECT_PASSWORD_ERROR = 'We couldn’t unlock your PDF. Save the PDF without a password and try again.'; @@ -24,6 +28,9 @@ export const reMapErrorMessage = error => { return errormessageMaps?.[result] ?? error; }; +export const checkIsFileNameTooLong = (name = '') => + name.length > MAX_FILE_NAME_LENGTH; + export const createPayload = (file, _formId, password) => { const payload = new FormData(); payload.append('decision_review_evidence_attachment[file_data]', file); diff --git a/src/applications/claims-status/components/appeals-v2/Docket.jsx b/src/applications/claims-status/components/appeals-v2/Docket.jsx index 9321c60721db..3a525e564f4b 100644 --- a/src/applications/claims-status/components/appeals-v2/Docket.jsx +++ b/src/applications/claims-status/components/appeals-v2/Docket.jsx @@ -5,7 +5,6 @@ import { flow, sortBy, toPairs } from 'lodash'; import omit from 'platform/utilities/data/omit'; import DocketCard from './DocketCard'; -import DurationCard from './DurationCard'; import { APPEAL_ACTIONS, DOCKET_TYPES, @@ -50,11 +49,6 @@ function Docket({ 'MMMM YYYY', ); - const etaFormatted = - eta && - eta[amaDocket] && - moment(eta[amaDocket], 'YYYY-MM-DD').format('MMMM YYYY'); - const otherEtas = flow( e => omit(amaDocket, e), toPairs, @@ -148,14 +142,6 @@ function Docket({

{yourPlaceText} {ahead && } - {etaFormatted && ( - - )}

Is there a way to prioritize my appeal?

If you are suffering a serious illness or are in financial distress, diff --git a/src/applications/claims-status/components/appeals-v2/DurationCard.jsx b/src/applications/claims-status/components/appeals-v2/DurationCard.jsx deleted file mode 100644 index 17f94006e8e4..000000000000 --- a/src/applications/claims-status/components/appeals-v2/DurationCard.jsx +++ /dev/null @@ -1,34 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -// Disabling duration card view (for now) per -// https://github.com/department-of-veterans-affairs/va.gov-team/issues/10293 -const DurationCard = ({ durationText, cardDescription, isDisabled = true }) => { - // Card's not very helpful without any actual duration information - if (!durationText || isDisabled) { - return null; - } - - return ( - -

-