Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lg 13876 seperate doc selfie into seperate forms #11194

Merged
merged 26 commits into from
Sep 13, 2024
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
ba502b7
Started work on form seperation
AShukla-GSA Sep 3, 2024
3ec108c
Upcoming Features, doc auth, seperate selfie and doc capture into sep…
AShukla-GSA Sep 4, 2024
c91c3b8
changelog: Upcoming Features, doc auth, seperate selfie and doc captu…
AShukla-GSA Sep 4, 2024
f3ced40
Resolve lint issues
AShukla-GSA Sep 4, 2024
adb963c
Trying to resolve dataset issues
AShukla-GSA Sep 4, 2024
c0a7ddd
Trying to resolve appRoot issue
AShukla-GSA Sep 4, 2024
fd64c92
Fixing js tests
AShukla-GSA Sep 4, 2024
82adaf8
Added hook, and resolved PR comments
AShukla-GSA Sep 5, 2024
250a625
Fixing js context test
AShukla-GSA Sep 5, 2024
980ec01
Changed to useEffect, needs further work. NOT Working
AShukla-GSA Sep 5, 2024
1619faf
Created isolated page for document capture, removed changeStepCanComp…
AShukla-GSA Sep 9, 2024
c1dfce3
Fixing rspec test
AShukla-GSA Sep 9, 2024
906229b
Changed to use componenets defined in other steps to resolve ticket L…
AShukla-GSA Sep 10, 2024
f5d8316
Resolving PR comments, fixing IPP steps on submission error bug
AShukla-GSA Sep 11, 2024
6c437db
Resolving failed tests
AShukla-GSA Sep 11, 2024
aa07a6e
Adding automated tests for functionality
AShukla-GSA Sep 12, 2024
8a67c3c
Adding context
AShukla-GSA Sep 12, 2024
d3337c0
Fixing test to click correct button
AShukla-GSA Sep 12, 2024
6f45874
changed test to search for correct page heading
AShukla-GSA Sep 12, 2024
a975758
Adding test for correct flow after re submission
AShukla-GSA Sep 12, 2024
c26c8c9
Removed flow test due to JSDOM doesn't support full page navigation c…
AShukla-GSA Sep 13, 2024
300c183
Adding ruby rspec tests to test split doc auth flow
AShukla-GSA Sep 13, 2024
a5388eb
Consolidated tests
AShukla-GSA Sep 13, 2024
33828eb
Added split doc auth flow to analytics_spec.rb
AShukla-GSA Sep 13, 2024
bfa8f0a
Resolving PR comments
AShukla-GSA Sep 13, 2024
34ac91f
Merge branch 'main' into lg-13876-seperate-doc-selfie-into-seperate-f…
AShukla-GSA Sep 13, 2024
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
Expand Up @@ -7,11 +7,9 @@ import type { FormStepComponentProps } from '@18f/identity-form-steps';
import GeneralError from './general-error';
import TipList from './tip-list';
import { SelfieCaptureContext } from '../context';
import {
DocumentCaptureSubheaderOne,
SelfieCaptureWithHeader,
DocumentFrontAndBackCapture,
} from './documents-and-selfie-step';
import { DocumentCaptureSubheaderOne } from './documents-and-selfie-step';
import { DocumentsCaptureStep } from './documents-step';
import { SelfieCaptureStep } from './selfie-step';
import type { ReviewIssuesStepValue } from './review-issues-step';

interface DocumentCaptureReviewIssuesProps extends FormStepComponentProps<ReviewIssuesStepValue> {
Expand Down Expand Up @@ -79,9 +77,9 @@ function DocumentCaptureReviewIssues({
]}
/>
)}
<DocumentFrontAndBackCapture defaultSideProps={defaultSideProps} value={value} />
<DocumentsCaptureStep defaultSideProps={defaultSideProps} value={value} />
{isSelfieCaptureEnabled && (
<SelfieCaptureWithHeader defaultSideProps={defaultSideProps} selfieValue={value.selfie} />
<SelfieCaptureStep defaultSideProps={defaultSideProps} selfieValue={value.selfie} />
)}
<FormStepsButton.Submit />
<Cancel />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import type { FormStep } from '@18f/identity-form-steps';
import { getConfigValue } from '@18f/identity-config';
import { UploadFormEntriesError } from '../services/upload';
import DocumentsAndSelfieStep from './documents-and-selfie-step';
import SelfieStep from './selfie-step';
import DocumentsStep from './documents-step';
import InPersonPrepareStep from './in-person-prepare-step';
import InPersonLocationPostOfficeSearchStep from './in-person-location-post-office-search-step';
import InPersonLocationFullAddressEntryPostOfficeSearchStep from './in-person-location-full-address-entry-post-office-search-step';
Expand All @@ -21,7 +23,7 @@ import { RetrySubmissionError } from './submission-complete';
import SuspenseErrorBoundary from './suspense-error-boundary';
import SubmissionInterstitial from './submission-interstitial';
import withProps from '../higher-order/with-props';
import { InPersonContext } from '../context';
import { InPersonContext, SelfieCaptureContext } from '../context';

interface DocumentCaptureProps {
/**
Expand All @@ -37,6 +39,7 @@ function DocumentCapture({ onStepChange = () => {} }: DocumentCaptureProps) {
const { t } = useI18n();
const { flowPath } = useContext(UploadContext);
const { trackSubmitEvent, trackVisitEvent } = useContext(AnalyticsContext);
const { isSelfieCaptureEnabled, docAuthSeparatePagesEnabled } = useContext(SelfieCaptureContext);
const { inPersonFullAddressEntryEnabled, inPersonURL, skipDocAuth, skipDocAuthFromHandoff } =
useContext(InPersonContext);
useDidUpdateEffect(onStepChange, [stepName]);
Expand All @@ -51,11 +54,25 @@ function DocumentCapture({ onStepChange = () => {} }: DocumentCaptureProps) {
: InPersonLocationPostOfficeSearchStep;

// Define different states to be used in human readable array declaration
const documentFormStep: FormStep = {
name: 'documents',
const documentAndSelfieFormStep: FormStep = {
name: 'documentsAndSelfie',
form: DocumentsAndSelfieStep,
title: t('doc_auth.headings.document_capture'),
};
const documentFormStep: FormStep = {
name: 'documents',
form: DocumentsStep,
title: t('doc_auth.headings.document_capture'), // might want to change title to isolated doc capture heading
};
const selfieFormStep: FormStep = {
name: 'selfie',
form: SelfieStep,
title: '', // TODO: replace with yml selfie_capture (Ticket LG-14392)
};
const documentsFormSteps: FormStep[] =
isSelfieCaptureEnabled && docAuthSeparatePagesEnabled && submissionError === undefined
? [documentFormStep, selfieFormStep]
: [documentAndSelfieFormStep];
const reviewFormStep: FormStep = {
name: 'review',
form:
Expand Down Expand Up @@ -131,10 +148,12 @@ function DocumentCapture({ onStepChange = () => {} }: DocumentCaptureProps) {
: ([prepareFormStep, locationFormStep, flowPath === 'hybrid' && hybridFormStep].filter(
Boolean,
) as FormStep[]);

const defaultSteps: FormStep[] = submissionError
? ([reviewFormStep] as FormStep[]).concat(inPersonSteps)
: ([documentFormStep] as FormStep[]);
const reviewAfterFailedSteps = [reviewFormStep] as FormStep[];
const reviewWithInPersonSteps = reviewAfterFailedSteps.concat(inPersonSteps);
const afterSubmissionErrorSteps = docAuthSeparatePagesEnabled
? reviewAfterFailedSteps
: reviewWithInPersonSteps;
const defaultSteps: FormStep[] = submissionError ? afterSubmissionErrorSteps : documentsFormSteps;

// If the user got here by opting-in to in-person proofing, when skipDocAuth === true,
// then set steps to inPersonSteps
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,10 @@ function DocumentSideAcuantCapture({
}: DocumentSideAcuantCaptureProps) {
const error = errors.find(({ field }) => field === side)?.error;
const { changeStepCanComplete } = useContext(FormStepsContext);
const { isSelfieCaptureEnabled, isSelfieDesktopTestMode } = useContext(SelfieCaptureContext);
const { isSelfieCaptureEnabled, isSelfieDesktopTestMode, docAuthSeparatePagesEnabled } =
useContext(SelfieCaptureContext);
const isUploadAllowed = isSelfieDesktopTestMode || !isSelfieCaptureEnabled;

const stepCanComplete = docAuthSeparatePagesEnabled ? undefined : true;
return (
<AcuantCapture
ref={registerField(side, { isRequired: true })}
Expand All @@ -79,7 +80,7 @@ function DocumentSideAcuantCapture({
onError(new Error(t('doc_auth.errors.doc.resubmit_failed_image')), { field: side });
changeStepCanComplete(false);
} else {
changeStepCanComplete(true);
changeStepCanComplete(stepCanComplete);
}
}}
onCameraAccessDeclined={() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,13 @@ import {
import { PageHeading } from '@18f/identity-components';
import { Cancel } from '@18f/identity-verify-flow';
import HybridDocCaptureWarning from './hybrid-doc-capture-warning';
import DocumentSideAcuantCapture from './document-side-acuant-capture';
import { SelfieCaptureStep } from './selfie-step';
import { DocumentsCaptureStep } from './documents-step';
import TipList from './tip-list';
import {
DefaultSideProps,
DocumentsAndSelfieStepValue,
} from '../interface/documents-image-selfie-value';
import { DeviceContext, SelfieCaptureContext, UploadContext } from '../context';

export function DocumentCaptureSubheaderOne({
Expand All @@ -20,83 +25,12 @@ export function DocumentCaptureSubheaderOne({
const { t } = useI18n();
return (
<h2>
<hr className="margin-y-5" />
{isSelfieCaptureEnabled && '1. '}
{t('doc_auth.headings.document_capture_subheader_id')}
</h2>
);
}

export function SelfieCaptureWithHeader({
defaultSideProps,
selfieValue,
}: {
defaultSideProps: DefaultSideProps;
selfieValue: ImageValue;
}) {
const { t } = useI18n();
return (
<>
<hr className="margin-y-5" />
<h2>2. {t('doc_auth.headings.document_capture_subheader_selfie')}</h2>
<p>{t('doc_auth.info.selfie_capture_content')}</p>
<TipList
title={t('doc_auth.tips.document_capture_selfie_selfie_text')}
titleClassName="margin-bottom-0 text-bold"
items={[
t('doc_auth.tips.document_capture_selfie_text1'),
t('doc_auth.tips.document_capture_selfie_text2'),
t('doc_auth.tips.document_capture_selfie_text3'),
t('doc_auth.tips.document_capture_selfie_text4'),
]}
/>
<DocumentSideAcuantCapture
{...defaultSideProps}
key="selfie"
side="selfie"
value={selfieValue}
/>
</>
);
}

export function DocumentFrontAndBackCapture({
defaultSideProps,
value,
}: {
defaultSideProps: DefaultSideProps;
value: Record<string, ImageValue>;
}) {
type DocumentSide = 'front' | 'back';
const documentsSides: DocumentSide[] = ['front', 'back'];
return (
<>
{documentsSides.map((side) => (
<DocumentSideAcuantCapture
{...defaultSideProps}
key={side}
side={side}
value={value[side]}
/>
))}
</>
);
}

type ImageValue = Blob | string | null | undefined;

interface DocumentsAndSelfieStepValue {
front: ImageValue;
back: ImageValue;
selfie: ImageValue;
front_image_metadata?: string;
back_image_metadata?: string;
}

type DefaultSideProps = Pick<
FormStepComponentProps<DocumentsAndSelfieStepValue>,
'registerField' | 'onChange' | 'errors' | 'onError'
>;

export default function DocumentsAndSelfieStep({
value = {},
onChange = () => {},
Expand All @@ -109,11 +43,9 @@ export default function DocumentsAndSelfieStep({
const { isLastStep } = useContext(FormStepsContext);
const { flowPath } = useContext(UploadContext);
const { isSelfieCaptureEnabled } = useContext(SelfieCaptureContext);

const pageHeaderText = isSelfieCaptureEnabled
? t('doc_auth.headings.document_capture_with_selfie')
: t('doc_auth.headings.document_capture');

const defaultSideProps: DefaultSideProps = {
registerField,
onChange,
Expand All @@ -136,9 +68,9 @@ export default function DocumentsAndSelfieStep({
t('doc_auth.tips.document_capture_id_text3'),
].concat(!isMobile ? [t('doc_auth.tips.document_capture_id_text4')] : [])}
/>
<DocumentFrontAndBackCapture defaultSideProps={defaultSideProps} value={value} />
<DocumentsCaptureStep defaultSideProps={defaultSideProps} value={value} />
{isSelfieCaptureEnabled && (
<SelfieCaptureWithHeader defaultSideProps={defaultSideProps} selfieValue={value.selfie} />
<SelfieCaptureStep defaultSideProps={defaultSideProps} selfieValue={value.selfie} />
)}
{isLastStep ? <FormStepsButton.Submit /> : <FormStepsButton.Continue />}
<Cancel />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { useContext } from 'react';
import { useI18n } from '@18f/identity-react-i18n';
import { FormStepComponentProps, FormStepsButton } from '@18f/identity-form-steps';
import { PageHeading } from '@18f/identity-components';
import { Cancel } from '@18f/identity-verify-flow';
import HybridDocCaptureWarning from './hybrid-doc-capture-warning';
import TipList from './tip-list';
import { DeviceContext, SelfieCaptureContext, UploadContext } from '../context';
import {
ImageValue,
DefaultSideProps,
DocumentsAndSelfieStepValue,
} from '../interface/documents-image-selfie-value';
import DocumentSideAcuantCapture from './document-side-acuant-capture';

export function DocumentsCaptureStep({
defaultSideProps,
value,
}: {
defaultSideProps: DefaultSideProps;
value: Record<string, ImageValue>;
}) {
type DocumentSide = 'front' | 'back';
const documentsSides: DocumentSide[] = ['front', 'back'];
return (
<>
{documentsSides.map((side) => (
<DocumentSideAcuantCapture
{...defaultSideProps}
key={side}
side={side}
value={value[side]}
/>
))}
</>
);
}

export function DocumentCaptureSubheaderOne() {
const { t } = useI18n();
return (
<h2>
<hr className="margin-y-5" />
{'1. '}
{t('doc_auth.headings.document_capture_subheader_id')}
</h2>
);
}

export default function DocumentsStep({
value = {},
onChange = () => {},
errors = [],
onError = () => {},
registerField = () => undefined,
}: FormStepComponentProps<DocumentsAndSelfieStepValue>) {
const { t } = useI18n();
const { isMobile } = useContext(DeviceContext);
const { flowPath } = useContext(UploadContext);
const { isSelfieCaptureEnabled } = useContext(SelfieCaptureContext);
const pageHeaderText = isSelfieCaptureEnabled
? t('doc_auth.headings.document_capture_with_selfie')
: t('doc_auth.headings.document_capture');
const defaultSideProps: DefaultSideProps = {
registerField,
onChange,
errors,
onError,
};
return (
<>
{flowPath === 'hybrid' && <HybridDocCaptureWarning className="margin-bottom-4" />}
<PageHeading>{pageHeaderText}</PageHeading>
<DocumentCaptureSubheaderOne />
<TipList
titleClassName="margin-bottom-0 text-bold"
title={t('doc_auth.tips.document_capture_selfie_id_header_text')}
items={[
t('doc_auth.tips.document_capture_id_text1'),
t('doc_auth.tips.document_capture_id_text2'),
t('doc_auth.tips.document_capture_id_text3'),
].concat(!isMobile ? [t('doc_auth.tips.document_capture_id_text4')] : [])}
/>
<DocumentsCaptureStep defaultSideProps={defaultSideProps} value={value} />
<FormStepsButton.Continue />
<Cancel />
</>
);
}
Loading