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
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { Button } from '@18f/identity-components';
import { useI18n } from '@18f/identity-react-i18n';
import { useContext } from 'react';
import FlowContext from '@18f/identity-verify-flow/context/flow-context';
import { addSearchParams, forceRedirect, Navigate } from '@18f/identity-url';
import { getConfigValue } from '@18f/identity-config';
import AnalyticsContext from '../context/analytics';
import { ServiceProviderContext } from '../context';

export interface DocumentCaptureNotReadyProps {
navigate?: Navigate;
}

function DocumentCaptureNotReady({ navigate }: DocumentCaptureNotReadyProps) {
const { t } = useI18n();
const { trackEvent } = useContext(AnalyticsContext);
const { currentStep } = useContext(FlowContext);
const { name: spName, failureToProofURL } = useContext(ServiceProviderContext);
const appName = getConfigValue('appName');
const handleExit = () => {
trackEvent('IdV: docauth not ready link clicked');
forceRedirect(
addSearchParams(spName ? failureToProofURL : '/account', {
step: currentStep,
location: 'not_ready',
}),
navigate,
);
};

return (
<>
<h2 className="h3">{t('doc_auth.not_ready.header')}</h2>
<p>
{spName
? t('doc_auth.not_ready.content_sp', {
sp_name: spName,
app_name: appName,
})
: t('doc_auth.not_ready.content_nosp', {
app_name: appName,
})}
</p>
<Button isUnstyled className="margin-top-1" onClick={handleExit}>
{spName
? t('doc_auth.not_ready.button_sp', { app_name: appName, sp_name: spName })
: t('doc_auth.not_ready.button_nosp')}
</Button>
</>
);
}

export default DocumentCaptureNotReady;
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { useContext } from 'react';
import { PageHeading } from '@18f/identity-components';
import {
FormStepError,
Expand All @@ -10,6 +11,8 @@ import { useI18n } from '@18f/identity-react-i18n';
import UnknownError from './unknown-error';
import TipList from './tip-list';
import DocumentSideAcuantCapture from './document-side-acuant-capture';
import DocumentCaptureNotReady from './document-capture-not-ready';
import { FeatureFlagContext } from '../context';

interface DocumentCaptureReviewIssuesProps {
isFailedDocType: boolean;
Expand Down Expand Up @@ -43,6 +46,7 @@ function DocumentCaptureReviewIssues({
hasDismissed,
}: DocumentCaptureReviewIssuesProps) {
const { t } = useI18n();
const { notReadySectionEnabled } = useContext(FeatureFlagContext);
return (
<>
<PageHeading>{t('doc_auth.headings.review_issues')}</PageHeading>
Expand Down Expand Up @@ -78,6 +82,7 @@ function DocumentCaptureReviewIssues({
/>
))}
<FormStepsButton.Submit />
{notReadySectionEnabled && <DocumentCaptureNotReady />}
<Cancel />
</>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import DocumentSideAcuantCapture from './document-side-acuant-capture';
import DeviceContext from '../context/device';
import UploadContext from '../context/upload';
import TipList from './tip-list';
import DocumentCaptureNotReady from './document-capture-not-ready';
import { FeatureFlagContext } from '../context';

/**
* @typedef {'front'|'back'} DocumentSide
Expand Down Expand Up @@ -43,7 +45,7 @@ function DocumentsStep({
const { isMobile } = useContext(DeviceContext);
const { isLastStep } = useContext(FormStepsContext);
const { flowPath } = useContext(UploadContext);

const { notReadySectionEnabled } = useContext(FeatureFlagContext);
return (
<>
{flowPath === 'hybrid' && <HybridDocCaptureWarning className="margin-bottom-4" />}
Expand All @@ -70,7 +72,7 @@ function DocumentsStep({
/>
))}
{isLastStep ? <FormStepsButton.Submit /> : <FormStepsButton.Continue />}

{notReadySectionEnabled && <DocumentCaptureNotReady />}
<Cancel />
</>
);
Expand Down
17 changes: 17 additions & 0 deletions app/javascript/packages/document-capture/context/feature-flag.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { createContext } from 'react';

export interface FeatureFlagContextProps {
/**
* Specify whether to show the not-ready section on doc capture screen.
* Populated from backend configuration
*/
notReadySectionEnabled: boolean;
}

const FeatureFlagContext = createContext<FeatureFlagContextProps>({
notReadySectionEnabled: false,
});

FeatureFlagContext.displayName = 'FeatureFlagContext';

export default FeatureFlagContext;
1 change: 1 addition & 0 deletions app/javascript/packages/document-capture/context/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ export {
} from './failed-capture-attempts';
export type { DeviceContextValue } from './device';
export { default as InPersonContext } from './in-person';
export { default as FeatureFlagContext } from './feature-flag';
11 changes: 11 additions & 0 deletions app/javascript/packs/document-capture.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
FailedCaptureAttemptsContextProvider,
MarketingSiteContextProvider,
InPersonContext,
FeatureFlagContext,
} from '@18f/identity-document-capture';
import { isCameraCapableMobile } from '@18f/identity-device';
import { FlowContext } from '@18f/identity-verify-flow';
Expand All @@ -33,6 +34,7 @@ interface AppRootData {
exitUrl: string;
idvInPersonUrl?: string;
securityAndPrivacyHowItWorksUrl: string;
uiNotReadySectionEnabled: string;
}

const appRoot = document.getElementById('document-capture-form')!;
Expand Down Expand Up @@ -99,6 +101,7 @@ const {
inPersonOutageExpectedUpdateDate,
usStatesTerritories = '',
phoneWithCamera = '',
uiNotReadySectionEnabled = '',
} = appRoot.dataset as DOMStringMap & AppRootData;

let parsedUsStatesTerritories = [];
Expand Down Expand Up @@ -175,6 +178,14 @@ const App = composeComponents(
maxSubmissionAttemptsBeforeNativeCamera: Number(maxSubmissionAttemptsBeforeNativeCamera),
},
],
[
FeatureFlagContext.Provider,
{
value: {
notReadySectionEnabled: String(uiNotReadySectionEnabled) === 'true',
},
},
],
[
DocumentCapture,
{
Expand Down
1 change: 1 addition & 0 deletions app/views/idv/shared/_document_capture.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
in_person_outage_expected_update_date: IdentityConfig.store.in_person_outage_expected_update_date,
us_states_territories: us_states_territories,
doc_auth_selfie_capture: IdentityConfig.store.doc_auth_selfie_capture,
ui_not_ready_section_enabled: IdentityConfig.store.doc_auth_not_ready_section_enabled,
} %>
<%= simple_form_for(
:doc_auth,
Expand Down
6 changes: 4 additions & 2 deletions config/application.yml.default
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ doc_auth_error_sharpness_threshold: 40
doc_auth_max_attempts: 5
doc_auth_max_capture_attempts_before_native_camera: 3
doc_auth_max_submission_attempts_before_native_camera: 3
doc_auth_not_ready_section_enabled: false
doc_auth_selfie_capture: '{"enabled":false}'
doc_auth_supported_country_codes: '["US", "GU", "VI", "AS", "MP", "PR", "USA" ,"GUM", "VIR", "ASM", "MNP", "PRI"]'
doc_capture_request_valid_for_minutes: 15
Expand Down Expand Up @@ -380,11 +381,12 @@ development:
database_worker_jobs_username: ''
database_worker_jobs_host: ''
database_worker_jobs_password: ''
doc_auth_selfie_capture: '{"enabled":false}'
doc_auth_selfie_capture: '{"enabled":false}'
doc_auth_vendor: 'mock'
doc_auth_vendor_randomize: false
doc_auth_vendor_randomize_percent: 0
doc_auth_vendor_randomize_alternate_vendor: ''
doc_auth_not_ready_section_enabled: true
domain_name: localhost:3000
enable_rate_limiting: false
hmac_fingerprinter_key: a2c813d4dca919340866ba58063e4072adc459b767a74cf2666d5c1eef3861db26708e7437abde1755eb24f4034386b0fea1850a1cb7e56bff8fae3cc6ade96c
Expand Down Expand Up @@ -523,7 +525,7 @@ test:
doc_auth_vendor_randomize: false
doc_auth_vendor_randomize_percent: 0
doc_auth_vendor_randomize_alternate_vendor: ''
doc_auth_selfie_capture: '{"enabled":false}'
doc_auth_selfie_capture: '{"enabled":false}'
doc_capture_polling_enabled: false
domain_name: www.example.com
hmac_fingerprinter_key: a2c813d4dca919340866ba58063e4072adc459b767a74cf2666d5c1eef3861db26708e7437abde1755eb24f4034386b0fea1850a1cb7e56bff8fae3cc6ade96c
Expand Down
9 changes: 9 additions & 0 deletions config/locales/doc_auth/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,15 @@ en:
- '<strong>Verify by mail</strong>: We’ll mail a letter to your home
address. This takes <strong>5 to 10 days</strong>.'
welcome: 'You will need your:'
not_ready:
button_nosp: Cancel and return to your profile
button_sp: Exit %{app_name} and return to %{sp_name}
content_nosp: If you exit %{app_name} now, you will not have verified your
identity. You can return later to finish this process.
content_sp: If you exit %{app_name} now and return to %{sp_name}, you will not
have verified your identity. You can return later to finish this
process.
header: Not ready to add photos?
phone_question:
do_not_have: I don’t have a phone
tips:
Expand Down
9 changes: 9 additions & 0 deletions config/locales/doc_auth/es.yml
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,15 @@ es:
- '<strong>Verificar por correo</strong>: Le enviaremos una carta a su
domicilio. Esto tarda entre <strong>5 y 10 días</strong>.'
welcome: 'Necesitará su:'
not_ready:
button_nosp: Cancelar y volver a su perfil
button_sp: Salir de %{app_name} y volver a %{sp_name}
content_nosp: Si sale ahora de %{app_name}, no habrá verificado su identidad.
Puede volver más tarde para completar este proceso.
content_sp: Si sale ahora de %{app_name} y regresa a %{sp_name}, no habrá
verificado su identidad. Puede volver más tarde para completar este
proceso.
header: ¿No está listo para enviar las fotos?
phone_question:
do_not_have: No tengo teléfono
tips:
Expand Down
9 changes: 9 additions & 0 deletions config/locales/doc_auth/fr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,15 @@ fr:
lettre à votre adresse personnelle. Cela prend <strong>5 à 10
jours</strong>.'
welcome: 'Vous aurez besoin de votre:'
not_ready:
button_nosp: Annuler et revenir à votre profil
button_sp: Quittez %{app_name} et retournez à %{sp_name}
content_nosp: Si vous quittez %{app_name}, votre identité n’aura pas été
vérifiée. Vous pourrez revenir plus tard pour terminer ce processus.
content_sp: Si vous quittez %{app_name} maintenant et revenez sur %{sp_name},
votre identité n’aura pas été vérifiée. Vous pourrez revenir plus tard
pour terminer ce processus.
header: Vous n’êtes pas prêt à ajouter des photos?
phone_question:
do_not_have: Je n’ai pas de téléphone
tips:
Expand Down
1 change: 1 addition & 0 deletions lib/identity_config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ def self.build_store(config_map)
config.add(:doc_auth_error_dpi_threshold, type: :integer)
config.add(:doc_auth_error_glare_threshold, type: :integer)
config.add(:doc_auth_error_sharpness_threshold, type: :integer)
config.add(:doc_auth_not_ready_section_enabled, type: :boolean)
config.add(:doc_auth_max_attempts, type: :integer)
config.add(:doc_auth_max_capture_attempts_before_native_camera, type: :integer)
config.add(:doc_auth_max_submission_attempts_before_native_camera, type: :integer)
Expand Down
14 changes: 13 additions & 1 deletion spec/features/idv/doc_auth/document_capture_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@
let(:user) { user_with_2fa }
let(:fake_analytics) { FakeAnalytics.new }
let(:sp_name) { 'Test SP' }
let(:enable_not_ready) { true }
before do
allow_any_instance_of(ApplicationController).to receive(:analytics).and_return(fake_analytics)
allow_any_instance_of(ServiceProviderSession).to receive(:sp_name).and_return(sp_name)

allow(IdentityConfig.store).to receive(:doc_auth_not_ready_section_enabled).
and_return(enable_not_ready)
visit_idp_from_oidc_sp_with_ial2

sign_in_and_2fa_user(user)
Expand Down Expand Up @@ -134,6 +136,16 @@

expect(DocAuthLog.find_by(user_id: user.id).state).to be_nil
end
context 'not ready section' do
it 'renders not ready section when enabled' do
expect(page).to have_content(
I18n.t(
'doc_auth.not_ready.content_sp', sp_name: sp_name,
app_name: APP_NAME
),
)
end
end
end

context 'standard mobile flow' do
Expand Down
Loading