@adyen/kyc-components
Version:
This guide assumes that you have already an account with Adyen. A legalEntity needs to be created, and you need to have a `legalEntityId` to instatiate a Component.
851 lines (850 loc) • 31.6 kB
JavaScript
try {
let e = "undefined" != typeof window ? window : "undefined" != typeof global ? global : "undefined" != typeof globalThis ? globalThis : "undefined" != typeof self ? self : {}, n = new e.Error().stack;
n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "7b4b96e7-1b36-48a4-ae5f-964d815a57d9", e._sentryDebugIdIdentifier = "sentry-dbid-7b4b96e7-1b36-48a4-ae5f-964d815a57d9");
} catch (e) {}
import { i as Typography, o as createLogger, r as useTranslation } from "./translation-BYvhW5zA.js";
import { n as IconButton, t as Button } from "./Button-i8I2dHP8.js";
import { r as httpPost, s as useApiContext } from "./http-8qgzqVqk.js";
import { l as keysOf, o as objectsDeepEqual, s as pick, u as valuesOf } from "./AnalyticsContext-BFrJmsp0.js";
import { t as CountryCodes } from "./country-code-CJk2hdPu.js";
import { n as translateTranslatable } from "./utils-C1buyvRw.js";
import { n as mergeFieldMetadataIntoProps, t as createFormUtils } from "./formUtils-DVc3a6gf.js";
import { a as alphanumericInputs, c as nonInputs, i as alphaInputs, l as numericInputs, o as customInputs, s as makeMask, t as MaskedInput, u as spacer } from "./MaskedInput-_dYxgb7_.js";
import { t as localizeDateString } from "./localizeDateString-Bmx3yBcR.js";
import { t as uppercase } from "./uppercase-DvjwUM0n.js";
import { o as validatePatternOnBlur } from "./patternValidators-DFve5Dzt.js";
import { t as resolveFieldMetadata } from "./fieldConfigurations-CZCFghnK.js";
import { t as Field } from "./Field-DoXLi6EY.js";
import { t as Checkbox } from "./Checkbox-D7BRIoQL.js";
import { t as Spacer } from "./Spacer-CEHRO4Ml.js";
import { useMemo } from "preact/hooks";
import { Fragment, jsx, jsxs } from "preact/jsx-runtime";
import { useMutation, useQuery } from "@tanstack/preact-query";
//#region src/utils/regex/countryIdNumberPatterns.ts
var CountryIdNumberPatterns = {
[CountryCodes.Brazil]: /^\d{11}$/,
[CountryCodes.Canada]: /^\d{9}$/,
[CountryCodes.Croatia]: /^\d{11}$/,
[CountryCodes.Denmark]: /^\d{10}$/,
[CountryCodes.Italy]: /^[A-Z]{6}[0-9]{2}[ABCDEHLMPRST][0-9]{2}[A-Z][0-9]{3}[A-Z]$/,
[CountryCodes.Poland]: /^\d{11}$/,
[CountryCodes.Romania]: /^\d{13}$/,
[CountryCodes.Singapore]: /^[A-Z][0-9]{7}[A-Z]$/,
[CountryCodes.Spain]: {
dni: /(^[KL]?\d{8}[A-Z]$)/,
nie: /(^[MXYZ]\d{7,8}[A-Z]$)/
},
[CountryCodes.Sweden]: /^\d{10}$|^\d{12}$/,
[CountryCodes.UnitedStates]: {
ssn: /^\d{9}$/,
ssnLastFour: /^\d{4}$/
}
};
//#endregion
//#region src/utils/regex/driversLicenseCardNumberPatterns.ts
var DriversLicenseCardNumberPatterns = {
[CountryCodes.NewZealand]: /^[\d]{3}$/,
[CountryCodes.Australia]: /^[A-Z0-9]{5,11}$/
};
//#endregion
//#region src/utils/regex/driversLicenseNumberPatterns.ts
var DriversLicenseNumberPatterns = {
[CountryCodes.Australia]: /^[A-Za-z0-9]{5,11}$/,
[CountryCodes.HongKong]: /^[A-Z0-9]{8}$/,
[CountryCodes.NewZealand]: /^[A-Z]{2}[0-9]{6}$/
};
//#endregion
//#region src/utils/regex/passportNumberPatterns.ts
var PassportNumberPatterns = {
[CountryCodes.Australia]: /^[A-Z0-9]{8,9}$/,
[CountryCodes.HongKong]: /^[A-Z0-9]{9}$/,
[CountryCodes.NewZealand]: /^[A-Z0-9]{8,9}$/
};
//#endregion
//#region src/utils/regex/proofOfIdentityCardPatterns.ts
var ProofOfIdentityCardPatterns = { [CountryCodes.HongKong]: /^[A-Z]{1,2}[0-9]{6}[0-9A]$/ };
//#endregion
//#region src/utils/verification/helpers/verifyIdNumber.ts
var COUNTRY_ID_NUMBER_MASKS = {
[CountryCodes.PuertoRico]: { length: 4 },
[CountryCodes.UnitedStates]: { length: 4 }
};
var COUNTRY_ID_NUMBER_UNMASKED = {
[CountryCodes.PuertoRico]: { length: 9 },
[CountryCodes.UnitedStates]: { length: 9 }
};
var ID_NUMBER_VERIFICATION_COUNTRIES = [CountryCodes.PuertoRico, CountryCodes.UnitedStates];
var FIELD = "idNumber";
var handleVerifyIdNumber = async (formData, basicDetails, verifyFn) => {
const country = formData.country;
const verified = {
field: "idNumber",
isVerified: true
};
if (formData.idNumberExempt || !country) return verified;
if (!ID_NUMBER_VERIFICATION_COUNTRIES.includes(country)) return verified;
const isCountryWithMaskedIdNumber = Object.keys(COUNTRY_ID_NUMBER_MASKS).includes(country);
const isValueMasked = formData.idNumber?.length === COUNTRY_ID_NUMBER_MASKS[country]?.length;
const hasCompleteValue = formData.idNumber?.length === COUNTRY_ID_NUMBER_UNMASKED[country]?.length;
if (isCountryWithMaskedIdNumber && isValueMasked) return verified;
if (!hasCompleteValue) return {
field: "idNumber",
isVerified: false
};
const response = await verifyFn({
name: {
firstName: basicDetails.firstName || "",
lastName: basicDetails.lastName || ""
},
countryCode: country,
idNumber: formData.idNumber || ""
});
if (response?.status === 422 || response?.verified === "false") return {
field: FIELD,
isVerified: false
};
return {
field: FIELD,
isVerified: true
};
};
//#endregion
//#region src/components/Individual/fields/IdentityNumber/fieldConfig.ts
var getAsyncIdNumberValidationRule = (verifyIdNumber, additionalPersonalDetails, basicDetails) => ({ idNumber: {
asyncValidate: async (idNumber) => {
if (!idNumber || !additionalPersonalDetails || !basicDetails) return false;
return (await handleVerifyIdNumber(additionalPersonalDetails, basicDetails, verifyIdNumber)).isVerified;
},
errorMessage: "unableToVerifyTheIdNumber",
modes: ["blur", "input"]
} });
var defaultFieldMetadata = { label: "idNumber" };
var defaultFieldConfig = {
[CountryCodes.Brazil]: {
label: "cadastroDePessoasFisicas",
mask: { mask: makeMask(...numericInputs(3), ...nonInputs(" . "), ...numericInputs(3), ...nonInputs(" . "), ...numericInputs(3), ...nonInputs(" - "), ...numericInputs(2)) },
validators: validatePatternOnBlur(CountryIdNumberPatterns[CountryCodes.Brazil]),
guidanceText: {
key: "enterNDigitsForExample",
values: {
numDigits: "11",
example: "231.002.999-00"
}
}
},
[CountryCodes.Canada]: {
label: "socialInsuranceNumber",
mask: { mask: makeMask(...numericInputs(3), spacer, ...numericInputs(3), spacer, ...numericInputs(3)) },
validators: validatePatternOnBlur(CountryIdNumberPatterns[CountryCodes.Canada]),
guidanceText: {
key: "enterNDigitsForExample",
values: {
numDigits: "9",
example: "046 454 286"
}
}
},
[CountryCodes.Croatia]: {
label: "oib",
mask: { mask: makeMask(...numericInputs(11)) },
validators: validatePatternOnBlur(CountryIdNumberPatterns[CountryCodes.Croatia]),
guidanceText: {
key: "enterNDigitsForExample",
values: {
numDigits: "11",
example: "94577403194"
}
}
},
[CountryCodes.Denmark]: {
label: "detCentralePersonregister",
mask: { mask: makeMask(...numericInputs(6), ...nonInputs(" - "), ...numericInputs(4)) },
validators: validatePatternOnBlur(CountryIdNumberPatterns[CountryCodes.Denmark]),
guidanceText: {
key: "enterNDigitsForExample",
values: {
numDigits: "10",
example: "010111-1113"
}
}
},
[CountryCodes.Italy]: {
label: "codiceFiscale",
mask: {
mask: makeMask(...alphaInputs(6), ...numericInputs(2), ...customInputs(1, /^[ABCDEHLMPRST]$/), ...numericInputs(2), ...alphaInputs(1), ...numericInputs(3), ...alphaInputs(1)),
transformOnType: uppercase
},
validators: validatePatternOnBlur(CountryIdNumberPatterns[CountryCodes.Italy]),
guidanceText: {
key: "enterNCharactersWithAMixForExample",
values: {
numChars: "16",
example: "YULSQG40E60L271T"
}
}
},
[CountryCodes.Poland]: {
label: "peselNumber",
mask: { mask: makeMask(...numericInputs(11)) },
validators: validatePatternOnBlur(CountryIdNumberPatterns[CountryCodes.Poland]),
guidanceText: {
key: "enterNDigitsForExample",
values: {
numDigits: "11",
example: "23012224757"
}
}
},
[CountryCodes.PuertoRico]: ({ idNumberType }) => {
switch (idNumberType) {
case "ssn": return {
label: "socialSecurityNumber",
mask: { mask: makeMask(...numericInputs(3), ...nonInputs(" - "), ...numericInputs(2), ...nonInputs(" - "), ...numericInputs(4)) },
validators: validatePatternOnBlur(CountryIdNumberPatterns[CountryCodes.UnitedStates].ssn),
guidanceText: {
key: "enterNDigitsForExample",
values: {
numDigits: "9",
example: "123-12-1234"
}
}
};
default: return {
label: "last4DigitsOfSocialSecurityNumber",
mask: { mask: makeMask(...numericInputs(4)) },
validators: {
modes: ["blur"],
validate: (val) => !!val && CountryIdNumberPatterns[CountryCodes.UnitedStates].ssnLastFour.test(val),
errorMessage: "mustContain4Digits"
}
};
}
},
[CountryCodes.Romania]: {
label: "codNumericPersonal",
mask: { mask: makeMask(...numericInputs(13)) },
validators: validatePatternOnBlur(CountryIdNumberPatterns[CountryCodes.Romania]),
guidanceText: {
key: "enterNDigitsForExample",
values: {
numDigits: "13",
example: "8001011234567"
}
}
},
[CountryCodes.Singapore]: {
label: "nric",
mask: {
mask: makeMask(...alphaInputs(1), ...numericInputs(7), ...alphaInputs(1)),
transformOnType: uppercase
},
validators: validatePatternOnBlur(CountryIdNumberPatterns[CountryCodes.Singapore]),
guidanceText: {
key: "enterNCharactersWithAMixForExample",
values: {
numChars: "9",
example: "T9123456J"
}
}
},
[CountryCodes.Spain]: ({ idNumberType }) => {
switch (idNumberType) {
case "dni": return {
label: "dni",
mask: {
mask: makeMask(...customInputs(1, /^[KL]$/, true), ...numericInputs(8), ...alphaInputs(1)),
transformOnType: uppercase
},
validators: validatePatternOnBlur(CountryIdNumberPatterns[CountryCodes.Spain].dni),
guidanceText: {
key: "enterXToYCharactersWithAMixForExample",
values: {
minChars: "9",
maxChars: "10",
example: "12345678A or L12345678A"
}
}
};
default: return {
label: "nie",
mask: {
mask: makeMask(...customInputs(1, /^[MXYZ]$/), ...numericInputs(7), ...numericInputs(1, true), ...alphaInputs(1)),
transformOnType: uppercase
},
validators: validatePatternOnBlur(CountryIdNumberPatterns[CountryCodes.Spain].nie),
guidanceText: {
key: "enterXToYCharactersWithAMixForExample",
values: {
minChars: "9",
maxChars: "10",
example: "X12345678A or Z6527153N"
}
}
};
}
},
[CountryCodes.Sweden]: {
label: "personnummer",
mask: { mask: makeMask(...numericInputs(6), ...numericInputs(2, true), ...nonInputs(" - "), ...numericInputs(4)) },
validators: validatePatternOnBlur(CountryIdNumberPatterns[CountryCodes.Sweden]),
guidanceText: {
key: "enterXOrYDigitsForExample",
values: {
xDigits: "10",
yDigits: "12",
example: "640823-3234 or 19640823-3234"
}
}
},
[CountryCodes.UnitedStates]: ({ idNumberType }) => {
switch (idNumberType) {
case "ssn": return {
label: "socialSecurityNumber",
mask: { mask: makeMask(...numericInputs(3), ...nonInputs(" - "), ...numericInputs(2), ...nonInputs(" - "), ...numericInputs(4)) },
validators: validatePatternOnBlur(CountryIdNumberPatterns[CountryCodes.UnitedStates].ssn),
guidanceText: {
key: "enterNDigitsForExample",
values: {
numDigits: "9",
example: "123-12-1234"
}
}
};
default: return {
label: "last4DigitsOfSocialSecurityNumber",
mask: { mask: makeMask(...numericInputs(4)) },
validators: {
modes: ["blur"],
validate: (val) => !!val && CountryIdNumberPatterns[CountryCodes.UnitedStates].ssnLastFour.test(val),
errorMessage: "mustContain4Digits"
}
};
}
},
[CountryCodes.NewZealand]: ({ idNumberType }) => {
switch (idNumberType) {
case "passport": return {
label: "passportNumber",
mask: {
mask: makeMask(...alphanumericInputs(9)),
transformOnType: uppercase
},
validators: validatePatternOnBlur(PassportNumberPatterns[CountryCodes.NewZealand]),
guidanceText: {
key: "enterXToYCharactersWithAMixForExample",
values: {
minChars: "8",
maxChars: "9",
example: "RA000750"
}
}
};
default: return {
label: "licenseNumber",
mask: {
mask: makeMask(...alphaInputs(2), ...numericInputs(6)),
transformOnType: uppercase
},
validators: validatePatternOnBlur(DriversLicenseNumberPatterns[CountryCodes.NewZealand]),
guidanceText: {
key: "enterNCharactersWithAMixForExample",
values: {
numChars: "8",
example: "KA111112"
}
}
};
}
},
[CountryCodes.HongKong]: ({ idNumberType }) => {
switch (idNumberType) {
case "proofOfIdentityCard": return {
label: "hkid",
mask: {
mask: makeMask(...alphaInputs(1), ...alphaInputs(1, true), ...numericInputs(6), ...nonInputs("(", { displayEagerly: false }), ...customInputs(1, /^[0-9A]$/), ...nonInputs(")")),
transformOnType: uppercase
},
validators: validatePatternOnBlur(ProofOfIdentityCardPatterns[CountryCodes.HongKong]),
guidanceText: {
key: "enterXToYCharactersWithAMixForExample",
values: {
minChars: "8",
maxChars: "9",
example: "Z683365(5) or AB123456(A)"
}
}
};
case "passport": return {
label: "passportNumber",
mask: {
mask: makeMask(...alphanumericInputs(9)),
transformOnType: uppercase
},
validators: validatePatternOnBlur(PassportNumberPatterns[CountryCodes.HongKong]),
guidanceText: {
key: "enterNCharactersWithAMixForExample",
values: {
numChars: "9",
example: "H12345678"
}
}
};
default: return {
label: "licenseNumber",
mask: {
mask: makeMask(...alphanumericInputs(7), spacer, ...alphanumericInputs(1)),
transformOnType: uppercase
},
validators: validatePatternOnBlur(DriversLicenseNumberPatterns[CountryCodes.HongKong]),
guidanceText: {
key: "enterNCharactersForExample",
values: {
numChars: "8",
example: "A123452 0"
}
}
};
}
},
[CountryCodes.Australia]: ({ idNumberType }) => {
switch (idNumberType) {
case "passport": return {
label: "passportNumber",
mask: {
mask: makeMask(...alphanumericInputs(9)),
transformOnType: uppercase
},
validators: validatePatternOnBlur(PassportNumberPatterns[CountryCodes.Australia]),
guidanceText: {
key: "enterXToYCharactersWithAMixForExample",
values: {
minChars: "8",
maxChars: "9",
example: "RA0123456"
}
}
};
default: return {
label: "licenseNumber",
mask: {
mask: makeMask(...alphanumericInputs(6), ...alphanumericInputs(5, true)),
transformOnType: uppercase
},
validators: validatePatternOnBlur(DriversLicenseNumberPatterns[CountryCodes.Australia]),
guidanceText: {
key: "enterXToYCharactersWithAMixForExample",
values: {
minChars: "5",
maxChars: "11",
example: "2093628291"
}
}
};
}
}
};
var licenseCardNumberDefaultMetadata = { label: "licenseCardNumber" };
var licenseCardNumberDefaultConfig = {
[CountryCodes.NewZealand]: {
label: "licenceVersionNumber",
mask: { mask: makeMask(...numericInputs(3)) },
validators: validatePatternOnBlur(DriversLicenseCardNumberPatterns[CountryCodes.NewZealand]),
guidanceText: {
key: "enterNDigitsForExample",
values: {
numDigits: "3",
example: "108"
}
}
},
[CountryCodes.Australia]: {
label: "licenseCardNumber",
mask: {
mask: makeMask(...alphanumericInputs(6), ...alphanumericInputs(5, true)),
transformOnType: uppercase
},
validators: validatePatternOnBlur(DriversLicenseCardNumberPatterns[CountryCodes.Australia]),
guidanceText: {
key: "enterXToYCharactersWithAMixForExample",
values: {
minChars: "5",
maxChars: "11",
example: "2093628291"
}
}
}
};
var idNumberExemptDefaultMetadata = { label: "identityNumberExempt" };
var idNumberExemptDefaultConfig = {
[CountryCodes.UnitedStates]: { label: "identityNumberExempt__US" },
[CountryCodes.Canada]: { label: "identityNumberExempt__CA" },
[CountryCodes.Singapore]: { label: "uploadDocumentForNric" }
};
//#endregion
//#region src/components/Individual/fields/IdentityNumber/IdentityNumber.tsx
var idNumberFields = ["idNumber", "idNumberExempt"];
function IdentityNumber(props) {
const { t } = useTranslation("common");
const { country, data, errors, fieldValidationErrors, idNumberType, obscuredFields, requiredFields, optionalFields, fieldConfig: propFieldConfig, readOnlyFields, handleFieldChange, valid } = props;
if (!handleFieldChange) return;
const metadata = resolveFieldMetadata((propFieldConfig ?? defaultFieldConfig)[country], { idNumberType }, defaultFieldMetadata);
const formUtils = createFormUtils(mergeFieldMetadataIntoProps("idNumberExempt", resolveFieldMetadata(idNumberExemptDefaultConfig[country], {}, idNumberExemptDefaultMetadata), mergeFieldMetadataIntoProps("idNumber", metadata, {
requiredFields,
optionalFields,
obscuredFields,
readOnlyFields
})), t);
const errorMessage = formUtils.getErrorMessage("idNumber", errors, fieldValidationErrors);
return /* @__PURE__ */ jsx("div", { children: formUtils.isVisibleField("idNumber") && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(MaskedInput, {
name: "idNumber",
type: "text",
label: formUtils.getLabel("idNumber", "idNumber"),
formatGuidance: translateTranslatable(t, metadata.guidanceText),
errorMessage,
shouldValidate: errors?.idNumber?.hasError,
isValid: !!valid?.idNumber,
"aria-required": formUtils.isRequiredField("idNumber"),
"aria-invalid": !valid?.idNumber,
disabled: data?.idNumberExempt,
onBlur: handleFieldChange("idNumber", "blur"),
readonly: formUtils.isReadOnly("idNumber"),
value: data?.idNumberExempt ? "" : data?.idNumber ?? "",
onInput: (e) => {
handleFieldChange("idNumber", "input")(e);
handleFieldChange("idNumberExempt", "input")(false);
},
acceptObscuredValue: formUtils?.isObscured("idNumber"),
...formUtils.getMask("idNumber")
}), formUtils.isVisibleField("idNumberExempt") && /* @__PURE__ */ jsx(Field, {
name: "idNumberExempt",
children: (childProps) => /* @__PURE__ */ jsx(Checkbox, {
...childProps,
label: formUtils.getLabel("idNumberExempt"),
checked: Boolean(data?.idNumberExempt),
name: "idNumberExempt",
onChange: handleFieldChange("idNumberExempt")
})
})] }) });
}
//#endregion
//#region src/api/idVerificationProviders/useExtractDocumentInformation.ts
var extractDocumentInformation = async (legalEntityId, baseUrl, data) => httpPost({
baseUrl,
path: `legalEntities/${legalEntityId}/providers/idVerification/extract`
}, data);
var useExtractDocumentInformation = (options) => {
const { rootLegalEntityId, baseUrl } = useApiContext();
return useMutation({
mutationFn: (data) => extractDocumentInformation(rootLegalEntityId.value, baseUrl.value, data),
...options
});
};
//#endregion
//#region src/utils/addressToString.tsx
/**
* Maps an Address object from the API model to the local AddressSchema used by forms.
* This is the single source of truth for this conversion.
* @param address - The Address object from the API (uses `street`, `street2`).
* @returns An AddressSchema object for use in UI components (uses `address`, `otherAddressInformation`).
*/
var mapApiAddressToSchema = (address) => ({
address: address.street,
otherAddressInformation: address.street2,
city: address.city,
postalCode: address.postalCode,
stateOrProvince: address.stateOrProvince,
country: address.country
});
var appendWithPreSeparator = (existing, separator, appendix) => existing.length === 0 ? appendix : `${existing}${separator}${appendix}`;
var addressToString = ({ address, otherAddressInformation, postalCode, city, stateOrProvince, country }, datasetUtils) => {
let out = "";
if (address) out = address;
if (otherAddressInformation) out = appendWithPreSeparator(out, " ", otherAddressInformation);
if (city) out = appendWithPreSeparator(out, ", ", city);
if (postalCode) out = appendWithPreSeparator(out, " ", postalCode);
if (stateOrProvince) out = appendWithPreSeparator(out, ", ", stateOrProvince);
if (country) out = appendWithPreSeparator(out, ", ", datasetUtils.getCountryName(country) ?? country);
return out;
};
//#endregion
//#region src/hooks/useDataConflicts.ts
var defaultConflictRule = (provided, detected) => {
if (detected === void 0 || detected === null) return { hasConflict: false };
if (provided === void 0 || provided === null) return {
hasConflict: false,
resolvedValue: detected
};
if (typeof provided === "string" && typeof detected === "string") return { hasConflict: provided.trim().toLowerCase() !== detected.trim().toLowerCase() };
return { hasConflict: !objectsDeepEqual(provided, detected) };
};
/**
* A factory function that returns a conflict rule for the `Address` model.
* The rule handles enrichment (auto-resolution) and deep equality checks.
*/
var createAddressConflictRule = (datasetUtils) => (provided, detected) => {
if (!detected || Object.keys(detected).length === 0) return { hasConflict: false };
if (!provided) return {
hasConflict: false,
resolvedValue: detected
};
if (provided.country !== detected.country) return { hasConflict: true };
const { country: _country, ...otherProvidedDetails } = provided;
if (valuesOf(otherProvidedDetails).every((value) => !value || value === "")) return {
hasConflict: false,
resolvedValue: detected
};
return { hasConflict: addressToString(mapApiAddressToSchema(provided), datasetUtils) !== addressToString(mapApiAddressToSchema(detected), datasetUtils) };
};
/**
* A hook to compare two data objects and identify conflicting properties.
* It supports custom rules for complex comparisons and can auto-resolve certain conflicts.
*
* @template T The shape of the data objects being compared.
* @param providedData The primary data source (e.g., user input).
* @param detectedData The secondary data source (e.g., OCR extraction).
* @param rules A map of custom conflict rules for specific properties.
* @param onAutoResolve
* @returns An object containing the conflict status and any resolved data.
*/
var useDataConflicts = (providedData, detectedData, rules = {}, onAutoResolve) => {
const { conflictingProperties, wasAutoResolved, resolvedData, hasConflicts } = useMemo(() => {
if (!providedData || !detectedData) return {
hasConflicts: false,
conflictingProperties: [],
wasAutoResolved: false,
resolvedData: void 0
};
const propertiesToCompare = keysOf(detectedData);
const conflictingProperties = [];
const autoResolvedPatches = /* @__PURE__ */ new Map();
for (const property of propertiesToCompare) {
const result = (rules[property] || defaultConflictRule)(providedData[property], detectedData[property]);
if (result.hasConflict) conflictingProperties.push(property);
else if (result.resolvedValue !== void 0) autoResolvedPatches.set(property, result.resolvedValue);
}
const hasConflicts = conflictingProperties.length > 0;
const wasAutoResolved = autoResolvedPatches.size > 0;
const resolvedData = wasAutoResolved ? {
...providedData ?? {},
...Object.fromEntries(autoResolvedPatches)
} : void 0;
if (wasAutoResolved && !hasConflicts && resolvedData) onAutoResolve?.(resolvedData);
return {
hasConflicts,
conflictingProperties,
wasAutoResolved,
resolvedData
};
}, [
providedData,
detectedData,
rules,
onAutoResolve
]);
return {
hasConflicts,
conflictingProperties,
wasAutoResolved,
resolvedData
};
};
var IdVerificationMethod_module_default = {
"verification-header-image": "_verification-header-image_1vivf_1",
verificationHeaderImage: "_verification-header-image_1vivf_1",
"or-separator": "_or-separator_1vivf_5",
orSeparator: "_or-separator_1vivf_5"
};
//#endregion
//#region src/components/Individual/forms/IdVerificationMethod/individualConflictsSchema.ts
/**
* Converts and flattens an {@link IndividualSchema} to an {@link IndividualConflictsSchema}.
*
* This is useful for comparing two {@link IndividualSchema} objects field by field.
*
* @param {IndividualSchema} individualSchema - The schema to convert.
* @returns {IndividualConflictsSchema} The flattened schema.
*/
var toIndividualConflictSchema = ({ basicDetails, additionalPersonalDetails }) => {
return {
firstName: basicDetails?.firstName,
lastName: basicDetails?.lastName,
email: basicDetails?.email,
phoneNumber: basicDetails?.phoneNumber,
birthDate: additionalPersonalDetails?.birthDate,
nationality: additionalPersonalDetails?.nationality,
address: pick("address", "otherAddressInformation", "postalCode", "city", "stateOrProvince", "country").from(additionalPersonalDetails),
idNumber: additionalPersonalDetails?.idNumber,
typeOfIdentity: additionalPersonalDetails?.typeOfIdentity,
issuerState: additionalPersonalDetails?.issuerState,
licenseCardNumber: additionalPersonalDetails?.licenseCardNumber,
expiryDate: additionalPersonalDetails?.expiryDate
};
};
/**
* Converts an {@link IndividualConflictsSchema} back to an {@link IndividualSchema}.
*
* This is useful for reconstructing the original schema after a comparison.
*
* @param {IndividualConflictsSchema} conflictSchema - The flattened schema to convert.
* @returns {IndividualSchema} The reconstructed schema.
*/
var fromIndividualConflictSchema = ({ firstName, lastName, email, phoneNumber, birthDate, nationality, address, ...idFields }) => ({
basicDetails: {
firstName,
lastName,
email,
phoneNumber
},
additionalPersonalDetails: {
birthDate,
nationality,
...idFields,
...address
}
});
//#endregion
//#region src/components/Individual/forms/IdVerificationMethod/mapExtractionResultToSchema.ts
var logger = createLogger();
var mapExtractionResultToSchema = (result, restrictCountryOfResidenceTo) => {
const { firstName, lastName, issuingCountry, issuingState, dateOfBirth, address, documentNumber, documentType, nationality, placeOfBirth } = result;
const schema = {
basicDetails: {
firstName,
lastName
},
additionalPersonalDetails: {}
};
let issuingCountryIsCountryOfResidency = false;
if (issuingCountry) {
const countryFromOcr = issuingCountry;
if (!restrictCountryOfResidenceTo || restrictCountryOfResidenceTo.includes(countryFromOcr)) {
schema.additionalPersonalDetails.country = countryFromOcr;
issuingCountryIsCountryOfResidency = true;
} else {
schema.additionalPersonalDetails.nationality = countryFromOcr;
issuingCountryIsCountryOfResidency = false;
}
}
if (dateOfBirth) schema.additionalPersonalDetails.birthDate = dateOfBirth;
if (issuingState) schema.additionalPersonalDetails.issuerState = issuingState;
if (nationality) schema.additionalPersonalDetails.nationality = nationality;
if (address && issuingCountryIsCountryOfResidency && Object.keys(address).length > 0) schema.additionalPersonalDetails = {
...schema.additionalPersonalDetails,
...mapAddressToSchema(address)
};
if (documentType) switch (documentType) {
case "identityCard":
schema.additionalPersonalDetails.typeOfIdentity = "proofOfIdentityCard";
schema.additionalPersonalDetails.idNumber = documentNumber;
break;
case "driversLicense":
schema.additionalPersonalDetails.typeOfIdentity = "driversLicense";
schema.additionalPersonalDetails.licenseCardNumber = documentNumber;
break;
case "passport":
schema.additionalPersonalDetails.typeOfIdentity = "passport";
schema.additionalPersonalDetails.idNumber = documentNumber;
break;
default:
logger.warn(`document type "${documentType}" not recognised`);
break;
}
return schema;
};
var mapAddressToSchema = ({ street, street2, city, postalCode, stateOrProvince }) => ({
address: street,
otherAddressInformation: street2,
city,
postalCode,
stateOrProvince
});
//#endregion
//#region src/api/idVerificationProviders/useIdVerificationToken.ts
var getIdVerificationToken = async (rootLegalEntityId, baseUrl, request) => httpPost({
baseUrl,
path: `legalEntities/${rootLegalEntityId}/providers/idVerification/initiate`
}, request);
/**
* Retrieves a token that we can use to proceed with ID verification for the given set of applicant
* details.
*
* **Note:** on the backend we re-use an existing Onfido applicant if a `legalEntityId` is sent
* and we have previously generated a token for that same legal entity. Therefore, this request
* effectively idempotent.
*/
var useIdVerificationToken = ({ firstName, lastName, residencyCountry }, legalEntityId, options) => {
const { rootLegalEntityId, baseUrl } = useApiContext();
const data = firstName && lastName && residencyCountry ? {
name: {
firstName,
lastName
},
country: residencyCountry,
origin: `${window.location.origin}/*`,
consents: [{
name: "privacy_notices_read",
granted: true
}],
...legalEntityId ? { legalEntityId } : {}
} : void 0;
return useQuery({
enabled: Boolean(firstName && lastName && residencyCountry),
queryKey: ["idVerificationToken", data],
queryFn: () => getIdVerificationToken(rootLegalEntityId.value, baseUrl.value, data),
...options
});
};
var UploadedDocument_module_default = {
"uploaded-document": "_uploaded-document_vsv6u_1",
uploadedDocument: "_uploaded-document_vsv6u_1"
};
//#endregion
//#region src/components/Individual/forms/IdVerificationMethod/UploadedDocument/UploadedDocument.tsx
var UploadedDocument = ({ document, onDelete, onUpdate }) => {
const { t, i18n } = useTranslation("common");
return /* @__PURE__ */ jsxs("article", {
className: UploadedDocument_module_default.uploadedDocument,
children: [
/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx(Typography, {
el: "h4",
variant: "title",
children: t(($) => $[document.idDocumentType])
}), /* @__PURE__ */ jsx(Typography, {
el: "p",
variant: "body",
children: t(($) => $["uploadedOn"], { date: localizeDateString(document.modificationDate, i18n.language, { month: "short" }) ?? "" })
})] }),
/* @__PURE__ */ jsx(Spacer, {}),
/* @__PURE__ */ jsx(IconButton, {
onClick: onDelete,
icon: "bin",
variant: "secondary",
ariaLabel: t(($) => $["delete"])
}),
/* @__PURE__ */ jsx(Button, {
onClick: onUpdate,
variant: "secondary",
children: t(($) => $["update"])
})
]
});
};
//#endregion
//#region src/components/Individual/forms/IdVerificationMethod/validateExtractionResult.ts
/**
* Validates the OCR extraction result against business rules.
* @param extractionResult - The data extracted from the document.
* @returns A translation key for an error message if validation fails, otherwise null.
*/
var validateExtractionResult = (extractionResult) => {
const { isExpired, isValidDocumentType, isUnderage, minimumOnboardingAge } = extractionResult;
if (isExpired) return { key: "theDocumentYouUploadedIsExpired" };
if (!isValidDocumentType) return { key: "theDocumentTypeYouUploadedIsNotSupported" };
if (isUnderage) return {
key: "weDontAcceptDocumentsOrInformationAboutAnyoneYoungerThan_",
options: { values: { minimumOnboardingAge: minimumOnboardingAge?.toString() ?? "" } }
};
return null;
};
//#endregion
export { licenseCardNumberDefaultConfig as _, fromIndividualConflictSchema as a, createAddressConflictRule as c, useExtractDocumentInformation as d, IdentityNumber as f, getAsyncIdNumberValidationRule as g, defaultFieldMetadata as h, mapExtractionResultToSchema as i, useDataConflicts as l, defaultFieldConfig as m, UploadedDocument as n, toIndividualConflictSchema as o, idNumberFields as p, useIdVerificationToken as r, IdVerificationMethod_module_default as s, validateExtractionResult as t, addressToString as u, licenseCardNumberDefaultMetadata as v };