diff --git a/src/api/requests/fetchFilingSubmissionLatest.ts b/src/api/requests/fetchFilingSubmissionLatest.ts index 32dce4c53..43af1de2b 100644 --- a/src/api/requests/fetchFilingSubmissionLatest.ts +++ b/src/api/requests/fetchFilingSubmissionLatest.ts @@ -70,24 +70,28 @@ async function retryRequestWithDelay( // eslint-disable-next-line no-param-reassign axiosInstance.defaults.retryCount += One; - // TODO: Remove console.logs once retry adjustments have been fully accepted - console.log( - 'Validation STILL in-progress - Long Polling - RETRYING', - response, - ); + if (import.meta.env.DEV) { + // eslint-disable-next-line no-console + console.log( + 'Validation STILL in-progress - Long Polling - RETRYING', + response, + ); - console.log( - 'retry delay time:', - // getRetryDelay(axiosInstance.defaults.retryCount), - ); + // eslint-disable-next-line no-console + console.log( + 'retry delay time:', + getRetryDelay(axiosInstance.defaults.retryCount), + ); + } return new Promise(resolve => { - setTimeout( - () => resolve(axiosInstance(response.config)), - // getRetryDelay(axiosInstance.defaults.retryCount), - // NOTE: Set to one second for AWS load testing - STANDARD_TIMEOUT, - ); + // NOTE: Set to one second for AWS load testing, will revert before mvp + // https://github.com/cfpb/sbl-frontend/issues/497 + // setTimeout( + // () => resolve(axiosInstance(response.config)), + // getRetryDelay(axiosInstance.defaults.retryCount), + // ); + setTimeout(() => resolve(axiosInstance(response.config)), STANDARD_TIMEOUT); }); } diff --git a/src/components/AlertApiUnavailable.tsx b/src/components/AlertApiUnavailable.tsx index 93a20b236..4f61c19a2 100644 --- a/src/components/AlertApiUnavailable.tsx +++ b/src/components/AlertApiUnavailable.tsx @@ -1,5 +1,6 @@ import { Link } from 'components/Link'; -import { Alert } from 'design-system-react'; +import { Alert, Paragraph } from 'design-system-react'; +import type { ComponentProps } from 'react'; import { sblHelpMail } from 'utils/common'; interface AlertApiUnavailableProperties { @@ -14,7 +15,7 @@ export function AlertApiUnavailable({ message, href = sblHelpMail, ...others -}: AlertApiUnavailableProperties & Partial): JSX.Element { +}: AlertApiUnavailableProperties & ComponentProps): JSX.Element { return ( - There was a connection issue or our service may be temporarily - unavailable. Make sure your computer is connected to the internet, and try - again. If this issue persists,{' '} - contact our support staff. + + There was a connection issue or our service may be temporarily + unavailable. Make sure your computer is connected to the internet, and + try again. If this issue persists,{' '} + contact our support staff. + ); } diff --git a/src/components/Button.tsx b/src/components/Button.tsx index 9c6f66e04..18712fee9 100644 --- a/src/components/Button.tsx +++ b/src/components/Button.tsx @@ -6,7 +6,7 @@ type ButtonProperties = ComponentProps; /* Handles new secondary styling */ const newSecondaryStyle = - 'cursor-pointer border-[1px] border-solid border-pacific bg-white text-pacific hover:border-[#0050B4] hover:bg-white hover:text-[#0050B4] focus:bg-transparent disabled:cursor-not-allowed disabled:border-none'; + 'cursor-pointer border-[1px] border-solid border-pacific bg-white text-pacific hover:border-[#0050B4] hover:bg-white hover:text-[#0050B4] focus:bg-white disabled:cursor-not-allowed disabled:border-none'; export function Button({ children, diff --git a/src/pages/Filing/FilingApp/FileDetailsValidation.tsx b/src/pages/Filing/FilingApp/FileDetailsValidation.tsx index d87bc05df..715547f91 100644 --- a/src/pages/Filing/FilingApp/FileDetailsValidation.tsx +++ b/src/pages/Filing/FilingApp/FileDetailsValidation.tsx @@ -6,27 +6,32 @@ import { fileSubmissionValidationStatus } from './FileSubmission.data'; interface FileDetailsProperties { dataGetSubmissionLatest: SubmissionResponse | undefined; errorGetSubmissionLatest: unknown; + hasWarnings: boolean; } function FileDetailsValidation({ dataGetSubmissionLatest, errorGetSubmissionLatest, + hasWarnings, }: FileDetailsProperties): JSX.Element | null { // Should only show once an validation has completed if ( - !dataGetSubmissionLatest?.filename && - !dataGetSubmissionLatest?.submission_time + errorGetSubmissionLatest || + (!dataGetSubmissionLatest?.filename && + !dataGetSubmissionLatest?.submission_time) ) return null; // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - const validationStatusMessage: string = errorGetSubmissionLatest - ? fileSubmissionValidationStatus[FileSubmissionState.VALIDATION_ERROR] - : // @ts-expect-error key in - dataGetSubmissionLatest.state in fileSubmissionValidationStatus - ? // @ts-expect-error use key - fileSubmissionValidationStatus[dataGetSubmissionLatest.state] - : ''; + const validationStatusMessage: string = + hasWarnings && + dataGetSubmissionLatest.state === FileSubmissionState.SUBMISSION_ACCEPTED + ? 'Your file contains no errors and warnings have been verified' + : // @ts-expect-error key in + dataGetSubmissionLatest.state in fileSubmissionValidationStatus + ? // @ts-expect-error use key + fileSubmissionValidationStatus[dataGetSubmissionLatest.state] + : ''; return (
diff --git a/src/pages/Filing/FilingApp/FileSubmission.data.tsx b/src/pages/Filing/FilingApp/FileSubmission.data.tsx index 9e61d5f78..caa37c2a2 100644 --- a/src/pages/Filing/FilingApp/FileSubmission.data.tsx +++ b/src/pages/Filing/FilingApp/FileSubmission.data.tsx @@ -1,14 +1,18 @@ import AlertApiUnavailable from 'components/AlertApiUnavailable'; import { Link } from 'components/Link'; -import { Alert } from 'design-system-react'; +import { Alert, Paragraph } from 'design-system-react'; import { FileSubmissionState } from 'types/filingTypes'; import { fileFormatLink, sblHelpMail } from 'utils/common'; +const uploadErrorSubheading = 'There was a problem uploading your file'; +const validationErrorSubheading = + 'There was a problem performing validation checks on your file'; + function SuccessAlert(): JSX.Element { return ( ); @@ -18,13 +22,34 @@ export function ValidationInitialFetchFailAlert(): JSX.Element { return ; } -function ValidationErrorGeneralAlert(): JSX.Element { +export function UploadErrorGeneralAlert(): JSX.Element { return ( + > + + An unknown error occurred during file upload. If this issue persists,{' '} + email our support staff. + + + ); +} + +export function ValidationErrorGeneralAlert(): JSX.Element { + return ( + + + An unknown error occurred while performing validation checks on your + file. If this issue persists,{' '} + email our support staff. + + ); } @@ -32,12 +57,14 @@ function ValidationErrorTimeoutAlert(): JSX.Element { return ( - Our system was not able to process your file within the allotted - timeframe. Try re-uploading the file. If this issue persists,{' '} - email our support staff.{' '} + + Our system was not able to process your file within the allotted + timeframe. Try re-uploading the file. If this issue persists,{' '} + email our support staff. + ); } @@ -46,12 +73,14 @@ export function UploadMaxSizeAlert(): JSX.Element { return ( - The file you tried to upload exceeds the file size requirement or contains - no data. Check your file and try again. If this issue persists,{' '} - email our support staff. + + The file you tried to upload exceeds the file size requirement or + contains no data. Check your file and try again. If this issue persists,{' '} + email our support staff. + ); } @@ -60,12 +89,14 @@ export function IncorrectFileTypeAlert(): JSX.Element { return ( - The file you uploaded is an unsupported media type. Check your file and - try again. If this issue persists,{' '} - email our support staff. + + The file you uploaded is an unsupported media type. Check your file and + try again. If this issue persists,{' '} + email our support staff. + ); } @@ -80,23 +111,27 @@ export const fileSubmissionStateAlert: Record< JSX.Element > = { [FileSubmissionState.VALIDATION_SUCCESSFUL]: , + [FileSubmissionState.SUBMISSION_ACCEPTED]: , [FileSubmissionState.VALIDATION_WITH_WARNINGS]: , [FileSubmissionState.VALIDATION_WITH_ERRORS]: , [FileSubmissionState.UPLOAD_FAILED]: ( - + ), [FileSubmissionState.VALIDATION_ERROR]: , [FileSubmissionState.VALIDATION_EXPIRED]: , [FileSubmissionState.SUBMISSION_UPLOAD_MALFORMED]: ( - There may be an issue with the formatting of your file. Make sure your - file meets the requirements detailed in - section 2.2 of the Filing instructions guide and try again. If this issue - persists, email our support staff. + + There may be an issue with the formatting of your file. Make sure your + file meets the requirements detailed in the filing instructions guide ( + section 2.2, "File format") + and try again. If this issue persists,{' '} + email our support staff. + ), }; @@ -105,22 +140,21 @@ export const fileSubmissionValidationStatus: Record< Exclude< FileSubmissionState, | FileSubmissionState.SUBMISSION_STARTED + | FileSubmissionState.SUBMISSION_UPLOAD_MALFORMED | FileSubmissionState.SUBMISSION_UPLOADED | FileSubmissionState.UPLOAD_FAILED + | FileSubmissionState.VALIDATION_ERROR + | FileSubmissionState.VALIDATION_EXPIRED | FileSubmissionState.VALIDATION_IN_PROGRESS >, string > = { [FileSubmissionState.VALIDATION_SUCCESSFUL]: - 'No errors or warnings were found in your file', + 'The validation checks returned no errors or warnings', + [FileSubmissionState.SUBMISSION_ACCEPTED]: + 'The validation checks returned no errors or warnings', [FileSubmissionState.VALIDATION_WITH_WARNINGS]: - 'Warnings were found in your file', + 'The validation checks returned warnings', [FileSubmissionState.VALIDATION_WITH_ERRORS]: - 'Errors were found in your file', - [FileSubmissionState.SUBMISSION_UPLOAD_MALFORMED]: - 'There may be an issue with the formatting of your file', - [FileSubmissionState.VALIDATION_ERROR]: - 'There may be an issue with the validation of your file', - [FileSubmissionState.VALIDATION_EXPIRED]: - 'There may be an issue with the validation of your file', + 'The validation checks returned errors', }; diff --git a/src/pages/Filing/FilingApp/FileSubmission.tsx b/src/pages/Filing/FilingApp/FileSubmission.tsx index 6a2149316..6d1086a63 100644 --- a/src/pages/Filing/FilingApp/FileSubmission.tsx +++ b/src/pages/Filing/FilingApp/FileSubmission.tsx @@ -13,13 +13,14 @@ import { Link } from 'components/Link'; import SectionIntro from 'components/SectionIntro'; import { Heading, Paragraph, TextIntroduction } from 'design-system-react'; import type { ChangeEvent } from 'react'; -import { useEffect, useRef, useState } from 'react'; +import { useEffect, useMemo, useRef, useState } from 'react'; import { useLocation, useNavigate, useParams } from 'react-router-dom'; import useGetSubmissionLatest from 'utils/useGetSubmissionLatest'; import type { AxiosResponse } from 'axios'; import FormButtonGroup from 'components/FormButtonGroup'; import { LoadingContent } from 'components/Loading'; +import { useError500 } from 'pages/Error/Error500'; import type { SubmissionResponse } from 'types/filingTypes'; import { FileSubmissionState } from 'types/filingTypes'; import { filingInstructionsPage } from 'utils/common'; @@ -31,11 +32,13 @@ import useInstitutionDetails from 'utils/useInstitutionDetails'; import FileDetailsUpload from './FileDetailsUpload'; import FileDetailsValidation from './FileDetailsValidation'; import FileSubmissionAlert from './FileSubmissionAlert'; +import { getErrorsWarningsSummary } from './FilingErrors/FilingErrors.helpers'; import { FilingNavButtons } from './FilingNavButtons'; import { FilingSteps } from './FilingSteps'; import InstitutionHeading from './InstitutionHeading'; export function FileSubmission(): JSX.Element { + const redirect500 = useError500(); const abortController = new AbortController(); const { lei, year } = useParams(); const navigate = useNavigate(); @@ -139,8 +142,8 @@ export function FileSubmission(): JSX.Element { // Derived Conditions const buttonLabel = dataGetSubmissionLatest?.state - ? 'Replace your file' - : 'Upload your file'; + ? 'Upload new file' + : 'Upload file'; const inputAriaLabel = dataGetSubmissionLatest?.state ? 'Replace your previously uploaded .csv file' : 'Select a .csv file to upload'; @@ -178,6 +181,51 @@ export function FileSubmission(): JSX.Element { // eslint-disable-next-line react-hooks/exhaustive-deps }, [pathname]); + /* + Derived data + */ + + const formattedData = useMemo( + () => getErrorsWarningsSummary(dataGetSubmissionLatest), + [dataGetSubmissionLatest], + ); + + const { + logicWarningsMulti, + logicWarningsSingle, + syntaxErrorsSingle, + logicErrorsSingle, + logicErrorsMulti, + registerErrors, + } = formattedData; + + const hasWarnings = [logicWarningsMulti, logicWarningsSingle].some( + array => array.length > 0, + ); + + const hasErrors = [ + syntaxErrorsSingle, + logicErrorsSingle, + logicErrorsMulti, + registerErrors, + ].some(array => array.length > 0); + + // // Redirect checks + useEffect(() => { + // Only execute redirection logic after initial component mount + if (!initialGetSubmissionLatestFetched && errorGetSubmissionLatest) { + redirect500({ + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment + code: errorGetSubmissionLatest.response?.status || '', + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access + message: errorGetSubmissionLatest.response?.statusText || '', + }); + } + }, [ + initialGetSubmissionLatestFetched, + errorGetSubmissionLatest, + redirect500, + ]); const onNextClick = (): void => navigate(`/filing/${year}/${lei}/errors`); const onPreviousClick = (): void => navigate(`/filing`); @@ -195,12 +243,13 @@ export function FileSubmission(): JSX.Element {
- Your file must be submitted in a comma-separated values (CSV) - file format and must not exceed 2GB in size. For detailed filing - specifications reference the{' '} + Your small business lending application register (register) must + be submitted in a comma-separated values (CSV) file format and + must not exceed 2GB in size. For detailed filing specifications + reference the{' '} Filing instructions guide for small business lending data @@ -215,29 +264,34 @@ export function FileSubmission(): JSX.Element { {initialGetSubmissionLatestFetched ? ( <> - + {!isFetchingGetSubmissionLatest && !isLoadingUpload && ( + + )} - + {dataGetSubmissionLatest?.state ? ( <> To change your file selection, click on "Replace your file," navigate to the file on your computer that you - wish to upload, and then select the file to start the - upload and validation process. Uploading a new file will - replace your current upload and reset your progress. + wish to upload, and select the file to start the upload + and validation process. Uploading a new file will replace + your current upload and reset your progress. ) : ( <> - To get started, click on "Upload your file," + To get started, click "Upload your file," navigate to the file on your computer that you wish to - upload, and then select the file to start the upload and + upload, and select the file to start the upload and validation process. )} @@ -257,9 +311,7 @@ export function FileSubmission(): JSX.Element { disabled={isLoadingUpload || isFetchingGetSubmissionLatest} />