UNPKG

@adyen/kyc-components

Version:

`adyen-kyc-components` provides the required pieces to build an onboarding flow based on a legal entity. To onboard and verify users, you need to create a user interface (UI) to collect user data. To speed up building your integration, Adyen offers onboar

504 lines (503 loc) 20.9 kB
; { 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] = "c9e9f2dd-daee-494f-94d2-a8615ac78c60", e._sentryDebugIdIdentifier = "sentry-dbid-c9e9f2dd-daee-494f-94d2-a8615ac78c60"); } catch (e) { } } ; import { jsx, jsxs, Fragment } from "preact/jsx-runtime"; import { aj as useApiContext, an as useQuery, ao as httpGet, H as Typography, u as useI18nContext, ap as useFormContext, a6 as Alert, J as Field, aq as RadioGroup, ar as getFormProps, h as Icon, as as isEmpty, U as Svg, at as sofStyles, B as Button, au as TaskStatusIndicator, av as normalizedTaskStatusStore, aw as Card, ax as StructuredList, ay as IconButton, az as isEmpty$1, ab as useQueryClient, n as useAnalyticsContext, p as useLegalEntity, Z as useUpdateLegalEntity, ah as useMultiForm, aA as getRequiredForms, aB as addValidityToForms, aC as useFormComposer, g as createLogger, q as Loader, aD as FormContextProvider, aE as FormWrapper } from "./core-B_WrZP-J.js"; import { useState, useRef, useEffect, useMemo, useCallback } from "preact/hooks"; import { signal } from "@preact/signals"; const getTaxClassification = async (legalEntityId, url) => { return httpGet({ loadingContext: url, errorLevel: "warn", errorMessage: `Failed to fetch Business lines`, path: `legalEntities/${legalEntityId}/taxclassification`, authentication: "jwt", headers: { "Content-Type": "application/json" } }); }; const useTaxClassification = (options) => { const { legalEntityId, baseUrl } = useApiContext(); return useQuery({ queryKey: ["taxClassification", legalEntityId.value, baseUrl.value], queryFn: () => getTaxClassification(legalEntityId.value, baseUrl.value), ...options }); }; const taxClassificationErrorMessage = signal(void 0); const setTaxClassificationErrorMessage = (message) => { taxClassificationErrorMessage.value = message; }; const clearTaxClassificationErrorMessage = () => { taxClassificationErrorMessage.value = void 0; }; const taxReportingDropin = "adyen-kyc-tax-reporting-dropin"; const textCenter = "adyen-kyc-text-center"; const radioCaption = "adyen-kyc-radio-caption"; const taxReportingDropinGettingStarted = "adyen-kyc-tax-reporting-dropin-getting-started"; const taxReportingDropinFormContainer = "adyen-kyc-tax-reporting-dropin-form-container"; const subtitle = "adyen-kyc-subtitle"; const summary = "adyen-kyc-summary"; const summaryTaxStatusCard = "adyen-kyc-summary-tax-status-card"; const summaryTaxStatusCardHeader = "adyen-kyc-summary-tax-status-card--header"; const summaryTaxStatusCardBody = "adyen-kyc-summary-tax-status-card--body"; const styles = { taxReportingDropin, textCenter, radioCaption, taxReportingDropinGettingStarted, taxReportingDropinFormContainer, subtitle, summary, summaryTaxStatusCard, summaryTaxStatusCardHeader, summaryTaxStatusCardBody }; const taxReportingForms = { taxClassification: { formId: "taxClassification", formName: "chooseATaxReportingClassificationOption", fields: ["type"] } }; const taxReportingRequiredFields = { taxClassification: ["type"] }; const taxReportingOptions = { nonFinancialActive: "yourBusinessReceivesTheMajorityOfItsIncomeThroughActiveIncome", nonFinancialPassive: "yourBusinessGeneratesMoreThanHalfOfItsRevenueAsPassiveIncome", nonFinancialNonReportable: "yourBusinessIsAPublicListedEntity", financialNonReportable: "yourBusinessIsAFinancialInstitution" }; const getTaxStatusSummary = (i18n, taxReportingClassification) => { var _a; const taxStatusDescription = ((_a = taxReportingClassification == null ? void 0 : taxReportingClassification.taxClassification) == null ? void 0 : _a.type) ? taxReportingClassification.taxClassification.type : void 0; return taxStatusDescription ? [ { term: i18n.get("status"), details: i18n.get(taxStatusDescription) }, { term: i18n.get("description"), details: i18n.get(taxReportingOptions[taxStatusDescription]) } ] : []; }; const getTaxOptionsRadioItems = (i18n, taxRecommendationData, taxReportingClassification) => { const taxOptionsWithoutRecommendation = Object.fromEntries( Object.entries(taxReportingOptions).filter(([key]) => key !== (taxRecommendationData == null ? void 0 : taxRecommendationData.type)) ); const taxReportingOptionsToShow = (taxRecommendationData == null ? void 0 : taxRecommendationData.type) && !(taxReportingClassification == null ? void 0 : taxReportingClassification.type) ? taxOptionsWithoutRecommendation : taxReportingOptions; return Object.entries(taxReportingOptionsToShow).map(([key, value]) => ({ id: key, name: key, content: /* @__PURE__ */ jsx(Typography, { variant: "body", color: "secondary", className: styles.radioCaption, children: i18n.get(value) }) })); }; const getRecommendedTaxOptionsRadioItems = (i18n, showRecommendation, taxRecommendationData) => { const taxRecommendationType = (taxRecommendationData == null ? void 0 : taxRecommendationData.type) ? taxRecommendationData.type : void 0; return showRecommendation && taxRecommendationType ? [ { id: taxRecommendationType, name: taxRecommendationType, content: /* @__PURE__ */ jsx(Typography, { variant: "body", color: "secondary", className: styles.radioCaption, children: i18n.get(taxReportingOptions[taxRecommendationType]) }) } ] : []; }; function TaxReportingClassificationForm({ data, taxReportingClassification, taxRecommendationData, errors }) { var _a, _b; const { i18n } = useI18nContext(); const { form } = useFormContext(); const { handleChangeFor } = form; const showRecommendation = (taxRecommendationData == null ? void 0 : taxRecommendationData.type) && !(taxReportingClassification == null ? void 0 : taxReportingClassification.type); const taxOptionsRadioItems = getTaxOptionsRadioItems( i18n, taxRecommendationData, taxReportingClassification ); const recommendedTaxOptionRadioItems = getRecommendedTaxOptionsRadioItems( i18n, showRecommendation, taxRecommendationData ); const handleFieldChange = (fieldName, mode) => handleChangeFor(fieldName, "taxClassification", mode); return /* @__PURE__ */ jsxs("form", { className: "tax-reporting", children: [ /* @__PURE__ */ jsx(Typography, { variant: "title-l", el: "h2", className: styles.textCenter, children: i18n.get("taxStatusSelfCertification") }), /* @__PURE__ */ jsx(Typography, { variant: "body", el: "div", className: styles.subtitle, children: /* @__PURE__ */ jsx( "div", { dangerouslySetInnerHTML: { __html: i18n.get("chooseTheTaxStatusWhichBestRepresentsYourBusiness") } } ) }), ((_a = errors == null ? void 0 : errors.type) == null ? void 0 : _a.errorMessage) && /* @__PURE__ */ jsx(Alert, { variant: "error", title: i18n.get(errors.type.errorMessage) }), showRecommendation ? /* @__PURE__ */ jsxs(Fragment, { children: [ /* @__PURE__ */ jsx(Typography, { variant: "body-stronger", children: i18n.get("recommendedForYourBusiness") }), /* @__PURE__ */ jsx(Field, { name: "type", errorMessage: (_b = errors == null ? void 0 : errors.type) == null ? void 0 : _b.errorMessage, children: (childProps) => /* @__PURE__ */ jsx( RadioGroup, { ...childProps, name: "type", items: recommendedTaxOptionRadioItems, value: data == null ? void 0 : data.type, onChange: handleFieldChange("type", "input") } ) }), /* @__PURE__ */ jsx(Typography, { variant: "body-stronger", children: i18n.get("otherOptions") }) ] }) : null, /* @__PURE__ */ jsx(Field, { name: "type", children: (childProps) => /* @__PURE__ */ jsx( RadioGroup, { ...childProps, name: "type", items: taxOptionsRadioItems, value: data == null ? void 0 : data.type, onChange: handleFieldChange("type", "input") } ) }) ] }); } const taxClassificationFormID = taxReportingForms.taxClassification.formId; function TaxReporting(props) { const { form } = useFormContext(); const { errors, valid, fieldProblems: fieldValidationErrors } = form; const { activeForm: propActiveForm, taxReportingClassification, taxRecommendationData } = props; const classificationFormProps = getFormProps(props, taxClassificationFormID); const renderActiveForm = (activeForm) => /* @__PURE__ */ jsx(Fragment, { children: (activeForm == null ? void 0 : activeForm.formId) === taxClassificationFormID && /* @__PURE__ */ jsx("div", { className: styles.taxReportingDropinFormContainer, children: /* @__PURE__ */ jsx( TaxReportingClassificationForm, { ...classificationFormProps, taxReportingClassification, taxRecommendationData, errors: errors == null ? void 0 : errors.taxClassification, valid: valid == null ? void 0 : valid.taxClassification, fieldValidationErrors: fieldValidationErrors == null ? void 0 : fieldValidationErrors.taxClassification } ) }) }); return /* @__PURE__ */ jsxs("div", { className: "tax-reporting", children: [ taxClassificationErrorMessage.value && /* @__PURE__ */ jsxs( Typography, { variant: "caption", color: "critical", "aria-live": "polite", className: "adyen-kyc-u-justify-content-center adyen-kyc-u-display-flex", children: [ /* @__PURE__ */ jsx(Icon, { name: "field-error" }), " ", /* @__PURE__ */ jsx("div", { children: taxClassificationErrorMessage.value }) ] } ), renderActiveForm(propActiveForm) ] }); } const TaxReportingGettingStarted = ({ handleToggleFormVisible, handleCancelClick, taxReportingClassification }) => { var _a, _b, _c, _d; const { i18n } = useI18nContext(); const hasTaxReportingClassification = !isEmpty( (_a = taxReportingClassification == null ? void 0 : taxReportingClassification.taxClassification) == null ? void 0 : _a.type ); const taxStatusSummary = getTaxStatusSummary(i18n, taxReportingClassification); return /* @__PURE__ */ jsxs("div", { className: styles.taxReportingDropinGettingStarted, children: [ !hasTaxReportingClassification && /* @__PURE__ */ jsxs(Fragment, { children: [ /* @__PURE__ */ jsx( Svg, { type: "image", testId: "source-of-funds-getting-started-icon", name: "tax-reporting-graph", className: sofStyles.sourceOfFundsGettingStartedIcon } ), /* @__PURE__ */ jsx( Typography, { className: sofStyles.sourceOfFundsGettingStartedHeading, el: "h2", variant: "title-l", children: i18n.get("taxStatusSelfCertification") } ), /* @__PURE__ */ jsx( Typography, { className: sofStyles.sourceOfFundsGettingStartedHeading, el: "div", variant: "body", children: i18n.get("toUnderstandIfYourBankAccountDetailsAreReportable") } ), /* @__PURE__ */ jsxs("div", { className: sofStyles.sourceOfFundsGettingStartedActions, children: [ /* @__PURE__ */ jsx( Button, { fullWidth: true, testId: "source-of-funds-getting-primary-button", onClick: handleToggleFormVisible, children: i18n.get("gettingStarted") } ), handleCancelClick && /* @__PURE__ */ jsx( Button, { variant: "tertiary", fullWidth: true, testId: "source-of-funds-getting-cancel-button", onClick: handleCancelClick, children: i18n.get("backToTaskList") } ) ] }) ] }), hasTaxReportingClassification && /* @__PURE__ */ jsxs(Fragment, { children: [ /* @__PURE__ */ jsxs("div", { children: [ /* @__PURE__ */ jsx( TaskStatusIndicator, { taskStatus: (_d = (_c = (_b = normalizedTaskStatusStore) == null ? void 0 : _b.value) == null ? void 0 : _c.TAX_REPORTING) == null ? void 0 : _d.status } ), /* @__PURE__ */ jsx(Typography, { className: styles.textCenter, el: "h2", variant: "title-l", children: i18n.get("selfCertifiedTaxStatus") }), /* @__PURE__ */ jsx(Typography, { className: styles.subtitle, el: "div", variant: "body", children: i18n.get("noFurtherActionOrRecertificationIsNeeded") }), /* @__PURE__ */ jsx("div", { className: styles.summary, children: /* @__PURE__ */ jsx( Card, { className: styles.summaryTaxStatusCard, headerClassName: styles.summaryTaxStatusCardHeader, bodyClassName: styles.summaryTaxStatusCardBody, title: i18n.get("taxStatus"), headerButton: /* @__PURE__ */ jsx( IconButton, { ariaLabel: "edit", icon: "edit", onClick: handleToggleFormVisible, variant: "tertiary" } ), children: /* @__PURE__ */ jsx( StructuredList, { className: styles.summaryTaxStatusCardDescription, items: taxStatusSummary } ) } ) }) ] }), handleCancelClick && /* @__PURE__ */ jsx( Button, { variant: "secondary", testId: "source-of-funds-getting-return-button", onClick: handleCancelClick, children: i18n.get("backToTaskList") } ) ] }) ] }); }; const taxReportingTypeValidations = { type: { modes: ["blur"], validate: (type) => !isEmpty$1(type), errorMessage: "chooseATaxStatusOptionToContinue" } }; const logger = createLogger(); function TaxReportingDropin({ problems, handleHomeClick }) { var _a, _b, _c, _d, _e; const [loadingStatus, setLoadingStatus] = useState("success"); const [formVisible, setFormVisible] = useState(false); useRef(null); const queryClient = useQueryClient(); const { i18n } = useI18nContext(); const { data: taxRecommendationData, isLoading: isLoadingTaxRecommendationData } = useTaxClassification(); const userEvents = useAnalyticsContext(); const { data: legalEntityData, isLoading } = useLegalEntity(); const { mutateAsync: updateLegalEntityMutation } = useUpdateLegalEntity(); useEffect(() => { clearTaxClassificationErrorMessage(); }, []); useEffect(() => { userEvents.addTaskEvent("Landed on page", { actionType: "start" }); }, [userEvents]); const taxReportingClassification = useMemo( () => { var _a2, _b2; return { taxClassification: { type: (_b2 = (_a2 = legalEntityData == null ? void 0 : legalEntityData.organization) == null ? void 0 : _a2.taxReportingClassification) == null ? void 0 : _b2.type } }; }, [(_b = (_a = legalEntityData == null ? void 0 : legalEntityData.organization) == null ? void 0 : _a.taxReportingClassification) == null ? void 0 : _b.type] ); const defaultData = useMemo( () => ({ ...taxReportingClassification }), [taxReportingClassification] ); const form = useMultiForm({ requiredFields: taxReportingRequiredFields, rules: { taxClassification: taxReportingTypeValidations }, defaultData }); const { data = taxReportingClassification, setData, triggerValidation } = form; const canSubmitForm = useMemo( () => { var _a2; return !isEmpty$1((_a2 = data == null ? void 0 : data.taxClassification) == null ? void 0 : _a2.type); }, [(_c = data == null ? void 0 : data.taxClassification) == null ? void 0 : _c.type] ); useEffect(() => { var _a2, _b2, _c2; if (!((_a2 = data == null ? void 0 : data.taxClassification) == null ? void 0 : _a2.type) && (((_b2 = taxReportingClassification == null ? void 0 : taxReportingClassification.taxClassification) == null ? void 0 : _b2.type) || (taxRecommendationData == null ? void 0 : taxRecommendationData.type))) { setData( "type", ((_c2 = taxReportingClassification == null ? void 0 : taxReportingClassification.taxClassification) == null ? void 0 : _c2.type) ?? (taxRecommendationData == null ? void 0 : taxRecommendationData.type), "taxClassification" ); (async () => { await triggerValidation("taxClassification"); })().catch(() => console.error("Error triggering validation")); } }, [ (_d = data == null ? void 0 : data.taxClassification) == null ? void 0 : _d.type, taxRecommendationData == null ? void 0 : taxRecommendationData.type, (_e = taxReportingClassification == null ? void 0 : taxReportingClassification.taxClassification) == null ? void 0 : _e.type, setData, triggerValidation ]); const forms = useMemo(() => { const requiredForms = getRequiredForms( taxReportingForms, taxReportingRequiredFields, void 0 ); const requiredFormsWithoutSummary = requiredForms.filter((form2) => form2.formId !== "summary"); return addValidityToForms(requiredFormsWithoutSummary, form.isValid, problems); }, [form.isValid, problems]); const handleSubmit = useCallback(async () => { var _a2; if (!legalEntityData) { return; } setLoadingStatus("loading"); const taxReportingPayload = { businessType: taxRecommendationData == null ? void 0 : taxRecommendationData.businessType, financialInstitutionNumber: taxRecommendationData == null ? void 0 : taxRecommendationData.financialInstitutionNumber, mainSourceOfIncome: taxRecommendationData == null ? void 0 : taxRecommendationData.mainSourceOfIncome, type: (_a2 = data == null ? void 0 : data.taxClassification) == null ? void 0 : _a2.type }; const legalEntityPayload = { id: legalEntityData.id, ...(legalEntityData == null ? void 0 : legalEntityData.organization) && { organization: { ...legalEntityData.organization, taxReportingClassification: taxReportingPayload } } }; try { await updateLegalEntityMutation(legalEntityPayload); await queryClient.invalidateQueries({ queryKey: ["taxClassification"] }); await queryClient.invalidateQueries({ queryKey: ["taskStatus"] }); handleHomeClick == null ? void 0 : handleHomeClick(); setFormVisible(false); gotoFormByFormIndex(0); setTaxClassificationErrorMessage(""); setLoadingStatus("success"); } catch (e) { setTaxClassificationErrorMessage((e == null ? void 0 : e.message) || i18n.get("errorUpdatingTaxClassification")); logger.log("Error updating source of funds", e); setLoadingStatus("success"); } }, [data, taxRecommendationData, legalEntityData, updateLegalEntityMutation]); const handleToggleFormVisible = () => { setFormVisible(!formVisible); }; const { handleNextClick, activeForm, setShouldValidate, gotoFormByFormIndex, steps } = useFormComposer({ problems, forms, onSubmit: handleSubmit, triggerValidation: form.triggerValidation }); return /* @__PURE__ */ jsx("div", { className: styles.taxReportingDropin, children: isLoading || isLoadingTaxRecommendationData ? /* @__PURE__ */ jsx(Loader, { size: "medium" }) : /* @__PURE__ */ jsxs(Fragment, { children: [ !formVisible && /* @__PURE__ */ jsx( TaxReportingGettingStarted, { handleCancelClick: handleHomeClick, handleToggleFormVisible, taxReportingClassification, problems: legalEntityData == null ? void 0 : legalEntityData.problems } ), formVisible && /* @__PURE__ */ jsx(FormContextProvider, { form, children: /* @__PURE__ */ jsx( FormWrapper, { taskName: "taxReportingClassification", gotoFormByFormIndex, hideSidebar: true, loadingStatus, forms, activeForm, validateForm: () => setShouldValidate(true), onSubmit: handleSubmit, problems, canSubmit: canSubmitForm, handleNextClick, showBackButton: true, handleBackClick: handleToggleFormVisible, handleHomeClick, steps, children: /* @__PURE__ */ jsx( TaxReporting, { taxReportingClassification: taxReportingClassification == null ? void 0 : taxReportingClassification.taxClassification, taxRecommendationData, activeForm, data } ) } ) }) ] }) }); } export { TaxReportingDropin };