diff --git a/src/id-verification/CameraHelpWithUpload.jsx b/src/id-verification/CameraHelpWithUpload.jsx
index ec46a36..3926ec3 100644
--- a/src/id-verification/CameraHelpWithUpload.jsx
+++ b/src/id-verification/CameraHelpWithUpload.jsx
@@ -35,7 +35,7 @@ function CameraHelpWithUpload(props) {
{props.intl.formatMessage(messages['id.verification.id.photo.instructions.upload'])}
-
+
);
diff --git a/src/id-verification/IdVerification.messages.js b/src/id-verification/IdVerification.messages.js
index 33119fa..de765a0 100644
--- a/src/id-verification/IdVerification.messages.js
+++ b/src/id-verification/IdVerification.messages.js
@@ -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',
diff --git a/src/id-verification/ImageFileUpload.jsx b/src/id-verification/ImageFileUpload.jsx
index 9d52ea1..ff607c6 100644
--- a/src/id-verification/ImageFileUpload.jsx
+++ b/src/id-verification/ImageFileUpload.jsx
@@ -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 (
-
+ <>
+
+ {fileTooLargeError && (
+
+ {intl.formatMessage(messages['id.verification.id.photo.instructions.upload.error'])}
+
+ )}
+ >
);
}
ImageFileUpload.propTypes = {
onFileChange: PropTypes.func.isRequired,
+ intl: intlShape.isRequired,
};
diff --git a/src/id-verification/panels/SummaryPanel.jsx b/src/id-verification/panels/SummaryPanel.jsx
index 141e5ef..e41f18c 100644
--- a/src/id-verification/panels/SummaryPanel.jsx
+++ b/src/id-verification/panels/SummaryPanel.jsx
@@ -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 &&
+ setSubmissionError(false)}
+ >
+ {props.intl.formatMessage(messages['id.verification.review.error'])} }}
+ />
+ }
{props.intl.formatMessage(messages['id.verification.review.description'])}
diff --git a/src/id-verification/tests/panels/SummaryPanel.test.jsx b/src/id-verification/tests/panels/SummaryPanel.test.jsx
index 54aecdf..4f4c1bc 100644
--- a/src/id-verification/tests/panels/SummaryPanel.test.jsx
+++ b/src/id-verification/tests/panels/SummaryPanel.test.jsx
@@ -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((
+
+
+
+
+
+
+
+ )));
+ 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();
});
});