xendit-components-web 0.0.17 → 0.0.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -1
- package/README.md +2 -2
- package/package.json +16 -16
- package/sdk/dist/cjs/index.cjs +1 -1
- package/sdk/dist/cjs/index.cjs.map +1 -1
- package/sdk/dist/cjs/test-data.cjs +1 -1
- package/sdk/dist/cjs/test-data.cjs.map +1 -1
- package/sdk/dist/esm-bundled/index.mjs +2 -2
- package/sdk/dist/esm-bundled/index.mjs.map +1 -1
- package/sdk/dist/esm-bundled/test-data.mjs +1 -1
- package/sdk/dist/esm-bundled/test-data.mjs.map +1 -1
- package/sdk/dist/esm-external/index.mjs +1 -1
- package/sdk/dist/esm-external/index.mjs.map +1 -1
- package/sdk/dist/esm-external/test-data.mjs +1 -1
- package/sdk/dist/esm-external/test-data.mjs.map +1 -1
- package/sdk/dist/index.d.ts +44 -1
- package/sdk/dist/index.umd.js +2 -2
- package/sdk/dist/index.umd.js.map +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","sources":["../../src/components/icon.tsx","../../src/preact-batch.ts","../../src/public-event-types.ts","../../src/internal.ts","../../src/components/accordion.tsx","../../src/components/accordion-item.tsx","../../src/components/session-provider.tsx","../../src/utils.ts","../../src/components/button.tsx","../../src/components/dropdown.tsx","../../src/bff-marshal.ts","../../src/components/channel-picker-group.tsx","../../src/components/channel-picker-digital-wallet-section.tsx","../../src/components/channel-picker.tsx","../../src/components/field-country.tsx","../../src/components/field-dropdown.tsx","../../src/components/form-ascociated-focus-trap.ts","../../src/dom-utils.ts","../../src/private-event-types.ts","../../src/components/iframe-registry.tsx","../../src/components/field-iframe.tsx","../../src/components/field-phone-number.tsx","../../src/data/provinces.ts","../../src/components/field-province.tsx","../../src/components/field-text.tsx","../../src/data/currencies.ts","../../src/amount-format.ts","../../src/components/field-installment-plan.tsx","../../src/components/field.tsx","../../src/localization.ts","../../src/validation.ts","../../src/components/form-simulation-helper.tsx","../../src/components/field-group.tsx","../../src/data/simulation-scenarios.ts","../../src/components/channel-form.tsx","../../src/components/instructions-icon.tsx","../../src/components/qr-scan-icon.tsx","../../src/components/checkbox.tsx","../../src/components/payment-channel.tsx","../../src/networking.ts","../../src/api.ts","../../src/lifecycle/behavior-tree-runner.ts","../../src/components/action-iframe.tsx","../../src/components/action-qr.tsx","../../src/components/dialog.tsx","../../src/components/default-action-container.tsx","../../src/components/instructions.tsx","../../src/components/tooltip.tsx","../../src/components/action-va.tsx","../../src/backend-types/payment-entity.ts","../../src/data/test-data-modifiers.ts","../../src/components/redirect-instructions.tsx","../../src/components/action-empty-list-push-notification.tsx","../../src/components/action-deep-link.tsx","../../src/lifecycle/behaviors/action.ts","../../src/lifecycle/behaviors/action-paylink.ts","../../src/lifecycle/behaviors/card-info.ts","../../src/lifecycle/behaviors/channel.ts","../../src/lifecycle/behaviors/poll-worker.ts","../../src/lifecycle/behaviors/payment-entity.ts","../../src/lifecycle/behaviors/payment-options.ts","../../src/lifecycle/behaviors/sdk.ts","../../src/lifecycle/behaviors/discard.ts","../../src/lifecycle/behaviors/session.ts","../../src/lifecycle/behaviors/simulate-payment.ts","../../src/lifecycle/behaviors/submission.ts","../../src/lifecycle/behavior-tree.ts","../../src/components/digital-wallet-googlepay.tsx","../../src/components/digital-wallet-wait-for-load.tsx","../../src/components/digital-wallet-container.tsx","../../src/public-sdk.ts","../../src/index.ts","../../src/styles.ts","../../src/styles.css"],"sourcesContent":["import {\n ComponentChildren,\n FunctionComponent,\n render,\n SVGAttributes,\n} from \"preact\";\n\ntype Direction = \"up\" | \"down\" | \"left\" | \"right\";\n\ntype Props = {\n name: IconName;\n size: number;\n direction?: Direction;\n className?: string;\n};\n\nconst Icon: FunctionComponent<SVGAttributes<SVGSVGElement> & Props> = (\n props,\n) => {\n const { name, size, direction } = props;\n\n let svgTransform = undefined;\n switch (direction) {\n case \"left\":\n svgTransform = \"rotate(0 12 12)\";\n break;\n case \"right\":\n svgTransform = \"rotate(180 12 12)\";\n break;\n case \"up\":\n svgTransform = \"rotate(90 12 12)\";\n break;\n case \"down\":\n svgTransform = \"rotate(-90 12 12)\";\n break;\n }\n\n return (\n <svg\n className={`xendit-icon ${props.className ?? \"\"}`}\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"none\"\n >\n {/* TODO: figure out why this doens't work. Maybe because of the self signed cert? */}\n {/* <use href={`#xendit-icon-${name}`} transform={svgTransform} /> */}\n <g transform={svgTransform}>\n {iconData.find((icon) => icon.name === name)?.node ?? null}\n </g>\n </svg>\n );\n};\n\nfunction makeIcon<T extends string>(\n id: T,\n children: ComponentChildren,\n scale: number,\n): { name: T; node: ComponentChildren } {\n return {\n name: id,\n node: (\n <g\n id={`xendit-icon-${id}`}\n transform={`scale(${1 / scale} ${1 / scale})`}\n >\n {children}\n </g>\n ),\n };\n}\n\nconst iconData = [\n makeIcon(\n \"chevron\",\n <path\n d=\"M15 19.5L7.5 12L15 4.5\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />,\n 24 / 24,\n ),\n makeIcon(\n \"check\",\n <path\n d=\"M13.5 4.5L6.5 11.5L3 8\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />,\n 16 / 24,\n ),\n makeIcon(\n \"x\",\n <>\n <path\n d=\"M18.75 5.25L5.25 18.75\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n <path\n d=\"M18.75 18.75L5.25 5.25\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </>,\n 24 / 24,\n ),\n makeIcon(\n \"card\",\n <path\n fill=\"currentColor\"\n d=\"M17.5 3.75H2.5C2.16848 3.75 1.85054 3.8817 1.61612 4.11612C1.3817 4.35054 1.25 4.66848 1.25 5V15C1.25 15.3315 1.3817 15.6495 1.61612 15.8839C1.85054 16.1183 2.16848 16.25 2.5 16.25H17.5C17.8315 16.25 18.1495 16.1183 18.3839 15.8839C18.6183 15.6495 18.75 15.3315 18.75 15V5C18.75 4.66848 18.6183 4.35054 18.3839 4.11612C18.1495 3.8817 17.8315 3.75 17.5 3.75ZM10.625 13.75H9.375C9.20924 13.75 9.05027 13.6842 8.93306 13.5669C8.81585 13.4497 8.75 13.2908 8.75 13.125C8.75 12.9592 8.81585 12.8003 8.93306 12.6831C9.05027 12.5658 9.20924 12.5 9.375 12.5H10.625C10.7908 12.5 10.9497 12.5658 11.0669 12.6831C11.1842 12.8003 11.25 12.9592 11.25 13.125C11.25 13.2908 11.1842 13.4497 11.0669 13.5669C10.9497 13.6842 10.7908 13.75 10.625 13.75ZM15.625 13.75H13.125C12.9592 13.75 12.8003 13.6842 12.6831 13.5669C12.5658 13.4497 12.5 13.2908 12.5 13.125C12.5 12.9592 12.5658 12.8003 12.6831 12.6831C12.8003 12.5658 12.9592 12.5 13.125 12.5H15.625C15.7908 12.5 15.9497 12.5658 16.0669 12.6831C16.1842 12.8003 16.25 12.9592 16.25 13.125C16.25 13.2908 16.1842 13.4497 16.0669 13.5669C15.9497 13.6842 15.7908 13.75 15.625 13.75ZM2.5 6.875V5H17.5V6.875H2.5Z\"\n />,\n 20 / 24,\n ),\n makeIcon(\n \"copy\",\n <>\n <path\n d=\"M6 9.5H10\"\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M6 7.5H10\"\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M10 2.5H12.5C12.6326 2.5 12.7598 2.55268 12.8536 2.64645C12.9473 2.74021 13 2.86739 13 3V13.5C13 13.6326 12.9473 13.7598 12.8536 13.8536C12.7598 13.9473 12.6326 14 12.5 14H3.5C3.36739 14 3.24021 13.9473 3.14645 13.8536C3.05268 13.7598 3 13.6326 3 13.5V3C3 2.86739 3.05268 2.74021 3.14645 2.64645C3.24021 2.55268 3.36739 2.5 3.5 2.5H6\"\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M5.5 4.5V4C5.5 3.33696 5.76339 2.70107 6.23223 2.23223C6.70107 1.76339 7.33696 1.5 8 1.5C8.66304 1.5 9.29893 1.76339 9.76777 2.23223C10.2366 2.70107 10.5 3.33696 10.5 4V4.5H5.5Z\"\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </>,\n 16 / 24,\n ),\n makeIcon(\n \"dummy\",\n <path\n fill=\"currentColor\"\n d=\"M17.5 11.875V15C17.5 15.3315 17.3683 15.6495 17.1339 15.8839C16.8995 16.1183 16.5815 16.25 16.25 16.25H3.75C3.41848 16.25 3.10054 16.1183 2.86612 15.8839C2.6317 15.6495 2.5 15.3315 2.5 15V11.875C2.5 11.5435 2.6317 11.2255 2.86612 10.9911C3.10054 10.7567 3.41848 10.625 3.75 10.625H16.25C16.5815 10.625 16.8995 10.7567 17.1339 10.9911C17.3683 11.2255 17.5 11.5435 17.5 11.875ZM16.25 3.75H3.75C3.41848 3.75 3.10054 3.8817 2.86612 4.11612C2.6317 4.35054 2.5 4.66848 2.5 5V8.125C2.5 8.45652 2.6317 8.77446 2.86612 9.00888C3.10054 9.2433 3.41848 9.375 3.75 9.375H16.25C16.5815 9.375 16.8995 9.2433 17.1339 9.00888C17.3683 8.77446 17.5 8.45652 17.5 8.125V5C17.5 4.66848 17.3683 4.35054 17.1339 4.11612C16.8995 3.8817 16.5815 3.75 16.25 3.75Z\"\n />,\n 20 / 24,\n ),\n];\n\ntype IconName = (typeof iconData)[number][\"name\"];\n\nexport function createIconSet() {\n const iconSet = document.createElement(\"svg\");\n iconSet.id = \"xendit-icon-set\";\n iconSet.style.display = \"none\";\n render(<defs>{iconData.map((icon) => icon.node)}</defs>, iconSet);\n document.head.appendChild(iconSet);\n}\n\nexport default Icon;\n","import { options } from \"preact\";\n\nlet once = false;\n\nexport function setupPreactBatch() {\n if (once) {\n return;\n }\n once = true;\n options.debounceRendering = (fn) => queueMicrotask(fn);\n}\n","/**\n * @public\n */\nexport type XenditEventMap = {\n init: XenditInitEvent;\n\n \"submission-ready\": XenditReadyEvent;\n \"submission-not-ready\": XenditReadyEvent;\n\n \"submission-begin\": XenditSubmissionBeginEvent;\n \"submission-end\": XenditSubmissionEndEvent;\n\n \"action-begin\": XenditActionBeginEvent;\n \"action-end\": XenditActionEndEvent;\n\n \"will-redirect\": XenditWillRedirectEvent;\n\n \"session-complete\": XenditSessionCompleteEvent;\n \"session-expired-or-canceled\": XenditSessionExpiredOrCanceledEvent;\n \"session-pending\": XenditSessionPendingEvent;\n \"session-not-pending\": XenditSessionNotPendingEvent;\n\n \"payment-request-created\": XenditPaymentRequestCreatedEvent;\n \"payment-request-discarded\": XenditPaymentRequestDiscardedEvent;\n \"payment-token-created\": XenditPaymentTokenCreatedEvent;\n \"payment-token-discarded\": XenditPaymentTokenDiscardedEvent;\n\n \"fatal-error\": XenditFatalErrorEvent;\n};\n\n/**\n * @public\n */\nexport type XenditEventListener<\n T extends Event | XenditEventMap[keyof XenditEventMap],\n> = ((event: T) => void) | null;\n\n/**\n * @public\n * Event fired when the Session is loaded.\n */\nexport class XenditInitEvent extends Event {\n static type = \"init\" as const;\n\n constructor() {\n super(XenditInitEvent.type, {});\n }\n}\n\n/**\n * @public\n * Event fired when the SDK fails in an unrecoverable way.\n */\nexport class XenditFatalErrorEvent extends Event {\n static type = \"fatal-error\" as const;\n\n constructor(\n /**\n * A detailed error message for developers. Don't show this to users.\n */\n public message: string,\n ) {\n super(XenditFatalErrorEvent.type, {});\n }\n}\n\n/**\n * @public\n * Event fired when the SDK is ready to submit.\n */\nexport class XenditReadyEvent extends Event {\n static type = \"submission-ready\" as const;\n\n constructor(public channelCode: string) {\n super(XenditReadyEvent.type, {});\n }\n}\n\n/**\n * @public\n * Event fired when the SDK is not ready to submit.\n */\nexport class XenditNotReadyEvent extends Event {\n static type = \"submission-not-ready\" as const;\n\n constructor() {\n super(XenditNotReadyEvent.type, {});\n }\n}\n\n/**\n * @public\n * Event fired after submission begins.\n */\nexport class XenditSubmissionBeginEvent extends Event {\n static type = \"submission-begin\" as const;\n\n constructor() {\n super(XenditSubmissionBeginEvent.type, {});\n }\n}\n\n/**\n * @public\n * Event fired when a submission is complete or fails. Submission encompasses creation of a\n * payment request or payment token, and any actions the user needs to complete.\n *\n * Includes details about why the submission ended, and error messages if applicable.\n */\nexport class XenditSubmissionEndEvent extends Event {\n static type = \"submission-end\" as const;\n\n constructor(\n /**\n * The reason why the submission ended.\n */\n public reason: string,\n /**\n * An error message to show to the user. A title and 1-2 lines of localized text.\n */\n public userErrorMessage?: string[],\n /**\n * A detailed error message for developers.\n */\n public developerErrorMessage?: {\n /**\n * The type of error.\n * - NETWORK_ERROR: A network error occurred while creating the payment request or payment token.\n * - ERROR: Failed to created a payment request or payment token.\n * - FAILURE: A payment request or payment token transitioned to a failure state.\n */\n type: \"NETWORK_ERROR\" | \"ERROR\" | \"FAILURE\";\n /**\n * The code associated with the error.\n */\n code: string;\n },\n ) {\n super(XenditSubmissionEndEvent.type, {});\n }\n}\n\n/**\n * @public\n * Event sometimes fired after submission, if an action is required.\n */\nexport class XenditActionBeginEvent extends Event {\n static type = \"action-begin\" as const;\n\n constructor() {\n super(XenditActionBeginEvent.type, {});\n }\n}\n\n/**\n * @public\n * Event fired when an action ends, success or fail.\n */\nexport class XenditActionEndEvent extends Event {\n static type = \"action-end\" as const;\n\n constructor() {\n super(XenditActionEndEvent.type, {});\n }\n}\n\n/**\n * @public\n * Event fired when the a redirect action is about to happen.\n */\nexport class XenditWillRedirectEvent extends Event {\n static type = \"will-redirect\" as const;\n\n constructor() {\n super(XenditWillRedirectEvent.type, {});\n }\n}\n\n/**\n * @public\n * Event fired when the session is complete, meaning the payment has been processed\n * or the token has been created.\n */\nexport class XenditSessionCompleteEvent extends Event {\n static type = \"session-complete\" as const;\n\n constructor() {\n super(XenditSessionCompleteEvent.type, {});\n }\n}\n\n/**\n * @public\n * Event fired when the session has failed, meaning expired or cancelled.\n */\nexport class XenditSessionExpiredOrCanceledEvent extends Event {\n static type = \"session-expired-or-canceled\" as const;\n\n constructor() {\n super(XenditSessionExpiredOrCanceledEvent.type, {});\n }\n}\n\n/**\n * @public\n * Event fired when the session is pending.\n */\nexport class XenditSessionPendingEvent extends Event {\n static type = \"session-pending\" as const;\n\n constructor() {\n super(XenditSessionPendingEvent.type, {});\n }\n}\n\n/**\n * @public\n * Event fired when the session is no longer pending.\n */\nexport class XenditSessionNotPendingEvent extends Event {\n static type = \"session-not-pending\" as const;\n\n constructor() {\n super(XenditSessionNotPendingEvent.type, {});\n }\n}\n\n/**\n * @public\n */\nexport class XenditPaymentRequestCreatedEvent extends Event {\n static type = \"payment-request-created\" as const;\n\n constructor(public paymentRequestId: string) {\n super(XenditPaymentRequestCreatedEvent.type, {});\n }\n}\n\n/**\n * @public\n */\nexport class XenditPaymentTokenCreatedEvent extends Event {\n static type = \"payment-token-created\" as const;\n\n constructor(public paymentTokenId: string) {\n super(XenditPaymentTokenCreatedEvent.type, {});\n }\n}\n\n/**\n * @public\n */\nexport class XenditPaymentRequestDiscardedEvent extends Event {\n static type = \"payment-request-discarded\" as const;\n\n constructor(public paymentRequestId: string) {\n super(XenditPaymentRequestDiscardedEvent.type, {});\n }\n}\n\n/**\n * @public\n */\nexport class XenditPaymentTokenDiscardedEvent extends Event {\n static type = \"payment-token-discarded\" as const;\n\n constructor(public paymentTokenId: string) {\n super(XenditPaymentTokenDiscardedEvent.type, {});\n }\n}\n","export const internal = Symbol(\"xendit-internal\");\n","import { ComponentChildren, FunctionComponent } from \"preact\";\n\ninterface Props {\n children: ComponentChildren;\n}\n\n/**\n * @example\n * <Accordion>\n * <AccordionItem>Content</AccordionItem>\n * <AccordionItem>Content</AccordionItem>\n * </Accordion>\n */\nexport const Accordion: FunctionComponent<Props> = (props) => {\n return <div class=\"xendit-accordion\">{props.children}</div>;\n};\n","import { useCallback } from \"preact/hooks\";\nimport Icon from \"./icon\";\nimport classNames from \"classnames\";\nimport {\n ComponentChildren,\n FunctionComponent,\n TargetedKeyboardEvent,\n} from \"preact\";\n\ninterface Props {\n id: string;\n title: string;\n subtitle?: string;\n disabled?: boolean;\n open: boolean;\n onClick: (id: string) => void;\n children: ComponentChildren;\n}\n\nexport const AccordionItem: FunctionComponent<Props> = (props) => {\n const { id, title, subtitle, disabled, open, onClick, children } = props;\n\n const chevronDirection = open ? \"up\" : \"down\";\n\n const toggleOpen = useCallback(() => {\n if (disabled) {\n return;\n }\n onClick(id);\n }, [disabled, onClick, id]);\n\n const handleKeyPress = useCallback(\n (event: TargetedKeyboardEvent<HTMLDivElement>) => {\n if (event.key === \"Enter\" || event.key === \" \") {\n toggleOpen();\n event.preventDefault();\n }\n },\n [toggleOpen],\n );\n\n const handleClick = useCallback(() => {\n toggleOpen();\n }, [toggleOpen]);\n\n return (\n <div\n className={classNames(\n \"xendit-accordion-item\",\n disabled ? \"xendit-accordion-item-disabled\" : \"\",\n open ? \"xendit-accordion-item-open\" : \"xendit-accordion-item-closed\",\n )}\n >\n <div\n className=\"xendit-accordion-item-header\"\n onClick={handleClick}\n onKeyDown={handleKeyPress}\n role=\"button\"\n tabIndex={disabled ? -1 : 0}\n >\n <Icon\n className=\"xendit-accordion-item-header-icon\"\n name=\"dummy\"\n size={24}\n />\n <div className=\"xendit-accordion-item-header-title xendit-text-16 xendit-text-bold\">\n {title}\n {subtitle ? (\n <div className=\"xendit-accordion-item-header-subtitle xendit-text-14\">\n {subtitle}\n </div>\n ) : null}\n </div>\n <Icon\n className=\"xendit-accordion-item-chevron\"\n name=\"chevron\"\n size={24}\n direction={chevronDirection}\n />\n </div>\n <div className=\"xendit-accordion-item-content\" inert={!open}>\n <div className=\"xendit-accordion-item-padding\">{children}</div>\n </div>\n </div>\n );\n};\n","import { WorldState, XenditComponents } from \"../public-sdk\";\nimport { BffSession } from \"../backend-types/session\";\nimport { BffBusiness } from \"../backend-types/business\";\nimport { BffCustomer } from \"../backend-types/customer\";\nimport { BffChannel, BffChannelUiGroup } from \"../backend-types/channel\";\nimport { internal } from \"../internal\";\nimport { ComponentChildren, createContext, FunctionComponent } from \"preact\";\nimport { useContext } from \"preact/hooks\";\nimport { BffDigitalWallets } from \"../backend-types/digital-wallets\";\n\n// Create contexts\nexport const SessionContext = createContext<BffSession | null>(null);\nSessionContext.displayName = \"SessionContext\";\n\nexport const BusinessContext = createContext<BffBusiness | null>(null);\nBusinessContext.displayName = \"BusinessContext\";\n\nexport const CustomerContext = createContext<BffCustomer | null>(null);\nCustomerContext.displayName = \"CustomerContext\";\n\nexport const ChannelsContext = createContext<BffChannel[] | null>(null);\nChannelsContext.displayName = \"ChannelsContext\";\n\nexport const ChannelUiGroupsContext = createContext<BffChannelUiGroup[] | null>(\n null,\n);\nChannelUiGroupsContext.displayName = \"ChannelUiGroupsContext\";\n\nexport const DigitalWalletsContext = createContext<BffDigitalWallets | null>(\n null,\n);\nDigitalWalletsContext.displayName = \"DigitalWalletsContext\";\n\nexport const SdkContext = createContext<XenditComponents | null>(null);\nSdkContext.displayName = \"SdkContext\";\n\nexport const CurrentChannelContext = createContext<BffChannel | null>(null);\nCurrentChannelContext.displayName = \"CurrentChannelContext\";\n\n// Custom hooks for consuming contexts\nexport const useSession = () => {\n const context = useContext(SessionContext);\n if (context === null) {\n throw new Error(\"useSession must be used within a XenditSessionProvider\");\n }\n return context;\n};\n\nexport const useBusiness = () => {\n const context = useContext(BusinessContext);\n if (context === null) {\n throw new Error(\"useBusiness must be used within a XenditSessionProvider\");\n }\n return context;\n};\n\nexport const useCustomer = () => {\n const context = useContext(CustomerContext);\n if (context === null) {\n throw new Error(\"useCustomer must be used within a XenditSessionProvider\");\n }\n return context;\n};\n\nexport const useChannels = () => {\n const context = useContext(ChannelsContext);\n if (context === null) {\n throw new Error(\"useChannels must be used within a XenditSessionProvider\");\n }\n return context;\n};\n\nexport const useChannelUiGroups = () => {\n const context = useContext(ChannelUiGroupsContext);\n if (context === null) {\n throw new Error(\n \"useChannelUiGroups must be used within a XenditSessionProvider\",\n );\n }\n return context;\n};\n\nexport const useDigitalWallets = () => {\n const context = useContext(DigitalWalletsContext);\n return context;\n};\n\nexport const useSdk = () => {\n const context = useContext(SdkContext);\n if (context === null) {\n throw new Error(\"useSdk must be used within a XenditSessionProvider\");\n }\n return context;\n};\n\nexport const useCurrentChannel = () => {\n return useContext(CurrentChannelContext);\n};\n\ninterface XenditSessionProviderProps {\n children: ComponentChildren;\n data: WorldState;\n sdk: XenditComponents;\n}\n\nexport const XenditSessionProvider: FunctionComponent<\n XenditSessionProviderProps\n> = ({ children, data, sdk }) => {\n const {\n session,\n business,\n customer,\n channels,\n digitalWallets,\n channelUiGroups,\n } = data;\n\n const channel = sdk.getCurrentChannel()?.[internal]?.[0] ?? null;\n\n if (sdk.getSdkStatus() !== \"ACTIVE\" || session.status !== \"ACTIVE\") {\n // clear all contents if the sdk is not initialized or crashes, or if the component is still mounted after completion or failure\n return null;\n }\n\n return (\n <SdkContext.Provider value={sdk}>\n <CurrentChannelContext.Provider value={channel}>\n <SessionContext.Provider value={session}>\n <BusinessContext.Provider value={business}>\n <CustomerContext.Provider value={customer}>\n <ChannelsContext.Provider value={channels}>\n <DigitalWalletsContext.Provider value={digitalWallets}>\n <ChannelUiGroupsContext.Provider value={channelUiGroups}>\n {children}\n </ChannelUiGroupsContext.Provider>\n </DigitalWalletsContext.Provider>\n </ChannelsContext.Provider>\n </CustomerContext.Provider>\n </BusinessContext.Provider>\n </SessionContext.Provider>\n </CurrentChannelContext.Provider>\n </SdkContext.Provider>\n );\n};\n","import {\n BffChannel,\n ChannelFormField,\n ChannelProperties,\n} from \"./backend-types/channel\";\nimport { useLayoutEffect, useRef } from \"preact/hooks\";\nimport { BffAction } from \"./backend-types/payment-entity\";\nimport { BffSession } from \"./backend-types/session\";\nimport { internal } from \"./internal\";\nimport { XenditComponents } from \"./public-sdk\";\n\nexport const MOCK_NETWORK_DELAY_MS = 300;\n\nexport function assert<T>(arg: unknown): asserts arg is NonNullable<T> {\n if (arg === null || arg === undefined) {\n throw new Error(\n \"Assertion failed: argument is null or undefined; this is a bug, please contact support.\",\n );\n }\n}\n\nexport function assertIsArray<T = unknown>(arg: unknown): asserts arg is T[] {\n if (!Array.isArray(arg)) {\n throw new Error(\n \"Assertion failed: expected array; this is a bug, please contact support.\",\n );\n }\n}\n\nexport function assertIsNotArray<T = unknown>(\n arg: T,\n): asserts arg is Exclude<T, unknown[]> {\n if (Array.isArray(arg)) {\n throw new Error(\n \"Assertion failed: expected array; this is a bug, please contact support.\",\n );\n }\n}\n\nexport function assertEquals<T>(a: unknown, b: T): asserts a is T {\n if (a !== b) {\n throw new Error(`Assertion failed; this is a bug, please contact support.`);\n }\n}\n\nexport function assertNotEquals<const A, const B extends A>(\n a: A,\n b: B,\n): asserts a is Exclude<A, B> {\n if (a === b) {\n throw new Error(`Assertion failed; this is a bug, please contact support.`);\n }\n}\n\nexport const SLEEP_MULTIPLIER = process.env.NODE_ENV === \"test\" ? 0.01 : 1;\n\nexport function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms * SLEEP_MULTIPLIER));\n}\n\nexport class AbortError extends Error {\n constructor() {\n super(\"AbortError\");\n this.name = \"AbortError\";\n }\n}\n\nexport function isAbortError(error: unknown): error is AbortError {\n return error instanceof AbortError && error.name === \"AbortError\";\n}\n\n/**\n * A sleep function that can be cancelled via an AbortSignal.\n */\nexport function cancellableSleep(\n ms: number,\n signal: AbortSignal,\n): Promise<void> {\n return new Promise((resolve, reject) => {\n function onAbort() {\n signal.removeEventListener(\"abort\", onAbort);\n clearTimeout(timeoutId);\n reject(new AbortError());\n }\n\n const timeoutId = setTimeout(() => {\n signal.removeEventListener(\"abort\", onAbort);\n resolve();\n }, ms * SLEEP_MULTIPLIER);\n\n // already aborted\n if (signal.aborted) {\n onAbort();\n return;\n }\n\n // abort on signal\n signal.addEventListener(\"abort\", onAbort);\n });\n}\n\nexport function camelCaseToKebabCase(str: string): string {\n return str.replace(/[A-Z]/gm, (match, offset) => {\n if (offset === 0) return match.toLowerCase();\n return `-${match.toLowerCase()}`;\n });\n}\n\n/**\n * Creates an async iterator with exponential delay. Yields the attempt number.\n *\n * Use with async for (const attempt of retryLoop(100, 5)).\n *\n * Delay is mult * base ** attempt\n * e.g. mult = 100ms, tries = 5, base = 2:\n * 100ms, 200ms, 400ms, 800ms, 1600ms\n *\n * Doesn't wait in tests, unless waitInTests=true.\n */\nexport async function* retryLoop(mult: number, tries: number, base = 2) {\n // first attempt always instant\n yield 0;\n\n let sleepTime = mult;\n\n for (let i = 1; i < tries; i++) {\n sleepTime *= base;\n await sleep(sleepTime);\n yield i;\n }\n}\n\nexport function redirectCanBeHandledInIframe(action: BffAction): boolean {\n if (action.type !== \"REDIRECT_CUSTOMER\") {\n return false;\n }\n if (action.iframe_capable === false) {\n return false;\n }\n // if iframe_capable is undefined, assume it can be handled in iframe\n return true;\n}\n\n/**\n * Return the first action in the list that we understand.\n */\nexport function findBestAction(actions: BffAction[]): BffAction | undefined {\n const best = actions.find((a) => {\n switch (a.type) {\n case \"REDIRECT_CUSTOMER\": {\n switch (a.descriptor) {\n case \"WEB_URL\":\n return true;\n case \"DEEPLINK_URL\":\n return isAndroidOrIos();\n case \"WEB_GOOGLE_PAYLINK\":\n return false;\n }\n a satisfies never;\n break;\n }\n case \"PRESENT_TO_CUSTOMER\":\n return true;\n case \"API_POST_REQUEST\":\n return false;\n }\n a satisfies never;\n return false;\n });\n if (best) return best;\n\n // if we don't understand any action, just return the first one, it will fire the fatal-error event later\n // (an empty action list has a special meaning, we should return an unsupported action rather than undefined if we support none of the actions)\n return actions[0];\n}\n\n/**\n * Find the paylink action, if it exists and the feature is enabled.\n */\nexport function findPaylinkAction(\n sdk: XenditComponents,\n actions: BffAction[],\n): BffAction | undefined {\n if (sdk[internal].options.enablePaylinks) {\n return actions.find(\n (a) =>\n a.type === \"REDIRECT_CUSTOMER\" && a.descriptor === \"WEB_GOOGLE_PAYLINK\",\n );\n }\n}\n\nfunction isAndroidOrIos() {\n const userAgent = navigator.userAgent;\n\n if (!userAgent) return false;\n\n if (/android/i.test(userAgent)) {\n return true;\n }\n\n // iOS detection from: http://stackoverflow.com/a/9039885/177710\n if (/iPad|iPhone|iPod/.test(userAgent)) {\n return true;\n }\n\n return false;\n}\n\nexport const MOCK_HOST_ID = \"mock\";\n\nconst hosts: Record<string, string | undefined> = {\n pl: process.env.XENDIT_CHECKOUT_UI_GATEWAY_PROD_LIVE,\n pd: process.env.XENDIT_CHECKOUT_UI_GATEWAY_PROD_DEV,\n sl: process.env.XENDIT_CHECKOUT_UI_GATEWAY_STAGING_LIVE,\n sd: process.env.XENDIT_CHECKOUT_UI_GATEWAY_STAGING_DEV,\n};\n\nexport function hostFromHostId(hostId: string): string | null {\n return hosts[hostId] ?? null;\n}\n\nexport type ParsedSdkKey = {\n sessionAuthKey: string;\n hostId: string;\n publicKey: string;\n signature: string;\n};\n\nexport function parseSdkKey(componentsSdkKey: string): ParsedSdkKey {\n if (!componentsSdkKey) {\n throw new Error(\n \"The componentsSdkKey option is missing; check the constructor parameters.\",\n );\n }\n const parts = componentsSdkKey.split(\"-\");\n if (\n parts.length < 4 ||\n (parts[2] !== MOCK_HOST_ID && hostFromHostId(parts[2]) === null)\n ) {\n throw new Error(\n \"The componentsSdkKey option has the wrong format. Ensure you pass the value returned from the `components_sdk_key` property of the `POST /sessions` response.\",\n );\n }\n\n return {\n sessionAuthKey: [parts[0], parts[1]].join(\"-\"),\n hostId: parts[2],\n publicKey: parts[3],\n signature: parts[4],\n };\n}\n\n/**\n * Return a copy of original, with properties from updates applied on top, except undefined properties.\n */\nexport function mergeIgnoringUndefined<T>(\n original: T,\n updates: Partial<{ [K in keyof T]: T[K] | undefined }>,\n): T {\n const result = { ...original };\n for (const key of Object.keys(updates) as (keyof T)[]) {\n const value = updates[key];\n if (value !== undefined) {\n result[key] = value;\n }\n }\n return result;\n}\n\nexport function usePrevious<T>(value: T) {\n const ref = useRef<T>(); // Create a ref to store the previous value\n\n useLayoutEffect(() => {\n ref.current = value; // Update the ref's current value after each render\n });\n\n // eslint-disable-next-line react-hooks/refs\n return ref.current; // Return the value stored in the ref (which is the previous value)\n}\n\n/**\n * Get the form field name for a given channel form field.\n * @param field The channel form field to get the name for.\n * @returns The form field name.\n */\nexport function formFieldName(field: ChannelFormField): string {\n let id: string;\n if (typeof field.channel_property === \"string\") {\n id = field.channel_property;\n } else {\n const keys = Object.values(field.channel_property);\n id = keys.join(\"__\");\n }\n return id;\n}\n\nconst seed =\n process.env.NODE_ENV !== \"test\" ? Math.floor(Math.random() * 255) : 0;\n\n/**\n * Get an ID for a channel field, for the \"id\" and label \"for\" attributes.\n */\nexport function formFieldId(field: ChannelFormField): string {\n const obfuscatedId = formFieldName(field)\n .split(\"\")\n .map((c) => {\n const code = (c.charCodeAt(0) % 256) ^ seed;\n return code.toString(16);\n })\n .join(\"\");\n return `xendit-id-${obfuscatedId}`;\n}\n\nexport function randomBytes(length: number) {\n const arr = new Uint8Array(length);\n for (let i = 0; i < length; i++) {\n arr[i] = Math.floor(Math.random() * 256);\n }\n return arr;\n}\n\nexport function randomHexString(length: number) {\n assert(length % 2 === 0);\n const bytes = randomBytes(length / 2);\n return Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\");\n}\n\nexport function randomUUID() {\n return [\n randomHexString(8),\n randomHexString(4),\n randomHexString(4),\n randomHexString(4),\n randomHexString(12),\n ].join(\"-\");\n}\n\n/**\n * useId but doesn't sometimes return the same id in different components\n */\nexport function useIdSafe(): string {\n const id = useRef(randomHexString(12));\n return `xendit-id-${id.current}`;\n}\n\nexport function canBeSimulated(action: BffAction): boolean {\n switch (action.type) {\n case \"PRESENT_TO_CUSTOMER\":\n return true;\n default:\n return false;\n }\n}\n\nexport function errorToString(error: unknown): string {\n if (error instanceof Error) {\n return error.stack ?? error.message;\n }\n if (typeof error === \"string\") {\n return error;\n }\n try {\n return `Unknown error: ${JSON.stringify(error)}`;\n } catch {\n return \"Unknown error\";\n }\n}\n\n/**\n * Modifies the input object, deleting properties with undefined values, excluding symbol properties or getters.\n */\nexport function removeUndefinedPropertiesFromObject<T extends object>(\n object: T,\n): T {\n for (const key of Object.keys(object) as (keyof T)[]) {\n if (typeof key === \"symbol\") {\n continue;\n }\n const descriptor = Object.getOwnPropertyDescriptor(object, key);\n if (descriptor === undefined) {\n continue;\n }\n if (typeof descriptor.get === \"function\") {\n continue;\n }\n if (descriptor.value === undefined) {\n delete object[key];\n }\n }\n return object;\n}\n\nexport function getValueFromChannelProperty(\n channelProperty: string | string[],\n channelProperties: ChannelProperties | null,\n) {\n let str = channelProperty;\n if (!channelProperties) {\n return undefined;\n }\n if (Array.isArray(str)) {\n throw new Error(\n \"Getting values from channel property arrays is not supported.\",\n );\n }\n\n let cursor: ChannelProperties[string] = channelProperties;\n while (true) {\n if (!cursor || typeof cursor !== \"object\" || Array.isArray(cursor)) {\n return undefined;\n }\n const dotIndex = str.indexOf(\".\");\n if (dotIndex === -1) {\n return cursor ? cursor[str] : undefined;\n } else {\n const key = str.slice(0, dotIndex);\n cursor = cursor ? cursor[key] : undefined;\n str = str.slice(dotIndex + 1);\n }\n }\n}\n\nexport function getCardNumberFromChannelProperties(\n channelProperties: ChannelProperties | null,\n) {\n const cardNumber = getValueFromChannelProperty(\n \"card_details.card_number\",\n channelProperties,\n );\n if (typeof cardNumber !== \"string\") {\n return null;\n }\n return cardNumber;\n}\n\nexport function parseEncryptedFieldValue(str: string) {\n const out = {\n version: 0,\n publicKey: \"\",\n iv: \"\",\n cipherText: \"\",\n valid: false,\n validationError: null as string | null,\n withoutValidationError: str,\n };\n if (!str) {\n return out;\n }\n\n const parts = str.split(\"-\");\n if (parts.length < 6) {\n throw new Error(\"Invalid encrypted field value format.\");\n }\n if (parts[0] !== \"xendit\") {\n throw new Error(\"Invalid encrypted field value format.\");\n }\n if (parts[1] !== \"encrypted\") {\n throw new Error(\"Invalid encrypted field value format.\");\n }\n const version = parseInt(parts[2], 10);\n if (isNaN(version) || version <= 0) {\n throw new Error(\"Invalid encrypted field value format.\");\n }\n out.version = version;\n out.publicKey = parts[3];\n out.iv = parts[4];\n out.cipherText = parts[5];\n if (parts.length > 6) {\n if (parts[6] !== \"invalid\") {\n throw new Error(\"Invalid encrypted field value format.\");\n }\n out.validationError = atob(parts[7]);\n out.withoutValidationError = parts.slice(0, 6).join(\"-\");\n } else {\n out.valid = true;\n }\n\n return out;\n}\n\nconst objectIdMap = new WeakMap<object, number>();\nlet objectIdCounter = 1;\nexport function objectId(object: object): string {\n if (!objectIdMap.has(object)) {\n objectIdMap.set(object, objectIdCounter++);\n }\n return objectIdMap.get(object)!.toString();\n}\n\nexport function resolvePairedChannel(\n channels: BffChannel[],\n savePaymentMethod: boolean,\n): BffChannel {\n assert(channels.length > 0);\n assert(channels.length <= 2);\n\n if (channels.length === 2) {\n if (savePaymentMethod) {\n assert(channels[1].allow_save === true);\n return channels[1];\n } else {\n assert(channels[0].allow_save === false);\n return channels[0];\n }\n } else {\n return channels[0];\n }\n}\n\nexport function satisfiesMinMax(\n session: Pick<BffSession, \"amount\" | \"session_type\">,\n channel: BffChannel,\n): boolean {\n if (session.session_type !== \"PAY\") {\n return true; // only pay sessions have min/max\n }\n\n const amount = session.amount;\n const min = channel.min_amount ?? 0;\n const max = channel.max_amount ?? Number.MAX_VALUE;\n if (amount < min || amount > max) {\n return false;\n }\n\n return true;\n}\n\nexport function lockDownInteralProperty(obj: { [internal]: unknown }) {\n // make [internal] non-enumerable\n Object.defineProperty(obj, internal, {\n enumerable: false,\n writable: false,\n configurable: false,\n value: obj[internal],\n });\n}\n\nconst RELEASED_CHANNELS: Record<string, boolean> = {\n CARDS: true,\n QRIS: true,\n QR_PH: true,\n PROMPTPAY: true,\n SGQR: true,\n // ALIPAY: true,\n // APPOTA: true,\n // ASTRAPAY: true,\n // DANA: true,\n // GCASH: true,\n // GRABPAY: true,\n // JENIUSPAY: true,\n // LINEPAY: true,\n // LINKAJA: true,\n // NEXCASH: true,\n // OVO: true,\n // PAYMAYA: true,\n // SHOPEEPAY: true,\n // TOUCHNGO: true,\n // TRUEMONEY: true,\n // VNPTWALLET: true,\n // WECHATPAY: true,\n // ZALOPAY: true,\n // GOPAY: true,\n // GOPAY_RECURRING: true,\n};\n\n// filter out channels not supported by this SDK version\nexport function removeUnreleasedChannels(channels: BffChannel[]): BffChannel[] {\n return channels.filter((channel) => RELEASED_CHANNELS[channel.channel_code]);\n}\n\n/**\n * Returns true if the form has a field of the given type, *before filtering*.\n */\nexport function formHasFieldOfType(\n form: ChannelFormField[],\n type: string,\n): boolean {\n for (const field of form) {\n if (field.type.name === type) {\n return true;\n }\n }\n return false;\n}\n","import classNames from \"classnames\";\nimport { ComponentChildren, FunctionComponent } from \"preact\";\n\nexport enum ButtonVariant {\n BARE = \"bare\",\n PRIMARY_ROUNDED = \"primary-rounded\",\n WHITE_ROUNDED = \"white-rounded\",\n}\n\nexport enum ButtonSize {\n SM = \"sm\",\n MD = \"md\",\n}\n\ntype Props = {\n children: ComponentChildren;\n className?: string;\n disabled?: boolean;\n onClick?: (event: MouseEvent) => void;\n type?: \"button\" | \"submit\" | \"reset\";\n variant: ButtonVariant;\n size?: ButtonSize;\n};\n\nexport const Button: FunctionComponent<Props> = (props) => {\n const { children, variant, size, type = \"button\", ...rest } = props;\n\n const buttonVariantClass = {\n [ButtonVariant.BARE]: undefined,\n [ButtonVariant.PRIMARY_ROUNDED]: \"xendit-button-primary-rounded\",\n [ButtonVariant.WHITE_ROUNDED]: \"xendit-button-white-rounded\",\n }[variant];\n\n const buttonSizeClass = {\n [ButtonSize.SM]: \"xendit-button-sm\",\n [ButtonSize.MD]: undefined,\n }[size ?? ButtonSize.MD];\n\n return (\n <button\n {...rest}\n className={classNames(\n props.className,\n \"xendit-button\",\n buttonVariantClass,\n buttonSizeClass,\n )}\n type={type}\n >\n {children}\n </button>\n );\n};\n\nexport const ButtonLoadingSpinner = () => {\n const angle1 = Math.PI * 0.4;\n const angle2 = 0;\n const radius = 0.4;\n const start = { x: Math.cos(angle1) * radius, y: Math.sin(angle1) * radius };\n const end = { x: Math.cos(angle2) * radius, y: Math.sin(angle2) * radius };\n\n return (\n <svg className=\"xendit-button-loading-spinner\" viewBox=\"-0.5 -0.5 1 1\">\n <path\n d={`M ${start.x} ${start.y} A ${radius} ${radius} 0 0 0 ${end.x} ${end.y}`}\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"0.1\"\n strokeLinecap=\"round\"\n ></path>\n </svg>\n );\n};\n","import {\n ComponentChildren,\n FunctionComponent,\n TargetedEvent,\n TargetedMouseEvent,\n} from \"preact\";\nimport {\n useCallback,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from \"preact/hooks\";\nimport Icon from \"./icon\";\nimport { useIdSafe } from \"../utils\";\nimport { useSdk } from \"./session-provider\";\nimport { ButtonLoadingSpinner } from \"./button\";\n\nexport type DropdownOption = {\n leadingAsset?: ComponentChildren; // e.g. flag/icon URL\n title: string; // primary line\n shortTitle?: string;\n description?: string; // secondary line\n disabled?: boolean;\n value: string;\n};\n\nexport type DropdownProps = {\n /** Unique id for aria attributes */\n id?: string;\n\n /** Options to render */\n options: DropdownOption[];\n\n /**\n * Called when a new option is selected.\n * Receives the selected option & its index.\n */\n onChange: (option: DropdownOption, index: number) => void;\n\n /** Optional initial selection index (uncontrolled). Default: -1 (none). */\n defaultIndex?: number;\n\n /** Optional externally-controlled selection index. If set, component becomes controlled. */\n selectedIndex?: number;\n\n /** Optional label for a11y (used in aria-labelledby). */\n label?: string;\n\n /** Placeholder text when nothing selected. */\n placeholder?: string;\n\n /** Extra class on the root container. */\n className?: string;\n\n /** Makes the dropdown disabled */\n disabled?: boolean;\n};\n\nexport const Dropdown = (props: DropdownProps) => {\n const {\n id: _id,\n options,\n onChange,\n defaultIndex = -1,\n selectedIndex,\n className,\n placeholder,\n disabled,\n } = props;\n\n const t = useSdk().t;\n\n const generatedId = useIdSafe();\n const id = _id || generatedId;\n\n // Controlled vs uncontrolled selection\n const isControlled = typeof selectedIndex === \"number\";\n const [internalIndex, setInternalIndex] = useState(defaultIndex);\n const currentIndex = isControlled ? (selectedIndex as number) : internalIndex;\n\n // Active item for keyboard nav (when list open)\n const [activeIndex, setActiveIndex] = useState(\n currentIndex >= 0 ? currentIndex : 0,\n );\n const [_open, setOpen] = useState(false);\n const open = _open && !disabled && options.length > 0; // force closed when disabled or no options\n\n const [searchQuery, setSearchQuery] = useState(\"\");\n\n const rootRef = useRef<HTMLDivElement>(null);\n const btnRef = useRef<HTMLButtonElement>(null);\n const listRef = useRef<HTMLUListElement>(null);\n const activeRef = useRef<HTMLLIElement>(null);\n const searchInputRef = useRef<HTMLInputElement>(null);\n\n // Filter options based on search query\n const filteredOptions = useMemo(() => {\n const filtered = options.map(withIndex).filter(({ item: opt }) => {\n if (searchQuery.trim() === \"\") return true;\n const query = searchQuery.toLowerCase();\n return (\n opt.title.toLowerCase().includes(query) ||\n opt.description?.toLowerCase().includes(query) ||\n opt.value.toLowerCase().includes(query)\n );\n });\n\n // Show all options if no results found\n return filtered.length > 0 ? filtered : options.map(withIndex);\n }, [searchQuery, options]);\n\n const clampedActive = Math.max(\n 0,\n Math.min(filteredOptions.length - 1, activeIndex),\n );\n\n // Close on outside click\n useLayoutEffect(() => {\n if (!open) return;\n const onMouseDown = (e: MouseEvent) => {\n const root = rootRef.current;\n if (!root) return;\n if (!root.contains(e.target as Node)) setOpen(false);\n };\n document.addEventListener(\"mousedown\", onMouseDown);\n return () => document.removeEventListener(\"mousedown\", onMouseDown);\n }, [open]);\n\n // Close on outside focusout\n useLayoutEffect(() => {\n if (!open) return;\n const onFocusOut = (e: FocusEvent) => {\n const root = rootRef.current;\n if (!root) return;\n if (!e.relatedTarget) return;\n if (!root.contains(e.relatedTarget as Node)) setOpen(false);\n };\n document.body.addEventListener(\"focusout\", onFocusOut);\n return () => document.body.removeEventListener(\"focusout\", onFocusOut);\n }, [open]);\n\n // Keep active in sync with current selection when opening\n useLayoutEffect(() => {\n if (!open) return;\n if (currentIndex >= 0) setActiveIndex(currentIndex);\n }, [open, currentIndex]);\n\n // when open state or active index changes, scroll to active item\n useLayoutEffect(() => {\n if (!open) return;\n if (!activeRef.current) return;\n if (!listRef.current) return;\n const scrollContainer = listRef.current.parentElement;\n if (!scrollContainer) return;\n scrollContainer.scrollTop =\n activeRef.current.offsetTop -\n scrollContainer.clientHeight / 2 +\n activeRef.current.clientHeight / 2;\n }, [open, activeIndex]);\n\n const openList = useCallback(() => {\n if (!open) {\n setOpen(true);\n queueMicrotask(() => searchInputRef.current?.focus());\n }\n }, [open]);\n\n const closeList = useCallback(() => {\n if (open) {\n setOpen(false);\n setSearchQuery(\"\");\n btnRef.current?.focus();\n }\n }, [open]);\n\n const onButtonClick = useCallback(() => {\n if (open) {\n closeList();\n } else {\n openList();\n }\n }, [closeList, open, openList]);\n\n const selectItemAndClose = useCallback(\n (index: number) => {\n const opt = options[index];\n if (!opt) return;\n if (opt.disabled) return;\n if (!isControlled) setInternalIndex(index);\n onChange(opt, index);\n closeList();\n },\n [closeList, isControlled, onChange, options],\n );\n\n const onButtonKeyDown = useCallback(\n (e: KeyboardEvent) => {\n if (\n e.key === \"ArrowDown\" ||\n e.key === \"ArrowUp\" ||\n e.key === \" \" ||\n e.key === \"Enter\"\n ) {\n e.preventDefault();\n openList();\n }\n },\n [openList],\n );\n\n const onListKeyDown = useCallback(\n (e: KeyboardEvent) => {\n // Allow normal typing in search input\n const isSearchInput = e.target === searchInputRef.current;\n\n if (e.key === \"Escape\") {\n e.preventDefault();\n closeList();\n return;\n }\n if (e.key === \"Enter\" || e.key === \" \") {\n // Allow space in search input for typing\n if (isSearchInput && e.key === \" \") {\n return;\n }\n e.preventDefault();\n const activeItem = filteredOptions[clampedActive];\n if (activeItem) {\n selectItemAndClose(activeItem.originalIndex);\n }\n return;\n }\n if (e.key === \"ArrowDown\") {\n e.preventDefault();\n setActiveIndex((i) => Math.min(filteredOptions.length - 1, i + 1));\n return;\n }\n if (e.key === \"ArrowUp\") {\n e.preventDefault();\n setActiveIndex((i) => Math.max(0, i - 1));\n return;\n }\n if (e.key === \"Home\") {\n e.preventDefault();\n setActiveIndex(0);\n return;\n }\n if (e.key === \"End\") {\n e.preventDefault();\n setActiveIndex(filteredOptions.length - 1);\n return;\n }\n },\n [clampedActive, closeList, selectItemAndClose, filteredOptions],\n );\n\n const onOptionClick = useCallback(\n (e: TargetedMouseEvent<HTMLLIElement>) => {\n e.stopPropagation();\n e.preventDefault();\n selectItemAndClose(Number(e.currentTarget.dataset.index));\n },\n [selectItemAndClose],\n );\n\n const onSearchTermChange = useCallback(\n (e: TargetedEvent<HTMLInputElement>) => {\n setSearchQuery(e.currentTarget.value);\n setActiveIndex(0);\n },\n [],\n );\n\n const selected = currentIndex >= 0 ? options[currentIndex] : undefined;\n\n return (\n <div ref={rootRef} className={`xendit-dropdown ${className ?? \"\"}`}>\n <button\n id={id}\n ref={btnRef}\n type=\"button\"\n className={selected?.leadingAsset ? \"xendit-dropdown-has-asset\" : \"\"}\n aria-expanded={open ? \"true\" : \"false\"}\n onClick={onButtonClick}\n onKeyDown={onButtonKeyDown}\n disabled={disabled}\n >\n {selected?.leadingAsset ? selected.leadingAsset : null}\n\n {selected ? (\n <span className=\"xendit-dropdown-button-title xendit-text-14\">\n {selected.shortTitle ?? selected.title}\n </span>\n ) : (\n <span className=\"xendit-dropdown-button-title xendit-text-14\">\n {placeholder}\n </span>\n )}\n\n <Icon\n className=\"xendit-dropdown-chevron\"\n name=\"chevron\"\n size={16}\n direction={\"down\"}\n />\n </button>\n\n {open ? (\n <div className=\"xendit-dropdown-menu\">\n <div className=\"xendit-dropdown-search\">\n <input\n ref={searchInputRef}\n placeholder={t(\"combobox.default_search_placeholder\")}\n value={searchQuery}\n onInput={onSearchTermChange}\n onClick={stopPropagation}\n onKeyDown={onListKeyDown}\n />\n </div>\n <ul\n ref={listRef}\n role=\"listbox\"\n tabIndex={-1}\n onKeyDown={onListKeyDown}\n >\n {filteredOptions.map(({ item: opt, originalIndex }, i) => {\n const isSelected = originalIndex === currentIndex;\n const isActive = i === clampedActive;\n return (\n <li\n key={originalIndex}\n role=\"option\"\n data-index={originalIndex}\n aria-disabled={opt.disabled ? true : undefined}\n aria-selected={isSelected}\n onClick={onOptionClick}\n ref={isActive ? activeRef : undefined}\n >\n <div\n className={`xendit-dropdown-item xendit-text-14 ${isActive ? \"xendit-dropdown-item-active\" : \"\"} ${opt.leadingAsset ? \"xendit-dropdown-has-asset\" : \"\"} ${opt.disabled ? \"xendit-dropdown-item-disabled\" : \"\"}`}\n >\n {opt.leadingAsset ? opt.leadingAsset : null}\n <div className=\"xendit-dropdown-item-text xendit-text-14\">\n <span className=\"xendit-dropdown-item-title\">\n {opt.title}\n </span>\n {opt.description && (\n <span className=\"xendit-dropdown-item-description xendit-text-12\">\n {opt.description}\n </span>\n )}\n </div>\n {isSelected ? (\n <Icon\n name=\"check\"\n size={16}\n className={\"xendit-dropdown-item-selected\"}\n />\n ) : null}\n </div>\n </li>\n );\n })}\n </ul>\n </div>\n ) : null}\n </div>\n );\n};\n\nexport const DropdownSkeleton: FunctionComponent<{ id: string }> = (props) => {\n return (\n <div className=\"xendit-dropdown xendit-skeleton-field\">\n <button inert id={props.id} disabled type=\"button\">\n <ButtonLoadingSpinner />\n </button>\n </div>\n );\n};\n\nfunction stopPropagation(e: Event) {\n e.stopPropagation();\n}\n\nfunction withIndex<T>(\n item: T,\n originalIndex: number,\n): { item: T; originalIndex: number } {\n return {\n item,\n originalIndex,\n };\n}\n","import { BffChannel, BffChannelUiGroup } from \"./backend-types/channel\";\nimport { BffCustomer } from \"./backend-types/customer\";\nimport { BffDigitalWallets } from \"./backend-types/digital-wallets\";\nimport { BffSession } from \"./backend-types/session\";\nimport { internal } from \"./internal\";\nimport {\n XenditCustomer,\n XenditDigitalWallet,\n XenditPaymentChannel,\n XenditPaymentChannelGroup,\n XenditSession,\n} from \"./public-data-types\";\nimport {\n assert,\n assertEquals,\n assertNotEquals,\n lockDownInteralProperty,\n removeUndefinedPropertiesFromObject,\n satisfiesMinMax,\n} from \"./utils\";\n\ntype XenditItem = NonNullable<XenditSession[\"items\"]>[number];\n\nexport function bffSessionToPublic(bffSession: BffSession): XenditSession {\n assertNotEquals(bffSession.session_type, \"AUTHORIZATION\");\n assertEquals(bffSession.mode, \"COMPONENTS\");\n\n return removeUndefinedPropertiesFromObject<XenditSession>({\n id: bffSession.payment_session_id,\n description: bffSession.description || undefined,\n sessionType: bffSession.session_type,\n mode: bffSession.mode,\n referenceId: bffSession.reference_id,\n country: bffSession.country,\n currency: bffSession.currency,\n amount: bffSession.amount,\n channelProperties: bffSession.channel_properties || undefined,\n expiresAt: new Date(bffSession.expires_at),\n locale: bffSession.locale,\n status: bffSession.status,\n\n items: bffSession.items?.map((item) => {\n return removeUndefinedPropertiesFromObject<XenditItem>({\n type: item.type,\n referenceId: item.reference_id,\n name: item.name,\n netUnitAmount: item.net_unit_amount,\n quantity: item.quantity,\n url: item.url,\n imageUrl: item.image_url,\n category: item.category,\n subcategory: item.subcategory,\n description: item.description,\n metadata: item.metadata,\n });\n }),\n });\n}\n\nexport function bffCustomerToPublic(bffCustomer: BffCustomer): XenditCustomer {\n assertEquals(bffCustomer.type, \"INDIVIDUAL\");\n assert(bffCustomer.individual_detail);\n return {\n id: bffCustomer.id,\n type: bffCustomer.type,\n email: bffCustomer.email ?? undefined,\n mobileNumber: bffCustomer.mobile_number ?? undefined,\n individualDetail: {\n givenNames: bffCustomer.individual_detail.given_names ?? undefined,\n surname: bffCustomer.individual_detail.surname ?? undefined,\n },\n };\n}\n\ntype ChannelMarshalConfig = {\n options: {\n filter?: string | string[] | RegExp;\n filterMinMax: boolean;\n };\n pairChannels: PairChannelData;\n session: Pick<BffSession, \"amount\" | \"session_type\">;\n};\n\n/**\n * Generate public channel groups list.\n */\nexport function bffUiGroupsToPublic(\n bffChannels: BffChannel[],\n bffChannelGroups: BffChannelUiGroup[],\n marshalConfig: ChannelMarshalConfig,\n): XenditPaymentChannelGroup[] {\n const groupsByGroupId = makeGroupsByGroupId(bffChannelGroups);\n const channelsByGroupId = makeChannelsByGroupId(bffChannels, marshalConfig);\n return bffChannelGroups\n .filter((group) => channelsByGroupId[group.id]?.length)\n .map((group) => {\n return bffUiGroupToPublic(\n group,\n channelsByGroupId,\n groupsByGroupId,\n marshalConfig,\n );\n });\n}\n\n/**\n * Generate one public channel group.\n */\nexport function bffUiGroupToPublic(\n bffChannelGroup: BffChannelUiGroup,\n channelsByGroupId: Record<string, BffChannel[]>,\n groupsByGroupId: Record<string, BffChannelUiGroup>,\n marshalConfig: ChannelMarshalConfig,\n) {\n const group = removeUndefinedPropertiesFromObject<XenditPaymentChannelGroup>({\n groupId: bffChannelGroup.id,\n label: bffChannelGroup.label,\n get channels() {\n return (channelsByGroupId[bffChannelGroup.id] || []).map((channel) => {\n return bffChannelToPublic(\n channel,\n channelsByGroupId,\n groupsByGroupId,\n marshalConfig,\n );\n });\n },\n [internal]: bffChannelGroup,\n });\n\n lockDownInteralProperty(group);\n\n return group;\n}\n\n/**\n * Generate one public channel, without group data.\n */\nexport function singleBffChannelToPublic(\n bffChannel: BffChannel,\n marshalConfig: ChannelMarshalConfig,\n): XenditPaymentChannel {\n return bffChannelToPublic(bffChannel, {}, {}, marshalConfig);\n}\n\n/**\n * Generate one public channel.\n */\nexport function bffChannelToPublic(\n bffChannel: BffChannel,\n bffChannelsByGroupId: Record<string, BffChannel[]>,\n bffGroupsByGroupId: Record<string, BffChannelUiGroup>,\n marshalConfig: ChannelMarshalConfig,\n): XenditPaymentChannel {\n assert(!marshalConfig.pairChannels.paired[bffChannel.channel_code]);\n\n const channel = removeUndefinedPropertiesFromObject<XenditPaymentChannel>({\n channelCode:\n marshalConfig.pairChannels.pairs[bffChannel.channel_code]?.map(\n (ch) => ch.channel_code,\n ) ?? bffChannel.channel_code,\n brandName: bffChannel.brand_name,\n brandColor: bffChannel.brand_color,\n brandLogoUrl: bffChannel.brand_logo_url,\n get uiGroup() {\n if (!bffGroupsByGroupId[bffChannel.ui_group]) {\n throw new Error(\"UI group not found\");\n }\n return bffUiGroupToPublic(\n bffGroupsByGroupId[bffChannel.ui_group],\n bffChannelsByGroupId,\n bffGroupsByGroupId,\n marshalConfig,\n );\n },\n minAmount: bffChannel.min_amount,\n maxAmount: bffChannel.max_amount,\n cardBrands: bffChannel.card?.brands.map((b) => {\n return {\n name: b.name,\n logoUrl: b.logo_url,\n };\n }),\n [internal]: marshalConfig.pairChannels.pairs[bffChannel.channel_code] ?? [\n bffChannel,\n ],\n });\n\n lockDownInteralProperty(channel);\n\n return channel;\n}\n\n/**\n * Generate public channels list.\n */\nexport function bffChannelsToPublic(\n bffChannels: BffChannel[],\n bffChannelGroups: BffChannelUiGroup[],\n marshalConfig: ChannelMarshalConfig,\n): XenditPaymentChannel[] {\n const groupsByGroupId = makeGroupsByGroupId(bffChannelGroups);\n const channelsByGroupId = makeChannelsByGroupId(bffChannels, marshalConfig);\n return bffChannels\n .filter((ch) => {\n return channelFilterFn(ch, marshalConfig);\n })\n .map((channel) => {\n return bffChannelToPublic(\n channel,\n channelsByGroupId,\n groupsByGroupId,\n marshalConfig,\n );\n });\n}\n\n/**\n * Make a mapping of group ID to group.\n */\nfunction makeGroupsByGroupId(\n bffChannelGroups: BffChannelUiGroup[],\n): Record<string, BffChannelUiGroup> {\n const groupMap: Record<string, BffChannelUiGroup> = {};\n for (const bffGroup of bffChannelGroups) {\n groupMap[bffGroup.id] = bffGroup;\n }\n return groupMap;\n}\n\n/**\n * Return true if the channel passes the filter criteria.\n */\nexport function channelFilterFn(\n channel: BffChannel,\n marshalConfig: ChannelMarshalConfig,\n) {\n if (marshalConfig.pairChannels.paired[channel.channel_code]) {\n // channel is a second member of a pair, skip\n // TODO: users may filter out the first member of a pair, in which case we should remap the second member to the first\n return false;\n }\n\n if (\n marshalConfig.options.filterMinMax &&\n !satisfiesMinMax(marshalConfig.session, channel)\n ) {\n // min/max amount not satisfied\n return false;\n }\n\n const filter = marshalConfig.options.filter;\n if (filter && !channelCodeMatchesFilter(filter, channel.channel_code)) {\n // channel code does not match filter\n return false;\n }\n\n return true;\n}\n\n/**\n * Checks a channel code string against a filter term.\n */\nfunction channelCodeMatchesFilter(\n filter: string | string[] | RegExp,\n code: string,\n) {\n if (typeof filter === \"string\" && code === filter) {\n return true;\n }\n if (Array.isArray(filter) && filter.includes(code)) {\n return true;\n }\n if (filter instanceof RegExp && filter.test(code)) {\n return true;\n }\n return false;\n}\n\n/**\n * Create a mapping of group ID to channels in that group, applying channel filtering and removing empty groups.\n */\nexport function makeChannelsByGroupId(\n bffChannels: BffChannel[],\n marshalConfig: ChannelMarshalConfig,\n): Record<string, BffChannel[]> {\n const channelsByGroupId: Record<string, BffChannel[]> = {};\n for (const bffChannel of bffChannels) {\n if (!channelFilterFn(bffChannel, marshalConfig)) {\n continue;\n }\n const groupId = bffChannel.ui_group;\n if (!channelsByGroupId[groupId]) {\n channelsByGroupId[groupId] = [];\n }\n channelsByGroupId[groupId].push(bffChannel);\n }\n return channelsByGroupId;\n}\n\ntype PairChannelData = {\n /** Map of channel_code of first member of pair to an array containing the pair */\n pairs: Record<string, [BffChannel, BffChannel]>;\n /** Set of channel_codes of second members of pairs */\n paired: Record<string, boolean>;\n};\n\n/**\n * Finds channels that are pairs (i.e., differ only by allow_save) and groups them together.\n */\nexport function findChannelPairs(bffChannels: BffChannel[]): PairChannelData {\n const brandMap = new Map<string, BffChannel[]>();\n for (const channel of bffChannels) {\n const brandName = channel.brand_name;\n if (!brandMap.has(brandName)) {\n brandMap.set(brandName, []);\n }\n brandMap.get(brandName)!.push(channel);\n }\n\n const pairs: Record<string, [BffChannel, BffChannel]> = {};\n const paired: Record<string, boolean> = {};\n for (const [_, channels] of brandMap) {\n for (const ch of channels) {\n const isFirst = channels[0].allow_save === false;\n if (isFirst) {\n const pair = channels.find(\n (other) =>\n ch.channel_code !== other.channel_code &&\n ch.ui_group === other.ui_group &&\n other.allow_save === true,\n );\n if (pair) {\n pairs[ch.channel_code] = [ch, pair];\n paired[pair.channel_code] = true;\n }\n }\n }\n }\n\n return {\n pairs,\n paired,\n };\n}\n\nexport function bffDigitalWalletsToPublic(\n bffDigitalWallets: BffDigitalWallets,\n bffChannels: BffChannel[],\n bffChannelGroups: BffChannelUiGroup[],\n marshalConfig: ChannelMarshalConfig,\n): XenditDigitalWallet[] {\n const out: XenditDigitalWallet[] = [];\n\n const groupsByGroupId = makeGroupsByGroupId(bffChannelGroups);\n\n if (bffDigitalWallets.google_pay) {\n const googlePayChannels =\n bffDigitalWallets.google_pay.allowed_payment_methods.map((method) => {\n const ch = bffChannels.find(\n (c) => c.channel_code === method.channel_code,\n );\n assert(ch);\n return ch;\n });\n\n const channelsByGroupId = makeChannelsByGroupId(\n googlePayChannels,\n marshalConfig,\n );\n\n out.push({\n digitalWalletCode: \"GOOGLE_PAY\",\n get channels() {\n return googlePayChannels.map((channel) => {\n return bffChannelToPublic(\n channel,\n channelsByGroupId,\n groupsByGroupId,\n marshalConfig,\n );\n });\n },\n [internal]: true,\n });\n }\n\n return out;\n}\n","import {\n useCurrentChannel,\n useChannels,\n useSdk,\n useSession,\n} from \"./session-provider\";\nimport { BffChannel, BffChannelUiGroup } from \"../backend-types/channel\";\nimport { Dropdown, DropdownOption } from \"./dropdown\";\nimport { BffSession } from \"../backend-types/session\";\nimport { satisfiesMinMax, useIdSafe, usePrevious } from \"../utils\";\nimport {\n useCallback,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from \"preact/hooks\";\nimport {\n channelFilterFn,\n findChannelPairs,\n singleBffChannelToPublic,\n} from \"../bff-marshal\";\nimport { TFunction } from \"../localization\";\nimport { FunctionComponent } from \"preact\";\n\ninterface ChannelPickerGroupProps {\n group: BffChannelUiGroup;\n open: boolean;\n}\n\nexport const ChannelPickerGroup: FunctionComponent<ChannelPickerGroupProps> = (\n props,\n) => {\n const { group, open } = props;\n\n const sdk = useSdk();\n const { t } = sdk;\n const session = useSession();\n const channels = useChannels();\n\n const currentChannel = useCurrentChannel();\n\n const sessionType = session.session_type;\n\n const dropdownId = useIdSafe();\n\n // record the last user selection in the dropdown.\n // if the current channel selection is not part of this group, use this instead.\n // if this is set, and the current channel is null, when the group is opened we will restore this selection.\n const [fakeDropdownSelection, setFakeDropdownSelection] = useState<\n string | null\n >(null);\n\n // container for the selected channel component\n const containerRef = useRef<HTMLDivElement>(null);\n // if true, the container has something in it\n const [containerIsPopulated, setContainerIsPopulated] = useState(false);\n // reference to the selected channel element\n const selectedChannelElementRef = useRef<HTMLElement>(null);\n\n const pairChannelData = useMemo(() => findChannelPairs(channels), [channels]);\n const marshalConfig = useMemo(\n () => ({\n pairChannels: pairChannelData,\n session: {\n amount: session.amount,\n session_type: session.session_type,\n },\n options: { filterMinMax: false },\n }),\n [pairChannelData, session.amount, session.session_type],\n );\n\n const channelsInGroup = useMemo(() => {\n return channels.filter((ch) => {\n return channelFilterFn(ch, marshalConfig) && ch.ui_group === group.id;\n });\n }, [channels, group.id, marshalConfig]);\n\n // Create and mount the channel component if a channel is selected.\n // (replacing whatever was there before)\n useLayoutEffect(() => {\n if (!containerRef.current) return;\n if (!currentChannel) return;\n if (!open) return;\n const channelIsInThisGroup = channelsInGroup.find(\n (ch) => ch.channel_code === currentChannel.channel_code,\n );\n if (!channelIsInThisGroup) return;\n\n selectedChannelElementRef.current = sdk.createChannelComponent(\n singleBffChannelToPublic(currentChannel, marshalConfig),\n );\n if (\n selectedChannelElementRef.current.parentElement !== containerRef.current\n ) {\n setContainerIsPopulated(true);\n containerRef.current.replaceChildren(selectedChannelElementRef.current);\n } else {\n // it's already in the right place, do nothing.\n // replaceChildren would cause iframes to reload even if we do a no-op update.\n }\n }, [channelsInGroup, currentChannel, marshalConfig, open, sdk]);\n\n // when the group is opened, if the currently selected channel is unset but the fakeDropdownSelection is set,\n // select that channel to sync this group's selection with the sdk state\n const previousOpen = usePrevious(open);\n useLayoutEffect(() => {\n if (open && !previousOpen) {\n // only run this when the group is opened\n if (currentChannel === null && fakeDropdownSelection !== null) {\n // restore the previous user selection\n const ch = channelsInGroup.find(\n (channel) => channel.channel_code === fakeDropdownSelection,\n );\n if (ch) {\n sdk.setCurrentChannel(singleBffChannelToPublic(ch, marshalConfig));\n }\n }\n }\n }, [\n channelsInGroup,\n currentChannel,\n fakeDropdownSelection,\n marshalConfig,\n open,\n previousOpen,\n sdk,\n ]);\n\n // Called on channel dropdown change\n const onSelectedChannelChange = useCallback(\n (dropdownOption: DropdownOption) => {\n const selected =\n channels.find(\n (channel) => channel.channel_code === dropdownOption.value,\n ) || null;\n\n // change both the local dropdown selection state and the sdk current channel\n setFakeDropdownSelection(selected?.channel_code ?? null);\n sdk.setCurrentChannel(\n selected ? singleBffChannelToPublic(selected, marshalConfig) : null,\n );\n },\n [channels, marshalConfig, sdk],\n );\n\n // Create channel options for dropdown\n const channelOptions = useMemo(() => {\n return channelsInGroup.map<DropdownOption>((channel) => ({\n leadingAsset: (\n <img\n className=\"xendit-channel-logo\"\n src={channel.brand_logo_url}\n key={channel.channel_code}\n />\n ),\n title: channel.brand_name,\n value: channel.channel_code,\n disabled: !satisfiesMinMax(session, channel),\n description: getChannelDisabledReason(t, session, channel) || undefined,\n }));\n }, [channelsInGroup, session, t]);\n\n // Hide dropdown for cards channel\n const hideDropdown =\n channelsInGroup.length === 1 && channelsInGroup[0].channel_code === \"CARDS\";\n\n function dropdownSelectedIndex() {\n // find the selected index based on currentChannel, or fallback to fakeDropdownSelection\n const i1 = channelOptions.findIndex((channel) => {\n return channel.value === currentChannel?.channel_code;\n });\n if (i1 !== -1) return i1;\n const i2 = channelOptions.findIndex((channel) => {\n return channel.value === fakeDropdownSelection;\n });\n if (i2 !== -1) return i2;\n return -1;\n }\n\n return (\n <div className=\"xendit-channel-picker-group\">\n {hideDropdown ? null : (\n <div className=\"xendit-channel-form-field-group\">\n <label htmlFor={dropdownId} className=\"xendit-text-14\">\n {sessionType === \"SAVE\"\n ? t(\"payment_methods.add_payment_method\", {\n groupName: group.label ?? \"\",\n ns: \"session\",\n })\n : t(\"payment_methods.pay_with\")}\n </label>\n <Dropdown\n id={dropdownId}\n selectedIndex={dropdownSelectedIndex()}\n options={channelOptions}\n disabled={channelOptions.length <= 1}\n onChange={onSelectedChannelChange}\n placeholder={t(\"payment_methods.select_channel_placeholder\", {\n groupName: group.label,\n ns: \"session\",\n })}\n />\n </div>\n )}\n <div\n style={{ display: containerIsPopulated ? \"\" : \"none\" }}\n ref={containerRef}\n />\n </div>\n );\n};\n\nexport function getChannelDisabledReason(\n t: TFunction,\n session: BffSession,\n channel: BffChannel,\n): string | null {\n if (satisfiesMinMax(session, channel)) {\n return null;\n }\n\n if (channel.min_amount && session.amount < channel.min_amount) {\n return t(\"payment_methods.channel_disabled_amount_too_small\");\n } else {\n return t(\"payment_methods.channel_disabled_amount_too_large\");\n }\n}\n","import { FunctionComponent } from \"preact\";\nimport { useDigitalWallets, useSdk } from \"./session-provider\";\nimport { useLayoutEffect, useRef } from \"preact/hooks\";\n\nexport const ChannelPickerDigitalWalletSection: FunctionComponent = (props) => {\n const sdk = useSdk();\n\n const containerRef = useRef<HTMLDivElement>(null);\n\n const digitalWallets = useDigitalWallets();\n const digitalWalletsGooglePay = digitalWallets?.google_pay;\n\n useLayoutEffect(() => {\n if (containerRef.current && digitalWalletsGooglePay) {\n const el = sdk.createDigitalWalletComponent(\"GOOGLE_PAY\");\n containerRef.current.appendChild(el);\n return () => {\n el.remove();\n };\n }\n }, [digitalWalletsGooglePay, sdk]);\n\n return (\n <div\n ref={containerRef}\n className=\"xendit-channel-picker-digital-wallet-section\"\n ></div>\n );\n};\n","import { Accordion } from \"./accordion\";\nimport { AccordionItem } from \"./accordion-item\";\nimport {\n useCurrentChannel,\n useChannelUiGroups,\n useSession,\n useChannels,\n useSdk,\n} from \"./session-provider\";\nimport {\n useCallback,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from \"preact/hooks\";\nimport { FunctionComponent } from \"preact\";\nimport {\n ChannelPickerGroup,\n getChannelDisabledReason,\n} from \"./channel-picker-group\";\nimport { assert, satisfiesMinMax } from \"../utils\";\nimport { BffSession } from \"../backend-types/session\";\nimport { BffChannel, BffChannelUiGroup } from \"../backend-types/channel\";\nimport { TFunction } from \"../localization\";\nimport {\n findChannelPairs,\n makeChannelsByGroupId,\n singleBffChannelToPublic,\n} from \"../bff-marshal\";\nimport { ChannelPickerDigitalWalletSection } from \"./channel-picker-digital-wallet-section\";\nimport { internal } from \"../internal\";\n\ntype Props = object;\n\nexport const XenditChannelPicker: FunctionComponent<Props> = (props) => {\n const sdk = useSdk();\n const session = useSession();\n const channelUiGroups = useChannelUiGroups();\n const currentChannel = useCurrentChannel();\n const channels = useChannels();\n const { t } = useSdk();\n\n const channelsByGroup = useMemo(() => {\n return makeChannelsByGroupId(channels, {\n options: { filterMinMax: false },\n pairChannels: findChannelPairs(channels),\n session,\n });\n }, [channels, session]);\n\n const thisRef = useRef<HTMLDivElement>(null);\n\n const pairChannelData = useMemo(() => findChannelPairs(channels), [channels]);\n const marshalConfig = useMemo(\n () => ({\n pairChannels: pairChannelData,\n session: {\n amount: session.amount,\n session_type: session.session_type,\n },\n options: { filterMinMax: false },\n }),\n [pairChannelData, session.amount, session.session_type],\n );\n\n // selected group is the containing group of the currently selected channel\n const selectedGroupId = currentChannel?.ui_group ?? null;\n\n // previewed group means expanded but no channel selected\n const [previewGroupId, setPreviewGroupId] = useState<string | null>(null);\n\n const handleSelectChannelGroup = useCallback(\n (groupId: string) => {\n if (selectedGroupId === groupId || previewGroupId === groupId) {\n // user wants to collapse the group while a channel was selected, clear the channel selection\n if (selectedGroupId === groupId) {\n // clear actual selection\n thisRef.current?.dispatchEvent(\n new XenditClearCurrentChannelEvent(groupId),\n );\n }\n if (previewGroupId === groupId) {\n // clear previewed state\n setPreviewGroupId(null);\n }\n } else {\n // user wants to open a different group\n // if the new group has one channel, select it automatically\n // otherwise set it as previewed\n const newGroup = channelUiGroups.find((g) => g.id === groupId);\n assert(newGroup);\n const enabledChannels = groupEnabledChannelStats(\n session,\n newGroup,\n channels,\n t,\n ).enabledChannels;\n if (enabledChannels === 0) {\n // no enabled channels, do nothing\n return;\n } else if (enabledChannels === 1) {\n // one enabled channel, select it automatically\n const ch = channelsByGroup[groupId][0];\n sdk.setCurrentChannel(singleBffChannelToPublic(ch, marshalConfig));\n setPreviewGroupId(null);\n } else {\n // multiple enabled channels, set as previewed and clear the channel selection\n setPreviewGroupId(groupId);\n sdk.setCurrentChannel(null);\n }\n }\n },\n [\n channelUiGroups,\n channels,\n channelsByGroup,\n marshalConfig,\n previewGroupId,\n sdk,\n selectedGroupId,\n session,\n t,\n ],\n );\n\n // once a channel is selected, remove previewGroupId.\n // (without this, the group would continue showing the old selected channel after the selection is cleared using setCurrentChannel(null))\n useLayoutEffect(() => {\n if (currentChannel !== null && previewGroupId !== null) {\n setPreviewGroupId(null);\n }\n }, [currentChannel, previewGroupId]);\n\n // TODO: enable by default when released\n const digitalWalletSectionEnabled =\n sdk[internal].options.enableDigitalWallets ?? false;\n\n return (\n <div ref={thisRef}>\n {digitalWalletSectionEnabled ? (\n <ChannelPickerDigitalWalletSection />\n ) : null}\n <Accordion>\n {channelUiGroups\n .filter((group) => {\n // remove empty groups\n return (channelsByGroup[group.id] || []).length > 0;\n })\n .map((group) => {\n // make the group open if it is selected or previewed\n const open =\n selectedGroupId !== null\n ? selectedGroupId === group.id\n : previewGroupId === group.id;\n\n // make the group disabled if it has no enabled channels\n const enabledChannelsStats = groupEnabledChannelStats(\n session,\n group,\n channels,\n t,\n );\n const disabled = enabledChannelsStats.enabledChannels === 0;\n const disabledReason =\n enabledChannelsStats.firstDisabledChannelReason;\n\n return (\n <AccordionItem\n key={group.id}\n id={group.id}\n title={group.label}\n subtitle={disabledReason ?? undefined}\n open={open}\n disabled={disabled}\n onClick={handleSelectChannelGroup}\n >\n <ChannelPickerGroup group={group} open={open} />\n </AccordionItem>\n );\n })}\n </Accordion>\n </div>\n );\n};\n\n// returns null if the group has any enabled channels, otherwise returns the disabled reason as a string\nfunction groupEnabledChannelStats(\n session: BffSession,\n group: BffChannelUiGroup,\n channels: BffChannel[],\n t: TFunction,\n): {\n enabledChannels: number;\n firstDisabledChannelReason: string | null;\n} {\n let firstDisabledChannelReason = null;\n let enabledChannels = 0;\n for (const channel of channels) {\n if (channel.ui_group !== group.id) continue;\n if (satisfiesMinMax(session, channel)) {\n enabledChannels++;\n continue;\n }\n if (firstDisabledChannelReason === null) {\n firstDisabledChannelReason = getChannelDisabledReason(\n t,\n session,\n channel,\n );\n }\n }\n return {\n enabledChannels,\n firstDisabledChannelReason,\n };\n}\n\nexport class XenditClearCurrentChannelEvent extends Event {\n static readonly type = \"xendit-clear-current-channel\" as const;\n uiGroup: string;\n\n constructor(uiGroup: string) {\n super(XenditClearCurrentChannelEvent.type, {\n bubbles: true,\n composed: true,\n });\n this.uiGroup = uiGroup;\n }\n}\n","import { useCallback, useLayoutEffect, useRef, useState } from \"preact/hooks\";\nimport { FieldProps } from \"./field\";\nimport { CountryCode, getCountries } from \"libphonenumber-js\";\nimport { Dropdown, DropdownOption } from \"./dropdown\";\nimport { formFieldId, formFieldName, usePrevious } from \"../utils\";\nimport { FunctionComponent } from \"preact\";\nimport { useChannelComponentData } from \"./payment-channel\";\n\ntype FlagIconProps = {\n countryCode: string;\n size?: number;\n};\n\nconst FlagIcon: FunctionComponent<FlagIconProps> = ({\n countryCode,\n size = 16,\n}) => {\n return (\n <div\n style={{\n width: `${size}px`,\n height: `${size}px`,\n borderRadius: \"50%\",\n backgroundImage: `url(https://assets.xendit.co/payment-session/flags/circle/${countryCode.toLowerCase()}.svg)`,\n backgroundSize: \"cover\",\n backgroundPosition: \"center\",\n }}\n />\n );\n};\n\nexport const CountryField: FunctionComponent<FieldProps> = (props) => {\n const { field, onChange } = props;\n const id = formFieldId(field);\n const name = formFieldName(field);\n\n const [selectedCountry, setSelectedCountry] = useState<\n CountryCode | undefined\n >(undefined);\n const selectedCountryIndex = COUNTRIES_AS_DROPDOWN_OPTIONS.findIndex(\n (option) => option.value === selectedCountry,\n );\n\n const hiddenFieldRef = useRef<HTMLInputElement>(null);\n\n useOnCardCountryChange((newCountry: CountryCode) => {\n if (hiddenFieldRef.current) {\n const newOption = COUNTRIES_AS_DROPDOWN_OPTIONS.find((option) => {\n return option.value === newCountry;\n });\n if (newOption) onChangeWrapper(newOption);\n }\n });\n\n const onChangeWrapper = useCallback(\n (option: DropdownOption) => {\n setSelectedCountry(option.value as CountryCode);\n if (hiddenFieldRef.current) {\n hiddenFieldRef.current.value = option.value;\n }\n onChange();\n },\n [onChange],\n );\n\n return (\n <div>\n <input type=\"hidden\" name={name} defaultValue=\"\" ref={hiddenFieldRef} />\n <Dropdown\n id={id}\n options={COUNTRIES_AS_DROPDOWN_OPTIONS}\n onChange={onChangeWrapper}\n placeholder={field.placeholder}\n selectedIndex={selectedCountryIndex}\n />\n </div>\n );\n};\n\nexport const COUNTRIES_AS_DROPDOWN_OPTIONS = getCountries()\n .map((countryCode) => {\n const country = new Intl.DisplayNames([\"en\"], {\n type: \"region\",\n }).of(countryCode);\n\n return {\n title: country,\n value: countryCode,\n leadingAsset: <FlagIcon countryCode={countryCode} />,\n } as DropdownOption;\n })\n .sort((a, b) => a.title.localeCompare(b.title));\n\nexport function useOnCardCountryChange(fn: (newCountry: CountryCode) => void) {\n const cardDetails = useChannelComponentData()?.cardDetails;\n const cardDetailsCountry = cardDetails?.details?.country_codes[0];\n\n // if card details changes, set country to card's country\n const previousCardDetailsCountry = usePrevious(cardDetailsCountry);\n useLayoutEffect(() => {\n if (\n cardDetailsCountry &&\n cardDetailsCountry !== previousCardDetailsCountry\n ) {\n fn(cardDetailsCountry as CountryCode);\n }\n });\n}\n","import { FunctionComponent } from \"preact\";\nimport { ChannelFormField, FieldType } from \"../backend-types/channel\";\nimport { formFieldId, formFieldName } from \"../utils\";\nimport { Dropdown, DropdownOption } from \"./dropdown\";\nimport { FieldProps } from \"./field\";\nimport { useCallback, useRef } from \"preact/hooks\";\n\nconst toDropdownOptions = (\n fieldOptions: (FieldType & { name: \"dropdown\" })[\"options\"],\n): DropdownOption[] => {\n return fieldOptions.map((opt) => ({\n title: opt.label,\n description: opt.subtitle,\n value: opt.value,\n }));\n};\n\nexport const DropdownField: FunctionComponent<FieldProps> = (props) => {\n const { field, onChange } = props;\n const id = formFieldId(field);\n const name = formFieldName(field);\n\n const hiddenFieldRef = useRef<HTMLInputElement>(null);\n\n const onChangeWrapper = useCallback(\n (option: DropdownOption) => {\n if (hiddenFieldRef.current) {\n hiddenFieldRef.current.value = option.value;\n }\n onChange();\n },\n [onChange],\n );\n\n if (!isDropdownField(field)) {\n throw new Error(\"DropdownField expects field.type.name to be 'dropdown'\");\n }\n\n return (\n <>\n <Dropdown\n id={id}\n placeholder={field.placeholder}\n options={toDropdownOptions(field.type.options)}\n onChange={onChangeWrapper}\n />\n <input type=\"hidden\" name={name} defaultValue=\"\" ref={hiddenFieldRef} />\n </>\n );\n};\n\nfunction isDropdownField(field: ChannelFormField): field is ChannelFormField & {\n type: { name: \"dropdown\" };\n} {\n return field.type.name === \"dropdown\";\n}\n","import { registerElement } from \"../dom-utils\";\n\n// prevent crash if running in node\nconst HTMLElement: (typeof window)[\"HTMLElement\"] =\n typeof window !== \"undefined\" && window.HTMLElement\n ? window.HTMLElement\n : (EventTarget as typeof HTMLElement);\n\n/**\n * https://html.spec.whatwg.org/multipage/forms.html#category-label\n * See the definition of \"labelable\".\n * This is a custom element which is labelable.\n *\n * This makes it possible to catch focus events when a label element is\n * clicked without adding any interactive elements.\n */\nexport class XenditFormAssociatedFocusTrap extends HTMLElement {\n static tag = \"xendit-form-associated-focus-trap\" as const;\n static formAssociated = true;\n private internals: ElementInternals;\n constructor() {\n super();\n this.internals = this.attachInternals();\n }\n}\nregisterElement(XenditFormAssociatedFocusTrap);\n\ndeclare module \"react/jsx-runtime\" {\n // eslint-disable-next-line @typescript-eslint/no-namespace\n namespace JSX {\n interface IntrinsicElements {\n \"xendit-form-associated-focus-trap\": preact.DetailedHTMLProps<\n preact.HTMLAttributes<XenditFormAssociatedFocusTrap>,\n XenditFormAssociatedFocusTrap\n >;\n }\n }\n}\n","export function registerElement(\n element: CustomElementConstructor & { tag: string },\n) {\n if (typeof window === \"undefined\" || !window.customElements) return;\n customElements.define(element.tag, element);\n}\n\nexport function findFirstStyleOrLinkElement() {\n return document.querySelector(\"style, link\");\n}\n","import { BffPollResponse } from \"./backend-types/common\";\nimport {\n ChannelComponentData,\n UpdatableWorldState,\n WorldState,\n} from \"./public-sdk\";\n\n/**\n * @internal\n * Event fired when a session / paymentEntity / etc is changed.\n *\n * Fire this on the sdk instance.\n * ! Don't fire this from within a react render\n */\nexport class InternalUpdateWorldState extends Event {\n static type = \"xendit-update-world-state\" as const;\n\n constructor(public data: WorldState | UpdatableWorldState) {\n super(InternalUpdateWorldState.type, { bubbles: false });\n }\n}\n\n/**\n * @internal\n * Event fired when a session / paymentEntity / etc is changed.\n *\n * Fire this on the sdk instance.\n * ! Don't fire this from within a react render\n */\nexport class InternalUpdateChannelComponentData extends Event {\n static type = \"xendit-update-channel-component-data\" as const;\n\n constructor(\n public channelCode: string,\n public data: Partial<ChannelComponentData>,\n ) {\n super(InternalUpdateChannelComponentData.type, { bubbles: false });\n }\n}\n\n/**\n * @internal\n * Marks it as touched, causing it to reveal validation errors.\n *\n * Fire this on the input to mark as touched.\n * Safe to fire from within a react render.\n */\nexport class InternalSetFieldTouchedEvent extends Event {\n static type = \"xendit-internal-set-field-touched\" as const;\n\n constructor() {\n super(InternalSetFieldTouchedEvent.type, { bubbles: true });\n }\n}\n\n/**\n * @internal\n * Schedules a behavior tree update.\n *\n * Fire this on the sdk instance.\n * Safe to fire from within a react render.\n * ! Be careful to avoid infinite loops.\n */\nexport class InternalBehaviorTreeUpdateEvent extends Event {\n static type = \"xendit-internal-behavior-tree-update\" as const;\n\n constructor() {\n super(InternalBehaviorTreeUpdateEvent.type, {});\n }\n}\n\n/**\n * @internal\n * Schedule a rerender of all components on the next tick.\n *\n * Fire this on the sdk instance.\n * ! Don't fire this from within a react render\n */\nexport class InternalNeedsRerenderEvent extends Event {\n static type = \"xendit-internal-needs-rerender\" as const;\n\n constructor() {\n super(InternalNeedsRerenderEvent.type, {});\n }\n}\n\n/**\n * @internal\n * Set the contents of the next mock poll response. Replaces any other pending scheduled mock update.\n *\n * Fire this on the sdk instance.\n * Safe to fire from within a react render.\n */\nexport class InternalScheduleMockUpdateEvent extends Event {\n static type = \"xendit-internal-schedule-mock-update\" as const;\n\n constructor(public mockData: BffPollResponse | null) {\n super(InternalScheduleMockUpdateEvent.type, {});\n }\n}\n","import {\n ComponentChildren,\n createContext,\n FunctionComponent,\n RefObject,\n} from \"preact\";\nimport { IframeEvent } from \"../../../shared/types\";\nimport { useRef } from \"preact/hooks\";\nimport { assert } from \"../utils\";\n\ninterface IframeRegistry {\n registerIframe: (\n fieldName: string,\n iframeRef: RefObject<HTMLIFrameElement>,\n ) => void;\n unregisterIframe: (fieldName: string) => void;\n postMessageToIframe: (fieldName: string, message: IframeEvent) => void;\n}\n\n/**\n * Context to keep track of iframes rendered in the form, allowing other components\n * to post messages to these iframes without needing direct access to their refs.\n */\nexport const IframeRegistryContext = createContext<IframeRegistry | null>(null);\n\n// read iframe data from environment variable\nassert(process.env.XENDIT_COMPONENTS_SECURE_IFRAME_URL);\nconst parsedIframeUrl = new URL(\n process.env.XENDIT_COMPONENTS_SECURE_IFRAME_URL,\n);\nconst IFRAME_ORIGIN = parsedIframeUrl.origin;\n\nexport const IframeRegistryProvider: FunctionComponent<{\n children: ComponentChildren;\n}> = ({ children }) => {\n const iframeRegistry = useRef<Map<string, HTMLIFrameElement>>(new Map());\n\n const iframeRegistryValue: IframeRegistry = {\n registerIframe: (fieldName, ref) => {\n if (ref.current) iframeRegistry.current.set(fieldName, ref.current);\n },\n unregisterIframe: (fieldName) => iframeRegistry.current.delete(fieldName),\n postMessageToIframe: (fieldName, message) => {\n const iframe = iframeRegistry.current.get(fieldName);\n if (iframe?.contentWindow) {\n iframe.contentWindow.postMessage(message, IFRAME_ORIGIN);\n }\n },\n };\n\n return (\n <IframeRegistryContext.Provider value={iframeRegistryValue}>\n {children}\n </IframeRegistryContext.Provider>\n );\n};\n","import {\n useCallback,\n useContext,\n useLayoutEffect,\n useRef,\n useState,\n} from \"preact/hooks\";\nimport { FieldProps } from \"./field\";\nimport { useSdk, useSession } from \"./session-provider\";\nimport { CardBrand, IframeEvent } from \"../../../shared/types\";\nimport { useChannel } from \"./payment-channel\";\nimport { XenditFormAssociatedFocusTrap } from \"./form-ascociated-focus-trap\";\nimport { internal } from \"../internal\";\nimport { assert, formFieldId, formFieldName } from \"../utils\";\nimport { FunctionComponent } from \"preact\";\nimport { InternalSetFieldTouchedEvent } from \"../private-event-types\";\nimport { IframeRegistryContext } from \"./iframe-registry\";\n\n// read iframe data from environment variable\nassert(process.env.XENDIT_COMPONENTS_SECURE_IFRAME_URL);\nconst parsedIframeUrl = new URL(\n process.env.XENDIT_COMPONENTS_SECURE_IFRAME_URL,\n);\nconst IFRAME_SRC = parsedIframeUrl.toString();\nconst IFRAME_ORIGIN = parsedIframeUrl.origin;\n\nexport const IframeField: FunctionComponent<FieldProps> = (props) => {\n const { field, onChange } = props;\n\n const sdk = useSdk();\n\n const id = formFieldId(field);\n const name = formFieldName(field);\n const session = useSession();\n\n const iframeRef = useRef<HTMLIFrameElement>(null);\n const hiddenFieldRef = useRef<HTMLInputElement>(null);\n const [iframeEcdhPublicKey, setIframeEcdhPublicKey] = useState<\n string | undefined\n >();\n\n const [focusWithin, setFocusWithin] = useState(false);\n\n const [cardBrand, setCardBrand] = useState<CardBrand | null>(null);\n\n const { card } = useChannel() ?? {};\n\n const handleEventFromIframe = useCallback(\n (event: MessageEvent) => {\n if (!iframeRef.current) return;\n\n const expectedSource = iframeRef.current.contentWindow;\n\n if (event.source !== expectedSource) {\n // this is normal, we are not the target of this message\n return;\n }\n\n if (event.origin !== IFRAME_ORIGIN) {\n // this is not normal, something fishy is happening\n return;\n }\n\n const data = event.data as IframeEvent;\n switch (data.type) {\n case \"xendit-iframe-ready\": {\n setIframeEcdhPublicKey(data.ecdhPublicKey);\n break;\n }\n case \"xendit-iframe-change\": {\n if (!hiddenFieldRef.current) return;\n\n setCardBrand(data.cardBrand);\n\n const encrypted = data.encrypted;\n const encryptionVersion = 1;\n const resultData = encrypted.map((enc) => {\n if (data.empty) {\n return \"\";\n }\n\n const parts = [\n \"xendit-encrypted\",\n encryptionVersion,\n iframeEcdhPublicKey,\n enc.iv,\n enc.value,\n ];\n\n if (!data.valid && data.validationErrorCodes.length) {\n // append validation error if invalid - because the validation code can't validate an encrypted string\n parts.push(\n \"invalid\",\n btoa(data.validationErrorCodes[0].localeKey),\n );\n }\n\n return parts.join(\"-\");\n });\n\n if (resultData.length === 0) {\n break; // should never happen\n }\n\n // fields expecting a single value are normal strings, fields expecting multiple values are json arrays\n hiddenFieldRef.current.value =\n resultData.length > 1 ? JSON.stringify(resultData) : resultData[0];\n onChange?.();\n break;\n }\n case \"xendit-iframe-focus\": {\n setFocusWithin(true);\n break;\n }\n case \"xendit-iframe-blur\": {\n setFocusWithin(false);\n if (hiddenFieldRef.current?.value) {\n // mark field as touched if not empty\n hiddenFieldRef.current?.dispatchEvent(\n new InternalSetFieldTouchedEvent(),\n );\n }\n break;\n }\n case \"xendit-iframe-failed-init\": {\n console.error(\n `Iframe field for ${field.channel_property} failed to initialize securely`,\n );\n break;\n }\n }\n },\n [field.channel_property, iframeEcdhPublicKey, onChange],\n );\n\n const giveFocusToIframe = useCallback(() => {\n if (iframeRef.current?.contentWindow) {\n iframeRef.current.contentWindow.postMessage(\n { type: \"xendit-iframe-focus\" satisfies IframeEvent[\"type\"] },\n IFRAME_ORIGIN,\n );\n }\n }, []);\n\n useLayoutEffect(() => {\n window.addEventListener(\"message\", handleEventFromIframe);\n return () => {\n window.removeEventListener(\"message\", handleEventFromIframe);\n };\n }, [handleEventFromIframe]);\n\n const registry = useContext(IframeRegistryContext);\n useLayoutEffect(() => {\n registry?.registerIframe(name, iframeRef);\n return () => registry?.unregisterIframe(name);\n }, [name, registry]);\n\n const iframeUrl = new URL(IFRAME_SRC);\n iframeUrl.searchParams.set(\"input_type\", field.type.name);\n iframeUrl.searchParams.set(\"embedder\", window.location.origin);\n iframeUrl.searchParams.set(\"session_id\", session.payment_session_id);\n\n iframeUrl.searchParams.set(\"pk\", sdk[internal].sdkKey.publicKey);\n iframeUrl.searchParams.set(\"sig\", sdk[internal].sdkKey.signature);\n\n // Pass appearance options if provided\n if (sdk[internal].options.iframeFieldAppearance) {\n iframeUrl.searchParams.set(\n \"appearance\",\n JSON.stringify(sdk[internal].options.iframeFieldAppearance),\n );\n }\n\n const focusClass = focusWithin ? \"xendit-field-focus\" : \"\";\n\n return (\n <div className={`xendit-iframe-container ${focusClass}`}>\n <XenditFormAssociatedFocusTrap.tag\n id={id}\n onFocus={giveFocusToIframe}\n tabIndex={-1}\n />\n <input type=\"hidden\" name={name} defaultValue=\"\" ref={hiddenFieldRef} />\n <iframe\n src={iframeUrl.toString()}\n ref={iframeRef}\n sandbox=\"allow-scripts allow-same-origin\"\n />\n {field.type.name === \"credit_card_number\" && card && (\n <CardBrands\n cardsBrandList={card.brands}\n selectedCardBrand={cardBrand}\n />\n )}\n </div>\n );\n};\n\nconst CardBrands = ({\n cardsBrandList,\n selectedCardBrand,\n}: {\n cardsBrandList: { name: string; logo_url: string }[];\n selectedCardBrand: CardBrand | null;\n}) => {\n if (!cardsBrandList) return null;\n\n const cardBrandLogo = cardsBrandList.find(\n (b) => b.name === selectedCardBrand,\n )?.logo_url;\n\n return (\n <div className=\"xendit-card-brands-list\">\n {selectedCardBrand\n ? cardBrandLogo && (\n <img\n className={\"xendit-card-brand-logo\"}\n src={cardBrandLogo}\n alt={selectedCardBrand}\n />\n )\n : cardsBrandList.map(({ name, logo_url }) => {\n return (\n <img\n className={\"xendit-card-brand-logo\"}\n src={logo_url}\n alt={name}\n key={name}\n />\n );\n })}\n </div>\n );\n};\n","import { FieldProps } from \"./field\";\nimport { Dropdown, DropdownOption } from \"./dropdown\";\nimport { CountryCode, getCountryCallingCode } from \"libphonenumber-js/min\";\nimport {\n COUNTRIES_AS_DROPDOWN_OPTIONS,\n useOnCardCountryChange,\n} from \"./field-country\";\nimport parsePhoneNumberFromString, {\n getExampleNumber,\n PhoneNumber,\n} from \"libphonenumber-js\";\nimport examples from \"libphonenumber-js/mobile/examples\";\nimport { useSession } from \"./session-provider\";\nimport { formFieldId, formFieldName } from \"../utils\";\nimport { useCallback, useMemo, useRef, useState } from \"preact/hooks\";\nimport { FunctionComponent, TargetedEvent, TargetedFocusEvent } from \"preact\";\nimport { InternalSetFieldTouchedEvent } from \"../private-event-types\";\n\nexport const PhoneNumberField: FunctionComponent<FieldProps> = (props) => {\n const { field, onChange } = props;\n const id = formFieldId(field);\n const name = formFieldName(field);\n\n const session = useSession();\n\n const hiddenFieldRef = useRef<HTMLInputElement>(null);\n\n const [countryCode, setCountryCode] = useState(session.country);\n const countryCodeIndex = useMemo(() => {\n const index = COUNTRIES_WITH_DIAL_CODES_AS_DROPDOWN_OPTIONS.findIndex(\n (r) => r.value === countryCode,\n );\n if (index === -1) return 0;\n return index;\n }, [countryCode]);\n const country =\n COUNTRIES_WITH_DIAL_CODES_AS_DROPDOWN_OPTIONS[countryCodeIndex];\n\n const [localNumber, setLocalNumber] = useState(\"\");\n const inputRef = useRef<HTMLInputElement>(null);\n\n const formatPhoneNumber = useCallback(\n (country: DropdownOptionWithDial, localNumber: string) => {\n const phoneNumber = sanitizePhoneNumber(country, localNumber);\n if (phoneNumber) {\n // use parsed format if parsing was successful\n return phoneNumber.number;\n } else {\n // else just concat the dial code and local number\n return `+${country.dial}${localNumber}`;\n }\n },\n [],\n );\n\n const updateHiddenField = useCallback(\n (country: DropdownOptionWithDial, localNumber: string) => {\n if (hiddenFieldRef.current) {\n hiddenFieldRef.current.value = formatPhoneNumber(country, localNumber);\n }\n },\n [formatPhoneNumber],\n );\n\n function handleLocalChange(event: TargetedEvent<HTMLInputElement>): void {\n const nextLocal = (event.target as HTMLInputElement).value;\n setLocalNumber(nextLocal);\n updateHiddenField(country, nextLocal);\n onChange();\n }\n\n function handleCountryChange(option: DropdownOption): void {\n const nextCountry = option as DropdownOptionWithDial;\n setCountryCode(nextCountry.value as string);\n updateHiddenField(nextCountry, localNumber);\n onChange();\n }\n\n function handleBlur(event: TargetedFocusEvent<HTMLInputElement>): void {\n formatForUser();\n if (event.currentTarget?.value) {\n hiddenFieldRef.current?.dispatchEvent(new InternalSetFieldTouchedEvent());\n }\n }\n\n // when the user inputs a card number, update the phone number field to match\n useOnCardCountryChange((newCountry: CountryCode) => {\n const newOption = COUNTRIES_WITH_DIAL_CODES_AS_DROPDOWN_OPTIONS.find(\n (option) => option.value === newCountry,\n );\n if (newOption && newOption.value !== countryCode && !localNumber) {\n handleCountryChange(newOption);\n }\n });\n\n function getExampleLocalNumber() {\n return (\n getExampleNumber(country.value as CountryCode, examples)\n ?.formatInternational()\n ?.replace(\n `+${getCountryCallingCode(country.value as CountryCode)} `,\n \"\",\n ) || \"\"\n );\n }\n\n function formatForUser() {\n const phoneNumber = sanitizePhoneNumber(country, localNumber);\n if (phoneNumber) {\n const international = phoneNumber.formatInternational();\n // remove country dial code from displayed local number\n setLocalNumber(\n international.replace(\n `+${getCountryCallingCode(country.value as CountryCode)} `,\n \"\",\n ),\n );\n }\n }\n\n return (\n <div className=\"xendit-input-phone\">\n <Dropdown\n options={COUNTRIES_WITH_DIAL_CODES_AS_DROPDOWN_OPTIONS}\n selectedIndex={countryCodeIndex}\n onChange={handleCountryChange}\n />\n <input\n id={id}\n ref={inputRef}\n type=\"tel\"\n inputMode=\"tel\"\n placeholder={getExampleLocalNumber()}\n className=\"xendit-text-14 xendit-phone-number-input\"\n onBlur={handleBlur}\n onChange={handleLocalChange}\n value={localNumber}\n autoComplete=\"tel\"\n />\n <input type=\"hidden\" name={name} ref={hiddenFieldRef} />\n </div>\n );\n};\n\ntype DropdownOptionWithDial = DropdownOption & { dial: string };\nconst COUNTRIES_WITH_DIAL_CODES_AS_DROPDOWN_OPTIONS =\n COUNTRIES_AS_DROPDOWN_OPTIONS.map<DropdownOptionWithDial | null>(\n (country) => {\n const dial = getCountryCallingCode(country.value as CountryCode);\n if (!dial) return null;\n return {\n ...country,\n shortTitle: `+${dial}`,\n title: `${country.title} (+${dial})`,\n dial,\n };\n },\n ).filter((country): country is DropdownOptionWithDial => {\n return Boolean(country);\n });\n\nconst sanitizePhoneNumber = (\n country: DropdownOptionWithDial,\n phoneNumber: string,\n): PhoneNumber | null => {\n const parsed = parsePhoneNumberFromString(\n phoneNumber,\n country.value as CountryCode,\n );\n if (parsed && parsed.isPossible()) return parsed;\n\n return null;\n};\n","type TitleValuePair = {\n title: string;\n value: string;\n};\n\nfunction toTitleValuePair(nameValue: {\n name: string;\n value: string;\n}): TitleValuePair {\n return {\n title: nameValue.name,\n value: nameValue.value,\n };\n}\n\n// https://gist.github.com/mshafrir/2646763\nexport const PROVINCES_US: TitleValuePair[] = [\n {\n name: \"Alabama\",\n value: \"AL\",\n },\n {\n name: \"Alaska\",\n value: \"AK\",\n },\n {\n name: \"American Samoa\",\n value: \"AS\",\n },\n {\n name: \"Arizona\",\n value: \"AZ\",\n },\n {\n name: \"Arkansas\",\n value: \"AR\",\n },\n {\n name: \"California\",\n value: \"CA\",\n },\n {\n name: \"Colorado\",\n value: \"CO\",\n },\n {\n name: \"Connecticut\",\n value: \"CT\",\n },\n {\n name: \"Delaware\",\n value: \"DE\",\n },\n {\n name: \"District Of Columbia\",\n value: \"DC\",\n },\n {\n name: \"Federated States Of Micronesia\",\n value: \"FM\",\n },\n {\n name: \"Florida\",\n value: \"FL\",\n },\n {\n name: \"Georgia\",\n value: \"GA\",\n },\n {\n name: \"Guam\",\n value: \"GU\",\n },\n {\n name: \"Hawaii\",\n value: \"HI\",\n },\n {\n name: \"Idaho\",\n value: \"ID\",\n },\n {\n name: \"Illinois\",\n value: \"IL\",\n },\n {\n name: \"Indiana\",\n value: \"IN\",\n },\n {\n name: \"Iowa\",\n value: \"IA\",\n },\n {\n name: \"Kansas\",\n value: \"KS\",\n },\n {\n name: \"Kentucky\",\n value: \"KY\",\n },\n {\n name: \"Louisiana\",\n value: \"LA\",\n },\n {\n name: \"Maine\",\n value: \"ME\",\n },\n {\n name: \"Marshall Islands\",\n value: \"MH\",\n },\n {\n name: \"Maryland\",\n value: \"MD\",\n },\n {\n name: \"Massachusetts\",\n value: \"MA\",\n },\n {\n name: \"Michigan\",\n value: \"MI\",\n },\n {\n name: \"Minnesota\",\n value: \"MN\",\n },\n {\n name: \"Mississippi\",\n value: \"MS\",\n },\n {\n name: \"Missouri\",\n value: \"MO\",\n },\n {\n name: \"Montana\",\n value: \"MT\",\n },\n {\n name: \"Nebraska\",\n value: \"NE\",\n },\n {\n name: \"Nevada\",\n value: \"NV\",\n },\n {\n name: \"New Hampshire\",\n value: \"NH\",\n },\n {\n name: \"New Jersey\",\n value: \"NJ\",\n },\n {\n name: \"New Mexico\",\n value: \"NM\",\n },\n {\n name: \"New York\",\n value: \"NY\",\n },\n {\n name: \"North Carolina\",\n value: \"NC\",\n },\n {\n name: \"North Dakota\",\n value: \"ND\",\n },\n {\n name: \"Northern Mariana Islands\",\n value: \"MP\",\n },\n {\n name: \"Ohio\",\n value: \"OH\",\n },\n {\n name: \"Oklahoma\",\n value: \"OK\",\n },\n {\n name: \"Oregon\",\n value: \"OR\",\n },\n {\n name: \"Palau\",\n value: \"PW\",\n },\n {\n name: \"Pennsylvania\",\n value: \"PA\",\n },\n {\n name: \"Puerto Rico\",\n value: \"PR\",\n },\n {\n name: \"Rhode Island\",\n value: \"RI\",\n },\n {\n name: \"South Carolina\",\n value: \"SC\",\n },\n {\n name: \"South Dakota\",\n value: \"SD\",\n },\n {\n name: \"Tennessee\",\n value: \"TN\",\n },\n {\n name: \"Texas\",\n value: \"TX\",\n },\n {\n name: \"Utah\",\n value: \"UT\",\n },\n {\n name: \"Vermont\",\n value: \"VT\",\n },\n {\n name: \"Virgin Islands\",\n value: \"VI\",\n },\n {\n name: \"Virginia\",\n value: \"VA\",\n },\n {\n name: \"Washington\",\n value: \"WA\",\n },\n {\n name: \"West Virginia\",\n value: \"WV\",\n },\n {\n name: \"Wisconsin\",\n value: \"WI\",\n },\n {\n name: \"Wyoming\",\n value: \"WY\",\n },\n].map(toTitleValuePair);\n\n// https://gist.github.com/pbojinov/a87adf559d2f7e81d86ae67e7bd883c7\nexport const PROVINCES_CA: TitleValuePair[] = [\n {\n name: \"Alberta\",\n value: \"AB\",\n },\n {\n name: \"British Columbia\",\n value: \"BC\",\n },\n {\n name: \"Manitoba\",\n value: \"MB\",\n },\n {\n name: \"New Brunswick\",\n value: \"NB\",\n },\n {\n name: \"Newfoundland and Labrador\",\n value: \"NL\",\n },\n {\n name: \"Northwest Territories\",\n value: \"NT\",\n },\n {\n name: \"Nova Scotia\",\n value: \"NS\",\n },\n {\n name: \"Nunavut\",\n value: \"NU\",\n },\n {\n name: \"Ontario\",\n value: \"ON\",\n },\n {\n name: \"Prince Edward Island\",\n value: \"PE\",\n },\n {\n name: \"Quebec\",\n value: \"QC\",\n },\n {\n name: \"Saskatchewan\",\n value: \"SK\",\n },\n {\n name: \"Yukon Territory\",\n value: \"YT\",\n },\n].map(toTitleValuePair);\n\nexport const PROVINCES_GB: TitleValuePair[] = [\n { name: \"Avon\" },\n { name: \"Bedfordshire\" },\n { name: \"Berkshire\" },\n { name: \"Buckinghamshire\" },\n { name: \"Cambridgeshire\" },\n { name: \"Cheshire\" },\n { name: \"Cleveland\" },\n { name: \"Cornwall\" },\n { name: \"Cumbria\" },\n { name: \"Derbyshire\" },\n { name: \"Devon\" },\n { name: \"Dorset\" },\n { name: \"Durham\" },\n { name: \"East Sussex\" },\n { name: \"Essex\" },\n { name: \"Gloucestershire\" },\n { name: \"Hampshire\" },\n { name: \"Herefordshire\" },\n { name: \"Hertfordshire\" },\n { name: \"Isle of Wight\" },\n { name: \"Kent\" },\n { name: \"Lancashire\" },\n { name: \"Leicestershire\" },\n { name: \"Lincolnshire\" },\n { name: \"London\" },\n { name: \"Merseyside\" },\n { name: \"Norfolk\" },\n { name: \"Northamptonshire\" },\n { name: \"Northumberland\" },\n { name: \"North Yorkshire\" },\n { name: \"Nottinghamshire\" },\n { name: \"Oxfordshire\" },\n { name: \"Rutland\" },\n { name: \"Shropshire\" },\n { name: \"Somerset\" },\n { name: \"South Yorkshire\" },\n { name: \"Staffordshire\" },\n { name: \"Suffolk\" },\n { name: \"Surrey\" },\n { name: \"Tyne and Wear\" },\n { name: \"Warwickshire\" },\n { name: \"West Midlands\" },\n { name: \"West Sussex\" },\n { name: \"West Yorkshire\" },\n { name: \"Wiltshire\" },\n { name: \"Worcestershire\" },\n { name: \"Clwyd\" },\n { name: \"Dyfed\" },\n { name: \"Gwent\" },\n { name: \"Gwynedd\" },\n { name: \"Mid Glamorgan\" },\n { name: \"Powys\" },\n { name: \"South Glamorgan\" },\n { name: \"West Glamorgan\" },\n { name: \"Aberdeenshire\" },\n { name: \"Angus\" },\n { name: \"Argyll\" },\n { name: \"Ayrshire\" },\n { name: \"Banffshire\" },\n { name: \"Berwickshire\" },\n { name: \"Bute\" },\n { name: \"Caithness\" },\n { name: \"Clackmannanshire\" },\n { name: \"Dumfriesshire\" },\n { name: \"Dunbartonshire\" },\n { name: \"East Lothian\" },\n { name: \"Fife\" },\n { name: \"Inverness-shire\" },\n { name: \"Kincardineshire\" },\n { name: \"Kinross-shire\" },\n { name: \"Kirkcudbrightshire\" },\n { name: \"Lanarkshire\" },\n { name: \"Midlothian\" },\n { name: \"Moray\" },\n { name: \"Nairnshire\" },\n { name: \"Orkney\" },\n { name: \"Peeblesshire\" },\n { name: \"Perthshire\" },\n { name: \"Renfrewshire\" },\n { name: \"Ross-shire\" },\n { name: \"Roxburghshire\" },\n { name: \"Selkirkshire\" },\n { name: \"Shetland\" },\n { name: \"Stirlingshire\" },\n { name: \"Sutherland\" },\n { name: \"West Lothian\" },\n { name: \"Wigtownshire\" },\n { name: \"Antrim\" },\n { name: \"Armagh\" },\n { name: \"Down\" },\n { name: \"Fermanagh\" },\n { name: \"Londonderry\" },\n { name: \"Tyrone\" },\n].map((province) => ({ title: province.name, value: province.name }));\n","import { useRef, useCallback, useLayoutEffect } from \"preact/hooks\";\nimport { FieldProps } from \"./field\";\nimport { CountryCode } from \"libphonenumber-js\";\nimport { Dropdown, DropdownOption } from \"./dropdown\";\nimport { useSession } from \"./session-provider\";\nimport { PROVINCES_CA, PROVINCES_GB, PROVINCES_US } from \"../data/provinces\";\nimport {\n formFieldId,\n formFieldName,\n getValueFromChannelProperty,\n objectId,\n usePrevious,\n} from \"../utils\";\nimport { useChannel } from \"./payment-channel\";\nimport { useChannelProperties } from \"./channel-form\";\nimport { ChannelFormField, ChannelProperties } from \"../backend-types/channel\";\nimport { BffSession } from \"../backend-types/session\";\nimport { FunctionComponent, TargetedEvent } from \"preact\";\nimport { InternalSetFieldTouchedEvent } from \"../private-event-types\";\n\nexport const ProvinceField: FunctionComponent<FieldProps> = (props) => {\n const { field, onChange } = props;\n const id = formFieldId(field);\n const name = formFieldName(field);\n\n const session = useSession();\n const allFields = useChannel()?.form;\n const channelProperties = useChannelProperties();\n\n const hiddenFieldRef = useRef<HTMLInputElement>(null);\n\n const clearValue = useCallback(() => {\n if (hiddenFieldRef.current) {\n hiddenFieldRef.current.value = \"\";\n }\n onChange();\n }, [onChange]);\n\n const onChangeDropdown = useCallback(\n (option: DropdownOption) => {\n if (hiddenFieldRef.current) {\n hiddenFieldRef.current.value = option.value;\n }\n onChange();\n hiddenFieldRef.current?.dispatchEvent(new InternalSetFieldTouchedEvent());\n },\n [onChange],\n );\n\n const onChangeInput = useCallback(\n (e: TargetedEvent<HTMLInputElement>) => {\n if (hiddenFieldRef.current) {\n hiddenFieldRef.current.value = (e.target as HTMLInputElement).value;\n }\n onChange();\n hiddenFieldRef.current?.dispatchEvent(new InternalSetFieldTouchedEvent());\n },\n [onChange],\n );\n\n // get the list of provinces for the chosen country\n const options = getProvinceList(\n getBestCountryForProvinceField(\n field,\n allFields ?? [],\n channelProperties ?? {},\n session,\n ),\n );\n\n // if the option list changes, clear the selection\n const previousOptions = usePrevious(options);\n useLayoutEffect(() => {\n if (previousOptions !== options) {\n clearValue();\n }\n }, [clearValue, options, previousOptions]);\n\n return (\n <>\n <input type=\"hidden\" name={name} defaultValue=\"\" ref={hiddenFieldRef} />\n {options ? (\n <Dropdown\n key={objectId(options)}\n id={id}\n options={options}\n onChange={onChangeDropdown}\n placeholder={field.placeholder}\n />\n ) : (\n <input\n type=\"text\"\n id={id}\n onChange={onChangeInput}\n placeholder={field.placeholder}\n className={`xendit-input xendit-text-14`}\n />\n )}\n </>\n );\n};\n\nfunction getProvinceList(country: CountryCode | null) {\n switch (country) {\n case \"US\":\n return PROVINCES_US;\n case \"CA\":\n return PROVINCES_CA;\n case \"GB\":\n return PROVINCES_GB;\n default:\n return null;\n }\n}\n\nfunction getBestCountryForProvinceField(\n thisField: ChannelFormField,\n allFields: ChannelFormField[],\n channelProperties: ChannelProperties,\n session: BffSession,\n): CountryCode {\n // country selection priority:\n // 1. previous form field\n // 3. session country\n if (allFields) {\n for (let i = 0; i < allFields.length; i++) {\n const otherField = allFields[i];\n if (i > 0 && otherField === thisField) {\n const previousField = allFields[i - 1];\n if (previousField.type.name === \"country\") {\n const country = getValueFromChannelProperty(\n previousField.channel_property,\n channelProperties,\n );\n if (country && typeof country === \"string\") {\n return country as CountryCode;\n }\n }\n }\n }\n }\n return session.country as CountryCode;\n}\n","import { ChannelFormField } from \"../backend-types/channel\";\nimport { FieldProps } from \"./field\";\nimport { formFieldId, formFieldName } from \"../utils\";\nimport { useRef } from \"preact/hooks\";\nimport { FunctionComponent, TargetedEvent, TargetedFocusEvent } from \"preact\";\nimport { InternalSetFieldTouchedEvent } from \"../private-event-types\";\n\nexport const TextField: FunctionComponent<FieldProps> = (props) => {\n const { field, onChange } = props;\n const id = formFieldId(field);\n const name = formFieldName(field);\n const inputRef = useRef<HTMLInputElement>(null);\n\n function handleChange(event: TargetedEvent<HTMLInputElement>): void {\n onChange();\n }\n\n function handleBlur(event: TargetedFocusEvent<HTMLInputElement>): void {\n if (event.currentTarget?.value) {\n inputRef.current?.dispatchEvent(new InternalSetFieldTouchedEvent());\n }\n }\n\n return (\n <input\n id={id}\n name={name}\n ref={inputRef}\n type=\"text\"\n placeholder={field.placeholder}\n className={`xendit-text-14`}\n onBlur={handleBlur}\n onChange={handleChange}\n minLength={isTextField(field) ? field.type.min_length : undefined}\n maxLength={isTextField(field) ? field.type.max_length : undefined}\n autoComplete={isTextField(field) ? field.type.autocomplete : undefined}\n />\n );\n};\n\nfunction isTextField(field: ChannelFormField): field is ChannelFormField & {\n type: { name: \"text\" };\n} {\n return field.type.name === \"text\";\n}\n","// affects number formatting (thousands separator, decimal separator)\n// defaults to \",\" for thousands and \".\" for decimal\nexport const CURRENCY_NUMBER_FORMAT_LOCALE: Record<string, string> = {\n IDR: \"id\",\n VND: \"vi\",\n BRL: \"pt-BR\",\n RUB: \"ru\",\n CZK: \"cs\",\n RON: \"ro\",\n UAH: \"uk\",\n CLP: \"es-CL\",\n COP: \"es-CO\",\n UYU: \"es-UY\",\n ARS: \"es-AR\",\n INR: \"hi-IN\",\n NPR: \"hi-IN\",\n LKR: \"hi-IN\",\n BDT: \"hi-IN\",\n};\n\n// Heavily modified from https://gist.github.com/ksafranski/2973986\n// checked against https://documentation.infiniteblue.com/platform/Currency_formats.htm\nexport const CURRENCY_SYMBOLS: Record<string, string> = {\n USD: \"US$\",\n CAD: \"CA$\",\n EUR: \"€\",\n AFN: \"؋\",\n ALL: \"Lek\",\n AMD: \"֏\",\n ARS: \"AR$\",\n AUD: \"AU$\",\n AZN: \"₼\",\n BAM: \"KM\",\n BDT: \"৳\",\n BIF: \"FBu\",\n BND: \"BN$\",\n BOB: \"Bs\",\n BRL: \"R$\",\n BWP: \"P\",\n BYN: \"Br\",\n BZD: \"BZ$\",\n CDF: \"FrCD\",\n CHF: \"CHF\",\n CLP: \"CL$\",\n CNY: \"CN¥\",\n COP: \"CO$\",\n CRC: \"₡\",\n CVE: \"CV$\",\n CZK: \"Kč\",\n DJF: \"Fdj\",\n DKK: \"kr\",\n DOP: \"RD$\",\n ERN: \"Nfk\",\n ETB: \"Br\",\n GBP: \"£\",\n GEL: \"₾\",\n GHS: \"GH₵\",\n GNF: \"FG\",\n GTQ: \"Q\",\n HKD: \"HK$\",\n HNL: \"L\",\n HUF: \"Ft\",\n IDR: \"Rp\",\n ILS: \"₪\",\n INR: \"₹\",\n IRR: \"IRR\",\n ISK: \"kr\",\n JMD: \"J$\",\n JPY: \"¥\",\n KES: \"Ksh\",\n KHR: \"៛\",\n KMF: \"FC\",\n KRW: \"₩\",\n KZT: \"₸\",\n LKR: \"SL Re\",\n MDL: \"lei\",\n MGA: \"MGA\",\n MKD: \"MKD\",\n MMK: \"K\",\n MOP: \"MOP$\",\n MUR: \"₨\",\n MXN: \"MX$\",\n MYR: \"RM\",\n MZN: \"MTn\",\n NAD: \"N$\",\n NGN: \"₦\",\n NIO: \"C$\",\n NOK: \"kr\",\n NPR: \"रु\",\n NZD: \"NZ$\",\n PAB: \"B/.\",\n PEN: \"S/.\",\n PHP: \"₱\",\n PKR: \"₨\",\n PLN: \"zł\",\n PYG: \"₲\",\n RON: \"RON\",\n RSD: \"RSD\",\n RUB: \"₽\",\n RWF: \"FR\",\n SDG: \"SDG\",\n SEK: \"kr\",\n SGD: \"S$\",\n SOS: \"Ssh\",\n THB: \"฿\",\n TOP: \"T$\",\n TRY: \"TL\",\n TTD: \"TT$\",\n TWD: \"NT$\",\n TZS: \"TSh\",\n UAH: \"₴\",\n UGX: \"USh\",\n UYU: \"$U\",\n UZS: \"сум\",\n VND: \"₫\",\n XAF: \"FCFA\",\n XOF: \"CFA\",\n ZAR: \"R\",\n ZMW: \"K\",\n ZWL: \"ZWL$\",\n};\n\n// $ is replaced with the currency symbol, 1 is replaced with the amount\n// default \"$1\"\nexport const CURRENCY_SYMBOL_POSITION: Record<string, string> = {\n ALL: \"1 $\",\n BAM: \"1 $\",\n BYN: \"1 $\",\n CZK: \"1 $\",\n DKK: \"1 $\",\n GEL: \"1 $\",\n HUF: \"1 $\",\n ISK: \"1 $\",\n IRR: \"1 $\",\n KHR: \"1$\",\n MDL: \"1 $\",\n MKD: \"1 $\",\n NOK: \"1 $\",\n PLN: \"1 $\",\n RON: \"1 $\",\n RSD: \"1 $\",\n RUB: \"1$\",\n SEK: \"1 $\",\n UZS: \"1 $\",\n VND: \"1$\",\n};\n\n// only list currencies that have more than 2 decimals\nexport const CURRENCY_SYMBOL_DECIMALS: Record<string, number> = {\n BHD: 3,\n JOD: 3,\n KWD: 3,\n LYD: 3,\n OMR: 3,\n TND: 3,\n};\n","import {\n CURRENCY_NUMBER_FORMAT_LOCALE,\n CURRENCY_SYMBOL_DECIMALS,\n CURRENCY_SYMBOL_POSITION,\n CURRENCY_SYMBOLS,\n} from \"./data/currencies\";\n\nexport function amountFormat(amount: number, currency: string): string {\n let str = \"\";\n\n const isNegative = amount < 0;\n\n // format as number with separators and 2 decimal places\n const locale = CURRENCY_NUMBER_FORMAT_LOCALE[currency] ?? \"en\";\n const decimals = CURRENCY_SYMBOL_DECIMALS[currency] ?? 2;\n\n str = new Intl.NumberFormat(locale, {\n style: \"decimal\",\n minimumFractionDigits: decimals,\n // Preserve fractional parts, if there are fractions where there shouldn't be that's\n // a backend problem and we should not suppress it.\n maximumFractionDigits: 20,\n }).format(Math.abs(amount));\n\n // remove trailing .00 or ,00 or .000 or ,000\n str = str.replace(/(\\.|,)000?$/, \"\");\n\n // add currency symbol\n if (CURRENCY_SYMBOLS[currency]) {\n const symbol = CURRENCY_SYMBOLS[currency] ?? currency;\n const positioning = CURRENCY_SYMBOL_POSITION[currency] ?? \"$1\";\n str = positioning.replace(\"$\", symbol).replace(\"1\", str);\n } else {\n str = currency + \" \" + str;\n }\n\n // add negative sign if needed\n if (isNegative) {\n str = \"-\" + str;\n }\n\n return str;\n}\n","import { FieldProps } from \"./field\";\nimport {\n assert,\n formFieldId,\n formFieldName,\n formHasFieldOfType,\n usePrevious,\n} from \"../utils\";\nimport {\n useCallback,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from \"preact/hooks\";\nimport { FunctionComponent } from \"preact\";\nimport { Dropdown, DropdownOption, DropdownSkeleton } from \"./dropdown\";\nimport { useChannel, useChannelComponentData } from \"./payment-channel\";\nimport { amountFormat } from \"../amount-format\";\nimport { useSdk, useSession } from \"./session-provider\";\nimport { InternalSetFieldTouchedEvent } from \"../private-event-types\";\nimport { BffInstallmentPlan } from \"../backend-types/payment-options\";\n\nexport const FieldInstallmentPlan: FunctionComponent<FieldProps> = (props) => {\n const { field, onChange } = props;\n\n const { t } = useSdk();\n const session = useSession();\n\n const id = formFieldId(field);\n const name = formFieldName(field);\n const hiddenFieldRef = useRef<HTMLInputElement>(null);\n\n const channel = useChannel();\n assert(channel);\n const hasCardsField = useMemo(() => {\n return formHasFieldOfType(channel.form, \"credit_card_number\");\n }, [channel.form]);\n\n const paymentOptions = useChannelComponentData()?.paymentOptions;\n const installmentPlans = paymentOptions?.options?.installment_plans;\n\n const [selectedItemKey, setSelectedItemKey] = useState<string | null>(null);\n\n const dropdownItems = useMemo(() => {\n const arr =\n installmentPlans?.map<DropdownOption>((plan) => ({\n title: t(`installment_plan.pay_in_installments`, {\n installments: plan.terms,\n amount: amountFormat(plan.installment_amount, session.currency),\n }),\n subtitle: plan.interest_rate,\n value: planKey(plan),\n })) ?? [];\n\n if (hasCardsField) {\n // the option to pay in full is shown if there is a card number field, because card payments need a way to opt out of installments.\n arr.unshift({\n title: t(`installment_plan.pay_in_full`, {\n amount: amountFormat(session.amount, session.currency),\n }),\n value: \"\",\n });\n }\n\n return arr;\n }, [hasCardsField, installmentPlans, session.amount, session.currency, t]);\n\n let selectedItemIndex = dropdownItems?.findIndex((item) => {\n return item.value === selectedItemKey;\n });\n if (selectedItemIndex === -1) {\n selectedItemIndex = 0;\n }\n\n const clearSelectedItem = useCallback(() => {\n setSelectedItemKey(null);\n if (hiddenFieldRef.current) {\n hiddenFieldRef.current.value = \"\";\n }\n }, []);\n\n const handleChange = useCallback(\n (option: DropdownOption) => {\n if (hiddenFieldRef.current) {\n const newPlan = installmentPlans?.find(\n (plan) => planKey(plan) === option.value,\n );\n if (newPlan) {\n if (newPlan.code) {\n // with plan code\n hiddenFieldRef.current.value = JSON.stringify([\n newPlan.terms,\n newPlan.interval,\n newPlan.code,\n ]);\n } else {\n // without plan code\n hiddenFieldRef.current.value = JSON.stringify([\n newPlan.terms,\n newPlan.interval,\n ]);\n }\n } else {\n hiddenFieldRef.current.value = \"\";\n }\n hiddenFieldRef.current?.dispatchEvent(\n new InternalSetFieldTouchedEvent(),\n );\n }\n setSelectedItemKey(option.value);\n onChange();\n },\n [installmentPlans, onChange],\n );\n\n useLayoutEffect(() => {\n // first render only, force select first option\n if (dropdownItems.length) handleChange(dropdownItems[0]);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const prevItems = usePrevious(dropdownItems);\n useLayoutEffect(() => {\n // if options change, and the selected code no longer exists, clear the field\n if (\n dropdownItems !== prevItems &&\n !installmentPlans?.some((plan) => planKey(plan) === selectedItemKey)\n ) {\n if (dropdownItems.length) {\n handleChange(dropdownItems[0]);\n } else {\n clearSelectedItem();\n }\n }\n }, [\n clearSelectedItem,\n dropdownItems,\n handleChange,\n installmentPlans,\n prevItems,\n selectedItemKey,\n ]);\n\n return (\n <>\n {paymentOptions ? (\n <Dropdown\n id={id}\n placeholder={field.placeholder}\n className={`xendit-text-14`}\n onChange={handleChange}\n options={dropdownItems}\n selectedIndex={selectedItemIndex}\n />\n ) : (\n <DropdownSkeleton id={id} />\n )}\n <input type=\"hidden\" name={name} ref={hiddenFieldRef} />\n </>\n );\n};\n\nfunction planKey(plan: BffInstallmentPlan) {\n return `${plan.terms}_${plan.interval}_${plan.code ?? \"\"}`;\n}\n","import { FunctionComponent } from \"preact\";\nimport { ChannelFormField } from \"../backend-types/channel\";\nimport { CountryField } from \"./field-country\";\nimport { DropdownField } from \"./field-dropdown\";\nimport { IframeField } from \"./field-iframe\";\nimport { PhoneNumberField } from \"./field-phone-number\";\nimport { ProvinceField } from \"./field-province\";\nimport { TextField } from \"./field-text\";\nimport { FieldInstallmentPlan } from \"./field-installment-plan\";\n\nexport interface FieldProps {\n field: ChannelFormField;\n onChange: () => void;\n className?: string;\n}\n\nconst Field: FunctionComponent<FieldProps> = (props) => {\n const { field, className } = props;\n\n function renderInner() {\n switch (field.type.name) {\n case \"credit_card_number\":\n case \"credit_card_expiry\":\n case \"credit_card_cvn\":\n return <IframeField {...props} />;\n case \"phone_number\":\n return <PhoneNumberField {...props} />;\n case \"text\":\n case \"email\":\n case \"postal_code\":\n return <TextField {...props} />;\n case \"dropdown\":\n return <DropdownField {...props} />;\n case \"installment_plan\":\n return <FieldInstallmentPlan {...props} />;\n case \"country\":\n return <CountryField {...props} />;\n case \"province\":\n return <ProvinceField {...props} />;\n }\n\n field.type satisfies never;\n throw new Error(\n `Unsupported field type: ${(field as ChannelFormField).type.name}`,\n );\n }\n\n return (\n <div\n className={`${className} xendit-channel-form-field xendit-form-field-span-${field.span}`}\n >\n {renderInner()}\n </div>\n );\n};\n\nexport default Field;\n","import { ChannelFormField } from \"./backend-types/channel\";\nimport en from \"./locale/en.json\";\nimport id from \"./locale/id.json\";\nimport th from \"./locale/th.json\";\nimport vi from \"./locale/vi.json\";\n\nconst localeMap: {\n en: typeof en.session;\n [locale: string]: Partial<typeof en.session>;\n} = {\n en: en.session,\n id: id.session,\n th: th.session,\n vi: vi.session,\n};\n\ntype InterpolationOptions = Record<string, string | number>;\n\n/**\n * Localization interface.\n *\n * ```\n * t(\"key\") -> Localize \"key\", falling back to \"key\"\n * t(\"key\", \"fallback\") -> Localize \"key\", falling back to \"fallback\"\n * t(\"key\", { var: value }) -> Localize \"key\" with interpolation, falling back to \"key\"\n * t(\"key\", \"fallback\", { var: value }) -> Localize \"key\" with interpolation, falling back to \"fallback\"\n * ```\n */\nexport interface TFunction {\n (key: keyof typeof en.session): string;\n (key: keyof typeof en.session, fallback: string): string;\n (key: keyof typeof en.session, options: InterpolationOptions): string;\n (\n key: keyof typeof en.session,\n fallback: string,\n options: InterpolationOptions,\n ): string;\n}\n\n/**\n * Generate a TFunction for a locale.\n */\nexport function createTFunction(locale: string): TFunction {\n const localeData = localeMap[locale];\n const tFn: TFunction = function (...args: unknown[]) {\n let key: keyof typeof en.session;\n let fallback: string | undefined;\n let options: InterpolationOptions = {};\n\n switch (args.length) {\n case 1:\n key = args[0] as keyof typeof en.session;\n break;\n case 2:\n if (typeof args[1] === \"string\") {\n key = args[0] as keyof typeof en.session;\n fallback = args[1];\n } else {\n key = args[0] as keyof typeof en.session;\n options = args[1] as InterpolationOptions;\n }\n break;\n case 3:\n key = args[0] as keyof typeof en.session;\n fallback = args[1] as string;\n options = args[2] as InterpolationOptions;\n break;\n default:\n throw new Error(\"Invalid arguments for t function\");\n }\n\n let template = localeData?.[key];\n if (template === undefined && fallback !== undefined) {\n template = fallback;\n }\n\n if (template) {\n return template.replace(/\\{\\{(\\w+)\\}\\}/g, (_, varName: string) => {\n return options[varName] ? String(options[varName]) : \"\";\n });\n } else {\n console.warn(`Missing localization for key: ${key} in locale: ${locale}`);\n return key;\n }\n };\n return tFn;\n}\n\n// An encapsulated localizable string\nexport type LocaleKey = {\n localeKey: keyof typeof en.session;\n};\n\n// An encapsulated already-localized string\nexport type LocalizedString = {\n value: string;\n};\n\n// Type guard function to check if errorCode is LocaleKey\nexport const isLocaleKey = (errorCode: unknown): errorCode is LocaleKey => {\n return (\n typeof errorCode === \"object\" &&\n errorCode !== null &&\n \"localeKey\" in errorCode\n );\n};\n\n// Get localized error message\nexport const getLocalizedErrorMessage = (\n t: TFunction,\n errorCode: LocaleKey | LocalizedString,\n field: ChannelFormField,\n): string | null => {\n if (!errorCode) return null;\n\n if (!isLocaleKey(errorCode)) {\n return errorCode.value;\n }\n\n // Get localized message with field name interpolation using i18n key directly\n return t(errorCode.localeKey, { field: field.label });\n};\n","import {\n BffChannel,\n ChannelFormField,\n ChannelProperties,\n ChannelPropertyPrimative,\n} from \"./backend-types/channel\";\nimport parsePhoneNumberFromString from \"libphonenumber-js/min\";\nimport { filterFormFields } from \"./components/channel-form\";\nimport { BffSessionType } from \"./backend-types/session\";\nimport { LocaleKey, LocalizedString } from \"./localization\";\nimport { ChannelComponentData } from \"./public-sdk\";\nimport { parseEncryptedFieldValue } from \"./utils\";\n\nexport type ValidationResult = {\n errorCode: LocaleKey | LocalizedString | undefined;\n};\n\nexport function validateEncryptedCardField(\n value: string,\n): LocaleKey | undefined {\n const parsed = parseEncryptedFieldValue(value);\n if (parsed.valid) {\n return undefined;\n }\n if (parsed.validationError) {\n return { localeKey: parsed.validationError as LocaleKey[\"localeKey\"] };\n }\n // unreachable\n throw new Error(\n \"Unexpected value in encrypted field, this is a bug, please contact support.\",\n );\n}\n\nexport const validateEmail = (value: string): LocaleKey | undefined => {\n // Allows letters, numbers, dots, underscores, hyphens before the @\n // Domain must be letters, numbers, hyphens (no leading/trailing hyphen)\n // TLD must be at least 2 letters\n const emailRegex =\n /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9-]+(\\.[a-zA-Z0-9-]+)*\\.[A-Za-z]{2,}$/;\n\n if (!emailRegex.test(value)) {\n return {\n localeKey: \"validation.generic_invalid\",\n };\n }\n};\n\nexport const validatePhoneNumber = (value: string): LocaleKey | undefined => {\n const phone = parsePhoneNumberFromString(value);\n if (!phone || !phone.isValid()) {\n return {\n localeKey: \"validation.generic_invalid\",\n };\n }\n};\n\nexport const validatePostalCode = (value: string): LocaleKey | undefined => {\n // Basic validation: must contain only letters, numbers, spaces, or hyphens\n if (!/^(?![-\\s]+)[A-Za-z0-9\\s-]+$/.test(value)) {\n return {\n localeKey: \"validation.generic_invalid\",\n };\n }\n};\n\nexport const validateText = (\n input: ChannelFormField & {\n type: { name: \"text\" };\n },\n value: string,\n): LocaleKey | LocalizedString | undefined => {\n if (Array.isArray(input.type.regex_validators)) {\n for (const pattern of input.type.regex_validators) {\n const regex = new RegExp(sanitizeRegex(pattern.regex));\n if (!regex.test(value)) {\n return {\n value: pattern.message,\n };\n }\n }\n }\n\n if (\n input.type.min_length !== undefined &&\n value.length < input.type.min_length\n ) {\n return { localeKey: \"validation.text_too_short\" };\n } else if (value.length > input.type.max_length) {\n return { localeKey: \"validation.text_too_long\" };\n }\n};\n\nfunction sanitizeRegex(pattern: string): string {\n // Remove leading and trailing slashes if present\n if (pattern.startsWith(\"/\") && pattern.endsWith(\"/\")) {\n return pattern.slice(1, -1);\n }\n return pattern;\n}\n\nexport function validate(\n input: ChannelFormField,\n value: string,\n): LocaleKey | LocalizedString | undefined {\n if (value.length === 0) {\n if (input.required) {\n return { localeKey: \"validation.required\" };\n } else {\n // ok, empty string and not required\n return undefined;\n }\n }\n\n switch (input.type.name) {\n case \"credit_card_number\":\n case \"credit_card_expiry\":\n case \"credit_card_cvn\": {\n return validateEncryptedCardField(value);\n }\n case \"phone_number\":\n return validatePhoneNumber(value);\n case \"email\":\n return validateEmail(value);\n case \"postal_code\":\n return validatePostalCode(value);\n case \"text\": {\n return validateText(\n input as ChannelFormField & {\n type: { name: \"text\" };\n },\n value,\n );\n }\n case \"country\":\n case \"province\":\n case \"installment_plan\":\n case \"dropdown\": {\n // no validation required for now\n return undefined;\n }\n\n default: {\n input.type satisfies never;\n throw new Error(\n `Unsupported input type: ${(input as ChannelFormField).type.name}; this is a bug, please contact support.`,\n );\n }\n }\n}\n\nexport function channelPropertiesAreValid(\n sessionType: BffSessionType,\n channel: BffChannel,\n channelProperties: ChannelProperties | null,\n channelComponentData: ChannelComponentData | null,\n): boolean {\n if (!channelProperties) channelProperties = {};\n\n for (const field of filterFormFields(\n sessionType,\n channel.form,\n channelProperties,\n channelComponentData,\n )) {\n if (channelPropertyFieldValidate(field, channelProperties)) {\n return false;\n }\n }\n\n return true;\n}\n\n// Return a validation error message if the channel property is invalid\nexport function channelPropertyFieldValidate(\n field: ChannelFormField,\n channelProperties: ChannelProperties,\n) {\n const channelPropertyKeys = Array.isArray(field.channel_property)\n ? field.channel_property\n : [field.channel_property];\n for (const key of channelPropertyKeys) {\n let value = getChannelPropertyValue(channelProperties, key);\n if (value === undefined) {\n value = \"\";\n }\n if (typeof value !== \"string\") {\n // validation for non-string values not supported\n continue;\n }\n const error = validate(field, value);\n if (error) {\n return error;\n }\n }\n}\n\nexport function getChannelPropertyValue(\n channelProperties: ChannelProperties,\n key: string,\n): ChannelPropertyPrimative | ChannelPropertyPrimative[] | undefined {\n const parts = key.split(\".\");\n const value = channelProperties[parts[0]];\n if (value === undefined) {\n return undefined;\n }\n if (typeof value !== \"object\" || Array.isArray(value)) {\n if (parts.length !== 1) {\n throw new Error(\n `Attempted to read channel property \"${key}\" expecting an object but found a primitive value; this is a bug, please contact support.`,\n );\n }\n return value;\n } else {\n return getChannelPropertyValue(value, parts.slice(1).join(\".\"));\n }\n}\n","import { ComponentChildren, createContext, FunctionComponent } from \"preact\";\nimport { useContext, useLayoutEffect, useRef, useState } from \"preact/hooks\";\nimport { Scenarios } from \"../data/simulation-scenarios\";\nimport { Dropdown } from \"./dropdown\";\nimport { useSdk } from \"./session-provider\";\n\ninterface Props {\n scenarios: Scenarios;\n onSelect: (scenarioName: string) => void;\n children: ComponentChildren;\n}\n\nconst FormSimulationHelperContext = createContext<{\n open: boolean;\n setOpen: (open: boolean) => void;\n scenarios: Scenarios;\n onSelect: (scenarioName: string) => void;\n} | null>(null);\n\nexport const FormSimulationHelper: FunctionComponent<Props> = ({\n scenarios,\n onSelect,\n children,\n}) => {\n const [open, setOpen] = useState(false);\n const rootRef = useRef<HTMLDivElement>(null);\n\n useLayoutEffect(() => {\n if (!open) return;\n const onMouseDown = (e: MouseEvent) => {\n const root = rootRef.current;\n if (!root) return;\n if (!root.contains(e.target as Node)) setOpen(false);\n };\n document.addEventListener(\"mousedown\", onMouseDown);\n return () => document.removeEventListener(\"mousedown\", onMouseDown);\n }, [open]);\n\n return (\n <div ref={rootRef}>\n <FormSimulationHelperContext.Provider\n value={{ open, setOpen, scenarios, onSelect }}\n >\n {children}\n </FormSimulationHelperContext.Provider>\n </div>\n );\n};\n\nexport const FormSimulationRoot: FunctionComponent<{\n children: ComponentChildren;\n}> = ({ children }) => {\n return <div className=\"xendit-form-simulation-root\">{children}</div>;\n};\n\nexport const FormSimulationTrigger: FunctionComponent<{\n children: ComponentChildren;\n}> = ({ children }) => {\n const { open, setOpen } = useContext(FormSimulationHelperContext) || {};\n\n return (\n <button\n type=\"button\"\n className=\"xendit-form-simulation-trigger\"\n onClick={() => setOpen?.(!open)}\n >\n {children}\n </button>\n );\n};\n\nexport const FormSimulationHelperPopover: FunctionComponent = () => {\n const { open, setOpen, scenarios, onSelect } =\n useContext(FormSimulationHelperContext) || {};\n const { t } = useSdk();\n\n if (!open || !scenarios) {\n return null;\n }\n\n return (\n <div className=\"xendit-form-simulation-popover\">\n <div className=\"xendit-text-12 xendit-text-semibold\">\n {t(\"simulation.simulate_test_scenario\")}\n </div>\n <Dropdown\n onChange={(option) => {\n const selectedScenario = scenarios.scenarios.find(\n (scenario) => scenario.description === option.value,\n );\n if (selectedScenario) {\n onSelect?.(selectedScenario.name);\n setOpen?.(false);\n }\n }}\n placeholder={t(\"simulation.select_scenario\")}\n options={scenarios.scenarios.map((scenario) => ({\n title: scenario.description,\n value: scenario.description,\n leadingAsset: (\n <img\n src={scenario.imageUrl}\n className=\"xendit-form-simulation-scenario-icon\"\n />\n ),\n }))}\n />\n {scenarios?.docsLink ? (\n <div className=\"xendit-text-14\">\n {t(\"simulation.want_to_test_all_scenarios\")}{\" \"}\n <a\n href={scenarios.docsLink}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"xendit-text-link\"\n >\n {t(\"simulation.see_all_scenarios\")}\n </a>\n </div>\n ) : null}\n </div>\n );\n};\n","import { useState, useLayoutEffect, useRef, useContext } from \"preact/hooks\";\nimport { ChannelFormField, ChannelProperties } from \"../backend-types/channel\";\nimport Field from \"./field\";\nimport classNames from \"classnames\";\nimport { formFieldId, formFieldName } from \"../utils\";\nimport { useSdk } from \"./session-provider\";\nimport { getLocalizedErrorMessage } from \"../localization\";\nimport { channelPropertyFieldValidate } from \"../validation\";\nimport { InternalSetFieldTouchedEvent } from \"../private-event-types\";\nimport { Scenarios } from \"../data/simulation-scenarios\";\nimport {\n FormSimulationHelper,\n FormSimulationHelperPopover,\n FormSimulationRoot,\n FormSimulationTrigger,\n} from \"./form-simulation-helper\";\nimport {\n IframeRegistryContext,\n IframeRegistryProvider,\n} from \"./iframe-registry\";\nimport { FunctionComponent } from \"preact\";\n\nconst CSS_CLASSES = {\n BOTTOM_LEFT_0: \"field-radius-bl-0\",\n BOTTOM_RIGHT_0: \"field-radius-br-0\",\n TOP_LEFT_0: \"field-radius-tl-0\",\n TOP_RIGHT_0: \"field-radius-tr-0\",\n COLLAPSE_RIGHT: \"field-collapse-r\",\n COLLAPSE_LEFT: \"field-collapse-l\",\n COLLAPSE_TOP: \"field-collapse-t\",\n COLLAPSE_BOTTOM: \"field-collapse-b\",\n} as const;\n\ninterface Props {\n fieldGroup: ChannelFormField[];\n groupIndex: number;\n handleFieldChanged: () => void;\n channelProperties: ChannelProperties | null;\n simulationScenarios?: Scenarios | null;\n}\n\nconst FieldGroup = ({\n fieldGroup,\n groupIndex,\n handleFieldChanged,\n channelProperties,\n simulationScenarios,\n}: Props) => {\n const { t } = useSdk();\n\n const groupContainerRef = useRef<HTMLDivElement>(null);\n\n const [touchedFields, setTouchedFields] = useState<Record<string, boolean>>(\n {},\n );\n\n const fieldGroupSpans = fieldGroup.map((f) => f.span);\n const groupRowCount = Math.ceil(\n fieldGroup.reduce((agg, field) => agg + field.span, 0) / 2,\n );\n\n const calculateFieldPosition = (index: number) => {\n const fieldPositionBySpan = fieldGroupSpans\n .slice(0, index)\n .reduce((agg, span) => agg + span, 0);\n const fieldRow = index === 0 ? 0 : Math.floor(fieldPositionBySpan / 2);\n const fieldColumn = fieldPositionBySpan % 2;\n const isLastRow = fieldRow === groupRowCount - 1;\n\n return { fieldPositionBySpan, fieldRow, fieldColumn, isLastRow };\n };\n\n const getFieldClassNames = (\n field: ChannelFormField,\n index: number,\n position: ReturnType<typeof calculateFieldPosition>,\n ) => {\n const { fieldPositionBySpan, fieldRow, fieldColumn, isLastRow } = position;\n return classNames({\n [CSS_CLASSES.BOTTOM_LEFT_0]:\n groupRowCount > fieldRow + 1 || fieldPositionBySpan % 2 === 1,\n [CSS_CLASSES.BOTTOM_RIGHT_0]: !!fieldGroupSpans[index + 1],\n [CSS_CLASSES.TOP_LEFT_0]: index > 0,\n [CSS_CLASSES.TOP_RIGHT_0]:\n !(fieldRow === 0 && fieldColumn === 1) &&\n !(fieldRow === 0 && fieldColumn === 0 && field.span === 2),\n [CSS_CLASSES.COLLAPSE_RIGHT]: field.span === 1 && fieldColumn === 0,\n [CSS_CLASSES.COLLAPSE_LEFT]: field.span === 1 && fieldColumn === 1,\n [CSS_CLASSES.COLLAPSE_TOP]: fieldPositionBySpan >= 2,\n [CSS_CLASSES.COLLAPSE_BOTTOM]: !isLastRow,\n });\n };\n\n useLayoutEffect(() => {\n const containerElement = groupContainerRef.current;\n if (!containerElement) return;\n function listener(event: InternalSetFieldTouchedEvent) {\n // when a field is touched, add it to touched state\n const name = (event.target as HTMLInputElement).name;\n setTouchedFields((prev) => ({\n ...prev,\n [name]: true,\n }));\n }\n containerElement.addEventListener(\n InternalSetFieldTouchedEvent.type,\n listener,\n );\n return () => {\n containerElement.removeEventListener(\n InternalSetFieldTouchedEvent.type,\n listener,\n );\n };\n }, []);\n\n const renderError = () => {\n for (const field of fieldGroup) {\n if (!touchedFields[formFieldName(field)]) {\n // field not touched yet, skip validation\n // (this prevents showing validation errors too eagerly while the user is typing)\n continue;\n }\n\n const err = channelPropertyFieldValidate(field, channelProperties ?? {});\n if (!err) {\n // ok, no error\n continue;\n }\n\n // render first error and ignore the rest\n return (\n <span className=\"xendit-error-message xendit-text-12\">\n {getLocalizedErrorMessage(t, err, field)}\n </span>\n );\n }\n return null;\n };\n\n const error = renderError();\n\n return (\n <IframeRegistryProvider>\n <div className=\"xendit-channel-form-field-group\">\n <div className=\"xendit-channel-form-field-group-label-container\">\n <label\n htmlFor={formFieldId(fieldGroup[0])}\n className=\"xendit-text-14\"\n >\n {fieldGroup[0].group_label ?? fieldGroup[0].label ?? \"\"}\n </label>\n {simulationScenarios ? (\n <FormSimulationHelperWrapper\n simulationScenarios={simulationScenarios}\n fieldGroup={fieldGroup}\n />\n ) : null}\n </div>\n <div\n ref={groupContainerRef}\n key={groupIndex}\n className={`xendit-form-field-group ${error ? \"invalid\" : \"\"}`}\n >\n {fieldGroup.map((field, index) => {\n const position = calculateFieldPosition(index);\n const className = getFieldClassNames(field, index, position);\n\n return (\n <Field\n className={className}\n key={index}\n field={field}\n onChange={handleFieldChanged}\n />\n );\n })}\n </div>\n {error}\n </div>\n </IframeRegistryProvider>\n );\n};\n\nconst FormSimulationHelperWrapper: FunctionComponent<{\n simulationScenarios: Scenarios;\n fieldGroup: ChannelFormField[];\n}> = ({ simulationScenarios, fieldGroup }) => {\n const iframeRegistry = useContext(IframeRegistryContext);\n const { t } = useSdk();\n\n return (\n <FormSimulationHelper\n scenarios={simulationScenarios}\n onSelect={(scenarioName) => {\n const scenario = simulationScenarios.scenarios.find(\n (s) => s.name === scenarioName,\n );\n if (!scenario?.values) return;\n\n // when a scenario is selected, set the values of the scenario to the fields\n for (const [fieldName, value] of Object.entries(scenario.values)) {\n const field = fieldGroup.find((f) => formFieldName(f) === fieldName);\n if (field) {\n if (\n field.type.name === \"credit_card_number\" ||\n field.type.name === \"credit_card_expiry\" ||\n field.type.name === \"credit_card_cvn\"\n ) {\n iframeRegistry?.postMessageToIframe(fieldName, {\n type: \"xendit-iframe-populate-for-simulation\",\n scenario: value,\n });\n }\n\n // TODO handle non-iframe fields if needed\n }\n }\n }}\n >\n <FormSimulationRoot>\n <FormSimulationTrigger>\n <div className=\"xendit-text-12 xendit-text-semibold xendit-text-link\">\n {t(\"simulation.simulate_scenario\")}\n </div>\n </FormSimulationTrigger>\n <FormSimulationHelperPopover />\n </FormSimulationRoot>\n </FormSimulationHelper>\n );\n};\n\nexport default FieldGroup;\n","import { IframePopulateForSimulationEvent } from \"../../../shared/types\";\n\nexport type Scenarios = {\n scenarios: {\n name: string;\n imageUrl?: string;\n description: string;\n values?: {\n [key: string]: string | IframePopulateForSimulationEvent[\"type\"];\n };\n }[];\n docsLink?: string;\n};\n\nexport const CARDS_SCENARIOS: Scenarios = {\n scenarios: [\n {\n imageUrl: \"https://assets.xendit.co/payment-session/logos/VISA.svg\",\n description:\n \"3DS Challenge, authentication is successful if OTP is correct.\",\n name: \"3_ds_challenge_authentication_is_successful_if_otp_is_correct_visa\",\n values: {\n \"card_details.card_number\":\n \"3_ds_challenge_authentication_is_successful_if_otp_is_correct_visa\",\n \"card_details.expiry_month__card_details.expiry_year\":\n \"3_ds_challenge_authentication_is_successful_if_otp_is_correct_visa\",\n \"card_details.cvn\":\n \"3_ds_challenge_authentication_is_successful_if_otp_is_correct_visa\",\n },\n },\n {\n imageUrl: \"https://assets.xendit.co/payment-session/logos/VISA.svg\",\n description: \"3DS Frictionless, authentication is successful.\",\n name: \"3_ds_frictionless_authentication_is_successful_visa\",\n values: {\n \"card_details.card_number\":\n \"3_ds_frictionless_authentication_is_successful_visa\",\n \"card_details.expiry_month__card_details.expiry_year\":\n \"3_ds_frictionless_authentication_is_successful_visa\",\n \"card_details.cvn\":\n \"3_ds_frictionless_authentication_is_successful_visa\",\n },\n },\n {\n imageUrl: \"https://assets.xendit.co/payment-session/logos/MASTERCARD.svg\",\n description:\n \"3DS Challenge, authentication is successful if OTP is correct.\",\n name: \"3_ds_challenge_authentication_is_successful_if_otp_is_correct_mastercard\",\n values: {\n \"card_details.card_number\":\n \"3_ds_challenge_authentication_is_successful_if_otp_is_correct_mastercard\",\n \"card_details.expiry_month__card_details.expiry_year\":\n \"3_ds_challenge_authentication_is_successful_if_otp_is_correct_mastercard\",\n \"card_details.cvn\":\n \"3_ds_challenge_authentication_is_successful_if_otp_is_correct_mastercard\",\n },\n },\n {\n imageUrl: \"https://assets.xendit.co/payment-session/logos/MASTERCARD.svg\",\n description: \"3DS Frictionless, authentication is successful.\",\n name: \"3_ds_frictionless_authentication_is_successful_mastercard\",\n values: {\n \"card_details.card_number\":\n \"3_ds_frictionless_authentication_is_successful_mastercard\",\n \"card_details.expiry_month__card_details.expiry_year\":\n \"3_ds_frictionless_authentication_is_successful_mastercard\",\n \"card_details.cvn\":\n \"3_ds_frictionless_authentication_is_successful_mastercard\",\n },\n },\n {\n imageUrl: \"https://assets.xendit.co/payment-session/logos/VISA.svg\",\n description: \"3DS Challenge, with list of simulated options.\",\n name: \"3_ds_challenge_with_list_of_simulated_options_visa\",\n values: {\n \"card_details.card_number\":\n \"3_ds_challenge_with_list_of_simulated_options_visa\",\n \"card_details.expiry_month__card_details.expiry_year\":\n \"3_ds_challenge_with_list_of_simulated_options_visa\",\n \"card_details.cvn\":\n \"3_ds_challenge_with_list_of_simulated_options_visa\",\n },\n },\n {\n imageUrl: \"https://assets.xendit.co/payment-session/logos/VISA.svg\",\n description: \"3DS Frictionless, authentication is successful.\",\n name: \"3_ds_frictionless_authentication_is_successful_visa2\",\n values: {\n \"card_details.card_number\":\n \"3_ds_frictionless_authentication_is_successful_visa2\",\n \"card_details.expiry_month__card_details.expiry_year\":\n \"3_ds_frictionless_authentication_is_successful_visa2\",\n \"card_details.cvn\":\n \"3_ds_frictionless_authentication_is_successful_visa2\",\n },\n },\n {\n imageUrl: \"https://assets.xendit.co/payment-session/logos/MASTERCARD.svg\",\n description: \"3DS Challenge, with list of simulated options.\",\n name: \"3_ds_challenge_with_list_of_simulated_options_mastercard\",\n values: {\n \"card_details.card_number\":\n \"3_ds_challenge_with_list_of_simulated_options_mastercard\",\n \"card_details.expiry_month__card_details.expiry_year\":\n \"3_ds_challenge_with_list_of_simulated_options_mastercard\",\n \"card_details.cvn\":\n \"3_ds_challenge_with_list_of_simulated_options_mastercard\",\n },\n },\n {\n imageUrl: \"https://assets.xendit.co/payment-session/logos/MASTERCARD.svg\",\n description: \"3DS Frictionless, authentication is successful.\",\n name: \"3_ds_frictionless_authentication_is_successful_mastercard2\",\n values: {\n \"card_details.card_number\":\n \"3_ds_frictionless_authentication_is_successful_mastercard2\",\n \"card_details.expiry_month__card_details.expiry_year\":\n \"3_ds_frictionless_authentication_is_successful_mastercard2\",\n \"card_details.cvn\":\n \"3_ds_frictionless_authentication_is_successful_mastercard2\",\n },\n },\n {\n imageUrl: \"https://assets.xendit.co/payment-session/logos/VISA.svg\",\n description:\n \"3DS Challenge, authentication is successful if OTP is correct. For frictionless flow, use amount < THB 20.\",\n name: \"3_ds_challenge_authentication_is_successful_if_otp_is_correct_for_frictionless_flow_use_amount_thb_20_visa\",\n values: {\n \"card_details.card_number\":\n \"3_ds_challenge_authentication_is_successful_if_otp_is_correct_for_frictionless_flow_use_amount_thb_20_visa\",\n \"card_details.expiry_month__card_details.expiry_year\":\n \"3_ds_challenge_authentication_is_successful_if_otp_is_correct_for_frictionless_flow_use_amount_thb_20_visa\",\n \"card_details.cvn\":\n \"3_ds_challenge_authentication_is_successful_if_otp_is_correct_for_frictionless_flow_use_amount_thb_20_visa\",\n },\n },\n {\n imageUrl: \"https://assets.xendit.co/payment-session/logos/MASTERCARD.svg\",\n description:\n \"3DS Challenge, authentication is successful if OTP is correct. For frictionless flow, use amount < THB 20.\",\n name: \"3_ds_challenge_authentication_is_successful_if_otp_is_correct_for_frictionless_flow_use_amount_thb_20_mastercard\",\n values: {\n \"card_details.card_number\":\n \"3_ds_challenge_authentication_is_successful_if_otp_is_correct_for_frictionless_flow_use_amount_thb_20_mastercard\",\n \"card_details.expiry_month__card_details.expiry_year\":\n \"3_ds_challenge_authentication_is_successful_if_otp_is_correct_for_frictionless_flow_use_amount_thb_20_mastercard\",\n \"card_details.cvn\":\n \"3_ds_challenge_authentication_is_successful_if_otp_is_correct_for_frictionless_flow_use_amount_thb_20_mastercard\",\n },\n },\n {\n imageUrl: \"https://assets.xendit.co/payment-session/logos/VISA.svg\",\n description: \"Failing transaction\",\n name: \"failing_transaction_visa\",\n values: {\n \"card_details.card_number\": \"failing_transaction_visa\",\n \"card_details.expiry_month__card_details.expiry_year\":\n \"failing_transaction_visa\",\n \"card_details.cvn\": \"failing_transaction_visa\",\n },\n },\n {\n imageUrl: \"https://assets.xendit.co/payment-session/logos/MASTERCARD.svg\",\n description: \"Failing transaction\",\n name: \"failing_transaction_mastercard\",\n values: {\n \"card_details.card_number\": \"failing_transaction_mastercard\",\n \"card_details.expiry_month__card_details.expiry_year\":\n \"failing_transaction_mastercard\",\n \"card_details.cvn\": \"failing_transaction_mastercard\",\n },\n },\n {\n imageUrl: \"https://assets.xendit.co/payment-session/logos/AMEX.svg\",\n description:\n \"3DS Frictionless, authentication successful (use a 4 digit CVN)\",\n name: \"3_ds_frictionless_authentication_successful_use_a_4_digit_cvn\",\n values: {\n \"card_details.card_number\":\n \"3_ds_frictionless_authentication_successful_use_a_4_digit_cvn\",\n \"card_details.expiry_month__card_details.expiry_year\":\n \"3_ds_frictionless_authentication_successful_use_a_4_digit_cvn\",\n \"card_details.cvn\":\n \"3_ds_frictionless_authentication_successful_use_a_4_digit_cvn\",\n },\n },\n {\n imageUrl: \"https://assets.xendit.co/payment-session/logos/AMEX.svg\",\n description:\n \"3DS Frictionless, authentication successful (use a 4 digit CVN)\",\n name: \"3_ds_frictionless_authentication_successful_use_a_4_digit_cvn2\",\n values: {\n \"card_details.card_number\":\n \"3_ds_frictionless_authentication_successful_use_a_4_digit_cvn2\",\n \"card_details.expiry_month__card_details.expiry_year\":\n \"3_ds_frictionless_authentication_successful_use_a_4_digit_cvn2\",\n \"card_details.cvn\":\n \"3_ds_frictionless_authentication_successful_use_a_4_digit_cvn2\",\n },\n },\n {\n imageUrl: \"https://assets.xendit.co/payment-session/logos/AMEX.svg\",\n description: \"3DS Challenge (use a 4 digit CVN)\",\n name: \"3_ds_challenge_use_a_4_digit_cvn\",\n values: {\n \"card_details.card_number\": \"3_ds_challenge_use_a_4_digit_cvn\",\n \"card_details.expiry_month__card_details.expiry_year\":\n \"3_ds_challenge_use_a_4_digit_cvn\",\n \"card_details.cvn\": \"3_ds_challenge_use_a_4_digit_cvn\",\n },\n },\n ],\n docsLink: \"https://docs.xendit.co/docs/cards-simulate-card-scenarios\",\n};\n","import { ChannelFormField, ChannelProperties } from \"../backend-types/channel\";\nimport { BffSession, BffSessionType } from \"../backend-types/session\";\nimport {\n useCallback,\n useContext,\n useEffect,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n} from \"preact/hooks\";\nimport { useSdk, useSession } from \"./session-provider\";\nimport FieldGroup from \"./field-group\";\nimport { formHasFieldOfType, usePrevious } from \"../utils\";\nimport { createContext } from \"preact\";\nimport { forwardRef } from \"preact/compat\";\nimport { InternalSetFieldTouchedEvent } from \"../private-event-types\";\nimport { useChannel, useChannelComponentData } from \"./payment-channel\";\nimport { getChannelPropertyValue } from \"../validation\";\nimport { ChannelComponentData } from \"../public-sdk\";\nimport { internal } from \"../internal\";\nimport { CARDS_SCENARIOS, Scenarios } from \"../data/simulation-scenarios\";\n\ninterface Props {\n form: ChannelFormField[];\n onChannelPropertiesChanged: (channelProperties: ChannelProperties) => void;\n}\nexport interface ChannelFormHandle {\n setAllFieldsTouched: () => void;\n}\n\nconst ChannelForm = forwardRef<ChannelFormHandle, Props>(\n ({ form, onChannelPropertiesChanged }, ref) => {\n const session = useSession();\n const channel = useChannel();\n const sdk = useSdk();\n const channelComponentData = useChannelComponentData();\n const formRef = useRef<HTMLFormElement>(null);\n\n const [channelProperties, setChannelProperties] =\n useState<ChannelProperties | null>(null);\n\n useImperativeHandle(ref, () => ({\n setAllFieldsTouched() {\n const form = formRef.current;\n if (!form) return;\n Array.from(form.elements)\n .filter((el) => el instanceof HTMLInputElement)\n .forEach((input) => {\n if (!input.name) {\n // only mark named fields as touched\n return;\n }\n input.dispatchEvent(new InternalSetFieldTouchedEvent());\n });\n },\n }));\n\n const getChannelProperties = useCallback((): ChannelProperties => {\n if (!formRef.current) return {};\n\n // The browser FormData collides with node's FormData, both are global, so we\n // need to make up a type for\n const formData = new FormData(formRef.current) as unknown as {\n entries: () => IterableIterator<[string, string | Blob]>;\n };\n\n return formKvToChannelProperties(formData.entries());\n }, []);\n\n const handleFieldChanged = useCallback(() => {\n if (!formRef.current) return;\n const channelProperties = getChannelProperties();\n setChannelProperties(channelProperties);\n onChannelPropertiesChanged(channelProperties);\n }, [getChannelProperties, onChannelPropertiesChanged]);\n\n const filteredForm = useFilteredFormFields(\n session,\n form,\n channelProperties || {},\n channelComponentData ?? null,\n );\n\n // trigger a field changed callback when the form changes\n const previousFilteredForm = usePrevious(filteredForm);\n useEffect(() => {\n if (\n // only trigger if the form changed\n !formsAreEqual(previousFilteredForm || [], filteredForm)\n ) {\n handleFieldChanged();\n }\n }, [filteredForm, handleFieldChanged, previousFilteredForm]);\n\n const getSimulationScenarios = useCallback(\n (fieldGroup: ChannelFormField[]): Scenarios | null => {\n // only show simulation scenarios for prod-dev (test mode)\n if (sdk[internal].sdkKey.hostId !== \"pd\") {\n return null;\n }\n\n // only show simulation scenarios for cards channel and if the field group has a credit card number field\n if (\n channel?.channel_code === \"CARDS\" &&\n fieldGroup.some((field) => field.type.name === \"credit_card_number\")\n ) {\n return CARDS_SCENARIOS;\n }\n\n return null;\n },\n [channel, sdk],\n );\n\n const filteredFieldGroups = groupFields(filteredForm).filter(\n (group) => group.length,\n );\n\n if (filteredFieldGroups.length === 0) {\n return null;\n }\n\n return (\n <div class=\"xendit-channel-form\">\n <form ref={formRef}>\n <ChannelPropertiesContext.Provider value={channelProperties}>\n {filteredFieldGroups.map((fieldGroup, index) => (\n <FieldGroup\n key={index}\n fieldGroup={fieldGroup}\n groupIndex={index}\n handleFieldChanged={handleFieldChanged}\n channelProperties={channelProperties}\n simulationScenarios={getSimulationScenarios(fieldGroup)}\n />\n ))}\n </ChannelPropertiesContext.Provider>\n </form>\n </div>\n );\n },\n);\n\nexport const ChannelPropertiesContext = createContext<ChannelProperties | null>(\n null,\n);\n\nexport const useChannelProperties = (): ChannelProperties | null => {\n return useContext(ChannelPropertiesContext);\n};\n\nfunction groupFields(fields: ChannelFormField[]): ChannelFormField[][] {\n // Group fields for rendering\n const fieldGroups: ChannelFormField[][] = [[]];\n for (const field of fields) {\n if (\n field.span === 1 &&\n fieldGroups[fieldGroups.length - 1].length === 1 &&\n fieldGroups[fieldGroups.length - 1][0].span === 1\n ) {\n // join two half-width fields into one group\n fieldGroups[fieldGroups.length - 1].push(field);\n continue;\n }\n\n if (field.join) {\n // if the field should be explicitly joined, add it to the last group\n fieldGroups[fieldGroups.length - 1].push(field);\n continue;\n }\n\n // otherwise, start a new group\n fieldGroups.push([field]);\n }\n\n return fieldGroups;\n}\n\n/**\n * Convert form key/value pairs to channel properties\n * .e.g\n * Input:\n * {\n * \"k\": \"v1\",\n * \"a.b.c\": \"v2\",\n * \"z.z__a.y\": [\"v3\", \"v3\"],\n * }\n * Output:\n * {\n * k: \"v1\",\n * a: { b: { c: \"v2\", }, },\n * z: { z: \"v3\", y: \"v4\" },\n * }\n **/\nfunction formKvToChannelProperties(\n iter: IterableIterator<[string, string | Blob]>,\n): ChannelProperties {\n const obj: ChannelProperties = {};\n\n for (const [key, rawValue] of iter) {\n if (rawValue instanceof Blob) {\n continue;\n }\n\n // keys with __ represent multiple k/v pairs\n // e.g. `{\"a__b\": [\"1\", \"2\"]}` becomes `{a: \"1\", b: \"2\"}`\n const subkeys = key.split(\"__\");\n\n // if there are multiple subkeys, assume the value is a JSON array of strings\n const valueAsArray = formValueToStringArray(subkeys, rawValue);\n\n outer: for (const subkey of subkeys) {\n // split key by dot, for each part, traverse the object\n // and assign the value at the end\n // e.g. { \"branch.leaf\": \"value\" } becomes { branch: { leaf: \"value\" } }\n // cursor will be the leaf object\n const parts = subkey.split(\".\");\n let cursor = obj;\n while (parts.length > 1) {\n const part = parts.shift()!;\n let selected = cursor[part];\n if (selected === undefined) {\n // child object doesn't exist, create it\n selected = cursor[part] = {};\n }\n if (selected && typeof selected === \"object\") {\n if (Array.isArray(selected)) {\n continue outer; // should never happen\n }\n // traverse into child object\n cursor = selected;\n }\n }\n\n // assign next value to channel properties\n const nextValue = valueAsArray.length ? valueAsArray.shift() : \"\";\n cursor[parts[0]] = nextValue;\n }\n }\n\n return obj;\n}\n\n/**\n * Parse a json string[] with error handling.\n */\nfunction formValueToStringArray(\n subkeys: string[],\n value: string,\n): (string | number)[] {\n if (subkeys.length === 0) return [];\n if (subkeys.length === 1) return [value];\n if (value === \"\") return [];\n try {\n return JSON.parse(value);\n } catch (_e) {\n return [value];\n }\n}\n\n/**\n * Checks if two forms are equal\n */\nfunction formsAreEqual(a: ChannelFormField[], b: ChannelFormField[]) {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n if (a[i] !== b[i]) return false;\n }\n return true;\n}\n\n/**\n * Takes a form and filters out fields that should not be shown based on context.\n */\nexport function useFilteredFormFields(\n session: BffSession,\n form: ChannelFormField[],\n channelProperties: ChannelProperties,\n channelComponentData: ChannelComponentData | null,\n) {\n const filteredForm = useMemo(() => {\n return filterFormFields(\n session.session_type,\n form,\n channelProperties,\n channelComponentData,\n );\n }, [channelComponentData, channelProperties, form, session.session_type]);\n\n return filteredForm;\n}\n\nexport function filterFormFields(\n sessionType: BffSessionType,\n form: ChannelFormField[],\n channelProperties: ChannelProperties,\n channelComponentData: ChannelComponentData | null,\n) {\n const hasCardsField = formHasFieldOfType(form, \"credit_card_number\");\n const showBillingDetailsFields =\n channelComponentData?.cardDetails?.details?.require_billing_information;\n const hasInstallmentPlans =\n !!channelComponentData?.paymentOptions?.options?.installment_plans?.length;\n\n return form.filter((field) => {\n if (field.flags?.require_billing_information) {\n // filter out billing info fields if the flag is disabled or the session type is not PAY\n if (sessionType !== \"PAY\") return false;\n if (!showBillingDetailsFields) return false;\n }\n if (field.type.name === \"installment_plan\") {\n // filter out installment plan fields if there are no installment plans AND there is a card number field\n // (if there's no card number, then the installments field would be mandatory so we can't hide it)\n if (!hasInstallmentPlans && hasCardsField) return false;\n }\n for (const condition of field.display_if || []) {\n // filter out fields if any of their display_if conditions fail\n const [property, operator, value] = condition;\n const channelValue = getChannelPropertyValue(channelProperties, property);\n switch (operator) {\n case \"equals\":\n if (channelValue !== value) return false;\n break;\n case \"not_equals\":\n if (channelValue === value) return false;\n break;\n }\n }\n return true;\n });\n}\n\nexport default ChannelForm;\n","import { FunctionComponent, SVGAttributes } from \"preact\";\nimport { useLayoutEffect, useRef } from \"preact/hooks\";\n\nexport const InstructionsIcon: FunctionComponent<\n SVGAttributes<SVGSVGElement>\n> = (props) => {\n const arrowRef = useRef<SVGGElement>(null);\n const arrowSquareGroupRef = useRef<SVGGElement>(null);\n\n const supportsAnimation = HTMLElement.prototype.animate !== undefined;\n\n useLayoutEffect(() => {\n if (!supportsAnimation) {\n return;\n }\n arrowRef.current?.animate(arrowKeyFrames, arrowAnimationOptions);\n\n arrowSquareGroupRef.current?.animate(\n arrowSquareBounceKeyFrames,\n arrowSquareBounceAnimationOptions,\n );\n }, [supportsAnimation]);\n\n return (\n <svg\n width=\"40\"\n height=\"40\"\n viewBox=\"0 0 40 40\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n {...props}\n >\n <g opacity=\"0.5\">\n <path\n d=\"M8.79453 10.2303C7.1791 10.2303 5.86953 11.5399 5.86953 13.1553V28.9503C5.86953 31.535 7.96484 33.6303 10.5495 33.6303H26.3445C27.96 33.6303 29.2695 32.3208 29.2695 30.7053\"\n fill=\"#F1F1F1\"\n />\n <path\n d=\"M8.79453 10.2303V10.2303C7.1791 10.2303 5.86953 11.5399 5.86953 13.1553V28.9503C5.86953 31.535 7.96484 33.6303 10.5495 33.6303H26.3445C27.96 33.6303 29.2695 32.3208 29.2695 30.7053V30.7053\"\n stroke=\"#D0D0D0\"\n strokeWidth=\"1.755\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </g>\n <g ref={arrowSquareGroupRef} style={{ transformOrigin: \"20px 20px\" }}>\n <path\n d=\"M28.8177 6.00256H14.7777C12.193 6.00256 10.0977 8.09787 10.0977 10.6826V24.7226C10.0977 27.3073 12.193 29.4026 14.7777 29.4026H28.8177C31.4023 29.4026 33.4977 27.3073 33.4977 24.7226V10.6826C33.4977 8.09787 31.4024 6.00256 28.8177 6.00256Z\"\n fill=\"white\"\n stroke=\"#EDEDED\"\n strokeWidth=\"1.755\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <g style={{ transformOrigin: \"10px 30px\" }} ref={arrowRef}>\n <path\n d=\"M26.7697 20.5301V12.7301H18.9697\"\n stroke=\"#7C7C7C\"\n strokeWidth=\"1.872\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M17.4102 22.0901L26.7702 12.7301\"\n stroke=\"#7C7C7C\"\n strokeWidth=\"1.872\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </g>\n </g>\n </svg>\n );\n};\n\nconst arrowKeyFrames: Keyframe[] = [\n { transform: \"scale(0.1)\" },\n { transform: \"scale(1)\" },\n];\nconst arrowAnimationOptions: EffectTiming = {\n duration: 500,\n easing: \"ease-out\",\n};\n\nconst arrowSquareBounceKeyFrames: Keyframe[] = [\n { transform: \"rotate(0deg)\" },\n { transform: \"rotate(5deg)\" },\n { transform: \"rotate(-5deg)\" },\n { transform: \"rotate(0deg)\" },\n];\nconst arrowSquareBounceAnimationOptions: EffectTiming = {\n duration: 1000,\n easing: \"ease-out\",\n iterations: Infinity,\n delay: 2000,\n};\n","import { FunctionComponent, SVGAttributes } from \"preact\";\nimport { useLayoutEffect, useRef } from \"preact/hooks\";\nimport { useIdSafe } from \"../utils\";\n\nexport const QrScanIcon: FunctionComponent<SVGAttributes<SVGSVGElement>> = (\n props,\n) => {\n const scannerRef = useRef<SVGRectElement>(null);\n const squareBackgroundRef = useRef<SVGRectElement>(null);\n\n const clipPathId = useIdSafe();\n\n const supportsAnimation = HTMLElement.prototype.animate !== undefined;\n\n useLayoutEffect(() => {\n if (!supportsAnimation) {\n return;\n }\n if (scannerRef.current) {\n const startAnimation = () => {\n if (!scannerRef.current) return;\n const a = scannerRef.current.animate(\n scannerKeyFrames,\n scanDownAnimationOptions,\n );\n setTimeout(() => {\n squareBackgroundRef.current?.animate(\n squareKeyFrames,\n squareAnimationOptions,\n );\n }, 1000);\n a.onfinish = () => {\n const b = scannerRef.current?.animate(\n scannerKeyFrames,\n scanUpAnimationOptions,\n );\n setTimeout(() => {\n squareBackgroundRef.current?.animate(\n squareKeyFrames,\n squareAnimationOptions,\n );\n }, 500);\n if (b) b.onfinish = startAnimation;\n };\n };\n startAnimation();\n }\n }, [supportsAnimation]);\n\n return (\n <svg\n width=\"40\"\n height=\"40\"\n viewBox=\"0 0 40 40\"\n fill=\"var(--xendit-color-icon-primary)\"\n xmlns=\"http://www.w3.org/2000/svg\"\n {...props}\n >\n <g clip-path={`url(#${clipPathId})`}>\n {/* background */}\n <rect\n x=\"8\"\n y=\"8\"\n width=\"24\"\n height=\"24\"\n fill=\"var(--xendit-color-icon-secondary)\"\n ref={squareBackgroundRef}\n />\n\n <path d=\"M11.5 13.1528C11.5 12.24 12.24 11.5 13.1528 11.5H17.4028C18.3156 11.5 19.0556 12.24 19.0556 13.1528V17.4028C19.0556 18.3156 18.3156 19.0556 17.4028 19.0556H13.1528C12.24 19.0556 11.5 18.3156 11.5 17.4028V13.1528Z\" />\n <path d=\"M20.9444 13.1528C20.9444 12.24 21.6844 11.5 22.5972 11.5H26.8472C27.76 11.5 28.5 12.24 28.5 13.1528V17.4028C28.5 18.3156 27.76 19.0556 26.8472 19.0556H22.5972C21.6844 19.0556 20.9444 18.3156 20.9444 17.4028V13.1528Z\" />\n <path d=\"M11.5 22.5972C11.5 21.6844 12.24 20.9444 13.1528 20.9444H17.4028C18.3156 20.9444 19.0556 21.6844 19.0556 22.5972V26.8472C19.0556 27.76 18.3156 28.5 17.4028 28.5H13.1528C12.24 28.5 11.5 27.76 11.5 26.8472V22.5972Z\" />\n <path d=\"M20.9444 22.5972C20.9444 21.6844 21.6844 20.9444 22.5972 20.9444H26.8472C27.76 20.9444 28.5 21.6844 28.5 22.5972V26.8472C28.5 27.76 27.76 28.5 26.8472 28.5H22.5972C21.6844 28.5 20.9444 27.76 20.9444 26.8472V22.5972Z\" />\n <path d=\"M7.875 23C8.35825 23 8.75 23.3918 8.75 23.875V30.2754C8.75021 30.6755 9.07451 30.9998 9.47461 31H15.875C16.3582 31 16.75 31.3918 16.75 31.875C16.75 32.3582 16.3582 32.75 15.875 32.75H9.47461C8.10801 32.7498 7.00021 31.642 7 30.2754V23.875C7 23.3918 7.39175 23 7.875 23Z\" />\n <path d=\"M31.875 23C32.3582 23 32.75 23.3918 32.75 23.875V30.2754C32.7498 31.642 31.642 32.7498 30.2754 32.75H23.875C23.3918 32.75 23 32.3582 23 31.875C23 31.3918 23.3918 31 23.875 31H30.2754C30.6755 30.9998 30.9998 30.6755 31 30.2754V23.875C31 23.3918 31.3918 23 31.875 23Z\" />\n <path d=\"M15.875 7C16.3582 7 16.75 7.39175 16.75 7.875C16.75 8.35825 16.3582 8.75 15.875 8.75H9.47461C9.07451 8.75021 8.75021 9.07451 8.75 9.47461V15.875C8.75 16.3582 8.35825 16.75 7.875 16.75C7.39175 16.75 7 16.3582 7 15.875V9.47461C7.00021 8.10801 8.10801 7.00021 9.47461 7H15.875Z\" />\n <path d=\"M30.2754 7C31.642 7.00021 32.7498 8.10801 32.75 9.47461V15.875C32.75 16.3582 32.3582 16.75 31.875 16.75C31.3918 16.75 31 16.3582 31 15.875V9.47461C30.9998 9.07451 30.6755 8.75021 30.2754 8.75H23.875C23.3918 8.75 23 8.35825 23 7.875C23 7.39175 23.3918 7 23.875 7H30.2754Z\" />\n {/* scanner */}\n <rect x=\"3\" y=\"-4\" width=\"34\" height=\"4\" rx=\"1.75\" ref={scannerRef} />\n </g>\n <defs>\n <clipPath id={clipPathId}>\n <rect width=\"40\" height=\"40\" fill=\"white\" />\n </clipPath>\n </defs>\n </svg>\n );\n};\n\nconst scannerKeyFrames: Keyframe[] = [\n { transform: \"translateY(0)\" },\n { transform: \"translateY(44px)\" },\n];\nconst scanDownAnimationOptions: EffectTiming = {\n duration: 1000,\n delay: 1000,\n easing: \"ease-out\",\n};\nconst scanUpAnimationOptions: EffectTiming = {\n duration: 1000,\n direction: \"reverse\",\n delay: 500,\n easing: \"ease-in\",\n};\n\nconst squareKeyFrames: Keyframe[] = [\n { opacity: 1 },\n { opacity: 0 },\n { opacity: 1 },\n];\nconst squareAnimationOptions: EffectTiming = {\n duration: 1000,\n};\n","import { FunctionComponent, TargetedEvent } from \"preact\";\nimport { useIdSafe } from \"../utils\";\n\ninterface Props {\n id?: string;\n label: string;\n checked?: boolean;\n disabled?: boolean;\n onChange?: (e: TargetedEvent<HTMLInputElement>) => void;\n}\n\n/**\n * Checkbox component\n */\nexport const Checkbox: FunctionComponent<Props> = (props) => {\n const { id, label, checked, onChange, disabled } = props;\n\n const generatedId = useIdSafe();\n const htmlId = id || generatedId;\n\n const handleChange = (e: TargetedEvent<HTMLInputElement>) => {\n onChange?.(e);\n };\n\n return (\n <div className=\"xendit-checkbox\">\n <div className=\"xendit-checkbox-box\">\n <input\n id={htmlId}\n type=\"checkbox\"\n onChange={handleChange}\n checked={checked}\n disabled={disabled}\n />\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 256 256\"\n className=\"xendit-checkbox-graphic\"\n >\n <polyline\n points=\"40 144 96 200 224 72\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"16\"\n ></polyline>\n </svg>\n </div>\n <label htmlFor={htmlId} className=\"xendit-text-14\">\n {label}\n </label>\n </div>\n );\n};\n","import ChannelForm, { ChannelFormHandle } from \"./channel-form\";\nimport { useContext, useRef } from \"preact/hooks\";\nimport {\n createContext,\n FunctionComponent,\n RefObject,\n TargetedEvent,\n} from \"preact\";\nimport {\n BffChannel,\n BffChannelBanner,\n ChannelProperties,\n} from \"../backend-types/channel\";\nimport { InstructionsIcon } from \"./instructions-icon\";\nimport { QrScanIcon } from \"./qr-scan-icon\";\nimport { useSdk, useSession } from \"./session-provider\";\nimport { Checkbox } from \"./checkbox\";\nimport { resolvePairedChannel } from \"../utils\";\nimport { ChannelComponentData } from \"../public-sdk\";\nimport { InternalUpdateChannelComponentData } from \"../private-event-types\";\n\nconst ChannelContext = createContext<BffChannel | null>(null);\n\nexport const useChannel = () => {\n const context = useContext(ChannelContext);\n if (context === undefined) {\n throw new Error(\"useChannel must be used within a ChannelProvider\");\n }\n return context;\n};\n\nconst ChannelComponentDataContext = createContext<ChannelComponentData | null>(\n null,\n);\nChannelComponentDataContext.displayName = \"ChannelComponentDataContext\";\n\nexport const useChannelComponentData = () => {\n const context = useContext(ChannelComponentDataContext);\n return context;\n};\n\ninterface Props {\n /** The channels to use. If this has two items then the first is the non-save channel and the second is the save version. */\n channelOrPair: BffChannel[];\n channelData: ChannelComponentData;\n savePaymentMethod: boolean;\n formRef: RefObject<ChannelFormHandle>;\n}\n\nexport const PaymentChannel: FunctionComponent<Props> = (props) => {\n const { channelOrPair, channelData, savePaymentMethod, formRef } = props;\n const divRef = useRef<HTMLDivElement>(null);\n const sdk = useSdk();\n const { t } = sdk;\n const session = useSession();\n\n // events always use channelOrPair[0] because the CachedChannelComponents are keyed by that\n const firstMemberChannel = channelOrPair[0];\n\n const hasPairedChannel = channelOrPair.length > 1;\n const resolvedChannel = resolvePairedChannel(\n channelOrPair,\n savePaymentMethod,\n );\n\n const instructions = instructionsAsTuple(resolvedChannel.instructions);\n\n const onChannelPropertiesChanged = (channelProperties: ChannelProperties) => {\n let cleanedProperties = channelProperties;\n if (\n firstMemberChannel.channel_code === \"CARDS\" &&\n channelProperties.installment_configuration\n ) {\n // for cards installment configuration, we need to remove any properties that have empty string values,\n // because the presence of those properties causes validation errors, even if the value is an empty string\n const cleanedInstallmentConfiguration = Object.fromEntries(\n Object.entries(channelProperties.installment_configuration).filter(\n ([_, value]) => value !== \"\",\n ),\n );\n if (Object.keys(cleanedInstallmentConfiguration).length === 0) {\n // if there are no valid properties left, set installment_configuration to undefined to avoid validation errors\n cleanedProperties = {\n ...channelProperties,\n installment_configuration: undefined,\n };\n } else {\n cleanedProperties = {\n ...channelProperties,\n installment_configuration: cleanedInstallmentConfiguration,\n };\n }\n }\n\n const event = new XenditChannelPropertiesChangedEvent(\n firstMemberChannel.channel_code,\n cleanedProperties,\n );\n divRef.current?.dispatchEvent(event);\n };\n\n const shouldShowSaveCheckbox =\n session.allow_save_payment_method === \"OPTIONAL\" &&\n (resolvedChannel.allow_save || hasPairedChannel);\n\n const handleCheckboxChange = (e: TargetedEvent<HTMLInputElement>) => {\n const checked = (e.target as HTMLInputElement)?.checked;\n sdk?.dispatchEvent(\n new InternalUpdateChannelComponentData(firstMemberChannel.channel_code, {\n savePaymentMethod: checked,\n }),\n );\n };\n\n return (\n <ChannelContext.Provider value={resolvedChannel}>\n <ChannelComponentDataContext.Provider value={channelData}>\n <div className=\"xendit-payment-channel\" ref={divRef}>\n <ChannelForm\n ref={formRef}\n form={resolvedChannel.form}\n onChannelPropertiesChanged={onChannelPropertiesChanged}\n />\n {resolvedChannel.banner ? (\n <Banner banner={resolvedChannel.banner} />\n ) : null}\n {shouldShowSaveCheckbox && (\n <Checkbox\n label={t(\"payment.save_checkbox_label\")}\n onChange={handleCheckboxChange}\n checked={savePaymentMethod}\n />\n )}\n {instructions ? (\n <div className=\"xendit-payment-channel-instructions\">\n {resolvedChannel.pm_type === \"QR_CODE\" ? (\n <QrScanIcon />\n ) : (\n <InstructionsIcon />\n )}\n <div className=\"xendit-payment-channel-instructions-text xendit-text-12\">\n {instructions.map((instr, i) => (\n <p\n key={i}\n className={i === 0 ? \"xendit-text-semibold\" : undefined}\n >\n {instr}\n </p>\n ))}\n </div>\n </div>\n ) : null}\n </div>\n </ChannelComponentDataContext.Provider>\n </ChannelContext.Provider>\n );\n};\n\nconst Banner: FunctionComponent<{ banner: BffChannelBanner }> = (props) => {\n const aspectRatio =\n typeof props.banner.aspect_ratio === \"number\"\n ? String(props.banner.aspect_ratio) // passing aspectRatio as a number does not work\n : undefined;\n\n if (props.banner?.link_url) {\n return (\n <a href={props.banner.link_url} target=\"_blank\" rel=\"noopener noreferrer\">\n <img\n src={props.banner.image_url}\n alt={props.banner.alt_text}\n className=\"xendit-payment-channel-banner\"\n style={{\n aspectRatio,\n }}\n />\n </a>\n );\n }\n\n return (\n <img\n src={props.banner.image_url}\n alt={props.banner.alt_text}\n className=\"xendit-payment-channel-banner\"\n style={{\n aspectRatio,\n }}\n />\n );\n};\n\nfunction instructionsAsTuple(\n instructions: string[] | undefined,\n): [string, string] | null {\n if (instructions && instructions.length === 2) {\n return [instructions[0], instructions[1]] as const;\n }\n return null;\n}\n\nexport class XenditChannelPropertiesChangedEvent extends Event {\n static readonly type = \"xendit-channel-properties-changed\" as const;\n channel: string;\n channelProperties: ChannelProperties;\n\n constructor(channel: string, channelProperties: ChannelProperties) {\n super(XenditChannelPropertiesChangedEvent.type, {\n bubbles: true,\n composed: true,\n });\n this.channel = channel;\n this.channelProperties = channelProperties;\n }\n}\n","import { assert, hostFromHostId, MOCK_HOST_ID, ParsedSdkKey } from \"./utils\";\n\nexport type ErrorResponse = {\n error_code: string;\n message: string;\n error_content?: {\n title: string;\n message_1: string;\n message_2?: string;\n };\n};\n\nexport class NetworkError extends Error {\n constructor(public errorResponse: ErrorResponse) {\n super(errorResponse.message);\n }\n}\n\n/**\n * Encode data for x-www-form-urlencoded content type\n */\nfunction convertDataToUrlSearchParams<T extends object>(data: T) {\n const params = new URLSearchParams();\n params.append(\"payload\", JSON.stringify(data));\n return params;\n}\n\n// GET with path param\nexport function endpoint<ResponseBody, PathArg>(\n method: \"GET\",\n getPath: (pathArg: PathArg) => string,\n): (\n sdkKey: ParsedSdkKey,\n pathArg: PathArg,\n queryArg?: null,\n abortSignal?: AbortSignal,\n) => Promise<ResponseBody>;\n\n// GET with path param and query param\nexport function endpoint<ResponseBody, PathArg, QueryArg = never>(\n method: \"GET\",\n getPath: (pathArg: PathArg) => string,\n getQuery: (queryArg: QueryArg) => URLSearchParams,\n): (\n sdkKey: ParsedSdkKey,\n pathArg: PathArg,\n queryArg?: QueryArg,\n abortSignal?: AbortSignal,\n) => Promise<ResponseBody>;\n\n// POST with path param\nexport function endpoint<RequestBody, ResponseBody, PathArg>(\n method: \"POST\",\n getPath: (pathArg: PathArg) => string,\n): (\n sdkKey: ParsedSdkKey,\n requestBody: RequestBody,\n pathArg: PathArg,\n queryArg?: null,\n abortSignal?: AbortSignal,\n) => Promise<ResponseBody>;\n\n// POST with path param and query param\nexport function endpoint<RequestBody, ResponseBody, PathArg, QueryArg = never>(\n method: \"POST\",\n getPath: (pathArg: PathArg) => string,\n getQuery: (queryArg: QueryArg) => URLSearchParams,\n): (\n sdkKey: ParsedSdkKey,\n requestBody: RequestBody,\n pathArg: PathArg,\n queryArg?: QueryArg,\n abortSignal?: AbortSignal,\n) => Promise<ResponseBody>;\n\n/**\n * Declares an endpoint in checkout-ui-gateway and returns a function to call it.\n *\n * @example\n * ```\n * // declare\n * const myEndpoint = endpoint<\n * { userId: string }, // Request body type\n * { name: string; age: number }, // Response body type\n * string, // Type of arg passed to getPath\n * string, // Type of arg passed to getQuery\n * >(\n * \"POST\",\n * (pathArg) => `/api/users/${pathArg}`, // getPath function\n * (queryArg) => new UrlSearchParams({id: queryArg}) // getQuery function\n * );\n *\n * // usage\n * await myEndpoint({userId: \"123\"}, \"456\", \"789\");\n * ```\n */\nexport function endpoint(\n method: \"GET\" | \"POST\",\n getPath: (pathArg: unknown) => string,\n getQuery?: (queryArg: unknown) => URLSearchParams,\n) {\n return async function (...rest: unknown[]): Promise<unknown> {\n let sdkKey: unknown;\n let pathArg: unknown;\n let queryArg: unknown;\n let requestBody: unknown;\n let abortSignal: unknown;\n\n switch (method) {\n case \"GET\":\n [sdkKey, pathArg, queryArg, abortSignal] = rest;\n break;\n case \"POST\":\n [sdkKey, requestBody, pathArg, queryArg, abortSignal] = rest;\n break;\n default:\n throw new Error(\n `Unable to call endpoint with method ${method}; this is a bug, please contact support.`,\n );\n }\n\n const versionNumber = process.env.XENDIT_COMPONENTS_VERSION;\n assert(versionNumber);\n assert(versionNumber.startsWith(\"v\"));\n\n const hostId = (sdkKey as ParsedSdkKey).hostId;\n if (hostId === MOCK_HOST_ID) {\n throw new Error(\n \"A network request was made in mock mode; this is a bug.\",\n );\n }\n const host = hostFromHostId(hostId);\n if (!host) {\n throw new Error(\n `Unknown hostId ${hostId} in sdkKey; this is a bug, please contact support.`,\n );\n }\n\n const url = new URL(getPath(pathArg), host);\n if (getQuery && !queryArg) {\n throw new Error(\n \"Query string argument is missing; this is a bug, please contact support.\",\n );\n }\n const query = getQuery?.(queryArg) ?? new URLSearchParams();\n query.set(\"components_version\", versionNumber);\n url.search = query.toString();\n\n const options: RequestInit = {\n method,\n body: requestBody ? convertDataToUrlSearchParams(requestBody) : undefined,\n headers: {\n \"Content-Type\": \"application/x-www-form-urlencoded\",\n },\n signal: abortSignal as AbortSignal | undefined,\n };\n\n const response = await fetch(url, options);\n if (!response.ok) {\n const errorData = (await response.json()) as ErrorResponse;\n if (!errorData || !errorData.error_code) {\n throw new Error(\"Unexpected error response from server\");\n }\n throw new NetworkError(errorData);\n }\n\n return response.json();\n };\n}\n","import { ChannelProperties } from \"./backend-types/channel\";\nimport { BffPollResponse, BffResponse } from \"./backend-types/common\";\nimport { BffCustomer } from \"./backend-types/customer\";\nimport {\n BffPaymentRequest,\n BffPaymentToken,\n} from \"./backend-types/payment-entity\";\nimport { BffCardDetails } from \"./backend-types/card-details\";\nimport { endpoint } from \"./networking\";\nimport { BffPaymentOptions } from \"./backend-types/payment-options\";\n\n/**\n * Initialization method, returns session, customer, business, and channels.\n */\nexport const fetchSessionData = endpoint<BffResponse, string>(\n \"GET\",\n (sessionAuthKey) => `/api/sessions/${sessionAuthKey}`,\n);\n\ntype CreatePaymentTokenRequestBody = {\n session_id: string;\n channel_code: string;\n channel_properties: ChannelProperties;\n};\n/**\n * Creates a payment token.\n */\nexport const createPaymentToken = endpoint<\n CreatePaymentTokenRequestBody,\n BffPaymentToken,\n null\n>(\"POST\", () => `/api/sessions/payment_tokens`);\n\ntype CreatePaymentRequestRequestBody = {\n session_id: string;\n channel_code: string;\n channel_properties: ChannelProperties;\n customer?: BffCustomer;\n save_payment_method?: boolean;\n};\n/**\n * Creates a payment request.\n */\nexport const createPaymentRequest = endpoint<\n CreatePaymentRequestRequestBody,\n BffPaymentRequest,\n null\n>(\"POST\", () => `/api/sessions/payment_requests`);\n\ntype SimulatePaymentRequestRequestBody = {\n channel_code: string;\n};\n/**\n * Simulates a payment request.\n */\nexport const simulatePaymentRequest = endpoint<\n SimulatePaymentRequestRequestBody,\n BffPaymentRequest,\n { sessionAuthKey: string; paymentRequestId: string }\n>(\n \"POST\",\n (pathArg) =>\n `/api/sessions/${pathArg.sessionAuthKey}/payment_requests/${pathArg.paymentRequestId}/simulate`,\n);\n\n/**\n * Polls the session for updates.\n *\n * Always returns the session.\n * If the session is active, the payment entity will be included.\n * If the session is completed, the succeeded channel will be included.\n */\nexport const pollSession = endpoint<BffPollResponse, string, string | null>(\n \"GET\",\n (sessionAuthKey) => `/api/sessions/${sessionAuthKey}/poll`,\n (tokenRequestId) =>\n new URLSearchParams(\n tokenRequestId ? { token_request_id: tokenRequestId } : {},\n ),\n);\n\ntype LookupCardDetailsRequestBody = {\n /**\n * Encrypted card number\n */\n card_number: string;\n};\n/**\n * Returns metadata about a card number.\n */\nexport const lookupCardDetails = endpoint<\n LookupCardDetailsRequestBody,\n BffCardDetails,\n string\n>(\"POST\", (sessionAuthKey) => `/api/sessions/${sessionAuthKey}/card_info`);\n\ntype GetPaymentOptionsRequest = {\n channel_code: string;\n channel_properties?: {\n card_number: string;\n };\n};\n/**\n * Returns metadata about a card number.\n */\nexport const getPaymentOptions = endpoint<\n GetPaymentOptionsRequest,\n BffPaymentOptions,\n string\n>(\n \"POST\",\n (sessionAuthKey) => `/api/sessions/${sessionAuthKey}/payment_options`,\n);\n","import { assertIsArray, assertIsNotArray } from \"../utils\";\n\n/**\n * A node in a behavior tree.\n */\nexport type BehaviorNodeSingle<BB extends object> = {\n impl: BehaviorConstructor<BB>;\n key: string;\n child: BehaviorNode<BB> | undefined;\n instance: Behavior | undefined;\n};\n\nexport type BehaviorNode<BB extends object> =\n | BehaviorNodeSingle<BB>\n | (BehaviorNodeSingle<BB> | undefined)[];\n\n/**\n * Creates a behavior tree node.\n *\n * Takes a constructor implementing Behavior and a unique key. Nodes that are different from the previous tree\n * are removed and replaced. \"different\" means either the constructor or the key is different.\n *\n * The BB (blackboard) is data shared between all nodes in the tree. It is mutable.\n */\nexport function behaviorNode<BB extends object>(\n impl: BehaviorConstructor<BB>,\n key?: string,\n child?: BehaviorNode<BB>,\n): BehaviorNodeSingle<BB> {\n return {\n impl,\n key: key ?? \"\",\n child,\n instance: undefined,\n };\n}\n\n/**\n * A behavior implementation constructor.\n */\nexport interface BehaviorConstructor<BB extends object> {\n new (blackboard: BB, key: string): Behavior;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type AnyBehaviorConstructor = BehaviorConstructor<any>;\n\nexport interface Behavior {\n /**\n * Called when entering this behavior\n */\n enter?(): void;\n /**\n * Called when a tree is updated but this node is not changed.\n */\n update?(): void;\n /**\n * Called when exiting this behavior\n */\n exit?(): void;\n}\n\n/**\n * A behavior tree.\n * https://en.wikipedia.org/wiki/Behavior_tree_(artificial_intelligence,_robotics_and_control)\n *\n * Updating a tree diffs the nodes and calls enter on new nodes and exit on removed nodes.\n */\nexport class BehaviorTree<BB extends object> {\n root: BehaviorNode<BB> = behaviorNode(class {});\n\n // whether an update is in progress\n updating: boolean = false;\n // whether another update is requested\n again: boolean = false;\n\n constructor(\n private fn: (bb: BB) => BehaviorNode<BB>,\n public bb: BB,\n ) {}\n\n update(): void {\n // flag to scheule an update\n this.again = true;\n\n if (this.updating) {\n // if this gets called recursively, just return, the outermost call will handle it\n return;\n }\n\n let updateCount = 0;\n\n try {\n this.updating = true;\n while (this.again) {\n this.again = false;\n updateCount += 1;\n assertMaxRecursionDepth(updateCount);\n\n const prev = this.root ?? undefined;\n const next = this.fn(this.bb);\n this.root = next;\n\n updateTree(prev, next, this.bb, 0);\n }\n } finally {\n this.updating = false;\n }\n }\n\n findBehavior<T extends AnyBehaviorConstructor>(\n constructor: T,\n ): InstanceType<T> | null {\n return findBehavior(this.root, constructor);\n }\n}\n\nfunction assertMaxRecursionDepth(depth: number) {\n if (depth > 32) {\n throw new Error(\n \"Max recursion depth exceeded; this is a bug, please contact support.\",\n );\n }\n}\n\nfunction isChanged<BB extends object>(\n prev: BehaviorNode<BB> | undefined,\n next: BehaviorNode<BB> | undefined,\n) {\n if (prev === undefined || next === undefined) {\n return true;\n }\n\n if (Array.isArray(prev) !== Array.isArray(next)) {\n // if it changed from an array to a non-array or vice versa, it is changed\n return true;\n }\n\n if (Array.isArray(prev) && Array.isArray(next)) {\n // if both are arrays, they aren't \"changed\" because arrays are functionally the same, but their children might be changed\n return false;\n }\n\n // they must both be non-arrays here\n assertIsNotArray(prev);\n assertIsNotArray(next);\n\n return prev.impl !== next.impl || prev.key !== next.key;\n}\n\nfunction updateTree<BB extends object>(\n prev: BehaviorNode<BB> | undefined,\n next: BehaviorNode<BB> | undefined,\n bb: BB,\n depth: number,\n) {\n assertMaxRecursionDepth(depth);\n\n if (isChanged(prev, next)) {\n // after we find a change, exit the previous nodes\n if (prev) {\n exitSubtree(prev, depth + 1);\n }\n // then enter the new nodes\n if (next) {\n enterSubtree(next, bb, depth + 1);\n }\n } else {\n // the nodes are equal\n if (Array.isArray(prev) || Array.isArray(next)) {\n // if the nodes are arrays, just update their children\n // (assert they are both arrays to keep typescript happy (we already checked that))\n assertIsArray(prev);\n assertIsArray(next);\n const maxLength = Math.max(prev.length, next.length);\n for (let i = 0; i < maxLength; i++) {\n updateTree(prev[i], next[i], bb, depth + 1);\n }\n } else {\n // if the nodes are not arrays, move the instance to the new node and update its child\n if (next) {\n next.instance = prev?.instance;\n }\n if (prev) {\n prev.instance = undefined;\n }\n updateTree(prev?.child, next?.child, bb, depth + 1);\n next?.instance?.update?.();\n }\n }\n}\n\nfunction enterSubtree<BB extends object>(\n node: BehaviorNode<BB>,\n bb: BB,\n depth: number,\n) {\n assertMaxRecursionDepth(depth);\n\n // handle parallel nodes\n if (Array.isArray(node)) {\n for (const child of node) {\n if (!child) continue;\n enterSubtree(child, bb, depth + 1);\n }\n return;\n }\n\n // construct instances and call enter traversing downwards\n node.instance = new node.impl(bb, node.key);\n node.instance.enter?.();\n if (node.child) {\n enterSubtree(node.child, bb, depth + 1);\n }\n}\n\nfunction exitSubtree<BB extends object>(node: BehaviorNode<BB>, depth: number) {\n assertMaxRecursionDepth(depth);\n\n // handle parallel nodes\n if (Array.isArray(node)) {\n for (const child of node) {\n if (!child) continue;\n exitSubtree(child, depth + 1);\n }\n return;\n }\n\n // call exit traversing upwards\n if (node.child) {\n exitSubtree(node.child, depth + 1);\n }\n node.instance?.exit?.();\n node.instance = undefined;\n}\n\nexport function flattenBehaviors<BB extends object>(\n node: BehaviorNode<BB>,\n): BehaviorNodeSingle<BB>[] {\n const result: BehaviorNodeSingle<BB>[] = [];\n function traverse(node: BehaviorNode<BB>) {\n if (Array.isArray(node)) {\n for (const child of node) {\n if (!child) continue;\n traverse(child);\n }\n } else {\n result.push(node);\n if (node.child) {\n traverse(node.child);\n }\n }\n }\n traverse(node);\n return result;\n}\n\nfunction findBehavior<BB extends object, T extends AnyBehaviorConstructor>(\n node: BehaviorNode<BB>,\n constructor: T,\n): InstanceType<T> | null {\n if (Array.isArray(node)) {\n for (const child of node) {\n if (!child) continue;\n const result = findBehavior(child, constructor);\n if (result) {\n return result;\n }\n }\n } else {\n if (node.impl === constructor) {\n return (node.instance as InstanceType<T>) ?? null;\n } else {\n if (node.child) {\n return findBehavior(node.child, constructor);\n }\n }\n }\n\n return null;\n}\n","import { useCallback, useLayoutEffect, useRef } from \"preact/hooks\";\nimport { IframeActionCompleteEvent } from \"../../../shared/types\";\n\ntype Props = {\n url: string;\n mock: boolean;\n onIframeComplete: (event: IframeActionCompleteEvent) => void;\n};\n\nexport function ActionIframe(props: Props) {\n const { url, mock, onIframeComplete } = props;\n\n const iframeRef = useRef<HTMLIFrameElement>(null);\n\n const handleEventFromIframe = useCallback(\n (event: MessageEvent) => {\n if (!iframeRef.current) return;\n\n const expectedSource = iframeRef.current.contentWindow;\n\n if (event.source !== expectedSource) {\n // we are not the target of this message\n return;\n }\n\n if (\n event.data?.type ===\n (\"xendit-iframe-action-complete\" satisfies IframeActionCompleteEvent[\"type\"])\n ) {\n onIframeComplete(event.data as IframeActionCompleteEvent);\n }\n },\n [onIframeComplete],\n );\n\n useLayoutEffect(() => {\n window.addEventListener(\"message\", handleEventFromIframe);\n return () => {\n window.removeEventListener(\"message\", handleEventFromIframe);\n };\n }, [handleEventFromIframe]);\n\n if (mock) {\n return (\n <iframe\n ref={iframeRef}\n srcDoc={MOCK_IFRAME_SRCDOC}\n className=\"xendit-action-iframe\"\n />\n );\n }\n\n return (\n <iframe\n ref={iframeRef}\n src={url}\n // sandbox=\"allow-scripts\"\n className=\"xendit-action-iframe\"\n />\n );\n}\n\nconst MOCK_IFRAME_SRCDOC = `\n <html>\n <head>\n <title>Xendit Mock Action Iframe</title>\n <style>\n body {\n font-family: Arial, sans-serif;\n font-size: 14px;\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 12px;\n }\n p {\n margin: 0;\n }\n .buttons {\n display: flex;\n gap: 8px;\n }\n button {\n font-size: 12px;\n display: flex;\n align-items: center;\n text-align: left;\n background-color: white;\n border: 1px solid rgba(243, 243, 243);\n border-radius: 4px;\n justify-content: space-between;\n padding: 4px;\n cursor: pointer;\n }\n button:hover {\n border-color: #1762ee;\n background-color: #1762ee;\n color: white;\n }\n </style>\n </head>\n <body>\n <p>This is a mock action page.</p>\n <p>Normally, this would be a 3DS authentication page.</p>\n <p>Click a button below to simulate the result of the action.</p>\n <div class=\"buttons\">\n <button onclick=\"parent.postMessage({type: 'xendit-iframe-action-complete', mockStatus: 'success'}, '*')\">\n Simulate Success\n </button>\n <button onclick=\"parent.postMessage({type: 'xendit-iframe-action-complete', mockStatus: 'fail'}, '*')\">\n Simulate Failure\n </button>\n </div>\n </body>\n </html>\n`;\n","import { TFunction } from \"../localization\";\nimport { useCallback, useMemo, useState } from \"preact/hooks\";\nimport qrcode from \"qrcode\";\nimport qrSvgRenderer from \"qrcode/lib/renderer/svg-tag.js\";\nimport { amountFormat } from \"../amount-format\";\nimport { Button, ButtonLoadingSpinner, ButtonVariant } from \"./button\";\n\ntype Props = {\n amount: number;\n businessName: string;\n channelLogo: string;\n currency: string;\n hideUi: boolean;\n onAffirm: () => void;\n qrString: string;\n title: string;\n t: TFunction;\n};\n\nexport function ActionQr(props: Props) {\n const {\n amount,\n businessName,\n channelLogo,\n currency,\n onAffirm,\n qrString,\n title,\n t,\n } = props;\n\n const [showSpinner, setShowSpinner] = useState(false);\n\n const onMadePaymentClicked = useCallback(() => {\n setShowSpinner(true);\n onAffirm();\n }, [onAffirm]);\n\n const svgNode = useMemo(() => {\n try {\n return generateQrSvg(qrString);\n } catch (error) {\n console.log(\"Error generating QR code SVG:\", error);\n // show an error message in place of the QR code\n const node = document.createElement(\"div\");\n node.innerText = t(\"action_qr.unable_to_generate\");\n return node;\n }\n }, [qrString, t]);\n\n if (props.hideUi) {\n return (\n <div\n data-testid=\"qr-code\"\n ref={(r) => {\n if (r && (r.childNodes.length !== 1 || r.firstChild !== svgNode)) {\n // insert svg if not already present\n r?.replaceChildren(svgNode);\n }\n }}\n />\n );\n }\n\n return (\n <div className=\"xendit-action-present-to-customer\">\n <img\n src={channelLogo}\n alt=\"Channel Logo\"\n className=\"xendit-action-qr-channel-logo\"\n />\n <div className=\"xendit-action-title\">{title}</div>\n <div className=\"xendit-action-qr-content\">\n <div className=\"xendit-text-16 xendit-text-semibold xendit-text-center\">\n {businessName}\n </div>\n <div\n data-testid=\"qr-code\"\n className=\"xendit-action-qr-qrcode-container\"\n ref={(r) => {\n if (r && (r.childNodes.length !== 1 || r.firstChild !== svgNode)) {\n // insert svg if not already present\n r?.replaceChildren(svgNode);\n }\n }}\n />\n <div className=\"xendit-text-16 xendit-text-semibold xendit-text-center\">\n {amountFormat(amount, currency)}\n </div>\n </div>\n <div className=\"xendit-action-present-to-customer-affirm\">\n <Button\n variant={ButtonVariant.WHITE_ROUNDED}\n disabled={showSpinner}\n onClick={onMadePaymentClicked}\n className=\"xendit-button-block\"\n >\n {showSpinner ? <ButtonLoadingSpinner /> : t(\"action.payment_made\")}\n </Button>\n <div className=\"xendit-text-12 xendit-text-secondary xendit-text-center\">\n {t(\"action.payment_confirmation_instructions\")}\n </div>\n </div>\n </div>\n );\n}\n\n/**\n * Generate a qr code svg. It will have 1x1 pixels and 1px margins.\n *\n * Returns the svg node and the size of the image including margins.\n */\nfunction generateQrSvg(text: string): SVGSVGElement {\n const qr = qrcode.create(text);\n const margin = 1;\n const svgText = qrSvgRenderer.render(qr, {\n margin,\n });\n const parser = new DOMParser();\n const svgNode = parser.parseFromString(svgText, \"image/svg+xml\")\n .documentElement as unknown as SVGSVGElement;\n\n svgNode.style.width = \"100%\";\n svgNode.style.height = \"100%\";\n svgNode.setAttribute(\"width\", String(qr.modules.size + margin * 2));\n svgNode.setAttribute(\"height\", String(qr.modules.size + margin * 2));\n\n // Override colors to use CSS variables\n const backgroundPath = svgNode.querySelector(\"[fill]\");\n backgroundPath?.setAttribute(\"fill\", \"var(--xendit-qr-background-color)\");\n const foregroundPath = svgNode.querySelector(\"[stroke]\");\n foregroundPath?.setAttribute(\"stroke\", \"var(--xendit-qr-foreground-color)\");\n\n return svgNode;\n}\n","import { useCallback, useLayoutEffect, useRef } from \"preact/hooks\";\nimport Icon from \"./icon\";\nimport { ComponentChildren, FunctionComponent } from \"preact\";\n\ntype Props = {\n /**\n * Title shown above the border.\n */\n title: string;\n /**\n * Called on close (after animation).\n */\n onClose: () => void;\n /**\n * If true, close the dialog on the next render. The animation will play then onClose will be called.\n */\n close?: boolean;\n children?: ComponentChildren;\n /**\n * if true, the header will float on top of the body content without a dividing line\n */\n seamless?: boolean;\n};\n\nexport const Dialog: FunctionComponent<Props> = (props) => {\n const { title, onClose, children, seamless } = props;\n\n const closeCalledRef = useRef(false);\n const closeAnimationPlaying = useRef(false);\n\n const dialogRef = useRef<HTMLDivElement>(null);\n const backdropRef = useRef<HTMLDivElement>(null);\n\n const supportsAnimation = HTMLElement.prototype.animate !== undefined;\n\n // call close callback only once\n const onCloseSafe = useCallback(() => {\n if (closeCalledRef.current) return;\n closeCalledRef.current = true;\n onClose();\n }, [onClose]);\n\n // play fade-out animation then call close callback\n const onCloseWithAnimation = useCallback(() => {\n if (\n !dialogRef.current ||\n !backdropRef.current ||\n closeAnimationPlaying.current\n ) {\n return;\n }\n closeAnimationPlaying.current = true;\n\n if (!supportsAnimation) {\n onCloseSafe();\n return;\n }\n\n backdropRef.current.animate?.(backdropFadeOutKeyframes, animationOptions);\n const animation = dialogRef.current.animate?.(\n foregroundFadeOutKeyframes,\n animationOptions,\n );\n animation.onfinish = onCloseSafe;\n }, [onCloseSafe, supportsAnimation]);\n\n // play fade-in animation\n useLayoutEffect(() => {\n if (!supportsAnimation) {\n return;\n }\n\n backdropRef.current?.animate?.(backdropFadeKeyframes, animationOptions);\n dialogRef.current?.animate?.(foregroundFadeKeyframes, animationOptions);\n }, [supportsAnimation]);\n\n useLayoutEffect(() => {\n if (props.close) {\n onCloseWithAnimation();\n }\n }, [props.close, onCloseWithAnimation]);\n\n return (\n <div className=\"xendit-dialog-backdrop\" ref={backdropRef}>\n <div className=\"xendit-dialog\" ref={dialogRef}>\n {!seamless ? (\n <div className=\"xendit-dialog-header xendit-text-16 xendit-text-semibold\">\n {title}\n <button aria-label=\"Close\" onClick={onCloseWithAnimation}>\n <Icon name=\"x\" size={20} />\n </button>\n </div>\n ) : (\n <button\n aria-label=\"Close\"\n onClick={onCloseWithAnimation}\n className=\"xendit-dialog-floating-close\"\n >\n <Icon name=\"x\" size={20} />\n </button>\n )}\n <div className=\"xendit-dialog-body\">{children}</div>\n </div>\n </div>\n );\n};\n\nconst animationOptions: EffectTiming = {\n duration: 200,\n easing: \"ease-in-out\",\n fill: \"forwards\",\n};\n\nconst backdropFadeKeyframes: Keyframe[] = [\n {\n backgroundColor: \"rgba(0, 0, 0, 0)\",\n },\n {\n backgroundColor: \"rgba(0, 0, 0, 0.5)\",\n },\n];\nconst backdropFadeOutKeyframes = backdropFadeKeyframes.slice().reverse();\n\nconst foregroundFadeKeyframes: Keyframe[] = [\n {\n opacity: 0,\n transform: `scale(0.9) translateY(-20px)`,\n },\n {\n opacity: 1,\n transform: \"\",\n },\n];\nconst foregroundFadeOutKeyframes = foregroundFadeKeyframes.slice().reverse();\n","import { useLayoutEffect, useRef } from \"preact/hooks\";\nimport { XenditComponents } from \"../public-sdk\";\nimport { Dialog } from \"./dialog\";\nimport { internal } from \"../internal\";\n\ntype Props = {\n sdk: XenditComponents;\n title: string;\n close?: boolean;\n onClose: () => void;\n width: number;\n height: number;\n};\n\nexport default function DefaultActionContainer(props: Props) {\n const { sdk, title, onClose, width, height } = props;\n\n const wrapperRef = useRef<HTMLDivElement>(null);\n useLayoutEffect(() => {\n const component = sdk.createActionContainerComponent(internal);\n wrapperRef.current?.replaceChildren(component);\n return () => {\n sdk.destroyComponent(component);\n };\n }, [sdk]);\n\n return (\n <Dialog title={title} onClose={onClose} close={props.close} seamless>\n <div\n className=\"xendit-default-action-container\"\n ref={wrapperRef}\n style={{\n width: width\n ? `calc(min(100vw - 64px, ${width}px))`\n : \"calc(100vw - 64px)\",\n height: height ? `calc(min(100vh - 64px, ${height}px))` : undefined,\n }}\n />\n </Dialog>\n );\n}\n","import { ComponentChildren, Fragment, FunctionComponent } from \"preact\";\nimport { useState } from \"preact/hooks\";\nimport {\n FormattedString,\n InstructionsStep,\n InstructionsTab,\n Instructions as InstructionsType,\n} from \"../backend-types/instructions\";\nimport classNames from \"classnames\";\n\ntype Props = {\n instructions: InstructionsType;\n};\n\nexport const Instructions: FunctionComponent<Props> = ({ instructions }) => {\n switch (instructions.length) {\n case 0:\n return null;\n case 1:\n return <SingleTabInstructions instruction={instructions[0]} />;\n default:\n return <MultiTabInstructions instructions={instructions} />;\n }\n};\n\nexport const SingleTabInstructions: FunctionComponent<{\n instruction: InstructionsTab;\n}> = (props) => {\n return (\n <div>\n <p className=\"xendit-instructions-single-tab-heading\">\n {props.instruction.title}\n </p>\n <InstructionsSteps instruction={props.instruction} />\n </div>\n );\n};\n\nconst MultiTabInstructions: FunctionComponent<{\n instructions: InstructionsType;\n}> = (props) => {\n const [selectedTab, setSelectedTab] = useState(0);\n\n return (\n <div>\n <div className=\"xendit-instructions-tab-list\">\n {props.instructions.map((instruction, index) => (\n <button\n key={index}\n className={classNames(\"xendit-instructions-tab-button\", {\n [\"xendit-instructions-active-tab\"]: selectedTab === index,\n })}\n onClick={() => setSelectedTab(index)}\n >\n {instruction.title}\n </button>\n ))}\n </div>\n <InstructionsSteps instruction={props.instructions[selectedTab]} />\n </div>\n );\n};\n\nexport const InstructionsSteps: FunctionComponent<{\n instruction: InstructionsTab;\n}> = (props) => {\n return (\n <ol\n className=\"xendit-instructions-numbered-list\"\n data-testid=\"instructions-steps\"\n >\n {props.instruction.content.map((step, index) => {\n const stepItems = Array.isArray(step) ? step : [step];\n return (\n <li className=\"xendit-instructions-step-li\" key={index}>\n <div className=\"xendit-instructions-step-box\">\n {stepItems.map((s, i) => (\n <Fragment key={i}>{renderStep(s)}</Fragment>\n ))}\n </div>\n </li>\n );\n })}\n </ol>\n );\n};\n\nfunction renderFormattedStringElement(\n el: Element,\n i: number,\n): ComponentChildren {\n const className = classNames({\n [\"xendit-instructions-bold\"]: el.nodeName === \"B\",\n [\"xendit-instructions-italics\"]: el.nodeName === \"I\",\n });\n\n // render the children without wrapping if this is an element we don't want\n if (!className) return renderFormattedStringChildren(el.childNodes);\n\n return (\n <span className={className} key={i}>\n {renderFormattedStringChildren(el.childNodes)}\n </span>\n );\n}\n\nfunction renderFormattedStringChildren(nodes: NodeListOf<ChildNode>) {\n const parts = Array.from(nodes);\n const renderedNodes = parts.map((part, i) => {\n switch (part.nodeType) {\n case Node.TEXT_NODE:\n if (part.textContent === null) return null;\n return part.textContent;\n case Node.ELEMENT_NODE:\n return renderFormattedStringElement(part as Element, i);\n default:\n return null;\n }\n });\n return renderedNodes;\n}\n\nconst domParser = typeof DOMParser !== \"undefined\" ? new DOMParser() : null;\n\nfunction renderFormattedString(text: FormattedString): ComponentChildren {\n try {\n if (!domParser) return text;\n const doc = domParser.parseFromString(text, \"text/html\");\n return renderFormattedStringChildren(doc.body.childNodes);\n } catch (_) {\n return text;\n }\n}\n\nfunction renderStep(step: string | InstructionsStep): ComponentChildren {\n if (typeof step === \"string\") {\n return (\n <p className=\"xendit-instructions-step-item\">\n {renderFormattedString(step)}\n </p>\n );\n }\n\n switch (step.type) {\n case \"text\":\n return renderTextStep(step);\n case \"image\":\n return renderImageStep(step);\n case \"bullets\":\n return renderBulletsStep(step);\n case \"form\":\n return renderFormStep(step);\n case \"table\":\n return renderTableStep(step);\n }\n\n return null;\n}\n\nfunction renderTextStep(step: Extract<InstructionsStep, { type: \"text\" }>) {\n return <p>{renderFormattedString(step.text)}</p>;\n}\n\nfunction renderImageStep(step: Extract<InstructionsStep, { type: \"image\" }>) {\n return (\n <div>\n <img\n src={step.src}\n alt={step.alt || \"\"}\n style={{ height: `${step.height ?? 24}px` }}\n />\n </div>\n );\n}\n\nfunction renderBulletsStep(\n step: Extract<InstructionsStep, { type: \"bullets\" }>,\n) {\n return (\n <ul className=\"xendit-instructions-bullet-list\">\n {step.items.map((item, index) => (\n <li key={index}>{renderFormattedString(item)}</li>\n ))}\n </ul>\n );\n}\n\nfunction renderFormStep(step: Extract<InstructionsStep, { type: \"form\" }>) {\n return (\n <div className=\"xendit-instructions-form-card\">\n {step.heading ? (\n <h3 className=\"xendit-instructions-form-heading\">\n {renderFormattedString(step.heading)}\n </h3>\n ) : null}\n {step.fields.map((field, index) => (\n <div className=\"xendit-instructions-form-field\" key={index}>\n <div className=\"xendit-instructions-form-field-label\">\n {renderFormattedString(field.label)}\n </div>\n <div className=\"xendit-instructions-form-field-value\">\n {renderFormattedString(field.value)}\n </div>\n </div>\n ))}\n </div>\n );\n}\n\nfunction renderTableStep(step: Extract<InstructionsStep, { type: \"table\" }>) {\n return (\n <table className=\"xendit-instructions-table\">\n <thead>\n <tr>\n {step.headers.map((header, index) => (\n <th className=\"xendit-instructions-table-header\" key={index}>\n {renderFormattedString(header)}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {step.rows.map((row, rowIndex) => (\n <tr key={rowIndex}>\n {row.map((cell, cellIndex) => (\n <td className=\"xendit-instructions-table-cell\" key={cellIndex}>\n {renderFormattedString(cell)}\n </td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n );\n}\n","import { createContext, FunctionComponent } from \"preact\";\nimport { useContext, useState } from \"preact/hooks\";\n\nexport const TooltipContext = createContext<{\n fire: (text: string) => void;\n text: string;\n}>({\n fire: () => {},\n text: \"\",\n});\n\nexport const TooltipProvider: FunctionComponent = ({ children }) => {\n const [text, setText] = useState(\"\");\n\n const fire = (text: string) => {\n setText(text);\n const timeout = setTimeout(() => {\n setText(\"\");\n }, 2000);\n return () => clearTimeout(timeout);\n };\n\n return (\n <TooltipContext.Provider value={{ text, fire }}>\n <div style={{ position: \"relative\" }}>{children}</div>\n </TooltipContext.Provider>\n );\n};\n\nexport const Tooltip: FunctionComponent = () => {\n const { text } = useContext(TooltipContext);\n\n if (!text) {\n return null;\n }\n\n return <div className=\"xendit-tooltip\">{text}</div>;\n};\n","import { FunctionComponent } from \"preact\";\nimport { useCallback, useContext, useState } from \"preact/hooks\";\nimport { amountFormat } from \"../amount-format\";\nimport { Instructions as InstructionsType } from \"../backend-types/instructions\";\nimport { TFunction } from \"../localization\";\nimport {\n Button,\n ButtonLoadingSpinner,\n ButtonSize,\n ButtonVariant,\n} from \"./button\";\nimport Icon from \"./icon\";\nimport { Instructions } from \"./instructions\";\nimport { Tooltip, TooltipContext, TooltipProvider } from \"./tooltip\";\n\ntype Props = {\n amount: number;\n channelLogo: string;\n currency: string;\n onAffirm: () => void;\n vaNumber: string;\n merchantName: string;\n instructions: InstructionsType;\n title: string;\n t: TFunction;\n};\n\nexport function ActionVa(props: Props) {\n const {\n amount,\n channelLogo,\n currency,\n onAffirm,\n vaNumber,\n merchantName,\n instructions,\n title,\n t,\n } = props;\n\n const [showSpinner, setShowSpinner] = useState(false);\n\n const onMadePaymentClicked = useCallback(() => {\n setShowSpinner(true);\n onAffirm();\n }, [onAffirm]);\n\n const vaDetails = [\n {\n heading: t(\"action_va.merchant_name\"),\n value: merchantName,\n },\n {\n heading: t(\"action_va.virtual_account_number\"),\n value: vaNumber,\n enableCopy: true,\n },\n {\n heading: t(\"action_va.amount_to_pay\"),\n value: amountFormat(amount, currency),\n enableCopy: true,\n },\n ];\n\n return (\n <div className=\"xendit-action-present-to-customer\">\n <img\n src={channelLogo}\n alt=\"Channel Logo\"\n className=\"xendit-action-qr-channel-logo\"\n />\n <div className=\"xendit-action-title\">{title}</div>\n <div className=\"xendit-action-va-content\">\n <div className=\"xendit-action-va-details\">\n {vaDetails.map((detail, index) => (\n <div key={index} className=\"xendit-action-va-detail-item\">\n <div className=\"xendit-action-va-detail-content\">\n <div className=\"xendit-action-va-heading xendit-text-12 xendit-text-semibold\">\n {detail.heading}\n </div>\n <div className=\"xendit-action-va-value xendit-text-semibold\">\n {detail.value}\n </div>\n </div>\n {detail.enableCopy ? (\n <TooltipProvider>\n <CopyButton value={detail.value} t={t} />\n <Tooltip />\n </TooltipProvider>\n ) : null}\n </div>\n ))}\n </div>\n </div>\n <div className=\"xendit-action-present-to-customer-affirm\">\n <Button\n variant={ButtonVariant.WHITE_ROUNDED}\n disabled={showSpinner}\n onClick={onMadePaymentClicked}\n className=\"xendit-button-block\"\n >\n {showSpinner ? <ButtonLoadingSpinner /> : t(\"action.payment_made\")}\n </Button>\n <div className=\"xendit-text-12 xendit-text-secondary xendit-text-center\">\n {t(\"action.payment_confirmation_instructions\")}\n </div>\n </div>\n <Instructions instructions={instructions} />\n </div>\n );\n}\n\nconst CopyButton: FunctionComponent<{ value: string; t: TFunction }> = ({\n value,\n t,\n}) => {\n const { fire } = useContext(TooltipContext);\n\n return (\n <Button\n variant={ButtonVariant.WHITE_ROUNDED}\n size={ButtonSize.SM}\n onClick={() => {\n navigator.clipboard.writeText(value);\n fire(t(\"action_va.copied_to_clipboard\"));\n }}\n >\n {t(\"action_va.copy\")}\n <Icon name=\"copy\" size={16} />\n </Button>\n );\n};\n","import { Instructions } from \"./instructions\";\n\nexport type BffAction =\n | {\n type: \"PRESENT_TO_CUSTOMER\";\n descriptor: \"PAYMENT_CODE\" | \"QR_STRING\" | \"VIRTUAL_ACCOUNT_NUMBER\";\n value: string;\n action_title: string;\n action_subtitle: string;\n action_graphic: string;\n instructions?: Instructions | null;\n }\n | {\n type: \"REDIRECT_CUSTOMER\";\n descriptor: \"WEB_URL\" | \"DEEPLINK_URL\" | \"WEB_GOOGLE_PAYLINK\";\n value: string;\n // indicates whether the redirect URL can be opened in an iframe\n // defaults to true since this isn't returned from backend yet\n // TODO: return this flag from backend\n iframe_capable?: boolean;\n }\n | {\n type: \"API_POST_REQUEST\";\n descriptor: \"CAPTURE_PAYMENT\" | \"VALIDATE_OTP\" | \"RESEND_OTP\";\n value: string;\n otp?: {\n title: string;\n instructions: string;\n };\n };\n\nexport type BffPaymentTokenStatus =\n | \"REQUIRES_ACTION\"\n | \"PENDING\"\n | \"ACTIVE\"\n | \"FAILED\"\n | \"EXPIRED\"\n | \"CANCELED\";\n\nexport type BffPaymentTokenFailureCode =\n | \"ACCOUNT_ALREADY_LINKED\"\n | \"INVALID_ACCOUNT_DETAILS\"\n | \"AUTHENTICATION_FAILED\"\n | \"CARD_DECLINED\"\n | \"CAPTURE_AMOUNT_EXCEEDED\"\n | \"INSUFFICIENT_BALANCE\"\n | \"ISSUER_UNAVAILABLE\"\n | \"CHANNEL_UNAVAILABLE\"\n | \"INVALID_MERCHANT_SETTINGS\";\n\nexport type BffPaymentToken = {\n payment_token_id: string;\n status: BffPaymentTokenStatus;\n failure_code?: BffPaymentTokenFailureCode;\n actions: BffAction[];\n channel_code: string;\n /**\n * Only returned when the payment request is created, not on polling\n */\n session_token_request_id?: string;\n};\n\nexport type BffPaymentRequestStatus =\n | \"ACCEPTING_PAYMENTS\"\n | \"REQUIRES_ACTION\"\n | \"PENDING\"\n | \"AUTHORIZED\"\n | \"CANCELED\"\n | \"EXPIRED\"\n | \"SUCCEEDED\"\n | \"FAILED\";\n\nexport type BffPaymentRequestFailureCode =\n | \"ACCOUNT_ACCESS_BLOCKED\"\n | \"INVALID_MERCHANT_SETTINGS\"\n | \"INVALID_ACCOUNT_DETAILS\"\n | \"PAYMENT_ATTEMPT_COUNTS_EXCEEDED\"\n | \"USER_DEVICE_UNREACHABLE\"\n | \"CHANNEL_UNAVAILABLE\"\n | \"INSUFFICIENT_BALANCE\"\n | \"ACCOUNT_NOT_ACTIVATED\"\n | \"INVALID_TOKEN\"\n | \"SERVER_ERROR\"\n | \"PARTNER_TIMEOUT_ERROR\"\n | \"TIMEOUT_ERROR\"\n | \"USER_DECLINED_PAYMENT\"\n | \"USER_DID_NOT_AUTHORIZE\"\n | \"PAYMENT_REQUEST_EXPIRED\"\n | \"FAILURE_DETAILS_UNAVAILABLE\"\n | \"EXPIRED_OTP\"\n | \"INVALID_OTP\"\n | \"PAYMENT_AMOUNT_LIMITS_EXCEEDED\"\n | \"OTP_ATTEMPT_COUNTS_EXCEEDED\"\n | \"CARD_DECLINED\"\n | \"DECLINED_BY_ISSUER\"\n | \"ISSUER_UNAVAILABLE\"\n | \"INVALID_CVV\"\n | \"DECLINED_BY_PROCESSOR\"\n | \"CAPTURE_AMOUNT_EXCEEDED\"\n | \"AUTHENTICATION_FAILED\";\n\nexport type BffPaymentRequest = {\n payment_request_id: string;\n status: BffPaymentRequestStatus;\n failure_code?: BffPaymentRequestFailureCode;\n actions: BffAction[];\n channel_code: string;\n /**\n * Only returned when the payment request is created, not on polling\n */\n session_token_request_id?: string;\n};\n\nexport enum BffPaymentEntityType {\n PaymentRequest = \"REQUEST\",\n PaymentToken = \"TOKEN\",\n}\n\nexport type BffPaymentEntity =\n | {\n id: string;\n type: BffPaymentEntityType.PaymentRequest;\n entity: BffPaymentRequest;\n }\n | {\n id: string;\n type: BffPaymentEntityType.PaymentToken;\n entity: BffPaymentToken;\n };\n\nexport function toPaymentEntity(\n prOrPt: BffPaymentRequest | BffPaymentToken,\n): BffPaymentEntity {\n if (\"payment_request_id\" in prOrPt) {\n return {\n id: prOrPt.payment_request_id,\n type: BffPaymentEntityType.PaymentRequest,\n entity: prOrPt,\n };\n } else {\n return {\n id: prOrPt.payment_token_id,\n type: BffPaymentEntityType.PaymentToken,\n entity: prOrPt,\n };\n }\n}\n\nexport function getFailureCodeCopyKey<\n T extends NonNullable<\n BffPaymentRequestFailureCode | BffPaymentTokenFailureCode\n >,\n>(failureCode: T) {\n return `failure_code.${failureCode.toLowerCase() as Lowercase<T>}` as const;\n}\n\nexport function getPaymentEntityStatusCopyKey<\n T extends\n | BffPaymentEntityType.PaymentRequest\n | BffPaymentEntityType.PaymentToken,\n S extends \"FAILED\" | \"EXPIRED\" | \"CANCELED\",\n const Suffix extends string,\n>(entityType: T, status: S, suffix: Suffix) {\n const t =\n entityType === BffPaymentEntityType.PaymentRequest\n ? \"payment_request\"\n : \"payment_token\";\n return `${t}_status.${\n status.toLowerCase() as Lowercase<S>\n }.${suffix}` as const;\n}\n","import {\n BffChannel,\n MockActionType,\n MockActionTypeSingle,\n} from \"../backend-types/channel\";\nimport { BffPollResponse } from \"../backend-types/common\";\nimport {\n BffAction,\n BffPaymentEntity,\n BffPaymentEntityType,\n BffPaymentRequest,\n BffPaymentRequestStatus,\n BffPaymentToken,\n BffPaymentTokenStatus,\n} from \"../backend-types/payment-entity\";\nimport { BffPaymentOptions } from \"../backend-types/payment-options\";\nimport { BffSession } from \"../backend-types/session\";\nimport { WorldState } from \"../public-sdk\";\nimport { assert, randomHexString, randomUUID } from \"../utils\";\n\nconst examplePublicKey =\n \"MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEyCADI5pdf6KmN8+Fxl2ES3yolUKXunNeY3gGScGNEvDcrcHAPKxIInAo5DVnDvTtYtqZvx/bu7HLeBJNMXwHhie/uyNEtT8dSaLc9bd0WSlYdxI+iUsTv2Qu0LiiPrZs\";\nconst exampleSignature =\n \"NKf7whM9meUs/eRCvG0oc180MDiyeli3kH6EQ3ZahECHsZQi5G2IpH6vk3cYMtf01Y1L4OBn1SZCOv1kwpjIUet4DJeoTwwq2nM5b+K7rD+/WFTi3AEX4NWJNkKi0a91\";\n\nexport function makeTestSdkKey() {\n return `session-${randomHexString(32)}-mock-${examplePublicKey}-${exampleSignature}`;\n}\n\nexport function makeTestPollResponse(\n world: WorldState,\n channel: BffChannel | null,\n result: \"SUCCESS\" | \"FAILURE\" | \"PENDING\" | \"PENDING_PAYMENT_ENTITY_ONLY\",\n) {\n const { session, paymentEntity } = world;\n assert(session);\n assert(paymentEntity);\n assert(channel);\n\n switch (result) {\n case \"PENDING\":\n // make the session pending\n return makeTestPollResponseForPending(session);\n case \"PENDING_PAYMENT_ENTITY_ONLY\":\n // make the payment entity pending, but keep the session active\n return makeTestPollResponseForPendingPaymentEntityOnly(\n session,\n paymentEntity,\n );\n case \"SUCCESS\": {\n if (channel._mock_action_type === \"PENDING\") {\n // channels with mock pending state (like FPX) always go to pending state when success is requested\n return makeTestPollResponseForPending(session);\n } else {\n return makeTestPollResponseForSuccess(session, paymentEntity);\n }\n }\n case \"FAILURE\":\n return makeTestPollResponseForFailure(session, paymentEntity);\n }\n}\n\nexport function makeTestPollResponseForPending(\n session: BffSession,\n): BffPollResponse {\n return {\n session: {\n ...session,\n status: \"PENDING\",\n },\n };\n}\n\nexport function makeTestPollResponseForPendingPaymentEntityOnly(\n session: BffSession,\n paymentEntity: BffPaymentEntity,\n): BffPollResponse {\n const paymentRequest =\n paymentEntity.type === BffPaymentEntityType.PaymentRequest\n ? paymentEntity.entity\n : undefined;\n const paymentToken =\n paymentEntity.type === BffPaymentEntityType.PaymentToken\n ? paymentEntity.entity\n : undefined;\n\n return {\n session,\n payment_request: withPaymentEntityStatus(paymentRequest, \"PENDING\"),\n payment_token: withPaymentEntityStatus(paymentToken, \"PENDING\"),\n };\n}\n\nexport function makeTestPollResponseForSuccess(\n session: BffSession,\n paymentEntity: BffPaymentEntity,\n): BffPollResponse {\n const paymentRequest =\n paymentEntity.type === BffPaymentEntityType.PaymentRequest\n ? paymentEntity.entity\n : undefined;\n const paymentToken =\n paymentEntity.type === BffPaymentEntityType.PaymentToken\n ? paymentEntity.entity\n : undefined;\n\n return {\n session: {\n ...session,\n status: \"COMPLETED\",\n payment_request_id: paymentRequest?.payment_request_id,\n payment_token_id: paymentToken?.payment_token_id,\n },\n payment_request: withPaymentEntityStatus(paymentRequest, \"SUCCEEDED\"),\n payment_token: withPaymentEntityStatus(paymentToken, \"ACTIVE\"),\n succeeded_channel: {\n channel_code: paymentEntity.entity.channel_code,\n logo_url: \"https://placehold.co/48\",\n },\n };\n}\n\nexport function makeTestPollResponseForFailure(\n session: BffSession,\n paymentEntity: BffPaymentEntity,\n): BffPollResponse {\n const paymentRequest =\n paymentEntity.type === BffPaymentEntityType.PaymentRequest\n ? paymentEntity.entity\n : undefined;\n const paymentToken =\n paymentEntity.type === BffPaymentEntityType.PaymentToken\n ? paymentEntity.entity\n : undefined;\n\n return {\n session: {\n ...session,\n status: \"ACTIVE\",\n },\n payment_request: withPaymentEntityStatus(paymentRequest, \"FAILED\"),\n payment_token: withPaymentEntityStatus(paymentToken, \"FAILED\"),\n };\n}\n\nexport function withPaymentEntityStatus<\n T extends BffPaymentRequest | BffPaymentToken | undefined,\n>(\n prOrPt: T,\n status: T extends BffPaymentRequest\n ? BffPaymentRequestStatus\n : T extends BffPaymentToken\n ? BffPaymentTokenStatus\n : undefined,\n): T {\n if (!prOrPt) return prOrPt;\n return {\n ...prOrPt,\n status: status,\n };\n}\n\nexport function makeTestPaymentRequest(\n channelCode: string,\n mockActionType: MockActionType | undefined,\n): BffPaymentRequest {\n if (mockActionType === \"PENDING\") {\n return {\n payment_request_id: `pr-${randomUUID()}`,\n status: \"PENDING\",\n channel_code: channelCode,\n actions: [],\n session_token_request_id: randomUUID(),\n };\n } else if (mockActionType) {\n return {\n payment_request_id: `pr-${randomUUID()}`,\n status: \"REQUIRES_ACTION\",\n channel_code: channelCode,\n actions: makeMockActions(mockActionType),\n session_token_request_id: randomUUID(),\n };\n } else {\n return {\n payment_request_id: `pr-${randomUUID()}`,\n status: \"SUCCEEDED\",\n channel_code: channelCode,\n actions: [],\n session_token_request_id: randomUUID(),\n };\n }\n}\n\nexport function makeTestPaymentToken(\n channelCode: string,\n mockActionType: MockActionType | undefined,\n): BffPaymentToken {\n if (mockActionType === \"PENDING\") {\n return {\n payment_token_id: `pt-${randomUUID()}`,\n status: \"PENDING\",\n channel_code: channelCode,\n actions: makeMockActions(mockActionType),\n session_token_request_id: randomUUID(),\n };\n } else if (mockActionType) {\n return {\n payment_token_id: `pt-${randomUUID()}`,\n status: \"REQUIRES_ACTION\",\n channel_code: channelCode,\n actions: makeMockActions(mockActionType),\n session_token_request_id: randomUUID(),\n };\n } else {\n return {\n payment_token_id: `pt-${randomUUID()}`,\n status: \"ACTIVE\",\n channel_code: channelCode,\n actions: [],\n session_token_request_id: randomUUID(),\n };\n }\n}\n\nexport function makeMockActions(\n mockActionType: MockActionType | undefined,\n): BffAction[] {\n if (!mockActionType) return [];\n const mockActionArray = Array.isArray(mockActionType)\n ? mockActionType\n : [mockActionType];\n const mockActions = mockActionArray\n .map((actionType) => makeOneMockAction(actionType))\n .filter((action) => action !== null);\n return mockActions;\n}\n\nexport function makeOneMockAction(\n mockActionType: MockActionTypeSingle,\n): BffAction | null {\n if (mockActionType === \"PENDING\") {\n throw new Error(\"PENDING mock action type should not generate an action\");\n }\n\n switch (mockActionType) {\n case \"IFRAME\":\n return {\n type: \"REDIRECT_CUSTOMER\",\n descriptor: \"WEB_URL\",\n value: \"https://example.com/iframe\",\n iframe_capable: true,\n };\n case \"REDIRECT\":\n return {\n type: \"REDIRECT_CUSTOMER\",\n descriptor: \"WEB_URL\",\n value: \"https://example.com/redirect\",\n iframe_capable: false,\n };\n case \"PAYLINK\":\n return {\n type: \"REDIRECT_CUSTOMER\",\n descriptor: \"WEB_GOOGLE_PAYLINK\",\n value: \"https://example.com/paylink\",\n };\n case \"DEEP_LINK\":\n return {\n type: \"REDIRECT_CUSTOMER\",\n descriptor: \"DEEPLINK_URL\",\n value: \"mockapp://mock-deep-link\",\n };\n case \"PUSH_NOTIFICATION\": {\n // push notification actions are represented by setting `{ status: \"REQUIRES_ACTION\", actions: [] }`\n return null;\n }\n case \"QR\":\n return {\n type: \"PRESENT_TO_CUSTOMER\",\n descriptor: \"QR_STRING\",\n value: \"https://example.com/qr-code-data\",\n action_title: \"Pay with QR Code\",\n action_subtitle: \"Scan the QR code below\",\n action_graphic: \"\",\n instructions: null,\n };\n case \"BARCODE\":\n return {\n type: \"PRESENT_TO_CUSTOMER\",\n descriptor: \"PAYMENT_CODE\",\n value: \"1234567890\",\n action_title: \"Pay at a Store\",\n action_subtitle: \"Show this barcode to the cashier\",\n action_graphic: \"\",\n instructions: null,\n };\n case \"VA\":\n return {\n type: \"PRESENT_TO_CUSTOMER\",\n descriptor: \"VIRTUAL_ACCOUNT_NUMBER\",\n value: \"1234567890\",\n action_title: \"Pay with Virtual Account\",\n action_subtitle:\n \"Protect yourself from fraud - ensure all details are correct\",\n action_graphic: \"\",\n instructions: [\n {\n title: \"Mobile Banking\",\n content: [\n {\n type: \"text\",\n text: \"Open Mobile App\",\n },\n {\n type: \"text\",\n text: \"Select <b>Mock VA</b>, then select <b>Transfer</b>\",\n },\n {\n type: \"text\",\n text: \"Enter your Virtual Account Number, for example 3816523906568, then press <b>OK</b>\",\n },\n {\n type: \"text\",\n text: \"Click on <b>Send</b> button at the top right corner to proceed\",\n },\n {\n type: \"text\",\n text: \"Click <b>OK</b> to proceed\",\n },\n {\n type: \"text\",\n text: \"Enter your PIN to authorize the transaction\",\n },\n ],\n },\n {\n title: \"Internet Banking\",\n content: [\n {\n type: \"text\",\n text: \"Login to the website\",\n },\n {\n type: \"text\",\n text: \"Select <b>Transfer</b>, then select <b>Transfer to Mock VA Virtual Account</b>\",\n },\n {\n type: \"text\",\n text: \"Enter the Virtual Account Number, for example 3816523906568\",\n },\n {\n type: \"text\",\n text: \"Select <b>Continue</b> to proceed your payment\",\n },\n ],\n },\n {\n title: \"ATM\",\n content: [\n {\n type: \"text\",\n text: \"Insert your ATM card and PIN\",\n },\n {\n type: \"text\",\n text: \"Enter your ATM PIN\",\n },\n {\n type: \"text\",\n text: \"Select <b>Transfer</b>\",\n },\n {\n type: \"text\",\n text: \"Select <b>To Mock VA Virtual Account</b>\",\n },\n {\n type: \"text\",\n text: \"Enter Virtual Account Number, for example 3816523906568. Press <b>Correct</b> to proceed\",\n },\n {\n type: \"text\",\n text: \"Verify Virtual Account details and then enter amount to be transferred and select <b>Correct</b> to confirm\",\n },\n {\n type: \"text\",\n text: \"Confirm your transaction details displayed\",\n },\n {\n type: \"text\",\n text: \"Select <b>Yes</b> if the details are correct or <b>No</b> if the details are not correct\",\n },\n ],\n },\n ],\n };\n }\n\n mockActionType satisfies never;\n throw new Error(`Unknown mock action type: ${mockActionType}`);\n}\n\nexport function makeMockPaymentOptions(\n channelCode: string,\n session: BffSession,\n): BffPaymentOptions {\n return {\n channel_code: channelCode,\n country: session.country,\n currency: session.currency,\n amount: session.amount,\n installment_plans: [\n {\n interval: \"MONTH\",\n interval_count: 1,\n terms: 3,\n installment_amount: Math.floor(session.amount / 3),\n total_amount: session.amount,\n description: `Unused`,\n code: \"3M\",\n interest_rate: 1,\n },\n {\n interval: \"MONTH\",\n interval_count: 1,\n terms: 6,\n installment_amount: Math.floor(session.amount / 6),\n total_amount: session.amount,\n description: `Unused`,\n code: \"6M\",\n interest_rate: 1,\n },\n {\n interval: \"MONTH\",\n interval_count: 1,\n terms: 9,\n installment_amount: Math.floor(session.amount / 9),\n total_amount: session.amount,\n description: `Unused`,\n interest_rate: 1,\n code: undefined, // this item has no code (like TH installment channels)\n },\n ],\n };\n}\n","import { FunctionComponent } from \"preact\";\n\ntype Props = {\n title: string;\n subtitle?: string;\n logoUrl: string;\n logoAlt: string;\n redirectUrl: string | null;\n redirectButtonLabel: string | null;\n};\n\nconst RedirectInstructions: FunctionComponent<Props> = (props) => {\n return (\n <div className=\"xendit-redirect-instructions\">\n <div className=\"xendit-redirect-instructions-logo\">\n <img src={props.logoUrl} alt={props.logoAlt} />\n </div>\n\n <div className=\"xendit-redirect-instructions-text\">\n <div className=\"xendit-text-16\">{props.title}</div>\n {props.subtitle ? (\n <div className=\"xendit-text-14 xendit-text-secondary\">\n {props.subtitle}\n </div>\n ) : null}\n </div>\n\n {props.redirectUrl ? (\n <a\n href={props.redirectUrl}\n className=\"xendit-redirect-instructions-button xendit-text-14\"\n >\n {props.redirectButtonLabel ?? \"\"}\n </a>\n ) : null}\n </div>\n );\n};\n\nexport { RedirectInstructions };\n","import { FunctionComponent } from \"preact\";\nimport { RedirectInstructions } from \"./redirect-instructions\";\nimport { TFunction } from \"../localization\";\nimport { BffChannel } from \"../backend-types/channel\";\n\ntype Props = {\n t: TFunction;\n channel: BffChannel;\n};\n\nexport const ActionEmptyListPushNotification: FunctionComponent<Props> = (\n props,\n) => {\n const t = props.t;\n const channel = props.channel;\n const channelName = channel.brand_name;\n\n return (\n <RedirectInstructions\n title={t(\"action_empty_list_push_notification.title\")}\n subtitle={t(\"action_empty_list_push_notification.subtext\", {\n channelName,\n })}\n logoUrl={channel.brand_logo_url}\n logoAlt={t(\"image_alt.channel_logo\", {\n channelName,\n })}\n redirectUrl={null}\n redirectButtonLabel={null}\n />\n );\n};\n","import { FunctionComponent } from \"preact\";\nimport { RedirectInstructions } from \"./redirect-instructions\";\nimport { TFunction } from \"../localization\";\nimport { BffChannel } from \"../backend-types/channel\";\n\ntype Props = {\n t: TFunction;\n channel: BffChannel;\n redirectUrl: string | null;\n};\n\nexport const ActionDeepLink: FunctionComponent<Props> = (props) => {\n const t = props.t;\n const channel = props.channel;\n const channelName = channel.brand_name;\n\n return (\n <RedirectInstructions\n title={t(\"action_deeplink.title\")}\n subtitle={t(\"action_deeplink.instructions\", {\n channelName,\n })}\n logoUrl={channel.brand_logo_url}\n logoAlt={t(\"image_alt.channel_logo\", {\n channelName,\n })}\n redirectUrl={props.redirectUrl}\n redirectButtonLabel={t(\"action_deeplink.button\", {\n channelName,\n })}\n />\n );\n};\n","import { createElement, render, ComponentChildren } from \"preact\";\nimport { IframeActionCompleteEvent } from \"../../../../shared/types\";\nimport {\n InternalBehaviorTreeUpdateEvent,\n InternalScheduleMockUpdateEvent,\n} from \"../../private-event-types\";\nimport { XenditWillRedirectEvent } from \"../../public-event-types\";\nimport { assert, assertEquals } from \"../../utils\";\nimport { BlackboardType } from \"../behavior-tree\";\nimport { Behavior } from \"../behavior-tree-runner\";\nimport { ActionIframe } from \"../../components/action-iframe\";\nimport { ActionQr } from \"../../components/action-qr\";\nimport { internal } from \"../../internal\";\nimport DefaultActionContainer from \"../../components/default-action-container\";\nimport { ActionVa } from \"../../components/action-va\";\nimport { makeTestPollResponse } from \"../../data/test-data-modifiers\";\nimport { ActionEmptyListPushNotification } from \"../../components/action-empty-list-push-notification\";\nimport { ActionDeepLink } from \"../../components/action-deep-link\";\n\nabstract class ContainerActionBehavior implements Behavior {\n cleanupFn: ((cancelledByUser: boolean) => void) | null = null;\n defaultContainerHeight = 0;\n defaultContainerWidth = 400;\n title = \"Complete your payment\";\n\n constructor(protected bb: BlackboardType) {}\n\n /**\n * Creates a default action container if the user has not created one already.\n * Returns a cleanup function that destroys the default action container if it was created.\n */\n ensureHasActionContainer() {\n if (this.bb.sdk[internal].liveComponents.actionContainer) {\n // user created action container already\n // TODO: validate it's in the dom and the right size\n return () => {\n this.emptyActionContainer();\n };\n }\n\n let cleanedUp = false;\n let success = false;\n\n const container = document.createElement(\"div\");\n container.setAttribute(\"class\", \"xendit-default-action-container\");\n\n const props = {\n sdk: this.bb.sdk,\n title: this.title,\n width: this.defaultContainerWidth,\n height: this.defaultContainerHeight,\n onClose: () => {\n cleanedUp = true;\n render(null, container);\n container.remove();\n if (!success) {\n this.bb.sdk.abortSubmission();\n }\n },\n };\n render(createElement(DefaultActionContainer, props), container);\n document.body.appendChild(container);\n\n // Cleanup function\n // (if actionCancelledByUser is true, abort the submission after the modal closes)\n return (actionCancelledByUser: boolean) => {\n if (!actionCancelledByUser) {\n success = true;\n }\n\n if (cleanedUp) return;\n\n // make the dialog play its close animation before removing it\n render(\n createElement(DefaultActionContainer, {\n ...props,\n close: true,\n }),\n container,\n );\n };\n }\n\n cleanupActionContainer(cancelledByUser: boolean) {\n if (this.cleanupFn) {\n this.cleanupFn(cancelledByUser);\n this.cleanupFn = null;\n }\n }\n\n emptyActionContainer() {\n const container = this.bb.sdk[internal].liveComponents.actionContainer;\n if (container) {\n render(null, container);\n }\n }\n\n updateActionContainerBrandColor() {\n assert(this.bb.channel);\n\n const container = this.bb.sdk[internal].liveComponents.actionContainer;\n if (container) {\n container.style.setProperty(\n \"--xendit-channel-brand-color\",\n this.bb.channel.brand_color,\n );\n }\n }\n\n /**\n * Populates the action container with the provided component.\n * This method handles the common logic of getting the container and rendering the component.\n */\n populateActionContainer(createComponent: () => ComponentChildren) {\n const container = this.bb.sdk[internal].liveComponents.actionContainer;\n if (!container) {\n throw new Error(\n \"Trying to populate action container, but it is missing; A default action container should have been created. This is a bug, please contact support.\",\n );\n }\n\n this.updateActionContainerBrandColor();\n\n render(createComponent(), container);\n }\n\n exit() {\n this.cleanupActionContainer(false);\n this.emptyActionContainer();\n }\n}\n\nexport class ActionCompletedBehavior implements Behavior {\n constructor(private bb: BlackboardType) {}\n enter() {}\n}\n\nexport class ActionRedirectBehavior implements Behavior {\n constructor(\n private bb: BlackboardType,\n private url: string,\n ) {}\n\n enter() {\n this.bb.dispatchEvent(new XenditWillRedirectEvent());\n window.location.href = this.url;\n }\n}\n\nexport class ActionIframeBehavior extends ContainerActionBehavior {\n constructor(\n protected bb: BlackboardType,\n private url: string,\n ) {\n super(bb);\n this.defaultContainerHeight = 600;\n }\n\n enter() {\n this.cleanupFn = this.ensureHasActionContainer();\n this.populateActionContainer(() =>\n createElement(ActionIframe, {\n url: this.url,\n mock: this.bb.mock,\n onIframeComplete: (event: IframeActionCompleteEvent) => {\n this.cleanupActionContainer(false);\n\n const mockResult =\n event.mockStatus === \"success\" ? \"SUCCESS\" : \"FAILURE\";\n this.updateMocksOnIframeCompletion(mockResult);\n\n // setting actionCompleted will ensure the action UI isn't shown again\n this.bb.actionCompleted = true;\n // request immediate poll on next update\n this.bb.pollImmediatelyRequested = true;\n\n this.bb.dispatchEvent(new InternalBehaviorTreeUpdateEvent());\n },\n }),\n );\n }\n\n updateMocksOnIframeCompletion(result: \"SUCCESS\" | \"FAILURE\") {\n assert(this.bb.world?.paymentEntity);\n if (this.bb.mock) {\n this.bb.dispatchEvent(\n new InternalScheduleMockUpdateEvent(\n makeTestPollResponse(this.bb.world, this.bb.channel, result),\n ),\n );\n }\n }\n\n exit() {\n super.exit();\n }\n}\n\nexport class ActionQrBehavior extends ContainerActionBehavior {\n constructor(\n protected bb: BlackboardType,\n private actionIndex: string,\n ) {\n super(bb);\n }\n\n enter() {\n const qrAction =\n this.bb.world?.paymentEntity?.entity.actions[Number(this.actionIndex)];\n\n assertEquals(qrAction?.type, \"PRESENT_TO_CUSTOMER\");\n assert(this.bb.world);\n assert(this.bb.channel);\n\n const container = this.bb.sdk[internal].liveComponents.actionContainer;\n\n const actionQrProps = {\n amount: this.bb.world.session.amount,\n businessName: this.bb.world.business.name ?? \"\",\n channelLogo: this.bb.channel.brand_logo_url,\n currency: this.bb.world.session.currency,\n hideUi: container?.getAttribute(\"data-qr-code-only\") === \"true\" || false,\n onAffirm: this.affirmPayment.bind(this),\n qrString: qrAction.value,\n title: qrAction.action_subtitle,\n t: this.bb.sdk.t.bind(this.bb.sdk),\n };\n\n this.cleanupFn = this.ensureHasActionContainer();\n this.populateActionContainer(() => createElement(ActionQr, actionQrProps));\n }\n\n /**\n * Fired when user affirms they have made the payment by clicking\n * the affirm button.\n */\n affirmPayment() {\n if (this.bb.sdk.isProdLive()) {\n // live mode\n this.bb.pollImmediatelyRequested = true;\n } else {\n this.bb.simulatePaymentRequested = true;\n }\n this.bb.dispatchEvent(new InternalBehaviorTreeUpdateEvent());\n }\n\n exit() {\n super.exit();\n }\n}\n\n/**\n * An empty list of actions means the user has to take some action on their own, like tapping a push notification.\n */\nexport class ActionDeepLinkBehavior extends ContainerActionBehavior {\n constructor(\n protected bb: BlackboardType,\n private actionIndex: string,\n ) {\n super(bb);\n }\n\n enter() {\n assert(this.bb.world);\n\n const deepLinkAction =\n this.bb.world?.paymentEntity?.entity.actions[Number(this.actionIndex)];\n assertEquals(deepLinkAction?.type, \"REDIRECT_CUSTOMER\");\n\n if (\n deepLinkAction.descriptor !== \"DEEPLINK_URL\" &&\n deepLinkAction.descriptor !== \"WEB_URL\"\n ) {\n // The deeplink popup can also handle regular web urls (if paylinks are enabled, that's useful to prevent auto-redirects)\n throw new Error(\"Unexpected action type in ActionDeepLinkBehavior\");\n }\n\n const t = this.bb.sdk.t.bind(this.bb.sdk);\n const channel = this.bb.channel;\n assert(channel);\n\n this.cleanupFn = this.ensureHasActionContainer();\n this.populateActionContainer(() => {\n return createElement(ActionDeepLink, {\n t,\n channel,\n redirectUrl: deepLinkAction.value,\n });\n });\n }\n\n exit() {\n super.exit();\n }\n}\n\n/**\n * An empty list of actions means the user has to take some action on their own, like tapping a push notification.\n */\nexport class ActionEmptyListPushNotificationBehavior extends ContainerActionBehavior {\n constructor(protected bb: BlackboardType) {\n super(bb);\n }\n\n enter() {\n assert(this.bb.world);\n\n // Keep this behavior alive even if the payment entity status changes to pending.\n // Normally, the status would change to pending almost immediently and the action would be closed.\n // This helps keep it open until the user pays.\n this.bb.hackyOvoActionLatch = true;\n\n const t = this.bb.sdk.t.bind(this.bb.sdk);\n const channel = this.bb.channel;\n assert(channel);\n\n this.cleanupFn = this.ensureHasActionContainer();\n this.populateActionContainer(() => {\n return createElement(ActionEmptyListPushNotification, {\n t,\n channel,\n });\n });\n\n if (this.bb.mock) {\n this.bb.dispatchEvent(\n new InternalScheduleMockUpdateEvent(\n makeTestPollResponse(\n this.bb.world,\n this.bb.channel,\n \"PENDING_PAYMENT_ENTITY_ONLY\",\n ),\n ),\n );\n }\n }\n\n exit() {\n this.bb.hackyOvoActionLatch = undefined;\n super.exit();\n }\n}\nexport class ActionVaBehavior extends ContainerActionBehavior {\n constructor(\n protected bb: BlackboardType,\n private actionIndex: string,\n ) {\n super(bb);\n }\n\n enter() {\n const vaAction =\n this.bb.world?.paymentEntity?.entity.actions[Number(this.actionIndex)];\n\n assertEquals(vaAction?.type, \"PRESENT_TO_CUSTOMER\");\n assert(this.bb.world);\n assert(this.bb.channel);\n\n const actionVaProps = {\n amount: this.bb.world.session.amount,\n channelLogo: this.bb.channel.brand_logo_url,\n currency: this.bb.world.session.currency,\n onAffirm: this.affirmPayment.bind(this),\n vaNumber: vaAction.value,\n merchantName: this.bb.world.business.name ?? \"\",\n instructions: vaAction.instructions ?? [],\n title: vaAction.action_title,\n t: this.bb.sdk.t.bind(this.bb.sdk),\n };\n\n this.cleanupFn = this.ensureHasActionContainer();\n this.populateActionContainer(() => createElement(ActionVa, actionVaProps));\n }\n\n /**\n * Fired when user affirms they have made the payment by clicking\n * the affirm button.\n */\n affirmPayment() {\n if (this.bb.sdk.isProdLive()) {\n // live mode\n this.bb.pollImmediatelyRequested = true;\n } else {\n this.bb.simulatePaymentRequested = true;\n }\n this.bb.dispatchEvent(new InternalBehaviorTreeUpdateEvent());\n }\n}\n","import { assert, assertEquals } from \"../../utils\";\nimport { BlackboardType } from \"../behavior-tree\";\nimport { Behavior } from \"../behavior-tree-runner\";\n\nexport class ActionPaylinkBehavior implements Behavior {\n private el: HTMLLinkElement | null = null;\n\n constructor(\n public bb: BlackboardType,\n private actionIndex: string,\n ) {}\n\n enter() {\n assert(this.bb.world);\n assert(this.bb.world.paymentEntity);\n\n const action =\n this.bb.world?.paymentEntity?.entity.actions[Number(this.actionIndex)];\n if (!action) {\n throw new Error(\"Action not found for paylink behavior\");\n }\n\n assertEquals(action.type, \"REDIRECT_CUSTOMER\");\n assertEquals(action.descriptor, \"WEB_GOOGLE_PAYLINK\");\n\n const link = document.createElement(\"link\");\n link.rel = \"facilitated-payment\";\n link.href = action.value;\n\n this.el = link;\n document.head.appendChild(link);\n }\n\n exit() {\n this.el?.remove();\n this.el = null;\n }\n}\n","import { lookupCardDetails } from \"../../api\";\nimport { InternalUpdateChannelComponentData } from \"../../private-event-types\";\nimport {\n AbortError,\n cancellableSleep,\n getCardNumberFromChannelProperties,\n isAbortError,\n parseEncryptedFieldValue,\n} from \"../../utils\";\nimport { BlackboardType } from \"../behavior-tree\";\nimport { Behavior } from \"../behavior-tree-runner\";\n\nexport class CardInfoBehavior implements Behavior {\n private cardDetailsRequest: {\n cardNumber: string;\n promise: Promise<void>;\n abortController: AbortController;\n } | null = null;\n\n constructor(\n public bb: BlackboardType,\n private channelCode: string,\n ) {}\n\n enter() {\n this.lookupCardDetails();\n }\n\n update() {\n this.lookupCardDetails();\n }\n\n exit() {\n this.abortLookupCardDetails();\n }\n\n abortLookupCardDetails() {\n if (this.cardDetailsRequest) {\n this.cardDetailsRequest.abortController.abort(new AbortError());\n this.cardDetailsRequest = null;\n }\n }\n\n lookupCardDetails() {\n const cardNumber = getCardNumberFromChannelProperties(\n this.bb.channelProperties,\n );\n if (!cardNumber) {\n return;\n }\n\n // don't look up the card number if a request is in flight for the same card number\n if (this.cardDetailsRequest?.cardNumber === cardNumber) {\n return;\n }\n\n // don't look up the card number if we already have the details\n if (this.bb.channelData?.cardDetails?.cardNumber === cardNumber) {\n return;\n }\n\n if (this.cardDetailsRequest) {\n this.abortLookupCardDetails();\n }\n\n const abortController = new AbortController();\n const promise = cancellableSleep(300, abortController.signal) // debounce\n .then(() => {\n if (this.bb.mock) {\n // in mock mode, if the ciphertext is actually a base64-encoded JSON string, then use that as the mock response\n const encodedError = parseEncryptedFieldValue(cardNumber).cipherText;\n try {\n return JSON.parse(atob(encodedError));\n } catch {\n // not json, ignore\n }\n\n // otherwise, return a fixed mock response\n return {\n schemes: [\"VISA\"],\n country_codes: [\"ID\"],\n require_billing_information: false,\n };\n } else {\n // remove encoded validation error -\n // normally, an invalid card number would have some other stuff appended to the end, but we still want to look up the card details even if the user hasn't finished typing\n const cleanedCardNumber =\n parseEncryptedFieldValue(cardNumber).withoutValidationError;\n\n // real card details\n return lookupCardDetails(\n this.bb.sdkKey,\n {\n card_number: cleanedCardNumber,\n },\n this.bb.sdkKey.sessionAuthKey,\n undefined,\n abortController.signal,\n );\n }\n })\n .then((response) => {\n this.bb.dispatchEvent(\n new InternalUpdateChannelComponentData(this.channelCode, {\n cardDetails: {\n cardNumber,\n details: response,\n },\n }),\n );\n })\n .catch((error) => {\n if (isAbortError(error)) return;\n throw error;\n });\n\n this.cardDetailsRequest = {\n cardNumber,\n promise,\n abortController,\n };\n }\n}\n","import {\n XenditNotReadyEvent,\n XenditReadyEvent,\n} from \"../../public-event-types\";\nimport { BlackboardType } from \"../behavior-tree\";\nimport { Behavior } from \"../behavior-tree-runner\";\n\nexport class ChannelValidBehavior implements Behavior {\n private lastChannelCode: string | null = null;\n\n constructor(private bb: BlackboardType) {}\n\n enter() {\n this.sendReadyEventIfChanged();\n }\n\n update() {\n this.sendReadyEventIfChanged();\n }\n\n sendReadyEventIfChanged() {\n const channelCode = this.bb.channel?.channel_code ?? null;\n if (channelCode && channelCode !== this.lastChannelCode) {\n this.bb.dispatchEvent(new XenditReadyEvent(channelCode));\n this.lastChannelCode = channelCode;\n }\n }\n\n exit() {\n this.bb.dispatchEvent(new XenditNotReadyEvent());\n }\n}\n\n/**\n * If this exists, submission is blocked.\n */\nexport class ChannelInvalidBehavior implements Behavior {\n constructor(\n private bb: BlackboardType,\n private channelCode: string | null,\n ) {}\n\n enter() {}\n}\n","import { pollSession } from \"../../api\";\nimport { BffPollResponse } from \"../../backend-types/common\";\nimport {\n BffPaymentEntity,\n toPaymentEntity,\n} from \"../../backend-types/payment-entity\";\nimport { XenditComponents, XenditComponentsTest } from \"../../public-sdk\";\nimport {\n MOCK_NETWORK_DELAY_MS,\n ParsedSdkKey,\n retryLoop,\n sleep,\n} from \"../../utils\";\n\n/**\n * Polls the session status forever until stop() is called.\n *\n * @example\n * const poller = new PollWorker(sessionId, tokenRequestId, (updatedSession) => {\n * // handle session update\n * }, () => {\n * // handle error\n * });\n *\n * poller.start();\n * // later\n * poller.stop();\n */\nexport class PollWorker {\n started = false;\n stopped = false;\n\n constructor(\n private sdkKey: ParsedSdkKey,\n private sdk: XenditComponents,\n private sessionTokenRequestId: string | null,\n private onPollResult: (\n result: BffPollResponse,\n paymentEntity: BffPaymentEntity | null,\n ) => void,\n ) {}\n\n async start() {\n if (this.stopped) {\n throw new Error(\n \"PollWorker has been stopped, make a new instance instead of calling start again\",\n );\n }\n this.started = true;\n\n // retry loop with exponential backoff\n // chart of retry times:\n // https://www.desmos.com/calculator/3sihry02vd\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n for await (const attempt of retryLoop(5000, 100, 1.06)) {\n if (this.stopped) return;\n\n let response: BffPollResponse;\n\n if (this.sdk.isMock()) {\n // mock polling\n if (\n this.sdk instanceof XenditComponentsTest &&\n this.sdk.nextMockUpdate\n ) {\n await sleep(MOCK_NETWORK_DELAY_MS); // simulate network delay\n response = this.sdk.nextMockUpdate;\n this.sdk.nextMockUpdate = null;\n } else {\n continue;\n }\n } else {\n // real polling request\n try {\n response = await pollSession(\n this.sdkKey,\n this.sdkKey.sessionAuthKey,\n this.sessionTokenRequestId,\n );\n } catch (_err) {\n // TODO: error handling\n continue;\n }\n }\n if (this.stopped) return;\n\n if (!response.session) {\n throw new Error(\"Session is not defined\"); // should be impossible\n }\n\n let paymentEntity: BffPaymentEntity | null = null;\n if (response.payment_token) {\n paymentEntity = toPaymentEntity(response.payment_token);\n } else if (response.payment_request) {\n paymentEntity = toPaymentEntity(response.payment_request);\n }\n\n this.onPollResult(response, paymentEntity);\n\n // give the caller a chance to stop before we make the next request\n await sleep(1);\n }\n }\n\n isPolling() {\n return this.started && !this.stopped;\n }\n\n stop() {\n this.started = false;\n this.stopped = true;\n }\n}\n","import { BffPollResponse } from \"../../backend-types/common\";\nimport { BffPaymentEntity } from \"../../backend-types/payment-entity\";\nimport { assert } from \"../../utils\";\nimport {\n InternalBehaviorTreeUpdateEvent,\n InternalScheduleMockUpdateEvent,\n InternalUpdateWorldState,\n} from \"../../private-event-types\";\nimport {\n XenditActionBeginEvent,\n XenditActionEndEvent,\n} from \"../../public-event-types\";\nimport { BlackboardType } from \"../behavior-tree\";\nimport { Behavior } from \"../behavior-tree-runner\";\nimport { PollWorker } from \"./poll-worker\";\nimport { makeTestPollResponse } from \"../../data/test-data-modifiers\";\n\nexport class PePendingBehavior implements Behavior {\n private pollWorker: PollWorker;\n constructor(private bb: BlackboardType) {\n this.pollWorker = new PollWorker(\n this.bb.sdkKey,\n this.bb.sdk,\n this.bb.world?.sessionTokenRequestId ?? null,\n this.onPollResult,\n );\n }\n\n enter() {\n if (this.bb.mock) {\n // if we get to pending state in mock mode, we need to schedule a mock update or nothing will happen.\n // usually, the payment entity will have a success/fail status and we need to also update the session status.\n assert(this.bb.world?.paymentEntity);\n switch (this.bb.world?.paymentEntity.entity.status) {\n case \"ACTIVE\":\n case \"AUTHORIZED\":\n case \"SUCCEEDED\":\n case \"PENDING\":\n this.bb.dispatchEvent(\n new InternalScheduleMockUpdateEvent(\n makeTestPollResponse(this.bb.world, this.bb.channel, \"SUCCESS\"),\n ),\n );\n break;\n case \"FAILED\":\n case \"CANCELED\":\n case \"EXPIRED\":\n this.bb.dispatchEvent(\n new InternalScheduleMockUpdateEvent(\n makeTestPollResponse(this.bb.world, this.bb.channel, \"FAILURE\"),\n ),\n );\n break;\n default:\n // should never happen, just stay in pending state forever :(\n }\n }\n\n this.pollWorker.start();\n }\n\n exit() {\n this.pollWorker.stop();\n }\n\n onPollResult = (\n pollResponse: BffPollResponse,\n paymentEntity: BffPaymentEntity | null,\n ) => {\n this.bb.dispatchEvent(\n new InternalUpdateWorldState({\n session: pollResponse.session,\n paymentEntity: paymentEntity ?? undefined, // do not clear payment entity if this returns undefined/null\n succeededChannel: pollResponse.succeeded_channel ?? null, // do set succeeded channel to null if it doesn't return one\n }),\n );\n };\n}\n\nexport class PeRequiresActionBehavior implements Behavior {\n private pollWorker: PollWorker | null = null;\n public canCreateActionContainer: boolean = true;\n\n constructor(private bb: BlackboardType) {\n this.resetPolling();\n }\n\n enter() {\n this.bb.dispatchEvent(new XenditActionBeginEvent());\n this.canCreateActionContainer = false;\n this.pollWorker?.start();\n }\n\n update() {\n if (this.bb.pollImmediatelyRequested) {\n this.bb.pollImmediatelyRequested = false;\n this.resetPolling();\n }\n }\n\n exit() {\n this.pollWorker?.stop();\n this.bb.dispatchEvent(new XenditActionEndEvent());\n\n // clear flag for next time\n this.bb.actionCompleted = false;\n }\n\n onPollResult = (\n pollResponse: BffPollResponse,\n paymentEntity: BffPaymentEntity | null,\n ) => {\n this.bb.dispatchEvent(\n new InternalUpdateWorldState({\n session: pollResponse.session,\n paymentEntity: paymentEntity ?? undefined, // do not clear payment entity if this returns undefined/null\n succeededChannel: pollResponse.succeeded_channel ?? null, // do set succeeded channel to null if it doesn't return one\n }),\n );\n };\n\n /**\n * Stop the current poll worker and make a new one. Start polling if the previous pollWorker was polling.\n */\n resetPolling() {\n const polling = this.pollWorker?.isPolling() ?? false;\n this.pollWorker?.stop();\n this.pollWorker = new PollWorker(\n this.bb.sdkKey,\n this.bb.sdk,\n this.bb.world?.sessionTokenRequestId ?? null,\n this.onPollResult,\n );\n if (polling) {\n this.pollWorker.start();\n }\n }\n}\n\nexport class PeFailedBehavior implements Behavior {\n constructor(private bb: BlackboardType) {}\n\n enter() {\n this.bb.submissionRequested = false;\n this.bb.dispatchEvent(new InternalBehaviorTreeUpdateEvent());\n }\n}\n","import { getPaymentOptions } from \"../../api\";\nimport { BffPaymentOptions } from \"../../backend-types/payment-options\";\nimport { BffSession } from \"../../backend-types/session\";\nimport { makeMockPaymentOptions } from \"../../data/test-data-modifiers\";\nimport { InternalUpdateChannelComponentData } from \"../../private-event-types\";\nimport {\n AbortError,\n assert,\n cancellableSleep,\n formHasFieldOfType,\n getCardNumberFromChannelProperties,\n isAbortError,\n MOCK_NETWORK_DELAY_MS,\n ParsedSdkKey,\n parseEncryptedFieldValue,\n} from \"../../utils\";\nimport { BlackboardType } from \"../behavior-tree\";\nimport { Behavior } from \"../behavior-tree-runner\";\n\nexport class PaymentOptionsBehavior implements Behavior {\n private paymentOptionsRequest: {\n cardNumber: string | undefined;\n promise: Promise<void>;\n abortController: AbortController;\n } | null = null;\n\n constructor(\n public bb: BlackboardType,\n private channelCode: string,\n ) {}\n\n enter() {\n this.lookupPaymentOptions();\n }\n\n update() {\n this.lookupPaymentOptions();\n }\n\n exit() {\n this.abortLookupPaymentOptions();\n }\n\n abortLookupPaymentOptions() {\n if (this.paymentOptionsRequest) {\n this.paymentOptionsRequest.abortController.abort(new AbortError());\n this.paymentOptionsRequest = null;\n }\n }\n\n lookupPaymentOptions() {\n assert(this.bb.world);\n assert(this.bb.channel);\n\n let cardNumber: string | undefined;\n if (formHasFieldOfType(this.bb.channel.form, \"credit_card_number\")) {\n cardNumber =\n getCardNumberFromChannelProperties(this.bb.channelProperties) ??\n undefined;\n\n // don't look up payment options if there's a card number field but it's not filled in\n if (!cardNumber) {\n return;\n }\n\n // don't look up the payment options if a request is in flight for the same card number\n if (this.paymentOptionsRequest?.cardNumber === cardNumber) {\n return;\n }\n\n // don't look up the payment options if we already have them for the same card numnber (including null)\n if (\n this.bb.channelData?.paymentOptions?.cardNumber ??\n null === cardNumber\n ) {\n return;\n }\n\n // don't look up payment options if the card number is invalid\n if (cardNumber) {\n const parsed = parseEncryptedFieldValue(cardNumber);\n if (!parsed.valid) {\n return;\n }\n }\n } else {\n // channel does not have a card number field, skip if any request is complete or in flight\n if (this.paymentOptionsRequest || this.bb.channelData?.paymentOptions) {\n return;\n }\n }\n\n if (this.paymentOptionsRequest) {\n this.abortLookupPaymentOptions();\n }\n\n const abortController = new AbortController();\n const promise = getPaymentOptionsAsync(\n this.bb.sdkKey,\n this.bb.world.session,\n this.bb.channel.channel_code,\n cardNumber,\n abortController.signal,\n this.bb.mock,\n )\n .then((response) => {\n this.bb.dispatchEvent(\n new InternalUpdateChannelComponentData(this.channelCode, {\n paymentOptions: {\n cardNumber: cardNumber ?? null,\n options: response,\n },\n }),\n );\n })\n .catch((error) => {\n if (isAbortError(error)) return;\n throw error;\n });\n\n this.paymentOptionsRequest = {\n cardNumber: cardNumber ?? undefined,\n promise,\n abortController,\n };\n }\n}\n\nasync function getPaymentOptionsAsync(\n sdkKey: ParsedSdkKey,\n session: BffSession,\n channelCode: string,\n cardNumber: string | undefined,\n abortSignal: AbortSignal,\n mock: boolean,\n): Promise<BffPaymentOptions> {\n if (mock) {\n // mock implementation\n return cancellableSleep(MOCK_NETWORK_DELAY_MS, abortSignal).then(() => {\n return makeMockPaymentOptions(channelCode, session);\n });\n } else {\n // real implementation\n const body = {\n channel_code: channelCode,\n channel_properties: cardNumber\n ? {\n card_number: cardNumber,\n }\n : undefined,\n };\n return getPaymentOptions(\n sdkKey,\n body,\n sdkKey.sessionAuthKey,\n null,\n abortSignal,\n );\n }\n}\n","import { InternalNeedsRerenderEvent } from \"../../private-event-types\";\nimport {\n XenditFatalErrorEvent,\n XenditInitEvent,\n} from \"../../public-event-types\";\nimport { BlackboardType } from \"../behavior-tree\";\nimport { Behavior } from \"../behavior-tree-runner\";\n\nexport class SdkLoadingBehavior implements Behavior {\n constructor(private bb: BlackboardType) {}\n\n enter() {\n // do nothing\n }\n}\n\nexport class SdkActiveBehavior implements Behavior {\n constructor(private bb: BlackboardType) {}\n\n enter() {\n this.bb.dispatchEvent(new XenditInitEvent());\n\n // Schedule rerender (components don't render anything if the sdk state is not active)\n this.bb.dispatchEvent(new InternalNeedsRerenderEvent());\n }\n\n exit() {\n this.bb.dispatchEvent(new InternalNeedsRerenderEvent());\n }\n}\n\nexport class SdkFatalErrorBehavior implements Behavior {\n constructor(private bb: BlackboardType) {}\n\n enter() {\n this.bb.dispatchEvent(\n new XenditFatalErrorEvent(\n this.bb.sdkFatalErrorMessage ?? \"Unknown error\",\n ),\n );\n }\n}\n","import {\n BffPaymentEntity,\n BffPaymentEntityType,\n} from \"../../backend-types/payment-entity\";\nimport { InternalUpdateWorldState } from \"../../private-event-types\";\nimport {\n XenditPaymentRequestDiscardedEvent,\n XenditPaymentTokenDiscardedEvent,\n} from \"../../public-event-types\";\nimport { BlackboardType } from \"../behavior-tree\";\n\nexport function discardPaymentEntity(\n paymentEntity: BffPaymentEntity,\n dispatchEvent: BlackboardType[\"dispatchEvent\"],\n) {\n switch (paymentEntity.type) {\n case BffPaymentEntityType.PaymentRequest:\n dispatchEvent(new XenditPaymentRequestDiscardedEvent(paymentEntity.id));\n break;\n case BffPaymentEntityType.PaymentToken:\n dispatchEvent(new XenditPaymentTokenDiscardedEvent(paymentEntity.id));\n break;\n default:\n paymentEntity satisfies never;\n }\n dispatchEvent(\n new InternalUpdateWorldState({\n paymentEntity: null,\n sessionTokenRequestId: null,\n }),\n );\n}\n","import { BffPollResponse } from \"../../backend-types/common\";\nimport { BffPaymentEntity } from \"../../backend-types/payment-entity\";\nimport {\n InternalNeedsRerenderEvent,\n InternalUpdateWorldState,\n} from \"../../private-event-types\";\nimport {\n XenditSessionCompleteEvent,\n XenditSessionExpiredOrCanceledEvent,\n XenditSessionNotPendingEvent,\n XenditSessionPendingEvent,\n} from \"../../public-event-types\";\nimport { assert } from \"../../utils\";\nimport { BlackboardType } from \"../behavior-tree\";\nimport { Behavior } from \"../behavior-tree-runner\";\nimport { discardPaymentEntity } from \"./discard\";\nimport { PollWorker } from \"./poll-worker\";\n\nexport class SessionActiveBehavior implements Behavior {\n constructor(private bb: BlackboardType) {}\n\n enter() {\n // Schedule rerender (components don't render anything if the session state is not active)\n this.bb.dispatchEvent(new InternalNeedsRerenderEvent());\n }\n\n exit() {\n this.bb.dispatchEvent(new InternalNeedsRerenderEvent());\n }\n}\n\nexport class SessionCompletedBehavior implements Behavior {\n constructor(private bb: BlackboardType) {}\n\n enter() {\n this.bb.dispatchEvent(new XenditSessionCompleteEvent());\n }\n}\n\nexport class SessionFailedBehavior implements Behavior {\n constructor(private bb: BlackboardType) {}\n\n enter() {\n this.bb.dispatchEvent(new XenditSessionExpiredOrCanceledEvent());\n }\n}\n\nexport class SessionPendingBehavior implements Behavior {\n private pollWorker: PollWorker;\n\n constructor(private bb: BlackboardType) {\n this.pollWorker = new PollWorker(\n this.bb.sdkKey,\n this.bb.sdk,\n this.bb.world?.sessionTokenRequestId ?? null,\n this.onPollResult,\n );\n }\n\n enter() {\n this.pollWorker.start();\n\n this.bb.dispatchEvent(new XenditSessionPendingEvent());\n }\n\n exit() {\n this.pollWorker.stop();\n\n assert(this.bb.world?.session);\n\n // discard payment entity unless session is transitioning to COMPLETE\n const paymentEntity = this.bb.world.paymentEntity;\n if (this.bb.world.session.status !== \"COMPLETED\" && paymentEntity) {\n discardPaymentEntity(paymentEntity, this.bb.dispatchEvent);\n }\n\n this.bb.dispatchEvent(new XenditSessionNotPendingEvent());\n }\n\n onPollResult = (\n pollResponse: BffPollResponse,\n paymentEntity: BffPaymentEntity | null,\n ) => {\n this.bb.dispatchEvent(\n new InternalUpdateWorldState({\n session: pollResponse.session,\n paymentEntity: paymentEntity ?? undefined, // do not clear payment entity if this returns undefined/null\n succeededChannel: pollResponse.succeeded_channel ?? null, // do set succeeded channel to null if it doesn't return one\n }),\n );\n };\n}\n","import { simulatePaymentRequest } from \"../../api\";\nimport { BffChannel } from \"../../backend-types/channel\";\nimport { BffPaymentEntityType } from \"../../backend-types/payment-entity\";\nimport {\n makeTestPaymentRequest,\n makeTestPollResponse,\n} from \"../../data/test-data-modifiers\";\nimport {\n InternalBehaviorTreeUpdateEvent,\n InternalScheduleMockUpdateEvent,\n} from \"../../private-event-types\";\nimport {\n AbortError,\n cancellableSleep,\n isAbortError,\n MOCK_NETWORK_DELAY_MS,\n ParsedSdkKey,\n} from \"../../utils\";\nimport { BlackboardType } from \"../behavior-tree\";\nimport { Behavior } from \"../behavior-tree-runner\";\n\nexport class SimulatePaymentBehavior implements Behavior {\n exited = false;\n\n private simulationRequest: {\n promise: Promise<void>;\n abortController: AbortController;\n } | null = null;\n\n constructor(private bb: BlackboardType) {}\n\n enter() {\n this.simulatePayment();\n }\n\n exit() {\n this.exited = true;\n this.bb.simulatePaymentRequested = false;\n this.abortSimulation();\n }\n\n abortSimulation() {\n if (this.simulationRequest) {\n this.simulationRequest.abortController.abort(new AbortError());\n this.simulationRequest = null;\n }\n }\n\n simulatePayment() {\n if (this.simulationRequest) {\n this.abortSimulation();\n }\n\n if (!this.bb.channel) {\n throw new Error(\"Channel is missing\");\n }\n if (!this.bb.world) {\n throw new Error(\"Invalid state\");\n }\n if (!this.bb.world.paymentEntity) {\n throw new Error(\"Payment entity is missing\");\n }\n if (\n this.bb.world.paymentEntity.type !== BffPaymentEntityType.PaymentRequest\n ) {\n throw new Error(\"Payment entity is not a payment request\");\n }\n\n const paymentRequestId = this.bb.world?.paymentEntity.id;\n\n const abortController = new AbortController();\n const promise = simulatePaymentAsync(\n this.bb.sdkKey,\n this.bb.mock,\n this.bb.channel,\n paymentRequestId,\n abortController.signal,\n )\n .then(() => {\n if (this.bb.mock && this.bb.world) {\n // in mock mode, trigger transition to success state\n this.bb.dispatchEvent(\n new InternalScheduleMockUpdateEvent(\n makeTestPollResponse(this.bb.world, this.bb.channel, \"SUCCESS\"),\n ),\n );\n }\n\n this.bb.dispatchEvent(new InternalBehaviorTreeUpdateEvent());\n })\n .catch((error) => {\n if (isAbortError(error)) return;\n\n // ignore if we already exited\n if (!this.exited) {\n // exit the simulate payment state and log the error\n this.bb.simulatePaymentRequested = false;\n console.error(\"Simulate Payment failed:\", error);\n }\n });\n\n this.simulationRequest = {\n promise,\n abortController,\n };\n }\n}\n\nasync function simulatePaymentAsync(\n sdkKey: ParsedSdkKey,\n mock: boolean,\n channel: BffChannel,\n paymentRequestId: string,\n abortSignal: AbortSignal,\n) {\n if (mock) {\n await cancellableSleep(MOCK_NETWORK_DELAY_MS, abortSignal);\n return makeTestPaymentRequest(\n channel.channel_code,\n channel._mock_action_type,\n );\n } else {\n return await simulatePaymentRequest(\n sdkKey,\n {\n channel_code: channel.channel_code,\n },\n {\n sessionAuthKey: sdkKey.sessionAuthKey,\n paymentRequestId: paymentRequestId,\n },\n undefined,\n abortSignal,\n );\n }\n}\n","import { createPaymentRequest, createPaymentToken } from \"../../api\";\nimport { ChannelProperties, MockActionType } from \"../../backend-types/channel\";\nimport {\n BffPaymentEntity,\n BffPaymentEntityType,\n BffPaymentRequest,\n BffPaymentRequestFailureCode,\n BffPaymentToken,\n BffPaymentTokenFailureCode,\n getFailureCodeCopyKey,\n getPaymentEntityStatusCopyKey,\n toPaymentEntity,\n} from \"../../backend-types/payment-entity\";\nimport { BffSessionType } from \"../../backend-types/session\";\nimport {\n InternalBehaviorTreeUpdateEvent,\n InternalNeedsRerenderEvent,\n InternalScheduleMockUpdateEvent,\n InternalUpdateWorldState,\n} from \"../../private-event-types\";\nimport {\n XenditPaymentRequestCreatedEvent,\n XenditPaymentTokenCreatedEvent,\n XenditSubmissionBeginEvent,\n XenditSubmissionEndEvent,\n} from \"../../public-event-types\";\nimport {\n makeTestPaymentRequest,\n makeTestPaymentToken,\n} from \"../../data/test-data-modifiers\";\nimport {\n AbortError,\n assert,\n cancellableSleep,\n isAbortError,\n MOCK_NETWORK_DELAY_MS,\n ParsedSdkKey,\n} from \"../../utils\";\nimport { BlackboardType } from \"../behavior-tree\";\nimport { Behavior } from \"../behavior-tree-runner\";\nimport { NetworkError } from \"../../networking\";\nimport { TFunction } from \"../../localization\";\nimport { discardPaymentEntity } from \"./discard\";\n\nexport type SubmissionError = {\n text: string[];\n code: string;\n};\n\nexport class SubmissionBehavior implements Behavior {\n private exited = false;\n\n private submission: {\n abortController: AbortController;\n promise: Promise<void>;\n } | null = null;\n private submissionError: Error | SubmissionError | null = null;\n\n constructor(private bb: BlackboardType) {}\n\n enter() {\n this.bb.dispatchEvent(new XenditSubmissionBeginEvent());\n this.bb.dispatchEvent(new InternalScheduleMockUpdateEvent(null));\n this.submit();\n }\n\n exit() {\n this.exited = true;\n\n assert(this.bb.world?.session);\n const t = this.bb.sdk.t;\n\n // If session is not complete or pending, discard payment entity\n const paymentEntity = this.bb.world.paymentEntity;\n if (\n this.bb.world.session.status !== \"COMPLETED\" &&\n this.bb.world.session.status !== \"PENDING\" &&\n paymentEntity\n ) {\n discardPaymentEntity(paymentEntity, this.bb.dispatchEvent);\n }\n\n // Determine reason for submission end\n let reason: string;\n let userErrorMessage: string[] | undefined = undefined;\n let developerErrorMessage:\n | {\n type: \"NETWORK_ERROR\" | \"ERROR\" | \"FAILURE\";\n code: string;\n }\n | undefined = undefined;\n\n if (this.bb.world.session.status !== \"ACTIVE\") {\n // if status is not active, that's why we ended submission\n reason = `SESSION_${this.bb.world.session.status}`;\n } else if (\n paymentEntity &&\n (paymentEntity.entity.status === \"FAILED\" ||\n paymentEntity.entity.status === \"CANCELED\" ||\n paymentEntity.entity.status === \"EXPIRED\")\n ) {\n // the payment entity failed, was canceled or expired\n reason = `PAYMENT_${paymentEntity.type}_${paymentEntity.entity.status}`;\n userErrorMessage = failureCodeUserErrorMessage(\n t,\n paymentEntity.type,\n paymentEntity.entity.status,\n paymentEntity.entity.failure_code,\n );\n developerErrorMessage = {\n type: \"FAILURE\",\n code: paymentEntity.entity.failure_code ?? \"UNKNOWN\",\n };\n } else if (this.submissionError) {\n // there was an error during submission\n reason = \"REQUEST_FAILED\";\n if (isSubmissionError(this.submissionError)) {\n // explicit error message from the server\n userErrorMessage = this.submissionError.text;\n developerErrorMessage = {\n type: \"ERROR\",\n code: this.submissionError.code,\n };\n } else {\n // unknown or network error\n userErrorMessage = defaultUserErrorMessage(t);\n developerErrorMessage = {\n type: \"NETWORK_ERROR\",\n code: \"NETWORK_ERROR\",\n };\n }\n } else if (this.submission) {\n // the submission is canceled during the request\n reason = \"REQUEST_ABORTED\";\n } else {\n // the submission was canceled during an action\n reason = \"ACTION_ABORTED\";\n }\n\n // Dispatch submission end event\n this.bb.dispatchEvent(\n new XenditSubmissionEndEvent(\n reason,\n userErrorMessage,\n developerErrorMessage,\n ),\n );\n\n // Abort ongoing submission request (the error will be ignored)\n if (this.submission) {\n this.submission?.abortController.abort(new AbortError());\n this.submission = null;\n }\n\n // Ensure submit flags are reset\n this.bb.submissionRequested = false;\n\n // Schedule rerender (to clear the inert attribute on the active component)\n this.bb.dispatchEvent(new InternalNeedsRerenderEvent());\n }\n\n private submit() {\n if (!this.bb.world?.session) {\n throw new Error(\"Session object missing\");\n }\n\n if (!this.bb.channel) {\n throw new Error(\"Channel missing\");\n }\n\n if (this.bb.instantSubmissionError) {\n this.bb.submissionRequested = false;\n this.submissionError = this.bb.instantSubmissionError;\n this.bb.instantSubmissionError = null;\n this.bb.dispatchEvent(new InternalBehaviorTreeUpdateEvent());\n return;\n }\n\n const shouldSendSavePaymentMethod =\n this.bb.world.session.allow_save_payment_method === \"OPTIONAL\" &&\n this.bb.channel?.allow_save;\n const sessionType = this.bb.world?.session?.session_type;\n const channelCode = this.bb.channel.channel_code;\n const mockActionType = this.bb.channel._mock_action_type;\n const channelProperties = this.bb.channelProperties ?? {};\n const abortController = new AbortController();\n const promise = asyncSubmit(\n this.bb.sdkKey,\n this.bb.mock,\n sessionType,\n channelCode,\n mockActionType,\n channelProperties,\n abortController,\n shouldSendSavePaymentMethod\n ? (this.bb.channelData?.savePaymentMethod ?? false)\n : undefined,\n )\n .then((paymentEntity: BffPaymentEntity) => {\n // clear abort controller since the request is complete\n this.submission = null;\n\n switch (paymentEntity.type) {\n case BffPaymentEntityType.PaymentRequest:\n this.bb.dispatchEvent(\n new XenditPaymentRequestCreatedEvent(paymentEntity.id),\n );\n break;\n case BffPaymentEntityType.PaymentToken:\n this.bb.dispatchEvent(\n new XenditPaymentTokenCreatedEvent(paymentEntity.id),\n );\n break;\n default:\n paymentEntity satisfies never;\n }\n\n // TODO: the payment-entity-created event should be sent only after the updateWorld call but that causes a behavior tree update which would cause events to fire in the wrong order\n this.bb.dispatchEvent(\n new InternalUpdateWorldState({\n paymentEntity,\n sessionTokenRequestId:\n paymentEntity.entity.session_token_request_id,\n }),\n );\n })\n .catch((error) => {\n if (isAbortError(error)) return;\n\n console.error(\"Submission failed:\", error);\n\n // avoid dispatching an event after exit\n if (!this.exited) {\n // set the error flag and exit the submission\n this.bb.submissionRequested = false;\n\n if (error instanceof NetworkError) {\n this.submissionError = {\n text: [\n error.errorResponse.error_content?.title,\n error.errorResponse.error_content?.message_1,\n error.errorResponse.error_content?.message_2,\n ].filter((str) => str !== undefined),\n code: error.errorResponse.error_code,\n };\n } else {\n this.submissionError = error;\n }\n\n this.bb.dispatchEvent(new InternalBehaviorTreeUpdateEvent());\n }\n });\n\n this.submission = {\n abortController,\n promise,\n };\n }\n}\n\nasync function asyncSubmit(\n sdkKey: ParsedSdkKey,\n mock: boolean,\n sessionType: BffSessionType,\n channelCode: string,\n mockActionType: MockActionType | undefined,\n channelProperties: ChannelProperties,\n abortController: AbortController,\n savePaymentMethod: boolean | undefined,\n): Promise<BffPaymentEntity> {\n let result: BffPaymentToken | BffPaymentRequest;\n if (mock) {\n // mock implementation\n switch (sessionType) {\n case \"PAY\": {\n await cancellableSleep(MOCK_NETWORK_DELAY_MS, abortController.signal);\n result = makeTestPaymentRequest(channelCode, mockActionType);\n break;\n }\n case \"SAVE\": {\n await cancellableSleep(MOCK_NETWORK_DELAY_MS, abortController.signal);\n result = makeTestPaymentToken(channelCode, mockActionType);\n break;\n }\n default: {\n throw new Error(`The session type ${sessionType} is not supported.`);\n }\n }\n } else {\n // real implementation\n switch (sessionType) {\n case \"PAY\": {\n result = await createPaymentRequest(\n sdkKey,\n {\n session_id: sdkKey.sessionAuthKey,\n channel_code: channelCode,\n channel_properties: channelProperties,\n save_payment_method: savePaymentMethod,\n // TODO: pass customer for VA channels\n },\n null,\n null,\n abortController.signal,\n );\n break;\n }\n case \"SAVE\": {\n result = await createPaymentToken(\n sdkKey,\n {\n session_id: sdkKey.sessionAuthKey,\n channel_code: channelCode,\n channel_properties: channelProperties,\n },\n null,\n null,\n abortController.signal,\n );\n break;\n }\n default: {\n throw new Error(`The session type ${sessionType} is not supported.`);\n }\n }\n }\n\n return toPaymentEntity(result);\n}\n\nfunction defaultUserErrorMessage(t: TFunction): string[] {\n return [\n t(\"default_error.title\"),\n t(\"default_error.message_1\"),\n t(\"default_error.message_2\"),\n ];\n}\n\nfunction failureCodeUserErrorMessage(\n t: TFunction,\n type: BffPaymentEntityType,\n status: \"FAILED\" | \"EXPIRED\" | \"CANCELED\",\n failureCode:\n | BffPaymentTokenFailureCode\n | BffPaymentRequestFailureCode\n | undefined,\n): string[] {\n const title = t(getPaymentEntityStatusCopyKey(type, status, \"title\"));\n const subtext = failureCode\n ? t(\n getFailureCodeCopyKey(failureCode),\n t(\"failure_code_unknown\", { failureCode }),\n )\n : t(getPaymentEntityStatusCopyKey(type, status, \"subtext\"));\n return [title, subtext];\n}\n\nfunction isSubmissionError(\n error: Error | SubmissionError,\n): error is SubmissionError {\n return !(\"message\" in error) && \"text\" in error && \"code\" in error;\n}\n","import { BffChannel, ChannelProperties } from \"../backend-types/channel\";\nimport { BffAction, BffPaymentEntity } from \"../backend-types/payment-entity\";\nimport { BffSession } from \"../backend-types/session\";\nimport {\n ChannelComponentData,\n WorldState,\n XenditComponents,\n} from \"../public-sdk\";\nimport {\n assert,\n canBeSimulated,\n findBestAction,\n findPaylinkAction,\n formHasFieldOfType,\n ParsedSdkKey,\n redirectCanBeHandledInIframe,\n} from \"../utils\";\nimport { channelPropertiesAreValid } from \"../validation\";\nimport { behaviorNode } from \"./behavior-tree-runner\";\nimport {\n ActionCompletedBehavior,\n ActionDeepLinkBehavior,\n ActionEmptyListPushNotificationBehavior,\n ActionIframeBehavior,\n ActionQrBehavior,\n ActionRedirectBehavior,\n ActionVaBehavior,\n} from \"./behaviors/action\";\nimport { ActionPaylinkBehavior } from \"./behaviors/action-paylink\";\nimport { CardInfoBehavior } from \"./behaviors/card-info\";\nimport {\n ChannelInvalidBehavior,\n ChannelValidBehavior,\n} from \"./behaviors/channel\";\nimport {\n PeFailedBehavior,\n PePendingBehavior,\n PeRequiresActionBehavior,\n} from \"./behaviors/payment-entity\";\nimport { PaymentOptionsBehavior } from \"./behaviors/payment-options\";\nimport {\n SdkActiveBehavior,\n SdkFatalErrorBehavior,\n SdkLoadingBehavior,\n} from \"./behaviors/sdk\";\nimport {\n SessionActiveBehavior,\n SessionCompletedBehavior,\n SessionFailedBehavior,\n SessionPendingBehavior,\n} from \"./behaviors/session\";\nimport { SimulatePaymentBehavior } from \"./behaviors/simulate-payment\";\nimport { SubmissionBehavior, SubmissionError } from \"./behaviors/submission\";\n\nexport type SdkStatus = \"ACTIVE\" | \"LOADING\" | \"FATAL_ERROR\";\n\n/**\n * \"Blackboard\" means mutable state available to the behavior tree and all behavior instances.\n */\nexport type BlackboardType = {\n readonly sdk: XenditComponents;\n readonly mock: boolean;\n readonly sdkKey: ParsedSdkKey;\n\n // backend state\n world: WorldState | null;\n\n // current UI state\n sdkStatus: SdkStatus;\n sdkFatalErrorMessage: string | null;\n channel: BffChannel | null;\n channelProperties: ChannelProperties | null;\n channelData: ChannelComponentData | null;\n channelIsDigitalWallet: boolean;\n instantSubmissionError: SubmissionError | null;\n\n // dispatch event on the SDK instance\n dispatchEvent(event: Event): boolean;\n\n // flags\n // if true, start a submission, if false abort submission\n submissionRequested: boolean;\n // if true, start simulate payment, if false abort simulate payment\n simulatePaymentRequested: boolean;\n // if true, do not show the current action UI\n actionCompleted: boolean;\n // if true, poll the payment entity immediately on the next update\n pollImmediatelyRequested: boolean;\n // if true, don't exit ovo's and jeniuspay's ActionEmptyListPushNotificationBehavior when the payment request status changes to pending\n hackyOvoActionLatch?: boolean;\n};\n\nexport function behaviorTreeForSdk(bb: BlackboardType) {\n switch (bb.sdkStatus) {\n case \"LOADING\": {\n return behaviorNode(SdkLoadingBehavior);\n }\n case \"ACTIVE\": {\n return behaviorNode(\n SdkActiveBehavior,\n \"active\",\n behaviorTreeForSession(bb),\n );\n }\n case \"FATAL_ERROR\": {\n return behaviorNode(SdkFatalErrorBehavior);\n }\n default: {\n bb.sdkStatus satisfies never;\n throw new Error(`Unknown SDK status: ${bb.sdkStatus as SdkStatus}`);\n }\n }\n}\n\nexport function behaviorTreeForSession(bb: BlackboardType) {\n assert(bb.world?.session);\n\n switch (bb.world.session.status) {\n case \"ACTIVE\": {\n return behaviorNode(\n SessionActiveBehavior,\n \"active\",\n bb.submissionRequested\n ? behaviorTreeForSubmission(bb)\n : behaviorTreeForForm(bb),\n );\n }\n case \"COMPLETED\": {\n return behaviorNode(SessionCompletedBehavior);\n }\n case \"EXPIRED\": {\n return behaviorNode(SessionFailedBehavior, bb.world.session.status);\n }\n case \"CANCELED\": {\n return behaviorNode(SessionFailedBehavior, bb.world.session.status);\n }\n case \"PENDING\": {\n return behaviorNode(SessionPendingBehavior, bb.world.session.status);\n }\n default: {\n bb.world.session.status satisfies never;\n throw new Error(\n `Unknown session status: ${(bb.world.session as BffSession).status}`,\n );\n }\n }\n}\n\nexport function behaviorTreeForForm(bb: BlackboardType) {\n if (!bb.channel || !bb.world?.session) {\n return undefined;\n }\n\n if (bb.channelIsDigitalWallet) {\n return undefined;\n }\n\n const channelPropertiesValid = channelPropertiesAreValid(\n bb.world.session.session_type,\n bb.channel,\n bb.channelProperties,\n bb.channelData,\n );\n\n const validityBehavior = channelPropertiesValid\n ? behaviorNode(ChannelValidBehavior)\n : behaviorNode(ChannelInvalidBehavior);\n\n const cardInfoBehavior = formHasFieldOfType(\n bb.channel.form,\n \"credit_card_number\",\n )\n ? behaviorNode(CardInfoBehavior, bb.channel.channel_code)\n : undefined;\n\n const paymentOptionsBehavior = formHasFieldOfType(\n bb.channel.form,\n \"installment_plan\",\n )\n ? behaviorNode(PaymentOptionsBehavior, bb.channel.channel_code)\n : undefined;\n\n return [validityBehavior, cardInfoBehavior, paymentOptionsBehavior];\n}\n\nexport function behaviorTreeForSubmission(bb: BlackboardType) {\n assert(bb.world);\n\n return behaviorNode(\n SubmissionBehavior,\n \"submission\",\n bb.world.paymentEntity && bb.world.sessionTokenRequestId !== null\n ? behaviorTreeForPaymentEntity(bb)\n : undefined,\n );\n}\n\nexport function behaviorTreeForPaymentEntity(bb: BlackboardType) {\n assert(bb.world?.paymentEntity);\n\n function maybePaylinkAction() {\n assert(bb.world?.paymentEntity);\n return findPaylinkAction(bb.sdk, bb.world.paymentEntity.entity.actions)\n ? behaviorTreeForPaylink(bb)\n : undefined;\n }\n\n if (\n bb.hackyOvoActionLatch &&\n bb.world.paymentEntity.entity.status === \"PENDING\"\n ) {\n // In ovo and jeniuspay, the REQUIRES_ACTION status changes to PENDING almost immediately, causing the instructions to the user to close.\n // We need to keep this behavior alive until the status changes to something other than PENDING.\n return behaviorNode(PeRequiresActionBehavior, bb.world.paymentEntity.id, [\n behaviorNode(ActionEmptyListPushNotificationBehavior, \"\"),\n maybePaylinkAction(),\n ]);\n }\n\n switch (bb.world.paymentEntity.entity.status) {\n case \"PENDING\": {\n return behaviorNode(PePendingBehavior);\n }\n case \"REQUIRES_ACTION\": {\n return behaviorNode(PeRequiresActionBehavior, bb.world.paymentEntity.id, [\n behaviorTreeForAction(bb),\n maybePaylinkAction(),\n ]);\n }\n case \"FAILED\":\n case \"EXPIRED\":\n case \"CANCELED\": {\n return behaviorNode(PeFailedBehavior);\n }\n case \"ACCEPTING_PAYMENTS\": {\n // Never happens because sessions don't set the PR type to REUSABLE_PAYMENT_CODE\n throw new Error(\"Status ACCEPTING_PAYMENTS should not happen\");\n }\n case \"AUTHORIZED\":\n case \"ACTIVE\":\n case \"SUCCEEDED\": {\n // The payemnt entity is completed but the session is still active, it should automatically switch to completed soon\n return behaviorNode(PePendingBehavior, bb.world.paymentEntity.id);\n }\n default: {\n bb.world.paymentEntity.entity satisfies never;\n throw new Error(\n `Unknown payment entity status: ${(bb.world.paymentEntity as BffPaymentEntity).entity.status}`,\n );\n }\n }\n}\n\nexport function behaviorTreeForAction(bb: BlackboardType) {\n assert(bb.world?.paymentEntity);\n\n if (bb.actionCompleted) {\n // action completed is for when we want to close the action UI and go back to polling\n return behaviorNode(ActionCompletedBehavior);\n }\n\n const action = findBestAction(bb.world.paymentEntity.entity.actions);\n\n if (!action) {\n // an empty list of actions means we prompt the user to tap a push notification\n return behaviorNode(ActionEmptyListPushNotificationBehavior, \"\");\n }\n\n const actionIndex = bb.world.paymentEntity.entity.actions.indexOf(action);\n const hasPaylink = !!findPaylinkAction(\n bb.sdk,\n bb.world.paymentEntity.entity.actions,\n );\n\n // adds simulate payment behavior as a child of the action behavior so that when\n // simulate payment is requested, it will run the simulate payment behavior while\n // keeping the action UI open until the payment entity updates\n let simulateBehavior = undefined;\n if (bb.simulatePaymentRequested && canBeSimulated(action)) {\n simulateBehavior = behaviorNode(SimulatePaymentBehavior);\n }\n\n switch (action.type) {\n case \"REDIRECT_CUSTOMER\": {\n switch (action.descriptor) {\n case \"WEB_URL\": {\n if (redirectCanBeHandledInIframe(action)) {\n return behaviorNode(ActionIframeBehavior, action.value);\n } else if (hasPaylink) {\n return behaviorNode(ActionDeepLinkBehavior, String(actionIndex));\n } else {\n return behaviorNode(ActionRedirectBehavior, action.value);\n }\n }\n case \"DEEPLINK_URL\": {\n return behaviorNode(ActionDeepLinkBehavior, String(actionIndex));\n }\n case \"WEB_GOOGLE_PAYLINK\": {\n throw new Error(`Paylink actions should not be the primary action`);\n }\n }\n break;\n }\n case \"PRESENT_TO_CUSTOMER\": {\n switch (action.descriptor) {\n case \"QR_STRING\": {\n return behaviorNode(\n ActionQrBehavior,\n String(actionIndex),\n simulateBehavior,\n );\n }\n case \"PAYMENT_CODE\": {\n throw new Error(\n `Unsupported action type ${action.type} ${action.descriptor}`,\n );\n }\n case \"VIRTUAL_ACCOUNT_NUMBER\": {\n return behaviorNode(\n ActionVaBehavior,\n String(actionIndex),\n simulateBehavior,\n );\n }\n }\n break;\n }\n case \"API_POST_REQUEST\": {\n switch (action.descriptor) {\n case \"CAPTURE_PAYMENT\": {\n throw new Error(\n `Unsupported action type ${action.type} ${action.descriptor}`,\n );\n }\n case \"VALIDATE_OTP\": {\n throw new Error(\n `Unsupported action type ${action.type} ${action.descriptor}`,\n );\n }\n case \"RESEND_OTP\": {\n throw new Error(\n `Unsupported action type ${action.type} ${action.descriptor}`,\n );\n }\n }\n break;\n }\n }\n action satisfies never;\n throw new Error(\n `Unknown action type: ${(action as BffAction).type} ${(action as BffAction).descriptor}`,\n );\n}\n\nfunction behaviorTreeForPaylink(bb: BlackboardType) {\n assert(bb.world?.paymentEntity);\n\n const paylinkAction = findPaylinkAction(\n bb.sdk,\n bb.world.paymentEntity.entity.actions,\n );\n assert(paylinkAction);\n\n const actionIndex =\n bb.world.paymentEntity.entity.actions.indexOf(paylinkAction);\n return behaviorNode(ActionPaylinkBehavior, String(actionIndex));\n}\n","import { FunctionComponent } from \"preact\";\nimport { useCallback, useLayoutEffect, useMemo, useRef } from \"preact/hooks\";\nimport {\n useBusiness,\n useDigitalWallets,\n useSdk,\n useSession,\n} from \"./session-provider\";\nimport { ChannelProperties } from \"../backend-types/channel\";\nimport { XenditPaymentChannel } from \"../public-data-types\";\nimport { assert } from \"../utils\";\nimport { DigitalWalletOptions } from \"../public-options-types\";\n\ntype Props = {\n options?: DigitalWalletOptions<\"GOOGLE_PAY\">;\n onReady: () => void;\n};\n\nexport const DigitalWalletGooglepay: FunctionComponent<Props> = (props) => {\n const { onReady, options } = props;\n\n const sdk = useSdk();\n const t = sdk.t;\n\n const session = useSession();\n const business = useBusiness();\n const digitalWallets = useDigitalWallets();\n const digitalWalletsGooglePay = digitalWallets?.google_pay;\n assert(digitalWalletsGooglePay);\n\n const didCallReady = useRef(false);\n const containerRef = useRef<HTMLDivElement>(null);\n\n const paymentsClient = useRef<google.payments.api.PaymentsClient | null>(\n null,\n );\n\n const googlePayChannels = useMemo(() => {\n return digitalWalletsGooglePay.allowed_payment_methods.map(\n (obj) => obj.payment_method_specification,\n );\n }, [digitalWalletsGooglePay.allowed_payment_methods]);\n\n const googlePayConfig: google.payments.api.PaymentDataRequest = useMemo(\n () => ({\n apiVersion: 2,\n apiVersionMinor: 0,\n allowedPaymentMethods: googlePayChannels,\n emailRequired: true,\n merchantInfo: {\n merchantId: digitalWalletsGooglePay.merchant_id,\n merchantName: business.name ?? \"\",\n },\n transactionInfo: {\n transactionId: session.payment_session_id,\n totalPriceStatus: \"FINAL\",\n totalPrice: String(session.amount),\n currencyCode: session.currency,\n },\n }),\n [\n business.name,\n digitalWalletsGooglePay.merchant_id,\n googlePayChannels,\n session.amount,\n session.currency,\n session.payment_session_id,\n ],\n );\n\n const buttonConfigWithDefaults: Omit<\n google.payments.api.ButtonOptions,\n \"onClick\"\n > = useMemo(\n () => ({\n buttonColor: \"default\",\n buttonType: \"plain\",\n buttonRadius: 999,\n buttonSizeMode: \"fill\",\n buttonBorderType: \"no_border\",\n ...options,\n }),\n [options],\n );\n\n useLayoutEffect(() => {\n const PaymentsClient = window.google?.payments?.api?.PaymentsClient;\n if (!PaymentsClient) {\n console.error(\n \"XenditComponents: Google Pay button was requested but the Google Pay SDK is not loaded.\",\n );\n return;\n }\n paymentsClient.current = new PaymentsClient({\n environment: sdk.isMock() ? \"TEST\" : \"PRODUCTION\",\n });\n }, [sdk]);\n\n const onClick = useCallback(() => {\n assert(paymentsClient.current);\n\n // return the channel corresponding to the selected payment method in google pay\n function findTargetChannel(paymentData: google.payments.api.PaymentData) {\n assert(digitalWalletsGooglePay);\n\n const allChannels = sdk.getActiveChannels();\n for (const googlePayChannel of digitalWalletsGooglePay.allowed_payment_methods) {\n if (\n googlePayChannel.payment_method_specification.type ===\n paymentData.paymentMethodData.type\n ) {\n return findChannel(allChannels, googlePayChannel.channel_code);\n }\n }\n\n throw new Error(\n `No matching channel found for selected Google Pay payment method ${paymentData.paymentMethodData.type}`,\n );\n }\n\n paymentsClient.current\n .loadPaymentData(googlePayConfig)\n .then(function (paymentData) {\n const targetChannel = findTargetChannel(paymentData);\n assert(targetChannel);\n\n let channelProperties: ChannelProperties = {};\n if (targetChannel.channelCode === \"CARDS\") {\n // for cards, pass the whole paymentData to backend in channel properties\n channelProperties = {\n google_pay: JSON.stringify(paymentData),\n };\n }\n\n sdk.submitDigitalWallet(\"GOOGLE_PAY\", targetChannel, channelProperties);\n })\n .catch(function (err) {\n type GooglePayErrorCode =\n | \"CANCELED\"\n | \"DEVELOPER_ERROR\"\n | \"BUYER_ACCOUNT_ERROR\"\n | \"MERCHANT_ACCOUNT_ERROR\"\n | \"INTERNAL_ERROR\"\n | \"UNKNOWN_ERROR\";\n const statusCode =\n (err.statusCode as GooglePayErrorCode) ?? \"UNKNOWN_ERROR\";\n\n if (statusCode === \"CANCELED\") {\n return;\n }\n\n function localeKeyForGooglePayError<\n T extends GooglePayErrorCode,\n U extends \"title\" | \"message\",\n >(errorCode: T, suffix: U) {\n return `google_pay_errors.${errorCode.toLowerCase() as Lowercase<T>}.${suffix}` as const;\n }\n\n const submissionError = {\n code: `GOOGLE_PAY_${statusCode}` as const,\n text: [\n t(\n localeKeyForGooglePayError(statusCode, \"title\"),\n t(\"google_pay_errors.unknown_error.title\"),\n ),\n t(\n localeKeyForGooglePayError(statusCode, \"message\"),\n t(\"google_pay_errors.unknown_error.message\", { statusCode }),\n ),\n ],\n };\n\n // there is no target channel on errors, pick the channel used for the first allowed payment method\n const firstGooglePayChannel =\n digitalWalletsGooglePay.allowed_payment_methods[0];\n assert(firstGooglePayChannel);\n const targetChannel = findChannel(\n sdk.getActiveChannels(),\n firstGooglePayChannel.channel_code,\n );\n\n // submit and force an error\n sdk.submitDigitalWallet(\n \"GOOGLE_PAY\",\n targetChannel,\n {},\n submissionError,\n );\n });\n }, [digitalWalletsGooglePay, googlePayConfig, sdk, t]);\n\n // call onready if the googlepay sdk is ready\n useLayoutEffect(() => {\n if (!paymentsClient.current) {\n return;\n }\n if (didCallReady.current) {\n return;\n }\n\n paymentsClient.current\n .isReadyToPay({\n apiVersion: 2,\n apiVersionMinor: 0,\n allowedPaymentMethods: googlePayChannels,\n })\n .then(function (response) {\n if (!response.result) {\n return;\n }\n\n if (didCallReady.current) return;\n didCallReady.current = true;\n onReady();\n })\n .catch(function (err) {\n console.error(\n \"XenditComponents: Error when checking if Google Pay is ready\",\n err,\n );\n });\n }, [googlePayChannels, onReady]);\n\n // create the button\n useLayoutEffect(() => {\n if (!paymentsClient.current) {\n return;\n }\n\n const button = paymentsClient.current.createButton({\n ...buttonConfigWithDefaults,\n buttonLocale: session.locale,\n allowedPaymentMethods: googlePayChannels,\n onClick,\n });\n if (containerRef.current) {\n containerRef.current.replaceChildren(button);\n }\n }, [buttonConfigWithDefaults, googlePayChannels, onClick, session.locale]);\n\n return <div ref={containerRef}></div>;\n};\n\nfunction findChannel(\n allChannels: XenditPaymentChannel[],\n targetChannelCode: string,\n): XenditPaymentChannel {\n const ch = allChannels.find((channel) => {\n if (Array.isArray(channel.channelCode)) {\n return channel.channelCode.includes(targetChannelCode);\n }\n return channel.channelCode === targetChannelCode;\n });\n if (!ch) {\n throw new Error(`Channel not found for code: ${targetChannelCode}`);\n }\n return ch;\n}\n","import { ComponentChildren, FunctionComponent } from \"preact\";\nimport { useLayoutEffect, useState } from \"preact/hooks\";\nimport { SLEEP_MULTIPLIER } from \"../utils\";\n\n/**\n * Renders the children only if the condition passes. Re-checks the condition when the given script tag is loaded, or every second.\n */\nexport const DigitalWalletWaitForLoad: FunctionComponent<{\n scriptTagRegex: RegExp;\n checkLoaded: () => boolean;\n children: ComponentChildren;\n}> = (props) => {\n const { scriptTagRegex, checkLoaded, children } = props;\n\n const [, forceRender] = useState<object>({});\n const ok = checkLoaded();\n\n useLayoutEffect(() => {\n if (ok) return;\n\n const targetScript = Array.from(document.scripts).find((script) =>\n scriptTagRegex.test(script.src),\n );\n\n if (targetScript) {\n const fn = () => {\n forceRender({});\n };\n targetScript.addEventListener(\"load\", fn);\n return () => {\n targetScript.removeEventListener(\"load\", fn);\n };\n }\n }, [forceRender, ok, scriptTagRegex]);\n\n useLayoutEffect(() => {\n if (!ok) {\n const timeout = setTimeout(() => {\n forceRender({});\n }, 1000 * SLEEP_MULTIPLIER);\n return () => clearTimeout(timeout);\n }\n }); // <- intentionally no dependencies, this timer should run in a loop until the check passes\n\n return ok ? children : null;\n};\n","import { FunctionComponent, JSX } from \"preact\";\nimport { DigitalWalletGooglepay } from \"./digital-wallet-googlepay\";\nimport { DigitalWalletOptions } from \"../public-options-types\";\nimport { XenditDigitalWalletCode } from \"../public-data-types\";\nimport { useCallback, useRef } from \"preact/hooks\";\nimport { DigitalWalletWaitForLoad } from \"./digital-wallet-wait-for-load\";\n\ntype Props<T extends XenditDigitalWalletCode> = {\n digitalWalletCode: T;\n digitalWalletOptions?: DigitalWalletOptions<T>;\n};\n\nexport const DigitalWalletContainer: FunctionComponent<\n Props<XenditDigitalWalletCode>\n> = (props) => {\n const { digitalWalletCode, digitalWalletOptions } = props;\n\n const containerRef = useRef<HTMLDivElement>(null);\n\n const onReady = useCallback(() => {\n containerRef.current?.parentElement?.style.setProperty(\"display\", \"block\");\n }, []);\n\n let el: JSX.Element | null = null;\n switch (digitalWalletCode) {\n case \"GOOGLE_PAY\": {\n el = (\n <DigitalWalletWaitForLoad\n scriptTagRegex={sdkStatusCheckers.GOOGLE_PAY.scriptTagRegex}\n checkLoaded={sdkStatusCheckers.GOOGLE_PAY.checkLoaded}\n >\n <DigitalWalletGooglepay\n onReady={onReady}\n options={digitalWalletOptions}\n />\n </DigitalWalletWaitForLoad>\n );\n break;\n }\n }\n\n return <div ref={containerRef}>{el}</div>;\n};\n\nconst sdkStatusCheckers = {\n GOOGLE_PAY: {\n scriptTagRegex: /https:\\/\\/pay.google.com\\/.*\\/js\\/pay.js/,\n checkLoaded: () =>\n typeof google !== \"undefined\" && typeof google.payments !== \"undefined\",\n },\n};\n","import {\n XenditActionBeginEvent,\n XenditActionEndEvent,\n XenditFatalErrorEvent,\n XenditEventListener,\n XenditEventMap,\n XenditInitEvent,\n XenditPaymentRequestCreatedEvent,\n XenditPaymentRequestDiscardedEvent,\n XenditPaymentTokenCreatedEvent,\n XenditPaymentTokenDiscardedEvent,\n XenditReadyEvent,\n XenditSessionCompleteEvent,\n XenditSessionExpiredOrCanceledEvent,\n XenditSubmissionBeginEvent,\n XenditSubmissionEndEvent,\n XenditWillRedirectEvent,\n XenditSessionPendingEvent,\n XenditSessionNotPendingEvent,\n} from \"./public-event-types\";\nimport {\n XenditSdkOptions as XenditComponentsOptions,\n XenditGetChannelsOptions,\n ActionContainerOptions,\n DigitalWalletOptions,\n} from \"./public-options-types\";\nimport {\n XenditCustomer,\n XenditDigitalWallet,\n XenditDigitalWalletCode,\n XenditPaymentChannel,\n XenditPaymentChannelGroup,\n XenditSession,\n} from \"./public-data-types\";\nimport { internal } from \"./internal\";\nimport { createElement, createRef, RefObject, render } from \"preact\";\nimport {\n XenditChannelPicker,\n XenditClearCurrentChannelEvent,\n} from \"./components/channel-picker\";\nimport { XenditSessionProvider } from \"./components/session-provider\";\nimport {\n BffChannel,\n BffChannelUiGroup,\n ChannelProperties,\n ChannelPropertyPrimative,\n} from \"./backend-types/channel\";\nimport {\n PaymentChannel,\n XenditChannelPropertiesChangedEvent,\n} from \"./components/payment-channel\";\nimport { fetchSessionData } from \"./api\";\nimport { ChannelFormHandle } from \"./components/channel-form\";\nimport { BehaviorTree } from \"./lifecycle/behavior-tree-runner\";\nimport {\n behaviorTreeForSdk,\n BlackboardType,\n SdkStatus,\n} from \"./lifecycle/behavior-tree\";\nimport { BffSession } from \"./backend-types/session\";\nimport { BffBusiness } from \"./backend-types/business\";\nimport { BffCustomer } from \"./backend-types/customer\";\nimport { BffPaymentEntity } from \"./backend-types/payment-entity\";\nimport { SessionActiveBehavior } from \"./lifecycle/behaviors/session\";\nimport {\n InternalBehaviorTreeUpdateEvent,\n InternalNeedsRerenderEvent,\n InternalScheduleMockUpdateEvent,\n InternalUpdateChannelComponentData,\n InternalUpdateWorldState,\n} from \"./private-event-types\";\nimport {\n BffPollResponse,\n BffResponse,\n BffSucceededChannel,\n} from \"./backend-types/common\";\nimport {\n canBeSimulated,\n errorToString,\n findBestAction,\n lockDownInteralProperty,\n mergeIgnoringUndefined,\n MOCK_NETWORK_DELAY_MS,\n ParsedSdkKey,\n parseSdkKey,\n removeUnreleasedChannels,\n resolvePairedChannel,\n satisfiesMinMax,\n sleep,\n} from \"./utils\";\nimport { makeTestSdkKey } from \"./data/test-data-modifiers\";\nimport {\n ChannelInvalidBehavior,\n ChannelValidBehavior,\n} from \"./lifecycle/behaviors/channel\";\nimport { PeRequiresActionBehavior } from \"./lifecycle/behaviors/payment-entity\";\nimport {\n SubmissionBehavior,\n SubmissionError,\n} from \"./lifecycle/behaviors/submission\";\nimport {\n bffChannelsToPublic,\n bffCustomerToPublic,\n bffDigitalWalletsToPublic,\n bffSessionToPublic,\n bffUiGroupsToPublic,\n findChannelPairs,\n} from \"./bff-marshal\";\nimport { BffCardDetails } from \"./backend-types/card-details\";\nimport { createTFunction, TFunction } from \"./localization\";\nimport { amountFormat } from \"./amount-format\";\nimport { BffPaymentOptions } from \"./backend-types/payment-options\";\nimport { DigitalWalletContainer } from \"./components/digital-wallet-container\";\nimport { BffDigitalWallets } from \"./backend-types/digital-wallets\";\n\n/**\n * @internal\n * Represents payment channel state.\n */\ntype CachedChannelComponent = {\n element: HTMLElement;\n channel: XenditPaymentChannel;\n channelProperties: ChannelProperties | null;\n channelFormRef: RefObject<ChannelFormHandle>;\n data: ChannelComponentData;\n};\n\n/**\n * @internal\n * Properties of a component updatable by events\n */\nexport type ChannelComponentData = {\n savePaymentMethod: boolean;\n cardDetails: {\n cardNumber: string;\n details: BffCardDetails | null;\n } | null;\n paymentOptions: {\n cardNumber: string | null;\n options: BffPaymentOptions | null;\n } | null;\n};\n\n/**\n * @internal\n * The session and associated entities that we get from the backend.\n */\nexport type WorldState = {\n business: BffBusiness;\n customer: BffCustomer | null;\n session: BffSession;\n channels: BffChannel[];\n channelUiGroups: BffChannelUiGroup[];\n digitalWallets: BffDigitalWallets | null;\n paymentEntity: BffPaymentEntity | null;\n sessionTokenRequestId: string | null;\n succeededChannel: BffSucceededChannel | null;\n};\n\n/**\n * @internal\n * Updatable parts of the world state. Nulls are written, undefineds are ignored.\n */\nexport type UpdatableWorldState = {\n [K in\n | \"session\"\n | \"paymentEntity\"\n | \"sessionTokenRequestId\"\n | \"succeededChannel\"]?: WorldState[K] | undefined;\n};\n\n/**\n * @internal\n * Used to assert that the SDK is initialized.\n */\ntype InitializedSdk = {\n [internal]: {\n worldState: WorldState;\n };\n};\n\n/**\n * @public\n */\nexport class XenditComponents extends EventTarget {\n /**\n * @internal\n */\n public t: TFunction = (str: string): string => {\n throw new Error(\"Localization used before initialization; this is a bug.\");\n };\n\n /**\n * @internal\n */\n protected [internal]: {\n /**\n * Parsed SDK key components.\n */\n sdkKey: ParsedSdkKey;\n\n /**\n * User-provided options.\n */\n options: XenditComponentsOptions;\n\n /**\n * The session and ascociated data from the backend.\n */\n worldState: WorldState | null;\n\n /**\n * Behavior tree for state management.\n */\n behaviorTree: BehaviorTree<BlackboardType>;\n\n /**\n * Components the user has created\n */\n liveComponents: {\n channelPicker: HTMLElement | null;\n paymentChannels: Map<string, CachedChannelComponent>;\n actionContainer: HTMLElement | null;\n digitalWalletContainer: Map<\n XenditDigitalWalletCode,\n {\n element: HTMLElement;\n options: DigitalWalletOptions<XenditDigitalWalletCode> | undefined;\n }\n >;\n };\n\n /**\n * The most recently created payment channel component's channel code.\n * This is used as a key into `paymentChannelComponents`.\n */\n currentChannelCode: string | null;\n\n /**\n * The ongoing digital wallet submission, if any.\n */\n currentDigitalWalletSubmission: {\n digitalWalletCode: XenditDigitalWalletCode;\n channelCode: string;\n channelProperties: ChannelProperties;\n instantSubmissionError: SubmissionError | null;\n } | null;\n\n /**\n * Tracks which event listeners are present on the SDK instance.\n */\n eventListenersPresent: Map<string, boolean>;\n };\n\n /**\n * @public\n * Initialize the SDK for a given session.\n *\n * You can get the components sdk key from the components_sdk_key field of the\n * `POST /sessions` or `GET /session` endpoints.\n *\n * This creates an object that can be used to create UI components, that allow\n * users to make payment or save tokens, using a variety of channels, depending on\n * the session configuration.\n *\n * @example\n * ```\n * // initialize\n * const components = new XenditComponents({\n * componentsSdkKey: \"your-session-client-key\",\n * });\n * ```\n */\n constructor(options: XenditComponentsOptions) {\n super();\n\n if (typeof window === \"undefined\" || typeof document === \"undefined\") {\n throw new Error(\"XenditComponents can only be instantiated in a browser\");\n }\n\n const sdkKey = parseSdkKey(options.componentsSdkKey);\n this[internal] = {\n sdkKey,\n options,\n worldState: null,\n liveComponents: {\n channelPicker: null,\n paymentChannels: new Map(),\n actionContainer: null,\n digitalWalletContainer: new Map(),\n },\n behaviorTree: new BehaviorTree<BlackboardType>(behaviorTreeForSdk, {\n sdk: this,\n sdkKey,\n mock: this.isMock(),\n sdkStatus: \"LOADING\",\n sdkFatalErrorMessage: null,\n channel: null,\n channelProperties: null,\n channelData: null,\n channelIsDigitalWallet: false,\n instantSubmissionError: null,\n dispatchEvent: this.dispatchEvent.bind(this),\n world: null,\n submissionRequested: false,\n simulatePaymentRequested: false,\n actionCompleted: false,\n pollImmediatelyRequested: false,\n }),\n currentChannelCode: null,\n currentDigitalWalletSubmission: null,\n eventListenersPresent: new Map(),\n };\n lockDownInteralProperty(this as unknown as { [internal]: unknown });\n\n // log fatal errors if user didn't attach a listener\n this.addEventListener(\"fatal-error\", (event) => {\n const fatalErrorEvent = event as XenditFatalErrorEvent;\n if (!this[internal].eventListenersPresent.get(\"fatal-error\")) {\n console.error(\n `XenditComponents: A \"fatal-error\" event occurred but no event listener was attached: ${fatalErrorEvent.message}`,\n );\n }\n });\n this[internal].eventListenersPresent.set(\"fatal-error\", false);\n\n this.behaviorTreeUpdate();\n\n // internal event listeners\n (this as EventTarget).addEventListener(\n InternalUpdateWorldState.type,\n this.onUpdateWorldState.bind(this),\n );\n (this as EventTarget).addEventListener(\n InternalUpdateChannelComponentData.type,\n this.onUpdateChannelComponentData.bind(this),\n );\n (this as EventTarget).addEventListener(\n InternalBehaviorTreeUpdateEvent.type,\n this.behaviorTreeUpdate.bind(this),\n );\n let hasScheduledRender = false;\n (this as EventTarget).addEventListener(\n InternalNeedsRerenderEvent.type,\n () => {\n if (hasScheduledRender) return;\n hasScheduledRender = true;\n queueMicrotask(() => {\n hasScheduledRender = false;\n this.rerenderAllComponents();\n this.syncInertAttribute();\n });\n },\n );\n\n // Initialize session data asynchronously\n this.initializeAsync();\n }\n\n /**\n * @internal\n * Initialize session data asynchronously\n */\n protected async initializeAsync(): Promise<void> {\n let bff: BffResponse;\n try {\n // Fetch session data from the server\n bff = await fetchSessionData(\n this[internal].sdkKey,\n this[internal].sdkKey.sessionAuthKey,\n );\n bff.channels = removeUnreleasedChannels(bff.channels);\n } catch (error) {\n this[internal].behaviorTree.bb.sdkStatus = \"FATAL_ERROR\";\n this[internal].behaviorTree.bb.sdkFatalErrorMessage =\n errorToString(error);\n this.behaviorTreeUpdate();\n return;\n }\n\n // Update world state\n this.dispatchEvent(\n new InternalUpdateWorldState({\n business: bff.business,\n customer: bff.customer,\n session: bff.session,\n channels: bff.channels,\n channelUiGroups: bff.channel_ui_groups,\n digitalWallets: bff.digital_wallets ?? null,\n paymentEntity: null,\n sessionTokenRequestId: null,\n succeededChannel: null,\n } satisfies WorldState),\n );\n }\n\n /**\n * @internal\n * Throws if the SDK is not initialized.\n */\n public assertInitialized(): asserts this is InitializedSdk {\n if (!this[internal].worldState) {\n throw new Error(\n \"The session data is not loaded. Listen for the `init` event. Only `createChannelPickerComponent` can be called before initialization.\",\n );\n }\n }\n\n /**\n * @internal\n */\n public isMock(): boolean {\n return false;\n }\n\n /**\n * @internal\n */\n public isProdLive() {\n return this[internal].sdkKey.hostId === \"pl\";\n }\n\n /**\n * @internal\n */\n private findChannel(channelCode: string) {\n this.assertInitialized();\n\n // TODO: use a map\n const channel = this[internal].worldState.channels.find(\n (ch) => ch.channel_code === channelCode,\n );\n return channel ?? null;\n }\n\n /**\n * @internal\n * Updates the session or other ascociated entities and syncs everything that depends on them.\n */\n private onUpdateWorldState(event: Event) {\n const data = (event as InternalUpdateWorldState).data;\n this[internal].worldState = mergeIgnoringUndefined(\n this[internal].worldState ?? ({} as WorldState),\n data,\n );\n\n // update locale\n const locale = this[internal].worldState.session.locale;\n this.t = createTFunction(locale);\n\n // update everything\n this.behaviorTreeUpdate();\n this.rerenderAllComponents();\n }\n\n /**\n * @internal\n * Updates channel component data and updates behavior tree and rerenders.\n */\n private onUpdateChannelComponentData(event: Event) {\n const channelCode = (event as InternalUpdateChannelComponentData)\n .channelCode;\n const newData = (event as InternalUpdateChannelComponentData).data;\n const component =\n this[internal].liveComponents.paymentChannels.get(channelCode);\n if (!component) {\n return;\n }\n\n component.data = mergeIgnoringUndefined(component.data, newData);\n this.behaviorTreeUpdate();\n\n // TODO: need to re-collect all channel properties since form fields may have been added or removed\n this.rerenderAllComponents();\n }\n\n /**\n * @internal\n * Updates the behavior tree with the latest world state and component state.\n */\n private behaviorTreeUpdate(): void {\n const bb = this[internal].behaviorTree.bb;\n\n if (bb.sdkStatus === \"LOADING\" && this[internal].worldState) {\n bb.sdkStatus = \"ACTIVE\";\n }\n\n bb.world = this[internal].worldState;\n\n if (this[internal].currentDigitalWalletSubmission) {\n // populate data for digital wallet submission\n bb.channel = this.findChannel(\n this[internal].currentDigitalWalletSubmission.channelCode,\n );\n bb.channelProperties =\n this[internal].currentDigitalWalletSubmission.channelProperties;\n bb.channelData = null;\n bb.channelIsDigitalWallet = true;\n bb.instantSubmissionError =\n this[internal].currentDigitalWalletSubmission.instantSubmissionError;\n } else {\n // populate data for normal channel component\n const component = this[internal].currentChannelCode\n ? this[internal].liveComponents.paymentChannels.get(\n this[internal].currentChannelCode,\n )\n : null;\n bb.channel = component\n ? resolvePairedChannel(\n component.channel[internal],\n component.data.savePaymentMethod,\n )\n : null;\n bb.channelProperties = component ? component.channelProperties : null;\n bb.channelData = component ? component.data : null;\n bb.channelIsDigitalWallet = false;\n }\n\n try {\n this[internal].behaviorTree.update();\n } catch (error) {\n // crash handler, move to fatal error state\n this[internal].behaviorTree.bb.sdkStatus = \"FATAL_ERROR\";\n this[internal].behaviorTree.bb.sdkFatalErrorMessage =\n errorToString(error);\n this[internal].behaviorTree.update();\n }\n }\n\n /**\n * @internal\n * Return the current SDK status.\n */\n public getSdkStatus(): SdkStatus {\n // TODO: pass this as a prop into SessionProvider instead\n return this[internal].behaviorTree.bb.sdkStatus;\n }\n\n /**\n * @internal\n * Rerender everything.\n */\n private rerenderAllComponents() {\n // re-render live components\n this.renderChannelPicker();\n for (const channelCode of this[\n internal\n ].liveComponents.paymentChannels.keys()) {\n this.renderPaymentChannel(channelCode);\n }\n for (const digitalWalletCode of this[\n internal\n ].liveComponents.digitalWalletContainer.keys()) {\n this.renderDigitalWalletComponent(digitalWalletCode);\n }\n }\n\n /**\n * @public\n * Retrieve the xendit session object.\n */\n getSession(): XenditSession {\n this.assertInitialized();\n return bffSessionToPublic(this[internal].worldState.session);\n }\n\n /**\n * @public\n * Retrieve the customer ascociated with the session.\n */\n getCustomer(): XenditCustomer | null {\n this.assertInitialized();\n if (!this[internal].worldState.customer) return null;\n return bffCustomerToPublic(this[internal].worldState.customer);\n }\n\n /**\n * @public\n * Retrieve the list of payment channels available for this session.\n *\n * The channels are organized in a way that is appropriate to show to users.\n * You can use this to render your channel picker UI.\n *\n * You can pass `{filter: \"CHANNEL_CODE\"}` to filter channels by string or regexp.\n */\n getActiveChannelGroups(\n options?: XenditGetChannelsOptions,\n ): XenditPaymentChannelGroup[] {\n this.assertInitialized();\n return bffUiGroupsToPublic(\n this[internal].worldState.channels,\n this[internal].worldState.channelUiGroups,\n {\n options: {\n filter: options?.filter,\n filterMinMax: options?.filterMinMax ?? true,\n },\n session: this[internal].worldState.session,\n pairChannels: findChannelPairs(this[internal].worldState.channels),\n },\n );\n }\n\n /**\n * @public\n * Retrieve an unorganized list of payment channels available for this session.\n *\n * Use this when you need to search for specific channels. When rendering your UI,\n * consider using `getActiveChannelGroups` if you support many channels.\n *\n * You can pass `{filter: \"CHANNEL_CODE\"}` to filter channels by string or regexp.\n */\n getActiveChannels(\n options?: XenditGetChannelsOptions,\n ): XenditPaymentChannel[] {\n this.assertInitialized();\n return bffChannelsToPublic(\n this[internal].worldState.channels,\n this[internal].worldState.channelUiGroups,\n {\n options: {\n filter: options?.filter,\n filterMinMax: options?.filterMinMax ?? true,\n },\n session: this[internal].worldState.session,\n pairChannels: findChannelPairs(this[internal].worldState.channels),\n },\n );\n }\n\n /**\n * @public\n * Creates a drop-in UI component for selecting a channel and making payments.\n *\n * This returns a div immediately. The component will be populated after\n * initialization is complete. You should insert this div into the DOM.\n *\n * Calling this again will destroy it and return a new element. Manually\n * destroying the component is not necessary, removing it from the DOM is sufficient.\n *\n * @example\n * ```\n * const channelPickerDiv = components.createChannelPickerComponent();\n * document.querySelector(\".payment-container\").appendChild(channelPickerDiv);\n * ```\n */\n createChannelPickerComponent(): HTMLElement {\n // destroy previous instance if it exists\n if (this[internal].liveComponents.channelPicker) {\n this.destroyComponent(this[internal].liveComponents.channelPicker);\n }\n\n const container = document.createElement(\"xendit-channel-picker\");\n container.setAttribute(\"translate\", \"no\");\n\n // Store the container for later population\n this[internal].liveComponents.channelPicker = container;\n\n // If initialization is complete, populate immediately\n // Otherwise, it will be populated when initializeAsync completes\n if (this[internal].worldState) {\n this.renderChannelPicker();\n }\n\n this.setupUiEventsForChannelPicker(container);\n\n return container;\n }\n\n /**\n * @internal\n * Render an existing channel picker element\n */\n private renderChannelPicker(): void {\n this.assertInitialized();\n\n const container = this[internal].liveComponents.channelPicker;\n if (!container) return;\n\n render(\n createElement(XenditSessionProvider, {\n data: this[internal].worldState,\n sdk: this,\n children: createElement(XenditChannelPicker, {}),\n }),\n container,\n );\n }\n\n /**\n * @internal\n * Handles events from the channel picker component.\n */\n private setupUiEventsForChannelPicker(container: HTMLElement): void {\n // clear current channel when the channel picker accordion is closed\n container.addEventListener(\n XenditClearCurrentChannelEvent.type,\n (_event) => {\n this.assertInitialized();\n\n // do nothing if the current channel is not in the same ui group as the event\n const event = _event as XenditClearCurrentChannelEvent;\n const currentChannelCode = this[internal].currentChannelCode;\n if (!currentChannelCode) return;\n const channel = this[internal].worldState.channels.find(\n (ch) => ch.channel_code === currentChannelCode,\n );\n if (!channel || channel.ui_group !== event.uiGroup) return;\n\n // clear active channel\n this.setCurrentChannel(null);\n },\n );\n }\n\n /**\n * @public\n * Creates a UI component for making payments with a specific channel. It will\n * contain form fields, and/or instructions for the user.\n *\n * This also makes the provided channel \"current\", the `submit` method\n * will use that channel.\n *\n * This returns a div. You should insert this div into the DOM. Creating a new\n * component multiple times for the same channel will return the same component instance.\n *\n * Destroying the component manually is not necessary, removing it from the DOM is sufficient,\n * but if you want to clear the form state, you can do so with the `destroyComponent` method.\n *\n * @example\n * ```\n * const cardsChannel = components.getActiveChannels({ filter: \"CARDS\" })[0];\n * const paymentComponent = components.createChannelComponent(cardsChannel);\n * document.querySelector(\".payment-container\").appendChild(paymentComponent);\n * ```\n */\n createChannelComponent(\n channel: XenditPaymentChannel,\n active = true,\n ): HTMLElement {\n this.assertInitialized();\n\n if (\n !satisfiesMinMax(this[internal].worldState.session, channel[internal][0])\n ) {\n throw new Error(\n `Cannot create channel component: \\`session.amount\\` is outside of the channel's min/max amount.`,\n );\n }\n\n const channelCode = channel[internal][0].channel_code;\n\n if (active) {\n // make it active (before creating the component)\n this[internal].currentChannelCode = channelCode;\n }\n\n // return previously created component if it exists\n const cachedComponent =\n this[internal].liveComponents.paymentChannels.get(channelCode);\n let container: HTMLElement;\n let channelFormRef = createRef<ChannelFormHandle>();\n\n if (cachedComponent) {\n container = cachedComponent.element;\n channelFormRef = cachedComponent.channelFormRef;\n } else {\n container = document.createElement(\"xendit-payment-channel\");\n container.setAttribute(\"data-channel-code\", channelCode);\n container.setAttribute(\"inert\", \"\");\n container.setAttribute(\"translate\", \"no\");\n container.style.setProperty(\n \"--xendit-channel-brand-color\",\n channel[internal][0].brand_color,\n );\n\n this.setupUiEventsForPaymentChannel(container);\n\n this[internal].liveComponents.paymentChannels.set(channelCode, {\n element: container,\n channel,\n channelProperties: null,\n channelFormRef: channelFormRef,\n data: {\n savePaymentMethod: false,\n cardDetails: null,\n paymentOptions: null,\n },\n });\n }\n\n this.renderPaymentChannel(channelCode);\n if (active) {\n this.behaviorTreeUpdate();\n this.syncInertAttribute();\n }\n\n // rerender other components next tick because we may already be in a render\n this.dispatchEvent(new InternalNeedsRerenderEvent());\n\n return container;\n }\n\n /**\n * @internal\n * Render an existing payment channel element\n */\n private renderPaymentChannel(channelCode: string): void {\n this.assertInitialized();\n\n const component =\n this[internal].liveComponents.paymentChannels.get(channelCode);\n if (!component) return;\n\n const channelObject = component.channel;\n\n render(\n createElement(XenditSessionProvider, {\n data: this[internal].worldState,\n sdk: this,\n children: createElement(PaymentChannel, {\n channelOrPair: channelObject[internal],\n channelData: component.data,\n savePaymentMethod: component.data.savePaymentMethod,\n formRef: component.channelFormRef,\n }),\n }),\n component.element,\n );\n }\n\n /**\n * @internal\n * TODO: make this public\n * Returns a list of digital wallets available for this session.\n *\n * For `GOOGLE_PAY`:\n *\n * A channel supported by Google Pay must be active for the session, and Google Pay must be available\n * in the session's country, and you must have configured your merchant ID on the Xendit dashboard.\n *\n * (Note that our hosted checkout doesn't have the requirement to provide a merchant ID)\n */\n public getActiveDigitalWallets(): XenditDigitalWallet[] {\n this.assertInitialized();\n if (!this[internal].worldState.digitalWallets) {\n return [];\n }\n return bffDigitalWalletsToPublic(\n this[internal].worldState.digitalWallets,\n this[internal].worldState.channels,\n this[internal].worldState.channelUiGroups,\n {\n options: {\n filterMinMax: false,\n },\n pairChannels: findChannelPairs(this[internal].worldState.channels),\n session: this[internal].worldState.session,\n },\n );\n }\n\n /**\n * @internal\n * TODO: make this public\n * Creates a UI component for making payments with a digital wallet. It will contain a button to trigger the digital\n * wallet payment. If the digital wallet is not supported by the browser, it will have `display:none`.\n *\n * After the user pays using the digital wallet UI, a submission will automatically begin. Equivalent to setting\n * the channel used (using `setCurrentChannel()`), and then calling `submit()`. The same events will be fired\n * as a normal submission, see {@link submit}.\n *\n * This returns a HTML Element, which you should insert into the DOM.\n */\n public createDigitalWalletComponent<T extends XenditDigitalWalletCode>(\n digitalWalletCode: T,\n digitalWalletOptions?: DigitalWalletOptions<T>,\n ): HTMLElement {\n this.assertInitialized();\n\n const prevComponent =\n this[internal].liveComponents.digitalWalletContainer.get(\n digitalWalletCode,\n );\n if (prevComponent) {\n this.destroyComponent(prevComponent.element);\n }\n\n const element = document.createElement(\"xendit-digital-wallet\");\n element.setAttribute(\"translate\", \"no\");\n element.style.setProperty(\"display\", \"none\"); // initially hide the component until we know whether the digital wallet is available\n this[internal].liveComponents.digitalWalletContainer.set(\n digitalWalletCode,\n {\n element,\n options: digitalWalletOptions,\n },\n );\n\n this.renderDigitalWalletComponent(digitalWalletCode);\n\n return element;\n }\n\n /**\n * @internal\n * Renders an existing digital wallet component.\n */\n renderDigitalWalletComponent(\n digitalWalletCode: XenditDigitalWalletCode,\n ): void {\n this.assertInitialized();\n const component =\n this[internal].liveComponents.digitalWalletContainer.get(\n digitalWalletCode,\n );\n if (!component) return;\n\n render(\n createElement(XenditSessionProvider, {\n data: this[internal].worldState,\n sdk: this,\n children: createElement(DigitalWalletContainer, {\n digitalWalletCode,\n digitalWalletOptions: component.options,\n }),\n }),\n component.element,\n );\n }\n\n /**\n * @public\n * Returns the current payment channel.\n */\n getCurrentChannel() {\n const currentChannelCode = this[internal].currentChannelCode;\n if (!currentChannelCode) {\n return null;\n }\n return (\n this.getActiveChannels().find((ch) => {\n if (\n ch.channelCode === currentChannelCode ||\n (Array.isArray(ch.channelCode) &&\n ch.channelCode.includes(currentChannelCode))\n ) {\n return true;\n }\n }) ?? null\n );\n }\n\n /**\n * @public\n * Makes the given channel the current channel for submission.\n *\n * The current channel:\n * - Is interactive if it has a form (other channel components are non-interactive)\n * - Is used when `submit()` is called.\n *\n * Set to null to clear the current channel.\n */\n setCurrentChannel(channel: XenditPaymentChannel | null): void {\n const currentChannelCode = this[internal].currentChannelCode;\n\n const channelCode = channel?.[internal][0].channel_code ?? null;\n\n if (currentChannelCode === channelCode) {\n // no change\n return;\n }\n\n this[internal].currentChannelCode = channelCode;\n\n // if channel is not null, the component must exist\n let component: CachedChannelComponent | null = null;\n if (channel && channelCode) {\n component =\n this[internal].liveComponents.paymentChannels.get(channelCode) ?? null;\n if (!component) {\n this.createChannelComponent(channel, false);\n component =\n this[internal].liveComponents.paymentChannels.get(channelCode) ??\n null;\n }\n }\n\n this.behaviorTreeUpdate();\n this.syncInertAttribute();\n this.renderChannelPicker();\n }\n\n /**\n * @internal\n * Ensure all components have the correct inert attribute. This needs to be called when the current channel changes or a submission starts or ends.\n */\n syncInertAttribute() {\n // all channel components should have `inert` unless they are the current channel and there is no submission in progress\n const hasSubmissionInProgress =\n this[internal].behaviorTree.bb.submissionRequested;\n const channelComponents = this[internal].liveComponents.paymentChannels;\n\n for (const [_, component] of channelComponents) {\n const channelCode = Array.isArray(component.channel.channelCode)\n ? component.channel.channelCode[0]\n : component.channel.channelCode;\n if (\n channelCode === this[internal].currentChannelCode &&\n !hasSubmissionInProgress\n ) {\n if (component.element.hasAttribute(\"inert\")) {\n component.element.removeAttribute(\"inert\");\n }\n } else {\n component.element.setAttribute(\"inert\", \"\");\n }\n }\n }\n\n /**\n * @internal\n * Handles events from the payment channel component.\n * - Updates channel properties when they change.\n * - Updates save payment method setting when it changes.\n */\n private setupUiEventsForPaymentChannel(container: HTMLElement): void {\n // update per-channel channel properties\n container.addEventListener(\n XenditChannelPropertiesChangedEvent.type,\n (_event) => {\n const event = _event as XenditChannelPropertiesChangedEvent;\n const channelCode = event.channel;\n const component =\n this[internal].liveComponents.paymentChannels.get(channelCode);\n if (!component) {\n return;\n }\n\n component.channelProperties = event.channelProperties;\n\n // update behavior tree (form validity may have changed)\n this.behaviorTreeUpdate();\n },\n );\n }\n\n /**\n * @public\n *\n * Reveals any hidden validation errors in the current channel's form. Does nothing if\n * there are no validation errors to show.\n *\n * Normally, validation errors on required fields are not shown if the user did not touch them.\n */\n showValidationErrors(): void {\n const channelInvalidBehavior = this[internal].behaviorTree.findBehavior(\n ChannelInvalidBehavior,\n );\n if (!channelInvalidBehavior) {\n // form is not invalid\n return;\n }\n\n const channelCode = this[internal].currentChannelCode;\n if (!channelCode) {\n // no current channel\n return;\n }\n\n const component =\n this[internal].liveComponents.paymentChannels.get(channelCode);\n if (!component) {\n throw new Error(\n \"Current channel is set but component is missing; this is a bug, please contact support.\",\n );\n }\n\n const form = component.channelFormRef.current;\n form?.setAllFieldsTouched();\n }\n\n /**\n * @public\n * Creates a container element for rendering action UIs.\n *\n * For example, 3DS or QR codes.\n *\n * Create an action container before or during the action-begin event, and\n * the action UI will be rendered inside it.\n * Creating an action container during an action will throw an error.\n *\n * If no action container is created (or if the created container is removed from the DOM or is too small),\n * the SDK will create an action container (in a modal dialog) for you.\n */\n createActionContainerComponent(): HTMLElement;\n\n /**\n * @public\n * Creates a container element for rendering action UIs with options.\n *\n * @param options - Configuration options for the action container\n */\n createActionContainerComponent(options: ActionContainerOptions): HTMLElement;\n\n /**\n * @internal If isInternal is passed, it bypasses the action-in-progress check.\n **/\n createActionContainerComponent(isInternal: typeof internal): HTMLElement;\n\n // implementation\n createActionContainerComponent(\n optionsOrInternal?: ActionContainerOptions | typeof internal,\n ): HTMLElement {\n this.assertInitialized();\n\n if (this[internal].liveComponents.actionContainer) {\n this.destroyComponent(this[internal].liveComponents.actionContainer);\n }\n\n // Type guard to check if parameter is the internal symbol\n const isInternal = optionsOrInternal === internal;\n const options = isInternal\n ? undefined\n : (optionsOrInternal as ActionContainerOptions | undefined);\n\n const requiresActionBehavior = this[internal].behaviorTree.findBehavior(\n PeRequiresActionBehavior,\n );\n if (\n !isInternal &&\n requiresActionBehavior &&\n !requiresActionBehavior.canCreateActionContainer\n ) {\n throw new Error(\n \"Unable to create action container; there is an action in progress. Create an action before or during the `action-begin` event.\",\n );\n }\n\n const container = document.createElement(\"xendit-action-container\");\n container.setAttribute(\"translate\", \"no\");\n\n // Apply QR code options as data attributes if provided\n if (options?.qrCode) {\n if (options.qrCode.qrCodeOnly !== undefined) {\n container.setAttribute(\n \"data-qr-code-only\",\n options.qrCode.qrCodeOnly.toString(),\n );\n }\n }\n\n this[internal].liveComponents.actionContainer = container;\n\n return container;\n }\n\n /**\n * @public\n * Destroys a component of any type created by the SDK. Removes it from the DOM if necessary.\n * Throws if the element is not a xendit component or if it was already destroyed.\n */\n destroyComponent(component: HTMLElement): void {\n if (!component.tagName.startsWith(\"XENDIT-\")) {\n throw new Error(\n \"Unable to destroy component; only elements created by this SDK can be destroyed.\",\n );\n }\n\n if (this[internal].liveComponents.channelPicker === component) {\n this[internal].liveComponents.channelPicker = null;\n render(null, component);\n component.remove();\n return;\n }\n\n for (const [channelCode, c] of this[internal].liveComponents\n .paymentChannels) {\n if (c.element === component) {\n this[internal].liveComponents.paymentChannels.delete(channelCode);\n if (this[internal].currentChannelCode === channelCode) {\n this.setCurrentChannel(null);\n }\n render(null, component);\n component.remove();\n return;\n }\n }\n\n if (this[internal].liveComponents.actionContainer === component) {\n this[internal].liveComponents.actionContainer = null;\n render(null, component);\n component.remove();\n return;\n }\n\n for (const [channelCode, c] of this[internal].liveComponents\n .digitalWalletContainer) {\n if (c.element === component) {\n this[internal].liveComponents.digitalWalletContainer.delete(\n channelCode,\n );\n render(null, component);\n component.remove();\n return;\n }\n }\n\n throw new Error(\n \"Unable to destroy component; component not found. It may have already been destroyed.\",\n );\n }\n\n /**\n * @public\n * Submit, makes a payment or saves a payment method for the current payment channel.\n *\n * Call this when your submit button is clicked. Listen to the events to know the status:\n * - `submission-begin` and `submission-end` to know when submission is in progress (you should disable your UI during this time). Submission-end also provides a reason.\n * - `action-begin` and `action-end` to know when user action is in progress\n * - `will-redirect` when the user will be redirected to another page\n * - `payment-[request|token]-[created|discarded]` informs you of the ID of the resource we create on the backend, and if/when it is discarded\n * - `session-complete` when the payment request or token is successfully created (you should redirect the user to your confirmation page)\n * - `session-expired-or-canceled` can happen at any time, but it's likely to happen on submission if the session expired or was cancelled during checkout\n * - `submission-not-ready` fires before `submission-begin` to indicate that you cannot submit while a submission is in progress\n *\n * When a submission fails, you can try again by calling `submit()` again.\n * (The `session-expired-or-canceled` and `fatal-error` events are fatal, submission failure is normal and recoverable)\n *\n * This corresponds to the endpoints:\n * - `POST /v3/payment_requests` for PAY sessions\n * - `POST /v3/payment_tokens` for SAVE sessions\n */\n submit() {\n this.assertInitialized();\n\n const sessionActiveBehavior = this[internal].behaviorTree.findBehavior(\n SessionActiveBehavior,\n );\n if (!sessionActiveBehavior) {\n throw new Error(\n \"Unable to submit; the session is not in the active state. Listen to the `session-complete` and `session-expired-or-canceled` events and display success or failure states accordingly.\",\n );\n }\n\n const channelCode = this[internal].currentChannelCode;\n if (!channelCode) {\n throw new Error(\n \"Unable to submit; there is no current payment channel. Create a payment component with `createChannelComponent` or make an existing one active with `setCurrentChannel`.\",\n );\n }\n\n const component =\n this[internal].liveComponents.paymentChannels.get(channelCode);\n if (!component) {\n throw new Error(\n \"Current channel is set but component is missing; this is a bug, please contact support.\",\n );\n }\n\n // ensure if user submits in invalid state, errors are visible\n this.showValidationErrors();\n\n const channelInvalidBehavior = this[internal].behaviorTree.findBehavior(\n ChannelInvalidBehavior,\n );\n if (channelInvalidBehavior) {\n throw new Error(\n \"Unable to submit; the form for the current channel has errors. Listen to the `submission-ready` and `submission-not-ready` events, do not allow submission while in the not-ready state.\",\n );\n }\n\n const channelValidBehavior =\n this[internal].behaviorTree.findBehavior(ChannelValidBehavior);\n if (!channelValidBehavior) {\n throw new Error(\n \"Unable to submit; the SDK is not in a valid state for submission. Listen to the `submission-ready` and `submission-not-ready` events, do not allow submission while in the not-ready state.\",\n );\n }\n\n this[internal].behaviorTree.bb.submissionRequested = true;\n this.behaviorTreeUpdate();\n\n this.syncInertAttribute();\n }\n\n /**\n * @internal\n * Submits a digital wallet payment.\n */\n submitDigitalWallet(\n digitalWalletCode: XenditDigitalWalletCode,\n channel: XenditPaymentChannel,\n channelProperties: ChannelProperties,\n instantSubmissionError: SubmissionError | null = null,\n ) {\n this.assertInitialized();\n\n this.setCurrentChannel(null);\n\n this[internal].currentDigitalWalletSubmission = {\n digitalWalletCode,\n channelCode: channel[internal][0].channel_code,\n channelProperties,\n instantSubmissionError,\n };\n\n this.addEventListener(\n XenditSubmissionEndEvent.type,\n () => {\n this[internal].currentDigitalWalletSubmission = null;\n },\n { once: true },\n );\n\n this[internal].behaviorTree.bb.submissionRequested = true;\n this.behaviorTreeUpdate();\n\n this.syncInertAttribute();\n }\n\n /**\n * @public\n * Cancels a submission.\n *\n * If a submission is in-flight, the request is cancelled. If an action is in progress,\n * the action is aborted. Any active PaymentRequest or PaymentToken is abandoned.\n *\n * Does nothing if there is no active submission.\n */\n abortSubmission() {\n this.assertInitialized();\n\n const submissionBehavior =\n this[internal].behaviorTree.findBehavior(SubmissionBehavior);\n if (!submissionBehavior) {\n return; // no submission in progress\n }\n\n this[internal].behaviorTree.bb.submissionRequested = false;\n this.behaviorTreeUpdate();\n }\n\n /**\n * @public\n * Completes a payment in test mode.\n *\n * The session must be in test mode, and the session type must be PAY, and\n * the sdk must have an in-progress action, and the channel must be a QR, VA, or OTC channel.\n *\n * @example\n * ```\n * components.addEventListener(\"action-begin\", () => {\n * components.simulatePayment();\n * });\n * ```\n */\n simulatePayment() {\n this.assertInitialized();\n\n if (this[internal].worldState.session.session_type !== \"PAY\") {\n throw new Error(\n 'Unable to simulate payment, the session type is not \"PAY\".',\n );\n }\n\n const requiresActionBehavior = this[internal].behaviorTree.findBehavior(\n PeRequiresActionBehavior,\n );\n if (!requiresActionBehavior) {\n throw new Error(\n \"Unable to simulate payment; there is no action in progress. You can simulate payments any time between the `action-begin` and `action-end` events.\",\n );\n }\n\n const paymentEntity = this[internal].worldState.paymentEntity;\n if (!paymentEntity) {\n throw new Error(\n \"The PeRequiresActionBehavior is present but there is no payment entity. This is a bug, please contact support.\",\n );\n }\n\n const channel = this.findChannel(paymentEntity.entity.channel_code);\n\n if (!channel) {\n throw new Error(\n \"Channel not found; this is a bug, please contact support.\",\n );\n }\n\n const action = findBestAction(paymentEntity.entity.actions);\n if (!action || !canBeSimulated(action)) {\n throw new Error(\n \"Unable to simulate payment; the action does not support simulation.\",\n );\n }\n\n this[internal].behaviorTree.bb.simulatePaymentRequested = true;\n this.behaviorTreeUpdate();\n }\n\n /**\n * @public\n * Request an immediate poll for session status. Useful for handling payment\n * affirmation (e.g. I have made the payment) by the user. The session must still\n * be active.\n *\n * @example\n * ```\n * function onUserAffirmPayment() {\n * components.pollImmediately();\n * }\n * ```\n */\n pollImmediately() {\n this.assertInitialized();\n\n if (this[internal].worldState.session.status !== \"ACTIVE\") {\n throw new Error(\n \"Unable to poll immediately; the session is not longer active.\",\n );\n }\n\n this[internal].behaviorTree.bb.pollImmediatelyRequested = true;\n this.behaviorTreeUpdate();\n }\n\n /**\n * @internal\n * TODO: remove this, it's for debugging\n */\n getState() {\n const channelCode = this[internal].currentChannelCode;\n const component = this[internal].liveComponents.paymentChannels.get(\n channelCode ?? \"\",\n );\n return {\n channelCode,\n channelProperties: component?.channelProperties || null,\n behaviorTree: this[internal].behaviorTree,\n };\n }\n\n /**\n * @public\n * The `init` event lets you know when the session data has been loaded.\n *\n * The `createChannelPickerComponent` method can be called before this event, but\n * most other functionaility needs to wait for this event.\n *\n * @example\n * ```\n * components.addEventListener(\"init\", () => {\n * components.getSession();\n * });\n * ```\n */\n addEventListener(\n name: \"init\",\n listener: XenditEventListener<XenditInitEvent>,\n options?: boolean | AddEventListenerOptions,\n ): void;\n\n /**\n * @public\n * The `submission-ready` and `submission-not-ready` events let you know when submission should be available.\n * If ready, you can call `submit()` to begin the payment or token creation process.\n *\n * \"submission-ready\" means a channel has been selected, and all required fields are populated,\n * and all fields are valid.\n *\n * Use this to enable/disable your submit button.\n *\n * @example\n * ```\n * components.addEventListener(\"submission-ready\", () => {\n * submitButton.disabled = false;\n * });\n * components.addEventListener(\"submission-not-ready\", () => {\n * submitButton.disabled = true;\n * });\n * ```\n */\n addEventListener(\n name: \"submission-ready\",\n listener: XenditEventListener<XenditReadyEvent>,\n options?: boolean | AddEventListenerOptions,\n ): void;\n addEventListener(\n name: \"submission-not-ready\",\n listener: XenditEventListener<XenditReadyEvent>,\n options?: boolean | AddEventListenerOptions,\n ): void;\n\n /**\n * @public\n * The `submission-begin` and `submission-end` events let you know when a submission is in progress.\n *\n * Use this to disable your UI while submission is in progress.\n *\n * In the case of successful submission, `submission-end` will be followed by `session-complete`.\n * In the case of failed submission, the SDK will return to the ready state and you can try submitting again.\n */\n addEventListener(\n name: \"submission-begin\",\n listener: XenditEventListener<XenditSubmissionBeginEvent>,\n options?: boolean | AddEventListenerOptions,\n ): void;\n addEventListener(\n name: \"submission-end\",\n listener: XenditEventListener<XenditSubmissionEndEvent>,\n options?: boolean | AddEventListenerOptions,\n ): void;\n\n /**\n * @public\n * The events `payment-request-created`, `payment-token-created`, `payment-request-discarded`, and `payment-token-discarded`\n * let you know when a payment request or payment token has been created (as part of a submission) or\n * discarded (by cancelling or failing a submission).\n */\n addEventListener(\n name: \"payment-request-created\",\n listener: XenditEventListener<XenditPaymentRequestCreatedEvent>,\n options?: boolean | AddEventListenerOptions,\n ): void;\n addEventListener(\n name: \"payment-token-created\",\n listener: XenditEventListener<XenditPaymentTokenCreatedEvent>,\n options?: boolean | AddEventListenerOptions,\n ): void;\n addEventListener(\n name: \"payment-request-discarded\",\n listener: XenditEventListener<XenditPaymentRequestDiscardedEvent>,\n options?: boolean | AddEventListenerOptions,\n ): void;\n addEventListener(\n name: \"payment-token-discarded\",\n listener: XenditEventListener<XenditPaymentTokenDiscardedEvent>,\n options?: boolean | AddEventListenerOptions,\n ): void;\n\n /**\n * @public\n * The `action-begin` and `action-end` events let you know when a user action is in progress.\n *\n * After submission, an action may be required (e.g. 3DS, redirect, QR code, etc.).\n * The SDK will control the UI for actions, you don't need to do anything.\n *\n * Avoid changing any application state while an action is in progress as it may be\n * confusing for the user or interrupt their payment attempt.\n *\n * `action-end` is fired after the action is done, successfully or not. Note that users can\n * voluntarily dismiss actions.\n */\n addEventListener(\n name: \"action-begin\",\n listener: XenditEventListener<XenditActionBeginEvent>,\n options?: boolean | AddEventListenerOptions,\n ): void;\n addEventListener(\n name: \"action-end\",\n listener: XenditEventListener<XenditActionEndEvent>,\n options?: boolean | AddEventListenerOptions,\n ): void;\n\n /**\n * @public\n * Event handler called just before the user is redirected to a third party site to\n * complete the payment.\n *\n * Since redirects are actions, this will always be preceded by an `action-begin` event.\n */\n addEventListener(\n name: \"will-redirect\",\n listener: XenditEventListener<XenditWillRedirectEvent>,\n options?: boolean | AddEventListenerOptions,\n ): void;\n\n /**\n * @public\n * Event handler called on success.\n * The payment has been made and/or the token has been created.\n */\n addEventListener(\n name: \"session-complete\",\n listener: XenditEventListener<XenditSessionCompleteEvent>,\n options?: boolean | AddEventListenerOptions,\n ): void;\n\n /**\n * @public\n * Event handler called when the session has expired or been cancelled.\n */\n addEventListener(\n name: \"session-expired-or-canceled\",\n listener: XenditEventListener<XenditSessionExpiredOrCanceledEvent>,\n options?: boolean | AddEventListenerOptions,\n ): void;\n\n /**\n * @public\n * Event handler called on pending state. You should show a pending UI in response to this event.\n *\n * The pending state means an associated payment request or token will take some time to complete.\n * No other payment attempts can be made while in the pending state.\n *\n * This occurs for payments requiring manual confirmation, e.g. FPX business payments.\n *\n * The pending state usually occurs after a submission-end event.\n * This event will also be fired if the SDK is initialized and the session is already pending.\n */\n addEventListener(\n name: \"session-pending\",\n listener: XenditEventListener<XenditSessionPendingEvent>,\n options?: boolean | AddEventListenerOptions,\n ): void;\n\n /**\n * @public\n * Event handler called when exiting the pending state.\n *\n * After the pending state, the session may be in the active state, allowing further attempts, or\n * it may be completed or expired/canceled, in which case the respective event will be fired immediently after this one.\n */\n addEventListener(\n name: \"session-not-pending\",\n listener: XenditEventListener<XenditSessionNotPendingEvent>,\n options?: boolean | AddEventListenerOptions,\n ): void;\n\n /**\n * @public\n * Event handler called when something unrecoverable has happened. You should create a new\n * session and a new SDK instance.\n */\n addEventListener(\n name: \"fatal-error\",\n listener: XenditEventListener<XenditFatalErrorEvent>,\n options?: boolean | AddEventListenerOptions,\n ): void;\n\n /**\n * @public\n * Fallback overload.\n */\n addEventListener<K extends keyof XenditEventMap>(\n type: K,\n listener: (this: XenditComponents, ev: XenditEventMap[K]) => void,\n options?: boolean | AddEventListenerOptions,\n ): void;\n\n /**\n * @internal\n * Implementation.\n */\n addEventListener(\n type: string,\n listener: unknown,\n options?: boolean | AddEventListenerOptions,\n ): void {\n this[internal].eventListenersPresent.set(type, true);\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return super.addEventListener(type, listener as any, options);\n }\n\n /**\n * @public\n * Fallback overload.\n */\n removeEventListener<K extends keyof XenditEventMap>(\n type: K,\n listener: (this: XenditComponents, ev: XenditEventMap[K]) => void,\n options?: boolean | AddEventListenerOptions,\n ): void;\n\n /**\n * @internal\n * Implementation.\n */\n removeEventListener(\n type: string,\n listener: unknown,\n options?: boolean | AddEventListenerOptions,\n ): void {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return super.removeEventListener(type, listener as any, options);\n }\n\n /**\n * @public\n * Formats a currency value according to the currency's conventions.\n *\n * e.g.\n * ```\n * USD 1000 -> \"$1,000\"\n * USD 1000.5 -> \"$1,000.50\"\n * IDR 1000000 -> \"Rp1.000.000\"\n * PHP 1000 -> \"₱1,000.00\"\n * ```\n */\n static amountFormat(amount: number, currency: string): string {\n return amountFormat(amount, currency);\n }\n}\n\n/**\n * @public\n * Test version of XenditComponents that uses mock data instead of API calls.\n * Use this class for testing and development purposes.\n *\n * The componentsSdkKey option is ignored.\n *\n * @example\n * ```\n * const testSdk = new XenditComponentsTest({});\n * ```\n */\nexport class XenditComponentsTest extends XenditComponents {\n /**\n * @internal\n * The mock to apply on the next poll.\n */\n public nextMockUpdate: BffPollResponse | null = null;\n\n /**\n * @public\n * Test SDK ignores componentsSdkKey and uses a mock key.\n */\n constructor(\n options: Omit<XenditComponentsOptions, \"componentsSdkKey\"> & {\n componentsSdkKey?: string;\n },\n ) {\n super({\n ...options,\n componentsSdkKey: makeTestSdkKey(),\n });\n\n // internal event listeners\n (this as EventTarget).addEventListener(\n InternalScheduleMockUpdateEvent.type,\n this.setNextMockUpdate.bind(this),\n );\n }\n\n /**\n * @internal\n * Override to use test data instead of making API calls\n */\n protected async initializeAsync(): Promise<void> {\n // Simulate network delay and prevent firing the init event before the constructor returns\n await sleep(MOCK_NETWORK_DELAY_MS);\n\n // Always use test data for this class\n const bff = (await import(\"./data/test-data\")).makeTestBffData();\n\n // Update internal data\n this.dispatchEvent(\n new InternalUpdateWorldState({\n business: bff.business,\n customer: bff.customer,\n session: bff.session,\n channels: bff.channels,\n channelUiGroups: bff.channel_ui_groups,\n digitalWallets: bff.digital_wallets ?? null,\n paymentEntity: null,\n sessionTokenRequestId: null,\n succeededChannel: null,\n } satisfies WorldState),\n );\n }\n\n /**\n * @internal\n * Indicates that this is a mock SDK.\n */\n public isMock(): boolean {\n return true;\n }\n\n /**\n * @internal\n * Sets the next mock update to use.\n */\n setNextMockUpdate(_event: Event): void {\n const event = _event as InternalScheduleMockUpdateEvent;\n this.nextMockUpdate = event.mockData;\n }\n}\n\n// re-exports\nexport type { ChannelProperties, ChannelPropertyPrimative };\n","// Must be the first import\nimport \"preact/debug\";\nimport \"preact/devtools\";\n\nimport { createIconSet } from \"./components/icon\";\nimport { createStyles } from \"./styles\";\nimport { setupPreactBatch } from \"./preact-batch\";\n\nif (typeof window === \"undefined\" || typeof document === \"undefined\") {\n // do not run browser initialization in node env\n} else {\n setupPreactBatch();\n createStyles();\n createIconSet();\n}\n\nexport * from \"./public-sdk\";\nexport * from \"./public-event-types\";\nexport * from \"./public-options-types\";\nexport * from \"./public-data-types\";\n","import { findFirstStyleOrLinkElement } from \"./dom-utils\";\nimport css from \"./styles.css\";\n\nexport function createStyles() {\n const styleElement = document.createElement(\"style\");\n styleElement.textContent = css;\n const firstStyleOrLinkElement = findFirstStyleOrLinkElement();\n if (firstStyleOrLinkElement) {\n firstStyleOrLinkElement.insertAdjacentElement(\"beforebegin\", styleElement);\n } else {\n document.head.appendChild(styleElement);\n }\n}\n","/* variables */\n:root {\n --xendit-font-family: sans-serif;\n --xendit-color-primary: #1762ee;\n --xendit-color-text: #252525;\n --xendit-color-text-secondary: #585858;\n --xendit-color-text-placeholder: #7d7d7d;\n --xendit-color-disabled: #f7f7f7;\n --xendit-color-danger: #d1414d;\n --xendit-color-border: #f3f3f3;\n --xendit-color-background: #ffffff;\n --xendit-focus-shadow: 0px 0px 0px 2px\n color-mix(in srgb, var(--xendit-color-primary) 15%, transparent);\n --xendit-animation-duration: 0.3s;\n --xendit-animation-ease: ease-in-out;\n --xendit-radius-1: 8px;\n --xendit-z-index-focus: 2;\n\n /* Browser-specific border collapse margins */\n --xendit-border-collapse-offset: -0.5px; /* Default for Chrome/Edge */\n --xendit-border-collapse-webkit-gecko: -1.5px; /* Fix Safari and Firefox subpixel rendering */\n\n /* QR code colors */\n --xendit-qr-foreground-color: #000000;\n --xendit-qr-background-color: #ffffff;\n\n /* icon colors */\n --xendit-color-icon-primary: #7c7c7c;\n --xendit-color-icon-secondary: #f1f1f1;\n}\n\n/* Set default font for root components */\nxendit-channel-picker,\nxendit-action-container,\nxendit-payment-channel {\n display: block;\n unicode-bidi: isolate;\n font-family: var(--xendit-font-family);\n color: var(--xendit-color-text);\n}\n\n.xendit-default-action-container {\n font-family: var(--xendit-font-family);\n}\n\nxendit-action-container {\n background-color: var(--xendit-color-background);\n flex: 1; /* Action container usually wants to stretch to fit, assuming the parent is a flexbox. */\n}\n\nxendit-payment-channel button,\nxendit-payment-channel textarea,\nxendit-payment-channel select,\nxendit-payment-channel input,\nxendit-payment-channel input::placeholder {\n font-family: inherit;\n}\n\nxendit-payment-channel input::placeholder,\nxendit-payment-channel textarea::placeholder,\nxendit-payment-channel select::placeholder {\n color: var(--xendit-color-text-placeholder);\n}\n\n/* Reusable typography classes */\n.xendit-text-12 {\n font-size: 12px;\n line-height: 16px;\n letter-spacing: -0.01px;\n}\n\n.xendit-text-14 {\n font-size: 14px;\n line-height: 16px;\n letter-spacing: -0.09px;\n}\n\n.xendit-text-16 {\n font-size: 16px;\n line-height: 16px;\n letter-spacing: -0.09px;\n}\n\n.xendit-text-18 {\n font-size: 18px;\n line-height: 24px;\n letter-spacing: -0.26px;\n}\n\n.xendit-text-20 {\n font-size: 20px;\n line-height: 28px;\n letter-spacing: -0.33px;\n}\n\n.xendit-text-12,\n.xendit-text-14,\n.xendit-text-16 {\n font-weight: 400;\n}\n\n.xendit-text-semibold {\n font-weight: 600;\n}\n\n.xendit-text-bold {\n font-weight: 700;\n}\n\n.xendit-text-link {\n color: var(--xendit-color-primary);\n}\n.xendit-text-secondary {\n color: var(--xendit-color-text-secondary);\n}\n\n.xendit-text-center {\n text-align: center;\n}\n\n/* Accordion component */\n\n.xendit-accordion {\n display: flex;\n flex-direction: column;\n border: 1px solid var(--xendit-color-border);\n border-radius: var(--xendit-radius-1);\n background: var(--xendit-color-background);\n}\n\n.xendit-accordion-item:not(:first-child) {\n border-top: 1px solid var(--xendit-color-border);\n border-top-left-radius: var(--xendit-radius-1);\n border-top-right-radius: var(--xendit-radius-1);\n}\n\n.xendit-accordion-item-header {\n display: grid;\n grid-template-columns: auto 1fr auto;\n grid-gap: 16px;\n align-items: center;\n cursor: pointer;\n padding: 24px 16px;\n color: var(--xendit-color-text);\n border-radius: 8px;\n}\n\n.xendit-accordion-item-disabled .xendit-accordion-item-header {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.xendit-accordion-item-header-title {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.xendit-accordion-item-disabled .xendit-accordion-item-header-title,\n.xendit-accordion-item-disabled .xendit-accordion-item-header-icon {\n opacity: 0.5;\n}\n\n.xendit-accordion-item.xendit-accordion-item-open\n .xendit-accordion-item-header {\n color: var(--xendit-color-primary);\n}\n\n.xendit-accordion-item-chevron {\n color: var(--xendit-color-text);\n}\n\n.xendit-accordion-item-disabled .xendit-accordion-item-chevron {\n display: none;\n}\n\n.xendit-accordion-item-chevron g {\n transition: transform var(--xendit-animation-duration)\n var(--xendit-animation-ease);\n}\n\n.xendit-accordion-item-header:focus-visible {\n border-radius: 8px;\n box-shadow: 0px 0px 0px 2px\n color-mix(in srgb, var(--xendit-color-primary) 15%, transparent);\n outline: none;\n}\n\n.xendit-accordion-item-content {\n overflow: hidden;\n transition: height var(--xendit-animation-duration)\n var(--xendit-animation-ease);\n}\n\n.xendit-accordion-item.xendit-accordion-item-closed\n .xendit-accordion-item-content {\n height: 0;\n}\n\n.xendit-accordion-item.xendit-accordion-item-open\n .xendit-accordion-item-content {\n height: calc-size(auto, size);\n}\n\n.xendit-accordion-item-padding {\n padding: 16px;\n}\n\n/* Channel picker digital wallet section */\n\n.xendit-channel-picker-digital-wallet-section {\n display: grid;\n grid-auto-flow: column;\n grid-auto-columns: 1fr;\n gap: 8px;\n margin-bottom: 8px;\n}\n\n/* Channel picker group */\n\n.xendit-channel-picker-group {\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n\n.xendit-channel-picker-group select {\n border: 1px solid var(--xendit-color-border);\n border-radius: 8px;\n padding: 12px;\n appearance: none;\n outline: none;\n}\n\n.xendit-channel-picker-group select:focus {\n box-shadow: 0px 0px 0px 2px\n color-mix(in srgb, var(--xendit-color-primary) 15%, transparent);\n}\n\n.xendit-channel-logo {\n width: 24px;\n height: 16px;\n margin: -5px 0;\n padding: 4px;\n border: 1px solid var(--xendit-color-border);\n border-radius: 4px;\n background-color: white; /* always white, not --xendit-color-background */\n object-fit: contain;\n}\n\n/* Payment channel */\n\nxendit-payment-channel[inert] {\n filter: opacity(0.5) grayscale(1);\n}\n\n.xendit-payment-channel {\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n\n.xendit-payment-channel-banner {\n width: 100%;\n height: auto;\n object-fit: contain;\n}\n\n.xendit-payment-channel-instructions {\n display: grid;\n grid-template-columns: auto 1fr;\n grid-gap: 12px;\n color: var(--xendit-color-text-secondary);\n}\n\n.xendit-payment-channel-instructions-logo {\n height: 40px;\n width: auto;\n object-fit: contain;\n}\n\n.xendit-payment-channel-instructions-text {\n display: flex;\n flex-direction: column;\n justify-content: center;\n gap: 4px;\n}\n\n.xendit-payment-channel-instructions-text p {\n margin: 0;\n}\n\n/* Forms */\n\n.xendit-channel-form {\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n\n.xendit-channel-form > form {\n display: contents;\n}\n\n.xendit-form-field-group {\n display: grid;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n}\n\n.xendit-channel-form-field {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.xendit-channel-form-field-group {\n display: grid;\n gap: 8px;\n}\n\n.xendit-channel-form-field-group-label-container {\n display: flex;\n justify-content: space-between;\n gap: 16px;\n}\n\n.xendit-channel-form-field-group label {\n width: fit-content;\n cursor: pointer;\n}\n\n.xendit-form-field-group.invalid .xendit-channel-form-field input,\n.xendit-form-field-group.invalid\n .xendit-channel-form-field\n .xendit-iframe-container,\n.xendit-form-field-group.invalid .xendit-dropdown button {\n border: 1px solid var(--xendit-color-danger);\n}\n\n.xendit-channel-form-field input:not([type=\"checkbox\"]),\n.xendit-channel-form-field select,\n.xendit-channel-form-field .xendit-iframe-container {\n display: flex;\n border: 1px solid var(--xendit-color-border);\n background: var(--xendit-color-background);\n border-radius: 8px;\n padding: 12px;\n appearance: none;\n}\n\n/* TODO: Refine these class usages */\n.xendit-channel-form-field.field-radius-tl-0 input,\n.xendit-channel-form-field.field-radius-tl-0 button,\n.xendit-channel-form-field.field-radius-tl-0 .xendit-iframe-container {\n border-top-left-radius: 0;\n}\n\n.xendit-channel-form-field.field-radius-tr-0 input,\n.xendit-channel-form-field.field-radius-tr-0 button,\n.xendit-channel-form-field.field-radius-tr-0 .xendit-iframe-container {\n border-top-right-radius: 0;\n}\n\n.xendit-channel-form-field.field-radius-bl-0 input,\n.xendit-channel-form-field.field-radius-bl-0 button,\n.xendit-channel-form-field.field-radius-bl-0 .xendit-iframe-container {\n border-bottom-left-radius: 0;\n}\n\n.xendit-channel-form-field.field-radius-br-0 input,\n.xendit-channel-form-field.field-radius-br-0 button,\n.xendit-channel-form-field.field-radius-br-0 .xendit-iframe-container {\n border-bottom-right-radius: 0;\n}\n\n.xendit-channel-form-field.field-collapse-l,\n.xendit-channel-form-field.field-collapse-l {\n margin-left: var(--xendit-border-collapse-offset);\n}\n\n.xendit-channel-form-field.field-collapse-r,\n.xendit-channel-form-field.field-collapse-r {\n margin-right: var(--xendit-border-collapse-offset);\n}\n\n.xendit-channel-form-field.field-collapse-l .xendit-iframe-container {\n margin-left: calc(var(--xendit-border-collapse-offset) * 2);\n width: calc(100% + abs(var(--xendit-border-collapse-offset) * 2));\n}\n\n.xendit-channel-form-field.field-collapse-r .xendit-iframe-container {\n margin-right: 0;\n}\n\n.xendit-channel-form-field.field-collapse-t input,\n.xendit-channel-form-field.field-collapse-t button,\n.xendit-channel-form-field.field-collapse-t .xendit-iframe-container {\n margin-top: var(--xendit-border-collapse-offset);\n}\n\n.xendit-channel-form-field.field-collapse-b input,\n.xendit-channel-form-field.field-collapse-b button,\n.xendit-channel-form-field.field-collapse-b .xendit-iframe-container {\n margin-bottom: var(--xendit-border-collapse-offset);\n}\n\n/* Safari and Firefox specific adjustments */\n@supports (font: -apple-system-body) or (-moz-appearance: none) {\n .xendit-channel-form-field.field-collapse-l .xendit-iframe-container {\n margin-left: 0;\n width: 100%;\n }\n\n .xendit-channel-form-field.field-collapse-b input,\n .xendit-channel-form-field.field-collapse-b button {\n margin-bottom: var(--xendit-border-collapse-webkit-gecko);\n height: calc(100% + abs(var(--xendit-border-collapse-webkit-gecko) * 2));\n }\n}\n\n.xendit-channel-form-field.field-collapse-r .xendit-iframe-container:focus {\n border-right: none;\n}\n\n.xendit-channel-form-field.field-collapse-l .xendit-iframe-container:focus {\n border-left: none;\n}\n/* Ends TODO */\n\n.xendit-card-brand-logo {\n width: 24px;\n height: 16px;\n border: 1px solid var(--xendit-color-border);\n border-radius: 4px;\n padding: 4px;\n background-color: white; /* always white, not --xendit-color-background */\n}\n\n.xendit-card-brands-list {\n display: flex;\n align-items: center;\n padding: 8px 12px;\n gap: 4px;\n}\n\n.xendit-channel-form-field input:focus,\n.xendit-channel-form-field select:focus,\n.xendit-channel-form-field .xendit-iframe-container.xendit-field-focus {\n border-color: var(--xendit-color-primary);\n box-shadow: var(--xendit-focus-shadow);\n outline: none;\n z-index: var(--xendit-z-index-focus);\n}\n\n.xendit-channel-form-field button:focus {\n position: relative;\n z-index: var(--xendit-z-index-focus);\n}\n\n.xendit-channel-form-field .xendit-iframe-container {\n height: 40px;\n width: 100%;\n padding: 0;\n overflow: hidden;\n box-sizing: border-box;\n}\n\n.xendit-channel-form-field .xendit-iframe-container iframe {\n height: 40px;\n width: 100%;\n border: none;\n min-width: 0;\n}\n\n.xendit-channel-form-field.xendit-form-field-span-1 {\n grid-column: span 1;\n}\n\n.xendit-channel-form-field.xendit-form-field-span-2 {\n grid-column: span 2;\n}\n\n.xendit-checkbox {\n display: flex;\n align-items: center;\n}\n\n.xendit-checkbox-box {\n display: flex;\n}\n\n.xendit-checkbox input {\n width: 16px;\n height: 16px;\n margin: 0;\n cursor: pointer;\n}\n\n.xendit-checkbox label {\n cursor: pointer;\n padding-left: 8px;\n}\n\n.xendit-checkbox input {\n opacity: 0;\n position: absolute;\n}\n\n.xendit-checkbox input + .xendit-checkbox-graphic {\n width: 16px;\n height: 16px;\n border: 1px solid var(--xendit-color-border);\n border-radius: 4px;\n box-sizing: border-box;\n color: transparent;\n}\n\n.xendit-checkbox input:checked + .xendit-checkbox-graphic {\n color: var(--xendit-color-background);\n background-color: var(--xendit-color-primary);\n border-color: var(--xendit-color-primary);\n}\n\n/* Dialog */\n\n.xendit-dialog-backdrop {\n position: fixed;\n top: 0;\n bottom: 0;\n left: 0;\n right: 0;\n background: rgba(0, 0, 0, 0.5);\n display: flex;\n padding: 48px;\n justify-content: center;\n align-items: center;\n}\n\n.xendit-dialog {\n background-color: var(--xendit-color-background);\n border-radius: 8px;\n position: relative;\n}\n\n.xendit-dialog-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n color: var(--xendit-color-text);\n padding: 16px;\n gap: 16px;\n line-height: 20px;\n border-bottom: 1px solid var(--xendit-color-border);\n}\n\n.xendit-dialog-header button {\n display: flex;\n background: none;\n border: none;\n color: var(--xendit-color-text);\n cursor: pointer;\n padding: 0;\n}\n\n.xendit-dialog-floating-close {\n position: absolute;\n top: 24px;\n right: 24px;\n background: none;\n border: none;\n color: var(--xendit-color-text);\n cursor: pointer;\n padding: 0;\n}\n\n.xendit-dialog-body {\n display: flex;\n padding: 24px;\n}\n\n.xendit-error-message {\n color: var(--xendit-color-danger);\n}\n\n/* Phone input Dropdown */\n.xendit-input-phone {\n display: flex;\n gap: 8px;\n}\n\n.xendit-phone-number-input {\n width: 100%;\n}\n\n.xendit-dropdown .xendit-dropdown-search input {\n padding: 8px;\n border: 1px solid var(--xendit-color-border);\n border-radius: var(--xendit-radius-1);\n box-sizing: border-box;\n}\n\n.xendit-dropdown-search input:focus {\n outline: none;\n border-color: var(--xendit-color-primary);\n box-shadow: var(--xendit-focus-shadow);\n}\n\n/* Phone input Dropdown ends */\n\n/* Dropdown */\n.xendit-dropdown button {\n width: 100%;\n display: grid;\n grid-template-columns: 1fr auto;\n align-items: center;\n gap: 8px;\n text-align: left;\n background-color: var(--xendit-color-background);\n border: 1px solid var(--xendit-color-border);\n border-radius: var(--xendit-radius-1);\n justify-content: space-between;\n padding: 12px;\n cursor: pointer;\n}\n\n.xendit-dropdown button.xendit-dropdown-has-asset {\n grid-template-columns: auto 1fr auto;\n}\n\n.xendit-dropdown button:disabled {\n background: var(--xendit-color-disabled);\n}\n\n.xendit-dropdown button:focus {\n outline: none;\n border: 1px solid var(--xendit-color-primary);\n box-shadow: 0px 0px 0px 2px #1762ee26;\n}\n\n.xendit-dropdown-menu {\n position: absolute;\n z-index: 1;\n display: flex;\n flex-direction: column;\n gap: 4px;\n max-height: 168px;\n width: 257px;\n padding: 4px;\n margin: 4px 0;\n background-color: var(--xendit-color-background);\n border: 1px solid var(--xendit-color-border);\n border-radius: var(--xendit-radius-1);\n list-style: none;\n box-shadow: 0px 4px 8px 0px #25252514;\n overflow-y: auto;\n}\n\n.xendit-dropdown-menu ul {\n list-style: none;\n padding: 4px;\n margin-top: 0;\n}\n\n.xendit-dropdown-search {\n position: sticky;\n top: 0;\n z-index: 1;\n}\n\n.xendit-dropdown-search input {\n width: 100%;\n}\n\n.xendit-dropdown-item {\n display: grid;\n grid-template-columns: 1fr auto;\n align-items: center;\n gap: 8px;\n padding: 8px 12px 8px 4px;\n border-radius: var(--xendit-radius-1);\n cursor: pointer;\n z-index: 0;\n --xendit-dropdown-item-hover-color: var(--xendit-color-background);\n --xendit-dropdown-item-hover-bg-color: var(--xendit-color-primary);\n}\n\n.xendit-dropdown-item-disabled {\n --xendit-dropdown-item-hover-color: var(--xendit-color-text);\n --xendit-dropdown-item-hover-bg-color: var(--xendit-color-disabled);\n}\n\n.xendit-dropdown-item-active {\n box-shadow: var(--xendit-focus-shadow);\n}\n\n.xendit-dropdown-item:hover {\n background-color: var(--xendit-dropdown-item-hover-bg-color);\n}\n\n.xendit-dropdown-item:hover .xendit-dropdown-item-text,\n.xendit-dropdown-item:hover .xendit-dropdown-item-description {\n color: var(--xendit-dropdown-item-hover-color);\n}\n\n.xendit-dropdown-item-selected {\n color: var(--xendit-color-primary);\n}\n\n.xendit-dropdown-item:hover .xendit-dropdown-item-selected {\n color: var(--xendit-dropdown-item-hover-color);\n}\n\n.xendit-dropdown-item.xendit-dropdown-has-asset {\n grid-template-columns: auto 1fr auto;\n}\n\n.xendit-dropdown-item-text {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.xendit-dropdown-item-disabled {\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n.xendit-dropdown-item-disabled:hover,\n.xendit-dropdown-item-disabled.xendit-dropdown-item-active {\n background-color: var(--xendit-color-disabled);\n}\n\n/* Dropdown ends */\n\n/* Button */\n.xendit-button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n padding: 12px 16px;\n font-family: var(--xendit-font-family);\n font-size: 14px;\n font-weight: 600;\n line-height: 16px;\n letter-spacing: -0.09px;\n cursor: pointer;\n transition: background-color var(--xendit-animation-duration)\n var(--xendit-animation-ease);\n}\n.xendit-button-primary-rounded {\n border: 1px solid transparent;\n background-color: var(--xendit-color-primary);\n color: var(--xendit-color-background);\n border-radius: var(--xendit-radius-1);\n}\n.xendit-button-white-rounded {\n background-color: var(--xendit-color-background);\n color: var(--xendit-color-text);\n border: 1px solid var(--xendit-color-border);\n border-radius: var(--xendit-radius-1);\n}\n.xendit-button-white-rounded:hover {\n background-color: var(--xendit-color-border);\n}\n.xendit-button-block {\n width: 100%;\n}\n.xendit-button-sm {\n padding: 8px 12px;\n font-size: 12px;\n line-height: 16px;\n}\n\n@keyframes xendit-button-loading-spinner-spin {\n 0% {\n transform: rotate(0deg);\n }\n 100% {\n transform: rotate(360deg);\n }\n}\n\n.xendit-button-loading-spinner {\n width: 16px;\n height: 16px;\n animation: xendit-button-loading-spinner-spin 1s linear infinite;\n}\n\n.xendit-skeleton-field button {\n height: 42px;\n background-color: var(--xendit-color-disabled);\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--xendit-color-text-secondary);\n}\n\n/* Button ends */\n\n.xendit-dotted-line {\n height: 1px;\n border: none;\n background: repeating-linear-gradient(\n to right,\n var(--xendit-color-border) 0px 4px,\n transparent 4px 8px\n );\n margin: 16px 0;\n}\n\n/* Form Simulation Helper */\n.xendit-form-simulation-root {\n position: relative;\n}\n.xendit-form-simulation-trigger {\n background: transparent;\n border: none;\n cursor: pointer;\n padding: 0;\n}\n.xendit-form-simulation-popover {\n position: absolute;\n top: 100%;\n right: 0;\n\n width: 350px;\n display: flex;\n flex-direction: column;\n gap: 12px;\n border-radius: 4px;\n padding: 12px;\n border: 1px solid var(--xendit-color-border);\n background: color-mix(\n in srgb,\n var(--xendit-color-background),\n transparent 40%\n );\n backdrop-filter: blur(6px);\n box-shadow: 0px 0px 0px 2px\n color-mix(in srgb, var(--xendit-color-primary) 15%, transparent);\n}\n.xendit-form-simulation-popover .xendit-dropdown {\n position: relative;\n}\n.xendit-form-simulation-popover .xendit-dropdown-menu {\n width: auto;\n}\n.xendit-form-simulation-scenario-icon {\n height: 28px;\n width: 40px;\n border-radius: 4px;\n border: 1px solid var(--xendit-color-border);\n object-fit: contain;\n background-color: white;\n}\n\n/* Form Simulation Helper ends */\n\n.xendit-tooltip {\n position: absolute;\n top: 100%;\n right: 50%;\n transform: translateX(50%);\n background-color: black;\n color: white;\n padding: 8px 12px;\n border-radius: var(--xendit-radius-1);\n white-space: nowrap;\n z-index: 1000;\n font-weight: 600;\n font-size: 14px;\n line-height: 16px;\n animation: xendit-tooltip-fade-in var(--xendit-animation-duration)\n var(--xendit-animation-ease);\n opacity: 1;\n}\n\n@keyframes xendit-tooltip-fade-in {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n\n/* Instructions */\n\n.xendit-instructions-bold {\n font-weight: 600;\n}\n.xendit-instructions-bullet-list {\n display: flex;\n flex-direction: column;\n gap: 12px;\n margin: 8px 0;\n}\n.xendit-instructions-bullet-list::marker {\n color: var(--xendit-color-text-secondary);\n}\n.xendit-instructions-form-card {\n display: flex;\n flex-direction: column;\n padding: 16px;\n border-radius: 12px;\n border: 1px solid var(--xendit-color-border);\n gap: 4px;\n width: 321px;\n}\n.xendit-instructions-form-field {\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 8px 0;\n border-bottom: 1px solid var(--xendit-color-border);\n}\n.xendit-instructions-form-field-label {\n font-size: 12px;\n font-weight: 600;\n line-height: 16px;\n color: var(--xendit-color-text-secondary);\n}\n.xendit-instructions-form-field-value {\n font-size: 14px;\n line-height: 20px;\n color: var(--xendit-color-text);\n}\n.xendit-instructions-form-heading {\n font-size: 14px;\n font-weight: 600;\n line-height: 20px;\n margin: 4px 0;\n}\n.xendit-instructions-italics {\n font-style: italic;\n}\n.xendit-instructions-numbered-list {\n display: flex;\n flex-direction: column;\n gap: 16px;\n list-style-type: decimal;\n padding-left: 40px;\n}\n.xendit-instructions-single-tab-heading {\n font-size: 14px;\n font-weight: 600;\n line-height: 20px;\n margin-bottom: 16px;\n}\n.xendit-instructions-step-box {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n.xendit-instructions-step-li {\n font-size: 14px;\n line-height: 20px;\n}\n.xendit-instructions-step-li p {\n margin: 0;\n}\n.xendit-instructions-step-li::marker {\n margin-left: 20px;\n}\n.xendit-instructions-tab-button {\n font-family: var(--xendit-font-family);\n font-size: 14px;\n padding: 8px 4px;\n background-color: transparent;\n border: none;\n border-top: 3px solid transparent;\n border-bottom: 3px solid transparent;\n}\n.xendit-instructions-active-tab {\n border-bottom-color: var(--xendit-color-primary);\n color: var(--xendit-color-primary);\n font-weight: 600;\n}\n.xendit-instructions-tab-list {\n display: flex;\n gap: 16px;\n margin-bottom: 16px;\n border-bottom: 1px solid var(--xendit-color-border);\n}\n.xendit-instructions-table {\n font-size: 14px;\n line-height: 16px;\n width: 100%;\n border-collapse: collapse;\n}\n.xendit-instructions-table-cell {\n padding: 4px;\n border: 1px solid black;\n}\n.xendit-instructions-table-header {\n font-size: 14px;\n font-weight: 600;\n line-height: 16px;\n padding: 4px;\n border: 1px solid black;\n}\n\n/* Instructions ends */\n\n.xendit-default-action-container {\n display: flex;\n flex-direction: column;\n border: none;\n}\n\n.xendit-action-title {\n font-weight: 600;\n font-size: 20px;\n line-height: 28px;\n text-align: center;\n}\n\n.xendit-action-iframe {\n border: none;\n width: 100%;\n height: 100%;\n}\n\n.xendit-action-present-to-customer {\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n.xendit-action-present-to-customer-affirm {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n.xendit-action-qr-content {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 16px;\n max-width: 384px;\n border: 1px solid var(--xendit-color-border);\n border-radius: var(--xendit-radius-1);\n padding: 16px;\n padding-bottom: 24px;\n}\n.xendit-action-qr-channel-logo {\n height: 64px;\n object-fit: contain;\n}\n.xendit-action-qr-qrcode-container {\n width: 100%;\n}\n\n/* va actions */\n.xendit-action-va-content {\n display: flex;\n flex-direction: column;\n border: 1px solid var(--xendit-color-border);\n border-radius: var(--xendit-radius-1);\n padding: 16px;\n padding-bottom: 24px;\n}\n.xendit-action-va-details {\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n.xendit-action-va-detail-item {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n.xendit-action-va-detail-content {\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n.xendit-action-va-heading {\n color: var(--xendit-color-text-placeholder);\n}\n.xendit-action-va-tag {\n color: var(--xendit-color-text-placeholder);\n background-color: #fafafa;\n padding: 2px 4px;\n border-radius: 4px;\n}\n\n/* redirect, deeplink, and push notification actions */\n.xendit-redirect-instructions {\n display: flex;\n flex-direction: column;\n align-items: center;\n text-align: center;\n gap: 24px;\n}\n\n.xendit-redirect-instructions-logo {\n display: flex;\n justify-content: center;\n align-items: center;\n width: 112px;\n height: 112px;\n border: 2px solid var(--xendit-color-border);\n border-radius: 50%;\n overflow: hidden;\n}\n\n.xendit-redirect-instructions-logo img {\n width: 96px;\n height: 96px;\n object-fit: contain;\n}\n\n.xendit-redirect-instructions-text {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.xendit-redirect-instructions-button {\n display: inline-block;\n border-radius: 99px;\n color: white;\n padding: 12px 16px;\n background-color: var(--xendit-channel-brand-color, #000);\n text-decoration: none;\n white-space: nowrap;\n}\n\n.xendit-redirect-instructions-button:hover,\n.xendit-redirect-instructions-button:active {\n filter: brightness(1.1);\n}\n\n/* googlepay */\n\n.gpay-card-info-container-fill {\n display: flex;\n}\n"],"names":["Icon","props","name","size","direction","svgTransform","_jsx","className","width","height","viewBox","fill","stroke","children","transform","iconData","find","icon","node","makeIcon","id","scale","d","_jsxs","_Fragment","strokeLinecap","strokeLinejoin","once","XenditInitEvent","Event","static","constructor","super","type","XenditFatalErrorEvent","message","this","XenditReadyEvent","channelCode","XenditNotReadyEvent","XenditSubmissionBeginEvent","XenditSubmissionEndEvent","reason","userErrorMessage","developerErrorMessage","XenditActionBeginEvent","XenditActionEndEvent","XenditWillRedirectEvent","XenditSessionCompleteEvent","XenditSessionExpiredOrCanceledEvent","XenditSessionPendingEvent","XenditSessionNotPendingEvent","XenditPaymentRequestCreatedEvent","paymentRequestId","XenditPaymentTokenCreatedEvent","paymentTokenId","XenditPaymentRequestDiscardedEvent","XenditPaymentTokenDiscardedEvent","internal","Symbol","Accordion","class","AccordionItem","title","subtitle","disabled","open","onClick","chevronDirection","toggleOpen","useCallback","handleKeyPress","event","key","preventDefault","handleClick","classNames","onKeyDown","role","tabIndex","inert","SessionContext","createContext","displayName","BusinessContext","CustomerContext","ChannelsContext","ChannelUiGroupsContext","DigitalWalletsContext","SdkContext","CurrentChannelContext","useSession","context","useContext","Error","useChannels","useDigitalWallets","useSdk","useCurrentChannel","XenditSessionProvider","data","sdk","session","business","customer","channels","digitalWallets","channelUiGroups","channel","getCurrentChannel","getSdkStatus","status","Provider","value","MOCK_NETWORK_DELAY_MS","assert","arg","assertIsArray","Array","isArray","assertIsNotArray","assertEquals","a","b","sleep","ms","Promise","resolve","setTimeout","AbortError","isAbortError","error","cancellableSleep","signal","reject","onAbort","removeEventListener","clearTimeout","timeoutId","aborted","addEventListener","findBestAction","actions","best","descriptor","userAgent","navigator","test","isAndroidOrIos","findPaylinkAction","options","enablePaylinks","MOCK_HOST_ID","hosts","pl","pd","sl","sd","hostFromHostId","hostId","mergeIgnoringUndefined","original","updates","result","Object","keys","undefined","usePrevious","ref","useRef","useLayoutEffect","current","formFieldName","field","channel_property","values","join","seed","Math","floor","random","formFieldId","split","map","c","charCodeAt","toString","randomHexString","length","bytes","arr","Uint8Array","i","randomBytes","from","padStart","randomUUID","useIdSafe","canBeSimulated","action","errorToString","stack","JSON","stringify","removeUndefinedPropertiesFromObject","object","getOwnPropertyDescriptor","get","getValueFromChannelProperty","channelProperty","channelProperties","str","cursor","dotIndex","indexOf","slice","getCardNumberFromChannelProperties","cardNumber","parseEncryptedFieldValue","out","version","publicKey","iv","cipherText","valid","validationError","withoutValidationError","parts","parseInt","isNaN","atob","objectIdMap","WeakMap","objectIdCounter","resolvePairedChannel","savePaymentMethod","allow_save","satisfiesMinMax","session_type","amount","min","min_amount","max","max_amount","Number","MAX_VALUE","lockDownInteralProperty","obj","defineProperty","enumerable","writable","configurable","RELEASED_CHANNELS","CARDS","QRIS","QR_PH","PROMPTPAY","SGQR","formHasFieldOfType","form","ButtonVariant","ButtonSize","Button","variant","rest","buttonVariantClass","BARE","PRIMARY_ROUNDED","WHITE_ROUNDED","buttonSizeClass","SM","MD","ButtonLoadingSpinner","angle1","PI","radius","start","cos","sin","end","strokeWidth","Dropdown","_id","onChange","defaultIndex","selectedIndex","placeholder","t","generatedId","isControlled","internalIndex","setInternalIndex","useState","currentIndex","activeIndex","setActiveIndex","_open","setOpen","searchQuery","setSearchQuery","rootRef","btnRef","listRef","activeRef","searchInputRef","filteredOptions","useMemo","filtered","withIndex","filter","item","opt","trim","query","toLowerCase","includes","description","clampedActive","onMouseDown","e","root","contains","target","document","onFocusOut","relatedTarget","body","scrollContainer","parentElement","scrollTop","offsetTop","clientHeight","openList","queueMicrotask","focus","closeList","onButtonClick","selectItemAndClose","index","onButtonKeyDown","onListKeyDown","isSearchInput","activeItem","originalIndex","onOptionClick","stopPropagation","currentTarget","dataset","onSearchTermChange","selected","leadingAsset","shortTitle","onInput","isSelected","isActive","DropdownSkeleton","bffSessionToPublic","bffSession","assertNotEquals","mode","payment_session_id","sessionType","referenceId","reference_id","country","currency","channel_properties","expiresAt","Date","expires_at","locale","items","netUnitAmount","net_unit_amount","quantity","url","imageUrl","image_url","category","subcategory","metadata","bffUiGroupToPublic","bffChannelGroup","channelsByGroupId","groupsByGroupId","marshalConfig","group","groupId","label","bffChannelToPublic","singleBffChannelToPublic","bffChannel","bffChannelsByGroupId","bffGroupsByGroupId","pairChannels","paired","channel_code","pairs","ch","brandName","brand_name","brandColor","brand_color","brandLogoUrl","brand_logo_url","uiGroup","ui_group","minAmount","maxAmount","cardBrands","card","brands","logoUrl","logo_url","makeGroupsByGroupId","bffChannelGroups","groupMap","bffGroup","channelFilterFn","filterMinMax","code","RegExp","channelCodeMatchesFilter","makeChannelsByGroupId","bffChannels","push","findChannelPairs","brandMap","Map","has","set","_","pair","other","ChannelPickerGroup","currentChannel","dropdownId","fakeDropdownSelection","setFakeDropdownSelection","containerRef","containerIsPopulated","setContainerIsPopulated","selectedChannelElementRef","pairChannelData","channelsInGroup","createChannelComponent","replaceChildren","previousOpen","setCurrentChannel","onSelectedChannelChange","dropdownOption","channelOptions","src","getChannelDisabledReason","hideDropdown","htmlFor","groupName","ns","i1","findIndex","i2","dropdownSelectedIndex","style","display","ChannelPickerDigitalWalletSection","digitalWalletsGooglePay","google_pay","el","createDigitalWalletComponent","appendChild","remove","XenditChannelPicker","useChannelUiGroups","channelsByGroup","thisRef","selectedGroupId","previewGroupId","setPreviewGroupId","handleSelectChannelGroup","dispatchEvent","XenditClearCurrentChannelEvent","newGroup","g","enabledChannels","groupEnabledChannelStats","digitalWalletSectionEnabled","enableDigitalWallets","enabledChannelsStats","disabledReason","firstDisabledChannelReason","bubbles","composed","FlagIcon","countryCode","borderRadius","backgroundImage","backgroundSize","backgroundPosition","CountryField","selectedCountry","setSelectedCountry","selectedCountryIndex","COUNTRIES_AS_DROPDOWN_OPTIONS","option","hiddenFieldRef","useOnCardCountryChange","newCountry","newOption","onChangeWrapper","defaultValue","getCountries","Intl","DisplayNames","of","sort","localeCompare","fn","cardDetails","useChannelComponentData","cardDetailsCountry","details","country_codes","previousCardDetailsCountry","DropdownField","isDropdownField","fieldOptions","HTMLElement","window","EventTarget","XenditFormAssociatedFocusTrap","internals","attachInternals","element","customElements","define","tag","InternalUpdateWorldState","InternalUpdateChannelComponentData","InternalSetFieldTouchedEvent","InternalBehaviorTreeUpdateEvent","InternalNeedsRerenderEvent","InternalScheduleMockUpdateEvent","mockData","IframeRegistryContext","IFRAME_ORIGIN","URL","origin","IframeRegistryProvider","iframeRegistry","iframeRegistryValue","registerIframe","fieldName","unregisterIframe","delete","postMessageToIframe","iframe","contentWindow","postMessage","parsedIframeUrl","IFRAME_SRC","IframeField","iframeRef","iframeEcdhPublicKey","setIframeEcdhPublicKey","focusWithin","setFocusWithin","cardBrand","setCardBrand","useChannel","handleEventFromIframe","expectedSource","source","ecdhPublicKey","encrypted","encryptionVersion","resultData","enc","empty","validationErrorCodes","btoa","localeKey","console","giveFocusToIframe","registry","iframeUrl","searchParams","location","sdkKey","signature","iframeFieldAppearance","focusClass","onFocus","sandbox","CardBrands","cardsBrandList","selectedCardBrand","cardBrandLogo","alt","PhoneNumberField","setCountryCode","countryCodeIndex","COUNTRIES_WITH_DIAL_CODES_AS_DROPDOWN_OPTIONS","r","localNumber","setLocalNumber","inputRef","formatPhoneNumber","phoneNumber","sanitizePhoneNumber","number","dial","updateHiddenField","handleCountryChange","nextCountry","inputMode","getExampleNumber","examples","formatInternational","replace","getCountryCallingCode","onBlur","international","formatForUser","nextLocal","autoComplete","Boolean","parsed","parsePhoneNumberFromString","isPossible","toTitleValuePair","nameValue","PROVINCES_US","PROVINCES_CA","PROVINCES_GB","province","ProvinceField","allFields","useChannelProperties","clearValue","onChangeDropdown","onChangeInput","getProvinceList","thisField","otherField","previousField","getBestCountryForProvinceField","previousOptions","TextField","minLength","isTextField","min_length","maxLength","max_length","autocomplete","CURRENCY_NUMBER_FORMAT_LOCALE","IDR","VND","BRL","RUB","CZK","RON","UAH","CLP","COP","UYU","ARS","INR","NPR","LKR","BDT","CURRENCY_SYMBOLS","USD","CAD","EUR","AFN","ALL","AMD","AUD","AZN","BAM","BIF","BND","BOB","BWP","BYN","BZD","CDF","CHF","CNY","CRC","CVE","DJF","DKK","DOP","ERN","ETB","GBP","GEL","GHS","GNF","GTQ","HKD","HNL","HUF","ILS","IRR","ISK","JMD","JPY","KES","KHR","KMF","KRW","KZT","MDL","MGA","MKD","MMK","MOP","MUR","MXN","MYR","MZN","NAD","NGN","NIO","NOK","NZD","PAB","PEN","PHP","PKR","PLN","PYG","RSD","RWF","SDG","SEK","SGD","SOS","THB","TOP","TRY","TTD","TWD","TZS","UGX","UZS","XAF","XOF","ZAR","ZMW","ZWL","CURRENCY_SYMBOL_POSITION","CURRENCY_SYMBOL_DECIMALS","BHD","JOD","KWD","LYD","OMR","TND","amountFormat","isNegative","decimals","NumberFormat","minimumFractionDigits","maximumFractionDigits","format","abs","symbol","FieldInstallmentPlan","hasCardsField","paymentOptions","installmentPlans","installment_plans","selectedItemKey","setSelectedItemKey","dropdownItems","plan","installments","terms","installment_amount","interest_rate","planKey","unshift","selectedItemIndex","clearSelectedItem","handleChange","newPlan","interval","prevItems","some","Field","span","renderInner","localeMap","en","th","vi","getLocalizedErrorMessage","errorCode","isLocaleKey","sanitizeRegex","pattern","startsWith","endsWith","validate","input","required","validateEncryptedCardField","phone","isValid","validatePhoneNumber","validateEmail","validatePostalCode","regex_validators","regex","validateText","channelPropertyFieldValidate","channelPropertyKeys","getChannelPropertyValue","FormSimulationHelperContext","FormSimulationHelper","scenarios","onSelect","FormSimulationRoot","FormSimulationTrigger","FormSimulationHelperPopover","selectedScenario","scenario","docsLink","href","rel","CSS_CLASSES","FieldGroup","fieldGroup","groupIndex","handleFieldChanged","simulationScenarios","groupContainerRef","touchedFields","setTouchedFields","fieldGroupSpans","f","groupRowCount","ceil","reduce","agg","containerElement","listener","prev","err","renderError","group_label","FormSimulationHelperWrapper","position","fieldPositionBySpan","fieldRow","fieldColumn","isLastRow","calculateFieldPosition","CSS_CLASSES_BOTTOM_LEFT_0","CSS_CLASSES_BOTTOM_RIGHT_0","CSS_CLASSES_TOP_LEFT_0","CSS_CLASSES_TOP_RIGHT_0","CSS_CLASSES_COLLAPSE_RIGHT","CSS_CLASSES_COLLAPSE_LEFT","CSS_CLASSES_COLLAPSE_TOP","CSS_CLASSES_COLLAPSE_BOTTOM","getFieldClassNames","scenarioName","s","entries","CARDS_SCENARIOS","ChannelForm","forwardRef","onChannelPropertiesChanged","channelComponentData","formRef","setChannelProperties","useImperativeHandle","setAllFieldsTouched","elements","HTMLInputElement","forEach","getChannelProperties","iter","rawValue","Blob","subkeys","valueAsArray","formValueToStringArray","outer","subkey","part","shift","nextValue","formKvToChannelProperties","FormData","filteredForm","filterFormFields","useFilteredFormFields","previousFilteredForm","useEffect","formsAreEqual","getSimulationScenarios","filteredFieldGroups","fields","fieldGroups","groupFields","ChannelPropertiesContext","parse","_e","showBillingDetailsFields","require_billing_information","hasInstallmentPlans","flags","condition","display_if","property","operator","channelValue","InstructionsIcon","arrowRef","arrowSquareGroupRef","supportsAnimation","prototype","animate","arrowKeyFrames","arrowAnimationOptions","arrowSquareBounceKeyFrames","arrowSquareBounceAnimationOptions","xmlns","opacity","transformOrigin","duration","easing","iterations","Infinity","delay","QrScanIcon","scannerRef","squareBackgroundRef","clipPathId","startAnimation","scannerKeyFrames","scanDownAnimationOptions","squareKeyFrames","squareAnimationOptions","onfinish","scanUpAnimationOptions","x","y","rx","Checkbox","checked","htmlId","points","ChannelContext","ChannelComponentDataContext","PaymentChannel","channelOrPair","channelData","divRef","firstMemberChannel","hasPairedChannel","resolvedChannel","instructions","instructionsAsTuple","shouldShowSaveCheckbox","allow_save_payment_method","cleanedProperties","installment_configuration","cleanedInstallmentConfiguration","fromEntries","XenditChannelPropertiesChangedEvent","banner","Banner","pm_type","instr","aspectRatio","aspect_ratio","String","link_url","alt_text","NetworkError","errorResponse","convertDataToUrlSearchParams","params","URLSearchParams","append","endpoint","method","getPath","getQuery","async","pathArg","queryArg","requestBody","abortSignal","versionNumber","host","search","headers","response","fetch","ok","errorData","json","error_code","fetchSessionData","sessionAuthKey","createPaymentToken","createPaymentRequest","simulatePaymentRequest","pollSession","tokenRequestId","token_request_id","lookupCardDetails","getPaymentOptions","behaviorNode","impl","child","instance","BehaviorTree","bb","updating","again","update","updateCount","assertMaxRecursionDepth","next","updateTree","findBehavior","depth","isChanged","exitSubtree","enterSubtree","enter","exit","ActionIframe","mock","onIframeComplete","srcDoc","MOCK_IFRAME_SRCDOC","ActionQr","businessName","channelLogo","onAffirm","qrString","showSpinner","setShowSpinner","onMadePaymentClicked","svgNode","text","qr","qrcode","create","margin","svgText","qrSvgRenderer","render","DOMParser","parseFromString","documentElement","setAttribute","modules","backgroundPath","querySelector","foregroundPath","generateQrSvg","log","createElement","innerText","hideUi","childNodes","firstChild","Dialog","onClose","seamless","closeCalledRef","closeAnimationPlaying","dialogRef","backdropRef","onCloseSafe","onCloseWithAnimation","backdropFadeOutKeyframes","animationOptions","animation","foregroundFadeOutKeyframes","backdropFadeKeyframes","foregroundFadeKeyframes","close","backgroundColor","reverse","DefaultActionContainer","wrapperRef","component","createActionContainerComponent","destroyComponent","Instructions","SingleTabInstructions","instruction","MultiTabInstructions","InstructionsSteps","selectedTab","setSelectedTab","content","step","stepItems","Fragment","renderStep","renderFormattedStringChildren","nodes","nodeType","Node","TEXT_NODE","textContent","ELEMENT_NODE","nodeName","renderFormattedStringElement","domParser","renderFormattedString","renderTextStep","renderImageStep","renderBulletsStep","heading","renderFormStep","header","rows","row","rowIndex","cell","cellIndex","renderTableStep","TooltipContext","fire","TooltipProvider","setText","timeout","Tooltip","ActionVa","vaNumber","merchantName","vaDetails","enableCopy","detail","CopyButton","clipboard","writeText","BffPaymentEntityType","toPaymentEntity","prOrPt","payment_request_id","PaymentRequest","entity","payment_token_id","PaymentToken","getPaymentEntityStatusCopyKey","entityType","suffix","makeTestPollResponse","world","paymentEntity","makeTestPollResponseForPending","paymentRequest","paymentToken","payment_request","withPaymentEntityStatus","payment_token","makeTestPollResponseForPendingPaymentEntityOnly","_mock_action_type","succeeded_channel","makeTestPollResponseForSuccess","makeTestPollResponseForFailure","makeTestPaymentRequest","mockActionType","session_token_request_id","makeMockActions","actionType","iframe_capable","action_title","action_subtitle","action_graphic","makeOneMockAction","RedirectInstructions","logoAlt","redirectUrl","redirectButtonLabel","ActionEmptyListPushNotification","channelName","ActionDeepLink","ContainerActionBehavior","cleanupFn","defaultContainerHeight","defaultContainerWidth","ensureHasActionContainer","liveComponents","actionContainer","emptyActionContainer","cleanedUp","success","container","abortSubmission","actionCancelledByUser","cleanupActionContainer","cancelledByUser","updateActionContainerBrandColor","setProperty","populateActionContainer","createComponent","ActionCompletedBehavior","ActionRedirectBehavior","ActionIframeBehavior","mockResult","mockStatus","updateMocksOnIframeCompletion","actionCompleted","pollImmediatelyRequested","ActionQrBehavior","actionIndex","qrAction","actionQrProps","getAttribute","affirmPayment","bind","isProdLive","simulatePaymentRequested","ActionDeepLinkBehavior","deepLinkAction","ActionEmptyListPushNotificationBehavior","hackyOvoActionLatch","ActionVaBehavior","vaAction","actionVaProps","ActionPaylinkBehavior","link","head","CardInfoBehavior","cardDetailsRequest","abortLookupCardDetails","abortController","abort","AbortController","promise","then","encodedError","schemes","cleanedCardNumber","card_number","catch","ChannelValidBehavior","lastChannelCode","sendReadyEventIfChanged","ChannelInvalidBehavior","PollWorker","sessionTokenRequestId","onPollResult","started","stopped","attempt","mult","tries","base","sleepTime","retryLoop","isMock","XenditComponentsTest","nextMockUpdate","_err","isPolling","stop","PePendingBehavior","pollWorker","pollResponse","succeededChannel","PeRequiresActionBehavior","canCreateActionContainer","resetPolling","polling","PeFailedBehavior","submissionRequested","PaymentOptionsBehavior","paymentOptionsRequest","lookupPaymentOptions","abortLookupPaymentOptions","interval_count","total_amount","makeMockPaymentOptions","getPaymentOptionsAsync","SdkLoadingBehavior","SdkActiveBehavior","SdkFatalErrorBehavior","sdkFatalErrorMessage","discardPaymentEntity","SessionActiveBehavior","SessionCompletedBehavior","SessionFailedBehavior","SessionPendingBehavior","SimulatePaymentBehavior","exited","simulationRequest","simulatePayment","abortSimulation","simulatePaymentAsync","SubmissionBehavior","submission","submissionError","submit","defaultUserErrorMessage","failureCode","subtext","getFailureCodeCopyKey","failureCodeUserErrorMessage","failure_code","instantSubmissionError","shouldSendSavePaymentMethod","makeTestPaymentToken","session_id","save_payment_method","asyncSubmit","error_content","message_1","message_2","behaviorTreeForSdk","sdkStatus","maybePaylinkAction","paylinkAction","behaviorTreeForPaylink","behaviorTreeForAction","behaviorTreeForPaymentEntity","behaviorTreeForSubmission","channelIsDigitalWallet","channelPropertiesValid","channelPropertiesAreValid","validityBehavior","cardInfoBehavior","paymentOptionsBehavior","behaviorTreeForForm","behaviorTreeForSession","hasPaylink","simulateBehavior","redirectCanBeHandledInIframe","DigitalWalletGooglepay","onReady","useBusiness","didCallReady","paymentsClient","googlePayChannels","allowed_payment_methods","payment_method_specification","googlePayConfig","apiVersion","apiVersionMinor","allowedPaymentMethods","emailRequired","merchantInfo","merchantId","merchant_id","transactionInfo","transactionId","totalPriceStatus","totalPrice","currencyCode","buttonConfigWithDefaults","buttonColor","buttonType","buttonRadius","buttonSizeMode","buttonBorderType","PaymentsClient","google","payments","api","environment","loadPaymentData","paymentData","targetChannel","allChannels","getActiveChannels","googlePayChannel","paymentMethodData","findChannel","findTargetChannel","submitDigitalWallet","statusCode","localeKeyForGooglePayError","firstGooglePayChannel","isReadyToPay","button","createButton","buttonLocale","targetChannelCode","DigitalWalletWaitForLoad","scriptTagRegex","checkLoaded","forceRender","targetScript","scripts","script","DigitalWalletContainer","digitalWalletCode","digitalWalletOptions","sdkStatusCheckers","GOOGLE_PAY","XenditComponents","componentsSdkKey","parseSdkKey","worldState","channelPicker","paymentChannels","digitalWalletContainer","behaviorTree","currentChannelCode","currentDigitalWalletSubmission","eventListenersPresent","fatalErrorEvent","behaviorTreeUpdate","onUpdateWorldState","onUpdateChannelComponentData","hasScheduledRender","rerenderAllComponents","syncInertAttribute","initializeAsync","bff","channel_ui_groups","digital_wallets","assertInitialized","localeData","args","fallback","template","varName","warn","createTFunction","newData","renderChannelPicker","renderPaymentChannel","renderDigitalWalletComponent","getSession","getCustomer","bffCustomer","individual_detail","email","mobileNumber","mobile_number","individualDetail","givenNames","given_names","surname","getActiveChannelGroups","bffUiGroupsToPublic","bffChannelsToPublic","createChannelPickerComponent","setupUiEventsForChannelPicker","_event","active","cachedComponent","channelFormRef","createRef","setupUiEventsForPaymentChannel","channelObject","getActiveDigitalWallets","bffDigitalWallets","bffDigitalWalletsToPublic","prevComponent","hasSubmissionInProgress","channelComponents","hasAttribute","removeAttribute","showValidationErrors","optionsOrInternal","isInternal","requiresActionBehavior","qrCode","qrCodeOnly","tagName","pollImmediately","getState","setNextMockUpdate","makeTestBffData","debounceRendering","styleElement","firstStyleOrLinkElement","insertAdjacentElement","createStyles","iconSet","createIconSet"],"mappings":"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M,WACN+G,MAAO,MAET,CACE/G,KAAM,SACN+G,MAAO,MAET,CACE/G,KAAM,gBACN+G,MAAO,MAET,CACE/G,KAAM,aACN+G,MAAO,MAET,CACE/G,KAAM,aACN+G,MAAO,MAET,CACE/G,KAAM,WACN+G,MAAO,MAET,CACE/G,KAAM,iBACN+G,MAAO,MAET,CACE/G,KAAM,eACN+G,MAAO,MAET,CACE/G,KAAM,2BACN+G,MAAO,MAET,CACE/G,KAAM,OACN+G,MAAO,MAET,CACE/G,KAAM,WACN+G,MAAO,MAET,CACE/G,KAAM,SACN+G,MAAO,MAET,CACE/G,KAAM,QACN+G,MAAO,MAET,CACE/G,KAAM,eACN+G,MAAO,MAET,CACE/G,KAAM,cACN+G,MAAO,MAET,CACE/G,KAAM,eACN+G,MAAO,MAET,CACE/G,KAAM,iBACN+G,MAAO,MAET,CACE/G,KAAM,eACN+G,MAAO,MAET,CACE/G,KAAM,YACN+G,MAAO,MAET,CACE/G,KAAM,QACN+G,MAAO,MAET,CACE/G,KAAM,OACN+G,MAAO,MAET,CACE/G,KAAM,UACN+G,MAAO,MAET,CACE/G,KAAM,iBACN+G,MAAO,MAET,CACE/G,KAAM,WACN+G,MAAO,MAET,CACE/G,KAAM,aACN+G,MAAO,MAET,CACE/G,KAAM,gBACN+G,MAAO,MAET,CACE/G,KAAM,YACN+G,MAAO,MAET,CACE/G,KAAM,UACN+G,MAAO,OAETsE,IAAI8b,IAGOG,GAAiC,CAC5C,CACEtnB,KAAM,UACN+G,MAAO,MAET,CACE/G,KAAM,mBACN+G,MAAO,MAET,CACE/G,KAAM,WACN+G,MAAO,MAET,CACE/G,KAAM,gBACN+G,MAAO,MAET,CACE/G,KAAM,4BACN+G,MAAO,MAET,CACE/G,KAAM,wBACN+G,MAAO,MAET,CACE/G,KAAM,cACN+G,MAAO,MAET,CACE/G,KAAM,UACN+G,MAAO,MAET,CACE/G,KAAM,UACN+G,MAAO,MAET,CACE/G,KAAM,uBACN+G,MAAO,MAET,CACE/G,KAAM,SACN+G,MAAO,MAET,CACE/G,KAAM,eACN+G,MAAO,MAET,CACE/G,KAAM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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../../src/preact-batch.ts","../../src/public-event-types.ts","../../src/internal.ts","../../src/components/core/accordion.tsx","../../src/components/icon.tsx","../../src/components/core/accordion-item.tsx","../../src/components/session-provider.tsx","../../src/utils.ts","../../src/components/core/button.tsx","../../src/components/core/dropdown.tsx","../../src/bff-marshal.ts","../../src/components/core/dotted-line.tsx","../../src/components/channel-picker-group.tsx","../../src/components/channel-picker-digital-wallet-section.tsx","../../src/components/channel-picker-root.tsx","../../src/components/field-country.tsx","../../src/components/field-dropdown.tsx","../../src/components/core/form-ascociated-focus-trap.ts","../../src/dom-utils.ts","../../src/private-event-types.ts","../../src/components/iframe-registry.tsx","../../src/components/field-iframe.tsx","../../src/components/field-phone-number.tsx","../../src/data/provinces.ts","../../src/components/field-province.tsx","../../src/components/field-text.tsx","../../src/data/currencies.ts","../../src/amount-format.ts","../../src/components/field-installment-plan.tsx","../../src/components/field.tsx","../../src/localization.ts","../../src/validation.ts","../../src/components/form-simulation-helper.tsx","../../src/components/field-group.tsx","../../src/data/simulation-scenarios.ts","../../src/components/channel-form.tsx","../../src/components/graphic-redirect-instructions.tsx","../../src/components/graphic-qr-scan.tsx","../../src/components/core/checkbox.tsx","../../src/components/channel-root.tsx","../../src/networking.ts","../../src/api.ts","../../src/lifecycle/behavior-tree-runner.ts","../../src/lifecycle/behaviors/action-completed.ts","../../src/components/redirect-instructions.tsx","../../src/components/action-deep-link.tsx","../../src/components/core/dialog.tsx","../../src/components/default-action-container.tsx","../../src/lifecycle/behaviors/action.ts","../../src/lifecycle/behaviors/action-deep-link.ts","../../src/components/action-empty-list-push-notification.tsx","../../src/backend-types/payment-entity.ts","../../src/data/test-data-modifiers.ts","../../src/lifecycle/behaviors/action-empty-list-push-notification.ts","../../src/components/action-iframe.tsx","../../src/lifecycle/behaviors/action-iframe.ts","../../src/lifecycle/behaviors/action-paylink.ts","../../src/components/action-qr-custom-art.tsx","../../src/components/action-qr-utils.ts","../../src/components/action-qr.tsx","../../src/data/emvco-qr-schema.ts","../../src/emvco-qr.ts","../../src/lifecycle/behaviors/action-qr.ts","../../src/lifecycle/behaviors/action-redirect.ts","../../src/components/instructions.tsx","../../src/components/core/tooltip.tsx","../../src/components/action-va.tsx","../../src/lifecycle/behaviors/action-va.ts","../../src/lifecycle/behaviors/card-info.ts","../../src/lifecycle/behaviors/channel-invalid.ts","../../src/lifecycle/behaviors/channel-valid.ts","../../src/lifecycle/behaviors/payment-entity-failed.ts","../../src/lifecycle/behaviors/utils/poll-worker.ts","../../src/lifecycle/behaviors/payment-entity-pending.ts","../../src/lifecycle/behaviors/payment-entity-requires-action.ts","../../src/lifecycle/behaviors/payment-options.ts","../../src/lifecycle/behaviors/sdk-active.ts","../../src/lifecycle/behaviors/sdk-fatal-error.ts","../../src/lifecycle/behaviors/sdk-loading.ts","../../src/lifecycle/behaviors/session-active.ts","../../src/lifecycle/behaviors/session-completed.ts","../../src/lifecycle/behaviors/session-failed.ts","../../src/lifecycle/behaviors/utils/discard.ts","../../src/lifecycle/behaviors/session-pending.ts","../../src/lifecycle/behaviors/simulate-payment.ts","../../src/lifecycle/behaviors/submission.ts","../../src/lifecycle/behavior-tree.ts","../../src/components/digital-wallet-googlepay.tsx","../../src/components/digital-wallet-wait-for-load.tsx","../../src/components/digital-wallet-container.tsx","../../src/public-sdk.ts","../../src/index.ts","../../src/styles.ts","../../src/styles.css"],"sourcesContent":["import { options } from \"preact\";\n\nlet once = false;\n\nexport function setupPreactBatch() {\n if (once) {\n return;\n }\n once = true;\n options.debounceRendering = (fn) => queueMicrotask(fn);\n}\n","/**\n * @public\n */\nexport type XenditEventMap = {\n init: XenditInitEvent;\n\n \"submission-ready\": XenditReadyEvent;\n \"submission-not-ready\": XenditReadyEvent;\n\n \"submission-begin\": XenditSubmissionBeginEvent;\n \"submission-end\": XenditSubmissionEndEvent;\n\n \"action-begin\": XenditActionBeginEvent;\n \"action-end\": XenditActionEndEvent;\n\n \"will-redirect\": XenditWillRedirectEvent;\n\n \"session-complete\": XenditSessionCompleteEvent;\n \"session-expired-or-canceled\": XenditSessionExpiredOrCanceledEvent;\n \"session-pending\": XenditSessionPendingEvent;\n \"session-not-pending\": XenditSessionNotPendingEvent;\n\n \"payment-request-created\": XenditPaymentRequestCreatedEvent;\n \"payment-request-discarded\": XenditPaymentRequestDiscardedEvent;\n \"payment-token-created\": XenditPaymentTokenCreatedEvent;\n \"payment-token-discarded\": XenditPaymentTokenDiscardedEvent;\n\n \"fatal-error\": XenditFatalErrorEvent;\n};\n\n/**\n * @public\n */\nexport type XenditEventListener<\n T extends Event | XenditEventMap[keyof XenditEventMap],\n> = ((event: T) => void) | null;\n\n/**\n * @public\n * Event fired when the Session is loaded.\n */\nexport class XenditInitEvent extends Event {\n static type = \"init\" as const;\n\n constructor() {\n super(XenditInitEvent.type, {});\n }\n}\n\n/**\n * @public\n * Event fired when the SDK fails in an unrecoverable way.\n */\nexport class XenditFatalErrorEvent extends Event {\n static type = \"fatal-error\" as const;\n\n constructor(\n /**\n * A detailed error message for developers. Don't show this to users.\n */\n public message: string,\n ) {\n super(XenditFatalErrorEvent.type, {});\n }\n}\n\n/**\n * @public\n * Event fired when the SDK is ready to submit.\n */\nexport class XenditReadyEvent extends Event {\n static type = \"submission-ready\" as const;\n\n constructor(public channelCode: string) {\n super(XenditReadyEvent.type, {});\n }\n}\n\n/**\n * @public\n * Event fired when the SDK is not ready to submit.\n */\nexport class XenditNotReadyEvent extends Event {\n static type = \"submission-not-ready\" as const;\n\n constructor() {\n super(XenditNotReadyEvent.type, {});\n }\n}\n\n/**\n * @public\n * Event fired after submission begins.\n */\nexport class XenditSubmissionBeginEvent extends Event {\n static type = \"submission-begin\" as const;\n\n constructor() {\n super(XenditSubmissionBeginEvent.type, {});\n }\n}\n\n/**\n * @public\n * Event fired when a submission is complete or fails. Submission encompasses creation of a\n * payment request or payment token, and any actions the user needs to complete.\n *\n * Includes details about why the submission ended, and error messages if applicable.\n */\nexport class XenditSubmissionEndEvent extends Event {\n static type = \"submission-end\" as const;\n\n constructor(\n /**\n * The reason why the submission ended.\n */\n public reason: string,\n /**\n * An error message to show to the user. A title and 1-2 lines of localized text.\n */\n public userErrorMessage?: string[],\n /**\n * A detailed error message for developers.\n */\n public developerErrorMessage?: {\n /**\n * The type of error.\n * - NETWORK_ERROR: A network error occurred while creating the payment request or payment token.\n * - ERROR: Failed to created a payment request or payment token.\n * - FAILURE: A payment request or payment token transitioned to a failure state.\n */\n type: \"NETWORK_ERROR\" | \"ERROR\" | \"FAILURE\";\n /**\n * The code associated with the error.\n */\n code: string;\n },\n ) {\n super(XenditSubmissionEndEvent.type, {});\n }\n}\n\n/**\n * @public\n * Event sometimes fired after submission, if an action is required.\n */\nexport class XenditActionBeginEvent extends Event {\n static type = \"action-begin\" as const;\n\n constructor() {\n super(XenditActionBeginEvent.type, {});\n }\n}\n\n/**\n * @public\n * Event fired when an action ends, success or fail.\n */\nexport class XenditActionEndEvent extends Event {\n static type = \"action-end\" as const;\n\n constructor() {\n super(XenditActionEndEvent.type, {});\n }\n}\n\n/**\n * @public\n * Event fired when the a redirect action is about to happen.\n */\nexport class XenditWillRedirectEvent extends Event {\n static type = \"will-redirect\" as const;\n\n constructor() {\n super(XenditWillRedirectEvent.type, {});\n }\n}\n\n/**\n * @public\n * Event fired when the session is complete, meaning the payment has been processed\n * or the token has been created.\n */\nexport class XenditSessionCompleteEvent extends Event {\n static type = \"session-complete\" as const;\n\n constructor() {\n super(XenditSessionCompleteEvent.type, {});\n }\n}\n\n/**\n * @public\n * Event fired when the session has failed, meaning expired or cancelled.\n */\nexport class XenditSessionExpiredOrCanceledEvent extends Event {\n static type = \"session-expired-or-canceled\" as const;\n\n constructor() {\n super(XenditSessionExpiredOrCanceledEvent.type, {});\n }\n}\n\n/**\n * @public\n * Event fired when the session is pending.\n */\nexport class XenditSessionPendingEvent extends Event {\n static type = \"session-pending\" as const;\n\n constructor() {\n super(XenditSessionPendingEvent.type, {});\n }\n}\n\n/**\n * @public\n * Event fired when the session is no longer pending.\n */\nexport class XenditSessionNotPendingEvent extends Event {\n static type = \"session-not-pending\" as const;\n\n constructor() {\n super(XenditSessionNotPendingEvent.type, {});\n }\n}\n\n/**\n * @public\n */\nexport class XenditPaymentRequestCreatedEvent extends Event {\n static type = \"payment-request-created\" as const;\n\n constructor(public paymentRequestId: string) {\n super(XenditPaymentRequestCreatedEvent.type, {});\n }\n}\n\n/**\n * @public\n */\nexport class XenditPaymentTokenCreatedEvent extends Event {\n static type = \"payment-token-created\" as const;\n\n constructor(public paymentTokenId: string) {\n super(XenditPaymentTokenCreatedEvent.type, {});\n }\n}\n\n/**\n * @public\n */\nexport class XenditPaymentRequestDiscardedEvent extends Event {\n static type = \"payment-request-discarded\" as const;\n\n constructor(public paymentRequestId: string) {\n super(XenditPaymentRequestDiscardedEvent.type, {});\n }\n}\n\n/**\n * @public\n */\nexport class XenditPaymentTokenDiscardedEvent extends Event {\n static type = \"payment-token-discarded\" as const;\n\n constructor(public paymentTokenId: string) {\n super(XenditPaymentTokenDiscardedEvent.type, {});\n }\n}\n","export const internal = Symbol(\"xendit-internal\");\n","import { ComponentChildren, FunctionComponent } from \"preact\";\n\ninterface Props {\n children: ComponentChildren;\n}\n\n/**\n * @example\n * <Accordion>\n * <AccordionItem>Content</AccordionItem>\n * <AccordionItem>Content</AccordionItem>\n * </Accordion>\n */\nexport const Accordion: FunctionComponent<Props> = (props) => {\n return <div class=\"xendit-accordion\">{props.children}</div>;\n};\n","import { ComponentChildren, FunctionComponent, SVGAttributes } from \"preact\";\n\ntype Direction = \"up\" | \"down\" | \"left\" | \"right\";\n\nexport type IconName =\n | \"chevron\"\n | \"check\"\n | \"x\"\n | \"card\"\n | \"qr\"\n | \"otc\"\n | \"ewallet\"\n | \"bank_transfer\"\n | \"online_banking\"\n | \"copy\"\n | \"dummy\";\n\ntype Props = {\n name: IconName;\n size: number;\n direction?: Direction;\n className?: string;\n};\n\nconst Icon: FunctionComponent<SVGAttributes<SVGSVGElement> & Props> = (\n props,\n) => {\n const { name, size, direction } = props;\n\n let svgTransform: string;\n switch (direction) {\n case \"right\":\n svgTransform = \"rotate(180 12 12)\";\n break;\n case \"up\":\n svgTransform = \"rotate(90 12 12)\";\n break;\n case \"down\":\n svgTransform = \"rotate(-90 12 12)\";\n break;\n case \"left\":\n default:\n svgTransform = \"rotate(0 12 12)\";\n break;\n }\n\n let iconNode: ComponentChildren;\n switch (name) {\n case \"chevron\": {\n iconNode = (\n <path\n d=\"M15 19.5L7.5 12L15 4.5\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n );\n break;\n }\n case \"check\": {\n iconNode = scaleIcon(\n <path\n d=\"M13.5 4.5L6.5 11.5L3 8\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />,\n 16 / 24,\n );\n break;\n }\n case \"x\": {\n iconNode = (\n <>\n <path\n d=\"M18.75 5.25L5.25 18.75\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n <path\n d=\"M18.75 18.75L5.25 5.25\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </>\n );\n break;\n }\n case \"card\": {\n iconNode = scaleIcon(\n <path\n fill=\"currentColor\"\n d=\"M17.25 3.75H2.75A1.25 1.25 0 0 0 1.5 5v10a1.25 1.25 0 0 0 1.25 1.25h14.5A1.25 1.25 0 0 0 18.5 15V5a1.25 1.25 0 0 0-1.25-1.25m-.875 9.5a1 1 0 0 1-1 1h-2.5a1 1 0 0 1-1-1V13a1 1 0 0 1 1-1h2.5a1 1 0 0 1 1 1zM1.5 8V6h17v2z\"\n />,\n 20 / 24,\n );\n break;\n }\n case \"qr\": {\n iconNode = scaleIcon(\n <>\n <path\n fill=\"currentColor\"\n d=\"M8.125 3.125h-3.75c-.69 0-1.25.56-1.25 1.25v3.75c0 .69.56 1.25 1.25 1.25h3.75c.69 0 1.25-.56 1.25-1.25v-3.75c0-.69-.56-1.25-1.25-1.25M8.125 10.625h-3.75c-.69 0-1.25.56-1.25 1.25v3.75c0 .69.56 1.25 1.25 1.25h3.75c.69 0 1.25-.56 1.25-1.25v-3.75c0-.69-.56-1.25-1.25-1.25M15.625 3.125h-3.75c-.69 0-1.25.56-1.25 1.25v3.75c0 .69.56 1.25 1.25 1.25h3.75c.69 0 1.25-.56 1.25-1.25v-3.75c0-.69-.56-1.25-1.25-1.25M11.25 14.375a.624.624 0 0 0 .625-.625v-2.5a.624.624 0 1 0-1.25 0v2.5a.624.624 0 0 0 .625.625\"\n />\n <path\n fill=\"currentColor\"\n d=\"M16.25 11.875h-1.875v-.625a.624.624 0 1 0-1.25 0v4.375H11.25a.624.624 0 1 0 0 1.25h2.5a.624.624 0 0 0 .625-.625v-3.125h1.875a.624.624 0 1 0 0-1.25M16.25 14.375a.624.624 0 0 0-.625.625v1.25a.624.624 0 1 0 1.25 0V15a.624.624 0 0 0-.625-.625\"\n />\n </>,\n 20 / 24,\n );\n break;\n }\n case \"otc\": {\n iconNode = scaleIcon(\n <>\n <path\n fill=\"currentColor\"\n fill-rule=\"evenodd\"\n d=\"M16.972 9.547c.092-.107.207-.021.207.12v6.924c0 .283-.23.513-.512.513h-7.18v-5.129a.513.513 0 0 0-.514-.512h-3.59a.513.513 0 0 0-.513.512v5.13H3.332a.514.514 0 0 1-.513-.514V9.853c0-.244.149-.33.331-.168.268.238.586.428.936.556a3.2 3.2 0 0 0 2.209 0c.35-.128.669-.318.936-.556a.56.56 0 0 1 .728 0c.267.238.586.428.935.556a3.2 3.2 0 0 0 2.209 0c.35-.128.669-.318.937-.556a.56.56 0 0 1 .727 0c.267.238.586.428.935.556a3.2 3.2 0 0 0 2.21 0c.349-.128.668-.318.936-.556.04-.036.081-.088.124-.138m-4.409 1.915a.513.513 0 0 0-.512.513v1.283c0 .283.23.512.512.513h2.052c.283 0 .513-.23.513-.513v-1.283a.513.513 0 0 0-.513-.512z\"\n clip-rule=\"evenodd\"\n />\n <path\n fill=\"currentColor\"\n d=\"M16.325 3c.148 0 .293.054.412.153.118.1.204.24.245.398l.99 2.872a.51.51 0 0 1-.333.654 2.4 2.4 0 0 1-.166.495c-.145.31-.357.593-.625.831a2.9 2.9 0 0 1-.936.556 3.2 3.2 0 0 1-2.209 0 2.9 2.9 0 0 1-.936-.556.56.56 0 0 0-.727 0 2.9 2.9 0 0 1-.936.556 3.2 3.2 0 0 1-2.209 0 2.9 2.9 0 0 1-.936-.556.56.56 0 0 0-.728 0 2.9 2.9 0 0 1-.935.556 3.2 3.2 0 0 1-2.21 0 2.9 2.9 0 0 1-.936-.556 2.6 2.6 0 0 1-.624-.831 2.4 2.4 0 0 1-.167-.495.51.51 0 0 1-.33-.654l.99-2.872a.77.77 0 0 1 .244-.397A.64.64 0 0 1 3.675 3z\"\n />\n </>,\n 20 / 24,\n );\n break;\n }\n case \"ewallet\": {\n iconNode = scaleIcon(\n <path\n fill=\"currentColor\"\n fill-rule=\"evenodd\"\n d=\"M11.313 2.07c.94-.23 2.112.266 2.63 1.145H9.331c-1.242 0-2.295.021-3.171.053 1.648-.683 3.44-.78 5.153-1.198M4.338 17.855c1.061.072 2.691.145 4.971.145s3.91-.073 4.972-.145c1.168-.08 2.09-.963 2.186-2.134q.029-.335.054-.747a40 40 0 0 1-2.644-.012c-1.298-.052-2.345-1.039-2.405-2.362a26 26 0 0 1-.023-1.153q.002-.67.023-1.153c.06-1.323 1.107-2.31 2.405-2.362q.745-.029 1.494-.027.654 0 1.15.016a36 36 0 0 0-.054-.748c-.096-1.17-1.018-2.053-2.186-2.133-1.062-.073-2.692-.146-4.972-.146s-3.91.073-4.971.146c-1.169.08-2.09.962-2.187 2.133A53 53 0 0 0 2 11.447c0 1.922.073 3.326.151 4.274.096 1.171 1.018 2.053 2.187 2.134m8.675-5.325c.03.662.544 1.155 1.21 1.181q.508.022 1.274.024.766-.002 1.273-.024c.667-.026 1.18-.52 1.21-1.181q.019-.404.02-.971-.001-.569-.02-.971c-.03-.662-.544-1.156-1.21-1.182a32 32 0 0 0-1.273-.024c-.512 0-.934.01-1.274.024-.667.026-1.18.52-1.21 1.182q-.019.403-.02.97.001.569.02.972m2.041-1.749c.159 0 .311.05.424.137a.42.42 0 0 1 .175.33v.622a.42.42 0 0 1-.175.33.7.7 0 0 1-.424.136.7.7 0 0 1-.423-.137.42.42 0 0 1-.176-.33v-.621c0-.124.063-.242.176-.33a.7.7 0 0 1 .423-.137\"\n clip-rule=\"evenodd\"\n />,\n 20 / 24,\n );\n break;\n }\n case \"bank_transfer\": {\n iconNode = scaleIcon(\n <path\n fill=\"currentColor\"\n d=\"M9.195 1.947a1.46 1.46 0 0 1 1.72 0l6.184 4.514c.814.593.629 1.463-.378 1.466H3.388C2.38 7.924 2.196 7.054 3.01 6.46zm.235 11.196a.2.2 0 0 1-.2.2H7.963a.2.2 0 0 1-.2-.2V9.377c0-.11.09-.2.2-.2H9.23c.11 0 .2.09.2.2zm2.916 0a.2.2 0 0 1-.2.2H10.88a.2.2 0 0 1-.2-.2V9.377c0-.11.09-.2.2-.2h1.267c.11 0 .2.09.2.2zm3.125 0a.2.2 0 0 1-.2.2h-1.475a.2.2 0 0 1-.2-.2V9.377c0-.11.09-.2.2-.2h1.475c.11 0 .2.09.2.2zm-12.916 1.45v1.875c0 .346.28.625.625.625h13.75a.625.625 0 0 0 .625-.625v-1.875s-12.07-.128-15 0m3.958-1.45a.2.2 0 0 1-.2.2H4.838a.2.2 0 0 1-.2-.2V9.377c0-.11.09-.2.2-.2h1.475c.11 0 .2.09.2.2z\"\n />,\n 20 / 24,\n );\n break;\n }\n case \"online_banking\": {\n iconNode = scaleIcon(\n <>\n <path\n stroke=\"currentColor\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"1.25\"\n d=\"M14.25 17.708a3.75 3.75 0 1 0 0-7.5 3.75 3.75 0 0 0 0 7.5\"\n />\n <path\n stroke=\"currentColor\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n d=\"M10.5 13.958H18m-3.75-3.75a5.437 5.437 0 0 0 0 7.5 5.44 5.44 0 0 0 0-7.5\"\n />\n <path\n fill=\"currentColor\"\n d=\"M8.706 14.537c.15.97.574 1.848 1.188 2.556H3.18a.625.625 0 0 1-.625-.625v-1.875c1.115-.049 3.556-.06 6.151-.056M6.346 9.177c.092 0 .167.074.167.166v3.833a.167.167 0 0 1-.167.167H4.805a.167.167 0 0 1-.167-.167V9.343c0-.092.075-.166.167-.166zM9.263 9.177c.092 0 .167.074.167.166v1.69a5.1 5.1 0 0 0-.767 2.31H7.93a.167.167 0 0 1-.167-.167V9.343c0-.092.075-.166.167-.166zM11.484 9.177q-.428.21-.804.495v-.329c0-.092.074-.166.166-.166zM10.055 1.667c.309 0 .61.098.86.28l6.184 4.514c.814.593.629 1.463-.378 1.466H3.388c-1.007-.003-1.192-.873-.379-1.466l6.185-4.513c.25-.183.551-.281.86-.281\"\n />\n </>,\n 20 / 24,\n );\n break;\n }\n case \"copy\": {\n iconNode = scaleIcon(\n <>\n <path\n d=\"M6 9.5H10\"\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M6 7.5H10\"\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M10 2.5H12.5C12.6326 2.5 12.7598 2.55268 12.8536 2.64645C12.9473 2.74021 13 2.86739 13 3V13.5C13 13.6326 12.9473 13.7598 12.8536 13.8536C12.7598 13.9473 12.6326 14 12.5 14H3.5C3.36739 14 3.24021 13.9473 3.14645 13.8536C3.05268 13.7598 3 13.6326 3 13.5V3C3 2.86739 3.05268 2.74021 3.14645 2.64645C3.24021 2.55268 3.36739 2.5 3.5 2.5H6\"\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M5.5 4.5V4C5.5 3.33696 5.76339 2.70107 6.23223 2.23223C6.70107 1.76339 7.33696 1.5 8 1.5C8.66304 1.5 9.29893 1.76339 9.76777 2.23223C10.2366 2.70107 10.5 3.33696 10.5 4V4.5H5.5Z\"\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </>,\n 16 / 24,\n );\n break;\n }\n case \"dummy\": {\n iconNode = scaleIcon(\n <path\n fill=\"currentColor\"\n d=\"M17.5 11.875V15C17.5 15.3315 17.3683 15.6495 17.1339 15.8839C16.8995 16.1183 16.5815 16.25 16.25 16.25H3.75C3.41848 16.25 3.10054 16.1183 2.86612 15.8839C2.6317 15.6495 2.5 15.3315 2.5 15V11.875C2.5 11.5435 2.6317 11.2255 2.86612 10.9911C3.10054 10.7567 3.41848 10.625 3.75 10.625H16.25C16.5815 10.625 16.8995 10.7567 17.1339 10.9911C17.3683 11.2255 17.5 11.5435 17.5 11.875ZM16.25 3.75H3.75C3.41848 3.75 3.10054 3.8817 2.86612 4.11612C2.6317 4.35054 2.5 4.66848 2.5 5V8.125C2.5 8.45652 2.6317 8.77446 2.86612 9.00888C3.10054 9.2433 3.41848 9.375 3.75 9.375H16.25C16.5815 9.375 16.8995 9.2433 17.1339 9.00888C17.3683 8.77446 17.5 8.45652 17.5 8.125V5C17.5 4.66848 17.3683 4.35054 17.1339 4.11612C16.8995 3.8817 16.5815 3.75 16.25 3.75Z\"\n />,\n 20 / 24,\n );\n break;\n }\n default: {\n name satisfies never;\n throw new Error(`Icon with name ${name} does not exist`);\n }\n }\n\n return (\n <svg\n className={`xendit-icon ${props.className ?? \"\"}`}\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"none\"\n >\n <g transform={svgTransform}>{iconNode}</g>\n </svg>\n );\n};\n\n// wrap an SVG path in a group that will scale it to fit within a 24x24 viewbox\n// e.g. if the original path is designed for a 16x16 viewbox, do `scaleIcon(<path d=\"...\" />, 16 / 24)`.\nfunction scaleIcon(\n children: ComponentChildren,\n scale: number,\n): ComponentChildren {\n return <g transform={`scale(${1 / scale} ${1 / scale})`}>{children}</g>;\n}\n\nexport default Icon;\n","import { useCallback } from \"preact/hooks\";\nimport Icon, { IconName } from \"../icon\";\nimport classNames from \"classnames\";\nimport {\n ComponentChildren,\n FunctionComponent,\n TargetedKeyboardEvent,\n} from \"preact\";\n\ninterface Props {\n id: string;\n title: string;\n iconName: IconName;\n subtitle?: string;\n disabled?: boolean;\n open: boolean;\n onClick: (id: string) => void;\n children: ComponentChildren;\n}\n\nexport const AccordionItem: FunctionComponent<Props> = (props) => {\n const { id, title, iconName, subtitle, disabled, open, onClick, children } =\n props;\n\n const chevronDirection = open ? \"up\" : \"down\";\n\n const toggleOpen = useCallback(() => {\n if (disabled) {\n return;\n }\n onClick(id);\n }, [disabled, onClick, id]);\n\n const handleKeyPress = useCallback(\n (event: TargetedKeyboardEvent<HTMLDivElement>) => {\n if (event.key === \"Enter\" || event.key === \" \") {\n toggleOpen();\n event.preventDefault();\n }\n },\n [toggleOpen],\n );\n\n const handleClick = useCallback(() => {\n toggleOpen();\n }, [toggleOpen]);\n\n return (\n <div\n className={classNames(\n \"xendit-accordion-item\",\n disabled ? \"xendit-accordion-item-disabled\" : \"\",\n open ? \"xendit-accordion-item-open\" : \"xendit-accordion-item-closed\",\n )}\n >\n <div\n className=\"xendit-accordion-item-header\"\n onClick={handleClick}\n onKeyDown={handleKeyPress}\n role=\"button\"\n tabIndex={disabled ? -1 : 0}\n >\n <Icon\n className=\"xendit-accordion-item-header-icon\"\n name={iconName}\n size={24}\n />\n <div className=\"xendit-accordion-item-header-title xendit-text-16 xendit-text-bold\">\n {title}\n {subtitle ? (\n <div className=\"xendit-accordion-item-header-subtitle xendit-text-14\">\n {subtitle}\n </div>\n ) : null}\n </div>\n <Icon\n className=\"xendit-accordion-item-chevron\"\n name=\"chevron\"\n size={24}\n direction={chevronDirection}\n />\n </div>\n <div className=\"xendit-accordion-item-content\" inert={!open}>\n <div className=\"xendit-accordion-item-padding\">{children}</div>\n </div>\n </div>\n );\n};\n","import { WorldState, XenditComponents } from \"../public-sdk\";\nimport { BffSession } from \"../backend-types/session\";\nimport { BffBusiness } from \"../backend-types/business\";\nimport { BffCustomer } from \"../backend-types/customer\";\nimport { BffChannel, BffChannelUiGroup } from \"../backend-types/channel\";\nimport { internal } from \"../internal\";\nimport { ComponentChildren, createContext, FunctionComponent } from \"preact\";\nimport { useContext } from \"preact/hooks\";\nimport { BffDigitalWallets } from \"../backend-types/digital-wallets\";\n\n// Create contexts\nexport const SessionContext = createContext<BffSession | null>(null);\nSessionContext.displayName = \"SessionContext\";\n\nexport const BusinessContext = createContext<BffBusiness | null>(null);\nBusinessContext.displayName = \"BusinessContext\";\n\nexport const CustomerContext = createContext<BffCustomer | null>(null);\nCustomerContext.displayName = \"CustomerContext\";\n\nexport const ChannelsContext = createContext<BffChannel[] | null>(null);\nChannelsContext.displayName = \"ChannelsContext\";\n\nexport const ChannelUiGroupsContext = createContext<BffChannelUiGroup[] | null>(\n null,\n);\nChannelUiGroupsContext.displayName = \"ChannelUiGroupsContext\";\n\nexport const DigitalWalletsContext = createContext<BffDigitalWallets | null>(\n null,\n);\nDigitalWalletsContext.displayName = \"DigitalWalletsContext\";\n\nexport const SdkContext = createContext<XenditComponents | null>(null);\nSdkContext.displayName = \"SdkContext\";\n\nexport const CurrentChannelContext = createContext<BffChannel | null>(null);\nCurrentChannelContext.displayName = \"CurrentChannelContext\";\n\n// Custom hooks for consuming contexts\nexport const useSession = () => {\n const context = useContext(SessionContext);\n if (context === null) {\n throw new Error(\"useSession must be used within a XenditSessionProvider\");\n }\n return context;\n};\n\nexport const useBusiness = () => {\n const context = useContext(BusinessContext);\n if (context === null) {\n throw new Error(\"useBusiness must be used within a XenditSessionProvider\");\n }\n return context;\n};\n\nexport const useCustomer = () => {\n const context = useContext(CustomerContext);\n if (context === null) {\n throw new Error(\"useCustomer must be used within a XenditSessionProvider\");\n }\n return context;\n};\n\nexport const useChannels = () => {\n const context = useContext(ChannelsContext);\n if (context === null) {\n throw new Error(\"useChannels must be used within a XenditSessionProvider\");\n }\n return context;\n};\n\nexport const useChannelUiGroups = () => {\n const context = useContext(ChannelUiGroupsContext);\n if (context === null) {\n throw new Error(\n \"useChannelUiGroups must be used within a XenditSessionProvider\",\n );\n }\n return context;\n};\n\nexport const useDigitalWallets = () => {\n const context = useContext(DigitalWalletsContext);\n return context;\n};\n\nexport const useSdk = () => {\n const context = useContext(SdkContext);\n if (context === null) {\n throw new Error(\"useSdk must be used within a XenditSessionProvider\");\n }\n return context;\n};\n\nexport const useCurrentChannel = () => {\n return useContext(CurrentChannelContext);\n};\n\ninterface XenditSessionProviderProps {\n children: ComponentChildren;\n data: WorldState;\n sdk: XenditComponents;\n}\n\nexport const XenditSessionProvider: FunctionComponent<\n XenditSessionProviderProps\n> = ({ children, data, sdk }) => {\n const {\n session,\n business,\n customer,\n channels,\n digitalWallets,\n channelUiGroups,\n } = data;\n\n const channel = sdk.getCurrentChannel()?.[internal]?.[0] ?? null;\n\n if (sdk.getSdkStatus() !== \"ACTIVE\" || session.status !== \"ACTIVE\") {\n // clear all contents if the sdk is not initialized or crashes, or if the component is still mounted after completion or failure\n return null;\n }\n\n return (\n <SdkContext.Provider value={sdk}>\n <CurrentChannelContext.Provider value={channel}>\n <SessionContext.Provider value={session}>\n <BusinessContext.Provider value={business}>\n <CustomerContext.Provider value={customer}>\n <ChannelsContext.Provider value={channels}>\n <DigitalWalletsContext.Provider value={digitalWallets}>\n <ChannelUiGroupsContext.Provider value={channelUiGroups}>\n {children}\n </ChannelUiGroupsContext.Provider>\n </DigitalWalletsContext.Provider>\n </ChannelsContext.Provider>\n </CustomerContext.Provider>\n </BusinessContext.Provider>\n </SessionContext.Provider>\n </CurrentChannelContext.Provider>\n </SdkContext.Provider>\n );\n};\n","import {\n BffChannel,\n ChannelFormField,\n ChannelProperties,\n} from \"./backend-types/channel\";\nimport { useLayoutEffect, useRef } from \"preact/hooks\";\nimport { BffAction } from \"./backend-types/payment-entity\";\nimport { BffSession } from \"./backend-types/session\";\nimport { internal } from \"./internal\";\nimport { XenditComponents } from \"./public-sdk\";\n\nexport const MOCK_NETWORK_DELAY_MS = 300;\n\nexport function assert<T>(arg: unknown): asserts arg is NonNullable<T> {\n if (!arg) {\n throw new Error(\n \"Assertion failed: argument is null or undefined; this is a bug, please contact support.\",\n );\n }\n}\n\nexport function assertIsArray<T = unknown>(arg: unknown): asserts arg is T[] {\n if (!Array.isArray(arg)) {\n throw new Error(\n \"Assertion failed: expected array; this is a bug, please contact support.\",\n );\n }\n}\n\nexport function assertIsNotArray<T = unknown>(\n arg: T,\n): asserts arg is Exclude<T, unknown[]> {\n if (Array.isArray(arg)) {\n throw new Error(\n \"Assertion failed: expected array; this is a bug, please contact support.\",\n );\n }\n}\n\nexport function assertEquals<T>(a: unknown, b: T): asserts a is T {\n if (a !== b) {\n throw new Error(`Assertion failed; this is a bug, please contact support.`);\n }\n}\n\nexport function assertNotEquals<const A, const B extends A>(\n a: A,\n b: B,\n): asserts a is Exclude<A, B> {\n if (a === b) {\n throw new Error(`Assertion failed; this is a bug, please contact support.`);\n }\n}\n\nexport const SLEEP_MULTIPLIER = process.env.NODE_ENV === \"test\" ? 0.01 : 1;\n\nexport function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms * SLEEP_MULTIPLIER));\n}\n\nexport class AbortError extends Error {\n constructor() {\n super(\"AbortError\");\n this.name = \"AbortError\";\n }\n}\n\nexport function isAbortError(error: unknown): error is AbortError {\n return error instanceof AbortError && error.name === \"AbortError\";\n}\n\n/**\n * A sleep function that can be cancelled via an AbortSignal.\n */\nexport function cancellableSleep(\n ms: number,\n signal: AbortSignal,\n): Promise<void> {\n return new Promise((resolve, reject) => {\n function onAbort() {\n signal.removeEventListener(\"abort\", onAbort);\n clearTimeout(timeoutId);\n reject(new AbortError());\n }\n\n const timeoutId = setTimeout(() => {\n signal.removeEventListener(\"abort\", onAbort);\n resolve();\n }, ms * SLEEP_MULTIPLIER);\n\n // already aborted\n if (signal.aborted) {\n onAbort();\n return;\n }\n\n // abort on signal\n signal.addEventListener(\"abort\", onAbort);\n });\n}\n\nexport function camelCaseToKebabCase(str: string): string {\n return str.replace(/[A-Z]/gm, (match, offset) => {\n if (offset === 0) return match.toLowerCase();\n return `-${match.toLowerCase()}`;\n });\n}\n\n/**\n * Creates an async iterator with exponential delay. Yields the attempt number.\n *\n * Use with async for (const attempt of retryLoop(100, 5)).\n *\n * Delay is mult * base ** attempt\n * e.g. mult = 100ms, tries = 5, base = 2:\n * 100ms, 200ms, 400ms, 800ms, 1600ms\n *\n * Doesn't wait in tests, unless waitInTests=true.\n */\nexport async function* retryLoop(mult: number, tries: number, base = 2) {\n // first attempt always instant\n yield 0;\n\n let sleepTime = mult;\n\n for (let i = 1; i < tries; i++) {\n sleepTime *= base;\n await sleep(sleepTime);\n yield i;\n }\n}\n\nexport function redirectCanBeHandledInIframe(action: BffAction): boolean {\n if (action.type !== \"REDIRECT_CUSTOMER\") {\n return false;\n }\n if (action.iframe_capable === false) {\n return false;\n }\n // if iframe_capable is undefined, assume it can be handled in iframe\n return true;\n}\n\n/**\n * Return the first action in the list that we understand.\n */\nexport function findBestAction(actions: BffAction[]): BffAction | undefined {\n const best = actions.find((a) => {\n switch (a.type) {\n case \"REDIRECT_CUSTOMER\": {\n switch (a.descriptor) {\n case \"WEB_URL\":\n return true;\n case \"DEEPLINK_URL\":\n return isAndroidOrIos();\n case \"WEB_GOOGLE_PAYLINK\":\n return false;\n }\n a satisfies never;\n break;\n }\n case \"PRESENT_TO_CUSTOMER\":\n return true;\n case \"API_POST_REQUEST\":\n return false;\n }\n a satisfies never;\n return false;\n });\n if (best) return best;\n\n // if we don't understand any action, just return the first one, it will fire the fatal-error event later\n // (an empty action list has a special meaning, we should return an unsupported action rather than undefined if we support none of the actions)\n return actions[0];\n}\n\n/**\n * Find the paylink action, if it exists and the feature is enabled.\n */\nexport function findPaylinkAction(\n sdk: XenditComponents,\n actions: BffAction[],\n): BffAction | undefined {\n if (sdk[internal].options.enablePaylinks) {\n return actions.find(\n (a) =>\n a.type === \"REDIRECT_CUSTOMER\" && a.descriptor === \"WEB_GOOGLE_PAYLINK\",\n );\n }\n}\n\nfunction isAndroidOrIos() {\n const userAgent = navigator.userAgent;\n\n if (!userAgent) return false;\n\n if (/android/i.test(userAgent)) {\n return true;\n }\n\n // iOS detection from: http://stackoverflow.com/a/9039885/177710\n if (/iPad|iPhone|iPod/.test(userAgent)) {\n return true;\n }\n\n return false;\n}\n\nexport const MOCK_HOST_ID = \"mock\";\n\nconst hosts: Record<string, string | undefined> = {\n pl: process.env.XENDIT_CHECKOUT_UI_GATEWAY_PROD_LIVE,\n pd: process.env.XENDIT_CHECKOUT_UI_GATEWAY_PROD_DEV,\n sl: process.env.XENDIT_CHECKOUT_UI_GATEWAY_STAGING_LIVE,\n sd: process.env.XENDIT_CHECKOUT_UI_GATEWAY_STAGING_DEV,\n};\n\nexport function hostFromHostId(hostId: string): string | null {\n return hosts[hostId] ?? null;\n}\n\nexport type ParsedSdkKey = {\n sessionAuthKey: string;\n hostId: string;\n publicKey: string;\n signature: string;\n};\n\nexport function parseSdkKey(componentsSdkKey: string): ParsedSdkKey {\n if (!componentsSdkKey) {\n throw new Error(\n \"The componentsSdkKey option is missing; check the constructor parameters.\",\n );\n }\n const parts = componentsSdkKey.split(\"-\");\n if (\n parts.length < 4 ||\n (parts[2] !== MOCK_HOST_ID && hostFromHostId(parts[2]) === null)\n ) {\n throw new Error(\n \"The componentsSdkKey option has the wrong format. Ensure you pass the value returned from the `components_sdk_key` property of the `POST /sessions` response.\",\n );\n }\n\n return {\n sessionAuthKey: [parts[0], parts[1]].join(\"-\"),\n hostId: parts[2],\n publicKey: parts[3],\n signature: parts[4],\n };\n}\n\n/**\n * Return a copy of original, with properties from updates applied on top, except undefined properties.\n */\nexport function mergeIgnoringUndefined<T>(\n original: T,\n updates: Partial<{ [K in keyof T]: T[K] | undefined }>,\n): T {\n const result = { ...original };\n for (const key of Object.keys(updates) as (keyof T)[]) {\n const value = updates[key];\n if (value !== undefined) {\n result[key] = value;\n }\n }\n return result;\n}\n\nexport function usePrevious<T>(value: T) {\n const ref = useRef<T>(); // Create a ref to store the previous value\n\n useLayoutEffect(() => {\n ref.current = value; // Update the ref's current value after each render\n });\n\n // eslint-disable-next-line react-hooks/refs\n return ref.current; // Return the value stored in the ref (which is the previous value)\n}\n\n/**\n * Get the form field name for a given channel form field.\n * @param field The channel form field to get the name for.\n * @returns The form field name.\n */\nexport function formFieldName(field: ChannelFormField): string {\n let id: string;\n if (typeof field.channel_property === \"string\") {\n id = field.channel_property;\n } else {\n const keys = Object.values(field.channel_property);\n id = keys.join(\"__\");\n }\n return id;\n}\n\nconst seed =\n process.env.NODE_ENV !== \"test\" ? Math.floor(Math.random() * 255) : 0;\n\n/**\n * Get an ID for a channel field, for the \"id\" and label \"for\" attributes.\n */\nexport function formFieldId(field: ChannelFormField): string {\n const obfuscatedId = formFieldName(field)\n .split(\"\")\n .map((c) => {\n const code = (c.charCodeAt(0) % 256) ^ seed;\n return code.toString(16);\n })\n .join(\"\");\n return `xendit-id-${obfuscatedId}`;\n}\n\nexport function randomBytes(length: number) {\n const arr = new Uint8Array(length);\n for (let i = 0; i < length; i++) {\n arr[i] = Math.floor(Math.random() * 256);\n }\n return arr;\n}\n\nexport function randomHexString(length: number) {\n assert(length % 2 === 0);\n const bytes = randomBytes(length / 2);\n return Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\");\n}\n\nexport function randomUUID() {\n return [\n randomHexString(8),\n randomHexString(4),\n randomHexString(4),\n randomHexString(4),\n randomHexString(12),\n ].join(\"-\");\n}\n\n/**\n * useId but doesn't sometimes return the same id in different components\n */\nexport function useIdSafe(): string {\n const id = useRef(randomHexString(12));\n return `xendit-id-${id.current}`;\n}\n\nexport function canBeSimulated(action: BffAction): boolean {\n switch (action.type) {\n case \"PRESENT_TO_CUSTOMER\":\n return true;\n default:\n return false;\n }\n}\n\nexport function errorToString(error: unknown): string {\n if (error instanceof Error) {\n return error.stack ?? error.message;\n }\n if (typeof error === \"string\") {\n return error;\n }\n try {\n return `Unknown error: ${JSON.stringify(error)}`;\n } catch {\n return \"Unknown error\";\n }\n}\n\n/**\n * Modifies the input object, deleting properties with undefined values, excluding symbol properties or getters.\n */\nexport function removeUndefinedPropertiesFromObject<T extends object>(\n object: T,\n): T {\n for (const key of Object.keys(object) as (keyof T)[]) {\n if (typeof key === \"symbol\") {\n continue;\n }\n const descriptor = Object.getOwnPropertyDescriptor(object, key);\n if (descriptor === undefined) {\n continue;\n }\n if (typeof descriptor.get === \"function\") {\n continue;\n }\n if (descriptor.value === undefined) {\n delete object[key];\n }\n }\n return object;\n}\n\nexport function getValueFromChannelProperty(\n channelProperty: string | string[],\n channelProperties: ChannelProperties | null,\n) {\n let str = channelProperty;\n if (!channelProperties) {\n return undefined;\n }\n if (Array.isArray(str)) {\n throw new Error(\n \"Getting values from channel property arrays is not supported.\",\n );\n }\n\n let cursor: ChannelProperties[string] = channelProperties;\n while (true) {\n if (!cursor || typeof cursor !== \"object\" || Array.isArray(cursor)) {\n return undefined;\n }\n const dotIndex = str.indexOf(\".\");\n if (dotIndex === -1) {\n return cursor ? cursor[str] : undefined;\n } else {\n const key = str.slice(0, dotIndex);\n cursor = cursor ? cursor[key] : undefined;\n str = str.slice(dotIndex + 1);\n }\n }\n}\n\nexport function getCardNumberFromChannelProperties(\n channelProperties: ChannelProperties | null,\n) {\n const cardNumber = getValueFromChannelProperty(\n \"card_details.card_number\",\n channelProperties,\n );\n if (typeof cardNumber !== \"string\") {\n return null;\n }\n return cardNumber;\n}\n\nexport function parseEncryptedFieldValue(str: string) {\n const out = {\n version: 0,\n publicKey: \"\",\n iv: \"\",\n cipherText: \"\",\n valid: false,\n validationError: null as string | null,\n withoutValidationError: str,\n };\n if (!str) {\n return out;\n }\n\n const parts = str.split(\"-\");\n if (parts.length < 6) {\n throw new Error(\"Invalid encrypted field value format.\");\n }\n if (parts[0] !== \"xendit\") {\n throw new Error(\"Invalid encrypted field value format.\");\n }\n if (parts[1] !== \"encrypted\") {\n throw new Error(\"Invalid encrypted field value format.\");\n }\n const version = parseInt(parts[2], 10);\n if (isNaN(version) || version <= 0) {\n throw new Error(\"Invalid encrypted field value format.\");\n }\n out.version = version;\n out.publicKey = parts[3];\n out.iv = parts[4];\n out.cipherText = parts[5];\n if (parts.length > 6) {\n if (parts[6] !== \"invalid\") {\n throw new Error(\"Invalid encrypted field value format.\");\n }\n out.validationError = atob(parts[7]);\n out.withoutValidationError = parts.slice(0, 6).join(\"-\");\n } else {\n out.valid = true;\n }\n\n return out;\n}\n\nconst objectIdMap = new WeakMap<object, number>();\nlet objectIdCounter = 1;\nexport function objectId(object: object): string {\n if (!objectIdMap.has(object)) {\n objectIdMap.set(object, objectIdCounter++);\n }\n return objectIdMap.get(object)!.toString();\n}\n\nexport function resolvePairedChannel(\n channels: BffChannel[],\n savePaymentMethod: boolean,\n): BffChannel {\n assert(channels.length > 0);\n assert(channels.length <= 2);\n\n if (channels.length === 2) {\n if (savePaymentMethod) {\n assert(channels[1].allow_save === true);\n return channels[1];\n } else {\n assert(channels[0].allow_save === false);\n return channels[0];\n }\n } else {\n return channels[0];\n }\n}\n\nexport function satisfiesMinMax(\n session: Pick<BffSession, \"amount\" | \"session_type\">,\n channel: BffChannel,\n): boolean {\n if (session.session_type !== \"PAY\") {\n return true; // only pay sessions have min/max\n }\n\n const amount = session.amount;\n const min = channel.min_amount ?? 0;\n const max = channel.max_amount ?? Number.MAX_VALUE;\n if (amount < min || amount > max) {\n return false;\n }\n\n return true;\n}\n\nexport function lockDownInteralProperty(obj: { [internal]: unknown }) {\n // make [internal] non-enumerable\n Object.defineProperty(obj, internal, {\n enumerable: false,\n writable: false,\n configurable: false,\n value: obj[internal],\n });\n}\n\nconst RELEASED_CHANNELS: Record<string, boolean> = {\n CARDS: true,\n QRIS: true,\n QR_PH: true,\n PROMPTPAY: true,\n SGQR: true,\n ALIPAY: true,\n APPOTA: true,\n ASTRAPAY: true,\n DANA: true,\n GCASH: true,\n GRABPAY: true,\n JENIUSPAY: true,\n LINEPAY: true,\n LINKAJA: true,\n NEXCASH: true,\n OVO: true,\n PAYMAYA: true,\n SHOPEEPAY: true,\n TOUCHNGO: true,\n TRUEMONEY: true,\n VNPTWALLET: true,\n WECHATPAY: true,\n ZALOPAY: true,\n GOPAY: true,\n GOPAY_RECURRING: true,\n};\n\n// filter out channels not supported by this SDK version\nexport function removeUnreleasedChannels(channels: BffChannel[]): BffChannel[] {\n return channels.filter((channel) => RELEASED_CHANNELS[channel.channel_code]);\n}\n\n/**\n * Returns true if the form has a field of the given type, *before filtering*.\n */\nexport function formHasFieldOfType(\n form: ChannelFormField[],\n type: string,\n): boolean {\n for (const field of form) {\n if (field.type.name === type) {\n return true;\n }\n }\n return false;\n}\n","import classNames from \"classnames\";\nimport { ComponentChildren, FunctionComponent } from \"preact\";\n\nexport enum ButtonVariant {\n BARE = \"bare\",\n PRIMARY_ROUNDED = \"primary-rounded\",\n WHITE_ROUNDED = \"white-rounded\",\n}\n\nexport enum ButtonSize {\n SM = \"sm\",\n MD = \"md\",\n}\n\ntype Props = {\n children: ComponentChildren;\n className?: string;\n disabled?: boolean;\n onClick?: (event: MouseEvent) => void;\n type?: \"button\" | \"submit\" | \"reset\";\n variant: ButtonVariant;\n size?: ButtonSize;\n};\n\nexport const Button: FunctionComponent<Props> = (props) => {\n const { children, variant, size, type = \"button\", ...rest } = props;\n\n const buttonVariantClass = {\n [ButtonVariant.BARE]: undefined,\n [ButtonVariant.PRIMARY_ROUNDED]: \"xendit-button-primary-rounded\",\n [ButtonVariant.WHITE_ROUNDED]: \"xendit-button-white-rounded\",\n }[variant];\n\n const buttonSizeClass = {\n [ButtonSize.SM]: \"xendit-button-sm\",\n [ButtonSize.MD]: undefined,\n }[size ?? ButtonSize.MD];\n\n return (\n <button\n {...rest}\n className={classNames(\n props.className,\n \"xendit-button\",\n buttonVariantClass,\n buttonSizeClass,\n )}\n type={type}\n >\n {children}\n </button>\n );\n};\n\nexport const ButtonLoadingSpinner = () => {\n const angle1 = Math.PI * 0.4;\n const angle2 = 0;\n const radius = 0.4;\n const start = { x: Math.cos(angle1) * radius, y: Math.sin(angle1) * radius };\n const end = { x: Math.cos(angle2) * radius, y: Math.sin(angle2) * radius };\n\n return (\n <svg className=\"xendit-button-loading-spinner\" viewBox=\"-0.5 -0.5 1 1\">\n <path\n d={`M ${start.x} ${start.y} A ${radius} ${radius} 0 0 0 ${end.x} ${end.y}`}\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"0.1\"\n strokeLinecap=\"round\"\n ></path>\n </svg>\n );\n};\n","import {\n ComponentChildren,\n FunctionComponent,\n TargetedEvent,\n TargetedMouseEvent,\n} from \"preact\";\nimport {\n useCallback,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from \"preact/hooks\";\nimport Icon from \"../icon\";\nimport { useIdSafe } from \"../../utils\";\nimport { useSdk } from \"../session-provider\";\nimport { ButtonLoadingSpinner } from \"./button\";\n\nexport type DropdownOption = {\n leadingAsset?: ComponentChildren; // e.g. flag/icon URL\n leadingAssetInOverlay?: ComponentChildren; // e.g. flag/icon URL, shown in the dropdown list (instead of the main button)\n title: string; // primary line\n shortTitle?: string;\n description?: string; // secondary line\n disabled?: boolean;\n value: string;\n};\n\nexport type DropdownProps = {\n /** Unique id for aria attributes */\n id?: string;\n\n /** Options to render */\n options: DropdownOption[];\n\n /**\n * Called when a new option is selected.\n * Receives the selected option & its index.\n */\n onChange: (option: DropdownOption, index: number) => void;\n\n /** Optional initial selection index (uncontrolled). Default: -1 (none). */\n defaultIndex?: number;\n\n /** Optional externally-controlled selection index. If set, component becomes controlled. */\n selectedIndex?: number;\n\n /** Optional label for a11y (used in aria-labelledby). */\n label?: string;\n\n /** Placeholder text when nothing selected. */\n placeholder?: string;\n\n /** Makes the dropdown disabled */\n disabled?: boolean;\n\n /** Adds a className to the button element */\n className?: string;\n\n /** If set, controls the overlay width */\n fixedOverlayWidth?: number;\n\n /** Toggles the search feature */\n enableSearch?: boolean;\n};\n\nexport const Dropdown = (props: DropdownProps) => {\n const {\n id: _id,\n options,\n onChange,\n defaultIndex = -1,\n selectedIndex,\n placeholder,\n disabled,\n className,\n fixedOverlayWidth,\n enableSearch,\n } = props;\n\n const t = useSdk().t;\n\n const generatedId = useIdSafe();\n const id = _id || generatedId;\n\n // Controlled vs uncontrolled selection\n const isControlled = typeof selectedIndex === \"number\";\n const [internalIndex, setInternalIndex] = useState(defaultIndex);\n const currentIndex = isControlled ? (selectedIndex as number) : internalIndex;\n\n // Active item for keyboard nav (when list open)\n const [activeIndex, setActiveIndex] = useState(\n currentIndex >= 0 ? currentIndex : 0,\n );\n const [_open, setOpen] = useState(false);\n const open = _open && !disabled && options.length > 0; // force closed when disabled or no options\n\n const [searchQuery, setSearchQuery] = useState(\"\");\n const [lastWidth, setLastWidth] = useState(0);\n\n const btnRef = useRef<HTMLButtonElement>(null);\n const rootRef = useRef<HTMLDivElement>(null);\n const listRef = useRef<HTMLUListElement>(null);\n const activeRef = useRef<HTMLLIElement>(null);\n const searchInputRef = useRef<HTMLInputElement>(null);\n const overlayRef = useRef<HTMLDivElement>(null);\n\n // Filter options based on search query\n const filteredOptions = useMemo(() => {\n const filtered = options.map(withIndex).filter(({ item: opt }) => {\n if (searchQuery.trim() === \"\") return true;\n const query = searchQuery.toLowerCase();\n return (\n opt.title.toLowerCase().includes(query) ||\n opt.description?.toLowerCase().includes(query) ||\n opt.value.toLowerCase().includes(query)\n );\n });\n\n // Show all options if no results found\n return filtered.length > 0 ? filtered : options.map(withIndex);\n }, [searchQuery, options]);\n\n const clampedActive = Math.max(\n 0,\n Math.min(filteredOptions.length - 1, activeIndex),\n );\n\n // Keep the overlay width in sync with the parent of the container element\n useLayoutEffect(() => {\n if (fixedOverlayWidth) {\n setLastWidth(fixedOverlayWidth);\n return;\n }\n\n const targetElement = btnRef.current;\n if (!targetElement) return;\n const width = targetElement.getBoundingClientRect().width;\n setLastWidth(width);\n\n if (!window.ResizeObserver) {\n // jsdom doesn't support ResizeObserver\n return;\n }\n\n // observe for future width changes (e.g. due to window resize)\n const resizeObserver = new ResizeObserver((entries) => {\n for (const entry of entries) {\n if (entry.target !== targetElement) continue;\n if (!entry.borderBoxSize?.length) continue;\n setLastWidth(entry.borderBoxSize[0].inlineSize);\n }\n });\n resizeObserver.observe(targetElement);\n return () => resizeObserver.disconnect();\n }, [fixedOverlayWidth]);\n\n // if the viewport OR the overlay element changes size, and on scroll, check if the overlay is overlapping the bottom of the viewport, and if it is, add bottom:0\n useLayoutEffect(() => {\n if (!open) return;\n const overlayEl = overlayRef.current;\n if (!overlayEl) return;\n const buttonEl = btnRef.current;\n if (!buttonEl) return;\n\n if (!window.ResizeObserver) {\n // jsdom doesn't support ResizeObserver\n return;\n }\n\n function updateOverlayPosition() {\n if (!overlayEl) return;\n if (!buttonEl) return;\n // if the distance from the bottom of the button to the bottom of the viewport is less than the height of the overlay, position the overlay with bottom:0\n const buttonRect = buttonEl.getBoundingClientRect();\n const overlayRect = overlayEl.getBoundingClientRect();\n const viewportBottom = window.innerHeight;\n const spaceBelow = viewportBottom - buttonRect.bottom;\n if (spaceBelow < overlayRect.height) {\n overlayEl.style.position = \"fixed\";\n overlayEl.style.bottom = \"0\";\n } else {\n overlayEl.style.position = \"\";\n overlayEl.style.bottom = \"\";\n }\n }\n\n updateOverlayPosition();\n\n const resizeObserver = new ResizeObserver(updateOverlayPosition);\n resizeObserver.observe(overlayEl);\n window.addEventListener(\"resize\", updateOverlayPosition);\n window.addEventListener(\"scroll\", updateOverlayPosition, true);\n return () => {\n resizeObserver.disconnect();\n window.removeEventListener(\"resize\", updateOverlayPosition);\n window.removeEventListener(\"scroll\", updateOverlayPosition, true);\n };\n }, [open]);\n\n // Close on outside click\n useLayoutEffect(() => {\n if (!open) return;\n const onMouseDown = (e: MouseEvent) => {\n const root = rootRef.current;\n if (!root) return;\n if (!root.contains(e.target as Node)) {\n setOpen(false);\n }\n };\n document.addEventListener(\"mousedown\", onMouseDown);\n return () => document.removeEventListener(\"mousedown\", onMouseDown);\n }, [open]);\n\n // Close on outside focusout\n useLayoutEffect(() => {\n if (!open) return;\n const onFocusOut = (e: FocusEvent) => {\n const root = rootRef.current;\n if (!root) return;\n if (!e.relatedTarget) return;\n if (!root.contains(e.relatedTarget as Node)) setOpen(false);\n };\n document.body.addEventListener(\"focusout\", onFocusOut);\n return () => document.body.removeEventListener(\"focusout\", onFocusOut);\n }, [open]);\n\n // Keep activeIndex in sync with current selection when opening\n useLayoutEffect(() => {\n if (!open) return;\n if (currentIndex >= 0) setActiveIndex(currentIndex);\n }, [open, currentIndex]);\n\n // when open state or active index changes, scroll to active item\n useLayoutEffect(() => {\n if (!open) return;\n if (!activeRef.current) return;\n if (!listRef.current) return;\n const scrollContainer = listRef.current.parentElement;\n if (!scrollContainer) return;\n scrollContainer.scrollTop =\n activeRef.current.offsetTop -\n scrollContainer.clientHeight / 2 +\n activeRef.current.clientHeight / 2;\n }, [open, activeIndex]);\n\n const openList = useCallback(() => {\n if (!open) {\n setOpen(true);\n queueMicrotask(() => searchInputRef.current?.focus());\n }\n }, [open]);\n\n const closeList = useCallback(() => {\n if (open) {\n setOpen(false);\n setSearchQuery(\"\");\n btnRef.current?.focus();\n }\n }, [open]);\n\n const onButtonClick = useCallback(() => {\n if (open) {\n closeList();\n } else {\n openList();\n }\n }, [closeList, open, openList]);\n\n const selectItemAndClose = useCallback(\n (index: number) => {\n const opt = options[index];\n if (!opt) return;\n if (opt.disabled) return;\n if (!isControlled) setInternalIndex(index);\n onChange(opt, index);\n closeList();\n },\n [closeList, isControlled, onChange, options],\n );\n\n const onListKeyDown = useCallback(\n (e: KeyboardEvent) => {\n // Allow normal typing in search input\n const isSearchInput = e.target === searchInputRef.current;\n\n if (e.key === \"Escape\") {\n e.preventDefault();\n closeList();\n return;\n }\n if (e.key === \"Enter\" || e.key === \" \") {\n // Allow space in search input for typing\n if (isSearchInput && e.key === \" \") {\n return;\n }\n e.preventDefault();\n const activeItem = filteredOptions[clampedActive];\n if (activeItem) {\n selectItemAndClose(activeItem.originalIndex);\n }\n return;\n }\n if (e.key === \"ArrowDown\") {\n e.preventDefault();\n setActiveIndex((i) => Math.min(filteredOptions.length - 1, i + 1));\n return;\n }\n if (e.key === \"ArrowUp\") {\n e.preventDefault();\n setActiveIndex((i) => Math.max(0, i - 1));\n return;\n }\n if (e.key === \"Home\") {\n e.preventDefault();\n setActiveIndex(0);\n return;\n }\n if (e.key === \"End\") {\n e.preventDefault();\n setActiveIndex(filteredOptions.length - 1);\n return;\n }\n },\n [clampedActive, closeList, selectItemAndClose, filteredOptions],\n );\n\n const onButtonKeyDown = useCallback(\n (e: KeyboardEvent) => {\n if (open) {\n return onListKeyDown(e);\n }\n if (\n e.key === \"ArrowDown\" ||\n e.key === \"ArrowUp\" ||\n e.key === \" \" ||\n e.key === \"Enter\"\n ) {\n e.preventDefault();\n openList();\n }\n },\n [onListKeyDown, open, openList],\n );\n\n const onOptionClick = useCallback(\n (e: TargetedMouseEvent<HTMLLIElement>) => {\n e.stopPropagation();\n e.preventDefault();\n selectItemAndClose(Number(e.currentTarget.dataset.index));\n },\n [selectItemAndClose],\n );\n\n const onSearchTermChange = useCallback(\n (e: TargetedEvent<HTMLInputElement>) => {\n setSearchQuery(e.currentTarget.value);\n setActiveIndex(0);\n },\n [],\n );\n\n const selected = currentIndex >= 0 ? options[currentIndex] : undefined;\n\n return (\n <div\n className=\"xendit-dropdown-container\"\n ref={rootRef}\n style={{ \"--xendit-dropdown-width\": lastWidth + \"px\" }}\n >\n <button\n id={id}\n ref={btnRef}\n type=\"button\"\n className={`xendit-dropdown ${className} ${open ? \"xendit-dropdown-open\" : \"\"} ${hasLeadingAsset(selected) ? \"xendit-dropdown-has-asset\" : \"\"}`}\n aria-expanded={open ? \"true\" : \"false\"}\n onClick={onButtonClick}\n onKeyDown={onButtonKeyDown}\n disabled={disabled}\n >\n {selected?.leadingAsset ?? null}\n\n {selected ? (\n <span className=\"xendit-dropdown-text xendit-text-14\">\n {selected.shortTitle ?? selected.title}\n </span>\n ) : (\n <span className=\"xendit-dropdown-text xendit-text-14\">\n {placeholder}\n </span>\n )}\n\n <Icon\n className=\"xendit-dropdown-chevron\"\n name=\"chevron\"\n size={16}\n direction=\"down\"\n />\n </button>\n\n {open ? (\n <div\n className=\"xendit-dropdown-overlay\"\n style={{ width: \"var(--xendit-dropdown-width)\" }}\n ref={overlayRef}\n >\n {enableSearch ? (\n <div className=\"xendit-dropdown-search\">\n <input\n ref={searchInputRef}\n placeholder={t(\"combobox.default_search_placeholder\")}\n value={searchQuery}\n onInput={onSearchTermChange}\n onClick={stopPropagation}\n onKeyDown={onListKeyDown}\n />\n </div>\n ) : null}\n <ul\n ref={listRef}\n role=\"listbox\"\n tabIndex={-1}\n onKeyDown={onListKeyDown}\n >\n {filteredOptions.map(({ item: opt, originalIndex }, i) => {\n const isSelected = originalIndex === currentIndex;\n const isActive = i === clampedActive;\n return (\n <li\n key={originalIndex}\n role=\"option\"\n data-index={originalIndex}\n aria-disabled={opt.disabled ? true : undefined}\n aria-selected={isSelected}\n onClick={onOptionClick}\n ref={isActive ? activeRef : undefined}\n >\n <div\n className={`xendit-dropdown-item xendit-text-14 ${isActive ? \"xendit-dropdown-item-active\" : \"\"} ${opt.leadingAsset ? \"xendit-dropdown-has-asset\" : \"\"} ${opt.disabled ? \"xendit-dropdown-item-disabled\" : \"\"}`}\n >\n {opt.leadingAssetInOverlay ?? opt.leadingAsset ?? null}\n <div className=\"xendit-dropdown-item-text xendit-text-14\">\n <span className=\"xendit-dropdown-item-title\">\n {opt.title}\n </span>\n {opt.description && (\n <span className=\"xendit-dropdown-item-description xendit-text-12\">\n {opt.description}\n </span>\n )}\n </div>\n {isSelected ? (\n <Icon\n name=\"check\"\n size={16}\n className={\"xendit-dropdown-item-selected\"}\n />\n ) : null}\n </div>\n </li>\n );\n })}\n </ul>\n </div>\n ) : null}\n </div>\n );\n};\n\nexport const DropdownSkeleton: FunctionComponent<{\n id: string;\n className?: string;\n}> = (props) => {\n return (\n <div className=\"xendit-dropdown-container xendit-skeleton-field\">\n <button\n className={`xendit-dropdown ${props.className}`}\n inert\n id={props.id}\n disabled\n type=\"button\"\n >\n <ButtonLoadingSpinner />\n </button>\n </div>\n );\n};\n\nfunction hasLeadingAsset(option: DropdownOption | undefined) {\n if (!option) return false;\n return !!(option.leadingAssetInOverlay || option.leadingAsset);\n}\n\nfunction stopPropagation(e: Event) {\n e.stopPropagation();\n}\n\nfunction withIndex<T>(\n item: T,\n originalIndex: number,\n): { item: T; originalIndex: number } {\n return {\n item,\n originalIndex,\n };\n}\n","import { BffChannel, BffChannelUiGroup } from \"./backend-types/channel\";\nimport { BffCustomer } from \"./backend-types/customer\";\nimport { BffDigitalWallets } from \"./backend-types/digital-wallets\";\nimport { BffSession } from \"./backend-types/session\";\nimport { internal } from \"./internal\";\nimport {\n XenditCustomer,\n XenditDigitalWallet,\n XenditPaymentChannel,\n XenditPaymentChannelGroup,\n XenditSession,\n} from \"./public-data-types\";\nimport {\n assert,\n assertEquals,\n assertNotEquals,\n lockDownInteralProperty,\n removeUndefinedPropertiesFromObject,\n satisfiesMinMax,\n} from \"./utils\";\n\ntype XenditItem = NonNullable<XenditSession[\"items\"]>[number];\n\nexport function bffSessionToPublic(bffSession: BffSession): XenditSession {\n assertNotEquals(bffSession.session_type, \"AUTHORIZATION\");\n assertEquals(bffSession.mode, \"COMPONENTS\");\n\n return removeUndefinedPropertiesFromObject<XenditSession>({\n id: bffSession.payment_session_id,\n description: bffSession.description || undefined,\n sessionType: bffSession.session_type,\n mode: bffSession.mode,\n referenceId: bffSession.reference_id,\n country: bffSession.country,\n currency: bffSession.currency,\n amount: bffSession.amount,\n channelProperties: bffSession.channel_properties || undefined,\n expiresAt: new Date(bffSession.expires_at),\n locale: bffSession.locale,\n status: bffSession.status,\n subscription: bffSession.subscription\n ? {\n immediatePayment: bffSession.subscription.immediate_payment,\n schedule: {\n anchorDate: new Date(bffSession.subscription.schedule.anchor_date),\n interval: bffSession.subscription.schedule.interval,\n intervalCount: bffSession.subscription.schedule.interval_count,\n retryInterval: bffSession.subscription.schedule.retry_interval,\n retryIntervalCount:\n bffSession.subscription.schedule.retry_interval_count,\n totalRecurrence: bffSession.subscription.schedule.total_recurrence,\n totalRetry: bffSession.subscription.schedule.total_retry,\n },\n }\n : undefined,\n\n items: bffSession.items?.map((item) => {\n return removeUndefinedPropertiesFromObject<XenditItem>({\n type: item.type,\n referenceId: item.reference_id,\n name: item.name,\n netUnitAmount: item.net_unit_amount,\n quantity: item.quantity,\n url: item.url,\n imageUrl: item.image_url,\n category: item.category,\n subcategory: item.subcategory,\n description: item.description,\n metadata: item.metadata,\n });\n }),\n });\n}\n\nexport function bffCustomerToPublic(bffCustomer: BffCustomer): XenditCustomer {\n assertEquals(bffCustomer.type, \"INDIVIDUAL\");\n assert(bffCustomer.individual_detail);\n return {\n id: bffCustomer.id,\n type: bffCustomer.type,\n email: bffCustomer.email ?? undefined,\n mobileNumber: bffCustomer.mobile_number ?? undefined,\n individualDetail: {\n givenNames: bffCustomer.individual_detail.given_names ?? undefined,\n surname: bffCustomer.individual_detail.surname ?? undefined,\n },\n };\n}\n\ntype ChannelMarshalConfig = {\n options: {\n filter?: string | string[] | RegExp;\n filterMinMax: boolean;\n };\n pairChannels: PairChannelData;\n session: Pick<BffSession, \"amount\" | \"session_type\">;\n};\n\n/**\n * Generate public channel groups list.\n */\nexport function bffUiGroupsToPublic(\n bffChannels: BffChannel[],\n bffChannelGroups: BffChannelUiGroup[],\n marshalConfig: ChannelMarshalConfig,\n): XenditPaymentChannelGroup[] {\n const groupsByGroupId = makeGroupsByGroupId(bffChannelGroups);\n const channelsByGroupId = makeChannelsByGroupId(bffChannels, marshalConfig);\n return bffChannelGroups\n .filter((group) => channelsByGroupId[group.id]?.length)\n .map((group) => {\n return bffUiGroupToPublic(\n group,\n channelsByGroupId,\n groupsByGroupId,\n marshalConfig,\n );\n });\n}\n\n/**\n * Generate one public channel group.\n */\nexport function bffUiGroupToPublic(\n bffChannelGroup: BffChannelUiGroup,\n channelsByGroupId: Record<string, BffChannel[]>,\n groupsByGroupId: Record<string, BffChannelUiGroup>,\n marshalConfig: ChannelMarshalConfig,\n) {\n const group = removeUndefinedPropertiesFromObject<XenditPaymentChannelGroup>({\n groupId: bffChannelGroup.id,\n label: bffChannelGroup.label,\n get channels() {\n return (channelsByGroupId[bffChannelGroup.id] || []).map((channel) => {\n return bffChannelToPublic(\n channel,\n channelsByGroupId,\n groupsByGroupId,\n marshalConfig,\n );\n });\n },\n [internal]: bffChannelGroup,\n });\n\n lockDownInteralProperty(group);\n\n return group;\n}\n\n/**\n * Generate one public channel, without group data.\n */\nexport function singleBffChannelToPublic(\n bffChannel: BffChannel,\n marshalConfig: ChannelMarshalConfig,\n): XenditPaymentChannel {\n return bffChannelToPublic(bffChannel, {}, {}, marshalConfig);\n}\n\n/**\n * Generate one public channel.\n */\nexport function bffChannelToPublic(\n bffChannel: BffChannel,\n bffChannelsByGroupId: Record<string, BffChannel[]>,\n bffGroupsByGroupId: Record<string, BffChannelUiGroup>,\n marshalConfig: ChannelMarshalConfig,\n): XenditPaymentChannel {\n assert(!marshalConfig.pairChannels.paired[bffChannel.channel_code]);\n\n const channel = removeUndefinedPropertiesFromObject<XenditPaymentChannel>({\n channelCode:\n marshalConfig.pairChannels.pairs[bffChannel.channel_code]?.map(\n (ch) => ch.channel_code,\n ) ?? bffChannel.channel_code,\n brandName: bffChannel.brand_name,\n brandColor: bffChannel.brand_color,\n brandLogoUrl: bffChannel.brand_logo_url,\n get uiGroup() {\n if (!bffGroupsByGroupId[bffChannel.ui_group]) {\n throw new Error(\"UI group not found\");\n }\n return bffUiGroupToPublic(\n bffGroupsByGroupId[bffChannel.ui_group],\n bffChannelsByGroupId,\n bffGroupsByGroupId,\n marshalConfig,\n );\n },\n minAmount: bffChannel.min_amount,\n maxAmount: bffChannel.max_amount,\n cardBrands: bffChannel.card?.brands.map((b) => {\n return {\n name: b.name,\n logoUrl: b.logo_url,\n };\n }),\n [internal]: marshalConfig.pairChannels.pairs[bffChannel.channel_code] ?? [\n bffChannel,\n ],\n });\n\n lockDownInteralProperty(channel);\n\n return channel;\n}\n\n/**\n * Generate public channels list.\n */\nexport function bffChannelsToPublic(\n bffChannels: BffChannel[],\n bffChannelGroups: BffChannelUiGroup[],\n marshalConfig: ChannelMarshalConfig,\n): XenditPaymentChannel[] {\n const groupsByGroupId = makeGroupsByGroupId(bffChannelGroups);\n const channelsByGroupId = makeChannelsByGroupId(bffChannels, marshalConfig);\n return bffChannels\n .filter((ch) => {\n return channelFilterFn(ch, marshalConfig);\n })\n .map((channel) => {\n return bffChannelToPublic(\n channel,\n channelsByGroupId,\n groupsByGroupId,\n marshalConfig,\n );\n });\n}\n\n/**\n * Make a mapping of group ID to group.\n */\nfunction makeGroupsByGroupId(\n bffChannelGroups: BffChannelUiGroup[],\n): Record<string, BffChannelUiGroup> {\n const groupMap: Record<string, BffChannelUiGroup> = {};\n for (const bffGroup of bffChannelGroups) {\n groupMap[bffGroup.id] = bffGroup;\n }\n return groupMap;\n}\n\n/**\n * Return true if the channel passes the filter criteria.\n */\nexport function channelFilterFn(\n channel: BffChannel,\n marshalConfig: ChannelMarshalConfig,\n) {\n if (marshalConfig.pairChannels.paired[channel.channel_code]) {\n // channel is a second member of a pair, skip\n // TODO: users may filter out the first member of a pair, in which case we should remap the second member to the first\n return false;\n }\n\n if (\n marshalConfig.options.filterMinMax &&\n !satisfiesMinMax(marshalConfig.session, channel)\n ) {\n // min/max amount not satisfied\n return false;\n }\n\n const filter = marshalConfig.options.filter;\n if (filter && !channelCodeMatchesFilter(filter, channel.channel_code)) {\n // channel code does not match filter\n return false;\n }\n\n return true;\n}\n\n/**\n * Checks a channel code string against a filter term.\n */\nfunction channelCodeMatchesFilter(\n filter: string | string[] | RegExp,\n code: string,\n) {\n if (typeof filter === \"string\" && code === filter) {\n return true;\n }\n if (Array.isArray(filter) && filter.includes(code)) {\n return true;\n }\n if (filter instanceof RegExp && filter.test(code)) {\n return true;\n }\n return false;\n}\n\n/**\n * Create a mapping of group ID to channels in that group, applying channel filtering and removing empty groups.\n */\nexport function makeChannelsByGroupId(\n bffChannels: BffChannel[],\n marshalConfig: ChannelMarshalConfig,\n): Record<string, BffChannel[]> {\n const channelsByGroupId: Record<string, BffChannel[]> = {};\n for (const bffChannel of bffChannels) {\n if (!channelFilterFn(bffChannel, marshalConfig)) {\n continue;\n }\n const groupId = bffChannel.ui_group;\n if (!channelsByGroupId[groupId]) {\n channelsByGroupId[groupId] = [];\n }\n channelsByGroupId[groupId].push(bffChannel);\n }\n return channelsByGroupId;\n}\n\ntype PairChannelData = {\n /** Map of channel_code of first member of pair to an array containing the pair */\n pairs: Record<string, [BffChannel, BffChannel]>;\n /** Set of channel_codes of second members of pairs */\n paired: Record<string, boolean>;\n};\n\n/**\n * Finds channels that are pairs (i.e., differ only by allow_save) and groups them together.\n */\nexport function findChannelPairs(bffChannels: BffChannel[]): PairChannelData {\n const brandMap = new Map<string, BffChannel[]>();\n for (const channel of bffChannels) {\n const brandName = channel.brand_name;\n if (!brandMap.has(brandName)) {\n brandMap.set(brandName, []);\n }\n brandMap.get(brandName)!.push(channel);\n }\n\n const pairs: Record<string, [BffChannel, BffChannel]> = {};\n const paired: Record<string, boolean> = {};\n for (const [_, channels] of brandMap) {\n for (const ch of channels) {\n const isFirst = channels[0].allow_save === false;\n if (isFirst) {\n const pair = channels.find(\n (other) =>\n ch.channel_code !== other.channel_code &&\n ch.ui_group === other.ui_group &&\n other.allow_save === true,\n );\n if (pair) {\n pairs[ch.channel_code] = [ch, pair];\n paired[pair.channel_code] = true;\n }\n }\n }\n }\n\n return {\n pairs,\n paired,\n };\n}\n\nexport function bffDigitalWalletsToPublic(\n bffDigitalWallets: BffDigitalWallets,\n bffChannels: BffChannel[],\n bffChannelGroups: BffChannelUiGroup[],\n marshalConfig: ChannelMarshalConfig,\n): XenditDigitalWallet[] {\n const out: XenditDigitalWallet[] = [];\n\n const groupsByGroupId = makeGroupsByGroupId(bffChannelGroups);\n\n if (bffDigitalWallets.google_pay) {\n const googlePayChannels =\n bffDigitalWallets.google_pay.allowed_payment_methods.map((method) => {\n const ch = bffChannels.find(\n (c) => c.channel_code === method.channel_code,\n );\n assert(ch);\n return ch;\n });\n\n const channelsByGroupId = makeChannelsByGroupId(\n googlePayChannels,\n marshalConfig,\n );\n\n out.push({\n digitalWalletCode: \"GOOGLE_PAY\",\n get channels() {\n return googlePayChannels.map((channel) => {\n return bffChannelToPublic(\n channel,\n channelsByGroupId,\n groupsByGroupId,\n marshalConfig,\n );\n });\n },\n [internal]: true,\n });\n }\n\n return out;\n}\n","import { FunctionComponent } from \"preact\";\n\nexport const DottedLine: FunctionComponent = (props) => {\n return <hr className={\"xendit-dotted-line\"} />;\n};\n","import {\n useCurrentChannel,\n useChannels,\n useSdk,\n useSession,\n} from \"./session-provider\";\nimport { BffChannel, BffChannelUiGroup } from \"../backend-types/channel\";\nimport { Dropdown, DropdownOption } from \"./core/dropdown\";\nimport { BffSession } from \"../backend-types/session\";\nimport { satisfiesMinMax, useIdSafe, usePrevious } from \"../utils\";\nimport {\n useCallback,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from \"preact/hooks\";\nimport {\n channelFilterFn,\n findChannelPairs,\n singleBffChannelToPublic,\n} from \"../bff-marshal\";\nimport { TFunction } from \"../localization\";\nimport { FunctionComponent } from \"preact\";\nimport { DottedLine } from \"./core/dotted-line\";\n\ninterface ChannelPickerGroupProps {\n group: BffChannelUiGroup;\n open: boolean;\n}\n\nexport const ChannelPickerGroup: FunctionComponent<ChannelPickerGroupProps> = (\n props,\n) => {\n const { group, open } = props;\n\n const sdk = useSdk();\n const { t } = sdk;\n const session = useSession();\n const channels = useChannels();\n\n const currentChannel = useCurrentChannel();\n\n const sessionType = session.session_type;\n\n const dropdownId = useIdSafe();\n\n // record the last user selection in the dropdown.\n // if the current channel selection is not part of this group, use this instead.\n // if this is set, and the current channel is null, when the group is opened we will restore this selection.\n const [fakeDropdownSelection, setFakeDropdownSelection] = useState<\n string | null\n >(null);\n\n // container for the selected channel component\n const containerRef = useRef<HTMLDivElement>(null);\n // if true, the container has something in it\n const [containerIsPopulated, setContainerIsPopulated] = useState(false);\n // reference to the selected channel element\n const selectedChannelElementRef = useRef<HTMLElement>(null);\n\n const pairChannelData = useMemo(() => findChannelPairs(channels), [channels]);\n const marshalConfig = useMemo(\n () => ({\n pairChannels: pairChannelData,\n session: {\n amount: session.amount,\n session_type: session.session_type,\n },\n options: { filterMinMax: false },\n }),\n [pairChannelData, session.amount, session.session_type],\n );\n\n const channelsInGroup = useMemo(() => {\n return channels.filter((ch) => {\n return channelFilterFn(ch, marshalConfig) && ch.ui_group === group.id;\n });\n }, [channels, group.id, marshalConfig]);\n\n // Create and mount the channel component if a channel is selected.\n // (replacing whatever was there before)\n useLayoutEffect(() => {\n if (!containerRef.current) return;\n if (!currentChannel) return;\n if (!open) return;\n const channelIsInThisGroup = channelsInGroup.find(\n (ch) => ch.channel_code === currentChannel.channel_code,\n );\n if (!channelIsInThisGroup) return;\n\n selectedChannelElementRef.current = sdk.createChannelComponent(\n singleBffChannelToPublic(currentChannel, marshalConfig),\n );\n if (\n selectedChannelElementRef.current.parentElement !== containerRef.current\n ) {\n setContainerIsPopulated(true);\n containerRef.current.replaceChildren(selectedChannelElementRef.current);\n } else {\n // it's already in the right place, do nothing.\n // replaceChildren would cause iframes to reload even if we do a no-op update.\n }\n }, [channelsInGroup, currentChannel, marshalConfig, open, sdk]);\n\n // when the group is opened, if the currently selected channel is unset but the fakeDropdownSelection is set,\n // select that channel to sync this group's selection with the sdk state\n const previousOpen = usePrevious(open);\n useLayoutEffect(() => {\n if (open && !previousOpen) {\n // only run this when the group is opened\n if (currentChannel === null && fakeDropdownSelection !== null) {\n // restore the previous user selection\n const ch = channelsInGroup.find(\n (channel) => channel.channel_code === fakeDropdownSelection,\n );\n if (ch) {\n sdk.setCurrentChannel(singleBffChannelToPublic(ch, marshalConfig));\n }\n }\n }\n }, [\n channelsInGroup,\n currentChannel,\n fakeDropdownSelection,\n marshalConfig,\n open,\n previousOpen,\n sdk,\n ]);\n\n // Called on channel dropdown change\n const onSelectedChannelChange = useCallback(\n (dropdownOption: DropdownOption) => {\n const selected =\n channels.find(\n (channel) => channel.channel_code === dropdownOption.value,\n ) || null;\n\n // change both the local dropdown selection state and the sdk current channel\n setFakeDropdownSelection(selected?.channel_code ?? null);\n sdk.setCurrentChannel(\n selected ? singleBffChannelToPublic(selected, marshalConfig) : null,\n );\n },\n [channels, marshalConfig, sdk],\n );\n\n // Create channel options for dropdown\n const channelOptions = useMemo(() => {\n return channelsInGroup.map<DropdownOption>((channel) => ({\n leadingAsset: (\n <img\n className=\"xendit-dropdown-channel-logo\"\n src={channel.brand_logo_url}\n key={channel.channel_code}\n />\n ),\n leadingAssetInOverlay: (\n <img\n className=\"xendit-channel-logo\"\n src={channel.brand_logo_url}\n key={channel.channel_code}\n />\n ),\n title: channel.brand_name,\n value: channel.channel_code,\n disabled: !satisfiesMinMax(session, channel),\n description: getChannelDisabledReason(t, session, channel) || undefined,\n }));\n }, [channelsInGroup, session, t]);\n\n // Hide dropdown for cards channel\n const hideDropdown =\n channelsInGroup.length === 1 && channelsInGroup[0].channel_code === \"CARDS\";\n\n function dropdownSelectedIndex() {\n // find the selected index based on currentChannel, or fallback to fakeDropdownSelection\n const i1 = channelOptions.findIndex((channel) => {\n return channel.value === currentChannel?.channel_code;\n });\n if (i1 !== -1) return i1;\n const i2 = channelOptions.findIndex((channel) => {\n return channel.value === fakeDropdownSelection;\n });\n if (i2 !== -1) return i2;\n\n // if there's only one option, pretend it's always selected\n if (channelOptions.length === 1) return 0;\n\n return -1;\n }\n\n return (\n <div className=\"xendit-channel-picker-group\">\n {hideDropdown ? null : (\n <div className=\"xendit-channel-form-field-group\">\n <label htmlFor={dropdownId} className=\"xendit-text-14\">\n {sessionType === \"SAVE\"\n ? t(\"payment_methods.add_payment_method\", {\n groupName: group.label ?? \"\",\n ns: \"session\",\n })\n : t(\"payment_methods.pay_with\")}\n </label>\n <Dropdown\n id={dropdownId}\n selectedIndex={dropdownSelectedIndex()}\n options={channelOptions}\n disabled={channelOptions.length <= 1}\n onChange={onSelectedChannelChange}\n placeholder={t(\"payment_methods.select_channel_placeholder\", {\n groupName: group.label,\n ns: \"session\",\n })}\n />\n </div>\n )}\n {!hideDropdown && containerIsPopulated ? <DottedLine /> : null}\n <div\n style={{ display: containerIsPopulated ? \"\" : \"none\" }}\n ref={containerRef}\n />\n </div>\n );\n};\n\nexport function getChannelDisabledReason(\n t: TFunction,\n session: BffSession,\n channel: BffChannel,\n): string | null {\n if (satisfiesMinMax(session, channel)) {\n return null;\n }\n\n if (channel.min_amount && session.amount < channel.min_amount) {\n return t(\"payment_methods.channel_disabled_amount_too_small\");\n } else {\n return t(\"payment_methods.channel_disabled_amount_too_large\");\n }\n}\n","import { FunctionComponent } from \"preact\";\nimport { useDigitalWallets, useSdk } from \"./session-provider\";\nimport { useLayoutEffect, useRef } from \"preact/hooks\";\n\nexport const ChannelPickerDigitalWalletSection: FunctionComponent = (props) => {\n const sdk = useSdk();\n\n const containerRef = useRef<HTMLDivElement>(null);\n\n const digitalWallets = useDigitalWallets();\n const digitalWalletsGooglePay = digitalWallets?.google_pay;\n\n useLayoutEffect(() => {\n if (containerRef.current && digitalWalletsGooglePay) {\n const el = sdk.createDigitalWalletComponent(\"GOOGLE_PAY\");\n containerRef.current.appendChild(el);\n return () => {\n el.remove();\n };\n }\n }, [digitalWalletsGooglePay, sdk]);\n\n return (\n <div\n ref={containerRef}\n className=\"xendit-channel-picker-digital-wallet-section\"\n ></div>\n );\n};\n","import { Accordion } from \"./core/accordion\";\nimport { AccordionItem } from \"./core/accordion-item\";\nimport {\n useCurrentChannel,\n useChannelUiGroups,\n useSession,\n useChannels,\n useSdk,\n} from \"./session-provider\";\nimport {\n useCallback,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from \"preact/hooks\";\nimport { FunctionComponent } from \"preact\";\nimport {\n ChannelPickerGroup,\n getChannelDisabledReason,\n} from \"./channel-picker-group\";\nimport { assert, satisfiesMinMax } from \"../utils\";\nimport { BffSession } from \"../backend-types/session\";\nimport { BffChannel, BffChannelUiGroup } from \"../backend-types/channel\";\nimport { TFunction } from \"../localization\";\nimport {\n findChannelPairs,\n makeChannelsByGroupId,\n singleBffChannelToPublic,\n} from \"../bff-marshal\";\nimport { ChannelPickerDigitalWalletSection } from \"./channel-picker-digital-wallet-section\";\nimport { internal } from \"../internal\";\nimport { IconName } from \"./icon\";\n\ntype Props = object;\n\nexport const ChannelPickerRoot: FunctionComponent<Props> = (props) => {\n const sdk = useSdk();\n const session = useSession();\n const channelUiGroups = useChannelUiGroups();\n const currentChannel = useCurrentChannel();\n const channels = useChannels();\n const { t } = useSdk();\n\n const channelsByGroup = useMemo(() => {\n return makeChannelsByGroupId(channels, {\n options: { filterMinMax: false },\n pairChannels: findChannelPairs(channels),\n session,\n });\n }, [channels, session]);\n\n const thisRef = useRef<HTMLDivElement>(null);\n\n const pairChannelData = useMemo(() => findChannelPairs(channels), [channels]);\n const marshalConfig = useMemo(\n () => ({\n pairChannels: pairChannelData,\n session: {\n amount: session.amount,\n session_type: session.session_type,\n },\n options: { filterMinMax: false },\n }),\n [pairChannelData, session.amount, session.session_type],\n );\n\n // selected group is the containing group of the currently selected channel\n const selectedGroupId = currentChannel?.ui_group ?? null;\n\n // previewed group means expanded but no channel selected\n const [previewGroupId, setPreviewGroupId] = useState<string | null>(null);\n\n const handleSelectChannelGroup = useCallback(\n (groupId: string) => {\n if (selectedGroupId === groupId || previewGroupId === groupId) {\n // user wants to collapse the group while a channel was selected, clear the channel selection\n if (selectedGroupId === groupId) {\n // clear actual selection\n thisRef.current?.dispatchEvent(\n new XenditClearCurrentChannelEvent(groupId),\n );\n }\n if (previewGroupId === groupId) {\n // clear previewed state\n setPreviewGroupId(null);\n }\n } else {\n // user wants to open a different group\n // if the new group has one channel, select it automatically\n // otherwise set it as previewed\n const newGroup = channelUiGroups.find((g) => g.id === groupId);\n assert(newGroup);\n const enabledChannels = groupEnabledChannelStats(\n session,\n newGroup,\n channels,\n t,\n ).enabledChannels;\n if (enabledChannels === 0) {\n // no enabled channels, do nothing\n return;\n } else if (enabledChannels === 1) {\n // one enabled channel, select it automatically\n const ch = channelsByGroup[groupId][0];\n sdk.setCurrentChannel(singleBffChannelToPublic(ch, marshalConfig));\n setPreviewGroupId(null);\n } else {\n // multiple enabled channels, set as previewed and clear the channel selection\n setPreviewGroupId(groupId);\n sdk.setCurrentChannel(null);\n }\n }\n },\n [\n channelUiGroups,\n channels,\n channelsByGroup,\n marshalConfig,\n previewGroupId,\n sdk,\n selectedGroupId,\n session,\n t,\n ],\n );\n\n // once a channel is selected, remove previewGroupId.\n // (without this, the group would continue showing the old selected channel after the selection is cleared using setCurrentChannel(null))\n useLayoutEffect(() => {\n if (currentChannel !== null && previewGroupId !== null) {\n setPreviewGroupId(null);\n }\n }, [currentChannel, previewGroupId]);\n\n // TODO: enable by default when released\n const digitalWalletSectionEnabled =\n sdk[internal].options.enableDigitalWallets ?? false;\n\n return (\n <div ref={thisRef}>\n {digitalWalletSectionEnabled ? (\n <ChannelPickerDigitalWalletSection />\n ) : null}\n <Accordion>\n {channelUiGroups\n .filter((group) => {\n // remove empty groups\n return (channelsByGroup[group.id] || []).length > 0;\n })\n .map((group) => {\n // make the group open if it is selected or previewed\n const open =\n selectedGroupId !== null\n ? selectedGroupId === group.id\n : previewGroupId === group.id;\n\n // make the group disabled if it has no enabled channels\n const enabledChannelsStats = groupEnabledChannelStats(\n session,\n group,\n channels,\n t,\n );\n const disabled = enabledChannelsStats.enabledChannels === 0;\n const disabledReason =\n enabledChannelsStats.firstDisabledChannelReason;\n\n return (\n <AccordionItem\n key={group.id}\n id={group.id}\n title={group.label}\n iconName={iconName(\n selectedGroupId === group.id ? currentChannel : null,\n channelsByGroup[group.id],\n )}\n subtitle={disabledReason ?? undefined}\n open={open}\n disabled={disabled}\n onClick={handleSelectChannelGroup}\n >\n <ChannelPickerGroup group={group} open={open} />\n </AccordionItem>\n );\n })}\n </Accordion>\n </div>\n );\n};\n\n// returns null if the group has any enabled channels, otherwise returns the disabled reason as a string\nfunction groupEnabledChannelStats(\n session: BffSession,\n group: BffChannelUiGroup,\n channels: BffChannel[],\n t: TFunction,\n): {\n enabledChannels: number;\n firstDisabledChannelReason: string | null;\n} {\n let firstDisabledChannelReason = null;\n let enabledChannels = 0;\n for (const channel of channels) {\n if (channel.ui_group !== group.id) continue;\n if (satisfiesMinMax(session, channel)) {\n enabledChannels++;\n continue;\n }\n if (firstDisabledChannelReason === null) {\n firstDisabledChannelReason = getChannelDisabledReason(\n t,\n session,\n channel,\n );\n }\n }\n return {\n enabledChannels,\n firstDisabledChannelReason,\n };\n}\n\nconst ICONS_BY_PM_TYPE: Record<string, IconName> = {\n CARDS: \"card\",\n QR_CODE: \"qr\",\n OVER_THE_COUNTER: \"otc\",\n EWALLET: \"ewallet\",\n BANK_TRANSFER: \"bank_transfer\",\n DIRECT_DEBIT: \"bank_transfer\",\n VIRTUAL_ACCOUNT: \"bank_transfer\",\n ONLINE_BANKING: \"online_banking\",\n};\n\nfunction iconName(\n currentChannel: BffChannel | null,\n channelsInGroup: BffChannel[],\n): IconName {\n if (\n currentChannel &&\n currentChannel.pm_type &&\n ICONS_BY_PM_TYPE[currentChannel.pm_type]\n ) {\n return ICONS_BY_PM_TYPE[currentChannel.pm_type];\n } else {\n for (const channel of channelsInGroup) {\n if (channel.pm_type && ICONS_BY_PM_TYPE[channel.pm_type]) {\n return ICONS_BY_PM_TYPE[channel.pm_type];\n }\n }\n }\n return \"dummy\";\n}\n\nexport class XenditClearCurrentChannelEvent extends Event {\n static readonly type = \"xendit-clear-current-channel\" as const;\n uiGroup: string;\n\n constructor(uiGroup: string) {\n super(XenditClearCurrentChannelEvent.type, {\n bubbles: true,\n composed: true,\n });\n this.uiGroup = uiGroup;\n }\n}\n","import { useCallback, useLayoutEffect, useRef, useState } from \"preact/hooks\";\nimport { FieldProps } from \"./field\";\nimport { CountryCode, getCountries } from \"libphonenumber-js\";\nimport { Dropdown, DropdownOption } from \"./core/dropdown\";\nimport { formFieldId, formFieldName, usePrevious } from \"../utils\";\nimport { FunctionComponent } from \"preact\";\nimport { useChannelComponentData } from \"./channel-root\";\n\ntype FlagIconProps = {\n countryCode: string;\n size?: number;\n};\n\nconst FlagIcon: FunctionComponent<FlagIconProps> = ({\n countryCode,\n size = 16,\n}) => {\n return (\n <div\n style={{\n width: `${size}px`,\n height: `${size}px`,\n borderRadius: \"50%\",\n backgroundImage: `url(https://assets.xendit.co/payment-session/flags/circle/${countryCode.toLowerCase()}.svg)`,\n backgroundSize: \"cover\",\n backgroundPosition: \"center\",\n }}\n />\n );\n};\n\nexport const CountryField: FunctionComponent<FieldProps> = (props) => {\n const { field, onChange } = props;\n const id = formFieldId(field);\n const name = formFieldName(field);\n\n const [selectedCountry, setSelectedCountry] = useState<\n CountryCode | undefined\n >(undefined);\n const selectedCountryIndex = COUNTRIES_AS_DROPDOWN_OPTIONS.findIndex(\n (option) => option.value === selectedCountry,\n );\n\n const hiddenFieldRef = useRef<HTMLInputElement>(null);\n\n useOnCardCountryChange((newCountry: CountryCode) => {\n if (hiddenFieldRef.current) {\n const newOption = COUNTRIES_AS_DROPDOWN_OPTIONS.find((option) => {\n return option.value === newCountry;\n });\n if (newOption) onChangeWrapper(newOption);\n }\n });\n\n const onChangeWrapper = useCallback(\n (option: DropdownOption) => {\n setSelectedCountry(option.value as CountryCode);\n if (hiddenFieldRef.current) {\n hiddenFieldRef.current.value = option.value;\n }\n onChange();\n },\n [onChange],\n );\n\n return (\n <div>\n <input type=\"hidden\" name={name} defaultValue=\"\" ref={hiddenFieldRef} />\n <Dropdown\n id={id}\n options={COUNTRIES_AS_DROPDOWN_OPTIONS}\n onChange={onChangeWrapper}\n placeholder={field.placeholder}\n selectedIndex={selectedCountryIndex}\n enableSearch\n className=\"xendit-form-field-inner\"\n />\n </div>\n );\n};\n\nexport const COUNTRIES_AS_DROPDOWN_OPTIONS = getCountries()\n .map((countryCode) => {\n const country = new Intl.DisplayNames([\"en\"], {\n type: \"region\",\n }).of(countryCode);\n\n return {\n title: country,\n value: countryCode,\n leadingAsset: <FlagIcon countryCode={countryCode} />,\n } as DropdownOption;\n })\n .sort((a, b) => a.title.localeCompare(b.title));\n\nexport function useOnCardCountryChange(fn: (newCountry: CountryCode) => void) {\n const cardDetails = useChannelComponentData()?.cardDetails;\n const cardDetailsCountry = cardDetails?.details?.country_codes[0];\n\n // if card details changes, set country to card's country\n const previousCardDetailsCountry = usePrevious(cardDetailsCountry);\n useLayoutEffect(() => {\n if (\n cardDetailsCountry &&\n cardDetailsCountry !== previousCardDetailsCountry\n ) {\n fn(cardDetailsCountry as CountryCode);\n }\n });\n}\n","import { FunctionComponent } from \"preact\";\nimport { ChannelFormField, FieldType } from \"../backend-types/channel\";\nimport { formFieldId, formFieldName } from \"../utils\";\nimport { Dropdown, DropdownOption } from \"./core/dropdown\";\nimport { FieldProps } from \"./field\";\nimport {\n useCallback,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from \"preact/hooks\";\n\nconst toDropdownOptions = (\n fieldOptions: (FieldType & { name: \"dropdown\" })[\"options\"],\n): DropdownOption[] => {\n return fieldOptions.map((opt) => ({\n title: opt.label,\n description: opt.subtitle,\n value: opt.value,\n }));\n};\n\nexport const DropdownField: FunctionComponent<FieldProps> = (props) => {\n const { field, onChange } = props;\n const id = formFieldId(field);\n const name = formFieldName(field);\n\n if (!isDropdownField(field)) {\n throw new Error(\"DropdownField expects field.type.name to be 'dropdown'\");\n }\n\n const hiddenFieldRef = useRef<HTMLInputElement>(null);\n\n const dropdownItems = useMemo(() => {\n return toDropdownOptions(field.type.options);\n }, [field.type.options]);\n\n const [selectedItemValue, setSelectedItemValue] = useState<string>(\n dropdownItems[0]?.value ?? \"\",\n );\n\n const onChangeWrapper = useCallback(\n (option: DropdownOption) => {\n if (hiddenFieldRef.current) {\n hiddenFieldRef.current.value = option.value;\n }\n setSelectedItemValue(option.value);\n onChange();\n },\n [onChange],\n );\n\n useLayoutEffect(() => {\n // first render only, force select first option\n if (dropdownItems.length) onChangeWrapper(dropdownItems[0]);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const selectedIndex = dropdownItems.findIndex(\n (opt) => opt.value === selectedItemValue,\n );\n\n return (\n <>\n <Dropdown\n id={id}\n placeholder={field.placeholder}\n options={dropdownItems}\n onChange={onChangeWrapper}\n selectedIndex={selectedIndex}\n className=\"xendit-form-field-inner\"\n />\n <input type=\"hidden\" name={name} defaultValue=\"\" ref={hiddenFieldRef} />\n </>\n );\n};\n\nfunction isDropdownField(field: ChannelFormField): field is ChannelFormField & {\n type: { name: \"dropdown\" };\n} {\n return field.type.name === \"dropdown\";\n}\n","import { registerElement } from \"../../dom-utils\";\n\n// prevent crash if running in node\nconst HTMLElement: (typeof window)[\"HTMLElement\"] =\n typeof window !== \"undefined\" && window.HTMLElement\n ? window.HTMLElement\n : (EventTarget as typeof HTMLElement);\n\n/**\n * https://html.spec.whatwg.org/multipage/forms.html#category-label\n * See the definition of \"labelable\".\n * This is a custom element which is labelable.\n *\n * This makes it possible to catch focus events when a label element is\n * clicked without adding any interactive elements.\n */\nexport class XenditFormAssociatedFocusTrap extends HTMLElement {\n static tag = \"xendit-form-associated-focus-trap\" as const;\n static formAssociated = true;\n private internals: ElementInternals;\n constructor() {\n super();\n this.internals = this.attachInternals();\n }\n}\nregisterElement(XenditFormAssociatedFocusTrap);\n\ndeclare module \"react/jsx-runtime\" {\n // eslint-disable-next-line @typescript-eslint/no-namespace\n namespace JSX {\n interface IntrinsicElements {\n \"xendit-form-associated-focus-trap\": preact.DetailedHTMLProps<\n preact.HTMLAttributes<XenditFormAssociatedFocusTrap>,\n XenditFormAssociatedFocusTrap\n >;\n }\n }\n}\n","export function registerElement(\n element: CustomElementConstructor & { tag: string },\n) {\n if (typeof window === \"undefined\" || !window.customElements) return;\n customElements.define(element.tag, element);\n}\n\nexport function findFirstStyleOrLinkElement() {\n return document.querySelector(\"style, link\");\n}\n","import { BffPollResponse } from \"./backend-types/common\";\nimport {\n ChannelComponentData,\n UpdatableWorldState,\n WorldState,\n} from \"./public-sdk\";\n\n/**\n * @internal\n * Event fired when a session / paymentEntity / etc is changed.\n *\n * Fire this on the sdk instance.\n * ! Don't fire this from within a react render\n */\nexport class InternalUpdateWorldState extends Event {\n static type = \"xendit-update-world-state\" as const;\n\n constructor(public data: WorldState | UpdatableWorldState) {\n super(InternalUpdateWorldState.type, { bubbles: false });\n }\n}\n\n/**\n * @internal\n * Event fired when a session / paymentEntity / etc is changed.\n *\n * Fire this on the sdk instance.\n * ! Don't fire this from within a react render\n */\nexport class InternalUpdateChannelComponentData extends Event {\n static type = \"xendit-update-channel-component-data\" as const;\n\n constructor(\n public channelCode: string,\n public data: Partial<ChannelComponentData>,\n ) {\n super(InternalUpdateChannelComponentData.type, { bubbles: false });\n }\n}\n\n/**\n * @internal\n * Marks it as touched, causing it to reveal validation errors.\n *\n * Fire this on the input to mark as touched.\n * Safe to fire from within a react render.\n */\nexport class InternalSetFieldTouchedEvent extends Event {\n static type = \"xendit-internal-set-field-touched\" as const;\n\n constructor() {\n super(InternalSetFieldTouchedEvent.type, { bubbles: true });\n }\n}\n\n/**\n * @internal\n * Schedules a behavior tree update.\n *\n * Fire this on the sdk instance.\n * Safe to fire from within a react render.\n * ! Be careful to avoid infinite loops.\n */\nexport class InternalBehaviorTreeUpdateEvent extends Event {\n static type = \"xendit-internal-behavior-tree-update\" as const;\n\n constructor() {\n super(InternalBehaviorTreeUpdateEvent.type, {});\n }\n}\n\n/**\n * @internal\n * Schedule a rerender of all components on the next tick.\n *\n * Fire this on the sdk instance.\n * ! Don't fire this from within a react render\n */\nexport class InternalNeedsRerenderEvent extends Event {\n static type = \"xendit-internal-needs-rerender\" as const;\n\n constructor() {\n super(InternalNeedsRerenderEvent.type, {});\n }\n}\n\n/**\n * @internal\n * Set the contents of the next mock poll response. Replaces any other pending scheduled mock update.\n *\n * Fire this on the sdk instance.\n * Safe to fire from within a react render.\n */\nexport class InternalScheduleMockUpdateEvent extends Event {\n static type = \"xendit-internal-schedule-mock-update\" as const;\n\n constructor(public mockData: BffPollResponse | null) {\n super(InternalScheduleMockUpdateEvent.type, {});\n }\n}\n","import {\n ComponentChildren,\n createContext,\n FunctionComponent,\n RefObject,\n} from \"preact\";\nimport { IframeEvent } from \"../../../shared/types\";\nimport { useRef } from \"preact/hooks\";\nimport { assert } from \"../utils\";\n\ninterface IframeRegistry {\n registerIframe: (\n fieldName: string,\n iframeRef: RefObject<HTMLIFrameElement>,\n ) => void;\n unregisterIframe: (fieldName: string) => void;\n postMessageToIframe: (fieldName: string, message: IframeEvent) => void;\n}\n\n/**\n * Context to keep track of iframes rendered in the form, allowing other components\n * to post messages to these iframes without needing direct access to their refs.\n */\nexport const IframeRegistryContext = createContext<IframeRegistry | null>(null);\n\n// read iframe data from environment variable\nassert(process.env.XENDIT_COMPONENTS_SECURE_IFRAME_URL);\nconst parsedIframeUrl = new URL(\n process.env.XENDIT_COMPONENTS_SECURE_IFRAME_URL,\n);\nconst IFRAME_ORIGIN = parsedIframeUrl.origin;\n\nexport const IframeRegistryProvider: FunctionComponent<{\n children: ComponentChildren;\n}> = ({ children }) => {\n const iframeRegistry = useRef<Map<string, HTMLIFrameElement>>(new Map());\n\n const iframeRegistryValue: IframeRegistry = {\n registerIframe: (fieldName, ref) => {\n if (ref.current) iframeRegistry.current.set(fieldName, ref.current);\n },\n unregisterIframe: (fieldName) => iframeRegistry.current.delete(fieldName),\n postMessageToIframe: (fieldName, message) => {\n const iframe = iframeRegistry.current.get(fieldName);\n if (iframe?.contentWindow) {\n iframe.contentWindow.postMessage(message, IFRAME_ORIGIN);\n }\n },\n };\n\n return (\n <IframeRegistryContext.Provider value={iframeRegistryValue}>\n {children}\n </IframeRegistryContext.Provider>\n );\n};\n","import {\n useCallback,\n useContext,\n useLayoutEffect,\n useRef,\n useState,\n} from \"preact/hooks\";\nimport { FieldProps } from \"./field\";\nimport { useSdk, useSession } from \"./session-provider\";\nimport { CardBrand, IframeEvent } from \"../../../shared/types\";\nimport { useChannel } from \"./channel-root\";\nimport { XenditFormAssociatedFocusTrap } from \"./core/form-ascociated-focus-trap\";\nimport { internal } from \"../internal\";\nimport { assert, formFieldId, formFieldName } from \"../utils\";\nimport { FunctionComponent } from \"preact\";\nimport { InternalSetFieldTouchedEvent } from \"../private-event-types\";\nimport { IframeRegistryContext } from \"./iframe-registry\";\n\n// read iframe data from environment variable\nassert(process.env.XENDIT_COMPONENTS_SECURE_IFRAME_URL);\nconst parsedIframeUrl = new URL(\n process.env.XENDIT_COMPONENTS_SECURE_IFRAME_URL,\n);\nconst IFRAME_SRC = parsedIframeUrl.toString();\nconst IFRAME_ORIGIN = parsedIframeUrl.origin;\n\nexport const IframeField: FunctionComponent<FieldProps> = (props) => {\n const { field, onChange } = props;\n\n const sdk = useSdk();\n\n const id = formFieldId(field);\n const name = formFieldName(field);\n const session = useSession();\n\n const iframeRef = useRef<HTMLIFrameElement>(null);\n const hiddenFieldRef = useRef<HTMLInputElement>(null);\n const [iframeEcdhPublicKey, setIframeEcdhPublicKey] = useState<\n string | undefined\n >();\n\n const [focusWithin, setFocusWithin] = useState(false);\n\n const [cardBrand, setCardBrand] = useState<CardBrand | null>(null);\n\n const { card } = useChannel() ?? {};\n\n const handleEventFromIframe = useCallback(\n (event: MessageEvent) => {\n if (!iframeRef.current) return;\n\n const expectedSource = iframeRef.current.contentWindow;\n\n if (event.source !== expectedSource) {\n // this is normal, we are not the target of this message\n return;\n }\n\n if (event.origin !== IFRAME_ORIGIN) {\n // this is not normal, something fishy is happening\n return;\n }\n\n const data = event.data as IframeEvent;\n switch (data.type) {\n case \"xendit-iframe-ready\": {\n setIframeEcdhPublicKey(data.ecdhPublicKey);\n break;\n }\n case \"xendit-iframe-change\": {\n if (!hiddenFieldRef.current) return;\n\n setCardBrand(data.cardBrand);\n\n const encrypted = data.encrypted;\n const encryptionVersion = 1;\n const resultData = encrypted.map((enc) => {\n if (data.empty) {\n return \"\";\n }\n\n const parts = [\n \"xendit-encrypted\",\n encryptionVersion,\n iframeEcdhPublicKey,\n enc.iv,\n enc.value,\n ];\n\n if (!data.valid && data.validationErrorCodes.length) {\n // append validation error if invalid - because the validation code can't validate an encrypted string\n parts.push(\n \"invalid\",\n btoa(data.validationErrorCodes[0].localeKey),\n );\n }\n\n return parts.join(\"-\");\n });\n\n if (resultData.length === 0) {\n break; // should never happen\n }\n\n // fields expecting a single value are normal strings, fields expecting multiple values are json arrays\n hiddenFieldRef.current.value =\n resultData.length > 1 ? JSON.stringify(resultData) : resultData[0];\n onChange?.();\n break;\n }\n case \"xendit-iframe-focus\": {\n setFocusWithin(true);\n break;\n }\n case \"xendit-iframe-blur\": {\n setFocusWithin(false);\n if (hiddenFieldRef.current?.value) {\n // mark field as touched if not empty\n hiddenFieldRef.current?.dispatchEvent(\n new InternalSetFieldTouchedEvent(),\n );\n }\n break;\n }\n case \"xendit-iframe-failed-init\": {\n console.error(\n `Iframe field for ${field.channel_property} failed to initialize securely`,\n );\n break;\n }\n }\n },\n [field.channel_property, iframeEcdhPublicKey, onChange],\n );\n\n const giveFocusToIframe = useCallback(() => {\n if (iframeRef.current?.contentWindow) {\n iframeRef.current.contentWindow.postMessage(\n { type: \"xendit-iframe-focus\" satisfies IframeEvent[\"type\"] },\n IFRAME_ORIGIN,\n );\n }\n }, []);\n\n useLayoutEffect(() => {\n window.addEventListener(\"message\", handleEventFromIframe);\n return () => {\n window.removeEventListener(\"message\", handleEventFromIframe);\n };\n }, [handleEventFromIframe]);\n\n const registry = useContext(IframeRegistryContext);\n useLayoutEffect(() => {\n registry?.registerIframe(name, iframeRef);\n return () => registry?.unregisterIframe(name);\n }, [name, registry]);\n\n const iframeUrl = new URL(IFRAME_SRC);\n iframeUrl.searchParams.set(\"input_type\", field.type.name);\n iframeUrl.searchParams.set(\"embedder\", window.location.origin);\n iframeUrl.searchParams.set(\"session_id\", session.payment_session_id);\n\n iframeUrl.searchParams.set(\"pk\", sdk[internal].sdkKey.publicKey);\n iframeUrl.searchParams.set(\"sig\", sdk[internal].sdkKey.signature);\n\n // Pass appearance options if provided\n if (sdk[internal].options.iframeFieldAppearance) {\n iframeUrl.searchParams.set(\n \"appearance\",\n JSON.stringify(sdk[internal].options.iframeFieldAppearance),\n );\n }\n\n const focusClass = focusWithin ? \"xendit-field-focus\" : \"\";\n\n return (\n <div\n className={`xendit-iframe-container xendit-form-field-inner ${focusClass}`}\n >\n <XenditFormAssociatedFocusTrap.tag\n id={id}\n onFocus={giveFocusToIframe}\n tabIndex={-1}\n />\n <input type=\"hidden\" name={name} defaultValue=\"\" ref={hiddenFieldRef} />\n <iframe\n src={iframeUrl.toString()}\n ref={iframeRef}\n sandbox=\"allow-scripts allow-same-origin\"\n />\n {field.type.name === \"credit_card_number\" && card && (\n <CardBrands\n cardsBrandList={card.brands}\n selectedCardBrand={cardBrand}\n />\n )}\n </div>\n );\n};\n\nconst CardBrands = ({\n cardsBrandList,\n selectedCardBrand,\n}: {\n cardsBrandList: { name: string; logo_url: string }[];\n selectedCardBrand: CardBrand | null;\n}) => {\n if (!cardsBrandList) return null;\n\n const cardBrandLogo = cardsBrandList.find(\n (b) => b.name === selectedCardBrand,\n )?.logo_url;\n\n return (\n <div className=\"xendit-card-brands-list\">\n {selectedCardBrand\n ? cardBrandLogo && (\n <img\n className={\"xendit-card-brand-logo\"}\n src={cardBrandLogo}\n alt={selectedCardBrand}\n />\n )\n : cardsBrandList.map(({ name, logo_url }) => {\n return (\n <img\n className={\"xendit-card-brand-logo\"}\n src={logo_url}\n alt={name}\n key={name}\n />\n );\n })}\n </div>\n );\n};\n","import { FieldProps } from \"./field\";\nimport { Dropdown, DropdownOption } from \"./core/dropdown\";\nimport { CountryCode, getCountryCallingCode } from \"libphonenumber-js/min\";\nimport {\n COUNTRIES_AS_DROPDOWN_OPTIONS,\n useOnCardCountryChange,\n} from \"./field-country\";\nimport parsePhoneNumberFromString, {\n getExampleNumber,\n PhoneNumber,\n} from \"libphonenumber-js\";\nimport examples from \"libphonenumber-js/mobile/examples\";\nimport { useSession } from \"./session-provider\";\nimport { formFieldId, formFieldName } from \"../utils\";\nimport { useCallback, useMemo, useRef, useState } from \"preact/hooks\";\nimport { FunctionComponent, TargetedEvent, TargetedFocusEvent } from \"preact\";\nimport { InternalSetFieldTouchedEvent } from \"../private-event-types\";\n\nexport const PhoneNumberField: FunctionComponent<FieldProps> = (props) => {\n const { field, onChange } = props;\n const id = formFieldId(field);\n const name = formFieldName(field);\n\n const session = useSession();\n\n const hiddenFieldRef = useRef<HTMLInputElement>(null);\n\n const [countryCode, setCountryCode] = useState(session.country);\n const countryCodeIndex = useMemo(() => {\n const index = COUNTRIES_WITH_DIAL_CODES_AS_DROPDOWN_OPTIONS.findIndex(\n (r) => r.value === countryCode,\n );\n if (index === -1) return 0;\n return index;\n }, [countryCode]);\n const country =\n COUNTRIES_WITH_DIAL_CODES_AS_DROPDOWN_OPTIONS[countryCodeIndex];\n\n const [localNumber, setLocalNumber] = useState(\"\");\n const inputRef = useRef<HTMLInputElement>(null);\n\n const formatPhoneNumber = useCallback(\n (country: DropdownOptionWithDial, localNumber: string) => {\n const phoneNumber = sanitizePhoneNumber(country, localNumber);\n if (phoneNumber) {\n // use parsed format if parsing was successful\n return phoneNumber.number;\n } else {\n // else just concat the dial code and local number\n return `+${country.dial}${localNumber}`;\n }\n },\n [],\n );\n\n const updateHiddenField = useCallback(\n (country: DropdownOptionWithDial, localNumber: string) => {\n if (hiddenFieldRef.current) {\n hiddenFieldRef.current.value = formatPhoneNumber(country, localNumber);\n }\n },\n [formatPhoneNumber],\n );\n\n function handleLocalChange(event: TargetedEvent<HTMLInputElement>): void {\n const nextLocal = (event.target as HTMLInputElement).value;\n setLocalNumber(nextLocal);\n updateHiddenField(country, nextLocal);\n onChange();\n }\n\n function handleCountryChange(option: DropdownOption): void {\n const nextCountry = option as DropdownOptionWithDial;\n setCountryCode(nextCountry.value as string);\n updateHiddenField(nextCountry, localNumber);\n onChange();\n }\n\n function handleBlur(event: TargetedFocusEvent<HTMLInputElement>): void {\n formatForUser();\n if (event.currentTarget?.value) {\n hiddenFieldRef.current?.dispatchEvent(new InternalSetFieldTouchedEvent());\n }\n }\n\n // when the user inputs a card number, update the phone number field to match\n useOnCardCountryChange((newCountry: CountryCode) => {\n const newOption = COUNTRIES_WITH_DIAL_CODES_AS_DROPDOWN_OPTIONS.find(\n (option) => option.value === newCountry,\n );\n if (newOption && newOption.value !== countryCode && !localNumber) {\n handleCountryChange(newOption);\n }\n });\n\n function getExampleLocalNumber() {\n return (\n getExampleNumber(country.value as CountryCode, examples)\n ?.formatInternational()\n ?.replace(\n `+${getCountryCallingCode(country.value as CountryCode)} `,\n \"\",\n ) || \"\"\n );\n }\n\n function formatForUser() {\n const phoneNumber = sanitizePhoneNumber(country, localNumber);\n if (phoneNumber) {\n const international = phoneNumber.formatInternational();\n // remove country dial code from displayed local number\n setLocalNumber(\n international.replace(\n `+${getCountryCallingCode(country.value as CountryCode)} `,\n \"\",\n ),\n );\n }\n }\n\n return (\n <div className=\"xendit-input-phone\">\n <Dropdown\n options={COUNTRIES_WITH_DIAL_CODES_AS_DROPDOWN_OPTIONS}\n selectedIndex={countryCodeIndex}\n onChange={handleCountryChange}\n fixedOverlayWidth={300}\n enableSearch\n className=\"xendit-form-field-inner\"\n />\n <input\n id={id}\n ref={inputRef}\n type=\"tel\"\n inputMode=\"tel\"\n placeholder={getExampleLocalNumber()}\n className=\"xendit-text-14 xendit-form-field-inner xendit-phone-number-input\"\n onBlur={handleBlur}\n onChange={handleLocalChange}\n value={localNumber}\n autoComplete=\"tel\"\n />\n <input type=\"hidden\" name={name} ref={hiddenFieldRef} />\n </div>\n );\n};\n\ntype DropdownOptionWithDial = DropdownOption & { dial: string };\nconst COUNTRIES_WITH_DIAL_CODES_AS_DROPDOWN_OPTIONS =\n COUNTRIES_AS_DROPDOWN_OPTIONS.map<DropdownOptionWithDial | null>(\n (country) => {\n const dial = getCountryCallingCode(country.value as CountryCode);\n if (!dial) return null;\n return {\n ...country,\n shortTitle: `+${dial}`,\n title: `${country.title} (+${dial})`,\n dial,\n };\n },\n ).filter((country): country is DropdownOptionWithDial => {\n return Boolean(country);\n });\n\nconst sanitizePhoneNumber = (\n country: DropdownOptionWithDial,\n phoneNumber: string,\n): PhoneNumber | null => {\n const parsed = parsePhoneNumberFromString(\n phoneNumber,\n country.value as CountryCode,\n );\n if (parsed && parsed.isPossible()) return parsed;\n\n return null;\n};\n","type TitleValuePair = {\n title: string;\n value: string;\n};\n\nfunction toTitleValuePair(nameValue: {\n name: string;\n value: string;\n}): TitleValuePair {\n return {\n title: nameValue.name,\n value: nameValue.value,\n };\n}\n\n// https://gist.github.com/mshafrir/2646763\nexport const PROVINCES_US: TitleValuePair[] = [\n {\n name: \"Alabama\",\n value: \"AL\",\n },\n {\n name: \"Alaska\",\n value: \"AK\",\n },\n {\n name: \"American Samoa\",\n value: \"AS\",\n },\n {\n name: \"Arizona\",\n value: \"AZ\",\n },\n {\n name: \"Arkansas\",\n value: \"AR\",\n },\n {\n name: \"California\",\n value: \"CA\",\n },\n {\n name: \"Colorado\",\n value: \"CO\",\n },\n {\n name: \"Connecticut\",\n value: \"CT\",\n },\n {\n name: \"Delaware\",\n value: \"DE\",\n },\n {\n name: \"District Of Columbia\",\n value: \"DC\",\n },\n {\n name: \"Federated States Of Micronesia\",\n value: \"FM\",\n },\n {\n name: \"Florida\",\n value: \"FL\",\n },\n {\n name: \"Georgia\",\n value: \"GA\",\n },\n {\n name: \"Guam\",\n value: \"GU\",\n },\n {\n name: \"Hawaii\",\n value: \"HI\",\n },\n {\n name: \"Idaho\",\n value: \"ID\",\n },\n {\n name: \"Illinois\",\n value: \"IL\",\n },\n {\n name: \"Indiana\",\n value: \"IN\",\n },\n {\n name: \"Iowa\",\n value: \"IA\",\n },\n {\n name: \"Kansas\",\n value: \"KS\",\n },\n {\n name: \"Kentucky\",\n value: \"KY\",\n },\n {\n name: \"Louisiana\",\n value: \"LA\",\n },\n {\n name: \"Maine\",\n value: \"ME\",\n },\n {\n name: \"Marshall Islands\",\n value: \"MH\",\n },\n {\n name: \"Maryland\",\n value: \"MD\",\n },\n {\n name: \"Massachusetts\",\n value: \"MA\",\n },\n {\n name: \"Michigan\",\n value: \"MI\",\n },\n {\n name: \"Minnesota\",\n value: \"MN\",\n },\n {\n name: \"Mississippi\",\n value: \"MS\",\n },\n {\n name: \"Missouri\",\n value: \"MO\",\n },\n {\n name: \"Montana\",\n value: \"MT\",\n },\n {\n name: \"Nebraska\",\n value: \"NE\",\n },\n {\n name: \"Nevada\",\n value: \"NV\",\n },\n {\n name: \"New Hampshire\",\n value: \"NH\",\n },\n {\n name: \"New Jersey\",\n value: \"NJ\",\n },\n {\n name: \"New Mexico\",\n value: \"NM\",\n },\n {\n name: \"New York\",\n value: \"NY\",\n },\n {\n name: \"North Carolina\",\n value: \"NC\",\n },\n {\n name: \"North Dakota\",\n value: \"ND\",\n },\n {\n name: \"Northern Mariana Islands\",\n value: \"MP\",\n },\n {\n name: \"Ohio\",\n value: \"OH\",\n },\n {\n name: \"Oklahoma\",\n value: \"OK\",\n },\n {\n name: \"Oregon\",\n value: \"OR\",\n },\n {\n name: \"Palau\",\n value: \"PW\",\n },\n {\n name: \"Pennsylvania\",\n value: \"PA\",\n },\n {\n name: \"Puerto Rico\",\n value: \"PR\",\n },\n {\n name: \"Rhode Island\",\n value: \"RI\",\n },\n {\n name: \"South Carolina\",\n value: \"SC\",\n },\n {\n name: \"South Dakota\",\n value: \"SD\",\n },\n {\n name: \"Tennessee\",\n value: \"TN\",\n },\n {\n name: \"Texas\",\n value: \"TX\",\n },\n {\n name: \"Utah\",\n value: \"UT\",\n },\n {\n name: \"Vermont\",\n value: \"VT\",\n },\n {\n name: \"Virgin Islands\",\n value: \"VI\",\n },\n {\n name: \"Virginia\",\n value: \"VA\",\n },\n {\n name: \"Washington\",\n value: \"WA\",\n },\n {\n name: \"West Virginia\",\n value: \"WV\",\n },\n {\n name: \"Wisconsin\",\n value: \"WI\",\n },\n {\n name: \"Wyoming\",\n value: \"WY\",\n },\n].map(toTitleValuePair);\n\n// https://gist.github.com/pbojinov/a87adf559d2f7e81d86ae67e7bd883c7\nexport const PROVINCES_CA: TitleValuePair[] = [\n {\n name: \"Alberta\",\n value: \"AB\",\n },\n {\n name: \"British Columbia\",\n value: \"BC\",\n },\n {\n name: \"Manitoba\",\n value: \"MB\",\n },\n {\n name: \"New Brunswick\",\n value: \"NB\",\n },\n {\n name: \"Newfoundland and Labrador\",\n value: \"NL\",\n },\n {\n name: \"Northwest Territories\",\n value: \"NT\",\n },\n {\n name: \"Nova Scotia\",\n value: \"NS\",\n },\n {\n name: \"Nunavut\",\n value: \"NU\",\n },\n {\n name: \"Ontario\",\n value: \"ON\",\n },\n {\n name: \"Prince Edward Island\",\n value: \"PE\",\n },\n {\n name: \"Quebec\",\n value: \"QC\",\n },\n {\n name: \"Saskatchewan\",\n value: \"SK\",\n },\n {\n name: \"Yukon Territory\",\n value: \"YT\",\n },\n].map(toTitleValuePair);\n\nexport const PROVINCES_GB: TitleValuePair[] = [\n { name: \"Avon\" },\n { name: \"Bedfordshire\" },\n { name: \"Berkshire\" },\n { name: \"Buckinghamshire\" },\n { name: \"Cambridgeshire\" },\n { name: \"Cheshire\" },\n { name: \"Cleveland\" },\n { name: \"Cornwall\" },\n { name: \"Cumbria\" },\n { name: \"Derbyshire\" },\n { name: \"Devon\" },\n { name: \"Dorset\" },\n { name: \"Durham\" },\n { name: \"East Sussex\" },\n { name: \"Essex\" },\n { name: \"Gloucestershire\" },\n { name: \"Hampshire\" },\n { name: \"Herefordshire\" },\n { name: \"Hertfordshire\" },\n { name: \"Isle of Wight\" },\n { name: \"Kent\" },\n { name: \"Lancashire\" },\n { name: \"Leicestershire\" },\n { name: \"Lincolnshire\" },\n { name: \"London\" },\n { name: \"Merseyside\" },\n { name: \"Norfolk\" },\n { name: \"Northamptonshire\" },\n { name: \"Northumberland\" },\n { name: \"North Yorkshire\" },\n { name: \"Nottinghamshire\" },\n { name: \"Oxfordshire\" },\n { name: \"Rutland\" },\n { name: \"Shropshire\" },\n { name: \"Somerset\" },\n { name: \"South Yorkshire\" },\n { name: \"Staffordshire\" },\n { name: \"Suffolk\" },\n { name: \"Surrey\" },\n { name: \"Tyne and Wear\" },\n { name: \"Warwickshire\" },\n { name: \"West Midlands\" },\n { name: \"West Sussex\" },\n { name: \"West Yorkshire\" },\n { name: \"Wiltshire\" },\n { name: \"Worcestershire\" },\n { name: \"Clwyd\" },\n { name: \"Dyfed\" },\n { name: \"Gwent\" },\n { name: \"Gwynedd\" },\n { name: \"Mid Glamorgan\" },\n { name: \"Powys\" },\n { name: \"South Glamorgan\" },\n { name: \"West Glamorgan\" },\n { name: \"Aberdeenshire\" },\n { name: \"Angus\" },\n { name: \"Argyll\" },\n { name: \"Ayrshire\" },\n { name: \"Banffshire\" },\n { name: \"Berwickshire\" },\n { name: \"Bute\" },\n { name: \"Caithness\" },\n { name: \"Clackmannanshire\" },\n { name: \"Dumfriesshire\" },\n { name: \"Dunbartonshire\" },\n { name: \"East Lothian\" },\n { name: \"Fife\" },\n { name: \"Inverness-shire\" },\n { name: \"Kincardineshire\" },\n { name: \"Kinross-shire\" },\n { name: \"Kirkcudbrightshire\" },\n { name: \"Lanarkshire\" },\n { name: \"Midlothian\" },\n { name: \"Moray\" },\n { name: \"Nairnshire\" },\n { name: \"Orkney\" },\n { name: \"Peeblesshire\" },\n { name: \"Perthshire\" },\n { name: \"Renfrewshire\" },\n { name: \"Ross-shire\" },\n { name: \"Roxburghshire\" },\n { name: \"Selkirkshire\" },\n { name: \"Shetland\" },\n { name: \"Stirlingshire\" },\n { name: \"Sutherland\" },\n { name: \"West Lothian\" },\n { name: \"Wigtownshire\" },\n { name: \"Antrim\" },\n { name: \"Armagh\" },\n { name: \"Down\" },\n { name: \"Fermanagh\" },\n { name: \"Londonderry\" },\n { name: \"Tyrone\" },\n].map((province) => ({ title: province.name, value: province.name }));\n","import { useRef, useCallback, useLayoutEffect } from \"preact/hooks\";\nimport { FieldProps } from \"./field\";\nimport { CountryCode } from \"libphonenumber-js\";\nimport { Dropdown, DropdownOption } from \"./core/dropdown\";\nimport { useSession } from \"./session-provider\";\nimport { PROVINCES_CA, PROVINCES_GB, PROVINCES_US } from \"../data/provinces\";\nimport {\n formFieldId,\n formFieldName,\n getValueFromChannelProperty,\n objectId,\n usePrevious,\n} from \"../utils\";\nimport { useChannel } from \"./channel-root\";\nimport { useChannelProperties } from \"./channel-form\";\nimport { ChannelFormField, ChannelProperties } from \"../backend-types/channel\";\nimport { BffSession } from \"../backend-types/session\";\nimport { FunctionComponent, TargetedEvent } from \"preact\";\nimport { InternalSetFieldTouchedEvent } from \"../private-event-types\";\n\nexport const ProvinceField: FunctionComponent<FieldProps> = (props) => {\n const { field, onChange } = props;\n const id = formFieldId(field);\n const name = formFieldName(field);\n\n const session = useSession();\n const allFields = useChannel()?.form;\n const channelProperties = useChannelProperties();\n\n const hiddenFieldRef = useRef<HTMLInputElement>(null);\n\n const clearValue = useCallback(() => {\n if (hiddenFieldRef.current) {\n hiddenFieldRef.current.value = \"\";\n }\n onChange();\n }, [onChange]);\n\n const onChangeDropdown = useCallback(\n (option: DropdownOption) => {\n if (hiddenFieldRef.current) {\n hiddenFieldRef.current.value = option.value;\n }\n onChange();\n hiddenFieldRef.current?.dispatchEvent(new InternalSetFieldTouchedEvent());\n },\n [onChange],\n );\n\n const onChangeInput = useCallback(\n (e: TargetedEvent<HTMLInputElement>) => {\n if (hiddenFieldRef.current) {\n hiddenFieldRef.current.value = (e.target as HTMLInputElement).value;\n }\n onChange();\n hiddenFieldRef.current?.dispatchEvent(new InternalSetFieldTouchedEvent());\n },\n [onChange],\n );\n\n // get the list of provinces for the chosen country\n const options = getProvinceList(\n getBestCountryForProvinceField(\n field,\n allFields ?? [],\n channelProperties ?? {},\n session,\n ),\n );\n\n // if the option list changes, clear the selection\n const previousOptions = usePrevious(options);\n useLayoutEffect(() => {\n if (previousOptions !== options) {\n clearValue();\n }\n }, [clearValue, options, previousOptions]);\n\n return (\n <>\n <input type=\"hidden\" name={name} defaultValue=\"\" ref={hiddenFieldRef} />\n {options ? (\n <Dropdown\n key={objectId(options)}\n id={id}\n options={options}\n onChange={onChangeDropdown}\n placeholder={field.placeholder}\n enableSearch\n className=\"xendit-form-field-inner\"\n />\n ) : (\n <input\n type=\"text\"\n id={id}\n onChange={onChangeInput}\n placeholder={field.placeholder}\n className={`xendit-form-field-inner xendit-text-14`}\n />\n )}\n </>\n );\n};\n\nfunction getProvinceList(country: CountryCode | null) {\n switch (country) {\n case \"US\":\n return PROVINCES_US;\n case \"CA\":\n return PROVINCES_CA;\n case \"GB\":\n return PROVINCES_GB;\n default:\n return null;\n }\n}\n\nfunction getBestCountryForProvinceField(\n thisField: ChannelFormField,\n allFields: ChannelFormField[],\n channelProperties: ChannelProperties,\n session: BffSession,\n): CountryCode {\n // country selection priority:\n // 1. previous form field\n // 3. session country\n if (allFields) {\n for (let i = 0; i < allFields.length; i++) {\n const otherField = allFields[i];\n if (i > 0 && otherField === thisField) {\n const previousField = allFields[i - 1];\n if (previousField.type.name === \"country\") {\n const country = getValueFromChannelProperty(\n previousField.channel_property,\n channelProperties,\n );\n if (country && typeof country === \"string\") {\n return country as CountryCode;\n }\n }\n }\n }\n }\n return session.country as CountryCode;\n}\n","import { ChannelFormField } from \"../backend-types/channel\";\nimport { FieldProps } from \"./field\";\nimport { formFieldId, formFieldName } from \"../utils\";\nimport { useRef } from \"preact/hooks\";\nimport { FunctionComponent, TargetedEvent, TargetedFocusEvent } from \"preact\";\nimport { InternalSetFieldTouchedEvent } from \"../private-event-types\";\n\nexport const TextField: FunctionComponent<FieldProps> = (props) => {\n const { field, onChange } = props;\n const id = formFieldId(field);\n const name = formFieldName(field);\n const inputRef = useRef<HTMLInputElement>(null);\n\n function handleChange(event: TargetedEvent<HTMLInputElement>): void {\n onChange();\n }\n\n function handleBlur(event: TargetedFocusEvent<HTMLInputElement>): void {\n if (event.currentTarget?.value) {\n inputRef.current?.dispatchEvent(new InternalSetFieldTouchedEvent());\n }\n }\n\n return (\n <input\n id={id}\n name={name}\n ref={inputRef}\n type=\"text\"\n placeholder={field.placeholder}\n className={`xendit-form-field-inner xendit-text-14`}\n onBlur={handleBlur}\n onChange={handleChange}\n minLength={isTextField(field) ? field.type.min_length : undefined}\n maxLength={isTextField(field) ? field.type.max_length : undefined}\n autoComplete={isTextField(field) ? field.type.autocomplete : undefined}\n />\n );\n};\n\nfunction isTextField(field: ChannelFormField): field is ChannelFormField & {\n type: { name: \"text\" };\n} {\n return field.type.name === \"text\";\n}\n","// affects number formatting (thousands separator, decimal separator)\n// defaults to \",\" for thousands and \".\" for decimal\nexport const CURRENCY_NUMBER_FORMAT_LOCALE: Record<string, string> = {\n IDR: \"id\",\n VND: \"vi\",\n BRL: \"pt-BR\",\n RUB: \"ru\",\n CZK: \"cs\",\n RON: \"ro\",\n UAH: \"uk\",\n CLP: \"es-CL\",\n COP: \"es-CO\",\n UYU: \"es-UY\",\n ARS: \"es-AR\",\n INR: \"hi-IN\",\n NPR: \"hi-IN\",\n LKR: \"hi-IN\",\n BDT: \"hi-IN\",\n};\n\n// Heavily modified from https://gist.github.com/ksafranski/2973986\n// checked against https://documentation.infiniteblue.com/platform/Currency_formats.htm\nexport const CURRENCY_SYMBOLS: Record<string, string> = {\n USD: \"US$\",\n CAD: \"CA$\",\n EUR: \"€\",\n AFN: \"؋\",\n ALL: \"Lek\",\n AMD: \"֏\",\n ARS: \"AR$\",\n AUD: \"AU$\",\n AZN: \"₼\",\n BAM: \"KM\",\n BDT: \"৳\",\n BIF: \"FBu\",\n BND: \"BN$\",\n BOB: \"Bs\",\n BRL: \"R$\",\n BWP: \"P\",\n BYN: \"Br\",\n BZD: \"BZ$\",\n CDF: \"FrCD\",\n CHF: \"CHF\",\n CLP: \"CL$\",\n CNY: \"CN¥\",\n COP: \"CO$\",\n CRC: \"₡\",\n CVE: \"CV$\",\n CZK: \"Kč\",\n DJF: \"Fdj\",\n DKK: \"kr\",\n DOP: \"RD$\",\n ERN: \"Nfk\",\n ETB: \"Br\",\n GBP: \"£\",\n GEL: \"₾\",\n GHS: \"GH₵\",\n GNF: \"FG\",\n GTQ: \"Q\",\n HKD: \"HK$\",\n HNL: \"L\",\n HUF: \"Ft\",\n IDR: \"Rp\",\n ILS: \"₪\",\n INR: \"₹\",\n IRR: \"IRR\",\n ISK: \"kr\",\n JMD: \"J$\",\n JPY: \"¥\",\n KES: \"Ksh\",\n KHR: \"៛\",\n KMF: \"FC\",\n KRW: \"₩\",\n KZT: \"₸\",\n LKR: \"SL Re\",\n MDL: \"lei\",\n MGA: \"MGA\",\n MKD: \"MKD\",\n MMK: \"K\",\n MOP: \"MOP$\",\n MUR: \"₨\",\n MXN: \"MX$\",\n MYR: \"RM\",\n MZN: \"MTn\",\n NAD: \"N$\",\n NGN: \"₦\",\n NIO: \"C$\",\n NOK: \"kr\",\n NPR: \"रु\",\n NZD: \"NZ$\",\n PAB: \"B/.\",\n PEN: \"S/.\",\n PHP: \"₱\",\n PKR: \"₨\",\n PLN: \"zł\",\n PYG: \"₲\",\n RON: \"RON\",\n RSD: \"RSD\",\n RUB: \"₽\",\n RWF: \"FR\",\n SDG: \"SDG\",\n SEK: \"kr\",\n SGD: \"S$\",\n SOS: \"Ssh\",\n THB: \"฿\",\n TOP: \"T$\",\n TRY: \"TL\",\n TTD: \"TT$\",\n TWD: \"NT$\",\n TZS: \"TSh\",\n UAH: \"₴\",\n UGX: \"USh\",\n UYU: \"$U\",\n UZS: \"сум\",\n VND: \"₫\",\n XAF: \"FCFA\",\n XOF: \"CFA\",\n ZAR: \"R\",\n ZMW: \"K\",\n ZWL: \"ZWL$\",\n};\n\n// $ is replaced with the currency symbol, 1 is replaced with the amount\n// default \"$1\"\nexport const CURRENCY_SYMBOL_POSITION: Record<string, string> = {\n ALL: \"1 $\",\n BAM: \"1 $\",\n BYN: \"1 $\",\n CZK: \"1 $\",\n DKK: \"1 $\",\n GEL: \"1 $\",\n HUF: \"1 $\",\n ISK: \"1 $\",\n IRR: \"1 $\",\n KHR: \"1$\",\n MDL: \"1 $\",\n MKD: \"1 $\",\n NOK: \"1 $\",\n PLN: \"1 $\",\n RON: \"1 $\",\n RSD: \"1 $\",\n RUB: \"1$\",\n SEK: \"1 $\",\n UZS: \"1 $\",\n VND: \"1$\",\n};\n\n// only list currencies that have more than 2 decimals\nexport const CURRENCY_SYMBOL_DECIMALS: Record<string, number> = {\n BHD: 3,\n JOD: 3,\n KWD: 3,\n LYD: 3,\n OMR: 3,\n TND: 3,\n};\n","import {\n CURRENCY_NUMBER_FORMAT_LOCALE,\n CURRENCY_SYMBOL_DECIMALS,\n CURRENCY_SYMBOL_POSITION,\n CURRENCY_SYMBOLS,\n} from \"./data/currencies\";\n\nexport function amountFormat(amount: number, currency: string): string {\n let str: string;\n\n const isNegative = amount < 0;\n\n // format as number with separators and 2 decimal places\n const locale = CURRENCY_NUMBER_FORMAT_LOCALE[currency] ?? \"en\";\n const decimals = CURRENCY_SYMBOL_DECIMALS[currency] ?? 2;\n\n str = new Intl.NumberFormat(locale, {\n style: \"decimal\",\n minimumFractionDigits: decimals,\n // Preserve fractional parts, if there are fractions where there shouldn't be that's\n // a backend problem and we should not suppress it.\n maximumFractionDigits: 20,\n }).format(Math.abs(amount));\n\n // remove trailing .00 or ,00 or .000 or ,000\n str = str.replace(/(\\.|,)000?$/, \"\");\n\n // add currency symbol\n if (CURRENCY_SYMBOLS[currency]) {\n const symbol = CURRENCY_SYMBOLS[currency] ?? currency;\n const positioning = CURRENCY_SYMBOL_POSITION[currency] ?? \"$1\";\n str = positioning.replace(\"$\", symbol).replace(\"1\", str);\n } else {\n str = currency + \" \" + str;\n }\n\n // add negative sign if needed\n if (isNegative) {\n str = \"-\" + str;\n }\n\n return str;\n}\n","import { FieldProps } from \"./field\";\nimport {\n assert,\n formFieldId,\n formFieldName,\n formHasFieldOfType,\n usePrevious,\n} from \"../utils\";\nimport {\n useCallback,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from \"preact/hooks\";\nimport { FunctionComponent } from \"preact\";\nimport { Dropdown, DropdownOption, DropdownSkeleton } from \"./core/dropdown\";\nimport { useChannel, useChannelComponentData } from \"./channel-root\";\nimport { amountFormat } from \"../amount-format\";\nimport { useSdk, useSession } from \"./session-provider\";\nimport { InternalSetFieldTouchedEvent } from \"../private-event-types\";\nimport { BffInstallmentPlan } from \"../backend-types/payment-options\";\n\nexport const FieldInstallmentPlan: FunctionComponent<FieldProps> = (props) => {\n const { field, onChange } = props;\n\n const { t } = useSdk();\n const session = useSession();\n\n const id = formFieldId(field);\n const name = formFieldName(field);\n const hiddenFieldRef = useRef<HTMLInputElement>(null);\n\n const channel = useChannel();\n assert(channel);\n const hasCardsField = useMemo(() => {\n return formHasFieldOfType(channel.form, \"credit_card_number\");\n }, [channel.form]);\n\n const paymentOptions = useChannelComponentData()?.paymentOptions;\n const installmentPlans = paymentOptions?.options?.installment_plans;\n\n const [selectedItemKey, setSelectedItemKey] = useState<string | null>(null);\n\n const dropdownItems = useMemo(() => {\n const arr =\n installmentPlans?.map<DropdownOption>((plan) => ({\n title: t(`installment_plan.pay_in_installments`, {\n installments: plan.terms,\n amount: amountFormat(plan.installment_amount, session.currency),\n }),\n subtitle: plan.interest_rate,\n value: planKey(plan),\n })) ?? [];\n\n if (hasCardsField) {\n // the option to pay in full is shown if there is a card number field, because card payments need a way to opt out of installments.\n arr.unshift({\n title: t(`installment_plan.pay_in_full`, {\n amount: amountFormat(session.amount, session.currency),\n }),\n value: \"\",\n });\n }\n\n return arr;\n }, [hasCardsField, installmentPlans, session.amount, session.currency, t]);\n\n let selectedItemIndex = dropdownItems?.findIndex((item) => {\n return item.value === selectedItemKey;\n });\n if (selectedItemIndex === -1) {\n selectedItemIndex = 0;\n }\n\n const clearSelectedItem = useCallback(() => {\n setSelectedItemKey(null);\n if (hiddenFieldRef.current) {\n hiddenFieldRef.current.value = \"\";\n }\n }, []);\n\n const handleChange = useCallback(\n (option: DropdownOption) => {\n if (hiddenFieldRef.current) {\n const newPlan = installmentPlans?.find(\n (plan) => planKey(plan) === option.value,\n );\n if (newPlan) {\n if (newPlan.code) {\n // with plan code\n hiddenFieldRef.current.value = JSON.stringify([\n newPlan.terms,\n newPlan.interval,\n newPlan.code,\n ]);\n } else {\n // without plan code\n hiddenFieldRef.current.value = JSON.stringify([\n newPlan.terms,\n newPlan.interval,\n ]);\n }\n } else {\n hiddenFieldRef.current.value = \"\";\n }\n hiddenFieldRef.current?.dispatchEvent(\n new InternalSetFieldTouchedEvent(),\n );\n }\n setSelectedItemKey(option.value);\n onChange();\n },\n [installmentPlans, onChange],\n );\n\n useLayoutEffect(() => {\n // first render only, force select first option\n if (dropdownItems.length) handleChange(dropdownItems[0]);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const prevItems = usePrevious(dropdownItems);\n useLayoutEffect(() => {\n // if options change, and the selected code no longer exists, clear the field\n if (\n dropdownItems !== prevItems &&\n !installmentPlans?.some((plan) => planKey(plan) === selectedItemKey)\n ) {\n if (dropdownItems.length) {\n handleChange(dropdownItems[0]);\n } else {\n clearSelectedItem();\n }\n }\n }, [\n clearSelectedItem,\n dropdownItems,\n handleChange,\n installmentPlans,\n prevItems,\n selectedItemKey,\n ]);\n\n return (\n <>\n {paymentOptions ? (\n <Dropdown\n id={id}\n placeholder={field.placeholder}\n onChange={handleChange}\n options={dropdownItems}\n selectedIndex={selectedItemIndex}\n className=\"xendit-form-field-inner\"\n />\n ) : (\n <DropdownSkeleton id={id} className=\"xendit-form-field-inner\" />\n )}\n <input type=\"hidden\" name={name} ref={hiddenFieldRef} />\n </>\n );\n};\n\nfunction planKey(plan: BffInstallmentPlan) {\n return `${plan.terms}_${plan.interval}_${plan.code ?? \"\"}`;\n}\n","import { FunctionComponent } from \"preact\";\nimport { ChannelFormField } from \"../backend-types/channel\";\nimport { CountryField } from \"./field-country\";\nimport { DropdownField } from \"./field-dropdown\";\nimport { IframeField } from \"./field-iframe\";\nimport { PhoneNumberField } from \"./field-phone-number\";\nimport { ProvinceField } from \"./field-province\";\nimport { TextField } from \"./field-text\";\nimport { FieldInstallmentPlan } from \"./field-installment-plan\";\n\nexport interface FieldProps {\n field: ChannelFormField;\n onChange: () => void;\n className?: string;\n}\n\nconst Field: FunctionComponent<FieldProps> = (props) => {\n const { field, className } = props;\n\n function renderInner() {\n switch (field.type.name) {\n case \"credit_card_number\":\n case \"credit_card_expiry\":\n case \"credit_card_cvn\":\n return <IframeField {...props} />;\n case \"phone_number\":\n return <PhoneNumberField {...props} />;\n case \"text\":\n case \"email\":\n case \"postal_code\":\n return <TextField {...props} />;\n case \"dropdown\":\n return <DropdownField {...props} />;\n case \"installment_plan\":\n return <FieldInstallmentPlan {...props} />;\n case \"country\":\n return <CountryField {...props} />;\n case \"province\":\n return <ProvinceField {...props} />;\n }\n\n field.type satisfies never;\n throw new Error(\n `Unsupported field type: ${(field as ChannelFormField).type.name}`,\n );\n }\n\n return (\n <div\n className={`${className} xendit-channel-form-field xendit-form-field-span-${field.span}`}\n >\n {renderInner()}\n </div>\n );\n};\n\nexport default Field;\n","import { ChannelFormField } from \"./backend-types/channel\";\nimport en from \"./locale/en.json\";\nimport id from \"./locale/id.json\";\nimport th from \"./locale/th.json\";\nimport vi from \"./locale/vi.json\";\n\nconst localeMap: {\n en: typeof en.session;\n [locale: string]: Partial<typeof en.session>;\n} = {\n en: en.session,\n id: id.session,\n th: th.session,\n vi: vi.session,\n};\n\ntype InterpolationOptions = Record<string, string | number>;\n\n/**\n * Localization interface.\n *\n * ```\n * t(\"key\") -> Localize \"key\", falling back to \"key\"\n * t(\"key\", \"fallback\") -> Localize \"key\", falling back to \"fallback\"\n * t(\"key\", { var: value }) -> Localize \"key\" with interpolation, falling back to \"key\"\n * t(\"key\", \"fallback\", { var: value }) -> Localize \"key\" with interpolation, falling back to \"fallback\"\n * ```\n */\nexport interface TFunction {\n (key: keyof typeof en.session): string;\n (key: keyof typeof en.session, fallback: string): string;\n (key: keyof typeof en.session, options: InterpolationOptions): string;\n (\n key: keyof typeof en.session,\n fallback: string,\n options: InterpolationOptions,\n ): string;\n}\n\n/**\n * Generate a TFunction for a locale.\n */\nexport function createTFunction(locale: string): TFunction {\n const localeData = localeMap[locale];\n const tFn: TFunction = function (...args: unknown[]) {\n let key: keyof typeof en.session;\n let fallback: string | undefined;\n let options: InterpolationOptions = {};\n\n switch (args.length) {\n case 1:\n key = args[0] as keyof typeof en.session;\n break;\n case 2:\n if (typeof args[1] === \"string\") {\n key = args[0] as keyof typeof en.session;\n fallback = args[1];\n } else {\n key = args[0] as keyof typeof en.session;\n options = args[1] as InterpolationOptions;\n }\n break;\n case 3:\n key = args[0] as keyof typeof en.session;\n fallback = args[1] as string;\n options = args[2] as InterpolationOptions;\n break;\n default:\n throw new Error(\"Invalid arguments for t function\");\n }\n\n let template = localeData?.[key];\n if (template === undefined && fallback !== undefined) {\n template = fallback;\n }\n\n if (template) {\n return template.replace(/\\{\\{(\\w+)\\}\\}/g, (_, varName: string) => {\n return options[varName] ? String(options[varName]) : \"\";\n });\n } else {\n console.warn(`Missing localization for key: ${key} in locale: ${locale}`);\n return key;\n }\n };\n return tFn;\n}\n\n// An encapsulated localizable string\nexport type LocaleKey = {\n localeKey: keyof typeof en.session;\n};\n\n// An encapsulated already-localized string\nexport type LocalizedString = {\n value: string;\n};\n\n// Type guard function to check if errorCode is LocaleKey\nexport const isLocaleKey = (errorCode: unknown): errorCode is LocaleKey => {\n return (\n typeof errorCode === \"object\" &&\n errorCode !== null &&\n \"localeKey\" in errorCode\n );\n};\n\n// Get localized error message\nexport const getLocalizedErrorMessage = (\n t: TFunction,\n errorCode: LocaleKey | LocalizedString,\n field: ChannelFormField,\n): string | null => {\n if (!errorCode) return null;\n\n if (!isLocaleKey(errorCode)) {\n return errorCode.value;\n }\n\n // Get localized message with field name interpolation using i18n key directly\n return t(errorCode.localeKey, { field: field.label });\n};\n","import {\n BffChannel,\n ChannelFormField,\n ChannelProperties,\n ChannelPropertyPrimative,\n} from \"./backend-types/channel\";\nimport parsePhoneNumberFromString from \"libphonenumber-js/min\";\nimport { filterFormFields } from \"./components/channel-form\";\nimport { BffSessionType } from \"./backend-types/session\";\nimport { LocaleKey, LocalizedString } from \"./localization\";\nimport { ChannelComponentData } from \"./public-sdk\";\nimport { parseEncryptedFieldValue } from \"./utils\";\n\nexport type ValidationResult = {\n errorCode: LocaleKey | LocalizedString | undefined;\n};\n\nexport function validateEncryptedCardField(\n value: string,\n): LocaleKey | undefined {\n const parsed = parseEncryptedFieldValue(value);\n if (parsed.valid) {\n return undefined;\n }\n if (parsed.validationError) {\n return { localeKey: parsed.validationError as LocaleKey[\"localeKey\"] };\n }\n // unreachable\n throw new Error(\n \"Unexpected value in encrypted field, this is a bug, please contact support.\",\n );\n}\n\nexport const validateEmail = (value: string): LocaleKey | undefined => {\n // Allows letters, numbers, dots, underscores, hyphens before the @\n // Domain must be letters, numbers, hyphens (no leading/trailing hyphen)\n // TLD must be at least 2 letters\n const emailRegex =\n /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9-]+(\\.[a-zA-Z0-9-]+)*\\.[A-Za-z]{2,}$/;\n\n if (!emailRegex.test(value)) {\n return {\n localeKey: \"validation.generic_invalid\",\n };\n }\n};\n\nexport const validatePhoneNumber = (value: string): LocaleKey | undefined => {\n const phone = parsePhoneNumberFromString(value);\n if (!phone || !phone.isValid()) {\n return {\n localeKey: \"validation.generic_invalid\",\n };\n }\n};\n\nexport const validatePostalCode = (value: string): LocaleKey | undefined => {\n // Basic validation: must contain only letters, numbers, spaces, or hyphens\n if (!/^(?![-\\s]+)[A-Za-z0-9\\s-]+$/.test(value)) {\n return {\n localeKey: \"validation.generic_invalid\",\n };\n }\n};\n\nexport const validateText = (\n input: ChannelFormField & {\n type: { name: \"text\" };\n },\n value: string,\n): LocaleKey | LocalizedString | undefined => {\n if (Array.isArray(input.type.regex_validators)) {\n for (const pattern of input.type.regex_validators) {\n const regex = new RegExp(sanitizeRegex(pattern.regex));\n if (!regex.test(value)) {\n return {\n value: pattern.message,\n };\n }\n }\n }\n\n if (\n input.type.min_length !== undefined &&\n value.length < input.type.min_length\n ) {\n return { localeKey: \"validation.text_too_short\" };\n } else if (value.length > input.type.max_length) {\n return { localeKey: \"validation.text_too_long\" };\n }\n};\n\nfunction sanitizeRegex(pattern: string): string {\n // Remove leading and trailing slashes if present\n if (pattern.startsWith(\"/\") && pattern.endsWith(\"/\")) {\n return pattern.slice(1, -1);\n }\n return pattern;\n}\n\nexport function validate(\n input: ChannelFormField,\n value: string,\n): LocaleKey | LocalizedString | undefined {\n if (value.length === 0) {\n if (input.required) {\n return { localeKey: \"validation.required\" };\n } else {\n // ok, empty string and not required\n return undefined;\n }\n }\n\n switch (input.type.name) {\n case \"credit_card_number\":\n case \"credit_card_expiry\":\n case \"credit_card_cvn\": {\n return validateEncryptedCardField(value);\n }\n case \"phone_number\":\n return validatePhoneNumber(value);\n case \"email\":\n return validateEmail(value);\n case \"postal_code\":\n return validatePostalCode(value);\n case \"text\": {\n return validateText(\n input as ChannelFormField & {\n type: { name: \"text\" };\n },\n value,\n );\n }\n case \"country\":\n case \"province\":\n case \"installment_plan\":\n case \"dropdown\": {\n // no validation required for now\n return undefined;\n }\n\n default: {\n input.type satisfies never;\n throw new Error(\n `Unsupported input type: ${(input as ChannelFormField).type.name}; this is a bug, please contact support.`,\n );\n }\n }\n}\n\nexport function channelPropertiesAreValid(\n sessionType: BffSessionType,\n channel: BffChannel,\n channelProperties: ChannelProperties | null,\n channelComponentData: ChannelComponentData | null,\n): boolean {\n if (!channelProperties) channelProperties = {};\n\n for (const field of filterFormFields(\n sessionType,\n channel.form,\n channelProperties,\n channelComponentData,\n )) {\n if (channelPropertyFieldValidate(field, channelProperties)) {\n return false;\n }\n }\n\n return true;\n}\n\n// Return a validation error message if the channel property is invalid\nexport function channelPropertyFieldValidate(\n field: ChannelFormField,\n channelProperties: ChannelProperties,\n) {\n const channelPropertyKeys = Array.isArray(field.channel_property)\n ? field.channel_property\n : [field.channel_property];\n for (const key of channelPropertyKeys) {\n let value = getChannelPropertyValue(channelProperties, key);\n if (value === undefined) {\n value = \"\";\n }\n if (typeof value !== \"string\") {\n // validation for non-string values not supported\n continue;\n }\n const error = validate(field, value);\n if (error) {\n return error;\n }\n }\n}\n\nexport function getChannelPropertyValue(\n channelProperties: ChannelProperties,\n key: string,\n): ChannelPropertyPrimative | ChannelPropertyPrimative[] | undefined {\n const parts = key.split(\".\");\n const value = channelProperties[parts[0]];\n if (value === undefined) {\n return undefined;\n }\n if (typeof value !== \"object\" || Array.isArray(value)) {\n if (parts.length !== 1) {\n throw new Error(\n `Attempted to read channel property \"${key}\" expecting an object but found a primitive value; this is a bug, please contact support.`,\n );\n }\n return value;\n } else {\n return getChannelPropertyValue(value, parts.slice(1).join(\".\"));\n }\n}\n","import { ComponentChildren, createContext, FunctionComponent } from \"preact\";\nimport { useContext, useLayoutEffect, useRef, useState } from \"preact/hooks\";\nimport { Scenarios } from \"../data/simulation-scenarios\";\nimport { Dropdown } from \"./core/dropdown\";\nimport { useSdk } from \"./session-provider\";\nimport { assert } from \"../utils\";\n\ninterface Props {\n scenarios: Scenarios;\n onSelect: (scenarioName: string) => void;\n children: ComponentChildren;\n}\n\nconst FormSimulationHelperContext = createContext<{\n open: boolean;\n setOpen: (open: boolean) => void;\n scenarios: Scenarios;\n onSelect: (scenarioName: string) => void;\n} | null>(null);\n\nexport const FormSimulationHelper: FunctionComponent<Props> = ({\n scenarios,\n onSelect,\n children,\n}) => {\n const [open, setOpen] = useState(false);\n const rootRef = useRef<HTMLDivElement>(null);\n\n useLayoutEffect(() => {\n if (!open) return;\n const onMouseDown = (e: MouseEvent) => {\n const root = rootRef.current;\n if (!root) return;\n if (!root.contains(e.target as Node)) setOpen(false);\n };\n document.addEventListener(\"mousedown\", onMouseDown);\n return () => document.removeEventListener(\"mousedown\", onMouseDown);\n }, [open]);\n\n return (\n <div ref={rootRef}>\n <FormSimulationHelperContext.Provider\n value={{ open, setOpen, scenarios, onSelect }}\n >\n {children}\n </FormSimulationHelperContext.Provider>\n </div>\n );\n};\n\nexport const FormSimulationRoot: FunctionComponent<{\n children: ComponentChildren;\n}> = ({ children }) => {\n return <div className=\"xendit-form-simulation-root\">{children}</div>;\n};\n\nexport const FormSimulationTrigger: FunctionComponent<{\n children: ComponentChildren;\n}> = ({ children }) => {\n const { open, setOpen } = useContext(FormSimulationHelperContext) || {};\n\n return (\n <button\n type=\"button\"\n className=\"xendit-form-simulation-trigger\"\n onClick={() => setOpen?.(!open)}\n >\n {children}\n </button>\n );\n};\n\nexport const FormSimulationHelperPopover: FunctionComponent = () => {\n const simulateHelper = useContext(FormSimulationHelperContext);\n assert(simulateHelper);\n const { open, setOpen, scenarios, onSelect } = simulateHelper;\n const { t } = useSdk();\n\n if (!open || !scenarios) {\n return null;\n }\n\n return (\n <div className=\"xendit-form-simulation-popover\">\n <div className=\"xendit-text-12 xendit-text-semibold\">\n {t(\"simulation.simulate_test_scenario\")}\n </div>\n <Dropdown\n onChange={(option) => {\n onSelect?.(option.value);\n setOpen?.(false);\n }}\n placeholder={t(\"simulation.select_scenario\")}\n options={scenarios.scenarios.map((scenario) => ({\n title: scenario.description,\n value: scenario.name,\n leadingAsset: (\n <img src={scenario.imageUrl} className=\"xendit-channel-logo\" />\n ),\n }))}\n />\n {scenarios?.docsLink ? (\n <div className=\"xendit-text-14\">\n {t(\"simulation.want_to_test_all_scenarios\")}{\" \"}\n <a\n href={scenarios.docsLink}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"xendit-text-link\"\n >\n {t(\"simulation.see_all_scenarios\")}\n </a>\n </div>\n ) : null}\n </div>\n );\n};\n","import { useState, useLayoutEffect, useRef, useContext } from \"preact/hooks\";\nimport { ChannelFormField, ChannelProperties } from \"../backend-types/channel\";\nimport Field from \"./field\";\nimport classNames from \"classnames\";\nimport { formFieldId, formFieldName } from \"../utils\";\nimport { useSdk } from \"./session-provider\";\nimport { getLocalizedErrorMessage } from \"../localization\";\nimport { channelPropertyFieldValidate } from \"../validation\";\nimport { InternalSetFieldTouchedEvent } from \"../private-event-types\";\nimport { Scenarios } from \"../data/simulation-scenarios\";\nimport {\n FormSimulationHelper,\n FormSimulationHelperPopover,\n FormSimulationRoot,\n FormSimulationTrigger,\n} from \"./form-simulation-helper\";\nimport {\n IframeRegistryContext,\n IframeRegistryProvider,\n} from \"./iframe-registry\";\nimport { FunctionComponent } from \"preact\";\n\nconst CSS_CLASSES = {\n BOTTOM_LEFT_0: \"field-radius-bl-0\",\n BOTTOM_RIGHT_0: \"field-radius-br-0\",\n TOP_LEFT_0: \"field-radius-tl-0\",\n TOP_RIGHT_0: \"field-radius-tr-0\",\n COLLAPSE_RIGHT: \"field-collapse-r\",\n COLLAPSE_LEFT: \"field-collapse-l\",\n COLLAPSE_TOP: \"field-collapse-t\",\n COLLAPSE_BOTTOM: \"field-collapse-b\",\n} as const;\n\ninterface Props {\n fieldGroup: ChannelFormField[];\n groupIndex: number;\n handleFieldChanged: () => void;\n channelProperties: ChannelProperties | null;\n simulationScenarios?: Scenarios | null;\n}\n\nconst FieldGroup = ({\n fieldGroup,\n groupIndex,\n handleFieldChanged,\n channelProperties,\n simulationScenarios,\n}: Props) => {\n const { t } = useSdk();\n\n const groupContainerRef = useRef<HTMLDivElement>(null);\n\n const [touchedFields, setTouchedFields] = useState<Record<string, boolean>>(\n {},\n );\n\n const fieldGroupSpans = fieldGroup.map((f) => f.span);\n const groupRowCount = Math.ceil(\n fieldGroup.reduce((agg, field) => agg + field.span, 0) / 2,\n );\n\n const calculateFieldPosition = (index: number) => {\n const fieldPositionBySpan = fieldGroupSpans\n .slice(0, index)\n .reduce((agg, span) => agg + span, 0);\n const fieldRow = index === 0 ? 0 : Math.floor(fieldPositionBySpan / 2);\n const fieldColumn = fieldPositionBySpan % 2;\n const isLastRow = fieldRow === groupRowCount - 1;\n\n return { fieldPositionBySpan, fieldRow, fieldColumn, isLastRow };\n };\n\n const getFieldClassNames = (\n field: ChannelFormField,\n index: number,\n position: ReturnType<typeof calculateFieldPosition>,\n ) => {\n const { fieldPositionBySpan, fieldRow, fieldColumn, isLastRow } = position;\n return classNames({\n [CSS_CLASSES.BOTTOM_LEFT_0]:\n groupRowCount > fieldRow + 1 || fieldPositionBySpan % 2 === 1,\n [CSS_CLASSES.BOTTOM_RIGHT_0]: !!fieldGroupSpans[index + 1],\n [CSS_CLASSES.TOP_LEFT_0]: index > 0,\n [CSS_CLASSES.TOP_RIGHT_0]:\n !(fieldRow === 0 && fieldColumn === 1) &&\n !(fieldRow === 0 && fieldColumn === 0 && field.span === 2),\n [CSS_CLASSES.COLLAPSE_RIGHT]: field.span === 1 && fieldColumn === 0,\n [CSS_CLASSES.COLLAPSE_LEFT]: field.span === 1 && fieldColumn === 1,\n [CSS_CLASSES.COLLAPSE_TOP]: fieldPositionBySpan >= 2,\n [CSS_CLASSES.COLLAPSE_BOTTOM]: !isLastRow,\n });\n };\n\n useLayoutEffect(() => {\n const containerElement = groupContainerRef.current;\n if (!containerElement) return;\n function listener(event: InternalSetFieldTouchedEvent) {\n // when a field is touched, add it to touched state\n const name = (event.target as HTMLInputElement).name;\n setTouchedFields((prev) => ({\n ...prev,\n [name]: true,\n }));\n }\n containerElement.addEventListener(\n InternalSetFieldTouchedEvent.type,\n listener,\n );\n return () => {\n containerElement.removeEventListener(\n InternalSetFieldTouchedEvent.type,\n listener,\n );\n };\n }, []);\n\n const renderError = () => {\n for (const field of fieldGroup) {\n if (!touchedFields[formFieldName(field)]) {\n // field not touched yet, skip validation\n // (this prevents showing validation errors too eagerly while the user is typing)\n continue;\n }\n\n const err = channelPropertyFieldValidate(field, channelProperties ?? {});\n if (!err) {\n // ok, no error\n continue;\n }\n\n // render first error and ignore the rest\n return (\n <span className=\"xendit-error-message xendit-text-12\">\n {getLocalizedErrorMessage(t, err, field)}\n </span>\n );\n }\n return null;\n };\n\n const error = renderError();\n\n return (\n <IframeRegistryProvider>\n <div className=\"xendit-channel-form-field-group\">\n <div className=\"xendit-channel-form-field-group-label-container\">\n <label\n htmlFor={formFieldId(fieldGroup[0])}\n className=\"xendit-text-14\"\n >\n {fieldGroup[0].group_label ?? fieldGroup[0].label ?? \"\"}\n </label>\n {simulationScenarios ? (\n <FormSimulationHelperWrapper\n simulationScenarios={simulationScenarios}\n fieldGroup={fieldGroup}\n />\n ) : null}\n </div>\n <div\n ref={groupContainerRef}\n key={groupIndex}\n className={`xendit-form-field-group ${error ? \"invalid\" : \"\"}`}\n >\n {fieldGroup.map((field, index) => {\n const position = calculateFieldPosition(index);\n const className = getFieldClassNames(field, index, position);\n\n return (\n <Field\n className={className}\n key={index}\n field={field}\n onChange={handleFieldChanged}\n />\n );\n })}\n </div>\n {error}\n </div>\n </IframeRegistryProvider>\n );\n};\n\nconst FormSimulationHelperWrapper: FunctionComponent<{\n simulationScenarios: Scenarios;\n fieldGroup: ChannelFormField[];\n}> = ({ simulationScenarios, fieldGroup }) => {\n const iframeRegistry = useContext(IframeRegistryContext);\n const { t } = useSdk();\n\n return (\n <FormSimulationHelper\n scenarios={simulationScenarios}\n onSelect={(scenarioName) => {\n const scenario = simulationScenarios.scenarios.find(\n (s) => s.name === scenarioName,\n );\n if (!scenario?.values) return;\n\n // when a scenario is selected, set the values of the scenario to the fields\n for (const [fieldName, value] of Object.entries(scenario.values)) {\n const field = fieldGroup.find((f) => formFieldName(f) === fieldName);\n if (field) {\n if (\n field.type.name === \"credit_card_number\" ||\n field.type.name === \"credit_card_expiry\" ||\n field.type.name === \"credit_card_cvn\"\n ) {\n iframeRegistry?.postMessageToIframe(fieldName, {\n type: \"xendit-iframe-populate-for-simulation\",\n scenario: value,\n });\n }\n\n // TODO handle non-iframe fields if needed\n }\n }\n }}\n >\n <FormSimulationRoot>\n <FormSimulationTrigger>\n <div className=\"xendit-text-12 xendit-text-semibold xendit-text-link\">\n {t(\"simulation.simulate_scenario\")}\n </div>\n </FormSimulationTrigger>\n <FormSimulationHelperPopover />\n </FormSimulationRoot>\n </FormSimulationHelper>\n );\n};\n\nexport default FieldGroup;\n","import { IframePopulateForSimulationEvent } from \"../../../shared/types\";\n\nexport type Scenarios = {\n scenarios: {\n name: string;\n imageUrl?: string;\n description: string;\n values?: {\n [key: string]: string | IframePopulateForSimulationEvent[\"type\"];\n };\n }[];\n docsLink?: string;\n};\n\nexport const CARDS_SCENARIOS: Scenarios = {\n scenarios: [\n {\n imageUrl: \"https://assets.xendit.co/payment-session/logos/VISA.svg\",\n description: \"3DS Challenge\",\n name: \"3_ds_challenge_authentication_is_successful_if_otp_is_correct_visa\",\n values: {\n \"card_details.card_number\":\n \"3_ds_challenge_authentication_is_successful_if_otp_is_correct_visa\",\n \"card_details.expiry_month__card_details.expiry_year\":\n \"3_ds_challenge_authentication_is_successful_if_otp_is_correct_visa\",\n \"card_details.cvn\":\n \"3_ds_challenge_authentication_is_successful_if_otp_is_correct_visa\",\n },\n },\n {\n imageUrl: \"https://assets.xendit.co/payment-session/logos/VISA.svg\",\n description: \"3DS Frictionless, success\",\n name: \"3_ds_frictionless_authentication_is_successful_visa\",\n values: {\n \"card_details.card_number\":\n \"3_ds_frictionless_authentication_is_successful_visa\",\n \"card_details.expiry_month__card_details.expiry_year\":\n \"3_ds_frictionless_authentication_is_successful_visa\",\n \"card_details.cvn\":\n \"3_ds_frictionless_authentication_is_successful_visa\",\n },\n },\n {\n imageUrl: \"https://assets.xendit.co/payment-session/logos/MASTERCARD.svg\",\n description: \"3DS Challenge\",\n name: \"3_ds_challenge_authentication_is_successful_if_otp_is_correct_mastercard\",\n values: {\n \"card_details.card_number\":\n \"3_ds_challenge_authentication_is_successful_if_otp_is_correct_mastercard\",\n \"card_details.expiry_month__card_details.expiry_year\":\n \"3_ds_challenge_authentication_is_successful_if_otp_is_correct_mastercard\",\n \"card_details.cvn\":\n \"3_ds_challenge_authentication_is_successful_if_otp_is_correct_mastercard\",\n },\n },\n {\n imageUrl: \"https://assets.xendit.co/payment-session/logos/MASTERCARD.svg\",\n description: \"3DS Frictionless, success\",\n name: \"3_ds_frictionless_authentication_is_successful_mastercard\",\n values: {\n \"card_details.card_number\":\n \"3_ds_frictionless_authentication_is_successful_mastercard\",\n \"card_details.expiry_month__card_details.expiry_year\":\n \"3_ds_frictionless_authentication_is_successful_mastercard\",\n \"card_details.cvn\":\n \"3_ds_frictionless_authentication_is_successful_mastercard\",\n },\n },\n // // Doesn't work\n // {\n // imageUrl: \"https://assets.xendit.co/payment-session/logos/VISA.svg\",\n // description: \"3DS Challenge, with list of simulated options.\",\n // name: \"3_ds_challenge_with_list_of_simulated_options_visa\",\n // values: {\n // \"card_details.card_number\":\n // \"3_ds_challenge_with_list_of_simulated_options_visa\",\n // \"card_details.expiry_month__card_details.expiry_year\":\n // \"3_ds_challenge_with_list_of_simulated_options_visa\",\n // \"card_details.cvn\":\n // \"3_ds_challenge_with_list_of_simulated_options_visa\",\n // },\n // },\n {\n imageUrl: \"https://assets.xendit.co/payment-session/logos/VISA.svg\",\n description: \"3DS Frictionless, success\",\n name: \"3_ds_frictionless_authentication_is_successful_visa2\",\n values: {\n \"card_details.card_number\":\n \"3_ds_frictionless_authentication_is_successful_visa2\",\n \"card_details.expiry_month__card_details.expiry_year\":\n \"3_ds_frictionless_authentication_is_successful_visa2\",\n \"card_details.cvn\":\n \"3_ds_frictionless_authentication_is_successful_visa2\",\n },\n },\n // // doesn't work\n // {\n // imageUrl: \"https://assets.xendit.co/payment-session/logos/MASTERCARD.svg\",\n // description: \"3DS Challenge, with list of simulated options.\",\n // name: \"3_ds_challenge_with_list_of_simulated_options_mastercard\",\n // values: {\n // \"card_details.card_number\":\n // \"3_ds_challenge_with_list_of_simulated_options_mastercard\",\n // \"card_details.expiry_month__card_details.expiry_year\":\n // \"3_ds_challenge_with_list_of_simulated_options_mastercard\",\n // \"card_details.cvn\":\n // \"3_ds_challenge_with_list_of_simulated_options_mastercard\",\n // },\n // },\n {\n imageUrl: \"https://assets.xendit.co/payment-session/logos/MASTERCARD.svg\",\n description: \"3DS Frictionless, success\",\n name: \"3_ds_frictionless_authentication_is_successful_mastercard2\",\n values: {\n \"card_details.card_number\":\n \"3_ds_frictionless_authentication_is_successful_mastercard2\",\n \"card_details.expiry_month__card_details.expiry_year\":\n \"3_ds_frictionless_authentication_is_successful_mastercard2\",\n \"card_details.cvn\":\n \"3_ds_frictionless_authentication_is_successful_mastercard2\",\n },\n },\n // // These are only applicable to TH\n // {\n // imageUrl: \"https://assets.xendit.co/payment-session/logos/VISA.svg\",\n // description:\n // \"3DS Challenge, authentication is successful if OTP is correct. For frictionless flow, use amount < THB 20.\",\n // name: \"3_ds_challenge_authentication_is_successful_if_otp_is_correct_for_frictionless_flow_use_amount_thb_20_visa\",\n // values: {\n // \"card_details.card_number\":\n // \"3_ds_challenge_authentication_is_successful_if_otp_is_correct_for_frictionless_flow_use_amount_thb_20_visa\",\n // \"card_details.expiry_month__card_details.expiry_year\":\n // \"3_ds_challenge_authentication_is_successful_if_otp_is_correct_for_frictionless_flow_use_amount_thb_20_visa\",\n // \"card_details.cvn\":\n // \"3_ds_challenge_authentication_is_successful_if_otp_is_correct_for_frictionless_flow_use_amount_thb_20_visa\",\n // },\n // },\n // {\n // imageUrl: \"https://assets.xendit.co/payment-session/logos/MASTERCARD.svg\",\n // description:\n // \"3DS Challenge, authentication is successful if OTP is correct. For frictionless flow, use amount < THB 20.\",\n // name: \"3_ds_challenge_authentication_is_successful_if_otp_is_correct_for_frictionless_flow_use_amount_thb_20_mastercard\",\n // values: {\n // \"card_details.card_number\":\n // \"3_ds_challenge_authentication_is_successful_if_otp_is_correct_for_frictionless_flow_use_amount_thb_20_mastercard\",\n // \"card_details.expiry_month__card_details.expiry_year\":\n // \"3_ds_challenge_authentication_is_successful_if_otp_is_correct_for_frictionless_flow_use_amount_thb_20_mastercard\",\n // \"card_details.cvn\":\n // \"3_ds_challenge_authentication_is_successful_if_otp_is_correct_for_frictionless_flow_use_amount_thb_20_mastercard\",\n // },\n // },\n {\n imageUrl: \"https://assets.xendit.co/payment-session/logos/VISA.svg\",\n description: \"Failure\",\n name: \"failing_transaction_visa\",\n values: {\n \"card_details.card_number\": \"failing_transaction_visa\",\n \"card_details.expiry_month__card_details.expiry_year\":\n \"failing_transaction_visa\",\n \"card_details.cvn\": \"failing_transaction_visa\",\n },\n },\n {\n imageUrl: \"https://assets.xendit.co/payment-session/logos/MASTERCARD.svg\",\n description: \"Failure\",\n name: \"failing_transaction_mastercard\",\n values: {\n \"card_details.card_number\": \"failing_transaction_mastercard\",\n \"card_details.expiry_month__card_details.expiry_year\":\n \"failing_transaction_mastercard\",\n \"card_details.cvn\": \"failing_transaction_mastercard\",\n },\n },\n {\n imageUrl: \"https://assets.xendit.co/payment-session/logos/AMEX.svg\",\n description: \"3DS Frictionless, success\",\n name: \"3_ds_frictionless_authentication_successful_use_a_4_digit_cvn\",\n values: {\n \"card_details.card_number\":\n \"3_ds_frictionless_authentication_successful_use_a_4_digit_cvn\",\n \"card_details.expiry_month__card_details.expiry_year\":\n \"3_ds_frictionless_authentication_successful_use_a_4_digit_cvn\",\n \"card_details.cvn\":\n \"3_ds_frictionless_authentication_successful_use_a_4_digit_cvn\",\n },\n },\n {\n imageUrl: \"https://assets.xendit.co/payment-session/logos/AMEX.svg\",\n description: \"3DS Frictionless, success\",\n name: \"3_ds_frictionless_authentication_successful_use_a_4_digit_cvn2\",\n values: {\n \"card_details.card_number\":\n \"3_ds_frictionless_authentication_successful_use_a_4_digit_cvn2\",\n \"card_details.expiry_month__card_details.expiry_year\":\n \"3_ds_frictionless_authentication_successful_use_a_4_digit_cvn2\",\n \"card_details.cvn\":\n \"3_ds_frictionless_authentication_successful_use_a_4_digit_cvn2\",\n },\n },\n {\n imageUrl: \"https://assets.xendit.co/payment-session/logos/AMEX.svg\",\n description: \"3DS Challenge\",\n name: \"3_ds_challenge_use_a_4_digit_cvn\",\n values: {\n \"card_details.card_number\": \"3_ds_challenge_use_a_4_digit_cvn\",\n \"card_details.expiry_month__card_details.expiry_year\":\n \"3_ds_challenge_use_a_4_digit_cvn\",\n \"card_details.cvn\": \"3_ds_challenge_use_a_4_digit_cvn\",\n },\n },\n ],\n docsLink: \"https://docs.xendit.co/docs/cards-simulate-card-scenarios\",\n};\n","import { ChannelFormField, ChannelProperties } from \"../backend-types/channel\";\nimport { BffSession, BffSessionType } from \"../backend-types/session\";\nimport {\n useCallback,\n useContext,\n useEffect,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n} from \"preact/hooks\";\nimport { useSdk, useSession } from \"./session-provider\";\nimport FieldGroup from \"./field-group\";\nimport { formHasFieldOfType, usePrevious } from \"../utils\";\nimport { createContext } from \"preact\";\nimport { forwardRef } from \"preact/compat\";\nimport { InternalSetFieldTouchedEvent } from \"../private-event-types\";\nimport { getChannelPropertyValue } from \"../validation\";\nimport { ChannelComponentData } from \"../public-sdk\";\nimport { CARDS_SCENARIOS, Scenarios } from \"../data/simulation-scenarios\";\nimport { useChannel, useChannelComponentData } from \"./channel-root\";\n\ninterface Props {\n form: ChannelFormField[];\n onChannelPropertiesChanged: (channelProperties: ChannelProperties) => void;\n}\nexport interface ChannelFormHandle {\n setAllFieldsTouched: () => void;\n}\n\nconst ChannelForm = forwardRef<ChannelFormHandle, Props>(\n ({ form, onChannelPropertiesChanged }, ref) => {\n const session = useSession();\n const channel = useChannel();\n const sdk = useSdk();\n const channelComponentData = useChannelComponentData();\n const formRef = useRef<HTMLFormElement>(null);\n\n const [channelProperties, setChannelProperties] =\n useState<ChannelProperties | null>(null);\n\n useImperativeHandle(ref, () => ({\n setAllFieldsTouched() {\n const form = formRef.current;\n if (!form) return;\n Array.from(form.elements)\n .filter((el) => el instanceof HTMLInputElement)\n .forEach((input) => {\n if (!input.name) {\n // only mark named fields as touched\n return;\n }\n input.dispatchEvent(new InternalSetFieldTouchedEvent());\n });\n },\n }));\n\n const getChannelProperties = useCallback((): ChannelProperties => {\n if (!formRef.current) return {};\n\n // The browser FormData collides with node's FormData, both are global, so we\n // need to make up a type for\n const formData = new FormData(formRef.current) as unknown as {\n entries: () => IterableIterator<[string, string | Blob]>;\n };\n\n return formKvToChannelProperties(formData.entries());\n }, []);\n\n const handleFieldChanged = useCallback(() => {\n if (!formRef.current) return;\n const channelProperties = getChannelProperties();\n setChannelProperties(channelProperties);\n onChannelPropertiesChanged(channelProperties);\n }, [getChannelProperties, onChannelPropertiesChanged]);\n\n const filteredForm = useFilteredFormFields(\n session,\n form,\n channelProperties || {},\n channelComponentData ?? null,\n );\n\n // trigger a field changed callback when the form changes\n const previousFilteredForm = usePrevious(filteredForm);\n useEffect(() => {\n if (\n // only trigger if the form changed\n !formsAreEqual(previousFilteredForm || [], filteredForm)\n ) {\n handleFieldChanged();\n }\n }, [filteredForm, handleFieldChanged, previousFilteredForm]);\n\n const getSimulationScenarios = useCallback(\n (fieldGroup: ChannelFormField[]): Scenarios | null => {\n // only show simulation scenarios for prod-dev (test mode)\n if (!sdk.supportsSimulationScenarios()) {\n return null;\n }\n\n // only show simulation scenarios for cards channel and if the field group has a credit card number field\n if (\n channel?.channel_code === \"CARDS\" &&\n fieldGroup.some((field) => field.type.name === \"credit_card_number\")\n ) {\n return CARDS_SCENARIOS;\n }\n\n return null;\n },\n [channel, sdk],\n );\n\n const filteredFieldGroups = groupFields(filteredForm).filter(\n (group) => group.length,\n );\n\n if (filteredFieldGroups.length === 0) {\n return null;\n }\n\n return (\n <div class=\"xendit-channel-form\">\n <form ref={formRef}>\n <ChannelPropertiesContext.Provider value={channelProperties}>\n {filteredFieldGroups.map((fieldGroup, index) => (\n <FieldGroup\n key={index}\n fieldGroup={fieldGroup}\n groupIndex={index}\n handleFieldChanged={handleFieldChanged}\n channelProperties={channelProperties}\n simulationScenarios={getSimulationScenarios(fieldGroup)}\n />\n ))}\n </ChannelPropertiesContext.Provider>\n </form>\n </div>\n );\n },\n);\n\nexport const ChannelPropertiesContext = createContext<ChannelProperties | null>(\n null,\n);\n\nexport const useChannelProperties = (): ChannelProperties | null => {\n return useContext(ChannelPropertiesContext);\n};\n\nfunction groupFields(fields: ChannelFormField[]): ChannelFormField[][] {\n // Group fields for rendering\n const fieldGroups: ChannelFormField[][] = [[]];\n for (const field of fields) {\n if (\n field.span === 1 &&\n fieldGroups[fieldGroups.length - 1].length === 1 &&\n fieldGroups[fieldGroups.length - 1][0].span === 1\n ) {\n // join two half-width fields into one group\n fieldGroups[fieldGroups.length - 1].push(field);\n continue;\n }\n\n if (field.join) {\n // if the field should be explicitly joined, add it to the last group\n fieldGroups[fieldGroups.length - 1].push(field);\n continue;\n }\n\n // otherwise, start a new group\n fieldGroups.push([field]);\n }\n\n return fieldGroups;\n}\n\n/**\n * Convert form key/value pairs to channel properties\n * .e.g\n * Input:\n * {\n * \"k\": \"v1\",\n * \"a.b.c\": \"v2\",\n * \"z.z__a.y\": [\"v3\", \"v3\"],\n * }\n * Output:\n * {\n * k: \"v1\",\n * a: { b: { c: \"v2\", }, },\n * z: { z: \"v3\", y: \"v4\" },\n * }\n **/\nfunction formKvToChannelProperties(\n iter: IterableIterator<[string, string | Blob]>,\n): ChannelProperties {\n const obj: ChannelProperties = {};\n\n for (const [key, rawValue] of iter) {\n if (rawValue instanceof Blob) {\n continue;\n }\n\n // keys with __ represent multiple k/v pairs\n // e.g. `{\"a__b\": [\"1\", \"2\"]}` becomes `{a: \"1\", b: \"2\"}`\n const subkeys = key.split(\"__\");\n\n // if there are multiple subkeys, assume the value is a JSON array of strings\n const valueAsArray = formValueToStringArray(subkeys, rawValue);\n\n outer: for (const subkey of subkeys) {\n // split key by dot, for each part, traverse the object\n // and assign the value at the end\n // e.g. { \"branch.leaf\": \"value\" } becomes { branch: { leaf: \"value\" } }\n // cursor will be the leaf object\n const parts = subkey.split(\".\");\n let cursor = obj;\n while (parts.length > 1) {\n const part = parts.shift()!;\n let selected = cursor[part];\n if (selected === undefined) {\n // child object doesn't exist, create it\n selected = cursor[part] = {};\n }\n if (selected && typeof selected === \"object\") {\n if (Array.isArray(selected)) {\n continue outer; // should never happen\n }\n // traverse into child object\n cursor = selected;\n }\n }\n\n // assign next value to channel properties\n const nextValue = valueAsArray.length ? valueAsArray.shift() : \"\";\n cursor[parts[0]] = nextValue;\n }\n }\n\n return obj;\n}\n\n/**\n * Parse a json string[] with error handling.\n */\nfunction formValueToStringArray(\n subkeys: string[],\n value: string,\n): (string | number)[] {\n if (subkeys.length === 0) return [];\n if (subkeys.length === 1) return [value];\n if (value === \"\") return [];\n try {\n return JSON.parse(value);\n } catch (_e) {\n return [value];\n }\n}\n\n/**\n * Checks if two forms are equal\n */\nfunction formsAreEqual(a: ChannelFormField[], b: ChannelFormField[]) {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n if (a[i] !== b[i]) return false;\n }\n return true;\n}\n\n/**\n * Takes a form and filters out fields that should not be shown based on context.\n */\nexport function useFilteredFormFields(\n session: BffSession,\n form: ChannelFormField[],\n channelProperties: ChannelProperties,\n channelComponentData: ChannelComponentData | null,\n) {\n const filteredForm = useMemo(() => {\n return filterFormFields(\n session.session_type,\n form,\n channelProperties,\n channelComponentData,\n );\n }, [channelComponentData, channelProperties, form, session.session_type]);\n\n return filteredForm;\n}\n\nexport function filterFormFields(\n sessionType: BffSessionType,\n form: ChannelFormField[],\n channelProperties: ChannelProperties,\n channelComponentData: ChannelComponentData | null,\n) {\n const hasCardsField = formHasFieldOfType(form, \"credit_card_number\");\n const showBillingDetailsFields =\n channelComponentData?.cardDetails?.details?.require_billing_information;\n const hasInstallmentPlans =\n !!channelComponentData?.paymentOptions?.options?.installment_plans?.length;\n\n return form.filter((field) => {\n if (field.flags?.require_billing_information) {\n // filter out billing info fields if the flag is disabled or the session type is not PAY\n if (sessionType !== \"PAY\") return false;\n if (!showBillingDetailsFields) return false;\n }\n if (field.type.name === \"installment_plan\") {\n // filter out installment plan fields if there are no installment plans AND there is a card number field\n // (if there's no card number, then the installments field would be mandatory so we can't hide it)\n if (!hasInstallmentPlans && hasCardsField) return false;\n }\n for (const condition of field.display_if || []) {\n // filter out fields if any of their display_if conditions fail\n const [property, operator, value] = condition;\n const channelValue = getChannelPropertyValue(channelProperties, property);\n switch (operator) {\n case \"equals\":\n if (channelValue !== value) return false;\n break;\n case \"not_equals\":\n if (channelValue === value) return false;\n break;\n }\n }\n return true;\n });\n}\n\nexport default ChannelForm;\n","import { FunctionComponent, SVGAttributes } from \"preact\";\nimport { useLayoutEffect, useRef } from \"preact/hooks\";\n\nexport const GraphicRedirectInstructions: FunctionComponent<\n SVGAttributes<SVGSVGElement>\n> = (props) => {\n const arrowRef = useRef<SVGGElement>(null);\n const arrowSquareGroupRef = useRef<SVGGElement>(null);\n\n const supportsAnimation = HTMLElement.prototype.animate !== undefined;\n\n useLayoutEffect(() => {\n if (!supportsAnimation) {\n return;\n }\n arrowRef.current?.animate(arrowKeyFrames, arrowAnimationOptions);\n\n arrowSquareGroupRef.current?.animate(\n arrowSquareBounceKeyFrames,\n arrowSquareBounceAnimationOptions,\n );\n }, [supportsAnimation]);\n\n return (\n <svg\n width=\"40\"\n height=\"40\"\n viewBox=\"0 0 40 40\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n {...props}\n >\n <g opacity=\"0.5\">\n <path\n d=\"M8.79453 10.2303C7.1791 10.2303 5.86953 11.5399 5.86953 13.1553V28.9503C5.86953 31.535 7.96484 33.6303 10.5495 33.6303H26.3445C27.96 33.6303 29.2695 32.3208 29.2695 30.7053\"\n fill=\"#F1F1F1\"\n />\n <path\n d=\"M8.79453 10.2303V10.2303C7.1791 10.2303 5.86953 11.5399 5.86953 13.1553V28.9503C5.86953 31.535 7.96484 33.6303 10.5495 33.6303H26.3445C27.96 33.6303 29.2695 32.3208 29.2695 30.7053V30.7053\"\n stroke=\"#D0D0D0\"\n strokeWidth=\"1.755\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </g>\n <g ref={arrowSquareGroupRef} style={{ transformOrigin: \"20px 20px\" }}>\n <path\n d=\"M28.8177 6.00256H14.7777C12.193 6.00256 10.0977 8.09787 10.0977 10.6826V24.7226C10.0977 27.3073 12.193 29.4026 14.7777 29.4026H28.8177C31.4023 29.4026 33.4977 27.3073 33.4977 24.7226V10.6826C33.4977 8.09787 31.4024 6.00256 28.8177 6.00256Z\"\n fill=\"white\"\n stroke=\"#EDEDED\"\n strokeWidth=\"1.755\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <g style={{ transformOrigin: \"10px 30px\" }} ref={arrowRef}>\n <path\n d=\"M26.7697 20.5301V12.7301H18.9697\"\n stroke=\"#7C7C7C\"\n strokeWidth=\"1.872\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n <path\n d=\"M17.4102 22.0901L26.7702 12.7301\"\n stroke=\"#7C7C7C\"\n strokeWidth=\"1.872\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </g>\n </g>\n </svg>\n );\n};\n\nconst arrowKeyFrames: Keyframe[] = [\n { transform: \"scale(0.1)\" },\n { transform: \"scale(1)\" },\n];\nconst arrowAnimationOptions: EffectTiming = {\n duration: 500,\n easing: \"ease-out\",\n};\n\nconst arrowSquareBounceKeyFrames: Keyframe[] = [\n { transform: \"rotate(0deg)\" },\n { transform: \"rotate(5deg)\" },\n { transform: \"rotate(-5deg)\" },\n { transform: \"rotate(0deg)\" },\n];\nconst arrowSquareBounceAnimationOptions: EffectTiming = {\n duration: 1000,\n easing: \"ease-out\",\n iterations: Infinity,\n delay: 2000,\n};\n","import { FunctionComponent, SVGAttributes } from \"preact\";\nimport { useLayoutEffect, useRef } from \"preact/hooks\";\nimport { useIdSafe } from \"../utils\";\n\nexport const GraphicQrScan: FunctionComponent<SVGAttributes<SVGSVGElement>> = (\n props,\n) => {\n const scannerRef = useRef<SVGRectElement>(null);\n const squareBackgroundRef = useRef<SVGRectElement>(null);\n\n const clipPathId = useIdSafe();\n\n const supportsAnimation = HTMLElement.prototype.animate !== undefined;\n\n useLayoutEffect(() => {\n if (!supportsAnimation) {\n return;\n }\n if (scannerRef.current) {\n const startAnimation = () => {\n if (!scannerRef.current) return;\n const a = scannerRef.current.animate(\n scannerKeyFrames,\n scanDownAnimationOptions,\n );\n setTimeout(() => {\n squareBackgroundRef.current?.animate(\n squareKeyFrames,\n squareAnimationOptions,\n );\n }, 1000);\n a.onfinish = () => {\n const b = scannerRef.current?.animate(\n scannerKeyFrames,\n scanUpAnimationOptions,\n );\n setTimeout(() => {\n squareBackgroundRef.current?.animate(\n squareKeyFrames,\n squareAnimationOptions,\n );\n }, 500);\n if (b) b.onfinish = startAnimation;\n };\n };\n startAnimation();\n }\n }, [supportsAnimation]);\n\n return (\n <svg\n width=\"40\"\n height=\"40\"\n viewBox=\"0 0 40 40\"\n fill=\"var(--xendit-color-icon-primary)\"\n xmlns=\"http://www.w3.org/2000/svg\"\n {...props}\n >\n <g clip-path={`url(#${clipPathId})`}>\n {/* background */}\n <rect\n x=\"8\"\n y=\"8\"\n width=\"24\"\n height=\"24\"\n fill=\"var(--xendit-color-icon-secondary)\"\n ref={squareBackgroundRef}\n />\n\n <path d=\"M11.5 13.1528C11.5 12.24 12.24 11.5 13.1528 11.5H17.4028C18.3156 11.5 19.0556 12.24 19.0556 13.1528V17.4028C19.0556 18.3156 18.3156 19.0556 17.4028 19.0556H13.1528C12.24 19.0556 11.5 18.3156 11.5 17.4028V13.1528Z\" />\n <path d=\"M20.9444 13.1528C20.9444 12.24 21.6844 11.5 22.5972 11.5H26.8472C27.76 11.5 28.5 12.24 28.5 13.1528V17.4028C28.5 18.3156 27.76 19.0556 26.8472 19.0556H22.5972C21.6844 19.0556 20.9444 18.3156 20.9444 17.4028V13.1528Z\" />\n <path d=\"M11.5 22.5972C11.5 21.6844 12.24 20.9444 13.1528 20.9444H17.4028C18.3156 20.9444 19.0556 21.6844 19.0556 22.5972V26.8472C19.0556 27.76 18.3156 28.5 17.4028 28.5H13.1528C12.24 28.5 11.5 27.76 11.5 26.8472V22.5972Z\" />\n <path d=\"M20.9444 22.5972C20.9444 21.6844 21.6844 20.9444 22.5972 20.9444H26.8472C27.76 20.9444 28.5 21.6844 28.5 22.5972V26.8472C28.5 27.76 27.76 28.5 26.8472 28.5H22.5972C21.6844 28.5 20.9444 27.76 20.9444 26.8472V22.5972Z\" />\n <path d=\"M7.875 23C8.35825 23 8.75 23.3918 8.75 23.875V30.2754C8.75021 30.6755 9.07451 30.9998 9.47461 31H15.875C16.3582 31 16.75 31.3918 16.75 31.875C16.75 32.3582 16.3582 32.75 15.875 32.75H9.47461C8.10801 32.7498 7.00021 31.642 7 30.2754V23.875C7 23.3918 7.39175 23 7.875 23Z\" />\n <path d=\"M31.875 23C32.3582 23 32.75 23.3918 32.75 23.875V30.2754C32.7498 31.642 31.642 32.7498 30.2754 32.75H23.875C23.3918 32.75 23 32.3582 23 31.875C23 31.3918 23.3918 31 23.875 31H30.2754C30.6755 30.9998 30.9998 30.6755 31 30.2754V23.875C31 23.3918 31.3918 23 31.875 23Z\" />\n <path d=\"M15.875 7C16.3582 7 16.75 7.39175 16.75 7.875C16.75 8.35825 16.3582 8.75 15.875 8.75H9.47461C9.07451 8.75021 8.75021 9.07451 8.75 9.47461V15.875C8.75 16.3582 8.35825 16.75 7.875 16.75C7.39175 16.75 7 16.3582 7 15.875V9.47461C7.00021 8.10801 8.10801 7.00021 9.47461 7H15.875Z\" />\n <path d=\"M30.2754 7C31.642 7.00021 32.7498 8.10801 32.75 9.47461V15.875C32.75 16.3582 32.3582 16.75 31.875 16.75C31.3918 16.75 31 16.3582 31 15.875V9.47461C30.9998 9.07451 30.6755 8.75021 30.2754 8.75H23.875C23.3918 8.75 23 8.35825 23 7.875C23 7.39175 23.3918 7 23.875 7H30.2754Z\" />\n {/* scanner */}\n <rect x=\"3\" y=\"-4\" width=\"34\" height=\"4\" rx=\"1.75\" ref={scannerRef} />\n </g>\n <defs>\n <clipPath id={clipPathId}>\n <rect width=\"40\" height=\"40\" fill=\"white\" />\n </clipPath>\n </defs>\n </svg>\n );\n};\n\nconst scannerKeyFrames: Keyframe[] = [\n { transform: \"translateY(0)\" },\n { transform: \"translateY(44px)\" },\n];\nconst scanDownAnimationOptions: EffectTiming = {\n duration: 1000,\n delay: 1000,\n easing: \"ease-out\",\n};\nconst scanUpAnimationOptions: EffectTiming = {\n duration: 1000,\n direction: \"reverse\",\n delay: 500,\n easing: \"ease-in\",\n};\n\nconst squareKeyFrames: Keyframe[] = [\n { opacity: 1 },\n { opacity: 0 },\n { opacity: 1 },\n];\nconst squareAnimationOptions: EffectTiming = {\n duration: 1000,\n};\n","import { FunctionComponent, TargetedEvent } from \"preact\";\nimport { useIdSafe } from \"../../utils\";\n\ninterface Props {\n id?: string;\n label: string;\n checked?: boolean;\n disabled?: boolean;\n onChange?: (e: TargetedEvent<HTMLInputElement>) => void;\n}\n\n/**\n * Checkbox component\n */\nexport const Checkbox: FunctionComponent<Props> = (props) => {\n const { id, label, checked, onChange, disabled } = props;\n\n const generatedId = useIdSafe();\n const htmlId = id || generatedId;\n\n const handleChange = (e: TargetedEvent<HTMLInputElement>) => {\n onChange?.(e);\n };\n\n return (\n <div className=\"xendit-checkbox\">\n <div className=\"xendit-checkbox-box\">\n <input\n id={htmlId}\n type=\"checkbox\"\n onChange={handleChange}\n checked={checked}\n disabled={disabled}\n />\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 256 256\"\n className=\"xendit-checkbox-graphic\"\n >\n <polyline\n points=\"40 144 96 200 224 72\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"16\"\n ></polyline>\n </svg>\n </div>\n <label htmlFor={htmlId} className=\"xendit-text-14\">\n {label}\n </label>\n </div>\n );\n};\n","import ChannelForm, { ChannelFormHandle } from \"./channel-form\";\nimport { useContext, useLayoutEffect, useRef } from \"preact/hooks\";\nimport {\n ComponentChildren,\n createContext,\n FunctionComponent,\n RefObject,\n TargetedEvent,\n} from \"preact\";\nimport {\n BffChannel,\n BffChannelBanner,\n ChannelProperties,\n} from \"../backend-types/channel\";\nimport { GraphicRedirectInstructions } from \"./graphic-redirect-instructions\";\nimport { GraphicQrScan } from \"./graphic-qr-scan\";\nimport { useSdk, useSession } from \"./session-provider\";\nimport { Checkbox } from \"./core/checkbox\";\nimport { resolvePairedChannel } from \"../utils\";\nimport { ChannelComponentData } from \"../public-sdk\";\nimport { InternalUpdateChannelComponentData } from \"../private-event-types\";\n\nconst ChannelContext = createContext<BffChannel | null>(null);\n\nexport const useChannel = () => {\n const context = useContext(ChannelContext);\n if (context === undefined) {\n throw new Error(\"useChannel must be used within a ChannelProvider\");\n }\n return context;\n};\n\nconst ChannelComponentDataContext = createContext<ChannelComponentData | null>(\n null,\n);\nChannelComponentDataContext.displayName = \"ChannelComponentDataContext\";\n\nexport const useChannelComponentData = () => {\n const context = useContext(ChannelComponentDataContext);\n return context;\n};\n\ninterface Props {\n /** The channels to use. If this has two items then the first is the non-save channel and the second is the save version. */\n channelOrPair: BffChannel[];\n channelData: ChannelComponentData;\n savePaymentMethod: boolean;\n formRef: RefObject<ChannelFormHandle>;\n}\n\nexport const ChannelRoot: FunctionComponent<Props> = (props) => {\n const { channelOrPair, channelData, savePaymentMethod, formRef } = props;\n const divRef = useRef<HTMLDivElement>(null);\n const sdk = useSdk();\n const { t } = sdk;\n const session = useSession();\n\n // events always use channelOrPair[0] because the CachedChannelComponents are keyed by that\n const firstMemberChannel = channelOrPair[0];\n\n const hasPairedChannel = channelOrPair.length > 1;\n const resolvedChannel = resolvePairedChannel(\n channelOrPair,\n savePaymentMethod,\n );\n\n const instructions = instructionsAsTuple(resolvedChannel.instructions);\n\n const onChannelPropertiesChanged = (channelProperties: ChannelProperties) => {\n let cleanedProperties = channelProperties;\n if (\n firstMemberChannel.channel_code === \"CARDS\" &&\n channelProperties.installment_configuration\n ) {\n // for cards installment configuration, we need to remove any properties that have empty string values,\n // because the presence of those properties causes validation errors, even if the value is an empty string\n const cleanedInstallmentConfiguration = Object.fromEntries(\n Object.entries(channelProperties.installment_configuration).filter(\n ([_, value]) => value !== \"\",\n ),\n );\n if (Object.keys(cleanedInstallmentConfiguration).length === 0) {\n // if there are no valid properties left, set installment_configuration to undefined to avoid validation errors\n cleanedProperties = {\n ...channelProperties,\n installment_configuration: undefined,\n };\n } else {\n cleanedProperties = {\n ...channelProperties,\n installment_configuration: cleanedInstallmentConfiguration,\n };\n }\n }\n\n const event = new XenditChannelPropertiesChangedEvent(\n firstMemberChannel.channel_code,\n cleanedProperties,\n );\n divRef.current?.dispatchEvent(event);\n };\n\n const shouldShowSaveCheckbox =\n session.allow_save_payment_method === \"OPTIONAL\" &&\n (resolvedChannel.allow_save || hasPairedChannel);\n\n const handleCheckboxChange = (e: TargetedEvent<HTMLInputElement>) => {\n const checked = (e.target as HTMLInputElement)?.checked;\n sdk?.dispatchEvent(\n new InternalUpdateChannelComponentData(firstMemberChannel.channel_code, {\n savePaymentMethod: checked,\n }),\n );\n };\n\n useLayoutEffect(() => {\n if (\n !instructions &&\n !resolvedChannel.form.length &&\n !resolvedChannel.banner\n ) {\n console.error(\n `Missing display data for ${resolvedChannel.channel_code}, this is a bug, please contact support`,\n );\n }\n }, [\n instructions,\n resolvedChannel.banner,\n resolvedChannel.channel_code,\n resolvedChannel.form,\n ]);\n\n return (\n <ChannelContext.Provider value={resolvedChannel}>\n <ChannelComponentDataContext.Provider value={channelData}>\n <div className=\"xendit-payment-channel\" ref={divRef}>\n <ChannelForm\n ref={formRef}\n form={resolvedChannel.form}\n onChannelPropertiesChanged={onChannelPropertiesChanged}\n />\n {resolvedChannel.banner ? (\n <Banner banner={resolvedChannel.banner} />\n ) : null}\n {shouldShowSaveCheckbox && (\n <Checkbox\n label={t(\"payment.save_checkbox_label\")}\n onChange={handleCheckboxChange}\n checked={savePaymentMethod}\n />\n )}\n {instructions ? (\n <div className=\"xendit-payment-channel-instructions\">\n {GRAPHIC_COMPONENTS_BY_PM_TYPE[resolvedChannel.pm_type ?? \"\"] ?? (\n <GraphicRedirectInstructions />\n )}\n <div className=\"xendit-payment-channel-instructions-text xendit-text-12\">\n {instructions.map((instr, i) => (\n <p\n key={i}\n className={i === 0 ? \"xendit-text-semibold\" : undefined}\n >\n {instr}\n </p>\n ))}\n </div>\n </div>\n ) : null}\n </div>\n </ChannelComponentDataContext.Provider>\n </ChannelContext.Provider>\n );\n};\n\nconst GRAPHIC_COMPONENTS_BY_PM_TYPE: Record<string, ComponentChildren> = {\n EWALLET: <GraphicRedirectInstructions />,\n QR_CODE: <GraphicQrScan />,\n};\n\nconst Banner: FunctionComponent<{ banner: BffChannelBanner }> = (props) => {\n const aspectRatio =\n typeof props.banner.aspect_ratio === \"number\"\n ? String(props.banner.aspect_ratio) // passing aspectRatio as a number does not work\n : undefined;\n\n if (props.banner?.link_url) {\n return (\n <a href={props.banner.link_url} target=\"_blank\" rel=\"noopener noreferrer\">\n <img\n src={props.banner.image_url}\n alt={props.banner.alt_text}\n className=\"xendit-payment-channel-banner\"\n style={{\n aspectRatio,\n }}\n />\n </a>\n );\n }\n\n return (\n <img\n src={props.banner.image_url}\n alt={props.banner.alt_text}\n className=\"xendit-payment-channel-banner\"\n style={{\n aspectRatio,\n }}\n />\n );\n};\n\nfunction instructionsAsTuple(\n instructions: string[] | undefined,\n): [string, string] | null {\n if (instructions && instructions.length === 2) {\n return [instructions[0], instructions[1]] as const;\n }\n return null;\n}\n\nexport class XenditChannelPropertiesChangedEvent extends Event {\n static readonly type = \"xendit-channel-properties-changed\" as const;\n channel: string;\n channelProperties: ChannelProperties;\n\n constructor(channel: string, channelProperties: ChannelProperties) {\n super(XenditChannelPropertiesChangedEvent.type, {\n bubbles: true,\n composed: true,\n });\n this.channel = channel;\n this.channelProperties = channelProperties;\n }\n}\n","import { assert, hostFromHostId, MOCK_HOST_ID, ParsedSdkKey } from \"./utils\";\n\nexport type ErrorResponse = {\n error_code: string;\n message: string;\n error_content?: {\n title: string;\n message_1: string;\n message_2?: string;\n };\n};\n\nexport class NetworkError extends Error {\n constructor(public errorResponse: ErrorResponse) {\n super(errorResponse.message);\n }\n}\n\n/**\n * Encode data for x-www-form-urlencoded content type\n */\nfunction convertDataToUrlSearchParams<T extends object>(data: T) {\n const params = new URLSearchParams();\n params.append(\"payload\", JSON.stringify(data));\n return params;\n}\n\n// GET with path param\nexport function endpoint<ResponseBody, PathArg>(\n method: \"GET\",\n getPath: (pathArg: PathArg) => string,\n): (\n sdkKey: ParsedSdkKey,\n pathArg: PathArg,\n queryArg?: null,\n abortSignal?: AbortSignal,\n) => Promise<ResponseBody>;\n\n// GET with path param and query param\nexport function endpoint<ResponseBody, PathArg, QueryArg = never>(\n method: \"GET\",\n getPath: (pathArg: PathArg) => string,\n getQuery: (queryArg: QueryArg) => URLSearchParams,\n): (\n sdkKey: ParsedSdkKey,\n pathArg: PathArg,\n queryArg?: QueryArg,\n abortSignal?: AbortSignal,\n) => Promise<ResponseBody>;\n\n// POST with path param\nexport function endpoint<RequestBody, ResponseBody, PathArg>(\n method: \"POST\",\n getPath: (pathArg: PathArg) => string,\n): (\n sdkKey: ParsedSdkKey,\n requestBody: RequestBody,\n pathArg: PathArg,\n queryArg?: null,\n abortSignal?: AbortSignal,\n) => Promise<ResponseBody>;\n\n// POST with path param and query param\nexport function endpoint<RequestBody, ResponseBody, PathArg, QueryArg = never>(\n method: \"POST\",\n getPath: (pathArg: PathArg) => string,\n getQuery: (queryArg: QueryArg) => URLSearchParams,\n): (\n sdkKey: ParsedSdkKey,\n requestBody: RequestBody,\n pathArg: PathArg,\n queryArg?: QueryArg,\n abortSignal?: AbortSignal,\n) => Promise<ResponseBody>;\n\n/**\n * Declares an endpoint in checkout-ui-gateway and returns a function to call it.\n *\n * @example\n * ```\n * // declare\n * const myEndpoint = endpoint<\n * { userId: string }, // Request body type\n * { name: string; age: number }, // Response body type\n * string, // Type of arg passed to getPath\n * string, // Type of arg passed to getQuery\n * >(\n * \"POST\",\n * (pathArg) => `/api/users/${pathArg}`, // getPath function\n * (queryArg) => new UrlSearchParams({id: queryArg}) // getQuery function\n * );\n *\n * // usage\n * await myEndpoint({userId: \"123\"}, \"456\", \"789\");\n * ```\n */\nexport function endpoint(\n method: \"GET\" | \"POST\",\n getPath: (pathArg: unknown) => string,\n getQuery?: (queryArg: unknown) => URLSearchParams,\n) {\n return async function (...rest: unknown[]): Promise<unknown> {\n let sdkKey: unknown;\n let pathArg: unknown;\n let queryArg: unknown;\n let requestBody: unknown;\n let abortSignal: unknown;\n\n switch (method) {\n case \"GET\":\n [sdkKey, pathArg, queryArg, abortSignal] = rest;\n break;\n case \"POST\":\n [sdkKey, requestBody, pathArg, queryArg, abortSignal] = rest;\n break;\n default:\n throw new Error(\n `Unable to call endpoint with method ${method}; this is a bug, please contact support.`,\n );\n }\n\n const versionNumber = process.env.XENDIT_COMPONENTS_VERSION;\n assert(versionNumber);\n assert(versionNumber.startsWith(\"v\"));\n\n const hostId = (sdkKey as ParsedSdkKey).hostId;\n if (hostId === MOCK_HOST_ID) {\n throw new Error(\n \"A network request was made in mock mode; this is a bug.\",\n );\n }\n const host = hostFromHostId(hostId);\n if (!host) {\n throw new Error(\n `Unknown hostId ${hostId} in sdkKey; this is a bug, please contact support.`,\n );\n }\n\n const url = new URL(getPath(pathArg), host);\n if (getQuery && !queryArg) {\n throw new Error(\n \"Query string argument is missing; this is a bug, please contact support.\",\n );\n }\n const query = getQuery?.(queryArg) ?? new URLSearchParams();\n query.set(\"components_version\", versionNumber);\n url.search = query.toString();\n\n const options: RequestInit = {\n method,\n body: requestBody ? convertDataToUrlSearchParams(requestBody) : undefined,\n headers: {\n \"Content-Type\": \"application/x-www-form-urlencoded\",\n },\n signal: abortSignal as AbortSignal | undefined,\n };\n\n const response = await fetch(url, options);\n if (!response.ok) {\n const errorData = (await response.json()) as ErrorResponse;\n if (!errorData || !errorData.error_code) {\n throw new Error(\"Unexpected error response from server\");\n }\n throw new NetworkError(errorData);\n }\n\n return response.json();\n };\n}\n","import { ChannelProperties } from \"./backend-types/channel\";\nimport { BffPollResponse, BffResponse } from \"./backend-types/common\";\nimport { BffCustomer } from \"./backend-types/customer\";\nimport {\n BffPaymentRequest,\n BffPaymentToken,\n} from \"./backend-types/payment-entity\";\nimport { BffCardDetails } from \"./backend-types/card-details\";\nimport { endpoint } from \"./networking\";\nimport { BffPaymentOptions } from \"./backend-types/payment-options\";\n\n/**\n * Initialization method, returns session, customer, business, and channels.\n */\nexport const fetchSessionData = endpoint<BffResponse, string>(\n \"GET\",\n (sessionAuthKey) => `/api/sessions/${sessionAuthKey}`,\n);\n\ntype CreatePaymentTokenRequestBody = {\n session_id: string;\n channel_code: string;\n channel_properties: ChannelProperties;\n};\n/**\n * Creates a payment token.\n */\nexport const createPaymentToken = endpoint<\n CreatePaymentTokenRequestBody,\n BffPaymentToken,\n null\n>(\"POST\", () => `/api/sessions/payment_tokens`);\n\ntype CreatePaymentRequestRequestBody = {\n session_id: string;\n channel_code: string;\n channel_properties: ChannelProperties;\n customer?: BffCustomer;\n save_payment_method?: boolean;\n};\n/**\n * Creates a payment request.\n */\nexport const createPaymentRequest = endpoint<\n CreatePaymentRequestRequestBody,\n BffPaymentRequest,\n null\n>(\"POST\", () => `/api/sessions/payment_requests`);\n\ntype SimulatePaymentRequestRequestBody = {\n channel_code: string;\n};\n/**\n * Simulates a payment request.\n */\nexport const simulatePaymentRequest = endpoint<\n SimulatePaymentRequestRequestBody,\n BffPaymentRequest,\n { sessionAuthKey: string; paymentRequestId: string }\n>(\n \"POST\",\n (pathArg) =>\n `/api/sessions/${pathArg.sessionAuthKey}/payment_requests/${pathArg.paymentRequestId}/simulate`,\n);\n\n/**\n * Polls the session for updates.\n *\n * Always returns the session.\n * If the session is active, the payment entity will be included.\n * If the session is completed, the succeeded channel will be included.\n */\nexport const pollSession = endpoint<BffPollResponse, string, string | null>(\n \"GET\",\n (sessionAuthKey) => `/api/sessions/${sessionAuthKey}/poll`,\n (tokenRequestId) =>\n new URLSearchParams(\n tokenRequestId ? { token_request_id: tokenRequestId } : {},\n ),\n);\n\ntype LookupCardDetailsRequestBody = {\n /**\n * Encrypted card number\n */\n card_number: string;\n};\n/**\n * Returns metadata about a card number.\n */\nexport const lookupCardDetails = endpoint<\n LookupCardDetailsRequestBody,\n BffCardDetails,\n string\n>(\"POST\", (sessionAuthKey) => `/api/sessions/${sessionAuthKey}/card_info`);\n\ntype GetPaymentOptionsRequest = {\n channel_code: string;\n channel_properties?: {\n card_number: string;\n };\n};\n/**\n * Returns the list of installment plans available if possible.\n */\nexport const getPaymentOptions = endpoint<\n GetPaymentOptionsRequest,\n BffPaymentOptions,\n string\n>(\n \"POST\",\n (sessionAuthKey) => `/api/sessions/${sessionAuthKey}/payment_options`,\n);\n","import { assertIsArray, assertIsNotArray } from \"../utils\";\n\n/**\n * A node in a behavior tree.\n */\nexport type BehaviorNodeSingle<BB extends object> = {\n impl: BehaviorConstructor<BB>;\n key: string;\n child: BehaviorNode<BB> | undefined;\n instance: Behavior | undefined;\n};\n\nexport type BehaviorNode<BB extends object> =\n | BehaviorNodeSingle<BB>\n | (BehaviorNodeSingle<BB> | undefined)[];\n\n/**\n * Creates a behavior tree node.\n *\n * Takes a constructor implementing Behavior and a unique key. Nodes that are different from the previous tree\n * are removed and replaced. \"different\" means either the constructor or the key is different.\n *\n * The BB (blackboard) is data shared between all nodes in the tree. It is mutable.\n */\nexport function behaviorNode<BB extends object>(\n impl: BehaviorConstructor<BB>,\n key?: string,\n child?: BehaviorNode<BB>,\n): BehaviorNodeSingle<BB> {\n return {\n impl,\n key: key ?? \"\",\n child,\n instance: undefined,\n };\n}\n\n/**\n * A behavior implementation constructor.\n */\nexport interface BehaviorConstructor<BB extends object> {\n new (blackboard: BB, key: string): Behavior;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type AnyBehaviorConstructor = BehaviorConstructor<any>;\n\nexport interface Behavior {\n /**\n * Called when entering this behavior\n */\n enter?(): void;\n /**\n * Called when a tree is updated but this node is not changed.\n */\n update?(): void;\n /**\n * Called when exiting this behavior\n */\n exit?(): void;\n}\n\n/**\n * A behavior tree.\n * https://en.wikipedia.org/wiki/Behavior_tree_(artificial_intelligence,_robotics_and_control)\n *\n * Updating a tree diffs the nodes and calls enter on new nodes and exit on removed nodes.\n */\nexport class BehaviorTree<BB extends object> {\n root: BehaviorNode<BB> = behaviorNode(class {});\n\n // whether an update is in progress\n updating: boolean = false;\n // whether another update is requested\n again: boolean = false;\n\n constructor(\n private fn: (bb: BB) => BehaviorNode<BB>,\n public bb: BB,\n ) {}\n\n update(): void {\n // flag to scheule an update\n this.again = true;\n\n if (this.updating) {\n // if this gets called recursively, just return, the outermost call will handle it\n return;\n }\n\n let updateCount = 0;\n\n try {\n this.updating = true;\n while (this.again) {\n this.again = false;\n updateCount += 1;\n assertMaxRecursionDepth(updateCount);\n\n const prev = this.root ?? undefined;\n const next = this.fn(this.bb);\n this.root = next;\n\n updateTree(prev, next, this.bb, 0);\n }\n } finally {\n this.updating = false;\n }\n }\n\n findBehavior<T extends AnyBehaviorConstructor>(\n constructor: T,\n ): InstanceType<T> | null {\n return findBehavior(this.root, constructor);\n }\n}\n\nfunction assertMaxRecursionDepth(depth: number) {\n if (depth > 32) {\n throw new Error(\n \"Max recursion depth exceeded; this is a bug, please contact support.\",\n );\n }\n}\n\nfunction isChanged<BB extends object>(\n prev: BehaviorNode<BB> | undefined,\n next: BehaviorNode<BB> | undefined,\n) {\n if (prev === undefined || next === undefined) {\n return true;\n }\n\n if (Array.isArray(prev) !== Array.isArray(next)) {\n // if it changed from an array to a non-array or vice versa, it is changed\n return true;\n }\n\n if (Array.isArray(prev) && Array.isArray(next)) {\n // if both are arrays, they aren't \"changed\" because arrays are functionally the same, but their children might be changed\n return false;\n }\n\n // they must both be non-arrays here\n assertIsNotArray(prev);\n assertIsNotArray(next);\n\n return prev.impl !== next.impl || prev.key !== next.key;\n}\n\nfunction updateTree<BB extends object>(\n prev: BehaviorNode<BB> | undefined,\n next: BehaviorNode<BB> | undefined,\n bb: BB,\n depth: number,\n) {\n assertMaxRecursionDepth(depth);\n\n if (isChanged(prev, next)) {\n // after we find a change, exit the previous nodes\n if (prev) {\n exitSubtree(prev, depth + 1);\n }\n // then enter the new nodes\n if (next) {\n enterSubtree(next, bb, depth + 1);\n }\n } else {\n // the nodes are equal\n if (Array.isArray(prev) || Array.isArray(next)) {\n // if the nodes are arrays, just update their children\n // (assert they are both arrays to keep typescript happy (we already checked that))\n assertIsArray(prev);\n assertIsArray(next);\n const maxLength = Math.max(prev.length, next.length);\n for (let i = 0; i < maxLength; i++) {\n updateTree(prev[i], next[i], bb, depth + 1);\n }\n } else {\n // if the nodes are not arrays, move the instance to the new node and update its child\n if (next) {\n next.instance = prev?.instance;\n }\n if (prev) {\n prev.instance = undefined;\n }\n updateTree(prev?.child, next?.child, bb, depth + 1);\n next?.instance?.update?.();\n }\n }\n}\n\nfunction enterSubtree<BB extends object>(\n node: BehaviorNode<BB>,\n bb: BB,\n depth: number,\n) {\n assertMaxRecursionDepth(depth);\n\n // handle parallel nodes\n if (Array.isArray(node)) {\n for (const child of node) {\n if (!child) continue;\n enterSubtree(child, bb, depth + 1);\n }\n return;\n }\n\n // construct instances and call enter traversing downwards\n node.instance = new node.impl(bb, node.key);\n node.instance.enter?.();\n if (node.child) {\n enterSubtree(node.child, bb, depth + 1);\n }\n}\n\nfunction exitSubtree<BB extends object>(node: BehaviorNode<BB>, depth: number) {\n assertMaxRecursionDepth(depth);\n\n // handle parallel nodes\n if (Array.isArray(node)) {\n for (const child of node) {\n if (!child) continue;\n exitSubtree(child, depth + 1);\n }\n return;\n }\n\n // call exit traversing upwards\n if (node.child) {\n exitSubtree(node.child, depth + 1);\n }\n node.instance?.exit?.();\n node.instance = undefined;\n}\n\nexport function flattenBehaviors<BB extends object>(\n node: BehaviorNode<BB>,\n): BehaviorNodeSingle<BB>[] {\n const result: BehaviorNodeSingle<BB>[] = [];\n function traverse(node: BehaviorNode<BB>) {\n if (Array.isArray(node)) {\n for (const child of node) {\n if (!child) continue;\n traverse(child);\n }\n } else {\n result.push(node);\n if (node.child) {\n traverse(node.child);\n }\n }\n }\n traverse(node);\n return result;\n}\n\nfunction findBehavior<BB extends object, T extends AnyBehaviorConstructor>(\n node: BehaviorNode<BB>,\n constructor: T,\n): InstanceType<T> | null {\n if (Array.isArray(node)) {\n for (const child of node) {\n if (!child) continue;\n const result = findBehavior(child, constructor);\n if (result) {\n return result;\n }\n }\n } else {\n if (node.impl === constructor) {\n return (node.instance as InstanceType<T>) ?? null;\n } else {\n if (node.child) {\n return findBehavior(node.child, constructor);\n }\n }\n }\n\n return null;\n}\n","import { BlackboardType } from \"../behavior-tree\";\nimport { Behavior } from \"../behavior-tree-runner\";\n\nexport class ActionCompletedBehavior implements Behavior {\n constructor(private bb: BlackboardType) {}\n enter() {}\n}\n","import { FunctionComponent } from \"preact\";\n\ntype Props = {\n title: string;\n subtitle?: string;\n logoUrl: string;\n logoAlt: string;\n redirectUrl: string | null;\n redirectButtonLabel: string | null;\n};\n\nconst RedirectInstructions: FunctionComponent<Props> = (props) => {\n return (\n <div className=\"xendit-redirect-instructions\">\n <div className=\"xendit-redirect-instructions-logo\">\n <img src={props.logoUrl} alt={props.logoAlt} />\n </div>\n\n <div className=\"xendit-redirect-instructions-text\">\n <div className=\"xendit-text-16\">{props.title}</div>\n {props.subtitle ? (\n <div className=\"xendit-text-14 xendit-text-secondary\">\n {props.subtitle}\n </div>\n ) : null}\n </div>\n\n {props.redirectUrl ? (\n <a\n href={props.redirectUrl}\n className=\"xendit-redirect-instructions-button xendit-text-14\"\n >\n {props.redirectButtonLabel ?? \"\"}\n </a>\n ) : null}\n </div>\n );\n};\n\nexport { RedirectInstructions };\n","import { FunctionComponent } from \"preact\";\nimport { RedirectInstructions } from \"./redirect-instructions\";\nimport { TFunction } from \"../localization\";\nimport { BffChannel } from \"../backend-types/channel\";\n\ntype Props = {\n t: TFunction;\n channel: BffChannel;\n redirectUrl: string | null;\n};\n\nexport const ActionDeepLink: FunctionComponent<Props> = (props) => {\n const t = props.t;\n const channel = props.channel;\n const channelName = channel.brand_name;\n\n return (\n <RedirectInstructions\n title={t(\"action_deeplink.title\")}\n subtitle={t(\"action_deeplink.instructions\", {\n channelName,\n })}\n logoUrl={channel.brand_logo_url}\n logoAlt={t(\"image_alt.channel_logo\", {\n channelName,\n })}\n redirectUrl={props.redirectUrl}\n redirectButtonLabel={t(\"action_deeplink.button\", {\n channelName,\n })}\n />\n );\n};\n","import { useCallback, useLayoutEffect, useRef } from \"preact/hooks\";\nimport Icon from \"../icon\";\nimport { ComponentChildren, FunctionComponent } from \"preact\";\n\ntype Props = {\n /**\n * Title shown above the border.\n */\n title: string;\n /**\n * Called on close (after animation).\n */\n onClose: () => void;\n /**\n * If true, close the dialog on the next render. The animation will play then onClose will be called.\n */\n close?: boolean;\n children?: ComponentChildren;\n /**\n * if true, the header will float on top of the body content without a dividing line\n */\n seamless?: boolean;\n /**\n * Remove padding on body element.\n */\n noPadding?: boolean;\n /**\n * Borders of the dialog.\n */\n borderColor?: string;\n};\n\nexport const Dialog: FunctionComponent<Props> = (props) => {\n const { title, onClose, children, seamless, borderColor } = props;\n\n const closeCalledRef = useRef(false);\n const closeAnimationPlaying = useRef(false);\n\n const dialogRef = useRef<HTMLDivElement>(null);\n const backdropRef = useRef<HTMLDivElement>(null);\n\n const supportsAnimation = HTMLElement.prototype.animate !== undefined;\n\n // call close callback only once\n const onCloseSafe = useCallback(() => {\n if (closeCalledRef.current) return;\n closeCalledRef.current = true;\n onClose();\n }, [onClose]);\n\n // play fade-out animation then call close callback\n const onCloseWithAnimation = useCallback(() => {\n if (\n !dialogRef.current ||\n !backdropRef.current ||\n closeAnimationPlaying.current\n ) {\n return;\n }\n closeAnimationPlaying.current = true;\n\n if (!supportsAnimation) {\n onCloseSafe();\n return;\n }\n\n backdropRef.current.animate?.(\n backdropFadeOutKeyframes,\n animationOptionsOut,\n );\n const animation = dialogRef.current.animate?.(\n foregroundFadeOutKeyframes,\n animationOptionsOut,\n );\n animation.onfinish = onCloseSafe;\n }, [onCloseSafe, supportsAnimation]);\n\n // play fade-in animation\n useLayoutEffect(() => {\n if (!supportsAnimation) {\n return;\n }\n\n backdropRef.current?.animate?.(backdropFadeKeyframes, animationOptionsIn);\n dialogRef.current?.animate?.(foregroundFadeKeyframes, animationOptionsIn);\n }, [supportsAnimation]);\n\n useLayoutEffect(() => {\n if (props.close) {\n onCloseWithAnimation();\n }\n }, [props.close, onCloseWithAnimation]);\n\n return (\n <div className=\"xendit-dialog-backdrop\" ref={backdropRef}>\n <div\n className={`xendit-dialog`}\n ref={dialogRef}\n style={borderColor ? { border: `4px solid ${borderColor}` } : undefined}\n >\n {!seamless ? (\n <div className=\"xendit-dialog-header xendit-text-16 xendit-text-semibold\">\n {title}\n <button aria-label=\"Close\" onClick={onCloseWithAnimation}>\n <Icon name=\"x\" size={20} />\n </button>\n </div>\n ) : null}\n <div\n className=\"xendit-dialog-body\"\n style={props.noPadding ? { padding: \"0\" } : undefined}\n >\n {children}\n </div>\n {seamless ? (\n <button\n aria-label=\"Close\"\n onClick={onCloseWithAnimation}\n className=\"xendit-dialog-floating-close\"\n >\n <Icon name=\"x\" size={20} />\n </button>\n ) : null}\n </div>\n </div>\n );\n};\n\nconst animationOptionsIn: EffectTiming = {\n duration: 500,\n easing: \"cubic-bezier(.32,.23,0,.92)\",\n fill: \"forwards\",\n};\n\nconst animationOptionsOut: EffectTiming = {\n duration: 200,\n easing: \"linear\",\n fill: \"forwards\",\n};\n\nconst backdropFadeKeyframes: Keyframe[] = [\n {\n backgroundColor: \"rgba(0, 0, 0, 0)\",\n },\n {\n backgroundColor: \"rgba(0, 0, 0, 0.2)\",\n offset: 0.1,\n },\n {\n backgroundColor: \"rgba(0, 0, 0, 0.6)\",\n },\n];\nconst backdropFadeOutKeyframes = backdropFadeKeyframes.slice().reverse();\n\nconst foregroundFadeKeyframes: Keyframe[] = [\n {\n opacity: 0,\n transform: `scale(0.98) translateY(-40px) rotateX(15deg)`,\n },\n {\n opacity: 0,\n transform: `scale(0.98) translateY(-40px) rotateX(15deg)`,\n },\n {\n opacity: 1,\n transform: \"\",\n },\n];\n\nconst foregroundFadeOutKeyframes: Keyframe[] = [\n {\n opacity: 1,\n transform: \"\",\n },\n {\n opacity: 0,\n transform: `scale(0.92) translateY(-10px)`,\n },\n];\n","import { useLayoutEffect, useRef } from \"preact/hooks\";\nimport { XenditComponents } from \"../public-sdk\";\nimport { Dialog } from \"./core/dialog\";\nimport { internal } from \"../internal\";\nimport { DefaultActionContainerType } from \"../lifecycle/behaviors/action\";\n\ntype Props = {\n sdk: XenditComponents;\n title: string;\n close?: boolean;\n onClose: () => void;\n width: number;\n height: number;\n borderColor?: string;\n defaultActionContainerType: DefaultActionContainerType;\n};\n\nexport default function DefaultActionContainer(props: Props) {\n const { sdk, title, onClose, width, height, borderColor } = props;\n\n const wrapperRef = useRef<HTMLDivElement>(null);\n useLayoutEffect(() => {\n const component = sdk.createActionContainerComponent(internal);\n wrapperRef.current?.replaceChildren(component);\n return () => {\n sdk.destroyComponent(component);\n };\n }, [sdk]);\n\n return (\n <Dialog\n title={title}\n onClose={onClose}\n close={props.close}\n borderColor={borderColor}\n noPadding={\n props.defaultActionContainerType ===\n DefaultActionContainerType.QrWithCustomArt\n }\n seamless\n >\n <div\n className=\"xendit-default-action-container\"\n ref={wrapperRef}\n style={{\n width: width\n ? `calc(min(100vw - 64px, ${width}px))`\n : \"calc(100vw - 64px)\",\n height: height ? `calc(min(100vh - 64px, ${height}px))` : undefined,\n }}\n />\n </Dialog>\n );\n}\n","import { createElement, render, ComponentChildren } from \"preact\";\nimport { assert } from \"../../utils\";\nimport { BlackboardType } from \"../behavior-tree\";\nimport { Behavior } from \"../behavior-tree-runner\";\nimport { internal } from \"../../internal\";\nimport DefaultActionContainer from \"../../components/default-action-container\";\n\nexport enum DefaultActionContainerType {\n QrWithCustomArt = \"qr-with-custom-art\",\n Generic = \"generic\",\n}\n\nexport abstract class ContainerActionBehavior implements Behavior {\n cleanupFn: ((cancelledByUser: boolean) => void) | null = null;\n defaultContainerHeight = 0;\n defaultContainerWidth = 400;\n title = \"Complete your payment\";\n\n constructor(protected bb: BlackboardType) {}\n\n /**\n * Creates a default action container if the user has not created one already.\n * Returns a cleanup function that destroys the default action container if it was created.\n */\n ensureHasActionContainer(\n defaultActionContainerType: DefaultActionContainerType = DefaultActionContainerType.Generic,\n ) {\n assert(this.bb.channel);\n\n if (this.bb.sdk[internal].liveComponents.actionContainer) {\n // user created action container already\n // TODO: validate it's in the dom and the right size\n return () => {\n this.emptyActionContainer();\n };\n }\n\n let cleanedUp = false;\n let success = false;\n\n const container = document.createElement(\"div\");\n container.setAttribute(\"class\", \"xendit-default-action-container\");\n\n const props: Parameters<typeof DefaultActionContainer>[0] = {\n sdk: this.bb.sdk,\n title: this.title,\n width: this.defaultContainerWidth,\n height: this.defaultContainerHeight,\n borderColor: undefined, // needs some design feedback\n // borderColor: this.bb.channel.brand_color,\n defaultActionContainerType,\n onClose: () => {\n cleanedUp = true;\n render(null, container);\n container.remove();\n if (!success) {\n this.bb.sdk.abortSubmission();\n }\n },\n };\n\n render(createElement(DefaultActionContainer, props), container);\n document.body.appendChild(container);\n\n // Cleanup function\n // (if actionCancelledByUser is true, abort the submission after the modal closes)\n return (actionCancelledByUser: boolean) => {\n if (!actionCancelledByUser) {\n success = true;\n }\n\n if (cleanedUp) return;\n\n // make the dialog play its close animation before removing it\n render(\n createElement(DefaultActionContainer, {\n ...props,\n close: true,\n }),\n container,\n );\n };\n }\n\n cleanupActionContainer(cancelledByUser: boolean) {\n if (this.cleanupFn) {\n this.cleanupFn(cancelledByUser);\n this.cleanupFn = null;\n }\n }\n\n emptyActionContainer() {\n const container = this.bb.sdk[internal].liveComponents.actionContainer;\n if (container) {\n render(null, container);\n }\n }\n\n updateActionContainerBrandColor() {\n assert(this.bb.channel);\n\n const container = this.bb.sdk[internal].liveComponents.actionContainer;\n if (container) {\n container.style.setProperty(\n \"--xendit-channel-brand-color\",\n this.bb.channel.brand_color,\n );\n }\n }\n\n /**\n * Populates the action container with the provided component.\n * This method handles the common logic of getting the container and rendering the component.\n */\n populateActionContainer(createComponent: () => ComponentChildren) {\n const container = this.bb.sdk[internal].liveComponents.actionContainer;\n if (!container) {\n throw new Error(\n \"Trying to populate action container, but it is missing; A default action container should have been created. This is a bug, please contact support.\",\n );\n }\n\n this.updateActionContainerBrandColor();\n\n render(createComponent(), container);\n }\n\n exit() {\n this.cleanupActionContainer(false);\n this.emptyActionContainer();\n }\n}\n","import { createElement } from \"preact\";\nimport { ActionDeepLink } from \"../../components/action-deep-link\";\nimport { assert, assertEquals } from \"../../utils\";\nimport { BlackboardType } from \"../behavior-tree\";\nimport { ContainerActionBehavior } from \"./action\";\n\n/**\n * An empty list of actions means the user has to take some action on their own, like tapping a push notification.\n */\nexport class ActionDeepLinkBehavior extends ContainerActionBehavior {\n constructor(\n protected bb: BlackboardType,\n private actionIndex: string,\n ) {\n super(bb);\n }\n\n enter() {\n assert(this.bb.world);\n\n const deepLinkAction =\n this.bb.world?.paymentEntity?.entity.actions[Number(this.actionIndex)];\n assertEquals(deepLinkAction?.type, \"REDIRECT_CUSTOMER\");\n\n if (\n deepLinkAction.descriptor !== \"DEEPLINK_URL\" &&\n deepLinkAction.descriptor !== \"WEB_URL\"\n ) {\n // The deeplink popup can also handle regular web urls (if paylinks are enabled, that's useful to prevent auto-redirects)\n throw new Error(\"Unexpected action type in ActionDeepLinkBehavior\");\n }\n\n const t = this.bb.sdk.t.bind(this.bb.sdk);\n const channel = this.bb.channel;\n assert(channel);\n\n this.cleanupFn = this.ensureHasActionContainer();\n this.populateActionContainer(() => {\n return createElement(ActionDeepLink, {\n t,\n channel,\n redirectUrl: deepLinkAction.value,\n });\n });\n }\n\n exit() {\n super.exit();\n }\n}\n","import { FunctionComponent } from \"preact\";\nimport { RedirectInstructions } from \"./redirect-instructions\";\nimport { TFunction } from \"../localization\";\nimport { BffChannel } from \"../backend-types/channel\";\n\ntype Props = {\n t: TFunction;\n channel: BffChannel;\n};\n\nexport const ActionEmptyListPushNotification: FunctionComponent<Props> = (\n props,\n) => {\n const t = props.t;\n const channel = props.channel;\n const channelName = channel.brand_name;\n\n return (\n <RedirectInstructions\n title={t(\"action_empty_list_push_notification.title\")}\n subtitle={t(\"action_empty_list_push_notification.subtext\", {\n channelName,\n })}\n logoUrl={channel.brand_logo_url}\n logoAlt={t(\"image_alt.channel_logo\", {\n channelName,\n })}\n redirectUrl={null}\n redirectButtonLabel={null}\n />\n );\n};\n","import { Instructions } from \"./instructions\";\n\nexport type BffAction =\n | {\n type: \"PRESENT_TO_CUSTOMER\";\n descriptor: \"PAYMENT_CODE\" | \"QR_STRING\" | \"VIRTUAL_ACCOUNT_NUMBER\";\n value: string;\n action_title: string;\n action_subtitle: string;\n action_graphic: string;\n instructions?: Instructions | null;\n }\n | {\n type: \"REDIRECT_CUSTOMER\";\n descriptor: \"WEB_URL\" | \"DEEPLINK_URL\" | \"WEB_GOOGLE_PAYLINK\";\n value: string;\n // indicates whether the redirect URL can be opened in an iframe\n // defaults to true since this isn't returned from backend yet\n // TODO: return this flag from backend\n iframe_capable?: boolean;\n }\n | {\n type: \"API_POST_REQUEST\";\n descriptor: \"CAPTURE_PAYMENT\" | \"VALIDATE_OTP\" | \"RESEND_OTP\";\n value: string;\n otp?: {\n title: string;\n instructions: string;\n };\n };\n\nexport type BffPaymentTokenStatus =\n | \"REQUIRES_ACTION\"\n | \"PENDING\"\n | \"ACTIVE\"\n | \"FAILED\"\n | \"EXPIRED\"\n | \"CANCELED\";\n\nexport type BffPaymentTokenFailureCode =\n | \"ACCOUNT_ALREADY_LINKED\"\n | \"INVALID_ACCOUNT_DETAILS\"\n | \"AUTHENTICATION_FAILED\"\n | \"CARD_DECLINED\"\n | \"CAPTURE_AMOUNT_EXCEEDED\"\n | \"INSUFFICIENT_BALANCE\"\n | \"ISSUER_UNAVAILABLE\"\n | \"CHANNEL_UNAVAILABLE\"\n | \"INVALID_MERCHANT_SETTINGS\";\n\nexport type BffPaymentToken = {\n payment_token_id: string;\n status: BffPaymentTokenStatus;\n failure_code?: BffPaymentTokenFailureCode;\n actions: BffAction[];\n channel_code: string;\n /**\n * Only returned when the payment request is created, not on polling\n */\n session_token_request_id?: string;\n};\n\nexport type BffPaymentRequestStatus =\n | \"ACCEPTING_PAYMENTS\"\n | \"REQUIRES_ACTION\"\n | \"PENDING\"\n | \"AUTHORIZED\"\n | \"CANCELED\"\n | \"EXPIRED\"\n | \"SUCCEEDED\"\n | \"FAILED\";\n\nexport type BffPaymentRequestFailureCode =\n | \"ACCOUNT_ACCESS_BLOCKED\"\n | \"INVALID_MERCHANT_SETTINGS\"\n | \"INVALID_ACCOUNT_DETAILS\"\n | \"PAYMENT_ATTEMPT_COUNTS_EXCEEDED\"\n | \"USER_DEVICE_UNREACHABLE\"\n | \"CHANNEL_UNAVAILABLE\"\n | \"INSUFFICIENT_BALANCE\"\n | \"ACCOUNT_NOT_ACTIVATED\"\n | \"INVALID_TOKEN\"\n | \"SERVER_ERROR\"\n | \"PARTNER_TIMEOUT_ERROR\"\n | \"TIMEOUT_ERROR\"\n | \"USER_DECLINED_PAYMENT\"\n | \"USER_DID_NOT_AUTHORIZE\"\n | \"PAYMENT_REQUEST_EXPIRED\"\n | \"FAILURE_DETAILS_UNAVAILABLE\"\n | \"EXPIRED_OTP\"\n | \"INVALID_OTP\"\n | \"PAYMENT_AMOUNT_LIMITS_EXCEEDED\"\n | \"OTP_ATTEMPT_COUNTS_EXCEEDED\"\n | \"CARD_DECLINED\"\n | \"DECLINED_BY_ISSUER\"\n | \"ISSUER_UNAVAILABLE\"\n | \"INVALID_CVV\"\n | \"DECLINED_BY_PROCESSOR\"\n | \"CAPTURE_AMOUNT_EXCEEDED\"\n | \"AUTHENTICATION_FAILED\";\n\nexport type BffPaymentRequest = {\n payment_request_id: string;\n status: BffPaymentRequestStatus;\n failure_code?: BffPaymentRequestFailureCode;\n actions: BffAction[];\n channel_code: string;\n /**\n * Only returned when the payment request is created, not on polling\n */\n session_token_request_id?: string;\n};\n\nexport enum BffPaymentEntityType {\n PaymentRequest = \"REQUEST\",\n PaymentToken = \"TOKEN\",\n}\n\nexport type BffPaymentEntity =\n | {\n id: string;\n type: BffPaymentEntityType.PaymentRequest;\n entity: BffPaymentRequest;\n }\n | {\n id: string;\n type: BffPaymentEntityType.PaymentToken;\n entity: BffPaymentToken;\n };\n\nexport function toPaymentEntity(\n prOrPt: BffPaymentRequest | BffPaymentToken,\n): BffPaymentEntity {\n if (\"payment_request_id\" in prOrPt) {\n return {\n id: prOrPt.payment_request_id,\n type: BffPaymentEntityType.PaymentRequest,\n entity: prOrPt,\n };\n } else {\n return {\n id: prOrPt.payment_token_id,\n type: BffPaymentEntityType.PaymentToken,\n entity: prOrPt,\n };\n }\n}\n\nexport function getFailureCodeCopyKey<\n T extends NonNullable<\n BffPaymentRequestFailureCode | BffPaymentTokenFailureCode\n >,\n>(failureCode: T) {\n return `failure_code.${failureCode.toLowerCase() as Lowercase<T>}` as const;\n}\n\nexport function getPaymentEntityStatusCopyKey<\n T extends\n | BffPaymentEntityType.PaymentRequest\n | BffPaymentEntityType.PaymentToken,\n S extends \"FAILED\" | \"EXPIRED\" | \"CANCELED\",\n const Suffix extends string,\n>(entityType: T, status: S, suffix: Suffix) {\n const t =\n entityType === BffPaymentEntityType.PaymentRequest\n ? \"payment_request\"\n : \"payment_token\";\n return `${t}_status.${\n status.toLowerCase() as Lowercase<S>\n }.${suffix}` as const;\n}\n","import {\n BffChannel,\n MockActionType,\n MockActionTypeSingle,\n} from \"../backend-types/channel\";\nimport { BffPollResponse } from \"../backend-types/common\";\nimport {\n BffAction,\n BffPaymentEntity,\n BffPaymentEntityType,\n BffPaymentRequest,\n BffPaymentRequestStatus,\n BffPaymentToken,\n BffPaymentTokenStatus,\n} from \"../backend-types/payment-entity\";\nimport { BffPaymentOptions } from \"../backend-types/payment-options\";\nimport { BffSession } from \"../backend-types/session\";\nimport { WorldState } from \"../public-sdk\";\nimport { assert, randomHexString, randomUUID } from \"../utils\";\n\nconst examplePublicKey =\n \"MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEyCADI5pdf6KmN8+Fxl2ES3yolUKXunNeY3gGScGNEvDcrcHAPKxIInAo5DVnDvTtYtqZvx/bu7HLeBJNMXwHhie/uyNEtT8dSaLc9bd0WSlYdxI+iUsTv2Qu0LiiPrZs\";\nconst exampleSignature =\n \"NKf7whM9meUs/eRCvG0oc180MDiyeli3kH6EQ3ZahECHsZQi5G2IpH6vk3cYMtf01Y1L4OBn1SZCOv1kwpjIUet4DJeoTwwq2nM5b+K7rD+/WFTi3AEX4NWJNkKi0a91\";\n\nexport function makeTestSdkKey() {\n return `session-${randomHexString(32)}-mock-${examplePublicKey}-${exampleSignature}`;\n}\n\nexport function makeTestPollResponse(\n world: WorldState,\n channel: BffChannel | null,\n result: \"SUCCESS\" | \"FAILURE\" | \"PENDING\" | \"PENDING_PAYMENT_ENTITY_ONLY\",\n) {\n const { session, paymentEntity } = world;\n assert(session);\n assert(paymentEntity);\n assert(channel);\n\n switch (result) {\n case \"PENDING\":\n // make the session pending\n return makeTestPollResponseForPending(session);\n case \"PENDING_PAYMENT_ENTITY_ONLY\":\n // make the payment entity pending, but keep the session active\n return makeTestPollResponseForPendingPaymentEntityOnly(\n session,\n paymentEntity,\n );\n case \"SUCCESS\": {\n if (channel._mock_action_type === \"PENDING\") {\n // channels with mock pending state (like FPX) always go to pending state when success is requested\n return makeTestPollResponseForPending(session);\n } else {\n return makeTestPollResponseForSuccess(session, paymentEntity);\n }\n }\n case \"FAILURE\":\n return makeTestPollResponseForFailure(session, paymentEntity);\n }\n}\n\nexport function makeTestPollResponseForPending(\n session: BffSession,\n): BffPollResponse {\n return {\n session: {\n ...session,\n status: \"PENDING\",\n },\n };\n}\n\nexport function makeTestPollResponseForPendingPaymentEntityOnly(\n session: BffSession,\n paymentEntity: BffPaymentEntity,\n): BffPollResponse {\n const paymentRequest =\n paymentEntity.type === BffPaymentEntityType.PaymentRequest\n ? paymentEntity.entity\n : undefined;\n const paymentToken =\n paymentEntity.type === BffPaymentEntityType.PaymentToken\n ? paymentEntity.entity\n : undefined;\n\n return {\n session,\n payment_request: withPaymentEntityStatus(paymentRequest, \"PENDING\"),\n payment_token: withPaymentEntityStatus(paymentToken, \"PENDING\"),\n };\n}\n\nexport function makeTestPollResponseForSuccess(\n session: BffSession,\n paymentEntity: BffPaymentEntity,\n): BffPollResponse {\n const paymentRequest =\n paymentEntity.type === BffPaymentEntityType.PaymentRequest\n ? paymentEntity.entity\n : undefined;\n const paymentToken =\n paymentEntity.type === BffPaymentEntityType.PaymentToken\n ? paymentEntity.entity\n : undefined;\n\n return {\n session: {\n ...session,\n status: \"COMPLETED\",\n payment_request_id: paymentRequest?.payment_request_id,\n payment_token_id: paymentToken?.payment_token_id,\n },\n payment_request: withPaymentEntityStatus(paymentRequest, \"SUCCEEDED\"),\n payment_token: withPaymentEntityStatus(paymentToken, \"ACTIVE\"),\n succeeded_channel: {\n channel_code: paymentEntity.entity.channel_code,\n logo_url: \"https://placehold.co/48\",\n },\n };\n}\n\nexport function makeTestPollResponseForFailure(\n session: BffSession,\n paymentEntity: BffPaymentEntity,\n): BffPollResponse {\n const paymentRequest =\n paymentEntity.type === BffPaymentEntityType.PaymentRequest\n ? paymentEntity.entity\n : undefined;\n const paymentToken =\n paymentEntity.type === BffPaymentEntityType.PaymentToken\n ? paymentEntity.entity\n : undefined;\n\n return {\n session: {\n ...session,\n status: \"ACTIVE\",\n },\n payment_request: withPaymentEntityStatus(paymentRequest, \"FAILED\"),\n payment_token: withPaymentEntityStatus(paymentToken, \"FAILED\"),\n };\n}\n\nexport function withPaymentEntityStatus<\n T extends BffPaymentRequest | BffPaymentToken | undefined,\n>(\n prOrPt: T,\n status: T extends BffPaymentRequest\n ? BffPaymentRequestStatus\n : T extends BffPaymentToken\n ? BffPaymentTokenStatus\n : undefined,\n): T {\n if (!prOrPt) return prOrPt;\n return {\n ...prOrPt,\n status: status,\n };\n}\n\nexport function makeTestPaymentRequest(\n channelCode: string,\n mockActionType: MockActionType | undefined,\n): BffPaymentRequest {\n if (mockActionType === \"PENDING\") {\n return {\n payment_request_id: `pr-${randomUUID()}`,\n status: \"PENDING\",\n channel_code: channelCode,\n actions: [],\n session_token_request_id: randomUUID(),\n };\n } else if (mockActionType) {\n return {\n payment_request_id: `pr-${randomUUID()}`,\n status: \"REQUIRES_ACTION\",\n channel_code: channelCode,\n actions: makeMockActions(mockActionType),\n session_token_request_id: randomUUID(),\n };\n } else {\n return {\n payment_request_id: `pr-${randomUUID()}`,\n status: \"SUCCEEDED\",\n channel_code: channelCode,\n actions: [],\n session_token_request_id: randomUUID(),\n };\n }\n}\n\nexport function makeTestPaymentToken(\n channelCode: string,\n mockActionType: MockActionType | undefined,\n): BffPaymentToken {\n if (mockActionType === \"PENDING\") {\n return {\n payment_token_id: `pt-${randomUUID()}`,\n status: \"PENDING\",\n channel_code: channelCode,\n actions: makeMockActions(mockActionType),\n session_token_request_id: randomUUID(),\n };\n } else if (mockActionType) {\n return {\n payment_token_id: `pt-${randomUUID()}`,\n status: \"REQUIRES_ACTION\",\n channel_code: channelCode,\n actions: makeMockActions(mockActionType),\n session_token_request_id: randomUUID(),\n };\n } else {\n return {\n payment_token_id: `pt-${randomUUID()}`,\n status: \"ACTIVE\",\n channel_code: channelCode,\n actions: [],\n session_token_request_id: randomUUID(),\n };\n }\n}\n\nexport function makeMockActions(\n mockActionType: MockActionType | undefined,\n): BffAction[] {\n if (!mockActionType) return [];\n const mockActionArray = Array.isArray(mockActionType)\n ? mockActionType\n : [mockActionType];\n const mockActions = mockActionArray\n .map((actionType) => makeOneMockAction(actionType))\n .filter((action) => action !== null);\n return mockActions;\n}\n\nexport function makeOneMockAction(\n mockActionType: MockActionTypeSingle,\n): BffAction | null {\n if (mockActionType === \"PENDING\") {\n throw new Error(\"PENDING mock action type should not generate an action\");\n }\n\n switch (mockActionType) {\n case \"IFRAME\":\n return {\n type: \"REDIRECT_CUSTOMER\",\n descriptor: \"WEB_URL\",\n value: \"https://example.com/iframe\",\n iframe_capable: true,\n };\n case \"REDIRECT\":\n return {\n type: \"REDIRECT_CUSTOMER\",\n descriptor: \"WEB_URL\",\n value: \"https://example.com/redirect\",\n iframe_capable: false,\n };\n case \"PAYLINK\":\n return {\n type: \"REDIRECT_CUSTOMER\",\n descriptor: \"WEB_GOOGLE_PAYLINK\",\n value: \"https://example.com/paylink\",\n };\n case \"DEEP_LINK\":\n return {\n type: \"REDIRECT_CUSTOMER\",\n descriptor: \"DEEPLINK_URL\",\n value: \"mockapp://mock-deep-link\",\n };\n case \"PUSH_NOTIFICATION\": {\n // push notification actions are represented by setting `{ status: \"REQUIRES_ACTION\", actions: [] }`\n return null;\n }\n case \"QR\":\n return {\n type: \"PRESENT_TO_CUSTOMER\",\n descriptor: \"QR_STRING\",\n value: \"https://example.com/qr-code-data\",\n action_title: \"Pay with QR Code\",\n action_subtitle: \"Scan the QR code below\",\n action_graphic: \"\",\n instructions: null,\n };\n case \"BARCODE\":\n return {\n type: \"PRESENT_TO_CUSTOMER\",\n descriptor: \"PAYMENT_CODE\",\n value: \"1234567890\",\n action_title: \"Pay at a Store\",\n action_subtitle: \"Show this barcode to the cashier\",\n action_graphic: \"\",\n instructions: null,\n };\n case \"VA\":\n return {\n type: \"PRESENT_TO_CUSTOMER\",\n descriptor: \"VIRTUAL_ACCOUNT_NUMBER\",\n value: \"1234567890\",\n action_title: \"Pay with Virtual Account\",\n action_subtitle:\n \"Protect yourself from fraud - ensure all details are correct\",\n action_graphic: \"\",\n instructions: [\n {\n title: \"Mobile Banking\",\n content: [\n {\n type: \"text\",\n text: \"Open Mobile App\",\n },\n {\n type: \"text\",\n text: \"Select <b>Mock VA</b>, then select <b>Transfer</b>\",\n },\n {\n type: \"text\",\n text: \"Enter your Virtual Account Number, for example 3816523906568, then press <b>OK</b>\",\n },\n {\n type: \"text\",\n text: \"Click on <b>Send</b> button at the top right corner to proceed\",\n },\n {\n type: \"text\",\n text: \"Click <b>OK</b> to proceed\",\n },\n {\n type: \"text\",\n text: \"Enter your PIN to authorize the transaction\",\n },\n ],\n },\n {\n title: \"Internet Banking\",\n content: [\n {\n type: \"text\",\n text: \"Login to the website\",\n },\n {\n type: \"text\",\n text: \"Select <b>Transfer</b>, then select <b>Transfer to Mock VA Virtual Account</b>\",\n },\n {\n type: \"text\",\n text: \"Enter the Virtual Account Number, for example 3816523906568\",\n },\n {\n type: \"text\",\n text: \"Select <b>Continue</b> to proceed your payment\",\n },\n ],\n },\n {\n title: \"ATM\",\n content: [\n {\n type: \"text\",\n text: \"Insert your ATM card and PIN\",\n },\n {\n type: \"text\",\n text: \"Enter your ATM PIN\",\n },\n {\n type: \"text\",\n text: \"Select <b>Transfer</b>\",\n },\n {\n type: \"text\",\n text: \"Select <b>To Mock VA Virtual Account</b>\",\n },\n {\n type: \"text\",\n text: \"Enter Virtual Account Number, for example 3816523906568. Press <b>Correct</b> to proceed\",\n },\n {\n type: \"text\",\n text: \"Verify Virtual Account details and then enter amount to be transferred and select <b>Correct</b> to confirm\",\n },\n {\n type: \"text\",\n text: \"Confirm your transaction details displayed\",\n },\n {\n type: \"text\",\n text: \"Select <b>Yes</b> if the details are correct or <b>No</b> if the details are not correct\",\n },\n ],\n },\n ],\n };\n }\n\n mockActionType satisfies never;\n throw new Error(`Unknown mock action type: ${mockActionType}`);\n}\n\nexport function makeMockPaymentOptions(\n channelCode: string,\n session: BffSession,\n): BffPaymentOptions {\n return {\n channel_code: channelCode,\n country: session.country,\n currency: session.currency,\n amount: session.amount,\n installment_plans: [\n {\n interval: \"MONTH\",\n interval_count: 1,\n terms: 3,\n installment_amount: Math.floor(session.amount / 3),\n total_amount: session.amount,\n description: `Unused`,\n code: \"3M\",\n interest_rate: 1,\n },\n {\n interval: \"MONTH\",\n interval_count: 1,\n terms: 6,\n installment_amount: Math.floor(session.amount / 6),\n total_amount: session.amount,\n description: `Unused`,\n code: \"6M\",\n interest_rate: 1,\n },\n {\n interval: \"MONTH\",\n interval_count: 1,\n terms: 9,\n installment_amount: Math.floor(session.amount / 9),\n total_amount: session.amount,\n description: `Unused`,\n interest_rate: 1,\n code: undefined, // this item has no code (like TH installment channels)\n },\n ],\n };\n}\n","import { createElement } from \"preact\";\nimport { assert } from \"../../utils\";\nimport { BlackboardType } from \"../behavior-tree\";\nimport { ContainerActionBehavior } from \"./action\";\nimport { ActionEmptyListPushNotification } from \"../../components/action-empty-list-push-notification\";\nimport { InternalScheduleMockUpdateEvent } from \"../../private-event-types\";\nimport { makeTestPollResponse } from \"../../data/test-data-modifiers\";\n\n/**\n * An empty list of actions means the user has to take some action on their own, like tapping a push notification.\n */\nexport class ActionEmptyListPushNotificationBehavior extends ContainerActionBehavior {\n constructor(protected bb: BlackboardType) {\n super(bb);\n }\n\n enter() {\n assert(this.bb.world);\n\n // Keep this behavior alive even if the payment entity status changes to pending.\n // Normally, the status would change to pending almost immediently and the action would be closed.\n // This helps keep it open until the user pays.\n this.bb.hackyOvoActionLatch = true;\n\n const t = this.bb.sdk.t.bind(this.bb.sdk);\n const channel = this.bb.channel;\n assert(channel);\n\n this.cleanupFn = this.ensureHasActionContainer();\n this.populateActionContainer(() => {\n return createElement(ActionEmptyListPushNotification, {\n t,\n channel,\n });\n });\n\n if (this.bb.mock) {\n this.bb.dispatchEvent(\n new InternalScheduleMockUpdateEvent(\n makeTestPollResponse(\n this.bb.world,\n this.bb.channel,\n \"PENDING_PAYMENT_ENTITY_ONLY\",\n ),\n ),\n );\n }\n }\n\n exit() {\n this.bb.hackyOvoActionLatch = undefined;\n super.exit();\n }\n}\n","import { useCallback, useLayoutEffect, useRef } from \"preact/hooks\";\nimport { IframeActionCompleteEvent } from \"../../../shared/types\";\n\ntype Props = {\n url: string;\n mock: boolean;\n channelCode: string;\n onIframeComplete: (event: IframeActionCompleteEvent) => void;\n};\n\nexport function ActionIframe(props: Props) {\n const { url, channelCode, mock, onIframeComplete } = props;\n\n const iframeRef = useRef<HTMLIFrameElement>(null);\n\n const handleEventFromIframe = useCallback(\n (event: MessageEvent) => {\n if (!iframeRef.current) return;\n\n const expectedSource = iframeRef.current.contentWindow;\n\n if (event.source !== expectedSource) {\n // we are not the target of this message\n return;\n }\n\n if (\n event.data?.type ===\n (\"xendit-iframe-action-complete\" satisfies IframeActionCompleteEvent[\"type\"])\n ) {\n onIframeComplete(event.data as IframeActionCompleteEvent);\n }\n },\n [onIframeComplete],\n );\n\n useLayoutEffect(() => {\n window.addEventListener(\"message\", handleEventFromIframe);\n return () => {\n window.removeEventListener(\"message\", handleEventFromIframe);\n };\n }, [handleEventFromIframe]);\n\n if (mock) {\n const authenticationTypeDescription =\n channelCode === \"CARDS\"\n ? \"a 3DS authentication page\"\n : \"an authentication page\";\n const srcDoc = mockIframeSrcDoc(authenticationTypeDescription);\n return (\n <iframe\n ref={iframeRef}\n srcDoc={srcDoc}\n className=\"xendit-action-iframe\"\n />\n );\n }\n\n return (\n <iframe\n ref={iframeRef}\n src={url}\n // sandbox=\"allow-scripts\"\n className=\"xendit-action-iframe\"\n />\n );\n}\n\nconst mockIframeSrcDoc = (whatItWouldBe: string) => `\n <html>\n <head>\n <title>Xendit Mock Action Iframe</title>\n <style>\n body {\n font-family: Arial, sans-serif;\n font-size: 14px;\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 12px;\n }\n p {\n margin: 0;\n }\n .buttons {\n display: flex;\n gap: 8px;\n }\n button {\n font-size: 12px;\n display: flex;\n align-items: center;\n text-align: left;\n background-color: white;\n border: 1px solid rgba(243, 243, 243);\n border-radius: 4px;\n justify-content: space-between;\n padding: 4px;\n cursor: pointer;\n }\n button:hover {\n border-color: #1762ee;\n background-color: #1762ee;\n color: white;\n }\n </style>\n </head>\n <body>\n <p>This is a mock action page.</p>\n <p>Normally, this would be ${whatItWouldBe}.</p>\n <p>Click a button below to simulate the result of the action.</p>\n <div class=\"buttons\">\n <button onclick=\"parent.postMessage({type: 'xendit-iframe-action-complete', mockStatus: 'success'}, '*')\">\n Simulate Success\n </button>\n <button onclick=\"parent.postMessage({type: 'xendit-iframe-action-complete', mockStatus: 'fail'}, '*')\">\n Simulate Failure\n </button>\n </div>\n </body>\n </html>\n`;\n","import { createElement } from \"preact\";\nimport { BlackboardType } from \"../behavior-tree\";\nimport { ContainerActionBehavior } from \"./action\";\nimport { ActionIframe } from \"../../components/action-iframe\";\nimport { IframeActionCompleteEvent } from \"../../../../shared/types\";\nimport {\n InternalBehaviorTreeUpdateEvent,\n InternalScheduleMockUpdateEvent,\n} from \"../../private-event-types\";\nimport { assert } from \"../../utils\";\nimport { makeTestPollResponse } from \"../../data/test-data-modifiers\";\n\nexport class ActionIframeBehavior extends ContainerActionBehavior {\n constructor(\n protected bb: BlackboardType,\n private url: string,\n ) {\n super(bb);\n this.defaultContainerHeight = 600;\n }\n\n enter() {\n this.cleanupFn = this.ensureHasActionContainer();\n this.populateActionContainer(() => {\n assert(this.bb.channel);\n return createElement(ActionIframe, {\n url: this.url,\n channelCode: this.bb.channel.channel_code,\n mock: this.bb.mock,\n onIframeComplete: (event: IframeActionCompleteEvent) => {\n this.cleanupActionContainer(false);\n\n const mockResult =\n event.mockStatus === \"success\" ? \"SUCCESS\" : \"FAILURE\";\n this.updateMocksOnIframeCompletion(mockResult);\n\n // setting actionCompleted will ensure the action UI isn't shown again\n this.bb.actionCompleted = true;\n // request immediate poll on next update\n this.bb.pollImmediatelyRequested = true;\n\n this.bb.dispatchEvent(new InternalBehaviorTreeUpdateEvent());\n },\n });\n });\n }\n\n updateMocksOnIframeCompletion(result: \"SUCCESS\" | \"FAILURE\") {\n assert(this.bb.world?.paymentEntity);\n if (this.bb.mock) {\n this.bb.dispatchEvent(\n new InternalScheduleMockUpdateEvent(\n makeTestPollResponse(this.bb.world, this.bb.channel, result),\n ),\n );\n }\n }\n\n exit() {\n super.exit();\n }\n}\n","import { assert, assertEquals } from \"../../utils\";\nimport { BlackboardType } from \"../behavior-tree\";\nimport { Behavior } from \"../behavior-tree-runner\";\n\nexport class ActionPaylinkBehavior implements Behavior {\n private el: HTMLLinkElement | null = null;\n\n constructor(\n public bb: BlackboardType,\n private actionIndex: string,\n ) {}\n\n enter() {\n assert(this.bb.world);\n assert(this.bb.world.paymentEntity);\n\n const action =\n this.bb.world?.paymentEntity?.entity.actions[Number(this.actionIndex)];\n if (!action) {\n throw new Error(\"Action not found for paylink behavior\");\n }\n\n assertEquals(action.type, \"REDIRECT_CUSTOMER\");\n assertEquals(action.descriptor, \"WEB_GOOGLE_PAYLINK\");\n\n const link = document.createElement(\"link\");\n link.rel = \"facilitated-payment\";\n link.href = action.value;\n\n this.el = link;\n document.head.appendChild(link);\n }\n\n exit() {\n this.el?.remove();\n this.el = null;\n }\n}\n","import { ComponentChildren, JSX } from \"preact\";\nimport { EmvcoQrData } from \"../data/emvco-qr-schema\";\nimport { TFunction } from \"../localization\";\n\nexport type QrArtComponentProps = {\n channelName: string;\n channelLogo: string;\n amountText: string;\n qr: ComponentChildren;\n parsedQr: EmvcoQrData | null;\n merchantName: string;\n t: TFunction;\n};\n\nexport function hasCustomQrArt(parsedQr: EmvcoQrData | null): boolean {\n return getCustomQrArtComponent(parsedQr) !== null;\n}\n\nexport function getCustomQrArtComponent(\n parsedQr: EmvcoQrData | null,\n): JSX.ElementType<QrArtComponentProps> | null {\n if (!parsedQr) return null;\n\n if (\n !parsedQr.merchantAccountInformation ||\n typeof parsedQr.merchantAccountInformation !== \"object\"\n ) {\n return null;\n }\n\n if (parsedQr.merchantAccountInformation[\"ID.CO.QRIS.WWW\"]) {\n return QrArtQris;\n }\n\n // if (parsedQr.merchantAccountInformation[\"SG.SGQR\"]) {\n // return QrArtSgqr;\n // }\n\n if (parsedQr.merchantAccountInformation[\"A0000006150001\"]) {\n return QrArtDuitnow;\n }\n\n return null;\n}\n\nfunction QrArtQris(props: QrArtComponentProps) {\n const { channelLogo, channelName, merchantName, amountText, parsedQr, t } =\n props;\n\n function getMerchantIdLabel() {\n const info = parsedQr?.merchantAccountInformation;\n if (typeof info === \"string\") return undefined;\n const qrisInfo = info?.[\"ID.CO.QRIS.WWW\"];\n if (typeof qrisInfo === \"string\") return undefined;\n if (!qrisInfo?.nmid) return undefined;\n return `NMID: ${qrisInfo.nmid}`;\n }\n const merchantIdLabel = getMerchantIdLabel();\n\n const qrisAccentColor = \"#DB4849\";\n const borderArtWidth = \"24px\";\n\n return (\n <div\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n position: \"relative\",\n paddingTop: \"24px\",\n paddingLeft: borderArtWidth,\n paddingRight: borderArtWidth,\n overflow: \"hidden\",\n }}\n >\n <img\n src={channelLogo}\n alt={t(\"image_alt.channel_logo\", { channelName })}\n style={{\n height: \"64px\",\n alignSelf: \"center\",\n }}\n />\n <div\n className=\"xendit-text-center xendit-text-16\"\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"4px\",\n marginTop: \"16px\",\n }}\n >\n <div className=\"xendit-text-semibold\">{merchantName}</div>\n {merchantIdLabel ? <div>{merchantIdLabel}</div> : null}\n </div>\n <div\n style={{\n position: \"relative\",\n margin: `-${borderArtWidth}`,\n marginBottom: \"0\",\n padding: borderArtWidth,\n }}\n >\n <div\n style={{\n padding: \"20px\",\n backgroundColor: \"white\",\n zIndex: 1,\n position: \"relative\",\n borderRadius: \"4px\",\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"16px\",\n }}\n >\n {props.qr}\n <div\n className=\"xendit-text-semibold xendit-text-center\"\n style={{ fontSize: \"24px\", lineHeight: borderArtWidth }}\n >\n {amountText}\n </div>\n </div>\n <svg\n style={{\n position: \"absolute\",\n top: \"-9%\",\n left: 0,\n width: \"60%\",\n height: \"auto\",\n pointerEvents: \"none\",\n }}\n viewBox=\"0 0 100 100\"\n >\n <polygon fill={qrisAccentColor} points=\"0,0 50,50 0,100\" />\n </svg>\n <svg\n style={{\n position: \"absolute\",\n bottom: 0,\n right: 0,\n width: \"30%\",\n height: \"auto\",\n pointerEvents: \"none\",\n }}\n viewBox=\"0 0 100 100\"\n >\n <polygon fill={qrisAccentColor} points=\"0,100 100,100 100,0\" />\n </svg>\n </div>\n </div>\n );\n}\n\n// we should use purple paynow branding for sg, but this might come in handy later\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nfunction QrArtSgqr(props: QrArtComponentProps) {\n const { merchantName, amountText } = props;\n\n const sgqrAccentColor = \"#FD0031\";\n\n return (\n <div\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n position: \"relative\",\n paddingTop: \"24px\",\n paddingLeft: \"24px\",\n paddingRight: \"24px\",\n overflow: \"hidden\",\n }}\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"83\"\n height=\"40\"\n fill=\"none\"\n style={{\n height: \"40px\",\n alignSelf: \"flex-start\",\n }}\n >\n <path\n fill={sgqrAccentColor}\n d=\"M18.395 39.983c-1.224-.14-2.626-.38-3.422-.587-3.582-.931-6.767-2.787-9.275-5.403-2.74-2.858-4.46-6.15-5.268-10.084C.174 22.663 0 21.206 0 20.11c0-1.08.183-2.682.33-3.479.426-2.313 1.002-4.05 1.922-5.793 2.09-3.962 5.07-6.896 8.903-8.768C15.535-.069 20.427-.564 25.188.65c.627.16 1.23.33 1.339.378.109.049.466.189.793.311 1.247.468 4.159 2.023 4.066 2.173-.022.036.02.066.093.066.149 0 .554.297 1.143.838.215.197.408.343.428.323.085-.085 1.9 1.72 2.529 2.515.833 1.051 1.838 2.587 2.344 3.583 1.04 2.045 1.845 4.59 1.99 6.29.034.381.078.827.099.99.301 2.344-.09 5.848-.936 8.368-.52 1.549-1.374 3.302-2.212 4.541-3.84 5.68-9.678 8.864-16.436 8.966-.955.014-1.87.011-2.033-.008m-3.521-11.997a4.97 4.97 0 0 0 2.763-2.024c.525-.767.739-1.481.747-2.498.006-.77-.029-.97-.26-1.464-.625-1.341-1.287-1.932-2.865-2.556-.537-.213-1.018-.387-1.068-.387-.193 0-2.957-.924-3.333-1.114-.519-.262-.864-.535-1.013-.8-.285-.508-.048-1.383.475-1.756.386-.274.82-.588 1.777-.588.68 0 1.93.388 3.025.94 1.057.53 1.241.621 1.339.469.023-.036.182-.319.404-.614.59-.783.897-1.342.832-1.512-.085-.22-.783-.692-1.713-1.16-1.789-.901-4.057-1.193-5.523-.71-1.955.642-3.242 1.871-3.68 3.513-.284 1.066-.054 2.359.603 3.384.707 1.104 1.445 1.467 5.606 2.76 1.291.402 1.656.595 2.01 1.066.822 1.092.13 2.172-1.585 2.47-.81.141-1.74.052-2.655-.255-.72-.241-1.972-.906-2.464-1.308-.154-.127-.335-.23-.401-.23-.097 0-1.142 1.204-1.599 1.843-.146.204.02.414.795 1 .693.525 1.724 1.069 2.591 1.368 1.351.467 3.915.547 5.192.163m13.686.177c1.398-.22 3.134-.984 4.219-1.856l.59-.475.082-.739c.09-.818.026-5.764-.078-5.93-.043-.072-1.146-.106-3.381-.106h-3.317l-.01.619c-.006.34-.028.94-.05 1.331-.024.447.002.737.07.779.059.036.928.06 1.931.05l1.824-.016-.019 1.267c-.021 1.454.04 1.345-1.068 1.891-.412.185-1.417.367-2.231.367-1.306 0-1.558-.027-2.061-.223-.742-.288-1.009-.457-1.592-1.008-.946-.893-1.469-2.297-1.468-3.943 0-1.703.476-2.94 1.52-3.95 1.032-.997 1.761-1.267 3.403-1.262 1.36.005 2.474.36 3.674 1.174.203.138.42.25.48.249.176-.003 1.647-1.844 1.647-2.062 0-.57-2.065-1.734-3.818-2.153-.966-.231-1.233-.256-2.33-.213-.924.035-1.405.103-1.885.266-2.384.811-4.35 2.497-5.259 4.51-.562 1.243-.798 3.178-.597 4.897.233 2.004 1.233 3.701 2.976 5.05.813.63 2.018 1.195 2.979 1.397.96.203 2.775.245 3.769.089m26.951-.466c-.28-.26-.638-.613-.794-.787-.304-.338-.413-.34-.89-.01-.82.568-2.916 1.168-4.076 1.168-1.205 0-3.068-.358-4.134-.95-1.996-1.107-3.6-3.424-3.882-5.96-.421-3.777 1.39-6.944 4.74-8.292 1.087-.438 2.055-.643 3.01-.636 2.095.015 4.211.768 5.616 2 .712.624 1.63 2.082 2.015 3.2.249.723.501 2.097.501 2.73 0 1.134-.536 3.078-1.147 4.157-.187.33-.34.64-.34.687s.279.316.62.598c.999.825 1 .828.322 1.665-.513.634-.805.9-.99.9-.033 0-.29-.212-.57-.47m-3.984-2.258c.727-.362.805-.61.32-1.01-.18-.15-.641-.564-1.023-.922-.863-.809-.804-.931-.554-1.218.144-.165.835-.956.941-1.084.242-.29.67-.002 2.108 1.398.607.592.783.546 1.223-.317.327-.643.352-1.452.384-1.827.023-.269-.013-1.368-.085-1.694-.65-2.936-3.836-4.965-6.546-4.167-1.22.359-2.147.982-2.857 1.92-.874 1.156-1.161 2.046-1.155 3.579.006 1.816.463 2.952 1.676 4.167 1.241 1.243 2.006 1.542 3.833 1.496 1.043-.026 1.204-.056 1.735-.321m8.396 2.254-1.017-.028V12.423l1.711-.002c2.44-.002 6.251.191 7.066.358 1.721.352 2.764 1.24 3.381 2.877.264.699.322 1.883.133 2.702-.157.68-.635 1.63-1.05 2.089-.432.478-1.36 1.107-1.985 1.345-.236.09-.43.224-.43.3 0 .074.211.435.469.803.257.367.788 1.135 1.18 1.707.678.99 1.064 1.533 1.808 2.536.182.247.312.468.288.492-.071.071-2.179.136-2.52.077-.278-.048-.507-.332-2.08-2.579-.974-1.388-1.84-2.562-1.928-2.609-.14-.075-1.422-.117-3.092-.1l-.57.005v2.612c0 2.409-.014 2.616-.174 2.649-.095.02-.63.024-1.19.008m7.165-7.829c.69-.327 1.353-.996 1.544-1.558.337-.987-.015-2.293-.78-2.897-.694-.547-1.127-.627-3.838-.716-1.364-.044-2.515-.044-2.56 0-.06.059-.114 3.938-.073 5.28.004.16.194.173 2.559.173h2.553z\"\n />\n </svg>\n <div\n className=\"xendit-text-center xendit-text-16\"\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"4px\",\n marginTop: \"16px\",\n }}\n >\n <div className=\"xendit-text-semibold\">{merchantName}</div>\n </div>\n <div\n style={{\n padding: \"20px\",\n backgroundColor: \"white\",\n zIndex: 1,\n position: \"relative\",\n borderRadius: \"4px\",\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"16px\",\n }}\n >\n {props.qr}\n <div\n className=\"xendit-text-semibold xendit-text-center\"\n style={{ fontSize: \"24px\", lineHeight: \"24px\" }}\n >\n {amountText}\n </div>\n <div\n style={{\n backgroundColor: sgqrAccentColor,\n color: \"white\",\n textAlign: \"center\",\n fontSize: \"20px\",\n lineHeight: \"28px\",\n padding: \"8px\",\n borderRadius: \"4px\",\n }}\n >\n SCAN TO PAY\n </div>\n </div>\n </div>\n );\n}\n\nfunction QrArtDuitnow(props: QrArtComponentProps) {\n const { merchantName, amountText } = props;\n\n const duitnowAccentColor = \"#ED3066\";\n\n return (\n <div\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n position: \"relative\",\n paddingTop: \"40px\",\n overflow: \"hidden\",\n }}\n >\n <div className=\"xendit-text-center xendit-text-16\">Scan To Pay</div>\n <div\n className=\"xendit-text-semibold xendit-text-center\"\n style={{ fontSize: \"24px\", lineHeight: \"24px\", marginTop: \"12px\" }}\n >\n {amountText}\n </div>\n <div\n className=\"xendit-text-center xendit-text-16 xendit-text-semibold\"\n style={{\n marginTop: \"8px\",\n }}\n >\n {merchantName}\n </div>\n <svg\n viewBox={\"0 0 180 180\"}\n style={{ aspectRatio: \"1\", margin: \"32px 14% 24px\" }}\n >\n <rect width=\"180\" height=\"180\" fill={duitnowAccentColor} rx={13} />\n <rect x=\"10\" y=\"10\" width=\"160\" height=\"140\" fill=\"white\" rx={4} />\n <path d=\"M0 180 L20 180 L0 160 Z\" fill={duitnowAccentColor} />\n <path d=\"M10 150 L30 150 L10 130 Z\" fill=\"white\" />\n <foreignObject x=\"40\" y=\"30\" width=\"100\" height=\"100\">\n <div style={{ \"--xendit-qr-foreground-color\": duitnowAccentColor }}>\n {props.qr}\n </div>\n </foreignObject>\n <foreignObject\n x=\"0\"\n y=\"160\"\n height=\"10px\"\n width=\"180px\"\n style={{ overflow: \"visible\" }}\n >\n <div\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n height: \"10px\",\n }}\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"209\"\n height=\"19\"\n fill=\"none\"\n viewBox=\"0 0 209 19\"\n style={{ width: \"auto\" }}\n >\n <title>Malaysia National QR</title>\n <path\n fill=\"#fff\"\n d=\"M1.16 14.58q-.56 0-.86-.32t-.3-.88V1.36Q0 .78.32.48.64.16 1.2.16q.5 0 .78.2.3.18.54.64l4.94 9.14h-.64L11.76 1q.24-.46.52-.64.28-.2.78-.2.56 0 .86.32.3.3.3.88v12.02q0 .56-.3.88-.28.32-.86.32-.56 0-.86-.32t-.3-.88V4.12h.44l-4.2 7.66a1.6 1.6 0 0 1-.42.5q-.22.16-.6.16t-.62-.16a1.6 1.6 0 0 1-.42-.5L1.84 4.1h.48v9.28q0 .56-.3.88-.28.32-.86.32m19.643.04q-1.06 0-1.9-.4a3.44 3.44 0 0 1-1.3-1.12 2.8 2.8 0 0 1-.46-1.58q0-1.08.56-1.7.56-.64 1.82-.92t3.38-.28h1v1.44h-.98q-1.239 0-1.98.12t-1.06.42q-.3.28-.3.8 0 .66.46 1.08t1.28.42q.66 0 1.16-.3.52-.32.82-.86t.3-1.24V8.2q0-1-.44-1.44t-1.48-.44q-.579 0-1.26.14-.66.14-1.4.48-.38.18-.68.1a.77.77 0 0 1-.44-.32 1.05 1.05 0 0 1-.16-.56q0-.3.16-.58.16-.3.54-.44a9 9 0 0 1 1.76-.54 8.6 8.6 0 0 1 1.56-.16q1.44 0 2.36.44a2.9 2.9 0 0 1 1.4 1.34q.46.88.46 2.28v4.8q0 .62-.3.96-.3.32-.86.32t-.88-.32q-.3-.34-.3-.96v-.96h.16q-.14.7-.56 1.22a2.7 2.7 0 0 1-1.02.78q-.62.28-1.42.28m11.558 0q-1.66 0-2.5-.94-.84-.96-.84-2.8V1.42q0-.62.32-.94t.92-.32.92.32q.34.32.34.94v9.34q0 .92.38 1.36.4.44 1.12.44h.3l.28-.04q.28-.04.38.16.1.18.1.76 0 .5-.2.78-.201.28-.66.34l-.42.04q-.22.02-.44.02m6.766 0q-1.06 0-1.9-.4a3.45 3.45 0 0 1-1.3-1.12 2.8 2.8 0 0 1-.46-1.58q0-1.08.56-1.7.56-.64 1.82-.92t3.38-.28h1v1.44h-.98q-1.239 0-1.98.12t-1.06.42q-.3.28-.3.8 0 .66.46 1.08t1.28.42q.66 0 1.16-.3.52-.32.82-.86t.3-1.24V8.2q0-1-.44-1.44t-1.48-.44q-.579 0-1.26.14-.66.14-1.4.48-.38.18-.68.1a.77.77 0 0 1-.44-.32 1.05 1.05 0 0 1-.16-.56q0-.3.16-.58.16-.3.54-.44a9 9 0 0 1 1.76-.54 8.6 8.6 0 0 1 1.56-.16q1.44 0 2.36.44a2.9 2.9 0 0 1 1.4 1.34q.46.88.46 2.28v4.8q0 .62-.3.96-.3.32-.86.32t-.88-.32q-.3-.34-.3-.96v-.96h.16q-.14.7-.56 1.22a2.7 2.7 0 0 1-1.02.78q-.62.28-1.42.28m10.6 3.56q-.44 0-.72-.24a.91.91 0 0 1-.34-.6q-.04-.38.14-.8l1.36-3.02v1.04l-3.64-8.42q-.18-.44-.12-.82a.89.89 0 0 1 .36-.6q.32-.24.86-.24.46 0 .74.22.28.2.5.78l2.7 6.74h-.6l2.76-6.76q.22-.56.52-.76.3-.22.8-.22.44 0 .7.24.26.22.32.6.06.36-.14.8l-4.86 11.1q-.26.56-.56.76t-.78.2m11.932-3.56a10 10 0 0 1-1.82-.18 5.4 5.4 0 0 1-1.72-.62 1.26 1.26 0 0 1-.46-.46 1.14 1.14 0 0 1-.1-.54 1 1 0 0 1 .2-.48.83.83 0 0 1 .44-.26q.28-.06.6.1a7.3 7.3 0 0 0 1.5.54q.7.14 1.38.14.96 0 1.42-.32.48-.34.48-.88 0-.46-.32-.7-.3-.26-.92-.38l-2-.38q-1.24-.24-1.9-.9-.64-.68-.64-1.74 0-.96.52-1.66.54-.7 1.48-1.08t2.16-.38q.88 0 1.64.2.78.18 1.5.58.3.16.4.42.12.26.06.54-.06.26-.24.48a.84.84 0 0 1-.46.26q-.26.04-.6-.12a5.4 5.4 0 0 0-1.2-.46 4.5 4.5 0 0 0-1.08-.14q-.98 0-1.46.34-.46.34-.46.9 0 .42.28.7t.86.38l2 .38q1.3.24 1.96.88.68.64.68 1.72 0 1.46-1.14 2.3-1.14.82-3.04.82m7.926-.06q-.6 0-.92-.36t-.32-1V5.86q0-.66.32-1 .32-.36.92-.36t.92.36q.34.34.34 1v7.34q0 .64-.32 1t-.94.36m0-11.92q-.7 0-1.1-.34-.38-.36-.38-.98 0-.64.38-.98.4-.34 1.1-.34.72 0 1.1.34t.38.98q0 .62-.38.98-.38.34-1.1.34m7.578 11.98q-1.06 0-1.9-.4a3.44 3.44 0 0 1-1.3-1.12 2.8 2.8 0 0 1-.46-1.58q0-1.08.56-1.7.56-.64 1.82-.92t3.38-.28h1v1.44h-.98q-1.24 0-1.98.12t-1.06.42q-.3.28-.3.8 0 .66.46 1.08t1.28.42q.66 0 1.16-.3.52-.32.82-.86t.3-1.24V8.2q0-1-.44-1.44t-1.48-.44q-.58 0-1.26.14-.66.14-1.4.48-.38.18-.68.1a.77.77 0 0 1-.44-.32 1.05 1.05 0 0 1-.16-.56q0-.3.16-.58.159-.3.54-.44a9 9 0 0 1 1.76-.54 8.6 8.6 0 0 1 1.56-.16q1.44 0 2.36.44a2.9 2.9 0 0 1 1.4 1.34q.46.88.46 2.28v4.8q0 .62-.3.96-.3.32-.86.32t-.88-.32q-.3-.34-.3-.96v-.96h.16q-.14.7-.56 1.22a2.7 2.7 0 0 1-1.02.78q-.62.28-1.42.28m15.587-.04q-.58 0-.9-.32-.3-.32-.3-.92V1.44q0-.62.3-.94.32-.34.82-.34.46 0 .68.18.24.16.56.56l7.66 9.94h-.52V1.38q0-.58.3-.9.32-.32.9-.32t.88.32.3.9v12q0 .56-.28.88t-.76.32q-.46 0-.74-.18-.26-.18-.58-.58l-7.64-9.94h.5v9.46q0 .6-.3.92t-.88.32m17.241.04q-1.06 0-1.9-.4a3.44 3.44 0 0 1-1.3-1.12 2.8 2.8 0 0 1-.46-1.58q0-1.08.56-1.7.56-.64 1.82-.92t3.38-.28h1v1.44h-.98q-1.24 0-1.98.12t-1.06.42q-.3.28-.3.8 0 .66.46 1.08t1.28.42q.66 0 1.16-.3.52-.32.82-.86t.3-1.24V8.2q0-1-.44-1.44t-1.48-.44q-.58 0-1.26.14-.66.14-1.4.48-.38.18-.68.1a.76.76 0 0 1-.44-.32 1.05 1.05 0 0 1-.16-.56q0-.3.16-.58.159-.3.54-.44a9 9 0 0 1 1.76-.54 8.6 8.6 0 0 1 1.56-.16q1.44 0 2.36.44.94.44 1.4 1.34.46.88.46 2.28v4.8q0 .62-.3.96-.3.32-.86.32t-.88-.32q-.3-.34-.3-.96v-.96h.16q-.14.7-.56 1.22a2.7 2.7 0 0 1-1.02.78q-.62.28-1.42.28m12.697 0q-1.3 0-2.18-.44-.86-.44-1.28-1.28-.42-.86-.42-2.12V6.52h-1.04q-.48 0-.74-.24-.26-.26-.26-.7 0-.46.26-.7t.74-.24h1.04V2.82q0-.62.32-.94.34-.32.94-.32t.92.32.32.94v1.82h2.12q.48 0 .74.24t.26.7q0 .44-.26.7-.26.24-.74.24h-2.12v4.12q0 .96.42 1.44t1.36.48q.34 0 .6-.06t.46-.08q.24-.02.4.16.16.16.16.68 0 .4-.14.72-.12.3-.46.42-.26.08-.68.14-.42.08-.74.08m5.19-.06q-.6 0-.92-.36t-.32-1V5.86q0-.66.32-1 .32-.36.92-.36t.92.36q.34.34.34 1v7.34q0 .64-.32 1t-.94.36m0-11.92q-.7 0-1.1-.34-.38-.36-.38-.98 0-.64.38-.98.4-.34 1.1-.34.72 0 1.1.34t.38.98q0 .62-.38.98-.38.34-1.1.34m8.818 11.98q-1.521 0-2.64-.62a4.33 4.33 0 0 1-1.74-1.76q-.62-1.16-.62-2.72 0-1.18.34-2.1a4.5 4.5 0 0 1 1.02-1.6q.66-.68 1.58-1.02.92-.36 2.06-.36 1.52 0 2.64.62 1.119.62 1.74 1.76.62 1.14.62 2.7 0 1.18-.36 2.12a4.5 4.5 0 0 1-1 1.62q-.66.66-1.58 1.02-.92.34-2.06.34m0-1.9q.74 0 1.3-.36t.86-1.06q.32-.72.32-1.78 0-1.6-.68-2.38-.681-.8-1.8-.8-.74 0-1.3.36-.56.34-.88 1.06-.3.7-.3 1.76 0 1.58.68 2.4.68.8 1.8.8m8.803 1.86q-.6 0-.92-.32-.32-.34-.32-.96V5.74q0-.62.32-.94t.9-.32.9.32.32.94V7.1l-.22-.5q.44-1.06 1.36-1.6.94-.56 2.12-.56t1.94.44 1.14 1.34q.38.88.38 2.24v4.84q0 .62-.32.96-.32.32-.92.32t-.94-.32q-.32-.34-.32-.96V8.58q0-1.14-.44-1.66-.42-.52-1.32-.52-1.1 0-1.76.7-.64.68-.64 1.82v4.38q0 1.28-1.26 1.28m14.179.04q-1.06 0-1.9-.4a3.45 3.45 0 0 1-1.3-1.12 2.8 2.8 0 0 1-.46-1.58q0-1.08.56-1.7.56-.64 1.82-.92t3.38-.28h1v1.44h-.98q-1.239 0-1.98.12t-1.06.42q-.3.28-.3.8 0 .66.46 1.08t1.28.42q.66 0 1.16-.3.52-.32.82-.86t.3-1.24V8.2q0-1-.44-1.44t-1.48-.44q-.579 0-1.26.14-.66.14-1.4.48-.38.18-.68.1a.77.77 0 0 1-.44-.32 1.06 1.06 0 0 1-.16-.56q0-.3.16-.58.16-.3.54-.44a9 9 0 0 1 1.76-.54 8.6 8.6 0 0 1 1.56-.16q1.44 0 2.36.44.94.44 1.4 1.34.46.88.46 2.28v4.8q0 .62-.3.96-.3.32-.86.32t-.88-.32q-.3-.34-.3-.96v-.96h.16a2.8 2.8 0 0 1-.56 1.22 2.7 2.7 0 0 1-1.02.78q-.62.28-1.42.28m11.558 0q-1.66 0-2.5-.94-.84-.96-.84-2.8V1.42q0-.62.32-.94t.92-.32.92.32q.34.32.34.94v9.34q0 .92.38 1.36.4.44 1.12.44h.3l.28-.04q.28-.04.38.16.1.18.1.76 0 .5-.2.78-.201.28-.66.34l-.42.04a5 5 0 0 1-.44.02m21.436 2.06q.28.44.22.8t-.32.6a1.13 1.13 0 0 1-.64.32 1.25 1.25 0 0 1-.76-.08q-.38-.14-.64-.56l-1.38-2.22a1.84 1.84 0 0 0-.76-.7q-.46-.22-1.14-.22l1.98-.78q.94 0 1.5.34.56.32 1.08 1.14zm-5.4-2.06q-2.04 0-3.58-.9-1.52-.9-2.36-2.52-.84-1.64-.84-3.84 0-1.66.48-2.98.48-1.34 1.36-2.28a5.9 5.9 0 0 1 2.14-1.46q1.26-.52 2.8-.52 2.06 0 3.58.9 1.52.88 2.36 2.5t.84 3.82q0 1.66-.48 3a6.5 6.5 0 0 1-1.38 2.3 5.9 5.9 0 0 1-2.14 1.48q-1.24.5-2.78.5m0-2.2q1.3 0 2.2-.6.92-.6 1.4-1.74.5-1.14.5-2.72 0-2.4-1.08-3.72-1.06-1.32-3.02-1.32-1.28 0-2.2.6-.92.58-1.42 1.72-.48 1.12-.48 2.72 0 2.38 1.08 3.72t3.02 1.34m11.163 2.16q-.62 0-.96-.34-.32-.36-.32-.98V1.62q0-.64.34-.96.34-.34.96-.34h4.82q2.32 0 3.58 1.12 1.26 1.1 1.26 3.1 0 1.3-.58 2.24-.56.94-1.64 1.44t-2.62.5l.18-.3h.66q.82 0 1.42.4.621.4 1.08 1.26l1.5 2.78q.24.42.22.82a.93.93 0 0 1-.3.66q-.28.24-.82.24t-.88-.22q-.339-.24-.6-.72l-2.02-3.72q-.36-.68-.86-.9-.48-.24-1.24-.24h-1.9v4.48q0 .62-.32.98-.32.34-.96.34m1.28-7.7h3.12q1.38 0 2.08-.56.72-.58.72-1.72 0-1.12-.72-1.68-.7-.58-2.08-.58h-3.12z\"\n />\n </svg>\n </div>\n </foreignObject>\n </svg>\n </div>\n );\n}\n","import qrcode from \"qrcode\";\nimport qrSvgRenderer from \"qrcode/lib/renderer/svg-tag.js\";\n\nexport type QrArtConfig = {\n margin: number;\n colors: [string, string];\n};\n\n/**\n * Generate a qr code svg. It will have 1x1 pixels and 1px margins.\n *\n * Returns the svg node and the size of the image including margins.\n */\nexport function generateQrSvg(\n text: string,\n artConfig: QrArtConfig,\n): SVGSVGElement {\n const qr = qrcode.create(text);\n const svgText = qrSvgRenderer.render(qr, {\n margin: artConfig.margin,\n });\n const parser = new DOMParser();\n const svgNode = parser.parseFromString(svgText, \"image/svg+xml\")\n .documentElement as unknown as SVGSVGElement;\n\n svgNode.style.width = \"100%\";\n svgNode.style.height = \"100%\";\n svgNode.setAttribute(\"width\", String(qr.modules.size + artConfig.margin * 2));\n svgNode.setAttribute(\n \"height\",\n String(qr.modules.size + artConfig.margin * 2),\n );\n\n // Override colors to use CSS variables\n\n const foregroundPath = svgNode.querySelector(\"[stroke]\");\n foregroundPath?.setAttribute(\"stroke\", artConfig.colors[0]);\n const backgroundPath = svgNode.querySelector(\"[fill]\");\n backgroundPath?.setAttribute(\"fill\", artConfig.colors[1]);\n\n return svgNode;\n}\n\n/**\n * Takes an svg node, renders it to a canvas, and downloads it as a png file.\n */\nexport async function downloadSvgAsPng(\n svgNode: SVGSVGElement,\n filename: string,\n): Promise<void> {\n // Browser compatibility check\n if (!window.URL?.createObjectURL)\n throw new Error(\"Browser doesn't support URL.createObjectURL\");\n if (!window.Blob) throw new Error(\"Browser doesn't support Blob\");\n if (!document.createElement)\n throw new Error(\"Browser doesn't support createElement\");\n\n // svg to string\n const svgString = new XMLSerializer().serializeToString(svgNode);\n const svgBlob = new Blob([svgString], {\n type: \"image/svg+xml;charset=utf-8\",\n });\n\n // string to blob\n const url = URL.createObjectURL(svgBlob);\n\n const image = new Image();\n image.src = url;\n\n return new Promise((resolve, reject) => {\n image.onload = function () {\n // start with the intrinsic size for qr and the natural size for barcode\n let width: number = image.naturalWidth;\n let height: number = image.naturalHeight;\n\n // double the size until it is at least 256px wide\n if (width !== 0) {\n while (width < 256) {\n width *= 2;\n height *= 2;\n }\n }\n\n // it must be mounted before creating the canvas context or else safari will not render it correctly\n document.body.appendChild(image);\n\n const canvas = document.createElement(\"canvas\");\n canvas.width = width;\n canvas.height = height;\n\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) {\n return reject(new Error(\"Failed to get canvas context\"));\n }\n\n ctx.drawImage(image, 0, 0, width, height);\n URL.revokeObjectURL(url);\n\n const imageDataUrl = canvas.toDataURL(\"image/png\");\n const anchor = document.createElement(\"a\");\n anchor.href = imageDataUrl;\n anchor.download = filename;\n document.body.appendChild(anchor);\n anchor.click();\n document.body.removeChild(anchor);\n\n image.remove();\n resolve();\n };\n image.onerror = function (error) {\n URL.revokeObjectURL(url);\n reject(new Error(\"Failed to generate image\"));\n };\n });\n}\n\nexport function timestampForFilename(): string {\n const now = new Date();\n return new Intl.DateTimeFormat(\"en-GB\", {\n hour: \"2-digit\",\n minute: \"2-digit\",\n day: \"2-digit\",\n month: \"2-digit\",\n year: \"numeric\",\n }).format(now);\n}\n\nexport function cleanStringForFilename(str: string): string {\n return str\n .split(\"\")\n .map((char) => {\n // replace non-alphanumeric characters with dashes, and convert to lowercase\n if (/[a-zA-Z0-9]/.test(char)) {\n return char.toLowerCase();\n } else {\n return \"-\";\n }\n })\n .join(\"\")\n .replace(/-+/g, \"-\"); // consecutive dashes to single dash\n}\n","import { TFunction } from \"../localization\";\nimport { useCallback, useMemo, useRef, useState } from \"preact/hooks\";\nimport { amountFormat } from \"../amount-format\";\nimport { Button, ButtonLoadingSpinner, ButtonVariant } from \"./core/button\";\nimport { TargetedEvent } from \"preact\";\nimport { EmvcoQrData } from \"../data/emvco-qr-schema\";\nimport { getCustomQrArtComponent } from \"./action-qr-custom-art\";\nimport {\n cleanStringForFilename,\n downloadSvgAsPng,\n generateQrSvg,\n QrArtConfig,\n timestampForFilename,\n} from \"./action-qr-utils\";\n\ntype Props = {\n amount: number;\n businessName: string;\n channelName: string;\n channelLogo: string;\n currency: string;\n hideUi: boolean;\n onAffirm: () => void;\n qrString: string;\n parsedQr: EmvcoQrData | null;\n title: string;\n t: TFunction;\n};\n\nexport function ActionQr(props: Props) {\n const {\n amount,\n businessName,\n channelName,\n channelLogo,\n currency,\n onAffirm,\n qrString,\n parsedQr,\n t,\n } = props;\n\n const [showSpinner, setShowSpinner] = useState(false);\n\n const onMadePaymentClicked = useCallback(() => {\n setShowSpinner(true);\n onAffirm();\n }, [onAffirm]);\n\n const svgNode = useMemo(() => {\n try {\n return generateQrSvg(qrString, qrArtConfigDefault);\n } catch (error) {\n console.log(\"Error generating QR code SVG:\", error);\n // show an error message in place of the QR code\n const node = document.createElement(\"div\");\n node.innerText = t(\"action_qr.unable_to_generate\");\n return node;\n }\n }, [qrString, t]);\n\n const didDownload = useRef(false);\n const onClickQrCode = useCallback(\n (event: TargetedEvent<HTMLDivElement>) => {\n if (event instanceof PointerEvent && event.pointerType !== \"touch\") {\n // only download on touch devices, only phone users need to save the qr code, desktop users can scan it with their phone\n return;\n }\n\n if (didDownload.current) {\n // prevent multiple downloads\n return;\n }\n\n event.currentTarget.animate?.(\n [\n { transform: \"scale(1)\" },\n { transform: \"scale(0.95)\" },\n { transform: \"scale(1)\" },\n ],\n {\n duration: 150,\n easing: \"ease-in-out\",\n },\n );\n\n const svgNode = generateQrSvg(qrString, qrArtConfigForDownload);\n const filename = [\n cleanStringForFilename(businessName),\n cleanStringForFilename(channelName),\n cleanStringForFilename(currency),\n cleanStringForFilename(String(amount)),\n cleanStringForFilename(timestampForFilename()),\n ].join(\"-\");\n\n didDownload.current = true;\n downloadSvgAsPng(svgNode, `${filename}.png`).catch((error) => {\n console.error(\"Error downloading QR code:\", error);\n });\n },\n [amount, businessName, channelName, currency, qrString],\n );\n\n if (props.hideUi) {\n return (\n <div\n data-testid=\"qr-code\"\n ref={(r) => {\n if (r && (r.childNodes.length !== 1 || r.firstChild !== svgNode)) {\n // insert svg if not already present\n r?.replaceChildren(svgNode);\n }\n }}\n />\n );\n }\n\n const qrWrapper = (\n <div\n data-testid=\"qr-code\"\n className=\"xendit-action-qr-qrcode-container\"\n role=\"button\"\n tabIndex={0}\n onClick={onClickQrCode}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n onClickQrCode(e);\n }\n }}\n ref={(r) => {\n if (r && (r.childNodes.length !== 1 || r.firstChild !== svgNode)) {\n // insert svg if not already present\n r?.replaceChildren(svgNode);\n }\n }}\n />\n );\n\n const affirmSection = (\n <div className=\"xendit-action-present-to-customer-affirm\">\n <Button\n variant={ButtonVariant.WHITE_ROUNDED}\n disabled={showSpinner}\n onClick={onMadePaymentClicked}\n className=\"xendit-button-block\"\n >\n {showSpinner ? <ButtonLoadingSpinner /> : t(\"action.payment_made\")}\n </Button>\n <div className=\"xendit-text-12 xendit-text-secondary xendit-text-center\">\n {t(\"action.payment_confirmation_instructions\")}\n </div>\n </div>\n );\n\n const amountText = amountFormat(amount, currency);\n\n const QrArtComponent = getCustomQrArtComponent(parsedQr);\n\n if (QrArtComponent) {\n return (\n <>\n <QrArtComponent\n channelLogo={channelLogo}\n channelName={channelName}\n merchantName={businessName}\n amountText={amountText}\n parsedQr={parsedQr}\n qr={qrWrapper}\n t={t}\n />\n <div\n style={{\n padding: \"48px\",\n paddingTop: \"8px\",\n paddingBottom: \"24px\",\n }}\n >\n {affirmSection}\n </div>\n </>\n );\n } else {\n return (\n <div className=\"xendit-action-present-to-customer\">\n <img\n src={channelLogo}\n alt={t(\"image_alt.channel_logo\", { channelName })}\n className=\"xendit-action-qr-channel-logo\"\n />\n <div className=\"xendit-action-qr-content\">\n <div className=\"xendit-text-16 xendit-text-center xendit-qr-merchant-info\">\n <div className=\"xendit-text-semibold\">{businessName}</div>\n </div>\n {qrWrapper}\n <div className=\"xendit-text-16 xendit-text-semibold xendit-text-center\">\n {amountText}\n </div>\n </div>\n {affirmSection}\n </div>\n );\n }\n}\n\nconst qrArtConfigDefault: QrArtConfig = {\n margin: 0,\n colors: [\n \"var(--xendit-qr-foreground-color)\",\n \"var(--xendit-qr-background-color)\",\n ],\n};\n\nconst qrArtConfigForDownload: QrArtConfig = {\n margin: 2,\n colors: [\"#000\", \"#FFF\"],\n};\n","/**\n * Spec for core EMVCo QR:\n * https://mvallim.github.io/emv-qrcode/docs/EMVCo-Merchant-Presented-QR-Specification-v1-1.pdf\n */\n\nexport type EmvcoQrTemplateClass = Record<string, EmvcoQrFieldDescriptor>;\nexport type EmvcoQrFieldDescriptor = {\n name: string;\n type: \"template\" | \"ans\" | \"string\" | \"numeric\";\n templateClass?: EmvcoQrTemplateClass;\n};\nexport type EmvcoQrData = { [key: string]: string | EmvcoQrData };\n\n// Page 22 Table 3.7 - Additional Data Field Template\nexport const additionalDataFieldTemplateClass: EmvcoQrTemplateClass = {\n \"01\": {\n name: \"billNumber\",\n type: \"ans\",\n },\n \"02\": {\n name: \"mobileNumber\",\n type: \"ans\",\n },\n \"03\": {\n name: \"storeLabel\",\n type: \"ans\",\n },\n \"04\": {\n name: \"loyaltyNumber\",\n type: \"ans\",\n },\n \"05\": {\n name: \"referenceLabel\",\n type: \"ans\",\n },\n \"06\": {\n name: \"customerLabel\",\n type: \"ans\",\n },\n \"07\": {\n name: \"terminalLabel\",\n type: \"ans\",\n },\n \"08\": {\n name: \"purposeOfTransaction\",\n type: \"ans\",\n },\n \"09\": {\n name: \"additionalConsumerDataRequest\",\n type: \"ans\",\n },\n};\n\n// Page 23 Table 3.8 - Language Template\nexport const languageTemplateClass: EmvcoQrTemplateClass = {\n \"00\": {\n name: \"languagePreference\",\n type: \"ans\",\n },\n \"01\": {\n name: \"merchantNameAlternateLanguage\",\n type: \"string\",\n },\n \"02\": {\n name: \"merchantCityAlternateLanguage\",\n type: \"string\",\n },\n};\n\n// Page 20 Table 3.6\nexport const rootTemplateClass: Record<string, EmvcoQrFieldDescriptor> = {\n \"00\": {\n name: \"payloadFormatIndicator\",\n type: \"numeric\",\n },\n \"01\": {\n name: \"pointOfInitiationMethod\",\n type: \"numeric\",\n },\n \"52\": {\n name: \"merchantCategoryCode\",\n type: \"numeric\",\n },\n \"53\": {\n name: \"transactionCurrency\",\n type: \"numeric\",\n },\n \"54\": {\n name: \"transactionAmount\",\n type: \"ans\",\n },\n \"55\": {\n name: \"tipOrConvenienceIndicator\",\n type: \"numeric\",\n },\n \"56\": {\n name: \"valueOfConvenienceFeeFixed\",\n type: \"ans\",\n },\n \"57\": {\n name: \"valueOfConvenienceFeePercentage\",\n type: \"ans\",\n },\n \"58\": {\n name: \"countryCode\",\n type: \"ans\",\n },\n \"59\": {\n name: \"merchantName\",\n type: \"ans\",\n },\n \"60\": {\n name: \"merchantCity\",\n type: \"ans\",\n },\n \"61\": {\n name: \"postalCode\",\n type: \"ans\",\n },\n \"62\": {\n name: \"additionalData\",\n type: \"template\",\n templateClass: additionalDataFieldTemplateClass,\n },\n \"63\": {\n name: \"crc\",\n type: \"ans\",\n },\n \"64\": {\n name: \"language\",\n type: \"template\",\n templateClass: languageTemplateClass,\n },\n};\n\n// PayNow\nexport const paynowTemplateClass: EmvcoQrTemplateClass = {\n \"00\": {\n name: \"globallyUniqueIdentifier\",\n type: \"string\",\n },\n \"01\": {\n name: \"type\",\n type: \"numeric\",\n },\n \"02\": {\n name: \"identifier\",\n type: \"ans\",\n },\n \"03\": {\n name: \"editable\",\n type: \"numeric\",\n },\n};\n\n// QRIS\nexport const qrisTemplateClass: EmvcoQrTemplateClass = {\n \"00\": {\n name: \"globallyUniqueIdentifier\",\n type: \"string\",\n },\n \"02\": {\n name: \"nmid\",\n type: \"ans\",\n },\n \"03\": {\n name: \"businessType\",\n type: \"ans\",\n },\n};\n\n// DANA\nexport const danaTemplateClass: EmvcoQrTemplateClass = {\n \"00\": {\n name: \"globallyUniqueIdentifier\",\n type: \"string\",\n },\n \"01\": {\n name: \"merchantId\",\n type: \"ans\",\n },\n \"02\": {\n name: \"storeOrTerminalId\",\n type: \"ans\",\n },\n \"03\": {\n name: \"additionalIdentifier\",\n type: \"ans\",\n },\n};\n\n// SGQR\nexport const sgqrTemplateClass: EmvcoQrTemplateClass = {\n \"00\": {\n name: \"globallyUniqueIdentifier\",\n type: \"string\",\n },\n \"01\": {\n name: \"sgqrNumber\",\n type: \"ans\",\n },\n \"02\": {\n name: \"version\",\n type: \"ans\",\n },\n \"03\": {\n name: \"postalCode\",\n type: \"ans\",\n },\n \"04\": {\n name: \"level\",\n type: \"ans\",\n },\n \"05\": {\n name: \"unit\",\n type: \"ans\",\n },\n \"06\": {\n name: \"misc\",\n type: \"ans\",\n },\n \"07\": {\n name: \"revisionDate\",\n type: \"ans\",\n },\n};\n\n// QRPH\n// https://xendit.atlassian.net/wiki/spaces/D/pages/3090056015/QR+String+Definitions\nexport const qrphTemplateClass: EmvcoQrTemplateClass = {\n \"00\": {\n name: \"globallyUniqueIdentifier\",\n type: \"string\",\n },\n \"01\": {\n name: \"acquirerId\",\n type: \"ans\",\n },\n \"03\": {\n name: \"merchantId\",\n type: \"ans\",\n },\n \"05\": {\n name: \"notifyFlags\",\n type: \"numeric\",\n },\n};\n\n// dynamic template selection for merchant info fields\nexport const knownTemplateClasses: Record<string, EmvcoQrTemplateClass> = {\n \"ID.CO.QRIS.WWW\": qrisTemplateClass,\n \"ID.DANA.WWW\": danaTemplateClass,\n \"SG.SGQR\": sgqrTemplateClass,\n \"SG.PAYNOW\": paynowTemplateClass,\n \"ph.ppmi.p2m\": qrphTemplateClass,\n};\n","import {\n EmvcoQrData,\n EmvcoQrFieldDescriptor,\n knownTemplateClasses,\n rootTemplateClass,\n} from \"./data/emvco-qr-schema\";\n\nfunction isSurrogatePair(char: string) {\n return /^[\\uD800-\\uDBFF]$/.test(char);\n}\n\n// decode an EMVCo QR string into an array of { key, value } pairs where key is 00 - 99\nexport function emvcoQrTokenize(\n emvcoString: string,\n): { key: string; value: string }[] {\n const seen = new Set<string>();\n const result: { key: string; value: string }[] = [];\n\n while (emvcoString.length) {\n const currentTag = emvcoString.substring(0, 2);\n if (!/^\\d{2}$/.test(currentTag)) {\n throw new Error(`Invalid EMVCo QR string, invalid tag`);\n }\n if (seen.has(currentTag)) {\n throw new Error(`Duplicate tag ${currentTag} in EMVCo QR string`);\n }\n seen.add(currentTag);\n const lengthStr = emvcoString.substring(2, 4);\n if (!/^\\d{2}$/.test(lengthStr)) {\n throw new Error(`Invalid EMVCo QR string, invalid length`);\n }\n const length = parseInt(lengthStr, 10); // nan and zero are both invalid\n if (!length) {\n throw new Error(\n `Invalid EMVCo QR string, expected length but got ${lengthStr}`,\n );\n }\n let value = \"\";\n let javascriptCharacters = 0; // javascript length of the value\n let realCharacters = 0; // normal characters count as 2, surrogate pair halves count as 1\n while (realCharacters < length) {\n // read a character and increment valueChars unless it's a high surrogate pair\n const char = emvcoString.substring(\n 4 + javascriptCharacters,\n 5 + javascriptCharacters,\n );\n if (char === \"\") {\n throw new Error(`Invalid EMVCo QR string, unexpected end of string`);\n }\n value += char;\n javascriptCharacters += 1;\n\n if (isSurrogatePair(char)) {\n realCharacters += 0.5;\n } else {\n realCharacters += 1;\n }\n }\n result.push({ key: currentTag, value });\n emvcoString = emvcoString.substring(4 + javascriptCharacters);\n }\n\n return result;\n}\n\n/**\n * Parse an EMVCo QR into a structured object\n */\nexport function emvcoQrParse(str: string): EmvcoQrData {\n const { result, raw } = parseTemplateWithClass(rootTemplateClass, str);\n\n // additionally parse merchant info using dynamic template selection\n result[\"merchantAccountInformation\"] = {};\n for (const rawField of raw) {\n const fieldNumber = Number(rawField.key);\n if (fieldNumber >= 26 && fieldNumber <= 51) {\n writeMerchantAccountInformationField(\n result[\"merchantAccountInformation\"] as EmvcoQrData,\n rawField.key,\n rawField.value,\n );\n }\n }\n\n return result;\n}\n\n// set a field in the result object, recursively parsing if required\nfunction writeFieldForDescriptor(\n result: EmvcoQrData,\n descriptorMap: Record<string, EmvcoQrFieldDescriptor>,\n key: string,\n value: string,\n) {\n result[`field${key}`] = value;\n const descriptor = descriptorMap[key];\n if (!descriptor) {\n return;\n }\n const output =\n descriptor.type === \"template\" && descriptor.templateClass\n ? parseTemplateWithClass(descriptor.templateClass, value).result\n : value;\n result[descriptor.name] = output;\n}\n\n// generic template parser\nfunction parseTemplateWithClass(\n templateClass: Record<string, EmvcoQrFieldDescriptor>,\n str: string,\n): { result: EmvcoQrData; raw: ReturnType<typeof emvcoQrTokenize> } {\n const raw = emvcoQrTokenize(str);\n const result: EmvcoQrData = {};\n\n for (const { key, value } of raw) {\n writeFieldForDescriptor(result, templateClass, key, value);\n }\n\n return { result, raw };\n}\n\n// generic merchant account information field parser\nfunction writeMerchantAccountInformationField(\n result: EmvcoQrData,\n key: string,\n value: string,\n) {\n const raw = emvcoQrTokenize(value);\n const fieldType = raw.find(({ key }) => key === \"00\")?.value;\n if (!fieldType) {\n throw new Error(\n `Missing field 00 in merchant account information template for field ${key}`,\n );\n }\n const templateClass = knownTemplateClasses[fieldType];\n if (templateClass) {\n result[fieldType] = parseTemplateWithClass(templateClass, value).result;\n }\n\n return result;\n}\n","import { createElement } from \"preact\";\nimport { internal } from \"../../internal\";\nimport { assert, assertEquals } from \"../../utils\";\nimport { BlackboardType } from \"../behavior-tree\";\nimport { ContainerActionBehavior, DefaultActionContainerType } from \"./action\";\nimport { ActionQr } from \"../../components/action-qr\";\nimport { InternalBehaviorTreeUpdateEvent } from \"../../private-event-types\";\nimport { emvcoQrParse } from \"../../emvco-qr\";\nimport { EmvcoQrData } from \"../../data/emvco-qr-schema\";\nimport { hasCustomQrArt } from \"../../components/action-qr-custom-art\";\n\nexport class ActionQrBehavior extends ContainerActionBehavior {\n constructor(\n protected bb: BlackboardType,\n private actionIndex: string,\n ) {\n super(bb);\n }\n\n enter() {\n const qrAction =\n this.bb.world?.paymentEntity?.entity.actions[Number(this.actionIndex)];\n\n assertEquals(qrAction?.type, \"PRESENT_TO_CUSTOMER\");\n assert(this.bb.world);\n assert(this.bb.channel);\n assert(this.bb.world.paymentEntity);\n\n let parsedQr: EmvcoQrData | null = null;\n try {\n parsedQr = emvcoQrParse(qrAction.value);\n } catch {\n // if we can't parse it, that's ok\n }\n\n // in mock mode, we lie about what's inside the qr code so we can trigger custom art,\n // the channel property mock_emvco_qr_field_26_00 controls this behavior\n if (\n this.bb.mock &&\n typeof this.bb.channelProperties?.mock_emvco_qr_field_26_00 === \"string\"\n ) {\n const field_26_00 = this.bb.channelProperties.mock_emvco_qr_field_26_00;\n parsedQr = {\n merchantAccountInformation: {\n [field_26_00]: {\n globallyUniqueIdentifier: field_26_00,\n },\n },\n };\n }\n\n const qrHasCustomArt = hasCustomQrArt(parsedQr);\n\n const container = this.bb.sdk[internal].liveComponents.actionContainer;\n\n const actionQrProps: Parameters<typeof ActionQr>[0] = {\n amount: this.bb.world.session.amount,\n businessName: this.bb.world.business.name ?? \"\",\n channelName: this.bb.channel.brand_name,\n channelLogo: this.bb.channel.brand_logo_url,\n currency: this.bb.world.session.currency,\n hideUi: container?.getAttribute(\"data-qr-code-only\") === \"true\" || false,\n onAffirm: this.affirmPayment.bind(this),\n qrString: qrAction.value,\n parsedQr,\n title: qrAction.action_subtitle,\n t: this.bb.sdk.t.bind(this.bb.sdk),\n };\n\n const defaultActionContainerType = qrHasCustomArt\n ? DefaultActionContainerType.QrWithCustomArt\n : DefaultActionContainerType.Generic;\n this.cleanupFn = this.ensureHasActionContainer(defaultActionContainerType);\n this.populateActionContainer(() => createElement(ActionQr, actionQrProps));\n }\n\n /**\n * Fired when user affirms they have made the payment by clicking\n * the affirm button.\n */\n affirmPayment() {\n if (this.bb.sdk.isProdLive()) {\n // live mode\n this.bb.pollImmediatelyRequested = true;\n } else {\n this.bb.simulatePaymentRequested = true;\n }\n this.bb.dispatchEvent(new InternalBehaviorTreeUpdateEvent());\n }\n\n exit() {\n super.exit();\n }\n}\n","import { XenditWillRedirectEvent } from \"../../public-event-types\";\nimport { BlackboardType } from \"../behavior-tree\";\nimport { Behavior } from \"../behavior-tree-runner\";\n\nexport class ActionRedirectBehavior implements Behavior {\n constructor(\n private bb: BlackboardType,\n private url: string,\n ) {}\n\n enter() {\n this.bb.dispatchEvent(new XenditWillRedirectEvent());\n window.location.href = this.url;\n }\n}\n","import { ComponentChildren, Fragment, FunctionComponent } from \"preact\";\nimport { useState } from \"preact/hooks\";\nimport {\n FormattedString,\n InstructionsStep,\n InstructionsTab,\n Instructions as InstructionsType,\n} from \"../backend-types/instructions\";\nimport classNames from \"classnames\";\n\ntype Props = {\n instructions: InstructionsType;\n};\n\nexport const Instructions: FunctionComponent<Props> = ({ instructions }) => {\n switch (instructions.length) {\n case 0:\n return null;\n case 1:\n return <SingleTabInstructions instruction={instructions[0]} />;\n default:\n return <MultiTabInstructions instructions={instructions} />;\n }\n};\n\nexport const SingleTabInstructions: FunctionComponent<{\n instruction: InstructionsTab;\n}> = (props) => {\n return (\n <div>\n <p className=\"xendit-instructions-single-tab-heading\">\n {props.instruction.title}\n </p>\n <InstructionsSteps instruction={props.instruction} />\n </div>\n );\n};\n\nconst MultiTabInstructions: FunctionComponent<{\n instructions: InstructionsType;\n}> = (props) => {\n const [selectedTab, setSelectedTab] = useState(0);\n\n return (\n <div>\n <div className=\"xendit-instructions-tab-list\">\n {props.instructions.map((instruction, index) => (\n <button\n key={index}\n className={classNames(\"xendit-instructions-tab-button\", {\n [\"xendit-instructions-active-tab\"]: selectedTab === index,\n })}\n onClick={() => setSelectedTab(index)}\n >\n {instruction.title}\n </button>\n ))}\n </div>\n <InstructionsSteps instruction={props.instructions[selectedTab]} />\n </div>\n );\n};\n\nexport const InstructionsSteps: FunctionComponent<{\n instruction: InstructionsTab;\n}> = (props) => {\n return (\n <ol\n className=\"xendit-instructions-numbered-list\"\n data-testid=\"instructions-steps\"\n >\n {props.instruction.content.map((step, index) => {\n const stepItems = Array.isArray(step) ? step : [step];\n return (\n <li className=\"xendit-instructions-step-li\" key={index}>\n <div className=\"xendit-instructions-step-box\">\n {stepItems.map((s, i) => (\n <Fragment key={i}>{renderStep(s)}</Fragment>\n ))}\n </div>\n </li>\n );\n })}\n </ol>\n );\n};\n\nfunction renderFormattedStringElement(\n el: Element,\n i: number,\n): ComponentChildren {\n const className = classNames({\n [\"xendit-instructions-bold\"]: el.nodeName === \"B\",\n [\"xendit-instructions-italics\"]: el.nodeName === \"I\",\n });\n\n // render the children without wrapping if this is an element we don't want\n if (!className) return renderFormattedStringChildren(el.childNodes);\n\n return (\n <span className={className} key={i}>\n {renderFormattedStringChildren(el.childNodes)}\n </span>\n );\n}\n\nfunction renderFormattedStringChildren(nodes: NodeListOf<ChildNode>) {\n const parts = Array.from(nodes);\n const renderedNodes = parts.map((part, i) => {\n switch (part.nodeType) {\n case Node.TEXT_NODE:\n if (part.textContent === null) return null;\n return part.textContent;\n case Node.ELEMENT_NODE:\n return renderFormattedStringElement(part as Element, i);\n default:\n return null;\n }\n });\n return renderedNodes;\n}\n\nconst domParser = typeof DOMParser !== \"undefined\" ? new DOMParser() : null;\n\nfunction renderFormattedString(text: FormattedString): ComponentChildren {\n try {\n if (!domParser) return text;\n const doc = domParser.parseFromString(text, \"text/html\");\n return renderFormattedStringChildren(doc.body.childNodes);\n } catch (_) {\n return text;\n }\n}\n\nfunction renderStep(step: string | InstructionsStep): ComponentChildren {\n if (typeof step === \"string\") {\n return (\n <p className=\"xendit-instructions-step-item\">\n {renderFormattedString(step)}\n </p>\n );\n }\n\n switch (step.type) {\n case \"text\":\n return renderTextStep(step);\n case \"image\":\n return renderImageStep(step);\n case \"bullets\":\n return renderBulletsStep(step);\n case \"form\":\n return renderFormStep(step);\n case \"table\":\n return renderTableStep(step);\n }\n\n return null;\n}\n\nfunction renderTextStep(step: Extract<InstructionsStep, { type: \"text\" }>) {\n return <p>{renderFormattedString(step.text)}</p>;\n}\n\nfunction renderImageStep(step: Extract<InstructionsStep, { type: \"image\" }>) {\n return (\n <div>\n <img\n src={step.src}\n alt={step.alt || \"\"}\n style={{ height: `${step.height ?? 24}px` }}\n />\n </div>\n );\n}\n\nfunction renderBulletsStep(\n step: Extract<InstructionsStep, { type: \"bullets\" }>,\n) {\n return (\n <ul className=\"xendit-instructions-bullet-list\">\n {step.items.map((item, index) => (\n <li key={index}>{renderFormattedString(item)}</li>\n ))}\n </ul>\n );\n}\n\nfunction renderFormStep(step: Extract<InstructionsStep, { type: \"form\" }>) {\n return (\n <div className=\"xendit-instructions-form-card\">\n {step.heading ? (\n <h3 className=\"xendit-instructions-form-heading\">\n {renderFormattedString(step.heading)}\n </h3>\n ) : null}\n {step.fields.map((field, index) => (\n <div className=\"xendit-instructions-form-field\" key={index}>\n <div className=\"xendit-instructions-form-field-label\">\n {renderFormattedString(field.label)}\n </div>\n <div className=\"xendit-instructions-form-field-value\">\n {renderFormattedString(field.value)}\n </div>\n </div>\n ))}\n </div>\n );\n}\n\nfunction renderTableStep(step: Extract<InstructionsStep, { type: \"table\" }>) {\n return (\n <table className=\"xendit-instructions-table\">\n <thead>\n <tr>\n {step.headers.map((header, index) => (\n <th className=\"xendit-instructions-table-header\" key={index}>\n {renderFormattedString(header)}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {step.rows.map((row, rowIndex) => (\n <tr key={rowIndex}>\n {row.map((cell, cellIndex) => (\n <td className=\"xendit-instructions-table-cell\" key={cellIndex}>\n {renderFormattedString(cell)}\n </td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n );\n}\n","import { createContext, FunctionComponent } from \"preact\";\nimport {\n useCallback,\n useContext,\n useLayoutEffect,\n useState,\n} from \"preact/hooks\";\n\nexport const TooltipContext = createContext<{\n fire: (text: string) => void;\n clear: () => void;\n text: string;\n}>({\n fire: () => {},\n clear: () => {},\n text: \"\",\n});\n\nexport const TooltipProvider: FunctionComponent = ({ children }) => {\n const [text, setText] = useState(\"\");\n\n const fire = useCallback((text: string) => {\n setText(text);\n const timeout = setTimeout(() => {\n setText(\"\");\n }, 2000);\n return () => clearTimeout(timeout);\n }, []);\n\n const clear = useCallback(() => {\n setText(\"\");\n }, []);\n\n return (\n <TooltipContext.Provider value={{ text, fire, clear }}>\n <div style={{ position: \"relative\" }}>{children}</div>\n </TooltipContext.Provider>\n );\n};\n\nexport const Tooltip: FunctionComponent = () => {\n const { text, clear } = useContext(TooltipContext);\n\n useLayoutEffect(() => {\n if (text) {\n const fn = () => {\n clear();\n };\n document.body.addEventListener(\"mousedown\", fn);\n return () => {\n document.body.removeEventListener(\"mousedown\", fn);\n };\n }\n }, [clear, text]);\n\n if (!text) {\n return null;\n }\n\n return <div className=\"xendit-tooltip\">{text}</div>;\n};\n","import { FunctionComponent } from \"preact\";\nimport { useCallback, useContext, useState } from \"preact/hooks\";\nimport { amountFormat } from \"../amount-format\";\nimport { Instructions as InstructionsType } from \"../backend-types/instructions\";\nimport { TFunction } from \"../localization\";\nimport {\n Button,\n ButtonLoadingSpinner,\n ButtonSize,\n ButtonVariant,\n} from \"./core/button\";\nimport Icon from \"./icon\";\nimport { Instructions } from \"./instructions\";\nimport { Tooltip, TooltipContext, TooltipProvider } from \"./core/tooltip\";\n\ntype Props = {\n amount: number;\n channelLogo: string;\n currency: string;\n onAffirm: () => void;\n vaNumber: string;\n merchantName: string;\n instructions: InstructionsType;\n title: string;\n t: TFunction;\n};\n\nexport function ActionVa(props: Props) {\n const {\n amount,\n channelLogo,\n currency,\n onAffirm,\n vaNumber,\n merchantName,\n instructions,\n title,\n t,\n } = props;\n\n const [showSpinner, setShowSpinner] = useState(false);\n\n const onMadePaymentClicked = useCallback(() => {\n setShowSpinner(true);\n onAffirm();\n }, [onAffirm]);\n\n const vaDetails = [\n {\n heading: t(\"action_va.merchant_name\"),\n value: merchantName,\n },\n {\n heading: t(\"action_va.virtual_account_number\"),\n value: vaNumber,\n enableCopy: true,\n },\n {\n heading: t(\"action_va.amount_to_pay\"),\n value: amountFormat(amount, currency),\n enableCopy: true,\n },\n ];\n\n return (\n <div className=\"xendit-action-present-to-customer\">\n <img\n src={channelLogo}\n alt=\"Channel Logo\"\n className=\"xendit-action-qr-channel-logo\"\n />\n <div className=\"xendit-action-title\">{title}</div>\n <div className=\"xendit-action-va-content\">\n <div className=\"xendit-action-va-details\">\n {vaDetails.map((detail, index) => (\n <div key={index} className=\"xendit-action-va-detail-item\">\n <div className=\"xendit-action-va-detail-content\">\n <div className=\"xendit-action-va-heading xendit-text-12 xendit-text-semibold\">\n {detail.heading}\n </div>\n <div className=\"xendit-action-va-value xendit-text-semibold\">\n {detail.value}\n </div>\n </div>\n {detail.enableCopy ? (\n <TooltipProvider>\n <CopyButton value={detail.value} t={t} />\n <Tooltip />\n </TooltipProvider>\n ) : null}\n </div>\n ))}\n </div>\n </div>\n <div className=\"xendit-action-present-to-customer-affirm\">\n <Button\n variant={ButtonVariant.WHITE_ROUNDED}\n disabled={showSpinner}\n onClick={onMadePaymentClicked}\n className=\"xendit-button-block\"\n >\n {showSpinner ? <ButtonLoadingSpinner /> : t(\"action.payment_made\")}\n </Button>\n <div className=\"xendit-text-12 xendit-text-secondary xendit-text-center\">\n {t(\"action.payment_confirmation_instructions\")}\n </div>\n </div>\n <Instructions instructions={instructions} />\n </div>\n );\n}\n\nconst CopyButton: FunctionComponent<{ value: string; t: TFunction }> = ({\n value,\n t,\n}) => {\n const { fire } = useContext(TooltipContext);\n\n return (\n <Button\n variant={ButtonVariant.WHITE_ROUNDED}\n size={ButtonSize.SM}\n onClick={() => {\n navigator.clipboard.writeText(value);\n fire(t(\"action_va.copied_to_clipboard\"));\n }}\n >\n {t(\"action_va.copy\")}\n <Icon name=\"copy\" size={16} />\n </Button>\n );\n};\n","import { createElement } from \"preact\";\nimport { assert, assertEquals } from \"../../utils\";\nimport { BlackboardType } from \"../behavior-tree\";\nimport { ContainerActionBehavior } from \"./action\";\nimport { ActionVa } from \"../../components/action-va\";\nimport { InternalBehaviorTreeUpdateEvent } from \"../../private-event-types\";\n\nexport class ActionVaBehavior extends ContainerActionBehavior {\n constructor(\n protected bb: BlackboardType,\n private actionIndex: string,\n ) {\n super(bb);\n }\n\n enter() {\n const vaAction =\n this.bb.world?.paymentEntity?.entity.actions[Number(this.actionIndex)];\n\n assertEquals(vaAction?.type, \"PRESENT_TO_CUSTOMER\");\n assert(this.bb.world);\n assert(this.bb.channel);\n\n const actionVaProps = {\n amount: this.bb.world.session.amount,\n channelLogo: this.bb.channel.brand_logo_url,\n currency: this.bb.world.session.currency,\n onAffirm: this.affirmPayment.bind(this),\n vaNumber: vaAction.value,\n merchantName: this.bb.world.business.name ?? \"\",\n instructions: vaAction.instructions ?? [],\n title: vaAction.action_title,\n t: this.bb.sdk.t.bind(this.bb.sdk),\n };\n\n this.cleanupFn = this.ensureHasActionContainer();\n this.populateActionContainer(() => createElement(ActionVa, actionVaProps));\n }\n\n /**\n * Fired when user affirms they have made the payment by clicking\n * the affirm button.\n */\n affirmPayment() {\n if (this.bb.sdk.isProdLive()) {\n // live mode\n this.bb.pollImmediatelyRequested = true;\n } else {\n this.bb.simulatePaymentRequested = true;\n }\n this.bb.dispatchEvent(new InternalBehaviorTreeUpdateEvent());\n }\n}\n","import { lookupCardDetails } from \"../../api\";\nimport { InternalUpdateChannelComponentData } from \"../../private-event-types\";\nimport {\n AbortError,\n cancellableSleep,\n getCardNumberFromChannelProperties,\n isAbortError,\n parseEncryptedFieldValue,\n} from \"../../utils\";\nimport { BlackboardType } from \"../behavior-tree\";\nimport { Behavior } from \"../behavior-tree-runner\";\n\nexport class CardInfoBehavior implements Behavior {\n private cardDetailsRequest: {\n cardNumber: string;\n promise: Promise<void>;\n abortController: AbortController;\n } | null = null;\n\n constructor(\n public bb: BlackboardType,\n private channelCode: string,\n ) {}\n\n enter() {\n this.lookupCardDetails();\n }\n\n update() {\n this.lookupCardDetails();\n }\n\n exit() {\n this.abortLookupCardDetails();\n }\n\n abortLookupCardDetails() {\n if (this.cardDetailsRequest) {\n this.cardDetailsRequest.abortController.abort(new AbortError());\n this.cardDetailsRequest = null;\n }\n }\n\n lookupCardDetails() {\n const cardNumber = getCardNumberFromChannelProperties(\n this.bb.channelProperties,\n );\n if (!cardNumber) {\n return;\n }\n\n // don't look up the card number if a request is in flight for the same card number\n if (this.cardDetailsRequest?.cardNumber === cardNumber) {\n return;\n }\n\n // don't look up the card number if we already have the details\n if (this.bb.channelData?.cardDetails?.cardNumber === cardNumber) {\n return;\n }\n\n if (this.cardDetailsRequest) {\n this.abortLookupCardDetails();\n }\n\n const abortController = new AbortController();\n const promise = cancellableSleep(300, abortController.signal) // debounce\n .then(() => {\n if (this.bb.mock) {\n // in mock mode, if the ciphertext is actually a base64-encoded JSON string, then use that as the mock response\n const encodedError = parseEncryptedFieldValue(cardNumber).cipherText;\n try {\n return JSON.parse(atob(encodedError));\n } catch {\n // not json, ignore\n }\n\n // otherwise, return a fixed mock response\n return {\n schemes: [\"VISA\"],\n country_codes: [\"ID\"],\n require_billing_information: false,\n };\n } else {\n // remove encoded validation error -\n // normally, an invalid card number would have some other stuff appended to the end, but we still want to look up the card details even if the user hasn't finished typing\n const cleanedCardNumber =\n parseEncryptedFieldValue(cardNumber).withoutValidationError;\n\n // real card details\n return lookupCardDetails(\n this.bb.sdkKey,\n {\n card_number: cleanedCardNumber,\n },\n this.bb.sdkKey.sessionAuthKey,\n undefined,\n abortController.signal,\n );\n }\n })\n .then((response) => {\n this.bb.dispatchEvent(\n new InternalUpdateChannelComponentData(this.channelCode, {\n cardDetails: {\n cardNumber,\n details: response,\n },\n }),\n );\n })\n .catch((error) => {\n if (isAbortError(error)) return;\n throw error;\n });\n\n this.cardDetailsRequest = {\n cardNumber,\n promise,\n abortController,\n };\n }\n}\n","import { BlackboardType } from \"../behavior-tree\";\nimport { Behavior } from \"../behavior-tree-runner\";\n\n/**\n * If this exists, submission is blocked.\n */\nexport class ChannelInvalidBehavior implements Behavior {\n constructor(\n private bb: BlackboardType,\n private channelCode: string | null,\n ) {}\n\n enter() {}\n}\n","import {\n XenditNotReadyEvent,\n XenditReadyEvent,\n} from \"../../public-event-types\";\nimport { BlackboardType } from \"../behavior-tree\";\nimport { Behavior } from \"../behavior-tree-runner\";\n\nexport class ChannelValidBehavior implements Behavior {\n private lastChannelCode: string | null = null;\n\n constructor(private bb: BlackboardType) {}\n\n enter() {\n this.sendReadyEventIfChanged();\n }\n\n update() {\n this.sendReadyEventIfChanged();\n }\n\n sendReadyEventIfChanged() {\n const channelCode = this.bb.channel?.channel_code ?? null;\n if (channelCode && channelCode !== this.lastChannelCode) {\n this.bb.dispatchEvent(new XenditReadyEvent(channelCode));\n this.lastChannelCode = channelCode;\n }\n }\n\n exit() {\n this.bb.dispatchEvent(new XenditNotReadyEvent());\n }\n}\n","import { InternalBehaviorTreeUpdateEvent } from \"../../private-event-types\";\nimport { BlackboardType } from \"../behavior-tree\";\nimport { Behavior } from \"../behavior-tree-runner\";\n\nexport class PaymentEntityFailedBehavior implements Behavior {\n constructor(private bb: BlackboardType) {}\n\n enter() {\n this.bb.submissionRequested = false;\n this.bb.dispatchEvent(new InternalBehaviorTreeUpdateEvent());\n }\n}\n","import { pollSession } from \"../../../api\";\nimport { BffPollResponse } from \"../../../backend-types/common\";\nimport {\n BffPaymentEntity,\n toPaymentEntity,\n} from \"../../../backend-types/payment-entity\";\nimport { XenditComponents, XenditComponentsTest } from \"../../../public-sdk\";\nimport {\n MOCK_NETWORK_DELAY_MS,\n ParsedSdkKey,\n retryLoop,\n sleep,\n} from \"../../../utils\";\n\n/**\n * Polls the session status forever until stop() is called.\n *\n * @example\n * const poller = new PollWorker(sessionId, tokenRequestId, (updatedSession) => {\n * // handle session update\n * }, () => {\n * // handle error\n * });\n *\n * poller.start();\n * // later\n * poller.stop();\n */\nexport class PollWorker {\n started = false;\n stopped = false;\n\n constructor(\n private sdkKey: ParsedSdkKey,\n private sdk: XenditComponents,\n private sessionTokenRequestId: string | null,\n private onPollResult: (\n result: BffPollResponse,\n paymentEntity: BffPaymentEntity | null,\n ) => void,\n ) {}\n\n async start() {\n if (this.stopped) {\n throw new Error(\n \"PollWorker has been stopped, make a new instance instead of calling start again\",\n );\n }\n this.started = true;\n\n // retry loop with exponential backoff\n // chart of retry times:\n // https://www.desmos.com/calculator/3sihry02vd\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n for await (const attempt of retryLoop(5000, 100, 1.06)) {\n if (this.stopped) return;\n\n let response: BffPollResponse;\n\n if (this.sdk.isMock()) {\n // mock polling\n if (\n this.sdk instanceof XenditComponentsTest &&\n this.sdk.nextMockUpdate\n ) {\n await sleep(MOCK_NETWORK_DELAY_MS); // simulate network delay\n response = this.sdk.nextMockUpdate;\n this.sdk.nextMockUpdate = null;\n } else {\n continue;\n }\n } else {\n // real polling request\n try {\n response = await pollSession(\n this.sdkKey,\n this.sdkKey.sessionAuthKey,\n this.sessionTokenRequestId,\n );\n } catch (_err) {\n // TODO: error handling\n continue;\n }\n }\n if (this.stopped) return;\n\n if (!response.session) {\n throw new Error(\"Session is not defined\"); // should be impossible\n }\n\n let paymentEntity: BffPaymentEntity | null = null;\n if (response.payment_token) {\n paymentEntity = toPaymentEntity(response.payment_token);\n } else if (response.payment_request) {\n paymentEntity = toPaymentEntity(response.payment_request);\n }\n\n this.onPollResult(response, paymentEntity);\n\n // give the caller a chance to stop before we make the next request\n await sleep(1);\n }\n }\n\n isPolling() {\n return this.started && !this.stopped;\n }\n\n stop() {\n this.started = false;\n this.stopped = true;\n }\n}\n","import { BffPollResponse } from \"../../backend-types/common\";\nimport { BffPaymentEntity } from \"../../backend-types/payment-entity\";\nimport { assert } from \"../../utils\";\nimport {\n InternalScheduleMockUpdateEvent,\n InternalUpdateWorldState,\n} from \"../../private-event-types\";\nimport { BlackboardType } from \"../behavior-tree\";\nimport { Behavior } from \"../behavior-tree-runner\";\nimport { PollWorker } from \"./utils/poll-worker\";\nimport { makeTestPollResponse } from \"../../data/test-data-modifiers\";\n\nexport class PaymentEntityPendingBehavior implements Behavior {\n private pollWorker: PollWorker;\n constructor(private bb: BlackboardType) {\n this.pollWorker = new PollWorker(\n this.bb.sdkKey,\n this.bb.sdk,\n this.bb.world?.sessionTokenRequestId ?? null,\n this.onPollResult,\n );\n }\n\n enter() {\n if (this.bb.mock) {\n // if we get to pending state in mock mode, we need to schedule a mock update or nothing will happen.\n // usually, the payment entity will have a success/fail status and we need to also update the session status.\n assert(this.bb.world?.paymentEntity);\n switch (this.bb.world?.paymentEntity.entity.status) {\n case \"ACTIVE\":\n case \"AUTHORIZED\":\n case \"SUCCEEDED\":\n case \"PENDING\":\n this.bb.dispatchEvent(\n new InternalScheduleMockUpdateEvent(\n makeTestPollResponse(this.bb.world, this.bb.channel, \"SUCCESS\"),\n ),\n );\n break;\n case \"FAILED\":\n case \"CANCELED\":\n case \"EXPIRED\":\n this.bb.dispatchEvent(\n new InternalScheduleMockUpdateEvent(\n makeTestPollResponse(this.bb.world, this.bb.channel, \"FAILURE\"),\n ),\n );\n break;\n default:\n // should never happen, just stay in pending state forever :(\n }\n }\n\n this.pollWorker.start();\n }\n\n exit() {\n this.pollWorker.stop();\n }\n\n onPollResult = (\n pollResponse: BffPollResponse,\n paymentEntity: BffPaymentEntity | null,\n ) => {\n this.bb.dispatchEvent(\n new InternalUpdateWorldState({\n session: pollResponse.session,\n paymentEntity: paymentEntity ?? undefined, // do not clear payment entity if this returns undefined/null\n succeededChannel: pollResponse.succeeded_channel ?? null, // do set succeeded channel to null if it doesn't return one\n }),\n );\n };\n}\n","import { BffPollResponse } from \"../../backend-types/common\";\nimport { BffPaymentEntity } from \"../../backend-types/payment-entity\";\nimport { InternalUpdateWorldState } from \"../../private-event-types\";\nimport {\n XenditActionBeginEvent,\n XenditActionEndEvent,\n} from \"../../public-event-types\";\nimport { BlackboardType } from \"../behavior-tree\";\nimport { Behavior } from \"../behavior-tree-runner\";\nimport { PollWorker } from \"./utils/poll-worker\";\n\nexport class PaymentEntityRequiresActionBehavior implements Behavior {\n private pollWorker: PollWorker | null = null;\n public canCreateActionContainer: boolean = true;\n\n constructor(private bb: BlackboardType) {\n this.resetPolling();\n }\n\n enter() {\n this.bb.dispatchEvent(new XenditActionBeginEvent());\n this.canCreateActionContainer = false;\n this.pollWorker?.start();\n }\n\n update() {\n if (this.bb.pollImmediatelyRequested) {\n this.bb.pollImmediatelyRequested = false;\n this.resetPolling();\n }\n }\n\n exit() {\n this.pollWorker?.stop();\n this.bb.dispatchEvent(new XenditActionEndEvent());\n\n // clear flag for next time\n this.bb.actionCompleted = false;\n }\n\n onPollResult = (\n pollResponse: BffPollResponse,\n paymentEntity: BffPaymentEntity | null,\n ) => {\n this.bb.dispatchEvent(\n new InternalUpdateWorldState({\n session: pollResponse.session,\n paymentEntity: paymentEntity ?? undefined, // do not clear payment entity if this returns undefined/null\n succeededChannel: pollResponse.succeeded_channel ?? null, // do set succeeded channel to null if it doesn't return one\n }),\n );\n };\n\n /**\n * Stop the current poll worker and make a new one. Start polling if the previous pollWorker was polling.\n */\n resetPolling() {\n const polling = this.pollWorker?.isPolling() ?? false;\n this.pollWorker?.stop();\n this.pollWorker = new PollWorker(\n this.bb.sdkKey,\n this.bb.sdk,\n this.bb.world?.sessionTokenRequestId ?? null,\n this.onPollResult,\n );\n if (polling) {\n this.pollWorker.start();\n }\n }\n}\n","import { getPaymentOptions } from \"../../api\";\nimport { BffPaymentOptions } from \"../../backend-types/payment-options\";\nimport { BffSession } from \"../../backend-types/session\";\nimport { makeMockPaymentOptions } from \"../../data/test-data-modifiers\";\nimport { InternalUpdateChannelComponentData } from \"../../private-event-types\";\nimport {\n AbortError,\n assert,\n cancellableSleep,\n formHasFieldOfType,\n getCardNumberFromChannelProperties,\n isAbortError,\n MOCK_NETWORK_DELAY_MS,\n ParsedSdkKey,\n parseEncryptedFieldValue,\n} from \"../../utils\";\nimport { BlackboardType } from \"../behavior-tree\";\nimport { Behavior } from \"../behavior-tree-runner\";\n\nexport class PaymentOptionsBehavior implements Behavior {\n private paymentOptionsRequest: {\n cardNumber: string | undefined;\n promise: Promise<void>;\n abortController: AbortController;\n } | null = null;\n\n constructor(\n public bb: BlackboardType,\n private channelCode: string,\n ) {}\n\n enter() {\n this.lookupPaymentOptions();\n }\n\n update() {\n this.lookupPaymentOptions();\n }\n\n exit() {\n this.abortLookupPaymentOptions();\n }\n\n abortLookupPaymentOptions() {\n if (this.paymentOptionsRequest) {\n this.paymentOptionsRequest.abortController.abort(new AbortError());\n this.paymentOptionsRequest = null;\n }\n }\n\n lookupPaymentOptions() {\n assert(this.bb.world);\n assert(this.bb.channel);\n\n let cardNumber: string | undefined;\n if (formHasFieldOfType(this.bb.channel.form, \"credit_card_number\")) {\n cardNumber =\n getCardNumberFromChannelProperties(this.bb.channelProperties) ??\n undefined;\n\n // don't look up payment options if there's a card number field but it's not filled in\n if (!cardNumber) {\n return;\n }\n\n // don't look up the payment options if a request is in flight for the same card number\n if (this.paymentOptionsRequest?.cardNumber === cardNumber) {\n return;\n }\n\n // don't look up the payment options if we already have them for the same card numnber (including null)\n if (\n this.bb.channelData?.paymentOptions?.cardNumber ??\n null === cardNumber\n ) {\n return;\n }\n\n // don't look up payment options if the card number is invalid\n if (cardNumber) {\n const parsed = parseEncryptedFieldValue(cardNumber);\n if (!parsed.valid) {\n return;\n }\n }\n } else {\n // channel does not have a card number field, skip if any request is complete or in flight\n if (this.paymentOptionsRequest || this.bb.channelData?.paymentOptions) {\n return;\n }\n }\n\n if (this.paymentOptionsRequest) {\n this.abortLookupPaymentOptions();\n }\n\n const abortController = new AbortController();\n const promise = getPaymentOptionsAsync(\n this.bb.sdkKey,\n this.bb.world.session,\n this.bb.channel.channel_code,\n cardNumber,\n abortController.signal,\n this.bb.mock,\n )\n .then((response) => {\n this.bb.dispatchEvent(\n new InternalUpdateChannelComponentData(this.channelCode, {\n paymentOptions: {\n cardNumber: cardNumber ?? null,\n options: response,\n },\n }),\n );\n })\n .catch((error) => {\n if (isAbortError(error)) return;\n throw error;\n });\n\n this.paymentOptionsRequest = {\n cardNumber: cardNumber ?? undefined,\n promise,\n abortController,\n };\n }\n}\n\nasync function getPaymentOptionsAsync(\n sdkKey: ParsedSdkKey,\n session: BffSession,\n channelCode: string,\n cardNumber: string | undefined,\n abortSignal: AbortSignal,\n mock: boolean,\n): Promise<BffPaymentOptions> {\n if (mock) {\n // mock implementation\n return cancellableSleep(MOCK_NETWORK_DELAY_MS, abortSignal).then(() => {\n return makeMockPaymentOptions(channelCode, session);\n });\n } else {\n // real implementation\n const body = {\n channel_code: channelCode,\n channel_properties: cardNumber\n ? {\n card_number: cardNumber,\n }\n : undefined,\n };\n return getPaymentOptions(\n sdkKey,\n body,\n sdkKey.sessionAuthKey,\n null,\n abortSignal,\n );\n }\n}\n","import { InternalNeedsRerenderEvent } from \"../../private-event-types\";\nimport { XenditInitEvent } from \"../../public-event-types\";\nimport { BlackboardType } from \"../behavior-tree\";\nimport { Behavior } from \"../behavior-tree-runner\";\n\nexport class SdkActiveBehavior implements Behavior {\n constructor(private bb: BlackboardType) {}\n\n enter() {\n this.bb.dispatchEvent(new XenditInitEvent());\n\n // Schedule rerender (components don't render anything if the sdk state is not active)\n this.bb.dispatchEvent(new InternalNeedsRerenderEvent());\n }\n\n exit() {\n this.bb.dispatchEvent(new InternalNeedsRerenderEvent());\n }\n}\n","import { XenditFatalErrorEvent } from \"../../public-event-types\";\nimport { BlackboardType } from \"../behavior-tree\";\nimport { Behavior } from \"../behavior-tree-runner\";\n\nexport class SdkFatalErrorBehavior implements Behavior {\n constructor(private bb: BlackboardType) {}\n\n enter() {\n this.bb.dispatchEvent(\n new XenditFatalErrorEvent(\n this.bb.sdkFatalErrorMessage ?? \"Unknown error\",\n ),\n );\n }\n}\n","import { BlackboardType } from \"../behavior-tree\";\nimport { Behavior } from \"../behavior-tree-runner\";\n\nexport class SdkLoadingBehavior implements Behavior {\n constructor(private bb: BlackboardType) {}\n\n enter() {\n // do nothing\n }\n}\n","import { InternalNeedsRerenderEvent } from \"../../private-event-types\";\nimport { BlackboardType } from \"../behavior-tree\";\nimport { Behavior } from \"../behavior-tree-runner\";\n\nexport class SessionActiveBehavior implements Behavior {\n constructor(private bb: BlackboardType) {}\n\n enter() {\n // Schedule rerender (components don't render anything if the session state is not active)\n this.bb.dispatchEvent(new InternalNeedsRerenderEvent());\n }\n\n exit() {\n this.bb.dispatchEvent(new InternalNeedsRerenderEvent());\n }\n}\n","import { XenditSessionCompleteEvent } from \"../../public-event-types\";\nimport { BlackboardType } from \"../behavior-tree\";\nimport { Behavior } from \"../behavior-tree-runner\";\n\nexport class SessionCompletedBehavior implements Behavior {\n constructor(private bb: BlackboardType) {}\n\n enter() {\n this.bb.dispatchEvent(new XenditSessionCompleteEvent());\n }\n}\n","import { XenditSessionExpiredOrCanceledEvent } from \"../../public-event-types\";\nimport { BlackboardType } from \"../behavior-tree\";\nimport { Behavior } from \"../behavior-tree-runner\";\n\nexport class SessionFailedBehavior implements Behavior {\n constructor(private bb: BlackboardType) {}\n\n enter() {\n this.bb.dispatchEvent(new XenditSessionExpiredOrCanceledEvent());\n }\n}\n","import {\n BffPaymentEntity,\n BffPaymentEntityType,\n} from \"../../../backend-types/payment-entity\";\nimport { InternalUpdateWorldState } from \"../../../private-event-types\";\nimport {\n XenditPaymentRequestDiscardedEvent,\n XenditPaymentTokenDiscardedEvent,\n} from \"../../../public-event-types\";\nimport { BlackboardType } from \"../../behavior-tree\";\n\nexport function discardPaymentEntity(\n paymentEntity: BffPaymentEntity,\n dispatchEvent: BlackboardType[\"dispatchEvent\"],\n) {\n switch (paymentEntity.type) {\n case BffPaymentEntityType.PaymentRequest:\n dispatchEvent(new XenditPaymentRequestDiscardedEvent(paymentEntity.id));\n break;\n case BffPaymentEntityType.PaymentToken:\n dispatchEvent(new XenditPaymentTokenDiscardedEvent(paymentEntity.id));\n break;\n default:\n paymentEntity satisfies never;\n }\n dispatchEvent(\n new InternalUpdateWorldState({\n paymentEntity: null,\n sessionTokenRequestId: null,\n }),\n );\n}\n","import { BffPollResponse } from \"../../backend-types/common\";\nimport { BffPaymentEntity } from \"../../backend-types/payment-entity\";\nimport { InternalUpdateWorldState } from \"../../private-event-types\";\nimport {\n XenditSessionNotPendingEvent,\n XenditSessionPendingEvent,\n} from \"../../public-event-types\";\nimport { assert } from \"../../utils\";\nimport { BlackboardType } from \"../behavior-tree\";\nimport { Behavior } from \"../behavior-tree-runner\";\nimport { discardPaymentEntity } from \"./utils/discard\";\nimport { PollWorker } from \"./utils/poll-worker\";\n\nexport class SessionPendingBehavior implements Behavior {\n private pollWorker: PollWorker;\n\n constructor(private bb: BlackboardType) {\n this.pollWorker = new PollWorker(\n this.bb.sdkKey,\n this.bb.sdk,\n this.bb.world?.sessionTokenRequestId ?? null,\n this.onPollResult,\n );\n }\n\n enter() {\n this.pollWorker.start();\n\n this.bb.dispatchEvent(new XenditSessionPendingEvent());\n }\n\n exit() {\n this.pollWorker.stop();\n\n assert(this.bb.world?.session);\n\n // discard payment entity unless session is transitioning to COMPLETE\n const paymentEntity = this.bb.world.paymentEntity;\n if (this.bb.world.session.status !== \"COMPLETED\" && paymentEntity) {\n discardPaymentEntity(paymentEntity, this.bb.dispatchEvent);\n }\n\n this.bb.dispatchEvent(new XenditSessionNotPendingEvent());\n }\n\n onPollResult = (\n pollResponse: BffPollResponse,\n paymentEntity: BffPaymentEntity | null,\n ) => {\n this.bb.dispatchEvent(\n new InternalUpdateWorldState({\n session: pollResponse.session,\n paymentEntity: paymentEntity ?? undefined, // do not clear payment entity if this returns undefined/null\n succeededChannel: pollResponse.succeeded_channel ?? null, // do set succeeded channel to null if it doesn't return one\n }),\n );\n };\n}\n","import { simulatePaymentRequest } from \"../../api\";\nimport { BffChannel } from \"../../backend-types/channel\";\nimport { BffPaymentEntityType } from \"../../backend-types/payment-entity\";\nimport {\n makeTestPaymentRequest,\n makeTestPollResponse,\n} from \"../../data/test-data-modifiers\";\nimport {\n InternalBehaviorTreeUpdateEvent,\n InternalScheduleMockUpdateEvent,\n} from \"../../private-event-types\";\nimport {\n AbortError,\n cancellableSleep,\n isAbortError,\n MOCK_NETWORK_DELAY_MS,\n ParsedSdkKey,\n} from \"../../utils\";\nimport { BlackboardType } from \"../behavior-tree\";\nimport { Behavior } from \"../behavior-tree-runner\";\n\nexport class SimulatePaymentBehavior implements Behavior {\n exited = false;\n\n private simulationRequest: {\n promise: Promise<void>;\n abortController: AbortController;\n } | null = null;\n\n constructor(private bb: BlackboardType) {}\n\n enter() {\n this.simulatePayment();\n }\n\n exit() {\n this.exited = true;\n this.bb.simulatePaymentRequested = false;\n this.abortSimulation();\n }\n\n abortSimulation() {\n if (this.simulationRequest) {\n this.simulationRequest.abortController.abort(new AbortError());\n this.simulationRequest = null;\n }\n }\n\n simulatePayment() {\n if (this.simulationRequest) {\n this.abortSimulation();\n }\n\n if (!this.bb.channel) {\n throw new Error(\"Channel is missing\");\n }\n if (!this.bb.world) {\n throw new Error(\"Invalid state\");\n }\n if (!this.bb.world.paymentEntity) {\n throw new Error(\"Payment entity is missing\");\n }\n if (\n this.bb.world.paymentEntity.type !== BffPaymentEntityType.PaymentRequest\n ) {\n throw new Error(\"Payment entity is not a payment request\");\n }\n\n const paymentRequestId = this.bb.world?.paymentEntity.id;\n\n const abortController = new AbortController();\n const promise = simulatePaymentAsync(\n this.bb.sdkKey,\n this.bb.mock,\n this.bb.channel,\n paymentRequestId,\n abortController.signal,\n )\n .then(() => {\n if (this.bb.mock && this.bb.world) {\n // in mock mode, trigger transition to success state\n this.bb.dispatchEvent(\n new InternalScheduleMockUpdateEvent(\n makeTestPollResponse(this.bb.world, this.bb.channel, \"SUCCESS\"),\n ),\n );\n }\n\n this.bb.dispatchEvent(new InternalBehaviorTreeUpdateEvent());\n })\n .catch((error) => {\n if (isAbortError(error)) return;\n\n // ignore if we already exited\n if (!this.exited) {\n // exit the simulate payment state and log the error\n this.bb.simulatePaymentRequested = false;\n console.error(\"Simulate Payment failed:\", error);\n }\n });\n\n this.simulationRequest = {\n promise,\n abortController,\n };\n }\n}\n\nasync function simulatePaymentAsync(\n sdkKey: ParsedSdkKey,\n mock: boolean,\n channel: BffChannel,\n paymentRequestId: string,\n abortSignal: AbortSignal,\n) {\n if (mock) {\n await cancellableSleep(MOCK_NETWORK_DELAY_MS, abortSignal);\n return makeTestPaymentRequest(\n channel.channel_code,\n channel._mock_action_type,\n );\n } else {\n return await simulatePaymentRequest(\n sdkKey,\n {\n channel_code: channel.channel_code,\n },\n {\n sessionAuthKey: sdkKey.sessionAuthKey,\n paymentRequestId: paymentRequestId,\n },\n undefined,\n abortSignal,\n );\n }\n}\n","import { createPaymentRequest, createPaymentToken } from \"../../api\";\nimport { ChannelProperties, MockActionType } from \"../../backend-types/channel\";\nimport {\n BffPaymentEntity,\n BffPaymentEntityType,\n BffPaymentRequest,\n BffPaymentRequestFailureCode,\n BffPaymentToken,\n BffPaymentTokenFailureCode,\n getFailureCodeCopyKey,\n getPaymentEntityStatusCopyKey,\n toPaymentEntity,\n} from \"../../backend-types/payment-entity\";\nimport { BffSessionType } from \"../../backend-types/session\";\nimport {\n InternalBehaviorTreeUpdateEvent,\n InternalNeedsRerenderEvent,\n InternalScheduleMockUpdateEvent,\n InternalUpdateWorldState,\n} from \"../../private-event-types\";\nimport {\n XenditPaymentRequestCreatedEvent,\n XenditPaymentTokenCreatedEvent,\n XenditSubmissionBeginEvent,\n XenditSubmissionEndEvent,\n} from \"../../public-event-types\";\nimport {\n makeTestPaymentRequest,\n makeTestPaymentToken,\n} from \"../../data/test-data-modifiers\";\nimport {\n AbortError,\n assert,\n cancellableSleep,\n isAbortError,\n MOCK_NETWORK_DELAY_MS,\n ParsedSdkKey,\n} from \"../../utils\";\nimport { BlackboardType } from \"../behavior-tree\";\nimport { Behavior } from \"../behavior-tree-runner\";\nimport { NetworkError } from \"../../networking\";\nimport { TFunction } from \"../../localization\";\nimport { discardPaymentEntity } from \"./utils/discard\";\n\nexport type SubmissionError = {\n text: string[];\n code: string;\n};\n\nexport class SubmissionBehavior implements Behavior {\n private exited = false;\n\n private submission: {\n abortController: AbortController;\n promise: Promise<void>;\n } | null = null;\n private submissionError: Error | SubmissionError | null = null;\n\n constructor(private bb: BlackboardType) {}\n\n enter() {\n this.bb.dispatchEvent(new XenditSubmissionBeginEvent());\n this.bb.dispatchEvent(new InternalScheduleMockUpdateEvent(null));\n this.submit();\n }\n\n exit() {\n this.exited = true;\n\n assert(this.bb.world?.session);\n const t = this.bb.sdk.t;\n\n // If session is not complete or pending, discard payment entity\n const paymentEntity = this.bb.world.paymentEntity;\n if (\n this.bb.world.session.status !== \"COMPLETED\" &&\n this.bb.world.session.status !== \"PENDING\" &&\n paymentEntity\n ) {\n discardPaymentEntity(paymentEntity, this.bb.dispatchEvent);\n }\n\n // Determine reason for submission end\n let reason: string;\n let userErrorMessage: string[] | undefined = undefined;\n let developerErrorMessage:\n | {\n type: \"NETWORK_ERROR\" | \"ERROR\" | \"FAILURE\";\n code: string;\n }\n | undefined = undefined;\n\n if (this.bb.world.session.status !== \"ACTIVE\") {\n // if status is not active, that's why we ended submission\n reason = `SESSION_${this.bb.world.session.status}`;\n } else if (\n paymentEntity &&\n (paymentEntity.entity.status === \"FAILED\" ||\n paymentEntity.entity.status === \"CANCELED\" ||\n paymentEntity.entity.status === \"EXPIRED\")\n ) {\n // the payment entity failed, was canceled or expired\n reason = `PAYMENT_${paymentEntity.type}_${paymentEntity.entity.status}`;\n userErrorMessage = failureCodeUserErrorMessage(\n t,\n paymentEntity.type,\n paymentEntity.entity.status,\n paymentEntity.entity.failure_code,\n );\n developerErrorMessage = {\n type: \"FAILURE\",\n code: paymentEntity.entity.failure_code ?? \"UNKNOWN\",\n };\n } else if (this.submissionError) {\n // there was an error during submission\n reason = \"REQUEST_FAILED\";\n if (isSubmissionError(this.submissionError)) {\n // explicit error message from the server\n userErrorMessage = this.submissionError.text;\n developerErrorMessage = {\n type: \"ERROR\",\n code: this.submissionError.code,\n };\n } else {\n // unknown or network error\n userErrorMessage = defaultUserErrorMessage(t);\n developerErrorMessage = {\n type: \"NETWORK_ERROR\",\n code: \"NETWORK_ERROR\",\n };\n }\n } else if (this.submission) {\n // the submission is canceled during the request\n reason = \"REQUEST_ABORTED\";\n } else {\n // the submission was canceled during an action\n reason = \"ACTION_ABORTED\";\n }\n\n // Dispatch submission end event\n this.bb.dispatchEvent(\n new XenditSubmissionEndEvent(\n reason,\n userErrorMessage,\n developerErrorMessage,\n ),\n );\n\n // Abort ongoing submission request (the error will be ignored)\n if (this.submission) {\n this.submission?.abortController.abort(new AbortError());\n this.submission = null;\n }\n\n // Ensure submit flags are reset\n this.bb.submissionRequested = false;\n\n // Schedule rerender (to clear the inert attribute on the active component)\n this.bb.dispatchEvent(new InternalNeedsRerenderEvent());\n }\n\n private submit() {\n if (!this.bb.world?.session) {\n throw new Error(\"Session object missing\");\n }\n\n if (!this.bb.channel) {\n throw new Error(\"Channel missing\");\n }\n\n if (this.bb.instantSubmissionError) {\n this.bb.submissionRequested = false;\n this.submissionError = this.bb.instantSubmissionError;\n this.bb.instantSubmissionError = null;\n this.bb.dispatchEvent(new InternalBehaviorTreeUpdateEvent());\n return;\n }\n\n const shouldSendSavePaymentMethod =\n this.bb.world.session.allow_save_payment_method === \"OPTIONAL\" &&\n this.bb.channel?.allow_save;\n const sessionType = this.bb.world?.session?.session_type;\n const channelCode = this.bb.channel.channel_code;\n const mockActionType = this.bb.channel._mock_action_type;\n const channelProperties = this.bb.channelProperties ?? {};\n const abortController = new AbortController();\n const promise = asyncSubmit(\n this.bb.sdkKey,\n this.bb.mock,\n sessionType,\n channelCode,\n mockActionType,\n channelProperties,\n abortController,\n shouldSendSavePaymentMethod\n ? (this.bb.channelData?.savePaymentMethod ?? false)\n : undefined,\n )\n .then((paymentEntity: BffPaymentEntity) => {\n // clear abort controller since the request is complete\n this.submission = null;\n\n switch (paymentEntity.type) {\n case BffPaymentEntityType.PaymentRequest:\n this.bb.dispatchEvent(\n new XenditPaymentRequestCreatedEvent(paymentEntity.id),\n );\n break;\n case BffPaymentEntityType.PaymentToken:\n this.bb.dispatchEvent(\n new XenditPaymentTokenCreatedEvent(paymentEntity.id),\n );\n break;\n default:\n paymentEntity satisfies never;\n }\n\n // TODO: the payment-entity-created event should be sent only after the updateWorld call but that causes a behavior tree update which would cause events to fire in the wrong order\n this.bb.dispatchEvent(\n new InternalUpdateWorldState({\n paymentEntity,\n sessionTokenRequestId:\n paymentEntity.entity.session_token_request_id,\n }),\n );\n })\n .catch((error) => {\n if (isAbortError(error)) return;\n\n console.error(\"Submission failed:\", error);\n\n // avoid dispatching an event after exit\n if (!this.exited) {\n // set the error flag and exit the submission\n this.bb.submissionRequested = false;\n\n if (error instanceof NetworkError) {\n this.submissionError = {\n text: [\n error.errorResponse.error_content?.title,\n error.errorResponse.error_content?.message_1,\n error.errorResponse.error_content?.message_2,\n ].filter((str) => str !== undefined),\n code: error.errorResponse.error_code,\n };\n } else {\n this.submissionError = error;\n }\n\n this.bb.dispatchEvent(new InternalBehaviorTreeUpdateEvent());\n }\n });\n\n this.submission = {\n abortController,\n promise,\n };\n }\n}\n\nasync function asyncSubmit(\n sdkKey: ParsedSdkKey,\n mock: boolean,\n sessionType: BffSessionType,\n channelCode: string,\n mockActionType: MockActionType | undefined,\n channelProperties: ChannelProperties,\n abortController: AbortController,\n savePaymentMethod: boolean | undefined,\n): Promise<BffPaymentEntity> {\n let result: BffPaymentToken | BffPaymentRequest;\n if (mock) {\n // mock implementation\n switch (sessionType) {\n case \"PAY\": {\n await cancellableSleep(MOCK_NETWORK_DELAY_MS, abortController.signal);\n result = makeTestPaymentRequest(channelCode, mockActionType);\n break;\n }\n case \"SAVE\":\n case \"SUBSCRIPTION\": {\n await cancellableSleep(MOCK_NETWORK_DELAY_MS, abortController.signal);\n result = makeTestPaymentToken(channelCode, mockActionType);\n break;\n }\n default: {\n throw new Error(`The session type ${sessionType} is not supported.`);\n }\n }\n } else {\n // real implementation\n switch (sessionType) {\n case \"PAY\": {\n result = await createPaymentRequest(\n sdkKey,\n {\n session_id: sdkKey.sessionAuthKey,\n channel_code: channelCode,\n channel_properties: channelProperties,\n save_payment_method: savePaymentMethod,\n // TODO: pass customer for VA channels\n },\n null,\n null,\n abortController.signal,\n );\n break;\n }\n case \"SAVE\":\n case \"SUBSCRIPTION\": {\n result = await createPaymentToken(\n sdkKey,\n {\n session_id: sdkKey.sessionAuthKey,\n channel_code: channelCode,\n channel_properties: channelProperties,\n },\n null,\n null,\n abortController.signal,\n );\n break;\n }\n default: {\n throw new Error(`The session type ${sessionType} is not supported.`);\n }\n }\n }\n\n return toPaymentEntity(result);\n}\n\nfunction defaultUserErrorMessage(t: TFunction): string[] {\n return [\n t(\"default_error.title\"),\n t(\"default_error.message_1\"),\n t(\"default_error.message_2\"),\n ];\n}\n\nfunction failureCodeUserErrorMessage(\n t: TFunction,\n type: BffPaymentEntityType,\n status: \"FAILED\" | \"EXPIRED\" | \"CANCELED\",\n failureCode:\n | BffPaymentTokenFailureCode\n | BffPaymentRequestFailureCode\n | undefined,\n): string[] {\n const title = t(getPaymentEntityStatusCopyKey(type, status, \"title\"));\n const subtext = failureCode\n ? t(\n getFailureCodeCopyKey(failureCode),\n t(\"failure_code_unknown\", { failureCode }),\n )\n : t(getPaymentEntityStatusCopyKey(type, status, \"subtext\"));\n return [title, subtext];\n}\n\nfunction isSubmissionError(\n error: Error | SubmissionError,\n): error is SubmissionError {\n return !(\"message\" in error) && \"text\" in error && \"code\" in error;\n}\n","import { BffChannel, ChannelProperties } from \"../backend-types/channel\";\nimport { BffAction, BffPaymentEntity } from \"../backend-types/payment-entity\";\nimport { BffSession } from \"../backend-types/session\";\nimport {\n ChannelComponentData,\n WorldState,\n XenditComponents,\n} from \"../public-sdk\";\nimport {\n assert,\n canBeSimulated,\n findBestAction,\n findPaylinkAction,\n formHasFieldOfType,\n ParsedSdkKey,\n redirectCanBeHandledInIframe,\n} from \"../utils\";\nimport { channelPropertiesAreValid } from \"../validation\";\nimport { behaviorNode } from \"./behavior-tree-runner\";\nimport { ActionCompletedBehavior } from \"./behaviors/action-completed\";\nimport { ActionDeepLinkBehavior } from \"./behaviors/action-deep-link\";\nimport { ActionEmptyListPushNotificationBehavior } from \"./behaviors/action-empty-list-push-notification\";\nimport { ActionIframeBehavior } from \"./behaviors/action-iframe\";\nimport { ActionPaylinkBehavior } from \"./behaviors/action-paylink\";\nimport { ActionQrBehavior } from \"./behaviors/action-qr\";\nimport { ActionRedirectBehavior } from \"./behaviors/action-redirect\";\nimport { ActionVaBehavior } from \"./behaviors/action-va\";\nimport { CardInfoBehavior } from \"./behaviors/card-info\";\nimport { ChannelInvalidBehavior } from \"./behaviors/channel-invalid\";\nimport { ChannelValidBehavior } from \"./behaviors/channel-valid\";\nimport { PaymentEntityFailedBehavior } from \"./behaviors/payment-entity-failed\";\nimport { PaymentEntityPendingBehavior } from \"./behaviors/payment-entity-pending\";\nimport { PaymentEntityRequiresActionBehavior } from \"./behaviors/payment-entity-requires-action\";\nimport { PaymentOptionsBehavior } from \"./behaviors/payment-options\";\nimport { SdkActiveBehavior } from \"./behaviors/sdk-active\";\nimport { SdkFatalErrorBehavior } from \"./behaviors/sdk-fatal-error\";\nimport { SdkLoadingBehavior } from \"./behaviors/sdk-loading\";\nimport { SessionActiveBehavior } from \"./behaviors/session-active\";\nimport { SessionCompletedBehavior } from \"./behaviors/session-completed\";\nimport { SessionFailedBehavior } from \"./behaviors/session-failed\";\nimport { SessionPendingBehavior } from \"./behaviors/session-pending\";\nimport { SimulatePaymentBehavior } from \"./behaviors/simulate-payment\";\nimport { SubmissionBehavior, SubmissionError } from \"./behaviors/submission\";\n\nexport type SdkStatus = \"ACTIVE\" | \"LOADING\" | \"FATAL_ERROR\";\n\n/**\n * \"Blackboard\" means mutable state available to the behavior tree and all behavior instances.\n */\nexport type BlackboardType = {\n readonly sdk: XenditComponents;\n readonly mock: boolean;\n readonly sdkKey: ParsedSdkKey;\n\n // backend state\n world: WorldState | null;\n\n // current UI state\n sdkStatus: SdkStatus;\n sdkFatalErrorMessage: string | null;\n channel: BffChannel | null;\n channelProperties: ChannelProperties | null;\n channelData: ChannelComponentData | null;\n channelIsDigitalWallet: boolean;\n instantSubmissionError: SubmissionError | null;\n\n // dispatch event on the SDK instance\n dispatchEvent(event: Event): boolean;\n\n // flags\n // if true, start a submission, if false abort submission\n submissionRequested: boolean;\n // if true, start simulate payment, if false abort simulate payment\n simulatePaymentRequested: boolean;\n // if true, do not show the current action UI\n actionCompleted: boolean;\n // if true, poll the payment entity immediately on the next update\n pollImmediatelyRequested: boolean;\n // if true, don't exit ovo's and jeniuspay's ActionEmptyListPushNotificationBehavior when the payment request status changes to pending\n hackyOvoActionLatch?: boolean;\n};\n\nexport function behaviorTreeForSdk(bb: BlackboardType) {\n switch (bb.sdkStatus) {\n case \"LOADING\": {\n return behaviorNode(SdkLoadingBehavior);\n }\n case \"ACTIVE\": {\n return behaviorNode(\n SdkActiveBehavior,\n \"active\",\n behaviorTreeForSession(bb),\n );\n }\n case \"FATAL_ERROR\": {\n return behaviorNode(SdkFatalErrorBehavior);\n }\n default: {\n bb.sdkStatus satisfies never;\n throw new Error(`Unknown SDK status: ${bb.sdkStatus as SdkStatus}`);\n }\n }\n}\n\nexport function behaviorTreeForSession(bb: BlackboardType) {\n assert(bb.world?.session);\n\n switch (bb.world.session.status) {\n case \"ACTIVE\": {\n return behaviorNode(\n SessionActiveBehavior,\n \"active\",\n bb.submissionRequested\n ? behaviorTreeForSubmission(bb)\n : behaviorTreeForForm(bb),\n );\n }\n case \"COMPLETED\": {\n return behaviorNode(SessionCompletedBehavior);\n }\n case \"EXPIRED\": {\n return behaviorNode(SessionFailedBehavior, bb.world.session.status);\n }\n case \"CANCELED\": {\n return behaviorNode(SessionFailedBehavior, bb.world.session.status);\n }\n case \"PENDING\": {\n return behaviorNode(SessionPendingBehavior, bb.world.session.status);\n }\n default: {\n bb.world.session.status satisfies never;\n throw new Error(\n `Unknown session status: ${(bb.world.session as BffSession).status}`,\n );\n }\n }\n}\n\nexport function behaviorTreeForForm(bb: BlackboardType) {\n if (!bb.channel || !bb.world?.session) {\n return undefined;\n }\n\n if (bb.channelIsDigitalWallet) {\n return undefined;\n }\n\n const channelPropertiesValid = channelPropertiesAreValid(\n bb.world.session.session_type,\n bb.channel,\n bb.channelProperties,\n bb.channelData,\n );\n\n const validityBehavior = channelPropertiesValid\n ? behaviorNode(ChannelValidBehavior)\n : behaviorNode(ChannelInvalidBehavior);\n\n const cardInfoBehavior = formHasFieldOfType(\n bb.channel.form,\n \"credit_card_number\",\n )\n ? behaviorNode(CardInfoBehavior, bb.channel.channel_code)\n : undefined;\n\n const paymentOptionsBehavior = formHasFieldOfType(\n bb.channel.form,\n \"installment_plan\",\n )\n ? behaviorNode(PaymentOptionsBehavior, bb.channel.channel_code)\n : undefined;\n\n return [validityBehavior, cardInfoBehavior, paymentOptionsBehavior];\n}\n\nexport function behaviorTreeForSubmission(bb: BlackboardType) {\n assert(bb.world);\n\n return behaviorNode(\n SubmissionBehavior,\n \"submission\",\n bb.world.paymentEntity && bb.world.sessionTokenRequestId !== null\n ? behaviorTreeForPaymentEntity(bb)\n : undefined,\n );\n}\n\nexport function behaviorTreeForPaymentEntity(bb: BlackboardType) {\n assert(bb.world?.paymentEntity);\n\n function maybePaylinkAction() {\n assert(bb.world?.paymentEntity);\n return findPaylinkAction(bb.sdk, bb.world.paymentEntity.entity.actions)\n ? behaviorTreeForPaylink(bb)\n : undefined;\n }\n\n if (\n bb.hackyOvoActionLatch &&\n bb.world.paymentEntity.entity.status === \"PENDING\"\n ) {\n // In ovo and jeniuspay, the REQUIRES_ACTION status changes to PENDING almost immediately, causing the instructions to the user to close.\n // We need to keep this behavior alive until the status changes to something other than PENDING.\n return behaviorNode(\n PaymentEntityRequiresActionBehavior,\n bb.world.paymentEntity.id,\n [\n behaviorNode(ActionEmptyListPushNotificationBehavior, \"\"),\n maybePaylinkAction(),\n ],\n );\n }\n\n switch (bb.world.paymentEntity.entity.status) {\n case \"PENDING\": {\n return behaviorNode(PaymentEntityPendingBehavior);\n }\n case \"REQUIRES_ACTION\": {\n return behaviorNode(\n PaymentEntityRequiresActionBehavior,\n bb.world.paymentEntity.id,\n [behaviorTreeForAction(bb), maybePaylinkAction()],\n );\n }\n case \"FAILED\":\n case \"EXPIRED\":\n case \"CANCELED\": {\n return behaviorNode(PaymentEntityFailedBehavior);\n }\n case \"ACCEPTING_PAYMENTS\": {\n // Never happens because sessions don't set the PR type to REUSABLE_PAYMENT_CODE\n throw new Error(\"Status ACCEPTING_PAYMENTS should not happen\");\n }\n case \"AUTHORIZED\":\n case \"ACTIVE\":\n case \"SUCCEEDED\": {\n // The payemnt entity is completed but the session is still active, it should automatically switch to completed soon\n return behaviorNode(\n PaymentEntityPendingBehavior,\n bb.world.paymentEntity.id,\n );\n }\n default: {\n bb.world.paymentEntity.entity satisfies never;\n throw new Error(\n `Unknown payment entity status: ${(bb.world.paymentEntity as BffPaymentEntity).entity.status}`,\n );\n }\n }\n}\n\nexport function behaviorTreeForAction(bb: BlackboardType) {\n assert(bb.world?.paymentEntity);\n\n if (bb.actionCompleted) {\n // action completed is for when we want to close the action UI and go back to polling\n return behaviorNode(ActionCompletedBehavior);\n }\n\n const action = findBestAction(bb.world.paymentEntity.entity.actions);\n\n if (!action) {\n // an empty list of actions means we prompt the user to tap a push notification\n return behaviorNode(ActionEmptyListPushNotificationBehavior, \"\");\n }\n\n const actionIndex = bb.world.paymentEntity.entity.actions.indexOf(action);\n const hasPaylink = !!findPaylinkAction(\n bb.sdk,\n bb.world.paymentEntity.entity.actions,\n );\n\n // adds simulate payment behavior as a child of the action behavior so that when\n // simulate payment is requested, it will run the simulate payment behavior while\n // keeping the action UI open until the payment entity updates\n let simulateBehavior = undefined;\n if (bb.simulatePaymentRequested && canBeSimulated(action)) {\n simulateBehavior = behaviorNode(SimulatePaymentBehavior);\n }\n\n switch (action.type) {\n case \"REDIRECT_CUSTOMER\": {\n switch (action.descriptor) {\n case \"WEB_URL\": {\n if (redirectCanBeHandledInIframe(action)) {\n return behaviorNode(ActionIframeBehavior, action.value);\n } else if (hasPaylink) {\n return behaviorNode(ActionDeepLinkBehavior, String(actionIndex));\n } else {\n return behaviorNode(ActionRedirectBehavior, action.value);\n }\n }\n case \"DEEPLINK_URL\": {\n return behaviorNode(ActionDeepLinkBehavior, String(actionIndex));\n }\n case \"WEB_GOOGLE_PAYLINK\": {\n throw new Error(`Paylink actions should not be the primary action`);\n }\n }\n break;\n }\n case \"PRESENT_TO_CUSTOMER\": {\n switch (action.descriptor) {\n case \"QR_STRING\": {\n return behaviorNode(\n ActionQrBehavior,\n String(actionIndex),\n simulateBehavior,\n );\n }\n case \"PAYMENT_CODE\": {\n throw new Error(\n `Unsupported action type ${action.type} ${action.descriptor}`,\n );\n }\n case \"VIRTUAL_ACCOUNT_NUMBER\": {\n return behaviorNode(\n ActionVaBehavior,\n String(actionIndex),\n simulateBehavior,\n );\n }\n }\n break;\n }\n case \"API_POST_REQUEST\": {\n switch (action.descriptor) {\n case \"CAPTURE_PAYMENT\": {\n throw new Error(\n `Unsupported action type ${action.type} ${action.descriptor}`,\n );\n }\n case \"VALIDATE_OTP\": {\n throw new Error(\n `Unsupported action type ${action.type} ${action.descriptor}`,\n );\n }\n case \"RESEND_OTP\": {\n throw new Error(\n `Unsupported action type ${action.type} ${action.descriptor}`,\n );\n }\n }\n break;\n }\n }\n action satisfies never;\n throw new Error(\n `Unknown action type: ${(action as BffAction).type} ${(action as BffAction).descriptor}`,\n );\n}\n\nfunction behaviorTreeForPaylink(bb: BlackboardType) {\n assert(bb.world?.paymentEntity);\n\n const paylinkAction = findPaylinkAction(\n bb.sdk,\n bb.world.paymentEntity.entity.actions,\n );\n assert(paylinkAction);\n\n const actionIndex =\n bb.world.paymentEntity.entity.actions.indexOf(paylinkAction);\n return behaviorNode(ActionPaylinkBehavior, String(actionIndex));\n}\n","import { FunctionComponent } from \"preact\";\nimport { useCallback, useLayoutEffect, useMemo, useRef } from \"preact/hooks\";\nimport {\n useBusiness,\n useDigitalWallets,\n useSdk,\n useSession,\n} from \"./session-provider\";\nimport { ChannelProperties } from \"../backend-types/channel\";\nimport { XenditPaymentChannel } from \"../public-data-types\";\nimport { assert } from \"../utils\";\nimport { DigitalWalletOptions } from \"../public-options-types\";\n\ntype Props = {\n options?: DigitalWalletOptions<\"GOOGLE_PAY\">;\n onReady: () => void;\n};\n\nexport const DigitalWalletGooglepay: FunctionComponent<Props> = (props) => {\n const { onReady, options } = props;\n\n const sdk = useSdk();\n const t = sdk.t;\n\n const session = useSession();\n const business = useBusiness();\n const digitalWallets = useDigitalWallets();\n const digitalWalletsGooglePay = digitalWallets?.google_pay;\n assert(digitalWalletsGooglePay);\n\n const didCallReady = useRef(false);\n const containerRef = useRef<HTMLDivElement>(null);\n\n const paymentsClient = useRef<google.payments.api.PaymentsClient | null>(\n null,\n );\n\n const googlePayChannels = useMemo(() => {\n return digitalWalletsGooglePay.allowed_payment_methods.map(\n (obj) => obj.payment_method_specification,\n );\n }, [digitalWalletsGooglePay.allowed_payment_methods]);\n\n const googlePayConfig: google.payments.api.PaymentDataRequest = useMemo(\n () => ({\n apiVersion: 2,\n apiVersionMinor: 0,\n allowedPaymentMethods: googlePayChannels,\n emailRequired: true,\n merchantInfo: {\n merchantId: digitalWalletsGooglePay.merchant_id,\n merchantName: business.name ?? \"\",\n },\n transactionInfo: {\n transactionId: session.payment_session_id,\n totalPriceStatus: \"FINAL\",\n totalPrice: String(session.amount),\n currencyCode: session.currency,\n },\n }),\n [\n business.name,\n digitalWalletsGooglePay.merchant_id,\n googlePayChannels,\n session.amount,\n session.currency,\n session.payment_session_id,\n ],\n );\n\n const buttonConfigWithDefaults: Omit<\n google.payments.api.ButtonOptions,\n \"onClick\"\n > = useMemo(\n () => ({\n buttonColor: \"default\",\n buttonType: \"plain\",\n buttonRadius: 999,\n buttonSizeMode: \"fill\",\n buttonBorderType: \"no_border\",\n ...options,\n }),\n [options],\n );\n\n useLayoutEffect(() => {\n const PaymentsClient = window.google?.payments?.api?.PaymentsClient;\n if (!PaymentsClient) {\n console.error(\n \"XenditComponents: Google Pay button was requested but the Google Pay SDK is not loaded.\",\n );\n return;\n }\n paymentsClient.current = new PaymentsClient({\n environment: sdk.isMock() ? \"TEST\" : \"PRODUCTION\",\n });\n }, [sdk]);\n\n const onClick = useCallback(() => {\n assert(paymentsClient.current);\n\n // return the channel corresponding to the selected payment method in google pay\n function findTargetChannel(paymentData: google.payments.api.PaymentData) {\n assert(digitalWalletsGooglePay);\n\n const allChannels = sdk.getActiveChannels();\n for (const googlePayChannel of digitalWalletsGooglePay.allowed_payment_methods) {\n if (\n googlePayChannel.payment_method_specification.type ===\n paymentData.paymentMethodData.type\n ) {\n return findChannel(allChannels, googlePayChannel.channel_code);\n }\n }\n\n throw new Error(\n `No matching channel found for selected Google Pay payment method ${paymentData.paymentMethodData.type}`,\n );\n }\n\n paymentsClient.current\n .loadPaymentData(googlePayConfig)\n .then(function (paymentData) {\n const targetChannel = findTargetChannel(paymentData);\n assert(targetChannel);\n\n let channelProperties: ChannelProperties = {};\n if (targetChannel.channelCode === \"CARDS\") {\n // for cards, pass the whole paymentData to backend in channel properties\n channelProperties = {\n google_pay: JSON.stringify(paymentData),\n };\n }\n\n sdk.submitDigitalWallet(\"GOOGLE_PAY\", targetChannel, channelProperties);\n })\n .catch(function (err) {\n type GooglePayErrorCode =\n | \"CANCELED\"\n | \"DEVELOPER_ERROR\"\n | \"BUYER_ACCOUNT_ERROR\"\n | \"MERCHANT_ACCOUNT_ERROR\"\n | \"INTERNAL_ERROR\"\n | \"UNKNOWN_ERROR\";\n const statusCode =\n (err.statusCode as GooglePayErrorCode) ?? \"UNKNOWN_ERROR\";\n\n if (statusCode === \"CANCELED\") {\n return;\n }\n\n function localeKeyForGooglePayError<\n T extends GooglePayErrorCode,\n U extends \"title\" | \"message\",\n >(errorCode: T, suffix: U) {\n return `google_pay_errors.${errorCode.toLowerCase() as Lowercase<T>}.${suffix}` as const;\n }\n\n const submissionError = {\n code: `GOOGLE_PAY_${statusCode}` as const,\n text: [\n t(\n localeKeyForGooglePayError(statusCode, \"title\"),\n t(\"google_pay_errors.unknown_error.title\"),\n ),\n t(\n localeKeyForGooglePayError(statusCode, \"message\"),\n t(\"google_pay_errors.unknown_error.message\", { statusCode }),\n ),\n ],\n };\n\n // there is no target channel on errors, pick the channel used for the first allowed payment method\n const firstGooglePayChannel =\n digitalWalletsGooglePay.allowed_payment_methods[0];\n assert(firstGooglePayChannel);\n const targetChannel = findChannel(\n sdk.getActiveChannels(),\n firstGooglePayChannel.channel_code,\n );\n\n // submit and force an error\n sdk.submitDigitalWallet(\n \"GOOGLE_PAY\",\n targetChannel,\n {},\n submissionError,\n );\n });\n }, [digitalWalletsGooglePay, googlePayConfig, sdk, t]);\n\n // call onready if the googlepay sdk is ready\n useLayoutEffect(() => {\n if (!paymentsClient.current) {\n return;\n }\n if (didCallReady.current) {\n return;\n }\n\n paymentsClient.current\n .isReadyToPay({\n apiVersion: 2,\n apiVersionMinor: 0,\n allowedPaymentMethods: googlePayChannels,\n })\n .then(function (response) {\n if (!response.result) {\n return;\n }\n\n if (didCallReady.current) return;\n didCallReady.current = true;\n onReady();\n })\n .catch(function (err) {\n console.error(\n \"XenditComponents: Error when checking if Google Pay is ready\",\n err,\n );\n });\n }, [googlePayChannels, onReady]);\n\n // create the button\n useLayoutEffect(() => {\n if (!paymentsClient.current) {\n return;\n }\n\n const button = paymentsClient.current.createButton({\n ...buttonConfigWithDefaults,\n buttonLocale: session.locale,\n allowedPaymentMethods: googlePayChannels,\n onClick,\n });\n if (containerRef.current) {\n containerRef.current.replaceChildren(button);\n }\n }, [buttonConfigWithDefaults, googlePayChannels, onClick, session.locale]);\n\n return <div ref={containerRef}></div>;\n};\n\nfunction findChannel(\n allChannels: XenditPaymentChannel[],\n targetChannelCode: string,\n): XenditPaymentChannel {\n const ch = allChannels.find((channel) => {\n if (Array.isArray(channel.channelCode)) {\n return channel.channelCode.includes(targetChannelCode);\n }\n return channel.channelCode === targetChannelCode;\n });\n if (!ch) {\n throw new Error(`Channel not found for code: ${targetChannelCode}`);\n }\n return ch;\n}\n","import { ComponentChildren, FunctionComponent } from \"preact\";\nimport { useLayoutEffect, useState } from \"preact/hooks\";\nimport { SLEEP_MULTIPLIER } from \"../utils\";\n\n/**\n * Renders the children only if the condition passes. Re-checks the condition when the given script tag is loaded, or every second.\n */\nexport const DigitalWalletWaitForLoad: FunctionComponent<{\n scriptTagRegex: RegExp;\n checkLoaded: () => boolean;\n children: ComponentChildren;\n}> = (props) => {\n const { scriptTagRegex, checkLoaded, children } = props;\n\n const [, forceRender] = useState<object>({});\n const ok = checkLoaded();\n\n useLayoutEffect(() => {\n if (ok) return;\n\n const targetScript = Array.from(document.scripts).find((script) =>\n scriptTagRegex.test(script.src),\n );\n\n if (targetScript) {\n const fn = () => {\n forceRender({});\n };\n targetScript.addEventListener(\"load\", fn);\n return () => {\n targetScript.removeEventListener(\"load\", fn);\n };\n }\n }, [forceRender, ok, scriptTagRegex]);\n\n useLayoutEffect(() => {\n if (!ok) {\n const timeout = setTimeout(() => {\n forceRender({});\n }, 1000 * SLEEP_MULTIPLIER);\n return () => clearTimeout(timeout);\n }\n }); // <- intentionally no dependencies, this timer should run in a loop until the check passes\n\n return ok ? children : null;\n};\n","import { FunctionComponent, JSX } from \"preact\";\nimport { DigitalWalletGooglepay } from \"./digital-wallet-googlepay\";\nimport { DigitalWalletOptions } from \"../public-options-types\";\nimport { XenditDigitalWalletCode } from \"../public-data-types\";\nimport { useCallback, useRef } from \"preact/hooks\";\nimport { DigitalWalletWaitForLoad } from \"./digital-wallet-wait-for-load\";\n\ntype Props<T extends XenditDigitalWalletCode> = {\n digitalWalletCode: T;\n digitalWalletOptions?: DigitalWalletOptions<T>;\n};\n\nexport const DigitalWalletContainer: FunctionComponent<\n Props<XenditDigitalWalletCode>\n> = (props) => {\n const { digitalWalletCode, digitalWalletOptions } = props;\n\n const containerRef = useRef<HTMLDivElement>(null);\n\n const onReady = useCallback(() => {\n containerRef.current?.parentElement?.style.setProperty(\"display\", \"block\");\n }, []);\n\n let el: JSX.Element | null = null;\n switch (digitalWalletCode) {\n case \"GOOGLE_PAY\": {\n el = (\n <DigitalWalletWaitForLoad\n scriptTagRegex={sdkStatusCheckers.GOOGLE_PAY.scriptTagRegex}\n checkLoaded={sdkStatusCheckers.GOOGLE_PAY.checkLoaded}\n >\n <DigitalWalletGooglepay\n onReady={onReady}\n options={digitalWalletOptions}\n />\n </DigitalWalletWaitForLoad>\n );\n break;\n }\n }\n\n return <div ref={containerRef}>{el}</div>;\n};\n\nconst sdkStatusCheckers = {\n GOOGLE_PAY: {\n scriptTagRegex: /https:\\/\\/pay.google.com\\/.*\\/js\\/pay.js/,\n checkLoaded: () =>\n typeof google !== \"undefined\" && typeof google.payments !== \"undefined\",\n },\n};\n","import {\n XenditActionBeginEvent,\n XenditActionEndEvent,\n XenditFatalErrorEvent,\n XenditEventListener,\n XenditEventMap,\n XenditInitEvent,\n XenditPaymentRequestCreatedEvent,\n XenditPaymentRequestDiscardedEvent,\n XenditPaymentTokenCreatedEvent,\n XenditPaymentTokenDiscardedEvent,\n XenditReadyEvent,\n XenditSessionCompleteEvent,\n XenditSessionExpiredOrCanceledEvent,\n XenditSubmissionBeginEvent,\n XenditSubmissionEndEvent,\n XenditWillRedirectEvent,\n XenditSessionPendingEvent,\n XenditSessionNotPendingEvent,\n} from \"./public-event-types\";\nimport {\n XenditSdkOptions as XenditComponentsOptions,\n XenditGetChannelsOptions,\n ActionContainerOptions,\n DigitalWalletOptions,\n} from \"./public-options-types\";\nimport {\n XenditCustomer,\n XenditDigitalWallet,\n XenditDigitalWalletCode,\n XenditPaymentChannel,\n XenditPaymentChannelGroup,\n XenditSession,\n} from \"./public-data-types\";\nimport { internal } from \"./internal\";\nimport { createElement, createRef, RefObject, render } from \"preact\";\nimport {\n ChannelPickerRoot,\n XenditClearCurrentChannelEvent,\n} from \"./components/channel-picker-root\";\nimport { XenditSessionProvider } from \"./components/session-provider\";\nimport {\n BffChannel,\n BffChannelUiGroup,\n ChannelProperties,\n ChannelPropertyPrimative,\n} from \"./backend-types/channel\";\nimport {\n ChannelRoot,\n XenditChannelPropertiesChangedEvent,\n} from \"./components/channel-root\";\nimport { fetchSessionData } from \"./api\";\nimport { ChannelFormHandle } from \"./components/channel-form\";\nimport { BehaviorTree } from \"./lifecycle/behavior-tree-runner\";\nimport {\n behaviorTreeForSdk,\n BlackboardType,\n SdkStatus,\n} from \"./lifecycle/behavior-tree\";\nimport { BffSession } from \"./backend-types/session\";\nimport { BffBusiness } from \"./backend-types/business\";\nimport { BffCustomer } from \"./backend-types/customer\";\nimport { BffPaymentEntity } from \"./backend-types/payment-entity\";\nimport {\n InternalBehaviorTreeUpdateEvent,\n InternalNeedsRerenderEvent,\n InternalScheduleMockUpdateEvent,\n InternalUpdateChannelComponentData,\n InternalUpdateWorldState,\n} from \"./private-event-types\";\nimport {\n BffPollResponse,\n BffResponse,\n BffSucceededChannel,\n} from \"./backend-types/common\";\nimport {\n canBeSimulated,\n errorToString,\n findBestAction,\n lockDownInteralProperty,\n mergeIgnoringUndefined,\n MOCK_NETWORK_DELAY_MS,\n ParsedSdkKey,\n parseSdkKey,\n removeUnreleasedChannels,\n resolvePairedChannel,\n satisfiesMinMax,\n sleep,\n} from \"./utils\";\nimport { makeTestSdkKey } from \"./data/test-data-modifiers\";\nimport { PaymentEntityRequiresActionBehavior } from \"./lifecycle/behaviors/payment-entity-requires-action\";\nimport {\n SubmissionBehavior,\n SubmissionError,\n} from \"./lifecycle/behaviors/submission\";\nimport {\n bffChannelsToPublic,\n bffCustomerToPublic,\n bffDigitalWalletsToPublic,\n bffSessionToPublic,\n bffUiGroupsToPublic,\n findChannelPairs,\n} from \"./bff-marshal\";\nimport { BffCardDetails } from \"./backend-types/card-details\";\nimport { createTFunction, TFunction } from \"./localization\";\nimport { amountFormat } from \"./amount-format\";\nimport { BffPaymentOptions } from \"./backend-types/payment-options\";\nimport { DigitalWalletContainer } from \"./components/digital-wallet-container\";\nimport { BffDigitalWallets } from \"./backend-types/digital-wallets\";\nimport { ChannelInvalidBehavior } from \"./lifecycle/behaviors/channel-invalid\";\nimport { SessionActiveBehavior } from \"./lifecycle/behaviors/session-active\";\nimport { ChannelValidBehavior } from \"./lifecycle/behaviors/channel-valid\";\n\n/**\n * @internal\n * Represents payment channel state.\n */\ntype CachedChannelComponent = {\n element: HTMLElement;\n channel: XenditPaymentChannel;\n channelProperties: ChannelProperties | null;\n channelFormRef: RefObject<ChannelFormHandle>;\n data: ChannelComponentData;\n};\n\n/**\n * @internal\n * Properties of a component updatable by events\n */\nexport type ChannelComponentData = {\n savePaymentMethod: boolean;\n cardDetails: {\n cardNumber: string;\n details: BffCardDetails | null;\n } | null;\n paymentOptions: {\n cardNumber: string | null;\n options: BffPaymentOptions | null;\n } | null;\n};\n\n/**\n * @internal\n * The session and associated entities that we get from the backend.\n */\nexport type WorldState = {\n business: BffBusiness;\n customer: BffCustomer | null;\n session: BffSession;\n channels: BffChannel[];\n channelUiGroups: BffChannelUiGroup[];\n digitalWallets: BffDigitalWallets | null;\n paymentEntity: BffPaymentEntity | null;\n sessionTokenRequestId: string | null;\n succeededChannel: BffSucceededChannel | null;\n};\n\n/**\n * @internal\n * Updatable parts of the world state. Nulls are written, undefineds are ignored.\n */\nexport type UpdatableWorldState = {\n [K in\n | \"session\"\n | \"paymentEntity\"\n | \"sessionTokenRequestId\"\n | \"succeededChannel\"]?: WorldState[K] | undefined;\n};\n\n/**\n * @internal\n * Used to assert that the SDK is initialized.\n */\ntype InitializedSdk = {\n [internal]: {\n worldState: WorldState;\n };\n};\n\n/**\n * @public\n */\nexport class XenditComponents extends EventTarget {\n /**\n * @internal\n */\n public t: TFunction = (str: string): string => {\n throw new Error(\"Localization used before initialization; this is a bug.\");\n };\n\n /**\n * @internal\n */\n protected [internal]: {\n /**\n * Parsed SDK key components.\n */\n sdkKey: ParsedSdkKey;\n\n /**\n * User-provided options.\n */\n options: XenditComponentsOptions;\n\n /**\n * The session and ascociated data from the backend.\n */\n worldState: WorldState | null;\n\n /**\n * Behavior tree for state management.\n */\n behaviorTree: BehaviorTree<BlackboardType>;\n\n /**\n * Components the user has created\n */\n liveComponents: {\n channelPicker: HTMLElement | null;\n paymentChannels: Map<string, CachedChannelComponent>;\n actionContainer: HTMLElement | null;\n digitalWalletContainer: Map<\n XenditDigitalWalletCode,\n {\n element: HTMLElement;\n options: DigitalWalletOptions<XenditDigitalWalletCode> | undefined;\n }\n >;\n };\n\n /**\n * The most recently created payment channel component's channel code.\n * This is used as a key into `paymentChannelComponents`.\n */\n currentChannelCode: string | null;\n\n /**\n * The ongoing digital wallet submission, if any.\n */\n currentDigitalWalletSubmission: {\n digitalWalletCode: XenditDigitalWalletCode;\n channelCode: string;\n channelProperties: ChannelProperties;\n instantSubmissionError: SubmissionError | null;\n } | null;\n\n /**\n * Tracks which event listeners are present on the SDK instance.\n */\n eventListenersPresent: Map<string, boolean>;\n };\n\n /**\n * @public\n * Initialize the SDK for a given session.\n *\n * You can get the components sdk key from the components_sdk_key field of the\n * `POST /sessions` or `GET /session` endpoints.\n *\n * This creates an object that can be used to create UI components, that allow\n * users to make payment or save tokens, using a variety of channels, depending on\n * the session configuration.\n *\n * @example\n * ```\n * // initialize\n * const components = new XenditComponents({\n * componentsSdkKey: \"your-session-client-key\",\n * });\n * ```\n */\n constructor(options: XenditComponentsOptions) {\n super();\n\n if (typeof window === \"undefined\" || typeof document === \"undefined\") {\n throw new Error(\"XenditComponents can only be instantiated in a browser\");\n }\n\n const sdkKey = parseSdkKey(options.componentsSdkKey);\n this[internal] = {\n sdkKey,\n options,\n worldState: null,\n liveComponents: {\n channelPicker: null,\n paymentChannels: new Map(),\n actionContainer: null,\n digitalWalletContainer: new Map(),\n },\n behaviorTree: new BehaviorTree<BlackboardType>(behaviorTreeForSdk, {\n sdk: this,\n sdkKey,\n mock: this.isMock(),\n sdkStatus: \"LOADING\",\n sdkFatalErrorMessage: null,\n channel: null,\n channelProperties: null,\n channelData: null,\n channelIsDigitalWallet: false,\n instantSubmissionError: null,\n dispatchEvent: this.dispatchEvent.bind(this),\n world: null,\n submissionRequested: false,\n simulatePaymentRequested: false,\n actionCompleted: false,\n pollImmediatelyRequested: false,\n }),\n currentChannelCode: null,\n currentDigitalWalletSubmission: null,\n eventListenersPresent: new Map(),\n };\n lockDownInteralProperty(this as unknown as { [internal]: unknown });\n\n // log fatal errors if user didn't attach a listener\n this.addEventListener(\"fatal-error\", (event) => {\n const fatalErrorEvent = event as XenditFatalErrorEvent;\n if (!this[internal].eventListenersPresent.get(\"fatal-error\")) {\n console.error(\n `XenditComponents: A \"fatal-error\" event occurred but no event listener was attached: ${fatalErrorEvent.message}`,\n );\n }\n });\n this[internal].eventListenersPresent.set(\"fatal-error\", false);\n\n this.behaviorTreeUpdate();\n\n // internal event listeners\n (this as EventTarget).addEventListener(\n InternalUpdateWorldState.type,\n this.onUpdateWorldState.bind(this),\n );\n (this as EventTarget).addEventListener(\n InternalUpdateChannelComponentData.type,\n this.onUpdateChannelComponentData.bind(this),\n );\n (this as EventTarget).addEventListener(\n InternalBehaviorTreeUpdateEvent.type,\n this.behaviorTreeUpdate.bind(this),\n );\n let hasScheduledRender = false;\n (this as EventTarget).addEventListener(\n InternalNeedsRerenderEvent.type,\n () => {\n if (hasScheduledRender) return;\n hasScheduledRender = true;\n queueMicrotask(() => {\n hasScheduledRender = false;\n this.rerenderAllComponents();\n this.syncInertAttribute();\n });\n },\n );\n\n // Initialize session data asynchronously\n this.initializeAsync();\n }\n\n /**\n * @internal\n * Initialize session data asynchronously\n */\n protected async initializeAsync(): Promise<void> {\n let bff: BffResponse;\n try {\n // Fetch session data from the server\n bff = await fetchSessionData(\n this[internal].sdkKey,\n this[internal].sdkKey.sessionAuthKey,\n );\n bff.channels = removeUnreleasedChannels(bff.channels);\n } catch (error) {\n this[internal].behaviorTree.bb.sdkStatus = \"FATAL_ERROR\";\n this[internal].behaviorTree.bb.sdkFatalErrorMessage =\n errorToString(error);\n this.behaviorTreeUpdate();\n return;\n }\n\n // Update world state\n this.dispatchEvent(\n new InternalUpdateWorldState({\n business: bff.business,\n customer: bff.customer,\n session: bff.session,\n channels: bff.channels,\n channelUiGroups: bff.channel_ui_groups,\n digitalWallets: bff.digital_wallets ?? null,\n paymentEntity: null,\n sessionTokenRequestId: null,\n succeededChannel: null,\n } satisfies WorldState),\n );\n }\n\n /**\n * @internal\n * Throws if the SDK is not initialized.\n */\n public assertInitialized(): asserts this is InitializedSdk {\n if (!this[internal].worldState) {\n throw new Error(\n \"The session data is not loaded. Listen for the `init` event. Only `createChannelPickerComponent` can be called before initialization.\",\n );\n }\n }\n\n /**\n * @internal\n */\n public isMock(): boolean {\n return false;\n }\n\n /**\n * @internal\n */\n public isProdLive() {\n return this[internal].sdkKey.hostId === \"pl\";\n }\n\n /**\n * @internal\n */\n public supportsSimulationScenarios(): boolean {\n return (\n this.isMock() ||\n this[internal].sdkKey.hostId === \"pd\" ||\n this[internal].sdkKey.hostId === \"sd\"\n );\n }\n\n /**\n * @internal\n */\n private findChannel(channelCode: string) {\n this.assertInitialized();\n\n // TODO: use a map\n const channel = this[internal].worldState.channels.find(\n (ch) => ch.channel_code === channelCode,\n );\n return channel ?? null;\n }\n\n /**\n * @internal\n * Updates the session or other ascociated entities and syncs everything that depends on them.\n */\n private onUpdateWorldState(event: Event) {\n const data = (event as InternalUpdateWorldState).data;\n this[internal].worldState = mergeIgnoringUndefined(\n this[internal].worldState ?? ({} as WorldState),\n data,\n );\n\n // update locale\n const locale = this[internal].worldState.session.locale;\n this.t = createTFunction(locale);\n\n // update everything\n this.behaviorTreeUpdate();\n this.rerenderAllComponents();\n }\n\n /**\n * @internal\n * Updates channel component data and updates behavior tree and rerenders.\n */\n private onUpdateChannelComponentData(event: Event) {\n const channelCode = (event as InternalUpdateChannelComponentData)\n .channelCode;\n const newData = (event as InternalUpdateChannelComponentData).data;\n const component =\n this[internal].liveComponents.paymentChannels.get(channelCode);\n if (!component) {\n return;\n }\n\n component.data = mergeIgnoringUndefined(component.data, newData);\n this.behaviorTreeUpdate();\n\n // TODO: need to re-collect all channel properties since form fields may have been added or removed\n this.rerenderAllComponents();\n }\n\n /**\n * @internal\n * Updates the behavior tree with the latest world state and component state.\n */\n private behaviorTreeUpdate(): void {\n const bb = this[internal].behaviorTree.bb;\n\n if (bb.sdkStatus === \"LOADING\" && this[internal].worldState) {\n bb.sdkStatus = \"ACTIVE\";\n }\n\n bb.world = this[internal].worldState;\n\n if (this[internal].currentDigitalWalletSubmission) {\n // populate data for digital wallet submission\n bb.channel = this.findChannel(\n this[internal].currentDigitalWalletSubmission.channelCode,\n );\n bb.channelProperties =\n this[internal].currentDigitalWalletSubmission.channelProperties;\n bb.channelData = null;\n bb.channelIsDigitalWallet = true;\n bb.instantSubmissionError =\n this[internal].currentDigitalWalletSubmission.instantSubmissionError;\n } else {\n // populate data for normal channel component\n const component = this[internal].currentChannelCode\n ? this[internal].liveComponents.paymentChannels.get(\n this[internal].currentChannelCode,\n )\n : null;\n bb.channel = component\n ? resolvePairedChannel(\n component.channel[internal],\n component.data.savePaymentMethod,\n )\n : null;\n bb.channelProperties = component ? component.channelProperties : null;\n bb.channelData = component ? component.data : null;\n bb.channelIsDigitalWallet = false;\n }\n\n try {\n this[internal].behaviorTree.update();\n } catch (error) {\n // crash handler, move to fatal error state\n this[internal].behaviorTree.bb.sdkStatus = \"FATAL_ERROR\";\n this[internal].behaviorTree.bb.sdkFatalErrorMessage =\n errorToString(error);\n this[internal].behaviorTree.update();\n }\n }\n\n /**\n * @internal\n * Return the current SDK status.\n */\n public getSdkStatus(): SdkStatus {\n // TODO: pass this as a prop into SessionProvider instead\n return this[internal].behaviorTree.bb.sdkStatus;\n }\n\n /**\n * @internal\n * Rerender everything.\n */\n private rerenderAllComponents() {\n // re-render live components\n this.renderChannelPicker();\n for (const channelCode of this[\n internal\n ].liveComponents.paymentChannels.keys()) {\n this.renderPaymentChannel(channelCode);\n }\n for (const digitalWalletCode of this[\n internal\n ].liveComponents.digitalWalletContainer.keys()) {\n this.renderDigitalWalletComponent(digitalWalletCode);\n }\n }\n\n /**\n * @public\n * Retrieve the xendit session object.\n */\n getSession(): XenditSession {\n this.assertInitialized();\n return bffSessionToPublic(this[internal].worldState.session);\n }\n\n /**\n * @public\n * Retrieve the customer ascociated with the session.\n */\n getCustomer(): XenditCustomer | null {\n this.assertInitialized();\n if (!this[internal].worldState.customer) return null;\n return bffCustomerToPublic(this[internal].worldState.customer);\n }\n\n /**\n * @public\n * Retrieve the list of payment channels available for this session.\n *\n * The channels are organized in a way that is appropriate to show to users.\n * You can use this to render your channel picker UI.\n *\n * You can pass `{filter: \"CHANNEL_CODE\"}` to filter channels by string or regexp.\n */\n getActiveChannelGroups(\n options?: XenditGetChannelsOptions,\n ): XenditPaymentChannelGroup[] {\n this.assertInitialized();\n return bffUiGroupsToPublic(\n this[internal].worldState.channels,\n this[internal].worldState.channelUiGroups,\n {\n options: {\n filter: options?.filter,\n filterMinMax: options?.filterMinMax ?? true,\n },\n session: this[internal].worldState.session,\n pairChannels: findChannelPairs(this[internal].worldState.channels),\n },\n );\n }\n\n /**\n * @public\n * Retrieve an unorganized list of payment channels available for this session.\n *\n * Use this when you need to search for specific channels. When rendering your UI,\n * consider using `getActiveChannelGroups` if you support many channels.\n *\n * You can pass `{filter: \"CHANNEL_CODE\"}` to filter channels by string or regexp.\n */\n getActiveChannels(\n options?: XenditGetChannelsOptions,\n ): XenditPaymentChannel[] {\n this.assertInitialized();\n return bffChannelsToPublic(\n this[internal].worldState.channels,\n this[internal].worldState.channelUiGroups,\n {\n options: {\n filter: options?.filter,\n filterMinMax: options?.filterMinMax ?? true,\n },\n session: this[internal].worldState.session,\n pairChannels: findChannelPairs(this[internal].worldState.channels),\n },\n );\n }\n\n /**\n * @public\n * Creates a drop-in UI component for selecting a channel and making payments.\n *\n * This returns a div immediately. The component will be populated after\n * initialization is complete. You should insert this div into the DOM.\n *\n * Calling this again will destroy it and return a new element. Manually\n * destroying the component is not necessary, removing it from the DOM is sufficient.\n *\n * @example\n * ```\n * const channelPickerDiv = components.createChannelPickerComponent();\n * document.querySelector(\".payment-container\").appendChild(channelPickerDiv);\n * ```\n */\n createChannelPickerComponent(): HTMLElement {\n // destroy previous instance if it exists\n if (this[internal].liveComponents.channelPicker) {\n this.destroyComponent(this[internal].liveComponents.channelPicker);\n }\n\n const container = document.createElement(\"xendit-channel-picker\");\n container.setAttribute(\"translate\", \"no\");\n\n // Store the container for later population\n this[internal].liveComponents.channelPicker = container;\n\n // If initialization is complete, populate immediately\n // Otherwise, it will be populated when initializeAsync completes\n if (this[internal].worldState) {\n this.renderChannelPicker();\n }\n\n this.setupUiEventsForChannelPicker(container);\n\n return container;\n }\n\n /**\n * @internal\n * Render an existing channel picker element\n */\n private renderChannelPicker(): void {\n this.assertInitialized();\n\n const container = this[internal].liveComponents.channelPicker;\n if (!container) return;\n\n render(\n createElement(XenditSessionProvider, {\n data: this[internal].worldState,\n sdk: this,\n children: createElement(ChannelPickerRoot, {}),\n }),\n container,\n );\n }\n\n /**\n * @internal\n * Handles events from the channel picker component.\n */\n private setupUiEventsForChannelPicker(container: HTMLElement): void {\n // clear current channel when the channel picker accordion is closed\n container.addEventListener(\n XenditClearCurrentChannelEvent.type,\n (_event) => {\n this.assertInitialized();\n\n // do nothing if the current channel is not in the same ui group as the event\n const event = _event as XenditClearCurrentChannelEvent;\n const currentChannelCode = this[internal].currentChannelCode;\n if (!currentChannelCode) return;\n const channel = this[internal].worldState.channels.find(\n (ch) => ch.channel_code === currentChannelCode,\n );\n if (!channel || channel.ui_group !== event.uiGroup) return;\n\n // clear active channel\n this.setCurrentChannel(null);\n },\n );\n }\n\n /**\n * @public\n * Creates a UI component for making payments with a specific channel. It will\n * contain form fields, and/or instructions for the user.\n *\n * This also makes the provided channel \"current\", the `submit` method\n * will use that channel.\n *\n * This returns a div. You should insert this div into the DOM. Creating a new\n * component multiple times for the same channel will return the same component instance.\n *\n * Destroying the component manually is not necessary, removing it from the DOM is sufficient,\n * but if you want to clear the form state, you can do so with the `destroyComponent` method.\n *\n * @example\n * ```\n * const cardsChannel = components.getActiveChannels({ filter: \"CARDS\" })[0];\n * const paymentComponent = components.createChannelComponent(cardsChannel);\n * document.querySelector(\".payment-container\").appendChild(paymentComponent);\n * ```\n */\n createChannelComponent(\n channel: XenditPaymentChannel,\n active = true,\n ): HTMLElement {\n this.assertInitialized();\n\n if (\n !satisfiesMinMax(this[internal].worldState.session, channel[internal][0])\n ) {\n throw new Error(\n `Cannot create channel component: \\`session.amount\\` is outside of the channel's min/max amount.`,\n );\n }\n\n const channelCode = channel[internal][0].channel_code;\n\n if (active) {\n // make it active (before creating the component)\n this[internal].currentChannelCode = channelCode;\n }\n\n // return previously created component if it exists\n const cachedComponent =\n this[internal].liveComponents.paymentChannels.get(channelCode);\n const channelFormRef = createRef<ChannelFormHandle>();\n let container: HTMLElement;\n\n if (cachedComponent) {\n container = cachedComponent.element;\n } else {\n container = document.createElement(\"xendit-payment-channel\");\n container.setAttribute(\"data-channel-code\", channelCode);\n container.setAttribute(\"inert\", \"\");\n container.setAttribute(\"translate\", \"no\");\n container.style.setProperty(\n \"--xendit-channel-brand-color\",\n channel[internal][0].brand_color,\n );\n\n this.setupUiEventsForPaymentChannel(container);\n\n this[internal].liveComponents.paymentChannels.set(channelCode, {\n element: container,\n channel,\n channelProperties: null,\n channelFormRef: channelFormRef,\n data: {\n savePaymentMethod: false,\n cardDetails: null,\n paymentOptions: null,\n },\n });\n }\n\n this.renderPaymentChannel(channelCode);\n if (active) {\n this.behaviorTreeUpdate();\n this.syncInertAttribute();\n }\n\n // rerender other components next tick because we may already be in a render\n this.dispatchEvent(new InternalNeedsRerenderEvent());\n\n return container;\n }\n\n /**\n * @internal\n * Render an existing payment channel element\n */\n private renderPaymentChannel(channelCode: string): void {\n this.assertInitialized();\n\n const component =\n this[internal].liveComponents.paymentChannels.get(channelCode);\n if (!component) return;\n\n const channelObject = component.channel;\n\n render(\n createElement(XenditSessionProvider, {\n data: this[internal].worldState,\n sdk: this,\n children: createElement(ChannelRoot, {\n channelOrPair: channelObject[internal],\n channelData: component.data,\n savePaymentMethod: component.data.savePaymentMethod,\n formRef: component.channelFormRef,\n }),\n }),\n component.element,\n );\n }\n\n /**\n * @internal\n * TODO: make this public\n * Returns a list of digital wallets available for this session.\n *\n * For `GOOGLE_PAY`:\n *\n * A channel supported by Google Pay must be active for the session, and Google Pay must be available\n * in the session's country, and you must have configured your merchant ID on the Xendit dashboard.\n *\n * (Note that our hosted checkout doesn't have the requirement to provide a merchant ID)\n */\n public getActiveDigitalWallets(): XenditDigitalWallet[] {\n this.assertInitialized();\n if (!this[internal].worldState.digitalWallets) {\n return [];\n }\n return bffDigitalWalletsToPublic(\n this[internal].worldState.digitalWallets,\n this[internal].worldState.channels,\n this[internal].worldState.channelUiGroups,\n {\n options: {\n filterMinMax: false,\n },\n pairChannels: findChannelPairs(this[internal].worldState.channels),\n session: this[internal].worldState.session,\n },\n );\n }\n\n /**\n * @internal\n * TODO: make this public\n * Creates a UI component for making payments with a digital wallet. It will contain a button to trigger the digital\n * wallet payment. If the digital wallet is not supported by the browser, it will have `display:none`.\n *\n * After the user pays using the digital wallet UI, a submission will automatically begin. Equivalent to setting\n * the channel used (using `setCurrentChannel()`), and then calling `submit()`. The same events will be fired\n * as a normal submission, see {@link submit}.\n *\n * This returns a HTML Element, which you should insert into the DOM.\n */\n public createDigitalWalletComponent<T extends XenditDigitalWalletCode>(\n digitalWalletCode: T,\n digitalWalletOptions?: DigitalWalletOptions<T>,\n ): HTMLElement {\n this.assertInitialized();\n\n const prevComponent =\n this[internal].liveComponents.digitalWalletContainer.get(\n digitalWalletCode,\n );\n if (prevComponent) {\n this.destroyComponent(prevComponent.element);\n }\n\n const element = document.createElement(\"xendit-digital-wallet\");\n element.setAttribute(\"translate\", \"no\");\n element.style.setProperty(\"display\", \"none\"); // initially hide the component until we know whether the digital wallet is available\n this[internal].liveComponents.digitalWalletContainer.set(\n digitalWalletCode,\n {\n element,\n options: digitalWalletOptions,\n },\n );\n\n this.renderDigitalWalletComponent(digitalWalletCode);\n\n return element;\n }\n\n /**\n * @internal\n * Renders an existing digital wallet component.\n */\n renderDigitalWalletComponent(\n digitalWalletCode: XenditDigitalWalletCode,\n ): void {\n this.assertInitialized();\n const component =\n this[internal].liveComponents.digitalWalletContainer.get(\n digitalWalletCode,\n );\n if (!component) return;\n\n render(\n createElement(XenditSessionProvider, {\n data: this[internal].worldState,\n sdk: this,\n children: createElement(DigitalWalletContainer, {\n digitalWalletCode,\n digitalWalletOptions: component.options,\n }),\n }),\n component.element,\n );\n }\n\n /**\n * @public\n * Returns the current payment channel.\n */\n getCurrentChannel() {\n const currentChannelCode = this[internal].currentChannelCode;\n if (!currentChannelCode) {\n return null;\n }\n return (\n this.getActiveChannels().find((ch) => {\n if (\n ch.channelCode === currentChannelCode ||\n (Array.isArray(ch.channelCode) &&\n ch.channelCode.includes(currentChannelCode))\n ) {\n return true;\n }\n }) ?? null\n );\n }\n\n /**\n * @public\n * Makes the given channel the current channel for submission.\n *\n * The current channel:\n * - Is interactive if it has a form (other channel components are non-interactive)\n * - Is used when `submit()` is called.\n *\n * Set to null to clear the current channel.\n */\n setCurrentChannel(channel: XenditPaymentChannel | null): void {\n const currentChannelCode = this[internal].currentChannelCode;\n\n const channelCode = channel?.[internal][0].channel_code ?? null;\n\n if (currentChannelCode === channelCode) {\n // no change\n return;\n }\n\n this[internal].currentChannelCode = channelCode;\n\n // if channel is not null, the component must exist\n if (channel && channelCode) {\n const component =\n this[internal].liveComponents.paymentChannels.get(channelCode) ?? null;\n if (!component) {\n this.createChannelComponent(channel, false);\n }\n }\n\n this.behaviorTreeUpdate();\n this.syncInertAttribute();\n this.renderChannelPicker();\n }\n\n /**\n * @internal\n * Ensure all components have the correct inert attribute. This needs to be called when the current channel changes or a submission starts or ends.\n */\n syncInertAttribute() {\n // all channel components should have `inert` unless they are the current channel and there is no submission in progress\n const hasSubmissionInProgress =\n this[internal].behaviorTree.bb.submissionRequested;\n const channelComponents = this[internal].liveComponents.paymentChannels;\n\n for (const [_, component] of channelComponents) {\n const channelCode = Array.isArray(component.channel.channelCode)\n ? component.channel.channelCode[0]\n : component.channel.channelCode;\n if (\n channelCode === this[internal].currentChannelCode &&\n !hasSubmissionInProgress\n ) {\n if (component.element.hasAttribute(\"inert\")) {\n component.element.removeAttribute(\"inert\");\n }\n } else {\n component.element.setAttribute(\"inert\", \"\");\n }\n }\n }\n\n /**\n * @internal\n * Handles events from the payment channel component.\n * - Updates channel properties when they change.\n * - Updates save payment method setting when it changes.\n */\n private setupUiEventsForPaymentChannel(container: HTMLElement): void {\n // update per-channel channel properties\n container.addEventListener(\n XenditChannelPropertiesChangedEvent.type,\n (_event) => {\n const event = _event as XenditChannelPropertiesChangedEvent;\n const channelCode = event.channel;\n const component =\n this[internal].liveComponents.paymentChannels.get(channelCode);\n if (!component) {\n return;\n }\n\n component.channelProperties = event.channelProperties;\n\n // update behavior tree (form validity may have changed)\n this.behaviorTreeUpdate();\n },\n );\n }\n\n /**\n * @public\n *\n * Reveals any hidden validation errors in the current channel's form. Does nothing if\n * there are no validation errors to show.\n *\n * Normally, validation errors on required fields are not shown if the user did not touch them.\n */\n showValidationErrors(): void {\n const channelInvalidBehavior = this[internal].behaviorTree.findBehavior(\n ChannelInvalidBehavior,\n );\n if (!channelInvalidBehavior) {\n // form is not invalid\n return;\n }\n\n const channelCode = this[internal].currentChannelCode;\n if (!channelCode) {\n // no current channel\n return;\n }\n\n const component =\n this[internal].liveComponents.paymentChannels.get(channelCode);\n if (!component) {\n throw new Error(\n \"Current channel is set but component is missing; this is a bug, please contact support.\",\n );\n }\n\n const form = component.channelFormRef.current;\n form?.setAllFieldsTouched();\n }\n\n /**\n * @public\n * Creates a container element for rendering action UIs.\n *\n * For example, 3DS or QR codes.\n *\n * Create an action container before or during the action-begin event, and\n * the action UI will be rendered inside it.\n * Creating an action container during an action will throw an error.\n *\n * If no action container is created (or if the created container is removed from the DOM or is too small),\n * the SDK will create an action container (in a modal dialog) for you.\n */\n createActionContainerComponent(): HTMLElement;\n\n /**\n * @public\n * Creates a container element for rendering action UIs with options.\n *\n * @param options - Configuration options for the action container\n */\n createActionContainerComponent(options: ActionContainerOptions): HTMLElement;\n\n /**\n * @internal If isInternal is passed, it bypasses the action-in-progress check.\n **/\n createActionContainerComponent(isInternal: typeof internal): HTMLElement;\n\n // implementation\n createActionContainerComponent(\n optionsOrInternal?: ActionContainerOptions | typeof internal,\n ): HTMLElement {\n this.assertInitialized();\n\n // Type guard to check if parameter is the internal symbol\n const isInternal = optionsOrInternal === internal;\n const options = isInternal\n ? undefined\n : (optionsOrInternal as ActionContainerOptions | undefined);\n\n const requiresActionBehavior = this[internal].behaviorTree.findBehavior(\n PaymentEntityRequiresActionBehavior,\n );\n if (\n !isInternal &&\n requiresActionBehavior &&\n !requiresActionBehavior.canCreateActionContainer\n ) {\n throw new Error(\n \"Unable to create action container; there is an action in progress. Create an action before or during the `action-begin` event.\",\n );\n }\n\n if (this[internal].liveComponents.actionContainer) {\n this.destroyComponent(this[internal].liveComponents.actionContainer);\n }\n\n const container = document.createElement(\"xendit-action-container\");\n container.setAttribute(\"translate\", \"no\");\n\n // Apply QR code options as data attributes if provided\n if (options?.qrCode) {\n if (options.qrCode.qrCodeOnly !== undefined) {\n container.setAttribute(\n \"data-qr-code-only\",\n options.qrCode.qrCodeOnly.toString(),\n );\n }\n }\n\n this[internal].liveComponents.actionContainer = container;\n\n return container;\n }\n\n /**\n * @public\n * Destroys a component of any type created by the SDK. Removes it from the DOM if necessary.\n * Throws if the element is not a xendit component or if it was already destroyed.\n */\n destroyComponent(component: HTMLElement): void {\n if (!component.tagName.startsWith(\"XENDIT-\")) {\n throw new Error(\n \"Unable to destroy component; only elements created by this SDK can be destroyed.\",\n );\n }\n\n if (this[internal].liveComponents.channelPicker === component) {\n this[internal].liveComponents.channelPicker = null;\n render(null, component);\n component.remove();\n return;\n }\n\n for (const [channelCode, c] of this[internal].liveComponents\n .paymentChannels) {\n if (c.element === component) {\n this[internal].liveComponents.paymentChannels.delete(channelCode);\n if (this[internal].currentChannelCode === channelCode) {\n this.setCurrentChannel(null);\n }\n render(null, component);\n component.remove();\n return;\n }\n }\n\n if (this[internal].liveComponents.actionContainer === component) {\n this[internal].liveComponents.actionContainer = null;\n render(null, component);\n component.remove();\n return;\n }\n\n for (const [channelCode, c] of this[internal].liveComponents\n .digitalWalletContainer) {\n if (c.element === component) {\n this[internal].liveComponents.digitalWalletContainer.delete(\n channelCode,\n );\n render(null, component);\n component.remove();\n return;\n }\n }\n\n throw new Error(\n \"Unable to destroy component; component not found. It may have already been destroyed.\",\n );\n }\n\n /**\n * @public\n * Submit, makes a payment or saves a payment method for the current payment channel.\n *\n * Call this when your submit button is clicked. Listen to the events to know the status:\n * - `submission-begin` and `submission-end` to know when submission is in progress (you should disable your UI during this time). Submission-end also provides a reason.\n * - `action-begin` and `action-end` to know when user action is in progress\n * - `will-redirect` when the user will be redirected to another page\n * - `payment-[request|token]-[created|discarded]` informs you of the ID of the resource we create on the backend, and if/when it is discarded\n * - `session-complete` when the payment request or token is successfully created (you should redirect the user to your confirmation page)\n * - `session-expired-or-canceled` can happen at any time, but it's likely to happen on submission if the session expired or was cancelled during checkout\n * - `submission-not-ready` fires before `submission-begin` to indicate that you cannot submit while a submission is in progress\n *\n * When a submission fails, you can try again by calling `submit()` again.\n * (The `session-expired-or-canceled` and `fatal-error` events are fatal, submission failure is normal and recoverable)\n *\n * This corresponds to the endpoints:\n * - `POST /v3/payment_requests` for PAY sessions\n * - `POST /v3/payment_tokens` for SAVE sessions\n */\n submit() {\n this.assertInitialized();\n\n const sessionActiveBehavior = this[internal].behaviorTree.findBehavior(\n SessionActiveBehavior,\n );\n if (!sessionActiveBehavior) {\n throw new Error(\n \"Unable to submit; the session is not in the active state. Listen to the `session-complete` and `session-expired-or-canceled` events and display success or failure states accordingly.\",\n );\n }\n\n const channelCode = this[internal].currentChannelCode;\n if (!channelCode) {\n throw new Error(\n \"Unable to submit; there is no current payment channel. Create a payment component with `createChannelComponent` or make an existing one active with `setCurrentChannel`.\",\n );\n }\n\n const component =\n this[internal].liveComponents.paymentChannels.get(channelCode);\n if (!component) {\n throw new Error(\n \"Current channel is set but component is missing; this is a bug, please contact support.\",\n );\n }\n\n // ensure if user submits in invalid state, errors are visible\n this.showValidationErrors();\n\n const channelInvalidBehavior = this[internal].behaviorTree.findBehavior(\n ChannelInvalidBehavior,\n );\n if (channelInvalidBehavior) {\n throw new Error(\n \"Unable to submit; the form for the current channel has errors. Listen to the `submission-ready` and `submission-not-ready` events, do not allow submission while in the not-ready state.\",\n );\n }\n\n const channelValidBehavior =\n this[internal].behaviorTree.findBehavior(ChannelValidBehavior);\n if (!channelValidBehavior) {\n throw new Error(\n \"Unable to submit; the SDK is not in a valid state for submission. Listen to the `submission-ready` and `submission-not-ready` events, do not allow submission while in the not-ready state.\",\n );\n }\n\n this[internal].behaviorTree.bb.submissionRequested = true;\n this.behaviorTreeUpdate();\n\n this.syncInertAttribute();\n }\n\n /**\n * @internal\n * Submits a digital wallet payment.\n */\n submitDigitalWallet(\n digitalWalletCode: XenditDigitalWalletCode,\n channel: XenditPaymentChannel,\n channelProperties: ChannelProperties,\n instantSubmissionError: SubmissionError | null = null,\n ) {\n this.assertInitialized();\n\n this.setCurrentChannel(null);\n\n this[internal].currentDigitalWalletSubmission = {\n digitalWalletCode,\n channelCode: channel[internal][0].channel_code,\n channelProperties,\n instantSubmissionError,\n };\n\n this.addEventListener(\n XenditSubmissionEndEvent.type,\n () => {\n this[internal].currentDigitalWalletSubmission = null;\n },\n { once: true },\n );\n\n this[internal].behaviorTree.bb.submissionRequested = true;\n this.behaviorTreeUpdate();\n\n this.syncInertAttribute();\n }\n\n /**\n * @public\n * Cancels a submission.\n *\n * If a submission is in-flight, the request is cancelled. If an action is in progress,\n * the action is aborted. Any active PaymentRequest or PaymentToken is abandoned.\n *\n * Does nothing if there is no active submission.\n */\n abortSubmission() {\n this.assertInitialized();\n\n const submissionBehavior =\n this[internal].behaviorTree.findBehavior(SubmissionBehavior);\n if (!submissionBehavior) {\n return; // no submission in progress\n }\n\n this[internal].behaviorTree.bb.submissionRequested = false;\n this.behaviorTreeUpdate();\n }\n\n /**\n * @public\n * Completes a payment in test mode.\n *\n * The session must be in test mode, and the session type must be PAY, and\n * the sdk must have an in-progress action, and the channel must be a QR, VA, or OTC channel.\n *\n * @example\n * ```\n * components.addEventListener(\"action-begin\", () => {\n * components.simulatePayment();\n * });\n * ```\n */\n simulatePayment() {\n this.assertInitialized();\n\n if (this[internal].worldState.session.session_type !== \"PAY\") {\n throw new Error(\n 'Unable to simulate payment, the session type is not \"PAY\".',\n );\n }\n\n const requiresActionBehavior = this[internal].behaviorTree.findBehavior(\n PaymentEntityRequiresActionBehavior,\n );\n if (!requiresActionBehavior) {\n throw new Error(\n \"Unable to simulate payment; there is no action in progress. You can simulate payments any time between the `action-begin` and `action-end` events.\",\n );\n }\n\n const paymentEntity = this[internal].worldState.paymentEntity;\n if (!paymentEntity) {\n throw new Error(\n \"The PeRequiresActionBehavior is present but there is no payment entity. This is a bug, please contact support.\",\n );\n }\n\n const channel = this.findChannel(paymentEntity.entity.channel_code);\n\n if (!channel) {\n throw new Error(\n \"Channel not found; this is a bug, please contact support.\",\n );\n }\n\n const action = findBestAction(paymentEntity.entity.actions);\n if (!action || !canBeSimulated(action)) {\n throw new Error(\n \"Unable to simulate payment; the action does not support simulation.\",\n );\n }\n\n this[internal].behaviorTree.bb.simulatePaymentRequested = true;\n this.behaviorTreeUpdate();\n }\n\n /**\n * @public\n * Request an immediate poll for session status. Useful for handling payment\n * affirmation (e.g. I have made the payment) by the user. The session must still\n * be active.\n *\n * @example\n * ```\n * function onUserAffirmPayment() {\n * components.pollImmediately();\n * }\n * ```\n */\n pollImmediately() {\n this.assertInitialized();\n\n if (this[internal].worldState.session.status !== \"ACTIVE\") {\n throw new Error(\n \"Unable to poll immediately; the session is not longer active.\",\n );\n }\n\n this[internal].behaviorTree.bb.pollImmediatelyRequested = true;\n this.behaviorTreeUpdate();\n }\n\n /**\n * @internal\n * TODO: remove this, it's for debugging\n */\n getState() {\n const channelCode = this[internal].currentChannelCode;\n const component = this[internal].liveComponents.paymentChannels.get(\n channelCode ?? \"\",\n );\n return {\n channelCode,\n channelProperties: component?.channelProperties || null,\n behaviorTree: this[internal].behaviorTree,\n };\n }\n\n /**\n * @public\n * The `init` event lets you know when the session data has been loaded.\n *\n * The `createChannelPickerComponent` method can be called before this event, but\n * most other functionaility needs to wait for this event.\n *\n * @example\n * ```\n * components.addEventListener(\"init\", () => {\n * components.getSession();\n * });\n * ```\n */\n addEventListener(\n name: \"init\",\n listener: XenditEventListener<XenditInitEvent>,\n options?: boolean | AddEventListenerOptions,\n ): void;\n\n /**\n * @public\n * The `submission-ready` and `submission-not-ready` events let you know when submission should be available.\n * If ready, you can call `submit()` to begin the payment or token creation process.\n *\n * \"submission-ready\" means a channel has been selected, and all required fields are populated,\n * and all fields are valid.\n *\n * Use this to enable/disable your submit button.\n *\n * @example\n * ```\n * components.addEventListener(\"submission-ready\", () => {\n * submitButton.disabled = false;\n * });\n * components.addEventListener(\"submission-not-ready\", () => {\n * submitButton.disabled = true;\n * });\n * ```\n */\n addEventListener(\n name: \"submission-ready\",\n listener: XenditEventListener<XenditReadyEvent>,\n options?: boolean | AddEventListenerOptions,\n ): void;\n addEventListener(\n name: \"submission-not-ready\",\n listener: XenditEventListener<XenditReadyEvent>,\n options?: boolean | AddEventListenerOptions,\n ): void;\n\n /**\n * @public\n * The `submission-begin` and `submission-end` events let you know when a submission is in progress.\n *\n * Use this to disable your UI while submission is in progress.\n *\n * In the case of successful submission, `submission-end` will be followed by `session-complete`.\n * In the case of failed submission, the SDK will return to the ready state and you can try submitting again.\n */\n addEventListener(\n name: \"submission-begin\",\n listener: XenditEventListener<XenditSubmissionBeginEvent>,\n options?: boolean | AddEventListenerOptions,\n ): void;\n addEventListener(\n name: \"submission-end\",\n listener: XenditEventListener<XenditSubmissionEndEvent>,\n options?: boolean | AddEventListenerOptions,\n ): void;\n\n /**\n * @public\n * The events `payment-request-created`, `payment-token-created`, `payment-request-discarded`, and `payment-token-discarded`\n * let you know when a payment request or payment token has been created (as part of a submission) or\n * discarded (by cancelling or failing a submission).\n */\n addEventListener(\n name: \"payment-request-created\",\n listener: XenditEventListener<XenditPaymentRequestCreatedEvent>,\n options?: boolean | AddEventListenerOptions,\n ): void;\n addEventListener(\n name: \"payment-token-created\",\n listener: XenditEventListener<XenditPaymentTokenCreatedEvent>,\n options?: boolean | AddEventListenerOptions,\n ): void;\n addEventListener(\n name: \"payment-request-discarded\",\n listener: XenditEventListener<XenditPaymentRequestDiscardedEvent>,\n options?: boolean | AddEventListenerOptions,\n ): void;\n addEventListener(\n name: \"payment-token-discarded\",\n listener: XenditEventListener<XenditPaymentTokenDiscardedEvent>,\n options?: boolean | AddEventListenerOptions,\n ): void;\n\n /**\n * @public\n * The `action-begin` and `action-end` events let you know when a user action is in progress.\n *\n * After submission, an action may be required (e.g. 3DS, redirect, QR code, etc.).\n * The SDK will control the UI for actions, you don't need to do anything.\n *\n * Avoid changing any application state while an action is in progress as it may be\n * confusing for the user or interrupt their payment attempt.\n *\n * `action-end` is fired after the action is done, successfully or not. Note that users can\n * voluntarily dismiss actions.\n */\n addEventListener(\n name: \"action-begin\",\n listener: XenditEventListener<XenditActionBeginEvent>,\n options?: boolean | AddEventListenerOptions,\n ): void;\n addEventListener(\n name: \"action-end\",\n listener: XenditEventListener<XenditActionEndEvent>,\n options?: boolean | AddEventListenerOptions,\n ): void;\n\n /**\n * @public\n * Event handler called just before the user is redirected to a third party site to\n * complete the payment.\n *\n * Since redirects are actions, this will always be preceded by an `action-begin` event.\n */\n addEventListener(\n name: \"will-redirect\",\n listener: XenditEventListener<XenditWillRedirectEvent>,\n options?: boolean | AddEventListenerOptions,\n ): void;\n\n /**\n * @public\n * Event handler called on success.\n * The payment has been made and/or the token has been created.\n */\n addEventListener(\n name: \"session-complete\",\n listener: XenditEventListener<XenditSessionCompleteEvent>,\n options?: boolean | AddEventListenerOptions,\n ): void;\n\n /**\n * @public\n * Event handler called when the session has expired or been cancelled.\n */\n addEventListener(\n name: \"session-expired-or-canceled\",\n listener: XenditEventListener<XenditSessionExpiredOrCanceledEvent>,\n options?: boolean | AddEventListenerOptions,\n ): void;\n\n /**\n * @public\n * Event handler called on pending state. You should show a pending UI in response to this event.\n *\n * The pending state means an associated payment request or token will take some time to complete.\n * No other payment attempts can be made while in the pending state.\n *\n * This occurs for payments requiring manual confirmation, e.g. FPX business payments.\n *\n * The pending state usually occurs after a submission-end event.\n * This event will also be fired if the SDK is initialized and the session is already pending.\n */\n addEventListener(\n name: \"session-pending\",\n listener: XenditEventListener<XenditSessionPendingEvent>,\n options?: boolean | AddEventListenerOptions,\n ): void;\n\n /**\n * @public\n * Event handler called when exiting the pending state.\n *\n * After the pending state, the session may be in the active state, allowing further attempts, or\n * it may be completed or expired/canceled, in which case the respective event will be fired immediently after this one.\n */\n addEventListener(\n name: \"session-not-pending\",\n listener: XenditEventListener<XenditSessionNotPendingEvent>,\n options?: boolean | AddEventListenerOptions,\n ): void;\n\n /**\n * @public\n * Event handler called when something unrecoverable has happened. You should create a new\n * session and a new SDK instance.\n */\n addEventListener(\n name: \"fatal-error\",\n listener: XenditEventListener<XenditFatalErrorEvent>,\n options?: boolean | AddEventListenerOptions,\n ): void;\n\n /**\n * @public\n * Fallback overload.\n */\n addEventListener<K extends keyof XenditEventMap>(\n type: K,\n listener: (this: XenditComponents, ev: XenditEventMap[K]) => void,\n options?: boolean | AddEventListenerOptions,\n ): void;\n\n /**\n * @internal\n * Implementation.\n */\n addEventListener(\n type: string,\n listener: unknown,\n options?: boolean | AddEventListenerOptions,\n ): void {\n this[internal].eventListenersPresent.set(type, true);\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return super.addEventListener(type, listener as any, options);\n }\n\n /**\n * @public\n * Fallback overload.\n */\n removeEventListener<K extends keyof XenditEventMap>(\n type: K,\n listener: (this: XenditComponents, ev: XenditEventMap[K]) => void,\n options?: boolean | AddEventListenerOptions,\n ): void;\n\n /**\n * @internal\n * Implementation.\n */\n removeEventListener(\n type: string,\n listener: unknown,\n options?: boolean | AddEventListenerOptions,\n ): void {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return super.removeEventListener(type, listener as any, options);\n }\n\n /**\n * @public\n * Formats a currency value according to the currency's conventions.\n *\n * e.g.\n * ```\n * USD 1000 -> \"$1,000\"\n * USD 1000.5 -> \"$1,000.50\"\n * IDR 1000000 -> \"Rp1.000.000\"\n * PHP 1000 -> \"₱1,000.00\"\n * ```\n */\n static amountFormat(amount: number, currency: string): string {\n return amountFormat(amount, currency);\n }\n}\n\n/**\n * @public\n * Test version of XenditComponents that uses mock data instead of API calls.\n * Use this class for testing and development purposes.\n *\n * The componentsSdkKey option is ignored.\n *\n * @example\n * ```\n * const testSdk = new XenditComponentsTest({});\n * ```\n */\nexport class XenditComponentsTest extends XenditComponents {\n /**\n * @internal\n * The mock to apply on the next poll.\n */\n public nextMockUpdate: BffPollResponse | null = null;\n\n /**\n * @public\n * Test SDK ignores componentsSdkKey and uses a mock key.\n */\n constructor(\n options: Omit<XenditComponentsOptions, \"componentsSdkKey\"> & {\n componentsSdkKey?: string;\n },\n ) {\n super({\n ...options,\n componentsSdkKey: makeTestSdkKey(),\n });\n\n // internal event listeners\n (this as EventTarget).addEventListener(\n InternalScheduleMockUpdateEvent.type,\n this.setNextMockUpdate.bind(this),\n );\n }\n\n /**\n * @internal\n * Override to use test data instead of making API calls\n */\n protected async initializeAsync(): Promise<void> {\n // Simulate network delay and prevent firing the init event before the constructor returns\n await sleep(MOCK_NETWORK_DELAY_MS);\n\n // Always use test data for this class\n const bff = (await import(\"./data/test-data\")).makeTestBffData();\n\n // Update internal data\n this.dispatchEvent(\n new InternalUpdateWorldState({\n business: bff.business,\n customer: bff.customer,\n session: bff.session,\n channels: bff.channels,\n channelUiGroups: bff.channel_ui_groups,\n digitalWallets: bff.digital_wallets ?? null,\n paymentEntity: null,\n sessionTokenRequestId: null,\n succeededChannel: null,\n } satisfies WorldState),\n );\n }\n\n /**\n * @internal\n * Indicates that this is a mock SDK.\n */\n public isMock(): boolean {\n return true;\n }\n\n /**\n * @internal\n * Sets the next mock update to use.\n */\n setNextMockUpdate(_event: Event): void {\n const event = _event as InternalScheduleMockUpdateEvent;\n this.nextMockUpdate = event.mockData;\n }\n}\n\n// re-exports\nexport type { ChannelProperties, ChannelPropertyPrimative };\n","// Must be the first import\nimport \"preact/debug\";\nimport \"preact/devtools\";\n\nimport { createStyles } from \"./styles\";\nimport { setupPreactBatch } from \"./preact-batch\";\n\nif (typeof window === \"undefined\" || typeof document === \"undefined\") {\n // do not run browser initialization in node env\n} else {\n setupPreactBatch();\n createStyles();\n}\n\nexport * from \"./public-sdk\";\nexport * from \"./public-event-types\";\nexport * from \"./public-options-types\";\nexport * from \"./public-data-types\";\n","import { findFirstStyleOrLinkElement } from \"./dom-utils\";\nimport css from \"./styles.css\";\n\nexport function createStyles() {\n const styleElement = document.createElement(\"style\");\n styleElement.textContent = css;\n const firstStyleOrLinkElement = findFirstStyleOrLinkElement();\n if (firstStyleOrLinkElement) {\n firstStyleOrLinkElement.insertAdjacentElement(\"beforebegin\", styleElement);\n } else {\n document.head.appendChild(styleElement);\n }\n}\n","/* variables */\n:root {\n --xendit-font-family: sans-serif;\n --xendit-color-primary: #1762ee;\n --xendit-color-text: #252525;\n --xendit-color-text-secondary: #585858;\n --xendit-color-text-placeholder: #7d7d7d;\n --xendit-color-disabled: #f7f7f7;\n --xendit-color-danger: #d1414d;\n --xendit-color-border: #f3f3f3;\n --xendit-color-background: #ffffff;\n --xendit-focus-shadow: 0px 0px 0px 2px\n color-mix(in srgb, var(--xendit-color-primary) 15%, transparent);\n --xendit-card-shadow: 0px 4px 8px 0px #25252514;\n --xendit-dialog-shadow: 8px 8px 12px 8px #25252529;\n --xendit-animation-duration: 0.3s;\n --xendit-animation-ease: ease-in-out;\n --xendit-radius-1: 8px;\n --xendit-z-index-focus: 2;\n --xendit-z-index-overlay: 3;\n\n /* Browser-specific border collapse margins */\n --xendit-border-collapse-offset: -0.5px; /* Default for Chrome/Edge */\n --xendit-border-collapse-webkit-gecko: -1.5px; /* Fix Safari and Firefox subpixel rendering */\n\n /* QR code colors */\n --xendit-qr-foreground-color: #000000;\n --xendit-qr-background-color: #ffffff;\n\n /* icon colors */\n --xendit-color-icon-primary: #7c7c7c;\n --xendit-color-icon-secondary: #f1f1f1;\n}\n\n/* Set default font for root components */\nxendit-channel-picker,\nxendit-action-container,\nxendit-payment-channel {\n display: block;\n unicode-bidi: isolate;\n font-family: var(--xendit-font-family);\n color: var(--xendit-color-text);\n touch-action: manipulation;\n}\n\n.xendit-default-action-container {\n font-family: var(--xendit-font-family);\n touch-action: manipulation;\n}\n\nxendit-action-container {\n position: relative;\n flex: 1; /* Action container usually wants to stretch to fit, assuming the parent is a flexbox. */\n touch-action: manipulation;\n}\n\nxendit-payment-channel button,\nxendit-payment-channel textarea,\nxendit-payment-channel select,\nxendit-payment-channel input,\nxendit-payment-channel input::placeholder {\n font-family: inherit;\n}\n\nxendit-payment-channel input::placeholder,\nxendit-payment-channel textarea::placeholder,\nxendit-payment-channel select::placeholder {\n color: var(--xendit-color-text-placeholder);\n}\n\n/* Reusable typography classes */\n.xendit-text-12 {\n font-size: 12px;\n line-height: 16px;\n letter-spacing: -0.01px;\n}\n\n.xendit-text-14 {\n font-size: 14px;\n line-height: 16px;\n letter-spacing: -0.09px;\n}\n\n.xendit-text-16 {\n font-size: 16px;\n line-height: 16px;\n letter-spacing: -0.09px;\n}\n\n.xendit-text-18 {\n font-size: 18px;\n line-height: 24px;\n letter-spacing: -0.26px;\n}\n\n.xendit-text-20 {\n font-size: 20px;\n line-height: 28px;\n letter-spacing: -0.33px;\n}\n\n.xendit-text-12,\n.xendit-text-14,\n.xendit-text-16 {\n font-weight: 400;\n}\n\n.xendit-text-semibold {\n font-weight: 600;\n}\n\n.xendit-text-bold {\n font-weight: 700;\n}\n\n.xendit-text-link {\n color: var(--xendit-color-primary);\n}\n.xendit-text-secondary {\n color: var(--xendit-color-text-secondary);\n}\n\n.xendit-text-center {\n text-align: center;\n}\n\n.xendit-dotted-line {\n height: 1px;\n border: none;\n background: repeating-linear-gradient(\n to right,\n var(--xendit-color-border) 0px 4px,\n transparent 4px 8px\n );\n margin: 0;\n}\n\n/* Accordion component */\n\n.xendit-accordion {\n display: flex;\n flex-direction: column;\n border: 1px solid var(--xendit-color-border);\n border-radius: var(--xendit-radius-1);\n background: var(--xendit-color-background);\n}\n\n.xendit-accordion-item:not(:first-child) {\n border-top: 1px solid var(--xendit-color-border);\n border-top-left-radius: var(--xendit-radius-1);\n border-top-right-radius: var(--xendit-radius-1);\n}\n\n.xendit-accordion-item-header {\n display: grid;\n grid-template-columns: auto 1fr auto;\n grid-gap: 16px;\n align-items: center;\n cursor: pointer;\n padding: 24px 16px;\n color: var(--xendit-color-text);\n border-radius: 8px;\n}\n\n.xendit-accordion-item-disabled .xendit-accordion-item-header {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.xendit-accordion-item-header-title {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.xendit-accordion-item-disabled .xendit-accordion-item-header-title,\n.xendit-accordion-item-disabled .xendit-accordion-item-header-icon {\n opacity: 0.5;\n}\n\n.xendit-accordion-item.xendit-accordion-item-open\n .xendit-accordion-item-header {\n color: var(--xendit-color-primary);\n}\n\n.xendit-accordion-item-chevron {\n color: var(--xendit-color-text);\n}\n\n.xendit-accordion-item-disabled .xendit-accordion-item-chevron {\n display: none;\n}\n\n.xendit-accordion-item-chevron g {\n transition: transform var(--xendit-animation-duration)\n var(--xendit-animation-ease);\n}\n\n.xendit-accordion-item-header:focus-visible {\n border-radius: 8px;\n box-shadow: var(--xendit-focus-shadow);\n outline: none;\n}\n\n.xendit-accordion-item-content {\n overflow: hidden;\n transition: height var(--xendit-animation-duration)\n var(--xendit-animation-ease);\n}\n\n.xendit-accordion-item.xendit-accordion-item-closed\n .xendit-accordion-item-content {\n height: 0;\n}\n\n.xendit-accordion-item.xendit-accordion-item-open\n .xendit-accordion-item-content {\n height: calc-size(auto, size);\n}\n\n.xendit-accordion-item-padding {\n padding: 16px;\n}\n\n/* Channel picker digital wallet section */\n\n.xendit-channel-picker-digital-wallet-section {\n display: grid;\n grid-auto-flow: column;\n grid-auto-columns: 1fr;\n gap: 8px;\n margin-bottom: 8px;\n}\n\n/* Channel picker group */\n\n.xendit-channel-picker-group {\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n\n.xendit-channel-picker-group select {\n border: 1px solid var(--xendit-color-border);\n border-radius: 8px;\n padding: 12px;\n appearance: none;\n outline: none;\n}\n\n.xendit-channel-picker-group select:focus {\n box-shadow: var(--xendit-focus-shadow);\n}\n\n.xendit-channel-logo {\n width: 24px;\n height: 16px;\n margin: -5px 0;\n padding: 4px;\n border: 1px solid var(--xendit-color-border);\n border-radius: 4px;\n background-color: white; /* always white, not --xendit-color-background */\n object-fit: contain;\n}\n\n/* Payment channel */\n\nxendit-payment-channel[inert] {\n filter: opacity(0.5) grayscale(1);\n}\n\n.xendit-payment-channel {\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n\n.xendit-payment-channel-banner {\n width: 100%;\n height: auto;\n object-fit: contain;\n}\n\n.xendit-payment-channel-instructions {\n display: grid;\n grid-template-columns: auto 1fr;\n grid-gap: 12px;\n color: var(--xendit-color-text-secondary);\n}\n\n.xendit-payment-channel-instructions-logo {\n height: 40px;\n width: auto;\n object-fit: contain;\n}\n\n.xendit-payment-channel-instructions-text {\n display: flex;\n flex-direction: column;\n justify-content: center;\n gap: 4px;\n}\n\n.xendit-payment-channel-instructions-text p {\n margin: 0;\n}\n\n/* Forms */\n\n.xendit-channel-form {\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n\n.xendit-channel-form > form {\n display: contents;\n}\n\n.xendit-form-field-group {\n display: grid;\n grid-template-columns: repeat(2, minmax(0, 1fr));\n}\n\n.xendit-channel-form-field {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.xendit-channel-form-field-group {\n display: grid;\n gap: 8px;\n}\n\n.xendit-channel-form-field-group-label-container {\n display: flex;\n justify-content: space-between;\n gap: 16px;\n}\n\n.xendit-channel-form-field-group label {\n width: fit-content;\n cursor: pointer;\n}\n\n.xendit-form-field-group.invalid\n .xendit-channel-form-field\n .xendit-form-field-inner {\n border: 1px solid var(--xendit-color-danger);\n}\n\n.xendit-channel-form-field .xendit-form-field-inner {\n border: 1px solid var(--xendit-color-border);\n background: var(--xendit-color-background);\n border-radius: 8px;\n appearance: none;\n}\n\n.xendit-channel-form-field.field-radius-tl-0 .xendit-form-field-inner {\n border-top-left-radius: 0;\n}\n\n.xendit-channel-form-field.field-radius-tr-0 .xendit-form-field-inner {\n border-top-right-radius: 0;\n}\n\n.xendit-channel-form-field.field-radius-bl-0 .xendit-form-field-inner {\n border-bottom-left-radius: 0;\n}\n\n.xendit-channel-form-field.field-radius-br-0 .xendit-form-field-inner {\n border-bottom-right-radius: 0;\n}\n\n.xendit-channel-form-field.field-collapse-l,\n.xendit-channel-form-field.field-collapse-l {\n margin-left: var(--xendit-border-collapse-offset);\n}\n\n.xendit-channel-form-field.field-collapse-r,\n.xendit-channel-form-field.field-collapse-r {\n margin-right: var(--xendit-border-collapse-offset);\n}\n\n.xendit-channel-form-field.field-collapse-l .xendit-iframe-container {\n margin-left: calc(var(--xendit-border-collapse-offset) * 2);\n width: calc(100% + abs(var(--xendit-border-collapse-offset) * 2));\n}\n\n.xendit-channel-form-field.field-collapse-r .xendit-iframe-container {\n margin-right: 0;\n}\n\n.xendit-channel-form-field.field-collapse-t .xendit-form-field-inner {\n margin-top: var(--xendit-border-collapse-offset);\n}\n\n.xendit-channel-form-field.field-collapse-b .xendit-form-field-inner {\n margin-bottom: var(--xendit-border-collapse-offset);\n}\n\n/* Safari and Firefox specific adjustments */\n@supports (font: -apple-system-body) or (-moz-appearance: none) {\n .xendit-channel-form-field.field-collapse-l .xendit-iframe-container {\n margin-left: 0;\n width: 100%;\n }\n\n .xendit-channel-form-field.field-collapse-b input,\n .xendit-channel-form-field.field-collapse-b button {\n margin-bottom: var(--xendit-border-collapse-webkit-gecko);\n height: calc(100% + abs(var(--xendit-border-collapse-webkit-gecko) * 2));\n }\n}\n\n.xendit-channel-form-field.field-collapse-r .xendit-iframe-container:focus {\n border-right: none;\n}\n\n.xendit-channel-form-field.field-collapse-l .xendit-iframe-container:focus {\n border-left: none;\n}\n\n.xendit-card-brand-logo {\n width: 24px;\n height: 16px;\n border: 1px solid var(--xendit-color-border);\n border-radius: 4px;\n padding: 4px;\n background-color: white; /* always white, not --xendit-color-background */\n}\n\n.xendit-card-brands-list {\n display: flex;\n align-items: center;\n padding: 8px 12px;\n gap: 4px;\n}\n\n.xendit-channel-form-field .xendit-form-field-inner:focus,\n.xendit-channel-form-field .xendit-form-field-inner.xendit-field-focus {\n border-color: var(--xendit-color-primary);\n box-shadow: var(--xendit-focus-shadow);\n outline: none;\n z-index: var(--xendit-z-index-focus);\n position: relative;\n}\n\n.xendit-channel-form-field button.xendit-dropdown-open {\n z-index: var(--xendit-z-index-focus);\n}\n\n.xendit-channel-form-field input.xendit-form-field-inner {\n padding: 12px;\n}\n\n.xendit-channel-form-field .xendit-iframe-container {\n height: 40px;\n width: 100%;\n padding: 0;\n overflow: hidden;\n box-sizing: border-box;\n}\n\n.xendit-channel-form-field .xendit-iframe-container iframe {\n height: 40px;\n width: 100%;\n border: none;\n min-width: 0;\n}\n\n.xendit-channel-form-field.xendit-form-field-span-1 {\n grid-column: span 1;\n}\n\n.xendit-channel-form-field.xendit-form-field-span-2 {\n grid-column: span 2;\n}\n\n.xendit-checkbox {\n display: flex;\n align-items: center;\n}\n\n.xendit-checkbox-box {\n display: flex;\n}\n\n.xendit-checkbox input {\n width: 16px;\n height: 16px;\n margin: 0;\n cursor: pointer;\n}\n\n.xendit-checkbox label {\n cursor: pointer;\n padding-left: 8px;\n}\n\n.xendit-checkbox input {\n opacity: 0;\n position: absolute;\n}\n\n.xendit-checkbox input + .xendit-checkbox-graphic {\n width: 16px;\n height: 16px;\n border: 1px solid var(--xendit-color-border);\n border-radius: 4px;\n box-sizing: border-box;\n color: transparent;\n}\n\n.xendit-checkbox input:checked + .xendit-checkbox-graphic {\n color: var(--xendit-color-background);\n background-color: var(--xendit-color-primary);\n border-color: var(--xendit-color-primary);\n}\n\n.xendit-checkbox input:focus + .xendit-checkbox-graphic {\n border: 1px solid var(--xendit-color-primary);\n box-shadow: var(--xendit-focus-shadow);\n}\n\n/* Dialog */\n\n.xendit-dialog-backdrop {\n position: fixed;\n top: 0;\n bottom: 0;\n left: 0;\n right: 0;\n background: rgba(0, 0, 0, 0.5);\n display: flex;\n padding: 48px;\n justify-content: center;\n align-items: center;\n}\n\n.xendit-dialog {\n position: relative;\n}\n\n.xendit-dialog-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n color: var(--xendit-color-text);\n padding: 16px;\n gap: 16px;\n line-height: 20px;\n border-bottom: 1px solid var(--xendit-color-border);\n}\n\n.xendit-dialog-header button {\n display: flex;\n background: none;\n border: none;\n color: var(--xendit-color-text);\n cursor: pointer;\n padding: 0;\n}\n\n.xendit-dialog-floating-close {\n position: absolute;\n top: 24px;\n right: 24px;\n display: flex;\n background: none;\n border: none;\n color: var(--xendit-color-text);\n cursor: pointer;\n padding: 0;\n}\n\n.xendit-dialog-body {\n display: flex;\n padding: 24px;\n background-color: var(--xendit-color-background);\n border-radius: 8px;\n box-shadow: var(--xendit-dialog-shadow);\n}\n\n.xendit-error-message {\n color: var(--xendit-color-danger);\n}\n\n/* Phone input Dropdown */\n.xendit-input-phone {\n display: flex;\n gap: 8px;\n}\n\n.xendit-phone-number-input {\n width: 100%;\n}\n\n/* Phone input Dropdown ends */\n\n/* Dropdown */\n.xendit-dropdown {\n width: 100%;\n display: grid;\n grid-template-columns: 1fr auto;\n align-items: center;\n text-align: left;\n background-color: var(--xendit-color-background);\n border: 1px solid var(--xendit-color-border);\n border-radius: var(--xendit-radius-1);\n justify-content: space-between;\n cursor: pointer;\n padding: 0;\n padding-left: 12px;\n outline: none;\n}\n\n.xendit-dropdown:focus {\n border-color: var(--xendit-color-primary);\n box-shadow: var(--xendit-focus-shadow);\n outline: none;\n z-index: var(--xendit-z-index-focus);\n position: relative;\n}\n\n.xendit-dropdown.xendit-dropdown-has-asset {\n grid-template-columns: auto 1fr auto;\n}\n\n.xendit-dropdown-channel-logo {\n height: 24px;\n width: 32px;\n object-fit: contain;\n padding: 2px 0px;\n padding-right: 12px;\n border-right: 1px solid var(--xendit-color-border);\n}\n\n.xendit-dropdown-text {\n padding: 12px;\n padding-right: 0;\n}\n\n.xendit-dropdown-chevron {\n height: 38px;\n width: 38px;\n padding: 12px;\n box-sizing: border-box;\n}\n\n.xendit-dropdown:disabled {\n background: var(--xendit-color-disabled);\n cursor: default;\n}\n\n.xendit-dropdown-overlay {\n contain: style;\n position: absolute;\n z-index: var(--xendit-z-index-overlay);\n display: flex;\n flex-direction: column;\n gap: 4px;\n max-height: 320px;\n padding: 4px;\n margin: 4px 0;\n box-sizing: border-box;\n background-color: var(--xendit-color-background);\n border: 1px solid var(--xendit-color-border);\n border-radius: var(--xendit-radius-1);\n list-style: none;\n box-shadow: var(--xendit-card-shadow);\n overflow-y: auto;\n overscroll-behavior: none;\n}\n\n.xendit-dropdown-overlay ul {\n list-style: none;\n padding: 4px;\n margin: 0;\n}\n\n.xendit-dropdown-search {\n position: sticky;\n top: 0;\n z-index: 1;\n}\n\n.xendit-dropdown-search input {\n width: 100%;\n padding: 8px;\n border: 1px solid var(--xendit-color-border);\n border-radius: var(--xendit-radius-1);\n box-sizing: border-box;\n outline: none;\n}\n\n.xendit-dropdown-search input:focus {\n border-color: var(--xendit-color-primary);\n box-shadow: var(--xendit-focus-shadow);\n}\n\n.xendit-dropdown-item {\n display: grid;\n grid-template-columns: 1fr auto;\n align-items: center;\n gap: 8px;\n padding: 8px 12px 8px 4px;\n border-radius: var(--xendit-radius-1);\n cursor: pointer;\n z-index: 0;\n --xendit-dropdown-item-hover-color: var(--xendit-color-background);\n --xendit-dropdown-item-hover-bg-color: var(--xendit-color-primary);\n}\n\n.xendit-dropdown-item-disabled {\n --xendit-dropdown-item-hover-color: var(--xendit-color-text);\n --xendit-dropdown-item-hover-bg-color: var(--xendit-color-disabled);\n}\n\n.xendit-dropdown-item-active {\n box-shadow: var(--xendit-focus-shadow);\n}\n\n.xendit-dropdown-item:hover {\n background-color: var(--xendit-dropdown-item-hover-bg-color);\n}\n\n.xendit-dropdown-item:hover .xendit-dropdown-item-text,\n.xendit-dropdown-item:hover .xendit-dropdown-item-description {\n color: var(--xendit-dropdown-item-hover-color);\n}\n\n.xendit-dropdown-item-selected {\n color: var(--xendit-color-primary);\n}\n\n.xendit-dropdown-item:hover .xendit-dropdown-item-selected {\n color: var(--xendit-dropdown-item-hover-color);\n}\n\n.xendit-dropdown-item.xendit-dropdown-has-asset {\n grid-template-columns: auto 1fr auto;\n}\n\n.xendit-dropdown-item-text {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.xendit-dropdown-item-disabled {\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n.xendit-dropdown-item-disabled:hover,\n.xendit-dropdown-item-disabled.xendit-dropdown-item-active {\n background-color: var(--xendit-color-disabled);\n}\n\n/* Dropdown ends */\n\n/* Button */\n.xendit-button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n padding: 12px 16px;\n font-family: var(--xendit-font-family);\n font-size: 14px;\n font-weight: 600;\n line-height: 16px;\n letter-spacing: -0.09px;\n cursor: pointer;\n transition: background-color var(--xendit-animation-duration)\n var(--xendit-animation-ease);\n}\n.xendit-button-primary-rounded {\n border: 1px solid transparent;\n background-color: var(--xendit-color-primary);\n color: var(--xendit-color-background);\n border-radius: var(--xendit-radius-1);\n}\n.xendit-button-white-rounded {\n background-color: var(--xendit-color-background);\n color: var(--xendit-color-text);\n border: 1px solid var(--xendit-color-border);\n border-radius: var(--xendit-radius-1);\n}\n.xendit-button-white-rounded:hover {\n background-color: var(--xendit-color-border);\n}\n.xendit-button-block {\n width: 100%;\n}\n.xendit-button-sm {\n padding: 8px 12px;\n font-size: 12px;\n line-height: 16px;\n}\n\n@keyframes xendit-button-loading-spinner-spin {\n 0% {\n transform: rotate(0deg);\n }\n 100% {\n transform: rotate(360deg);\n }\n}\n\n.xendit-button-loading-spinner {\n width: 16px;\n height: 16px;\n animation: xendit-button-loading-spinner-spin 1s linear infinite;\n}\n\n.xendit-skeleton-field button {\n height: 42px;\n background-color: var(--xendit-color-disabled);\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--xendit-color-text-secondary);\n}\n\n/* Button ends */\n\n/* Form Simulation Helper */\n.xendit-form-simulation-root {\n position: relative;\n}\n.xendit-form-simulation-trigger {\n background: transparent;\n border: none;\n cursor: pointer;\n padding: 0;\n}\n.xendit-form-simulation-popover {\n position: absolute;\n top: 100%;\n right: 0;\n\n width: 350px;\n display: flex;\n flex-direction: column;\n gap: 12px;\n border-radius: 4px;\n padding: 12px;\n border: 1px solid var(--xendit-color-border);\n background: color-mix(\n in srgb,\n var(--xendit-color-background),\n transparent 40%\n );\n backdrop-filter: blur(6px);\n box-shadow: var(--xendit-card-shadow);\n}\n\n.xendit-form-simulation-popover .xendit-dropdown-overlay {\n width: auto;\n}\n\n.xendit-form-simulation-scenario-icon {\n height: 28px;\n width: 40px;\n border-radius: 4px;\n border: 1px solid var(--xendit-color-border);\n object-fit: contain;\n background-color: white;\n}\n\n/* Form Simulation Helper ends */\n\n.xendit-tooltip {\n position: absolute;\n top: 100%;\n right: 50%;\n transform: translateX(50%);\n background-color: black;\n color: white;\n padding: 8px 12px;\n border-radius: var(--xendit-radius-1);\n white-space: nowrap;\n z-index: 1000;\n font-weight: 600;\n font-size: 14px;\n line-height: 16px;\n animation: xendit-tooltip-fade-in var(--xendit-animation-duration)\n var(--xendit-animation-ease);\n opacity: 1;\n}\n\n@keyframes xendit-tooltip-fade-in {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n\n/* Instructions */\n\n.xendit-instructions-bold {\n font-weight: 600;\n}\n.xendit-instructions-bullet-list {\n display: flex;\n flex-direction: column;\n gap: 12px;\n margin: 8px 0;\n}\n.xendit-instructions-bullet-list::marker {\n color: var(--xendit-color-text-secondary);\n}\n.xendit-instructions-form-card {\n display: flex;\n flex-direction: column;\n padding: 16px;\n border-radius: 12px;\n border: 1px solid var(--xendit-color-border);\n gap: 4px;\n width: 321px;\n}\n.xendit-instructions-form-field {\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 8px 0;\n border-bottom: 1px solid var(--xendit-color-border);\n}\n.xendit-instructions-form-field-label {\n font-size: 12px;\n font-weight: 600;\n line-height: 16px;\n color: var(--xendit-color-text-secondary);\n}\n.xendit-instructions-form-field-value {\n font-size: 14px;\n line-height: 20px;\n color: var(--xendit-color-text);\n}\n.xendit-instructions-form-heading {\n font-size: 14px;\n font-weight: 600;\n line-height: 20px;\n margin: 4px 0;\n}\n.xendit-instructions-italics {\n font-style: italic;\n}\n.xendit-instructions-numbered-list {\n display: flex;\n flex-direction: column;\n gap: 16px;\n list-style-type: decimal;\n padding-left: 40px;\n}\n.xendit-instructions-single-tab-heading {\n font-size: 14px;\n font-weight: 600;\n line-height: 20px;\n margin-bottom: 16px;\n}\n.xendit-instructions-step-box {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n.xendit-instructions-step-li {\n font-size: 14px;\n line-height: 20px;\n}\n.xendit-instructions-step-li p {\n margin: 0;\n}\n.xendit-instructions-step-li::marker {\n margin-left: 20px;\n}\n.xendit-instructions-tab-button {\n font-family: var(--xendit-font-family);\n font-size: 14px;\n padding: 8px 4px;\n background-color: transparent;\n border: none;\n border-top: 3px solid transparent;\n border-bottom: 3px solid transparent;\n cursor: pointer;\n}\n.xendit-instructions-active-tab {\n border-bottom-color: var(--xendit-color-primary);\n color: var(--xendit-color-primary);\n font-weight: 600;\n}\n.xendit-instructions-tab-list {\n display: flex;\n gap: 16px;\n margin-bottom: 16px;\n border-bottom: 1px solid var(--xendit-color-border);\n}\n.xendit-instructions-table {\n font-size: 14px;\n line-height: 16px;\n width: 100%;\n border-collapse: collapse;\n}\n.xendit-instructions-table-cell {\n padding: 4px;\n border: 1px solid black;\n}\n.xendit-instructions-table-header {\n font-size: 14px;\n font-weight: 600;\n line-height: 16px;\n padding: 4px;\n border: 1px solid black;\n}\n\n/* Instructions ends */\n\n.xendit-default-action-container {\n display: flex;\n flex-direction: column;\n border: none;\n}\n\n.xendit-action-title {\n font-weight: 600;\n font-size: 20px;\n line-height: 28px;\n text-align: center;\n}\n\n.xendit-action-iframe {\n border: none;\n width: 100%;\n height: 100%;\n}\n\n.xendit-action-present-to-customer {\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n.xendit-action-present-to-customer-affirm {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n.xendit-action-qr-content {\n position: relative;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 12px;\n max-width: 384px;\n border: 1px solid var(--xendit-color-border);\n border-radius: var(--xendit-radius-1);\n padding: 16px;\n overflow: hidden;\n}\n.xendit-qr-merchant-info {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 4px;\n}\n.xendit-action-qr-channel-logo {\n height: 64px;\n align-self: center;\n object-fit: contain;\n}\n.xendit-action-qr-qrcode-container {\n width: 100%;\n position: relative;\n z-index: var(--xendit-z-index-overlay);\n}\n\n/* va actions */\n.xendit-action-va-content {\n display: flex;\n flex-direction: column;\n border: 1px solid var(--xendit-color-border);\n border-radius: var(--xendit-radius-1);\n padding: 16px;\n padding-bottom: 24px;\n}\n.xendit-action-va-details {\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n.xendit-action-va-detail-item {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n.xendit-action-va-detail-content {\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n.xendit-action-va-heading {\n color: var(--xendit-color-text-placeholder);\n}\n.xendit-action-va-tag {\n color: var(--xendit-color-text-placeholder);\n background-color: #fafafa;\n padding: 2px 4px;\n border-radius: 4px;\n}\n\n/* redirect, deeplink, and push notification actions */\n.xendit-redirect-instructions {\n display: flex;\n flex-direction: column;\n align-items: center;\n text-align: center;\n gap: 24px;\n}\n\n.xendit-redirect-instructions-logo {\n display: flex;\n justify-content: center;\n align-items: center;\n width: 112px;\n height: 112px;\n border: 2px solid var(--xendit-color-border);\n border-radius: 50%;\n overflow: hidden;\n box-shadow: var(--xendit-card-shadow);\n}\n\n.xendit-redirect-instructions-logo img {\n width: 96px;\n height: 96px;\n object-fit: contain;\n}\n\n.xendit-redirect-instructions-text {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.xendit-redirect-instructions-button {\n display: inline-block;\n border-radius: 99px;\n color: white;\n padding: 12px 16px;\n background-color: var(--xendit-channel-brand-color, #000);\n text-decoration: none;\n white-space: nowrap;\n box-shadow: var(--xendit-card-shadow);\n}\n\n.xendit-redirect-instructions-button:hover,\n.xendit-redirect-instructions-button:active {\n filter: brightness(1.1);\n}\n\n/* googlepay */\n\n.gpay-card-info-container-fill {\n display: flex;\n}\n"],"names":["once","XenditInitEvent","Event","static","constructor","super","type","XenditFatalErrorEvent","message","this","XenditReadyEvent","channelCode","XenditNotReadyEvent","XenditSubmissionBeginEvent","XenditSubmissionEndEvent","reason","userErrorMessage","developerErrorMessage","XenditActionBeginEvent","XenditActionEndEvent","XenditWillRedirectEvent","XenditSessionCompleteEvent","XenditSessionExpiredOrCanceledEvent","XenditSessionPendingEvent","XenditSessionNotPendingEvent","XenditPaymentRequestCreatedEvent","paymentRequestId","XenditPaymentTokenCreatedEvent","paymentTokenId","XenditPaymentRequestDiscardedEvent","XenditPaymentTokenDiscardedEvent","internal","Symbol","Accordion","props","_jsx","class","children","Icon","name","size","direction","svgTransform","iconNode","d","stroke","scaleIcon","_jsxs","_Fragment","fill","strokeLinecap","strokeLinejoin","Error","className","width","height","viewBox","transform","scale","AccordionItem","id","title","iconName","subtitle","disabled","open","onClick","chevronDirection","toggleOpen","useCallback","handleKeyPress","event","key","preventDefault","handleClick","classNames","onKeyDown","role","tabIndex","inert","SessionContext","createContext","displayName","BusinessContext","CustomerContext","ChannelsContext","ChannelUiGroupsContext","DigitalWalletsContext","SdkContext","CurrentChannelContext","useSession","context","useContext","useChannels","useDigitalWallets","useSdk","useCurrentChannel","XenditSessionProvider","data","sdk","session","business","customer","channels","digitalWallets","channelUiGroups","channel","getCurrentChannel","getSdkStatus","status","Provider","value","MOCK_NETWORK_DELAY_MS","assert","arg","assertIsArray","Array","isArray","assertIsNotArray","assertEquals","a","b","sleep","ms","Promise","resolve","setTimeout","AbortError","isAbortError","error","cancellableSleep","signal","reject","onAbort","removeEventListener","clearTimeout","timeoutId","aborted","addEventListener","findBestAction","actions","best","find","descriptor","userAgent","navigator","test","isAndroidOrIos","findPaylinkAction","options","enablePaylinks","MOCK_HOST_ID","hosts","pl","pd","sl","sd","hostFromHostId","hostId","mergeIgnoringUndefined","original","updates","result","Object","keys","undefined","usePrevious","ref","useRef","useLayoutEffect","current","formFieldName","field","channel_property","values","join","seed","Math","floor","random","formFieldId","split","map","c","charCodeAt","toString","randomHexString","length","bytes","arr","Uint8Array","i","randomBytes","from","padStart","randomUUID","useIdSafe","canBeSimulated","action","errorToString","stack","JSON","stringify","removeUndefinedPropertiesFromObject","object","getOwnPropertyDescriptor","get","getValueFromChannelProperty","channelProperty","channelProperties","str","cursor","dotIndex","indexOf","slice","getCardNumberFromChannelProperties","cardNumber","parseEncryptedFieldValue","out","version","publicKey","iv","cipherText","valid","validationError","withoutValidationError","parts","parseInt","isNaN","atob","objectIdMap","WeakMap","objectIdCounter","resolvePairedChannel","savePaymentMethod","allow_save","satisfiesMinMax","session_type","amount","min","min_amount","max","max_amount","Number","MAX_VALUE","lockDownInteralProperty","obj","defineProperty","enumerable","writable","configurable","RELEASED_CHANNELS","CARDS","QRIS","QR_PH","PROMPTPAY","SGQR","ALIPAY","APPOTA","ASTRAPAY","DANA","GCASH","GRABPAY","JENIUSPAY","LINEPAY","LINKAJA","NEXCASH","OVO","PAYMAYA","SHOPEEPAY","TOUCHNGO","TRUEMONEY","VNPTWALLET","WECHATPAY","ZALOPAY","GOPAY","GOPAY_RECURRING","formHasFieldOfType","form","ButtonVariant","ButtonSize","Button","variant","rest","buttonVariantClass","BARE","PRIMARY_ROUNDED","WHITE_ROUNDED","buttonSizeClass","SM","MD","ButtonLoadingSpinner","angle1","PI","radius","start","cos","sin","end","strokeWidth","Dropdown","_id","onChange","defaultIndex","selectedIndex","placeholder","fixedOverlayWidth","enableSearch","t","generatedId","isControlled","internalIndex","setInternalIndex","useState","currentIndex","activeIndex","setActiveIndex","_open","setOpen","searchQuery","setSearchQuery","lastWidth","setLastWidth","btnRef","rootRef","listRef","activeRef","searchInputRef","overlayRef","filteredOptions","useMemo","filtered","withIndex","filter","item","opt","trim","query","toLowerCase","includes","description","clampedActive","targetElement","getBoundingClientRect","window","ResizeObserver","resizeObserver","entries","entry","target","borderBoxSize","inlineSize","observe","disconnect","overlayEl","buttonEl","updateOverlayPosition","buttonRect","overlayRect","innerHeight","bottom","style","position","onMouseDown","e","root","contains","document","onFocusOut","relatedTarget","body","scrollContainer","parentElement","scrollTop","offsetTop","clientHeight","openList","queueMicrotask","focus","closeList","onButtonClick","selectItemAndClose","index","onListKeyDown","isSearchInput","activeItem","originalIndex","onButtonKeyDown","onOptionClick","stopPropagation","currentTarget","dataset","onSearchTermChange","selected","hasLeadingAsset","leadingAsset","shortTitle","onInput","isSelected","isActive","leadingAssetInOverlay","DropdownSkeleton","option","bffSessionToPublic","bffSession","assertNotEquals","mode","payment_session_id","sessionType","referenceId","reference_id","country","currency","channel_properties","expiresAt","Date","expires_at","locale","subscription","immediatePayment","immediate_payment","schedule","anchorDate","anchor_date","interval","intervalCount","interval_count","retryInterval","retry_interval","retryIntervalCount","retry_interval_count","totalRecurrence","total_recurrence","totalRetry","total_retry","items","netUnitAmount","net_unit_amount","quantity","url","imageUrl","image_url","category","subcategory","metadata","bffUiGroupToPublic","bffChannelGroup","channelsByGroupId","groupsByGroupId","marshalConfig","group","groupId","label","bffChannelToPublic","singleBffChannelToPublic","bffChannel","bffChannelsByGroupId","bffGroupsByGroupId","pairChannels","paired","channel_code","pairs","ch","brandName","brand_name","brandColor","brand_color","brandLogoUrl","brand_logo_url","uiGroup","ui_group","minAmount","maxAmount","cardBrands","card","brands","logoUrl","logo_url","makeGroupsByGroupId","bffChannelGroups","groupMap","bffGroup","channelFilterFn","filterMinMax","code","RegExp","channelCodeMatchesFilter","makeChannelsByGroupId","bffChannels","push","findChannelPairs","brandMap","Map","has","set","_","pair","other","DottedLine","ChannelPickerGroup","currentChannel","dropdownId","fakeDropdownSelection","setFakeDropdownSelection","containerRef","containerIsPopulated","setContainerIsPopulated","selectedChannelElementRef","pairChannelData","channelsInGroup","createChannelComponent","replaceChildren","previousOpen","setCurrentChannel","onSelectedChannelChange","dropdownOption","channelOptions","src","getChannelDisabledReason","hideDropdown","htmlFor","groupName","ns","i1","findIndex","i2","dropdownSelectedIndex","display","ChannelPickerDigitalWalletSection","digitalWalletsGooglePay","google_pay","el","createDigitalWalletComponent","appendChild","remove","ChannelPickerRoot","useChannelUiGroups","channelsByGroup","thisRef","selectedGroupId","previewGroupId","setPreviewGroupId","handleSelectChannelGroup","dispatchEvent","XenditClearCurrentChannelEvent","newGroup","g","enabledChannels","groupEnabledChannelStats","digitalWalletSectionEnabled","enableDigitalWallets","enabledChannelsStats","disabledReason","firstDisabledChannelReason","ICONS_BY_PM_TYPE","QR_CODE","OVER_THE_COUNTER","EWALLET","BANK_TRANSFER","DIRECT_DEBIT","VIRTUAL_ACCOUNT","ONLINE_BANKING","pm_type","bubbles","composed","FlagIcon","countryCode","borderRadius","backgroundImage","backgroundSize","backgroundPosition","CountryField","selectedCountry","setSelectedCountry","selectedCountryIndex","COUNTRIES_AS_DROPDOWN_OPTIONS","hiddenFieldRef","useOnCardCountryChange","newCountry","newOption","onChangeWrapper","defaultValue","getCountries","Intl","DisplayNames","of","sort","localeCompare","fn","cardDetails","useChannelComponentData","cardDetailsCountry","details","country_codes","previousCardDetailsCountry","DropdownField","isDropdownField","dropdownItems","selectedItemValue","setSelectedItemValue","HTMLElement","EventTarget","XenditFormAssociatedFocusTrap","internals","attachInternals","element","customElements","define","tag","InternalUpdateWorldState","InternalUpdateChannelComponentData","InternalSetFieldTouchedEvent","InternalBehaviorTreeUpdateEvent","InternalNeedsRerenderEvent","InternalScheduleMockUpdateEvent","mockData","IframeRegistryContext","IFRAME_ORIGIN","URL","origin","IframeRegistryProvider","iframeRegistry","iframeRegistryValue","registerIframe","fieldName","unregisterIframe","delete","postMessageToIframe","iframe","contentWindow","postMessage","parsedIframeUrl","IFRAME_SRC","IframeField","iframeRef","iframeEcdhPublicKey","setIframeEcdhPublicKey","focusWithin","setFocusWithin","cardBrand","setCardBrand","useChannel","handleEventFromIframe","expectedSource","source","ecdhPublicKey","encrypted","encryptionVersion","resultData","enc","empty","validationErrorCodes","btoa","localeKey","console","giveFocusToIframe","registry","iframeUrl","searchParams","location","sdkKey","signature","iframeFieldAppearance","focusClass","onFocus","sandbox","CardBrands","cardsBrandList","selectedCardBrand","cardBrandLogo","alt","PhoneNumberField","setCountryCode","countryCodeIndex","COUNTRIES_WITH_DIAL_CODES_AS_DROPDOWN_OPTIONS","r","localNumber","setLocalNumber","inputRef","formatPhoneNumber","phoneNumber","sanitizePhoneNumber","number","dial","updateHiddenField","handleCountryChange","nextCountry","inputMode","getExampleNumber","examples","formatInternational","replace","getCountryCallingCode","onBlur","international","formatForUser","nextLocal","autoComplete","Boolean","parsed","parsePhoneNumberFromString","isPossible","toTitleValuePair","nameValue","PROVINCES_US","PROVINCES_CA","PROVINCES_GB","province","ProvinceField","allFields","useChannelProperties","clearValue","onChangeDropdown","onChangeInput","getProvinceList","thisField","otherField","previousField","getBestCountryForProvinceField","previousOptions","TextField","minLength","isTextField","min_length","maxLength","max_length","autocomplete","CURRENCY_NUMBER_FORMAT_LOCALE","IDR","VND","BRL","RUB","CZK","RON","UAH","CLP","COP","UYU","ARS","INR","NPR","LKR","BDT","CURRENCY_SYMBOLS","USD","CAD","EUR","AFN","ALL","AMD","AUD","AZN","BAM","BIF","BND","BOB","BWP","BYN","BZD","CDF","CHF","CNY","CRC","CVE","DJF","DKK","DOP","ERN","ETB","GBP","GEL","GHS","GNF","GTQ","HKD","HNL","HUF","ILS","IRR","ISK","JMD","JPY","KES","KHR","KMF","KRW","KZT","MDL","MGA","MKD","MMK","MOP","MUR","MXN","MYR","MZN","NAD","NGN","NIO","NOK","NZD","PAB","PEN","PHP","PKR","PLN","PYG","RSD","RWF","SDG","SEK","SGD","SOS","THB","TOP","TRY","TTD","TWD","TZS","UGX","UZS","XAF","XOF","ZAR","ZMW","ZWL","CURRENCY_SYMBOL_POSITION","CURRENCY_SYMBOL_DECIMALS","BHD","JOD","KWD","LYD","OMR","TND","amountFormat","isNegative","decimals","NumberFormat","minimumFractionDigits","maximumFractionDigits","format","abs","symbol","FieldInstallmentPlan","hasCardsField","paymentOptions","installmentPlans","installment_plans","selectedItemKey","setSelectedItemKey","plan","installments","terms","installment_amount","interest_rate","planKey","unshift","selectedItemIndex","clearSelectedItem","handleChange","newPlan","prevItems","some","Field","span","renderInner","localeMap","en","th","vi","getLocalizedErrorMessage","errorCode","isLocaleKey","sanitizeRegex","pattern","startsWith","endsWith","validate","input","required","validateEncryptedCardField","phone","isValid","validatePhoneNumber","validateEmail","validatePostalCode","regex_validators","regex","validateText","channelPropertyFieldValidate","channelPropertyKeys","getChannelPropertyValue","FormSimulationHelperContext","FormSimulationHelper","scenarios","onSelect","FormSimulationRoot","FormSimulationTrigger","FormSimulationHelperPopover","simulateHelper","scenario","docsLink","href","rel","CSS_CLASSES","FieldGroup","fieldGroup","groupIndex","handleFieldChanged","simulationScenarios","groupContainerRef","touchedFields","setTouchedFields","fieldGroupSpans","f","groupRowCount","ceil","reduce","agg","containerElement","listener","prev","err","renderError","group_label","FormSimulationHelperWrapper","fieldPositionBySpan","fieldRow","fieldColumn","isLastRow","calculateFieldPosition","CSS_CLASSES_BOTTOM_LEFT_0","CSS_CLASSES_BOTTOM_RIGHT_0","CSS_CLASSES_TOP_LEFT_0","CSS_CLASSES_TOP_RIGHT_0","CSS_CLASSES_COLLAPSE_RIGHT","CSS_CLASSES_COLLAPSE_LEFT","CSS_CLASSES_COLLAPSE_TOP","CSS_CLASSES_COLLAPSE_BOTTOM","getFieldClassNames","scenarioName","s","CARDS_SCENARIOS","ChannelForm","forwardRef","onChannelPropertiesChanged","channelComponentData","formRef","setChannelProperties","useImperativeHandle","setAllFieldsTouched","elements","HTMLInputElement","forEach","getChannelProperties","iter","rawValue","Blob","subkeys","valueAsArray","formValueToStringArray","outer","subkey","part","shift","nextValue","formKvToChannelProperties","FormData","filteredForm","filterFormFields","useFilteredFormFields","previousFilteredForm","useEffect","formsAreEqual","getSimulationScenarios","supportsSimulationScenarios","filteredFieldGroups","fields","fieldGroups","groupFields","ChannelPropertiesContext","parse","_e","showBillingDetailsFields","require_billing_information","hasInstallmentPlans","flags","condition","display_if","property","operator","channelValue","GraphicRedirectInstructions","arrowRef","arrowSquareGroupRef","supportsAnimation","prototype","animate","arrowKeyFrames","arrowAnimationOptions","arrowSquareBounceKeyFrames","arrowSquareBounceAnimationOptions","xmlns","opacity","transformOrigin","duration","easing","iterations","Infinity","delay","scannerKeyFrames","scanDownAnimationOptions","scanUpAnimationOptions","squareKeyFrames","squareAnimationOptions","Checkbox","checked","htmlId","points","ChannelContext","ChannelComponentDataContext","ChannelRoot","channelOrPair","channelData","divRef","firstMemberChannel","hasPairedChannel","resolvedChannel","instructions","instructionsAsTuple","shouldShowSaveCheckbox","allow_save_payment_method","banner","cleanedProperties","installment_configuration","cleanedInstallmentConfiguration","fromEntries","XenditChannelPropertiesChangedEvent","Banner","GRAPHIC_COMPONENTS_BY_PM_TYPE","instr","scannerRef","squareBackgroundRef","clipPathId","startAnimation","onfinish","x","y","rx","aspectRatio","aspect_ratio","String","link_url","alt_text","NetworkError","errorResponse","convertDataToUrlSearchParams","params","URLSearchParams","append","endpoint","method","getPath","getQuery","async","pathArg","queryArg","requestBody","abortSignal","versionNumber","host","search","headers","response","fetch","ok","errorData","json","error_code","fetchSessionData","sessionAuthKey","createPaymentToken","createPaymentRequest","simulatePaymentRequest","pollSession","tokenRequestId","token_request_id","lookupCardDetails","getPaymentOptions","behaviorNode","impl","child","instance","BehaviorTree","bb","updating","again","update","updateCount","assertMaxRecursionDepth","next","updateTree","findBehavior","depth","isChanged","exitSubtree","enterSubtree","node","enter","exit","ActionCompletedBehavior","RedirectInstructions","logoAlt","redirectUrl","redirectButtonLabel","ActionDeepLink","channelName","Dialog","onClose","seamless","borderColor","closeCalledRef","closeAnimationPlaying","dialogRef","backdropRef","onCloseSafe","onCloseWithAnimation","backdropFadeOutKeyframes","animationOptionsOut","animation","foregroundFadeOutKeyframes","backdropFadeKeyframes","animationOptionsIn","foregroundFadeKeyframes","close","border","noPadding","padding","backgroundColor","offset","reverse","DefaultActionContainer","wrapperRef","component","createActionContainerComponent","destroyComponent","defaultActionContainerType","DefaultActionContainerType","QrWithCustomArt","ContainerActionBehavior","cleanupFn","defaultContainerHeight","defaultContainerWidth","ensureHasActionContainer","Generic","liveComponents","actionContainer","emptyActionContainer","cleanedUp","success","container","createElement","setAttribute","render","abortSubmission","actionCancelledByUser","cleanupActionContainer","cancelledByUser","updateActionContainerBrandColor","setProperty","populateActionContainer","createComponent","ActionDeepLinkBehavior","actionIndex","world","deepLinkAction","paymentEntity","entity","bind","ActionEmptyListPushNotification","BffPaymentEntityType","toPaymentEntity","prOrPt","payment_request_id","PaymentRequest","payment_token_id","PaymentToken","getPaymentEntityStatusCopyKey","entityType","suffix","makeTestPollResponse","makeTestPollResponseForPending","paymentRequest","paymentToken","payment_request","withPaymentEntityStatus","payment_token","makeTestPollResponseForPendingPaymentEntityOnly","_mock_action_type","succeeded_channel","makeTestPollResponseForSuccess","makeTestPollResponseForFailure","makeTestPaymentRequest","mockActionType","session_token_request_id","makeMockActions","actionType","iframe_capable","action_title","action_subtitle","action_graphic","content","text","makeOneMockAction","ActionEmptyListPushNotificationBehavior","hackyOvoActionLatch","mock","ActionIframe","onIframeComplete","srcDoc","mockIframeSrcDoc","whatItWouldBe","ActionIframeBehavior","mockResult","mockStatus","updateMocksOnIframeCompletion","actionCompleted","pollImmediatelyRequested","ActionPaylinkBehavior","link","head","getCustomQrArtComponent","parsedQr","merchantAccountInformation","QrArtQris","QrArtDuitnow","channelLogo","merchantName","amountText","merchantIdLabel","info","qrisInfo","nmid","getMerchantIdLabel","qrisAccentColor","borderArtWidth","flexDirection","paddingTop","paddingLeft","paddingRight","overflow","alignSelf","gap","marginTop","margin","marginBottom","zIndex","qr","fontSize","lineHeight","top","left","pointerEvents","right","duitnowAccentColor","generateQrSvg","artConfig","qrcode","create","svgText","qrSvgRenderer","svgNode","DOMParser","parseFromString","documentElement","modules","foregroundPath","querySelector","colors","backgroundPath","timestampForFilename","now","DateTimeFormat","hour","minute","day","month","year","cleanStringForFilename","char","ActionQr","businessName","onAffirm","qrString","showSpinner","setShowSpinner","onMadePaymentClicked","qrArtConfigDefault","log","innerText","didDownload","onClickQrCode","PointerEvent","pointerType","qrArtConfigForDownload","filename","createObjectURL","svgString","XMLSerializer","serializeToString","svgBlob","image","Image","onload","naturalWidth","naturalHeight","canvas","ctx","getContext","drawImage","revokeObjectURL","imageDataUrl","toDataURL","anchor","download","click","removeChild","onerror","downloadSvgAsPng","catch","hideUi","childNodes","firstChild","qrWrapper","affirmSection","QrArtComponent","paddingBottom","rootTemplateClass","templateClass","knownTemplateClasses","isSurrogatePair","emvcoQrTokenize","emvcoString","seen","Set","currentTag","substring","add","lengthStr","javascriptCharacters","realCharacters","writeFieldForDescriptor","descriptorMap","output","parseTemplateWithClass","raw","writeMerchantAccountInformationField","fieldType","ActionQrBehavior","qrAction","rawField","fieldNumber","emvcoQrParse","mock_emvco_qr_field_26_00","field_26_00","globallyUniqueIdentifier","qrHasCustomArt","hasCustomQrArt","actionQrProps","getAttribute","affirmPayment","isProdLive","simulatePaymentRequested","ActionRedirectBehavior","Instructions","SingleTabInstructions","instruction","MultiTabInstructions","InstructionsSteps","selectedTab","setSelectedTab","step","stepItems","Fragment","renderStep","renderFormattedStringChildren","nodes","nodeType","Node","TEXT_NODE","textContent","ELEMENT_NODE","nodeName","renderFormattedStringElement","domParser","renderFormattedString","renderTextStep","renderImageStep","renderBulletsStep","heading","renderFormStep","header","rows","row","rowIndex","cell","cellIndex","renderTableStep","TooltipContext","fire","clear","TooltipProvider","setText","timeout","Tooltip","ActionVa","vaNumber","vaDetails","enableCopy","detail","CopyButton","clipboard","writeText","ActionVaBehavior","vaAction","actionVaProps","CardInfoBehavior","cardDetailsRequest","abortLookupCardDetails","abortController","abort","AbortController","promise","then","encodedError","schemes","cleanedCardNumber","card_number","ChannelInvalidBehavior","ChannelValidBehavior","lastChannelCode","sendReadyEventIfChanged","PaymentEntityFailedBehavior","submissionRequested","PollWorker","sessionTokenRequestId","onPollResult","started","stopped","attempt","mult","tries","base","sleepTime","retryLoop","isMock","XenditComponentsTest","nextMockUpdate","_err","isPolling","stop","PaymentEntityPendingBehavior","pollWorker","pollResponse","succeededChannel","PaymentEntityRequiresActionBehavior","canCreateActionContainer","resetPolling","polling","PaymentOptionsBehavior","paymentOptionsRequest","lookupPaymentOptions","abortLookupPaymentOptions","total_amount","makeMockPaymentOptions","getPaymentOptionsAsync","SdkActiveBehavior","SdkFatalErrorBehavior","sdkFatalErrorMessage","SdkLoadingBehavior","SessionActiveBehavior","SessionCompletedBehavior","SessionFailedBehavior","discardPaymentEntity","SessionPendingBehavior","SimulatePaymentBehavior","exited","simulationRequest","simulatePayment","abortSimulation","simulatePaymentAsync","SubmissionBehavior","submission","submissionError","submit","defaultUserErrorMessage","failureCode","subtext","getFailureCodeCopyKey","failureCodeUserErrorMessage","failure_code","instantSubmissionError","shouldSendSavePaymentMethod","makeTestPaymentToken","session_id","save_payment_method","asyncSubmit","error_content","message_1","message_2","behaviorTreeForSdk","sdkStatus","maybePaylinkAction","paylinkAction","behaviorTreeForPaylink","behaviorTreeForAction","behaviorTreeForPaymentEntity","behaviorTreeForSubmission","channelIsDigitalWallet","channelPropertiesValid","channelPropertiesAreValid","validityBehavior","cardInfoBehavior","paymentOptionsBehavior","behaviorTreeForForm","behaviorTreeForSession","hasPaylink","simulateBehavior","redirectCanBeHandledInIframe","DigitalWalletGooglepay","onReady","useBusiness","didCallReady","paymentsClient","googlePayChannels","allowed_payment_methods","payment_method_specification","googlePayConfig","apiVersion","apiVersionMinor","allowedPaymentMethods","emailRequired","merchantInfo","merchantId","merchant_id","transactionInfo","transactionId","totalPriceStatus","totalPrice","currencyCode","buttonConfigWithDefaults","buttonColor","buttonType","buttonRadius","buttonSizeMode","buttonBorderType","PaymentsClient","google","payments","api","environment","loadPaymentData","paymentData","targetChannel","allChannels","getActiveChannels","googlePayChannel","paymentMethodData","findChannel","findTargetChannel","submitDigitalWallet","statusCode","localeKeyForGooglePayError","firstGooglePayChannel","isReadyToPay","button","createButton","buttonLocale","targetChannelCode","DigitalWalletWaitForLoad","scriptTagRegex","checkLoaded","forceRender","targetScript","scripts","script","DigitalWalletContainer","digitalWalletCode","digitalWalletOptions","sdkStatusCheckers","GOOGLE_PAY","XenditComponents","componentsSdkKey","parseSdkKey","worldState","channelPicker","paymentChannels","digitalWalletContainer","behaviorTree","currentChannelCode","currentDigitalWalletSubmission","eventListenersPresent","fatalErrorEvent","behaviorTreeUpdate","onUpdateWorldState","onUpdateChannelComponentData","hasScheduledRender","rerenderAllComponents","syncInertAttribute","initializeAsync","bff","channel_ui_groups","digital_wallets","assertInitialized","localeData","args","fallback","template","varName","warn","createTFunction","newData","renderChannelPicker","renderPaymentChannel","renderDigitalWalletComponent","getSession","getCustomer","bffCustomer","individual_detail","email","mobileNumber","mobile_number","individualDetail","givenNames","given_names","surname","getActiveChannelGroups","bffUiGroupsToPublic","bffChannelsToPublic","createChannelPickerComponent","setupUiEventsForChannelPicker","_event","active","cachedComponent","channelFormRef","createRef","setupUiEventsForPaymentChannel","channelObject","getActiveDigitalWallets","bffDigitalWallets","bffDigitalWalletsToPublic","prevComponent","hasSubmissionInProgress","channelComponents","hasAttribute","removeAttribute","showValidationErrors","optionsOrInternal","isInternal","requiresActionBehavior","qrCode","qrCodeOnly","tagName","pollImmediately","getState","setNextMockUpdate","makeTestBffData","debounceRendering","styleElement","firstStyleOrLinkElement","insertAdjacentElement","createStyles"],"mappings":"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,QAMtCkG,GACJnG,GAA8BzY,IAC3BqO,IACC,MAAMgR,EAAOS,EAAAA,sBAAsBzR,EAAQ5S,OAC3C,OAAK4jB,EACE,IACFhR,EACHf,WAAY,IAAI+R,IAChB9mB,MAAO,GAAG8V,EAAQ9V,WAAW8mB,KAC7BA,QALgB,OAQpB9V,OAAQ8E,GACD+R,QAAQ/R,IAGb8Q,GAAsB,CAC1B9Q,EACA6Q,KAEA,MAAMmB,EAASC,EACbpB,EACA7Q,EAAQ5S,OAEV,OAAI4kB,GAAUA,EAAOE,aAAqBF,EAEnC,MCzKT,SAASG,GAAiBC,GAIxB,MAAO,CACLloB,MAAOkoB,EAAUxpB,KACjBwE,MAAOglB,EAAUhlB,MAErB,CAGO,MAAMilB,GAAiC,CAC5C,CACEzpB,KAAM,UACNwE,MAAO,MAET,CACExE,KAAM,SACNwE,MAAO,MAET,CACExE,KAAM,iBACNwE,MAAO,MAET,CACExE,KAAM,UACNwE,MAAO,MAET,CACExE,KAAM,WACNwE,MAAO,MAET,CACExE,KAAM,aACNwE,MAAO,MAET,CACExE,KAAM,WACNwE,MAAO,MAET,CACExE,KAAM,cACNwE,MAAO,MAET,CACExE,KAAM,WACNwE,MAAO,MAET,CACExE,KAAM,uBACNwE,MAAO,MAET,CACExE,KAAM,iCACNwE,MAAO,MAET,CACExE,KAAM,UACNwE,MAAO,MAET,CACExE,KAAM,UACNwE,MAAO,MAET,CACExE,KAAM,OACNwE,MAAO,MAET,CACExE,KAAM,SACNwE,MAAO,MAET,CACExE,KAAM,QACNwE,MAAO,MAET,CACExE,KAAM,WACNwE,MAAO,MAET,CACExE,KAAM,UACNwE,MAAO,MAET,CACExE,KAAM,OACNwE,MAAO,MAET,CACExE,KAAM,SACNwE,MAAO,MAET,CACExE,KAAM,WACNwE,MAAO,MAET,CACExE,KAAM,YACNwE,MAAO,MAET,CACExE,KAAM,QACNwE,MAAO,MAET,CACExE,KAAM,mBACNwE,MAAO,MAET,CACExE,KAAM,WACNwE,MAAO,MAET,CACExE,KAAM,gBACNwE,MAAO,MAET,CACExE,KAAM,WACNwE,MAAO,MAET,CACExE,KAAM,YACNwE,MAAO,MAET,CACExE,KAAM,cACNwE,MAAO,MAET,CACExE,KAAM,WACNwE,MAAO,MAET,CACExE,KAAM,UACNwE,MAAO,MAET,CACExE,KAAM,WACNwE,MAAO,MAET,CACExE,KAAM,SACNwE,MAAO,MAET,CACExE,KAAM,gBACNwE,MAAO,MAET,CACExE,KAAM,aACNwE,MAAO,MAET,CACExE,KAAM,aACNwE,MAAO,MAET,CACExE,KAAM,WACNwE,MAAO,MAET,CACExE,KAAM,iBACNwE,MAAO,MAET,CACExE,KAAM,eACNwE,MAAO,MAET,CACExE,KAAM,2BACNwE,MAAO,MAET,CACExE,KAAM,OACNwE,MAAO,MAET,CACExE,KAAM,WACNwE,MAAO,MAET,CACExE,KAAM,SACNwE,MAAO,MAET,CACExE,KAAM,QACNwE,MAAO,MAET,CACExE,KAAM,eACNwE,MAAO,MAET,CACExE,KAAM,cACNwE,MAAO,MAET,CACExE,KAAM,eACNwE,MAAO,MAET,CACExE,KAAM,iBACNwE,MAAO,MAET,CACExE,KAAM,eACNwE,MAAO,MAET,CACExE,KAAM,YACNwE,MAAO,MAET,CACExE,KAAM,QACNwE,MAAO,MAET,CACExE,KAAM,OACNwE,MAAO,MAET,CACExE,KAAM,UACNwE,MAAO,MAET,CACExE,KAAM,iBACNwE,MAAO,MAET,CACExE,KAAM,WACNwE,MAAO,MAET,CACExE,KAAM,aACNwE,MAAO,MAET,CACExE,KAAM,gBACNwE,MAAO,MAET,CACExE,KAAM,YACNwE,MAAO,MAET,CACExE,KAAM,UACNwE,MAAO,OAETuE,IAAIwgB,IAGOG,GAAiC,CAC5C,CACE1pB,KAAM,UACNwE,MAAO,MAET,CACExE,KAAM,mBACNwE,MAAO,MAET,CACExE,KAAM,WACNwE,MAAO,MAET,CACExE,KAAM,gBACNwE,MAAO,MAET,CACExE,KAAM,4BACNwE,MAAO,MAET,CACExE,KAAM,wBACNwE,MAAO,MAET,CACExE,KAAM,cACNwE,MAAO,MAET,CACExE,KAAM,UACNwE,MAAO,MAET,CACE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"}
|