app/javascript/packs/document-capture.tsx
import { render } from 'react-dom';
import { composeComponents } from '@18f/identity-compose-components';
import {
DocumentCapture,
DeviceContext,
AcuantContextProvider,
UploadContextProvider,
ServiceProviderContextProvider,
AnalyticsContextProvider,
FailedCaptureAttemptsContextProvider,
MarketingSiteContextProvider,
InPersonContext,
SelfieCaptureContext,
} from '@18f/identity-document-capture';
import { isCameraCapableMobile } from '@18f/identity-device';
import { FlowContext } from '@18f/identity-verify-flow';
import { trackEvent as baseTrackEvent } from '@18f/identity-analytics';
import { extendSession } from '@18f/identity-session';
import type { FlowPath, DeviceContextValue } from '@18f/identity-document-capture';
/**
* @see MarketingSiteContextProvider
* @see FailedCaptureAttemptsContext
* @see UploadContext
*/
interface AppRootData {
helpCenterRedirectUrl: string;
maxAttemptsBeforeNativeCamera: string;
acuantSdkUpgradeABTestingEnabled: string;
useAlternateSdk: string;
acuantVersion: string;
flowPath: FlowPath;
cancelUrl: string;
idvInPersonUrl?: string;
optedInToInPersonProofing: string;
securityAndPrivacyHowItWorksUrl: string;
skipDocAuth: string;
skipDocAuthFromHandoff: string;
howToVerifyURL: string;
previousStepUrl: string;
docAuthSelfieDesktopTestMode: string;
locationsUrl: string;
addressSearchUrl: string;
docAuthSeparatePagesEnabled: string;
}
const appRoot = document.getElementById('document-capture-form')!;
const isMockClient = appRoot.hasAttribute('data-mock-client');
const glareThreshold = Number(appRoot.getAttribute('data-glare-threshold')) ?? undefined;
const sharpnessThreshold = Number(appRoot.getAttribute('data-sharpness-threshold')) ?? undefined;
function getServiceProvider() {
const { spName: name = null, failureToProofUrl: failureToProofURL = '' } = appRoot.dataset;
return { name, failureToProofURL };
}
function getSelfieCaptureEnabled() {
const { docAuthSelfieCapture } = appRoot.dataset;
return docAuthSelfieCapture === 'true';
}
function getMetaContent(name): string | null {
const meta = document.querySelector<HTMLMetaElement>(`meta[name="${name}"]`);
return meta?.content ?? null;
}
const device: DeviceContextValue = { isMobile: isCameraCapableMobile() };
const trackEvent: typeof baseTrackEvent = (event, payload) => {
const {
flowPath,
acuantSdkUpgradeABTestingEnabled,
useAlternateSdk,
acuantVersion,
optedInToInPersonProofing,
} = appRoot.dataset;
return baseTrackEvent(event, {
...payload,
flow_path: flowPath,
acuant_sdk_upgrade_a_b_testing_enabled: acuantSdkUpgradeABTestingEnabled,
use_alternate_sdk: useAlternateSdk,
acuant_version: acuantVersion,
opted_in_to_in_person_proofing: optedInToInPersonProofing === 'true',
});
};
const formData: Record<string, any> = {
document_capture_session_uuid: appRoot.getAttribute('data-document-capture-session-uuid'),
locale: document.documentElement.lang,
};
const {
helpCenterRedirectUrl: helpCenterRedirectURL,
maxCaptureAttemptsBeforeNativeCamera,
maxSubmissionAttemptsBeforeNativeCamera,
acuantVersion,
flowPath,
cancelUrl: cancelURL,
accountUrl: accountURL,
idvInPersonUrl: inPersonURL,
securityAndPrivacyHowItWorksUrl: securityAndPrivacyHowItWorksURL,
inPersonFullAddressEntryEnabled,
inPersonOutageMessageEnabled,
inPersonOutageExpectedUpdateDate,
optedInToInPersonProofing,
usStatesTerritories = '',
skipDocAuth,
skipDocAuthFromHandoff,
howToVerifyUrl,
previousStepUrl,
docAuthSelfieDesktopTestMode,
docAuthSeparatePagesEnabled,
locationsUrl: locationsURL,
addressSearchUrl: addressSearchURL,
} = appRoot.dataset as DOMStringMap & AppRootData;
let parsedUsStatesTerritories = [];
try {
parsedUsStatesTerritories = JSON.parse(usStatesTerritories);
} catch (e) {}
const App = composeComponents(
[MarketingSiteContextProvider, { helpCenterRedirectURL, securityAndPrivacyHowItWorksURL }],
[DeviceContext.Provider, { value: device }],
[
InPersonContext.Provider,
{
value: {
inPersonURL,
locationsURL,
addressSearchURL,
inPersonOutageMessageEnabled: inPersonOutageMessageEnabled === 'true',
inPersonOutageExpectedUpdateDate,
inPersonFullAddressEntryEnabled: inPersonFullAddressEntryEnabled === 'true',
optedInToInPersonProofing: optedInToInPersonProofing === 'true',
usStatesTerritories: parsedUsStatesTerritories,
skipDocAuth: skipDocAuth === 'true',
skipDocAuthFromHandoff: skipDocAuthFromHandoff === 'true',
howToVerifyURL: howToVerifyUrl,
previousStepURL: previousStepUrl,
},
},
],
[AnalyticsContextProvider, { trackEvent }],
[
AcuantContextProvider,
{
sdkSrc: acuantVersion && `/acuant/${acuantVersion}/AcuantJavascriptWebSdk.min.js`,
cameraSrc: acuantVersion && `/acuant/${acuantVersion}/AcuantCamera.min.js`,
passiveLivenessOpenCVSrc: acuantVersion && `/acuant/${acuantVersion}/opencv.min.js`,
passiveLivenessSrc: getSelfieCaptureEnabled()
? acuantVersion && `/acuant/${acuantVersion}/AcuantPassiveLiveness.min.js`
: undefined,
credentials: getMetaContent('acuant-sdk-initialization-creds'),
endpoint: getMetaContent('acuant-sdk-initialization-endpoint'),
glareThreshold,
sharpnessThreshold,
},
],
[
UploadContextProvider,
{
endpoint: String(appRoot.getAttribute('data-endpoint')),
statusEndpoint: String(appRoot.getAttribute('data-status-endpoint')),
statusPollInterval: Number(appRoot.getAttribute('data-status-poll-interval-ms')),
isMockClient,
formData,
flowPath,
},
],
[
FlowContext.Provider,
{
value: {
accountURL,
cancelURL,
currentStep: 'document_capture',
},
},
],
[
ServiceProviderContextProvider,
{
value: getServiceProvider(),
},
],
[
SelfieCaptureContext.Provider,
{
value: {
isSelfieCaptureEnabled: getSelfieCaptureEnabled(),
isSelfieDesktopTestMode: String(docAuthSelfieDesktopTestMode) === 'true',
docAuthSeparatePagesEnabled: String(docAuthSeparatePagesEnabled) === 'true',
},
},
],
[
FailedCaptureAttemptsContextProvider,
{
maxCaptureAttemptsBeforeNativeCamera: Number(maxCaptureAttemptsBeforeNativeCamera),
maxSubmissionAttemptsBeforeNativeCamera: Number(maxSubmissionAttemptsBeforeNativeCamera),
},
],
[
DocumentCapture,
{
onStepChange: extendSession,
},
],
);
render(<App />, appRoot);