@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.
293 lines (292 loc) • 11.8 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] = "49700cd8-0269-461a-822b-d637dc58d9c1", e._sentryDebugIdIdentifier = "sentry-dbid-49700cd8-0269-461a-822b-d637dc58d9c1");
} catch (e) {}
import { o as createLogger, r as useTranslation } from "./translation-BFxyJ1c5.js";
import { r as httpPost, s as useApiContext } from "./http-D1NDkBxF.js";
import { u as entriesOf } from "./useAnalyticsContext-BVFDMrVE.js";
import { y as isEmpty } from "./validatorUtils-DRapRJ6z.js";
import { t as Header } from "./Header-CPmJyuoP.js";
import { t as CountryCodes } from "./country-code-CX5KqMBr.js";
import { t as useDataset } from "./useDataset-ZHrWhmsh.js";
import { t as datasetIdentifier } from "./datasetUtil-Zd4TCTDn.js";
import { n as mergeFieldMetadataIntoProps, t as createFormUtils } from "./formUtils-DCvL3uZG.js";
import { c as nonInputs, l as numericInputs, n as InputEmail, s as makeMask, t as MaskedInput, u as spacer } from "./MaskedInput-BFPSwRto.js";
import { n as emailPattern } from "./basePatterns-VqSYMnkh.js";
import { t as resolveFieldMetadata } from "./fieldConfigurations-m7oWP1DZ.js";
import { t as Field } from "./Field-pcJkjIG_.js";
import { t as Select } from "./Select-CcSRI-H0.js";
import { t as InputGroup } from "./InputGroup-CVYzCygf.js";
import { useCallback, useEffect, useMemo, useState } from "preact/hooks";
import { jsx, jsxs } from "preact/jsx-runtime";
import "@tanstack/preact-query";
//#region src/api/validation/useValidatePhoneNumber.ts
var validatePhoneNumber = (baseUrl, data) => {
return httpPost({
baseUrl,
path: `validations/phonenumber`
}, data);
};
var useValidatePhoneNumberImperatively = () => {
const { baseUrl } = useApiContext();
return useCallback((data) => validatePhoneNumber(baseUrl.value, data), [baseUrl.value]);
};
//#endregion
//#region src/components/Shared/fields/PhoneField/fieldConfig.ts
var validatePhoneCountryCodeNotEmptyOnBlur = {
modes: ["blur"],
validate: (phone) => !isEmpty(phone?.phoneCountryCode),
errorMessage: "missingPhoneCountryCode"
};
var validatePhoneNumberNotEmpty = {
modes: ["blur"],
validate: (phone) => !isEmpty(phone?.number),
errorMessage: "invalidPhoneNumber"
};
var getAsyncPhoneValidationRules = (validatePhoneNumber) => ({ phoneNumber: {
asyncValidate: async (phone) => {
if (!phone?.number) return false;
return (await validatePhoneNumber({ number: phone.number })).valid;
},
errorMessage: "invalidPhoneNumber",
modes: ["blur"]
} });
var defaultValidators = [validatePhoneCountryCodeNotEmptyOnBlur, validatePhoneNumberNotEmpty];
var defaultFieldMetadata = { validators: defaultValidators };
var fieldConfig = {
[CountryCodes.Albania]: {
validators: defaultValidators,
mask: { mask: makeMask(...numericInputs(2), spacer, ...numericInputs(3), spacer, ...numericInputs(4)) }
},
[CountryCodes.AmericanSamoa]: {
validators: defaultValidators,
mask: { mask: makeMask(...numericInputs(3), ...nonInputs("-"), ...numericInputs(4)) }
},
[CountryCodes.Netherlands]: {
validators: defaultValidators,
mask: { mask: makeMask(...numericInputs(1), spacer, ...numericInputs(8)) }
},
[CountryCodes.Singapore]: {
validators: defaultValidators,
mask: { mask: makeMask(...numericInputs(4), spacer, ...numericInputs(4)) }
},
[CountryCodes.Japan]: {
validators: defaultValidators,
mask: { mask: makeMask(...numericInputs(2), ...nonInputs("-"), ...numericInputs(4), ...nonInputs("-"), ...numericInputs(4)) }
},
[CountryCodes.UnitedStates]: {
validators: defaultValidators,
mask: { mask: makeMask(...nonInputs("(", { displayEagerly: false }), ...numericInputs(3), ...nonInputs(")"), spacer, ...numericInputs(3), ...nonInputs("-"), ...numericInputs(4)) }
}
};
/**
* Returns the placeholder text for the phone field based on country.
*/
var getPhonePlaceholder = (country) => {
switch (country) {
case CountryCodes.Albania: return "00 000 0000";
case CountryCodes.AmericanSamoa: return "000-0000";
case CountryCodes.Netherlands: return "0 00000000";
case CountryCodes.Singapore: return "0000 0000";
case CountryCodes.Japan: return "00-0000-0000";
case CountryCodes.UnitedStates: return "(000) 000-0000";
default: return;
}
};
//#endregion
//#region src/components/Shared/forms/ContactDetails/validate.ts
var contactDetailsValidationRules = { email: [{
modes: ["blur"],
validate: (email) => email ? emailPattern.test(email) : false,
errorMessage: "invalidEmail"
}] };
//#endregion
//#region src/components/Shared/fields/PhoneField/PhoneField.tsx
var PHONE_FIELD = ["phoneNumber"];
var logger = createLogger();
var usePhonePrefixes = () => {
const [phonePrefixes, setPhonePrefixes] = useState();
useEffect(() => {
const loadPhonePrefixes = async () => {
const loaded = (await import("./phonePrefixes-DcdX_CFz.js").then((n) => n.n)).default;
setPhonePrefixes(loaded);
};
loadPhonePrefixes().catch(logger.error);
}, []);
return phonePrefixes;
};
function PhoneField({ country, name = "phoneNumber", data, valid, errors, label, mask, readonly, optional, placeholder, helper, helperPosition, handleChangeFor }) {
const { t } = useTranslation("common");
const { dataset: countries } = useDataset(datasetIdentifier.country);
const [isFocused, setIsFocused] = useState(false);
const phonePrefixes = usePhonePrefixes();
const currentPrefix = phonePrefixes?.[data.phoneNumber?.phoneCountryCode ?? country];
const numberStrippedOfCountryCode = useMemo(() => {
if (!phonePrefixes || !data.phoneNumber?.number) return "";
return currentPrefix && data.phoneNumber?.number.startsWith(currentPrefix) ? data.phoneNumber.number.slice(currentPrefix.length) : data.phoneNumber.number;
}, [
phonePrefixes,
data.phoneNumber?.number,
currentPrefix
]);
const selectItems = useMemo(() => {
const countryMap = new Map(countries.map((entry) => [entry.id, entry.name]));
return entriesOf(phonePrefixes ?? {}).map(([countryCode, prefix]) => {
return {
id: countryCode,
name: `${countryMap.get(countryCode) ?? countryCode} (${prefix})`,
selectedOptionName: `${countryCode} (${prefix})`
};
}).sort((a, b) => a.name.localeCompare(b.name));
}, [phonePrefixes, countries]);
const handleSelectChange = useCallback((event) => {
const newCC = phonePrefixes?.[event.target.value];
const withoutCC = currentPrefix && data.phoneNumber?.number?.startsWith(currentPrefix) ? data.phoneNumber?.number?.slice(currentPrefix.length) : data.phoneNumber?.number?.replace(/\D+/g, "");
handleChangeFor("phoneNumber", "input")({
phoneCountryCode: event.target.value,
number: withoutCC ? newCC + withoutCC : newCC,
type: "mobile"
});
}, [
currentPrefix,
data.phoneNumber?.number,
handleChangeFor,
phonePrefixes
]);
const handleOnInput = useCallback((event) => {
const onlyDigits = (currentPrefix ? event.replace(currentPrefix, "") : event).replace(/\D+/g, "");
const number = currentPrefix ? `${currentPrefix}${onlyDigits}` : onlyDigits;
handleChangeFor("phoneNumber", "input")({
...data.phoneNumber,
number,
type: "mobile"
});
}, [
currentPrefix,
data.phoneNumber,
handleChangeFor
]);
const handleOnBlur = useCallback((event) => {
const onlyDigits = event.currentTarget.value.replace(/\D+/g, "");
const number = currentPrefix ? `${currentPrefix}${onlyDigits}` : onlyDigits;
setIsFocused(false);
handleChangeFor("phoneNumber", "blur")({
...data.phoneNumber,
number,
type: "mobile"
});
}, [
currentPrefix,
data.phoneNumber,
handleChangeFor
]);
const transformOnType = useCallback((value) => currentPrefix ? value.startsWith(currentPrefix) ? value.slice(currentPrefix.length) : value : value, [currentPrefix]);
useEffect(() => {
if (!data.phoneNumber?.phoneCountryCode && country) handleChangeFor("phoneNumber", "input")({
...data.phoneNumber,
phoneCountryCode: country,
type: "mobile"
});
}, [
country,
data.phoneNumber?.phoneCountryCode,
data?.phoneNumber,
handleChangeFor
]);
return /* @__PURE__ */ jsx(Field, {
el: "fieldset",
name,
label: label ?? t(($) => $["phoneNumber"]),
errorMessage: errors.phoneNumber,
isValid: Boolean(valid.phoneNumber),
optional: Boolean(optional),
disabled: Boolean(readonly),
helper,
helperPosition,
children: (childProps) => /* @__PURE__ */ jsxs(InputGroup, {
...childProps,
id: "phoneInputGroup",
isFocused,
isInvalid: Boolean(!valid.phoneNumber && errors.phoneNumber),
children: [/* @__PURE__ */ jsx(Select, {
name: "phoneCountryCode",
"aria-label": t(($) => $["phoneNumberPrefix"]),
isMulti: false,
items: selectItems,
selected: data.phoneNumber?.phoneCountryCode,
placeholder: t(($) => $["select"]),
onChange: handleSelectChange,
minimal: true
}), /* @__PURE__ */ jsx(MaskedInput, {
useFieldComponent: false,
name: "phoneNumber",
type: "tel",
label: label ?? t(($) => $["phoneNumber"]),
value: numberStrippedOfCountryCode,
"aria-invalid": Boolean(!valid.phoneNumber),
isValid: Boolean(valid.phoneNumber),
placeholder,
shouldValidate: true,
errorMessage: errors.phoneNumber,
readonly,
disabled: readonly,
transformOnType,
...mask,
stripNonAllowedInputs: true,
onInput: handleOnInput,
onBlur: handleOnBlur,
onFocus: () => setIsFocused(true)
})]
})
});
}
//#endregion
//#region src/components/Shared/forms/ContactDetails/ContactDetails.tsx
var contactDetailFields = [...PHONE_FIELD, "email"];
function ContactDetails(props) {
const { t } = useTranslation("common");
const { country, data, errors = {}, handleFieldChange, fieldValidationErrors, valid = {}, ...newProps } = props;
let mergedProps = newProps;
if (!handleFieldChange) return;
mergedProps = mergeFieldMetadataIntoProps("phoneNumber", resolveFieldMetadata(fieldConfig[data?.phoneNumber?.phoneCountryCode ?? country], {}, defaultFieldMetadata), mergedProps);
const formUtils = createFormUtils(mergedProps, t);
return /* @__PURE__ */ jsxs("div", {
role: "form",
className: "adyen-kyc-individual__contact-details",
children: [
mergedProps.heading && /* @__PURE__ */ jsx(Header, { title: mergedProps.heading }),
formUtils.isRequiredField("email") && /* @__PURE__ */ jsx("div", {
className: "adyen-kyc-email",
children: /* @__PURE__ */ jsx(Field, {
name: "email",
label: formUtils.getLabel("email"),
errorMessage: formUtils.getErrorMessage("email", errors, fieldValidationErrors),
isValid: valid.email,
children: (childProps) => /* @__PURE__ */ jsx(InputEmail, {
...childProps,
name: "email",
value: data?.email,
readonly: formUtils.isReadOnly("email"),
onInput: handleFieldChange("email", "input"),
onBlur: handleFieldChange("email", "blur"),
"aria-required": true,
"aria-invalid": !valid?.email
})
})
}),
formUtils.isRequiredField("phoneNumber") && /* @__PURE__ */ jsx(PhoneField, {
country,
data: formUtils.getFieldData(data ?? {}, PHONE_FIELD),
valid: formUtils.getFieldValid(valid, PHONE_FIELD),
errors: formUtils.getFieldErrors(errors, {}, PHONE_FIELD),
placeholder: getPhonePlaceholder(country),
optional: formUtils.isOptionalField("phoneNumber"),
readonly: formUtils.isReadOnly("phoneNumber"),
mask: formUtils.getMask("phoneNumber"),
handleChangeFor: handleFieldChange
})
]
});
}
//#endregion
export { defaultFieldMetadata as a, getPhonePlaceholder as c, contactDetailsValidationRules as i, useValidatePhoneNumberImperatively as l, contactDetailFields as n, fieldConfig as o, PhoneField as r, getAsyncPhoneValidationRules as s, ContactDetails as t };