react-native-adapty
Version:
Adapty React Native SDK
185 lines • 6.85 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.OnboardingViewEmitter = void 0;
const bridge_1 = require("../bridge");
const onboarding_events_1 = require("../types/onboarding-events");
const logger_1 = require("../logger");
// Emitting view ID is passed in JSON["_view_id"]
// So that no all visible views would emit this event
// Must be in every callback response in the form of UUID string
// const KEY_VIEW = 'view_id';
/**
* OnboardingViewEmitter manages event handlers for onboarding view events.
* Each event type can have only one handler - new handlers replace existing ones.
*
* @remarks
* View emitter wraps NativeEventEmitter
* and provides several modifications:
* - Synthetic type restrictions to avoid misspelling
* - Safe data deserialization with SDK decoders
* - Logging emitting and deserialization processes
* - Filters out events for other views by _id
*
* @internal
*/
class OnboardingViewEmitter {
constructor(viewId) {
this.eventListeners = new Map();
this.handlers = new Map();
this.viewId = viewId;
}
addListener(event, callback, onRequestClose) {
const config = HANDLER_TO_EVENT_CONFIG[event];
if (!config) {
throw new Error(`No event config found for handler: ${event}`);
}
// Replace existing handler for this event type
this.handlers.set(event, {
handler: callback,
config,
onRequestClose,
});
if (!this.eventListeners.has(config.nativeEvent)) {
const subscription = bridge_1.$bridge.addEventListener(config.nativeEvent, this.createEventHandler(config));
this.eventListeners.set(config.nativeEvent, subscription);
}
return this.eventListeners.get(config.nativeEvent);
}
createEventHandler(config) {
return (parsedEvent) => {
const eventViewId = parsedEvent.view.id;
if (this.viewId !== eventViewId) {
return;
}
const ctx = new logger_1.LogContext();
const log = ctx.event({ methodName: config.nativeEvent });
log.start({ viewId: eventViewId, eventId: parsedEvent.id });
// Get all possible handler names for this native event
const possibleHandlers = NATIVE_EVENT_TO_HANDLERS[config.nativeEvent] || [];
let hasError = false;
for (const handlerName of possibleHandlers) {
const handlerData = this.handlers.get(handlerName);
if (!handlerData) {
continue; // Handler not registered for this view
}
const { handler, onRequestClose } = handlerData;
const callbackArgs = extractCallbackArgs(handlerName, parsedEvent);
const callback = handler;
let shouldClose = false;
try {
shouldClose = callback(...callbackArgs);
}
catch (error) {
hasError = true;
shouldClose = true;
log.failed({
error,
handlerName,
viewId: eventViewId,
eventId: parsedEvent.id,
reason: 'user_handler_failed',
});
}
if (shouldClose) {
onRequestClose().catch(error => {
log.failed({
error,
handlerName,
viewId: eventViewId,
eventId: parsedEvent.id,
reason: 'on_request_close_failed',
});
});
}
}
if (!hasError) {
log.success({ viewId: eventViewId, eventId: parsedEvent.id });
}
};
}
removeAllListeners() {
this.eventListeners.forEach(subscription => subscription.remove());
this.eventListeners.clear();
this.handlers.clear();
}
}
exports.OnboardingViewEmitter = OnboardingViewEmitter;
const ONBOARDING_EVENT_MAPPINGS = {
onboarding_on_close_action: [
{
handlerName: 'onClose',
},
],
onboarding_on_custom_action: [
{
handlerName: 'onCustom',
},
],
onboarding_on_paywall_action: [
{
handlerName: 'onPaywall',
},
],
onboarding_on_state_updated_action: [
{
handlerName: 'onStateUpdated',
},
],
onboarding_did_finish_loading: [
{
handlerName: 'onFinishedLoading',
},
],
onboarding_on_analytics_action: [
{
handlerName: 'onAnalytics',
},
],
onboarding_did_fail_with_error: [
{
handlerName: 'onError',
},
],
};
const HANDLER_TO_EVENT_CONFIG = Object.entries(ONBOARDING_EVENT_MAPPINGS).reduce((acc, [nativeEvent, mappings]) => {
mappings.forEach(({ handlerName }) => {
acc[handlerName] = {
nativeEvent,
handlerName,
};
});
return acc;
}, {});
// Reverse mapping: nativeEvent -> EventName[]
const NATIVE_EVENT_TO_HANDLERS = Object.entries(HANDLER_TO_EVENT_CONFIG).reduce((acc, [handlerName, config]) => {
if (!acc[config.nativeEvent]) {
acc[config.nativeEvent] = [];
}
const handlers = acc[config.nativeEvent];
if (handlers) {
handlers.push(handlerName);
}
return acc;
}, {});
function extractCallbackArgs(_handlerName, event) {
switch (event.id) {
case onboarding_events_1.OnboardingEventId.Close:
case onboarding_events_1.OnboardingEventId.Custom:
case onboarding_events_1.OnboardingEventId.Paywall:
return [event.actionId, event.meta];
case onboarding_events_1.OnboardingEventId.StateUpdated:
return [event.action, event.meta];
case onboarding_events_1.OnboardingEventId.FinishedLoading:
return [event.meta];
case onboarding_events_1.OnboardingEventId.Analytics:
return [
Object.assign(Object.assign({}, event.event), {
// Add backward compatibility: populate element_id from elementId
element_id: event.event.elementId }),
event.meta,
];
case onboarding_events_1.OnboardingEventId.Error:
return [event.error];
}
}
//# sourceMappingURL=onboarding-view-emitter.js.map