import React, { useRef } from 'react'; import type WebView from 'react-native-webview'; import { RequestRefreshEvent, UnitComponentsMessage, } from '../../messages/webMessages/unitComponentsMessages'; import { WebComponent } from '../../webComponent/WebComponent'; import type { WebViewMessage } from '../../messages/webMessages'; import { PresentationMode, WebComponentType } from '../../types/internal/webComponent.types'; import { withReduxStore } from '../../helpers/store/helpers'; import { UNConnectedAccount, UNCounterparty, UNComponentsError, UNComponentsOnLoadResponse, UNPayeeManagementComponentPaginationType, UNPayeeManagementMenuItem, UNPlaidAccountFilter } from '../../types/shared'; import { getPayeeParams, getPayeeManagementScript, injectRefreshEventIfNeeded, injectUnitPlaidResponse, injectUnitOpenPlaid, injectUnitPlaidExit } from './UNPayeeManagementComponent.utils'; import { BottomSheetRenderingType, BottomSheetSlotData, SlotRendering } from '../../types/internal/bottomSheet.types'; import { RequestRenderingEvent } from '../../messages/webMessages/unitComponentsMessages'; import { eventBus } from '../../utils/eventBus'; import { BottomSheetNativeMessage } from '../../messages/nativeMessages/bottomSheetMessage'; import { useEventListener } from '../../hooks/useEventListener'; import { LinkExit, LinkSuccess, open as openPlaidLink, create as createPlaidLink } from 'react-native-plaid-link-sdk'; import { OpenPlaidEvent, PlaidMessage } from '../../messages/webMessages/plaidMessages'; import { PayeeConnectedAccountEvent, PayeeCounterpartyEvent, PayeeManagementMessage, PayeeMicroDepositeConnectionEvent } from '../../messages/webMessages/payeeManagementMessage'; import { UNBaseView } from '../../nativeComponents/UNBaseView'; import { RESPONSE_KEYS, UnitOnLoadResponseEvent } from '../../messages/webMessages/onLoadMessage'; export interface UNPayeeManagementComponentProps { // inputs menuItems?: UNPayeeManagementMenuItem[]; queryFilter?: string; paginationType?: UNPayeeManagementComponentPaginationType; counterPartiesPerPage?: number; // ui theme?: string; language?: string; hideTitle?: boolean; hideCounterpartyActionsButton?: boolean; showAccountTypeSelector?: boolean; menuPlaceholder?: string; flowPlaceholder?: string; payeeCreationPlaceholder?: string; microDepositConnectionPlaceholder?: string; plaidAccountFilters?: UNPlaidAccountFilter[]; plaidLinkCustomizationName?: string; // events onLoad?: (response: UNComponentsOnLoadResponse<[UNCounterparty]>) => void; onCounterpartyCreated?: (counterparty: UNCounterparty) => void; onCounterpartyDeleted?: (counterparty: UNCounterparty) => void; onConnectedAccountCreated?: (connectedAccount: UNConnectedAccount) => void; onMicroDepositConnectionCreated?: (onnectedAccount: UNCounterparty) => void; onMicroDepositConnectionRejected?: (connectedAccount: UNConnectedAccount) => void; } const UNPayeeManagementComponent = (props: UNPayeeManagementComponentProps) => { const webRef = useRef(null); const requestRefresh = (data: RequestRefreshEvent) => { injectRefreshEventIfNeeded(webRef.current, data); }; const openPlaid = (openPlaidData: OpenPlaidEvent) => { injectUnitOpenPlaid(webRef.current, openPlaidData); const linkToken = openPlaidData.plaidLinkToken.attributes.linkToken; createPlaidLink({ token: linkToken }); openPlaidLink({ onSuccess: (success: LinkSuccess) => { injectUnitPlaidResponse(webRef.current, success); }, onExit: (exit: LinkExit) => { injectUnitPlaidExit(webRef.current, exit.error); } }); }; const reportCounterpartyDeleted = (counterparty: UNCounterparty) => { props.onCounterpartyDeleted && props.onCounterpartyDeleted(counterparty); }; useEventListener({ busEventKey: UnitComponentsMessage.UNIT_REQUEST_REFRESH, action: requestRefresh }); useEventListener({ busEventKey: PlaidMessage.UNIT_OPEN_PLAID, action: openPlaid }); useEventListener({ busEventKey: PayeeManagementMessage.UNIT_COUNTERPARTY_DELETED, action: reportCounterpartyDeleted }); const handleRequestRendering = (requestRenderingEvent : RequestRenderingEvent) => { switch (requestRenderingEvent.data.nativeComponentName) { default: { const slotData: BottomSheetSlotData = { componentName: requestRenderingEvent.data.nativeComponentName, requestRenderingEvent: requestRenderingEvent, }; const data = { type: BottomSheetRenderingType.Slot, data: slotData, } as SlotRendering; eventBus.emit(BottomSheetNativeMessage.REQUEST_RENDERING, data); } } }; const handleUnitOnLoad = (response: UnitOnLoadResponseEvent) => { if (!props.onLoad) { return; } if (RESPONSE_KEYS.errors in response) { props.onLoad(response as UNComponentsError); return; } if (RESPONSE_KEYS.counterpartiesResult in response) { props.onLoad(response[RESPONSE_KEYS.counterpartiesResult] as UNComponentsOnLoadResponse<[UNCounterparty]>); return; } console.error('On Load Error: unexpected response type'); return; }; const handleMessage = (message: WebViewMessage) => { switch (message.type) { case UnitComponentsMessage.UNIT_REQUEST_RENDERING: { const requestRenderingEvent = message.details as RequestRenderingEvent; handleRequestRendering(requestRenderingEvent); break; } case UnitComponentsMessage.UNIT_ON_LOAD: { handleUnitOnLoad(message.details as UnitOnLoadResponseEvent); break; } case PayeeManagementMessage.UNIT_CONNECTED_ACCOUNT_CREATED: { const account: UNConnectedAccount = (message.details as PayeeConnectedAccountEvent).account; props.onConnectedAccountCreated && props.onConnectedAccountCreated(account); break; } case PayeeManagementMessage.UNIT_COUNTERPARTY_CREATED: { const counterparty: UNCounterparty = (message.details as PayeeCounterpartyEvent).counterparty; props.onCounterpartyCreated && props.onCounterpartyCreated(counterparty); break; } case PayeeManagementMessage.UNIT_MICRO_DEPOSIT_CONNECTION_CREATED: { const counterparty: UNCounterparty = (message.details as PayeeMicroDepositeConnectionEvent).account; props.onMicroDepositConnectionCreated && props.onMicroDepositConnectionCreated(counterparty); break; } case PayeeManagementMessage.UNIT_MICRO_DEPOSIT_CONNECTION_REJECTED: { const account: UNConnectedAccount = (message.details as PayeeConnectedAccountEvent).account; props.onMicroDepositConnectionRejected && props.onMicroDepositConnectionRejected(account); break; } } }; return ( }> handleMessage(message)} /> ); }; export default withReduxStore(UNPayeeManagementComponent);