Merge pull request #298 from edx/alangsto/add_instructions_for_camera_permissions
Added instructions for camera permissions
This commit is contained in:
5
package-lock.json
generated
5
package-lock.json
generated
@@ -7329,6 +7329,11 @@
|
||||
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.5.0.tgz",
|
||||
"integrity": "sha512-Z93QoXvodoVslA+PWNdk23Hze4RBYIkpb5h8I2HY2Tu2h7A0LpAgLcyrhrSUyo2/Oxm2l1fRZPs1e5hnxnliXA=="
|
||||
},
|
||||
"bowser": {
|
||||
"version": "2.10.0",
|
||||
"resolved": "https://registry.npmjs.org/bowser/-/bowser-2.10.0.tgz",
|
||||
"integrity": "sha512-OCsqTQboTEWWsUjcp5jLSw2ZHsBiv2C105iFs61bOT0Hnwi9p7/uuXdd7mu8RYcarREfdjNN+8LitmEHATsLYg=="
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
"@fortawesome/free-solid-svg-icons": "5.8.2",
|
||||
"@fortawesome/react-fontawesome": "0.1.11",
|
||||
"babel-polyfill": "6.26.0",
|
||||
"bowser": "^2.10.0",
|
||||
"classnames": "2.2.6",
|
||||
"font-awesome": "4.7.0",
|
||||
"form-urlencoded": "4.0.1",
|
||||
|
||||
@@ -131,6 +131,131 @@ const messages = defineMessages({
|
||||
defaultMessage: 'It looks like we\'re unable to access your camera. Please verify that your webcam is connected and that you have allowed your browser to access it.',
|
||||
description: 'Text indicating that the camera could not be accessed.',
|
||||
},
|
||||
'id.verification.camera.access.failure.temporary.chrome': {
|
||||
id: 'id.verification.camera.access.failure.temporary.chrome',
|
||||
defaultMessage: 'To enable camera access in Chrome:',
|
||||
description: 'Description for the directions on enabling camera access.',
|
||||
},
|
||||
'id.verification.camera.access.failure.temporary.chrome.step1': {
|
||||
id: 'id.verification.camera.access.failure.temporary.chrome.step1',
|
||||
defaultMessage: 'Open Chrome.',
|
||||
description: 'Text for step one of enabling camera access.',
|
||||
},
|
||||
'id.verification.camera.access.failure.temporary.chrome.step2': {
|
||||
id: 'id.verification.camera.access.failure.temporary.chrome.step2',
|
||||
defaultMessage: 'Navigate to More > Settings.',
|
||||
description: 'Text for step two of enabling camera access.',
|
||||
},
|
||||
'id.verification.camera.access.failure.temporary.chrome.step2.windows': {
|
||||
id: 'id.verification.camera.access.failure.temporary.chrome.step2.windows',
|
||||
defaultMessage: 'For Windows: Alt+F, Alt+E, or F10 followed by the spacebar',
|
||||
description: 'Text for Windows keyboard shortcut in chrome.',
|
||||
},
|
||||
'id.verification.camera.access.failure.temporary.chrome.step2.mac': {
|
||||
id: 'id.verification.camera.access.failure.temporary.chrome.step2.mac',
|
||||
defaultMessage: 'For Mac: Command+,',
|
||||
description: 'Text for Mac keyboard shortcut in chrome.',
|
||||
},
|
||||
'id.verification.camera.access.failure.temporary.chrome.step3': {
|
||||
id: 'id.verification.camera.access.failure.temporary.chrome.step3',
|
||||
defaultMessage: 'Under the "Privacy and security" tab, select "Site Settings" and then "Camera."',
|
||||
description: 'Text for step three of enabling camera access.',
|
||||
},
|
||||
'id.verification.camera.access.failure.temporary.chrome.step4': {
|
||||
id: 'id.verification.camera.access.failure.temporary.chrome.step4',
|
||||
defaultMessage: 'Under "Blocked," find "edx.org" and select it.',
|
||||
description: 'Text for step four of enabling camera access.',
|
||||
},
|
||||
'id.verification.camera.access.failure.temporary.chrome.step5': {
|
||||
id: 'id.verification.camera.access.failure.temporary.chrome.step5',
|
||||
defaultMessage: 'In the "Permissions" section, update the camera permissions to "Allow."',
|
||||
description: 'Text for step five of enabling camera access.',
|
||||
},
|
||||
'id.verification.camera.access.failure.temporary.ie11': {
|
||||
id: 'id.verification.camera.access.failure.temporary.ie11',
|
||||
defaultMessage: 'To enable camera access in Internet Explorer:',
|
||||
description: 'Description for the directions on enabling camera access.',
|
||||
},
|
||||
'id.verification.camera.access.failure.temporary.ie11.step1': {
|
||||
id: 'id.verification.camera.access.failure.temporary.ie11.step1',
|
||||
defaultMessage: 'Open the Flash Player Settings Manager by navigating to Windows Settings > Control Panel > Flash Player.',
|
||||
description: 'Text for step one of enabling camera access.',
|
||||
},
|
||||
'id.verification.camera.access.failure.temporary.ie11.step2': {
|
||||
id: 'id.verification.camera.access.failure.temporary.ie11.step2',
|
||||
defaultMessage: 'Select the "Camera and Mic" tab, and then select the "Camera and Microphone Settings by Site" button.',
|
||||
description: 'Text for step two of enabling camera access.',
|
||||
},
|
||||
'id.verification.camera.access.failure.temporary.ie11.step3': {
|
||||
id: 'id.verification.camera.access.failure.temporary.ie11.step3',
|
||||
defaultMessage: 'Choose "edx.org" from the list of websites and change the permissions by selecting "Allow" in the dropdown menu.',
|
||||
description: 'Text for step three of enabling camera access.',
|
||||
},
|
||||
'id.verification.camera.access.failure.temporary.firefox': {
|
||||
id: 'id.verification.camera.access.failure.temporary.firefox',
|
||||
defaultMessage: 'To enable camera access in Firefox:',
|
||||
description: 'Description for the directions on enabling camera access.',
|
||||
},
|
||||
'id.verification.camera.access.failure.temporary.firefox.step1': {
|
||||
id: 'id.verification.camera.access.failure.temporary.firefox.step1',
|
||||
defaultMessage: 'Open Firefox.',
|
||||
description: 'Text for step one of enabling camera access.',
|
||||
},
|
||||
'id.verification.camera.access.failure.temporary.firefox.step2': {
|
||||
id: 'id.verification.camera.access.failure.temporary.firefox.step2',
|
||||
defaultMessage: 'Enter "about:preferences" in the URL bar.',
|
||||
description: 'Text for step two of enabling camera access.',
|
||||
},
|
||||
'id.verification.camera.access.failure.temporary.firefox.step3': {
|
||||
id: 'id.verification.camera.access.failure.temporary.firefox.step3',
|
||||
defaultMessage: 'Select the "Privacy & Security" tab, and navigate to the "Permissions" section.',
|
||||
description: 'Text for step three of enabling camera access.',
|
||||
},
|
||||
'id.verification.camera.access.failure.temporary.firefox.step4': {
|
||||
id: 'id.verification.camera.access.failure.temporary.firefox.step4',
|
||||
defaultMessage: 'Next to "Camera," select the "Settings…" button.',
|
||||
description: 'Text for step four of enabling camera access.',
|
||||
},
|
||||
'id.verification.camera.access.failure.temporary.firefox.step5': {
|
||||
id: 'id.verification.camera.access.failure.temporary.firefox.step5',
|
||||
defaultMessage: 'In the search bar, enter "edx.org."',
|
||||
description: 'Text for step five of enabling camera access.',
|
||||
},
|
||||
'id.verification.camera.access.failure.temporary.firefox.step6': {
|
||||
id: 'id.verification.camera.access.failure.temporary.firefox.step6',
|
||||
defaultMessage: 'In the status column for "edx.org," select "Allow" from the drop down.',
|
||||
description: 'Text for step six of enabling camera access.',
|
||||
},
|
||||
'id.verification.camera.access.failure.temporary.firefox.step7': {
|
||||
id: 'id.verification.camera.access.failure.temporary.firefox.step7',
|
||||
defaultMessage: 'Select "Save Changes."',
|
||||
description: 'Text for step seven of enabling camera access.',
|
||||
},
|
||||
'id.verification.camera.access.failure.temporary.safari': {
|
||||
id: 'id.verification.camera.access.failure.temporary.safari',
|
||||
defaultMessage: 'To enable camera access in Safari:',
|
||||
description: 'Description for the directions on enabling camera access.',
|
||||
},
|
||||
'id.verification.camera.access.failure.temporary.safari.step1': {
|
||||
id: 'id.verification.camera.access.failure.temporary.safari.step1',
|
||||
defaultMessage: 'Open Safari.',
|
||||
description: 'Text for step one of enabling camera access.',
|
||||
},
|
||||
'id.verification.camera.access.failure.temporary.safari.step2': {
|
||||
id: 'id.verification.camera.access.failure.temporary.safari.step2',
|
||||
defaultMessage: 'Click on the Safari app menu, then select "Preferences." You can also use Command+, as a keyboard shortcut.',
|
||||
description: 'Text for step two of enabling camera access.',
|
||||
},
|
||||
'id.verification.camera.access.failure.temporary.safari.step3': {
|
||||
id: 'id.verification.camera.access.failure.temporary.safari.step3',
|
||||
defaultMessage: 'Select the "Websites" tab and then select "Camera."',
|
||||
description: 'Text for step three of enabling camera access.',
|
||||
},
|
||||
'id.verification.camera.access.failure.temporary.safari.step4': {
|
||||
id: 'id.verification.camera.access.failure.temporary.safari.step4',
|
||||
defaultMessage: 'Select "edx.org" and change the camera permissions to "Allow."',
|
||||
description: 'Text for step four of enabling camera access.',
|
||||
},
|
||||
'id.verification.photo.tips.title': {
|
||||
id: 'id.verification.photo.tips.title',
|
||||
defaultMessage: 'Helpful Photo Tips',
|
||||
|
||||
71
src/id-verification/panels/EnableCameraDirectionsPanel.jsx
Normal file
71
src/id-verification/panels/EnableCameraDirectionsPanel.jsx
Normal file
@@ -0,0 +1,71 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||
import messages from '../IdVerification.messages';
|
||||
|
||||
export function EnableCameraDirectionsPanel(props) {
|
||||
if (props.browserName === 'Internet Explorer') {
|
||||
return (
|
||||
<>
|
||||
<h6>{props.intl.formatMessage(messages['id.verification.camera.access.failure.temporary.ie11'])}</h6>
|
||||
<ol>
|
||||
<li>{props.intl.formatMessage(messages['id.verification.camera.access.failure.temporary.ie11.step1'])}</li>
|
||||
<li>{props.intl.formatMessage(messages['id.verification.camera.access.failure.temporary.ie11.step2'])}</li>
|
||||
<li>{props.intl.formatMessage(messages['id.verification.camera.access.failure.temporary.ie11.step3'])}</li>
|
||||
</ol>
|
||||
</>
|
||||
);
|
||||
} else if (props.browserName === 'Chrome') {
|
||||
return (
|
||||
<>
|
||||
<h6>{props.intl.formatMessage(messages['id.verification.camera.access.failure.temporary.chrome'])}</h6>
|
||||
<ol>
|
||||
<li>{props.intl.formatMessage(messages['id.verification.camera.access.failure.temporary.chrome.step1'])}</li>
|
||||
<li>{props.intl.formatMessage(messages['id.verification.camera.access.failure.temporary.chrome.step2'])}</li>
|
||||
<ul>
|
||||
<li>{props.intl.formatMessage(messages['id.verification.camera.access.failure.temporary.chrome.step2.windows'])}</li>
|
||||
<li>{props.intl.formatMessage(messages['id.verification.camera.access.failure.temporary.chrome.step2.mac'])}</li>
|
||||
</ul>
|
||||
<li>{props.intl.formatMessage(messages['id.verification.camera.access.failure.temporary.chrome.step3'])}</li>
|
||||
<li>{props.intl.formatMessage(messages['id.verification.camera.access.failure.temporary.chrome.step4'])}</li>
|
||||
<li>{props.intl.formatMessage(messages['id.verification.camera.access.failure.temporary.chrome.step5'])}</li>
|
||||
</ol>
|
||||
</>
|
||||
);
|
||||
} else if (props.browserName === 'Firefox') {
|
||||
return (
|
||||
<>
|
||||
<h6>{props.intl.formatMessage(messages['id.verification.camera.access.failure.temporary.firefox'])}</h6>
|
||||
<ol>
|
||||
<li>{props.intl.formatMessage(messages['id.verification.camera.access.failure.temporary.firefox.step1'])}</li>
|
||||
<li>{props.intl.formatMessage(messages['id.verification.camera.access.failure.temporary.firefox.step2'])}</li>
|
||||
<li>{props.intl.formatMessage(messages['id.verification.camera.access.failure.temporary.firefox.step3'])}</li>
|
||||
<li>{props.intl.formatMessage(messages['id.verification.camera.access.failure.temporary.firefox.step4'])}</li>
|
||||
<li>{props.intl.formatMessage(messages['id.verification.camera.access.failure.temporary.firefox.step5'])}</li>
|
||||
<li>{props.intl.formatMessage(messages['id.verification.camera.access.failure.temporary.firefox.step6'])}</li>
|
||||
<li>{props.intl.formatMessage(messages['id.verification.camera.access.failure.temporary.firefox.step7'])}</li>
|
||||
</ol>
|
||||
</>
|
||||
);
|
||||
} else if (props.browserName === 'Safari') {
|
||||
return (
|
||||
<>
|
||||
<h6>{props.intl.formatMessage(messages['id.verification.camera.access.failure.temporary.safari'])}</h6>
|
||||
<ol>
|
||||
<li>{props.intl.formatMessage(messages['id.verification.camera.access.failure.temporary.safari.step1'])}</li>
|
||||
<li>{props.intl.formatMessage(messages['id.verification.camera.access.failure.temporary.safari.step2'])}</li>
|
||||
<li>{props.intl.formatMessage(messages['id.verification.camera.access.failure.temporary.safari.step3'])}</li>
|
||||
<li>{props.intl.formatMessage(messages['id.verification.camera.access.failure.temporary.safari.step4'])}</li>
|
||||
</ol>
|
||||
</>
|
||||
);
|
||||
}
|
||||
return <></>;
|
||||
}
|
||||
|
||||
EnableCameraDirectionsPanel.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
browserName: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
export default injectIntl(EnableCameraDirectionsPanel);
|
||||
@@ -1,5 +1,6 @@
|
||||
import React, { useState, useEffect, useContext } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import Bowser from 'bowser';
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
import { sendTrackEvent } from '@edx/frontend-platform/analytics';
|
||||
import { injectIntl, intlShape, FormattedMessage } from '@edx/frontend-platform/i18n';
|
||||
@@ -7,6 +8,7 @@ import { injectIntl, intlShape, FormattedMessage } from '@edx/frontend-platform/
|
||||
import { useNextPanelSlug } from '../routing-utilities';
|
||||
import BasePanel from './BasePanel';
|
||||
import { IdVerificationContext, MEDIA_ACCESS } from '../IdVerificationContext';
|
||||
import { EnableCameraDirectionsPanel } from './EnableCameraDirectionsPanel';
|
||||
|
||||
import messages from '../IdVerification.messages';
|
||||
|
||||
@@ -16,6 +18,7 @@ function RequestCameraAccessPanel(props) {
|
||||
const panelSlug = 'request-camera-access';
|
||||
const nextPanelSlug = useNextPanelSlug(panelSlug);
|
||||
const { tryGetUserMedia, mediaAccess, userId } = useContext(IdVerificationContext);
|
||||
const browserName = Bowser.parse(window.navigator.userAgent).browser.name;
|
||||
|
||||
useEffect(() => {
|
||||
if (mediaAccess === MEDIA_ACCESS.UNSUPPORTED) {
|
||||
@@ -89,10 +92,11 @@ function RequestCameraAccessPanel(props) {
|
||||
)}
|
||||
|
||||
{[MEDIA_ACCESS.UNSUPPORTED, MEDIA_ACCESS.DENIED].includes(mediaAccess) && (
|
||||
<div>
|
||||
<div data-testid="camera-failure-instructions">
|
||||
<p data-testid="camera-access-failure">
|
||||
{props.intl.formatMessage(messages['id.verification.camera.access.failure.temporary'])}
|
||||
</p>
|
||||
<EnableCameraDirectionsPanel browserName={browserName} intl={props.intl} />
|
||||
<div className="action-row">
|
||||
<a className="btn btn-primary" href={`${getConfig().LMS_BASE_URL}/${returnUrl}`}>
|
||||
{props.intl.formatMessage(messages[returnText])}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React from 'react';
|
||||
import { Router } from 'react-router-dom';
|
||||
import Bowser from 'bowser';
|
||||
import { createMemoryHistory } from 'history';
|
||||
import { render, screen, cleanup, act, fireEvent } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
@@ -11,6 +12,8 @@ jest.mock('@edx/frontend-platform/analytics', () => ({
|
||||
sendTrackEvent: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('bowser');
|
||||
|
||||
const history = createMemoryHistory();
|
||||
|
||||
const IntlRequestCameraAccessPanel = injectIntl(RequestCameraAccessPanel);
|
||||
@@ -30,6 +33,7 @@ describe('RequestCameraAccessPanel', () => {
|
||||
|
||||
it('renders correctly with media access pending', async () => {
|
||||
contextValue.mediaAccess = 'pending';
|
||||
Bowser.parse = jest.fn().mockReturnValue({ browser: { name: '' } });
|
||||
await act(async () => render((
|
||||
<Router history={history}>
|
||||
<IntlProvider locale="en">
|
||||
@@ -45,6 +49,7 @@ describe('RequestCameraAccessPanel', () => {
|
||||
|
||||
it('renders correctly with media access granted and routes to PortraitPhotoContextPanel', async () => {
|
||||
contextValue.mediaAccess = 'granted';
|
||||
Bowser.parse = jest.fn().mockReturnValue({ browser: { name: '' } });
|
||||
await act(async () => render((
|
||||
<Router history={history}>
|
||||
<IntlProvider locale="en">
|
||||
@@ -63,6 +68,7 @@ describe('RequestCameraAccessPanel', () => {
|
||||
|
||||
it('renders correctly with media access denied', async () => {
|
||||
contextValue.mediaAccess = 'denied';
|
||||
Bowser.parse = jest.fn().mockReturnValue({ browser: { name: '' } });
|
||||
await act(async () => render((
|
||||
<Router history={history}>
|
||||
<IntlProvider locale="en">
|
||||
@@ -78,6 +84,7 @@ describe('RequestCameraAccessPanel', () => {
|
||||
|
||||
it('renders correctly with media access unsupported', async () => {
|
||||
contextValue.mediaAccess = 'unsupported';
|
||||
Bowser.parse = jest.fn().mockReturnValue({ browser: { name: '' } });
|
||||
await act(async () => render((
|
||||
<Router history={history}>
|
||||
<IntlProvider locale="en">
|
||||
@@ -90,4 +97,68 @@ describe('RequestCameraAccessPanel', () => {
|
||||
const text = await screen.findByTestId('camera-access-failure');
|
||||
expect(text).toHaveTextContent(/It looks like we're unable to access your camera./);
|
||||
});
|
||||
|
||||
it('renders correct directions for Chrome with media access denied', async () => {
|
||||
contextValue.mediaAccess = 'denied';
|
||||
Bowser.parse = jest.fn().mockReturnValue({ browser: { name: 'Chrome' } });
|
||||
await act(async () => render((
|
||||
<Router history={history}>
|
||||
<IntlProvider locale="en">
|
||||
<IdVerificationContext.Provider value={contextValue}>
|
||||
<IntlRequestCameraAccessPanel {...defaultProps} />
|
||||
</IdVerificationContext.Provider>
|
||||
</IntlProvider>
|
||||
</Router>
|
||||
)));
|
||||
const text = await screen.findByTestId('camera-failure-instructions');
|
||||
expect(text).toHaveTextContent(/Open Chrome./);
|
||||
});
|
||||
|
||||
it('renders correct directions for Firefox with media access denied', async () => {
|
||||
contextValue.mediaAccess = 'denied';
|
||||
Bowser.parse = jest.fn().mockReturnValue({ browser: { name: 'Firefox' } });
|
||||
await act(async () => render((
|
||||
<Router history={history}>
|
||||
<IntlProvider locale="en">
|
||||
<IdVerificationContext.Provider value={contextValue}>
|
||||
<IntlRequestCameraAccessPanel {...defaultProps} />
|
||||
</IdVerificationContext.Provider>
|
||||
</IntlProvider>
|
||||
</Router>
|
||||
)));
|
||||
const text = await screen.findByTestId('camera-failure-instructions');
|
||||
expect(text).toHaveTextContent(/Open Firefox./);
|
||||
});
|
||||
|
||||
it('renders correct directions for Safari with media access denied', async () => {
|
||||
contextValue.mediaAccess = 'denied';
|
||||
Bowser.parse = jest.fn().mockReturnValue({ browser: { name: 'Safari' } });
|
||||
await act(async () => render((
|
||||
<Router history={history}>
|
||||
<IntlProvider locale="en">
|
||||
<IdVerificationContext.Provider value={contextValue}>
|
||||
<IntlRequestCameraAccessPanel {...defaultProps} />
|
||||
</IdVerificationContext.Provider>
|
||||
</IntlProvider>
|
||||
</Router>
|
||||
)));
|
||||
const text = await screen.findByTestId('camera-failure-instructions');
|
||||
expect(text).toHaveTextContent(/Open Safari./);
|
||||
});
|
||||
|
||||
it('renders correct directions for IE11 with media access denied', async () => {
|
||||
contextValue.mediaAccess = 'denied';
|
||||
Bowser.parse = jest.fn().mockReturnValue({ browser: { name: 'Internet Explorer' } });
|
||||
await act(async () => render((
|
||||
<Router history={history}>
|
||||
<IntlProvider locale="en">
|
||||
<IdVerificationContext.Provider value={contextValue}>
|
||||
<IntlRequestCameraAccessPanel {...defaultProps} />
|
||||
</IdVerificationContext.Provider>
|
||||
</IntlProvider>
|
||||
</Router>
|
||||
)));
|
||||
const text = await screen.findByTestId('camera-failure-instructions');
|
||||
expect(text).toHaveTextContent(/Open the Flash Player/);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user