added error messaging for image upload and idv submission
updated testing wrapped button click moved maximum file size to a const variable
This commit is contained in:
@@ -35,7 +35,7 @@ function CameraHelpWithUpload(props) {
|
||||
<p>
|
||||
{props.intl.formatMessage(messages['id.verification.id.photo.instructions.upload'])}
|
||||
</p>
|
||||
<ImageFileUpload onFileChange={setAndTrackIdPhotoFile} />
|
||||
<ImageFileUpload onFileChange={setAndTrackIdPhotoFile} intl={props.intl} />
|
||||
</Collapsible>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -403,9 +403,14 @@ const messages = defineMessages({
|
||||
},
|
||||
'id.verification.id.photo.instructions.upload': {
|
||||
id: 'id.verification.id.photo.instructions.upload',
|
||||
defaultMessage: 'Please upload an ID photo. Ensure the entire ID fits inside the frame and is well-lit. (Supported formats: .jpg, .jpeg, .png)',
|
||||
defaultMessage: 'Please upload an ID photo. Ensure the entire ID fits inside the frame and is well-lit. The file size must be under 10 MB. (Supported formats: .jpg, .jpeg, .png)',
|
||||
description: 'Instructions for ID photo upload.',
|
||||
},
|
||||
'id.verification.id.photo.instructions.upload.error': {
|
||||
id: 'id.verification.id.photo.instructions.upload.error',
|
||||
defaultMessage: 'The file you have selected is too large. Please try again with a file less than 10MB.',
|
||||
description: 'Error message for file upload that is larger than 10MB.',
|
||||
},
|
||||
'id.verification.account.name.title': {
|
||||
id: 'id.verification.account.name.title',
|
||||
defaultMessage: 'Account Name Check',
|
||||
@@ -506,6 +511,11 @@ const messages = defineMessages({
|
||||
defaultMessage: 'Submit',
|
||||
description: 'Button to confirm all information is correct and submit.',
|
||||
},
|
||||
'id.verification.review.error': {
|
||||
id: 'id.verification.review.error',
|
||||
defaultMessage: 'edX Support Page',
|
||||
description: 'Text linking to the support page.',
|
||||
},
|
||||
'id.verification.submitted.title': {
|
||||
id: 'id.verification.submitted.title',
|
||||
defaultMessage: 'Identity Verification in Progress',
|
||||
|
||||
@@ -1,28 +1,52 @@
|
||||
import React, { useCallback } from 'react';
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import { intlShape } from '@edx/frontend-platform/i18n';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Alert } from '@edx/paragon';
|
||||
import messages from './IdVerification.messages';
|
||||
|
||||
|
||||
export default function ImageFileUpload({ onFileChange, intl }) {
|
||||
const [fileTooLargeError, setFileTooLargeError] = useState(false);
|
||||
const maxFileSize = 10000000;
|
||||
|
||||
export default function ImageFileUpload({ onFileChange }) {
|
||||
const handleChange = useCallback((e) => {
|
||||
if (e.target.files.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const fileObject = e.target.files[0];
|
||||
const fileReader = new FileReader();
|
||||
fileReader.addEventListener('load', () => onFileChange(fileReader.result));
|
||||
fileReader.readAsDataURL(fileObject);
|
||||
if (fileObject.size < maxFileSize) {
|
||||
const fileReader = new FileReader();
|
||||
fileReader.addEventListener('load', () => onFileChange(fileReader.result));
|
||||
fileReader.readAsDataURL(fileObject);
|
||||
} else {
|
||||
setFileTooLargeError(true);
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<input
|
||||
type="file"
|
||||
accept="image/*"
|
||||
data-testid="fileUpload"
|
||||
onChange={handleChange}
|
||||
/>
|
||||
<>
|
||||
<input
|
||||
type="file"
|
||||
accept="image/*"
|
||||
data-testid="fileUpload"
|
||||
onChange={handleChange}
|
||||
/>
|
||||
{fileTooLargeError && (
|
||||
<Alert
|
||||
id="fileTooLargeError"
|
||||
variant="danger"
|
||||
tabIndex="-1"
|
||||
style={{ marginTop: '1rem' }}
|
||||
>
|
||||
{intl.formatMessage(messages['id.verification.id.photo.instructions.upload.error'])}
|
||||
</Alert>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
ImageFileUpload.propTypes = {
|
||||
onFileChange: PropTypes.func.isRequired,
|
||||
intl: intlShape.isRequired,
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useState, useContext } from 'react';
|
||||
import { history } from '@edx/frontend-platform';
|
||||
import { Input, Button, Spinner } from '@edx/paragon';
|
||||
import { Input, Button, Spinner, Alert } from '@edx/paragon';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { injectIntl, intlShape, FormattedMessage } from '@edx/frontend-platform/i18n';
|
||||
|
||||
@@ -25,6 +25,7 @@ function SummaryPanel(props) {
|
||||
} = useContext(IdVerificationContext);
|
||||
const nameToBeUsed = idPhotoName || nameOnAccount || '';
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
const [submissionError, setSubmissionError] = useState(false);
|
||||
|
||||
function SubmitButton() {
|
||||
async function handleClick() {
|
||||
@@ -39,6 +40,10 @@ function SummaryPanel(props) {
|
||||
if (result.success) {
|
||||
stopUserMedia();
|
||||
history.push(nextPanelSlug);
|
||||
} else {
|
||||
stopUserMedia();
|
||||
setIsSubmitting(false);
|
||||
setSubmissionError(true);
|
||||
}
|
||||
}
|
||||
return (
|
||||
@@ -59,6 +64,24 @@ function SummaryPanel(props) {
|
||||
name={panelSlug}
|
||||
title={props.intl.formatMessage(messages['id.verification.review.title'])}
|
||||
>
|
||||
{submissionError &&
|
||||
<Alert
|
||||
variant="danger"
|
||||
data-testid="submission-error"
|
||||
dismissible
|
||||
onClose={() => setSubmissionError(false)}
|
||||
>
|
||||
<FormattedMessage
|
||||
id="idv.submission.alert.error"
|
||||
defaultMessage={`
|
||||
We encountered a technical error while trying to submit ID verification.
|
||||
This might be a temporary issue, so please try again in a few minutes.
|
||||
If the problem persists,
|
||||
please go to {support_link} for help.
|
||||
`}
|
||||
values={{ support_link: <Alert.Link href="https://support.edx.org/hc/en-us">{props.intl.formatMessage(messages['id.verification.review.error'])}</Alert.Link> }}
|
||||
/>
|
||||
</Alert>}
|
||||
<p>
|
||||
{props.intl.formatMessage(messages['id.verification.review.description'])}
|
||||
</p>
|
||||
|
||||
@@ -5,7 +5,7 @@ import { render, cleanup, act, screen, fireEvent, waitFor } from '@testing-libra
|
||||
import '@edx/frontend-platform/analytics';
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
import { injectIntl, IntlProvider } from '@edx/frontend-platform/i18n';
|
||||
import { submitIdVerification } from '../../data/service';
|
||||
import * as dataService from '../../data/service';
|
||||
import { IdVerificationContext } from '../../IdVerificationContext';
|
||||
import SummaryPanel from '../../panels/SummaryPanel';
|
||||
|
||||
@@ -13,9 +13,8 @@ jest.mock('@edx/frontend-platform/analytics', () => ({
|
||||
sendTrackEvent: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('../../data/service', () => ({
|
||||
submitIdVerification: jest.fn(() => ({ success: true, message: null })),
|
||||
}));
|
||||
jest.mock('../../data/service');
|
||||
dataService.submitIdVerification = jest.fn().mockReturnValue({ success: true });
|
||||
|
||||
const IntlSummaryPanel = injectIntl(SummaryPanel);
|
||||
|
||||
@@ -74,7 +73,26 @@ describe('SummaryPanel', () => {
|
||||
it('submits', async () => {
|
||||
const button = await screen.findByTestId('submit-button');
|
||||
fireEvent.click(button);
|
||||
expect(submitIdVerification).toHaveBeenCalled();
|
||||
await waitFor(() => expect(contextValue.stopUserMedia).toHaveBeenCalled())
|
||||
expect(dataService.submitIdVerification).toHaveBeenCalled();
|
||||
await waitFor(() => expect(contextValue.stopUserMedia).toHaveBeenCalled());
|
||||
});
|
||||
|
||||
it('shows error when cannot submit', async () => {
|
||||
await cleanup();
|
||||
dataService.submitIdVerification = jest.fn().mockReturnValue({ success: false });
|
||||
await act(async () => render((
|
||||
<Router history={history}>
|
||||
<IntlProvider locale="en">
|
||||
<IdVerificationContext.Provider value={contextValue}>
|
||||
<IntlSummaryPanel {...defaultProps} />
|
||||
</IdVerificationContext.Provider>
|
||||
</IntlProvider>
|
||||
</Router>
|
||||
)));
|
||||
const button = await screen.findByTestId('submit-button');
|
||||
await act(async () => fireEvent.click(button));
|
||||
expect(dataService.submitIdVerification).toHaveBeenCalled();
|
||||
const error = await screen.getByTestId('submission-error');
|
||||
expect(error).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user