added option for image upload
added friction to allowing users to upload id image only shows picture within component if it has been uploaded, not if it was captured through the webcam
This commit is contained in:
53
src/id-verification/CameraHelpWithUpload.jsx
Normal file
53
src/id-verification/CameraHelpWithUpload.jsx
Normal file
@@ -0,0 +1,53 @@
|
||||
import React, { useState, useContext } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Collapsible } from '@edx/paragon';
|
||||
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||
import { sendTrackEvent } from '@edx/frontend-platform/analytics';
|
||||
|
||||
import messages from './IdVerification.messages';
|
||||
import ImageFileUpload from './ImageFileUpload';
|
||||
import { IdVerificationContext } from './IdVerificationContext';
|
||||
import ImagePreview from './ImagePreview';
|
||||
|
||||
function CameraHelpWithUpload(props) {
|
||||
const { setIdPhotoFile, idPhotoFile, userId } = useContext(IdVerificationContext);
|
||||
const [hasUploadedImage, setHasUploadedImage] = useState(false);
|
||||
|
||||
function setAndTrackIdPhotoFile(image) {
|
||||
sendTrackEvent('edx.id_verification.upload_id', {
|
||||
category: 'id_verification',
|
||||
user_id: userId,
|
||||
});
|
||||
setHasUploadedImage(true);
|
||||
setIdPhotoFile(image);
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Collapsible
|
||||
styling="card"
|
||||
title={props.intl.formatMessage(messages['id.verification.id.photo.unclear.question'])}
|
||||
data-testid="collapsible"
|
||||
className="mb-4 shadow"
|
||||
defaultOpen={props.isOpen}
|
||||
>
|
||||
{idPhotoFile && hasUploadedImage && <ImagePreview src={idPhotoFile} alt={props.intl.formatMessage(messages['id.verification.id.photo.preview.alt'])} />}
|
||||
<p>
|
||||
{props.intl.formatMessage(messages['id.verification.id.photo.instructions.upload'])}
|
||||
</p>
|
||||
<ImageFileUpload onFileChange={setAndTrackIdPhotoFile} />
|
||||
</Collapsible>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
CameraHelpWithUpload.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
isOpen: PropTypes.bool,
|
||||
};
|
||||
|
||||
CameraHelpWithUpload.defaultProps = {
|
||||
isOpen: false,
|
||||
};
|
||||
|
||||
export default injectIntl(CameraHelpWithUpload);
|
||||
@@ -341,6 +341,11 @@ const messages = defineMessages({
|
||||
defaultMessage: 'If you require assistance with taking a photo for submission, contact edX support for additional suggestions.',
|
||||
description: 'Confirming what to do if the user has difficult holding their head relative to the camera.',
|
||||
},
|
||||
'id.verification.id.photo.unclear.question': {
|
||||
id: 'id.verification.id.photo.unclear.question',
|
||||
defaultMessage: 'Is your ID image not clear or too blurry?',
|
||||
description: 'Question on what to do if the user\'s ID image is unclear',
|
||||
},
|
||||
'id.verification.id.tips.title': {
|
||||
id: 'id.verification.id.tips.title',
|
||||
defaultMessage: 'Helpful ID Tips',
|
||||
|
||||
@@ -17,6 +17,7 @@ export default function ImageFileUpload({ onFileChange }) {
|
||||
<input
|
||||
type="file"
|
||||
accept="image/*"
|
||||
data-testid="fileUpload"
|
||||
onChange={handleChange}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -11,6 +11,7 @@ import { IdVerificationContext } from '../IdVerificationContext';
|
||||
import ImagePreview from '../ImagePreview';
|
||||
|
||||
import messages from '../IdVerification.messages';
|
||||
import CameraHelpWithUpload from '../CameraHelpWithUpload';
|
||||
|
||||
function SummaryPanel(props) {
|
||||
const panelSlug = 'summary';
|
||||
@@ -101,6 +102,7 @@ function SummaryPanel(props) {
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
<CameraHelpWithUpload />
|
||||
<div className="form-group">
|
||||
<label htmlFor="name-to-be-used">
|
||||
{props.intl.formatMessage(messages['id.verification.account.name.label'])}
|
||||
|
||||
@@ -4,47 +4,29 @@ import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||
|
||||
import { useNextPanelSlug } from '../routing-utilities';
|
||||
import BasePanel from './BasePanel';
|
||||
import ImageFileUpload from '../ImageFileUpload';
|
||||
import ImagePreview from '../ImagePreview';
|
||||
import Camera from '../Camera';
|
||||
import CameraHelp from '../CameraHelp';
|
||||
import { IdVerificationContext } from '../IdVerificationContext';
|
||||
|
||||
import messages from '../IdVerification.messages';
|
||||
import CameraHelp from '../CameraHelp';
|
||||
|
||||
function TakeIdPhotoPanel(props) {
|
||||
const panelSlug = 'take-id-photo';
|
||||
const nextPanelSlug = useNextPanelSlug(panelSlug);
|
||||
const { setIdPhotoFile, idPhotoFile } = useContext(IdVerificationContext);
|
||||
const shouldUseCamera = true;
|
||||
// to reenable upload component:
|
||||
// const shouldUseCamera = mediaAccess === MEDIA_ACCESS.GRANTED;
|
||||
|
||||
return (
|
||||
<BasePanel
|
||||
name={panelSlug}
|
||||
title={shouldUseCamera ? props.intl.formatMessage(messages['id.verification.id.photo.title.camera']) : props.intl.formatMessage(messages['id.verification.id.photo.title.upload'])}
|
||||
title={props.intl.formatMessage(messages['id.verification.id.photo.title.camera'])}
|
||||
>
|
||||
<div>
|
||||
{idPhotoFile && !shouldUseCamera && <ImagePreview src={idPhotoFile} alt={props.intl.formatMessage(messages['id.verification.id.photo.preview.alt'])} />}
|
||||
|
||||
{shouldUseCamera ? (
|
||||
<div>
|
||||
<p>
|
||||
{props.intl.formatMessage(messages['id.verification.id.photo.instructions.camera'])}
|
||||
</p>
|
||||
<Camera onImageCapture={setIdPhotoFile} />
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
<p>
|
||||
{props.intl.formatMessage(messages['id.verification.id.photo.instructions.upload'])}
|
||||
</p>
|
||||
<ImageFileUpload onFileChange={setIdPhotoFile} />
|
||||
</div>
|
||||
)}
|
||||
<p>
|
||||
{props.intl.formatMessage(messages['id.verification.id.photo.instructions.camera'])}
|
||||
</p>
|
||||
<Camera onImageCapture={setIdPhotoFile} />
|
||||
</div>
|
||||
{shouldUseCamera && <CameraHelp />}
|
||||
<CameraHelp />
|
||||
<div className="action-row" style={{ visibility: idPhotoFile ? 'unset' : 'hidden' }}>
|
||||
<Link to={nextPanelSlug} className="btn btn-primary" data-testid="next-button">
|
||||
{props.intl.formatMessage(messages['id.verification.next'])}
|
||||
|
||||
@@ -2,6 +2,7 @@ import React from 'react';
|
||||
import { Router } from 'react-router-dom';
|
||||
import { createMemoryHistory } from 'history';
|
||||
import { render, cleanup, act, screen, fireEvent } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
import '@edx/frontend-platform/analytics';
|
||||
import { injectIntl, IntlProvider } from '@edx/frontend-platform/i18n';
|
||||
import { submitIdVerification } from '../../data/service';
|
||||
@@ -62,6 +63,13 @@ describe('SummaryPanel', () => {
|
||||
expect(history.location.state.fromSummary).toEqual(true);
|
||||
});
|
||||
|
||||
it('allows user to upload ID photo', async () => {
|
||||
const collapsible = await screen.getAllByRole('button', { 'aria-expanded': false })[0];
|
||||
fireEvent.click(collapsible);
|
||||
const uploadButton = await screen.getByTestId('fileUpload');
|
||||
expect(uploadButton).toBeVisible();
|
||||
});
|
||||
|
||||
it('submits', async () => {
|
||||
const button = await screen.findByTestId('submit-button');
|
||||
fireEvent.click(button);
|
||||
|
||||
Reference in New Issue
Block a user