UNPKG

react-native-nami-sdk

Version:

React Native SDK for Nami - No-code paywall and onboarding flows with A/B testing.

101 lines (85 loc) 3.22 kB
import { TurboModuleRegistry, NativeModules, NativeEventEmitter, } from 'react-native'; import type { Spec } from '../specs/NativeNamiFlowManager'; import type { NamiFlowHandoffPayload, NamiFlowHandoffStepHandler, NamiHandoffComplete, NamiHandoffOutcome, } from './types'; const RNNamiFlowManager: Spec = TurboModuleRegistry.getEnforcing?.<Spec>('RNNamiFlowManager') ?? NativeModules.RNNamiFlowManager; const emitter = new NativeEventEmitter(NativeModules.RNNamiFlowManager); export enum NamiFlowManagerEvents { Handoff = 'Handoff', FlowEvent = 'FlowEvent', } export const NamiFlowManager = { emitter, registerStepHandoff: (callback: NamiFlowHandoffStepHandler): (() => void) => { console.info('[NamiFlowManager] Registering step handoff listener...'); const sub = emitter.addListener( NamiFlowManagerEvents.Handoff, (event: NamiFlowHandoffPayload) => { console.info('[NamiFlowManager] Received handoff event:', event); // Manufacture the per-handoff completion callback. The native event // carries a `handoffId` that correlates this call back to the native // pending handoff (TurboModule callbacks can't hold per-call closures). let completed = false; const complete: NamiHandoffComplete = ( outcome?: NamiHandoffOutcome, ) => { if (completed) { console.warn( `[NamiFlowManager] complete() called more than once for handoff '${event.handoffTag}' — ignored`, ); return; } completed = true; // The ONE bridge-side defaulting point: bare complete() ≙ done. // `outcome` stays required on the wire (native never sees a null). const normalized: NamiHandoffOutcome = outcome ?? { kind: 'done' }; RNNamiFlowManager.completeHandoff?.(event.handoffId, normalized); }; // Single handler shape `(tag, data, complete)`. Legacy `(tag, data)` // handlers still run — the extra arg is ignored — and their `resume()` // degrades to done-with-warning natively (the native pending token owns // that, surviving Metro fast-refresh wiping this closure). callback(event.handoffTag, event.handoffData, complete); }, ); RNNamiFlowManager.registerStepHandoff?.(); return () => { sub.remove(); RNNamiFlowManager.unregisterStepHandoff?.(); }; }, resume: (): void => { console.info('[NamiFlowManager] resume from handoff requested'); RNNamiFlowManager.resume?.(); }, pause: (): void => { console.info('[NamiFlowManager] pause from handoff requested'); RNNamiFlowManager.pause(); }, registerEventHandler: ( callback: (payload: Record<string, unknown>) => void, ): (() => void) => { const sub = emitter.addListener(NamiFlowManagerEvents.FlowEvent, callback); RNNamiFlowManager.registerEventHandler?.(); return () => { sub.remove(); RNNamiFlowManager.unregisterEventHandler?.(); }; }, finish: (): void => { RNNamiFlowManager.finish(); }, isFlowOpen: async (): Promise<boolean> => { return RNNamiFlowManager.isFlowOpen(); }, };