Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions app/assets/javascripts/i18n-strings.js.erb
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,14 @@ window.LoginGov = window.LoginGov || {};
'doc_auth.forms.selected_file',
'doc_auth.forms.change_file',
'doc_auth.forms.choose_file',
'doc_auth.headings.document_capture',
'doc_auth.headings.upload_front',
'doc_auth.headings.upload_back',
'doc_auth.instructions.document_capture_header_text',
'doc_auth.instructions.document_capture_id_text1',
'doc_auth.instructions.document_capture_id_text2',
'doc_auth.instructions.document_capture_id_text3',
'doc_auth.instructions.document_capture_id_text4',
'users.personal_key.close'
] %>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import React from 'react';
import React, { useContext } from 'react';
import PropTypes from 'prop-types';
import FileInput from './file-input';
import PageHeading from './page-heading';
import useI18n from '../hooks/use-i18n';
import DeviceContext from '../context/device';

/**
* Sides of document to present as file input.
Expand All @@ -12,9 +14,20 @@ const DOCUMENT_SIDES = ['front', 'back'];

function DocumentsStep({ value, onChange }) {
const t = useI18n();
const { isMobile } = useContext(DeviceContext);

return (
<>
<PageHeading>{t('doc_auth.headings.document_capture')}</PageHeading>
<p className="margin-top-2 margin-bottom-0">
{t('doc_auth.instructions.document_capture_header_text')}
</p>
<ul>
<li>{t('doc_auth.instructions.document_capture_id_text1')}</li>
<li>{t('doc_auth.instructions.document_capture_id_text2')}</li>
<li>{t('doc_auth.instructions.document_capture_id_text3')}</li>
{!isMobile && <li>{t('doc_auth.instructions.document_capture_id_text4')}</li>}
</ul>
{DOCUMENT_SIDES.map((side) => {
const label = t(`doc_auth.headings.upload_${side}`);
const inputKey = `${side}_image`;
Expand Down
12 changes: 12 additions & 0 deletions app/javascript/app/document-capture/components/page-heading.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import React from 'react';
import PropTypes from 'prop-types';

function PageHeading({ children }) {
return <h1 className="h3 my0">{children}</h1>;
}

PageHeading.propTypes = {
children: PropTypes.node.isRequired,
};

export default PageHeading;
11 changes: 11 additions & 0 deletions app/javascript/app/document-capture/context/device.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { createContext } from 'react';

/**
* @typedef DeviceContext
*
* @prop {boolean} isMobile Device is a mobile device.
*/

const DeviceContext = createContext(/** @type {DeviceContext} */ ({ isMobile: false }));

export default DeviceContext;
12 changes: 11 additions & 1 deletion app/javascript/packs/document-capture.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { render } from 'react-dom';
import DocumentCapture from '../app/document-capture/components/document-capture';
import AssetContext from '../app/document-capture/context/asset';
import I18nContext from '../app/document-capture/context/i18n';
import DeviceContext from '../app/document-capture/context/device';
import { Provider as AcuantProvider } from '../app/document-capture/context/acuant';

const { I18n: i18n, assets } = window.LoginGov;
Expand All @@ -11,6 +12,13 @@ function getMetaContent(name) {
return document.querySelector(`meta[name="${name}"]`)?.content ?? null;
}

/** @type {import('../app/document-capture/context/device').DeviceContext} */
const device = {
isMobile:
'mediaDevices' in window.navigator &&
/ip(hone|ad|od)|android/i.test(window.navigator.userAgent),
};

const appRoot = document.getElementById('document-capture-form');
appRoot.innerHTML = '';
render(
Expand All @@ -20,7 +28,9 @@ render(
>
<I18nContext.Provider value={i18n.strings[i18n.currentLocale()]}>
<AssetContext.Provider value={assets}>
<DocumentCapture />
<DeviceContext.Provider value={device}>
<DocumentCapture />
</DeviceContext.Provider>
</AssetContext.Provider>
</I18nContext.Provider>
</AcuantProvider>,
Expand Down
6 changes: 6 additions & 0 deletions config/locales/doc_auth/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ en:
headings:
address: Mailing Address
capture_complete: We have verified your state issued ID
document_capture: Add your state-issued ID
document_capture_html: Upload your state&#8209;issued&nbsp;ID
document_capture_with_selfie_html: Upload your state&#8209;issued&nbsp;ID and
a photo of you
Expand Down Expand Up @@ -72,6 +73,11 @@ en:
and share your personal information. We will only use it to verify your identity.
document_capture_fallback_html: Having trouble? %{link}
document_capture_fallback_link: Click here to upload an image
document_capture_header_text: 'For best results:'
document_capture_id_text1: Use a dark background
document_capture_id_text2: Take the photo on a flat surface
document_capture_id_text3: Do not use the flash on your camera
document_capture_id_text4: File size should be at least 2 MB
email_sent: Link sent to %{email}. Please check your desktop email and follow
instructions to verify your identity.
learn_more: Learn more.
Expand Down
6 changes: 6 additions & 0 deletions config/locales/doc_auth/es.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ es:
headings:
address: Dirección de envio
capture_complete: Hemos verificado la identificación emitida por su estado
document_capture: Agregue su identificación emitida por el estado
document_capture_html: Cargue su identificación emitida por el estado
document_capture_with_selfie_html: Cargue su identificación emitida por el estado
y una foto suya
Expand Down Expand Up @@ -78,6 +79,11 @@ es:
su identidad.
document_capture_fallback_html: "¿Teniendo problemas? %{link}"
document_capture_fallback_link: Haga clic aquí para cargar una imagen.
document_capture_header_text: 'Para mejores resultados:'
document_capture_id_text1: Usa un fondo oscuro
document_capture_id_text2: Toma la foto sobre una superficie plana
document_capture_id_text3: No uses el flash en tu cámara
document_capture_id_text4: El tamaño del archivo debe ser de al menos 2 MB
email_sent: Enlace enviado a %{email}. Compruebe el correo electrónico de su
escritorio y siga las instrucciones para verificar su identidad.
learn_more: Aprende más.
Expand Down
6 changes: 6 additions & 0 deletions config/locales/doc_auth/fr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ fr:
headings:
address: Adresse mail
capture_complete: Nous avons vérifié votre ID émis par l'état
document_capture: Ajoutez votre pièce d'identité émise par l'État
document_capture_html: Téléchargez votre pièce d'identité délivrée par l'État
document_capture_with_selfie_html: Téléchargez votre pièce d'identité officielle
et une photo de vous
Expand Down Expand Up @@ -84,6 +85,11 @@ fr:
que pour vérifier votre identité.
document_capture_fallback_html: Avoir des problèmes? %{link}
document_capture_fallback_link: Cliquez ici pour télécharger une image
document_capture_header_text: 'Pour les meilleurs résultats:'
document_capture_id_text1: Utilisez un fond sombre
document_capture_id_text2: Prenez la photo sur une surface plane
document_capture_id_text3: Ne pas utiliser le flash sur votre appareil photo
document_capture_id_text4: La taille du fichier doit être d'au moins 2 Mo
email_sent: Lien envoyé à %{email}. Veuillez vérifier votre email de bureau
et suivez les instructions pour vérifier votre identité.
learn_more: Apprendre encore plus.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from 'react';
import userEvent from '@testing-library/user-event';
import sinon from 'sinon';
import render from '../../../support/render';
import DeviceContext from '../../../../../app/javascript/app/document-capture/context/device';
import DocumentsStep from '../../../../../app/javascript/app/document-capture/components/documents-step';

describe('document-capture/components/documents-step', () => {
Expand Down Expand Up @@ -39,4 +40,18 @@ describe('document-capture/components/documents-step', () => {
// See: https://github.com/testing-library/user-event/issues/421
expect(input.getAttribute('accept')).to.equal('image/*');
});

it('renders device-specific instructions', () => {
let { getByText } = render(
<DeviceContext.Provider value={{ isMobile: true }}>
<DocumentsStep />
</DeviceContext.Provider>,
);

expect(() => getByText('doc_auth.instructions.document_capture_id_text4')).to.throw();

getByText = render(<DocumentsStep />).getByText;

expect(() => getByText('doc_auth.instructions.document_capture_id_text4')).not.to.throw();
});
});
13 changes: 13 additions & 0 deletions spec/javascripts/app/document-capture/context/device-spec.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React, { useContext } from 'react';
import render from '../../../support/render';
import DeviceContext from '../../../../../app/javascript/app/document-capture/context/device';

describe('document-capture/context/device', () => {
const ContextValue = () => JSON.stringify(useContext(DeviceContext));

it('defaults to an object shape of device supports', () => {
const { container } = render(<ContextValue />);

expect(container.textContent).to.equal('{"isMobile":false}');
});
});