import { NativeEventEmitter, NativeModules } from 'react-native'; import type { EmitterSubscription } from 'react-native'; import type { PrimerComponentDataValidationError, PrimerInvalidComponentData, PrimerValidComponentData, PrimerValidatingComponentData, } from '../../../models/PrimerComponentDataValidation'; import { PrimerError } from '../../../models/PrimerError'; import { eventTypes } from './Utils/EventType'; import type { EventType } from './Utils/EventType'; import type { AchStep } from '../../../models/ach/AchSteps'; import type { AchValidatableData } from '../../../models/ach/AchCollectableData'; const { RNTPrimerHeadlessUniversalCheckoutStripeAchUserDetailsComponent } = NativeModules; const eventEmitter = new NativeEventEmitter(RNTPrimerHeadlessUniversalCheckoutStripeAchUserDetailsComponent); export interface AchManagerProps { paymentMethodType: string; onStep?: (data: AchStep) => void; onError?: (error: PrimerError) => void; onInvalid?: (data: PrimerInvalidComponentData) => void; onValid?: (data: PrimerValidComponentData) => void; onValidating?: (data: PrimerValidatingComponentData) => void; onValidationError?: (data: PrimerComponentDataValidationError) => void; } export interface StripeAchUserDetailsComponent { /** * Starts the component, causing the {@link UserDetailsRetrieved} step * to be emitted. */ start(): Promise; /** * Sets the customer's first name. * @param value The customer's first name. */ handleFirstNameChange(value: String): Promise; /** * Sets the customer's last name. * @param value The customer's last name. */ handleLastNameChange(value: String): Promise; /** * Sets the customer's email address. * @param value The customer's email address. */ handleEmailAddressChange(value: String): Promise; /** * Submits the component, initiating the payment authorization process. * This function should only be called after setting the customer first name, * last name and email address. */ submit(): Promise; } export class PrimerHeadlessUniversalCheckoutAchManager { /////////////////////////////////////////// // Init /////////////////////////////////////////// constructor() {} /////////////////////////////////////////// // API /////////////////////////////////////////// async provide(props: AchManagerProps): Promise { await this.configureListeners(props); if (props.paymentMethodType === 'STRIPE_ACH') { const component: StripeAchUserDetailsComponent = { start: async () => { RNTPrimerHeadlessUniversalCheckoutStripeAchUserDetailsComponent.start(); }, submit: async () => { RNTPrimerHeadlessUniversalCheckoutStripeAchUserDetailsComponent.submit(); }, handleFirstNameChange: async (value: String) => { RNTPrimerHeadlessUniversalCheckoutStripeAchUserDetailsComponent.onSetFirstName(value); }, handleLastNameChange: async (value: String) => { RNTPrimerHeadlessUniversalCheckoutStripeAchUserDetailsComponent.onSetLastName(value); }, handleEmailAddressChange: async (value: String) => { RNTPrimerHeadlessUniversalCheckoutStripeAchUserDetailsComponent.onSetEmailAddress(value); }, }; await RNTPrimerHeadlessUniversalCheckoutStripeAchUserDetailsComponent.configure(); return component; } else { return null; } } private async configureListeners(props: AchManagerProps): Promise { if (props?.onStep) { this.addListener('onStep', (data) => { props.onStep?.(data); }); } if (props?.onInvalid) { this.addListener('onInvalid', (data) => { props.onInvalid?.(data); }); } if (props?.onError) { this.addListener('onError', (data) => { props.onError?.(data); }); } if (props?.onValid) { this.addListener('onValid', (data) => { props.onValid?.(data); }); } if (props?.onValidating) { this.addListener('onValidating', (data) => { props.onValidating?.(data); }); } if (props?.onValidationError) { this.addListener('onValidationError', (data) => { props.onValidationError?.(data); }); } } /////////////////////////////////////////// // HELPERS /////////////////////////////////////////// async addListener(eventType: EventType, listener: (...args: any[]) => any): Promise { return eventEmitter.addListener(eventType, listener); } removeListener(subscription: EmitterSubscription): void { return subscription.remove(); } removeAllListenersForEvent(eventType: EventType) { eventEmitter.removeAllListeners(eventType); } removeAllListeners() { eventTypes.forEach((eventType) => this.removeAllListenersForEvent(eventType)); } }