@tryheliumai/paywall-sdk-react-native 0.2.22 → 3.0.3
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/PaywallSdkReactNative.podspec +2 -2
- package/ios/HeliumSwiftInterface.swift +90 -76
- package/ios/RCTHeliumBridge.m +1 -0
- package/lib/commonjs/handlers/revenuecat.js +1 -1
- package/lib/commonjs/handlers/revenuecat.js.map +1 -1
- package/lib/commonjs/index.js +0 -18
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/native-interface.js +81 -165
- package/lib/commonjs/native-interface.js.map +1 -1
- package/lib/commonjs/types.js +4 -0
- package/lib/commonjs/types.js.map +1 -1
- package/lib/module/handlers/revenuecat.js +1 -1
- package/lib/module/handlers/revenuecat.js.map +1 -1
- package/lib/module/index.js +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/native-interface.js +81 -161
- package/lib/module/native-interface.js.map +1 -1
- package/lib/module/types.js +4 -0
- package/lib/module/types.js.map +1 -1
- package/lib/typescript/commonjs/src/handlers/revenuecat.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/index.d.ts +2 -2
- package/lib/typescript/commonjs/src/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/native-interface.d.ts +2 -21
- package/lib/typescript/commonjs/src/native-interface.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/types.d.ts +102 -3
- package/lib/typescript/commonjs/src/types.d.ts.map +1 -1
- package/lib/typescript/module/src/handlers/revenuecat.d.ts.map +1 -1
- package/lib/typescript/module/src/index.d.ts +2 -2
- package/lib/typescript/module/src/index.d.ts.map +1 -1
- package/lib/typescript/module/src/native-interface.d.ts +2 -21
- package/lib/typescript/module/src/native-interface.d.ts.map +1 -1
- package/lib/typescript/module/src/types.d.ts +102 -3
- package/lib/typescript/module/src/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/handlers/revenuecat.ts +0 -1
- package/src/index.ts +9 -3
- package/src/native-interface.tsx +105 -172
- package/src/types.ts +142 -5
package/src/native-interface.tsx
CHANGED
|
@@ -1,128 +1,42 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import {
|
|
2
|
+
NativeModules,
|
|
3
|
+
NativeEventEmitter,
|
|
4
|
+
requireNativeComponent,
|
|
5
|
+
} from 'react-native';
|
|
6
|
+
import type {
|
|
7
|
+
HeliumConfig,
|
|
8
|
+
HeliumUpsellViewProps,
|
|
9
|
+
HeliumDownloadStatus,
|
|
10
|
+
PaywallInfo,
|
|
11
|
+
PresentUpsellParams,
|
|
12
|
+
PaywallEventHandlers,
|
|
13
|
+
HeliumPaywallEvent,
|
|
14
|
+
} from './types';
|
|
4
15
|
|
|
5
16
|
const { HeliumBridge } = NativeModules;
|
|
6
17
|
const heliumEventEmitter = new NativeEventEmitter(HeliumBridge);
|
|
7
18
|
|
|
8
19
|
// Register the native component once at module level
|
|
9
|
-
|
|
10
|
-
|
|
20
|
+
export const NativeHeliumUpsellView =
|
|
21
|
+
requireNativeComponent<HeliumUpsellViewProps>('HeliumUpsellView');
|
|
11
22
|
|
|
12
|
-
let isProviderMounted = false;
|
|
13
23
|
// Add a flag to track if initialization has occurred
|
|
14
24
|
let isInitialized = false;
|
|
15
|
-
// Add a promise to track when the provider is mounted
|
|
16
|
-
let providerMountedPromise: Promise<void>;
|
|
17
|
-
let resolveProviderMounted: () => void;
|
|
18
|
-
|
|
19
|
-
// Initialize the promise
|
|
20
|
-
providerMountedPromise = new Promise<void>((resolve) => {
|
|
21
|
-
resolveProviderMounted = resolve;
|
|
22
|
-
// If provider is already mounted, resolve immediately
|
|
23
|
-
if (isProviderMounted) {
|
|
24
|
-
resolve();
|
|
25
|
-
}
|
|
26
|
-
});
|
|
27
|
-
|
|
28
25
|
// Add module-level download status tracking
|
|
29
26
|
let globalDownloadStatus: HeliumDownloadStatus = 'notStarted';
|
|
30
27
|
export const getDownloadStatus = () => globalDownloadStatus;
|
|
31
28
|
|
|
32
|
-
// Create a context for the download status
|
|
33
|
-
interface HeliumContextType {
|
|
34
|
-
downloadStatus: HeliumDownloadStatus;
|
|
35
|
-
setDownloadStatus: (status: HeliumDownloadStatus) => void;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const HeliumContext = createContext<HeliumContextType | undefined>(undefined);
|
|
39
|
-
|
|
40
|
-
// Update the setter ref to also update global status
|
|
41
|
-
let setDownloadStatusRef: ((status: HeliumDownloadStatus) => void) | null = null;
|
|
42
29
|
const updateDownloadStatus = (status: HeliumDownloadStatus) => {
|
|
43
30
|
globalDownloadStatus = status;
|
|
44
|
-
setDownloadStatusRef?.(status);
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
// Hook to use the Helium context
|
|
48
|
-
export const useHelium = () => {
|
|
49
|
-
const context = useContext(HeliumContext);
|
|
50
|
-
if (!context) {
|
|
51
|
-
throw new Error('useHelium must be used within a HeliumProvider');
|
|
52
|
-
}
|
|
53
|
-
return context;
|
|
54
31
|
};
|
|
55
32
|
|
|
56
|
-
interface HeliumProviderProps {
|
|
57
|
-
children: React.ReactNode;
|
|
58
|
-
fallbackView?: React.ComponentType;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// Create a ref to store the fallback view reference
|
|
62
|
-
const fallbackRef = createRef<View>();
|
|
63
|
-
// Store a reference to the fallback view component
|
|
64
|
-
let FallbackViewComponent: React.ComponentType | null = null;
|
|
65
|
-
|
|
66
|
-
// Provider component to be rendered at the app root
|
|
67
|
-
export const HeliumProvider = ({ children, fallbackView }: HeliumProviderProps) => {
|
|
68
|
-
// TODO - deprecate fallbackView (and maybe HeliumProvider too?)
|
|
69
|
-
if (fallbackView) {
|
|
70
|
-
console.warn('HeliumProvider: fallbackView is deprecated. Use onFallback passed to presentUpsell instead.');
|
|
71
|
-
}
|
|
72
|
-
const FallbackView = (() => null);
|
|
73
|
-
// Add state for download status
|
|
74
|
-
const [downloadStatus, setDownloadStatus] = useState<HeliumDownloadStatus>('notStarted');
|
|
75
|
-
|
|
76
|
-
// Store the setter in the ref so it can be accessed outside of components
|
|
77
|
-
useEffect(() => {
|
|
78
|
-
setDownloadStatusRef = setDownloadStatus;
|
|
79
|
-
// Store the fallback view component for later use
|
|
80
|
-
FallbackViewComponent = FallbackView;
|
|
81
|
-
}, [setDownloadStatus, FallbackView]);
|
|
82
|
-
|
|
83
|
-
useEffect(() => {
|
|
84
|
-
isProviderMounted = true;
|
|
85
|
-
// Resolve the promise when the provider is mounted
|
|
86
|
-
resolveProviderMounted();
|
|
87
|
-
return () => {
|
|
88
|
-
isProviderMounted = false;
|
|
89
|
-
setDownloadStatusRef = null;
|
|
90
|
-
};
|
|
91
|
-
}, []);
|
|
92
|
-
|
|
93
|
-
return (
|
|
94
|
-
<HeliumContext.Provider value={{ downloadStatus, setDownloadStatus }}>
|
|
95
|
-
<View
|
|
96
|
-
ref={fallbackRef}
|
|
97
|
-
collapsable={false}
|
|
98
|
-
style={{
|
|
99
|
-
display: 'none'
|
|
100
|
-
}}
|
|
101
|
-
>
|
|
102
|
-
<FallbackView />
|
|
103
|
-
</View>
|
|
104
|
-
{children}
|
|
105
|
-
</HeliumContext.Provider>
|
|
106
|
-
);
|
|
107
|
-
};
|
|
108
|
-
|
|
109
|
-
// Update initialize to accept full config
|
|
110
33
|
export const initialize = async (config: HeliumConfig) => {
|
|
111
34
|
// Early return if already initialized
|
|
112
35
|
if (isInitialized) {
|
|
36
|
+
console.log('[Helium] Already initialized, skipping...');
|
|
113
37
|
return;
|
|
114
38
|
}
|
|
115
39
|
|
|
116
|
-
// Wait for the provider to be mounted if it's not already
|
|
117
|
-
if (!isProviderMounted) {
|
|
118
|
-
await providerMountedPromise;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
const viewTag = findNodeHandle(fallbackRef.current);
|
|
122
|
-
if (!viewTag) {
|
|
123
|
-
throw new Error('Failed to get fallback view reference. Make sure HeliumProvider is mounted with a fallback view.');
|
|
124
|
-
}
|
|
125
|
-
|
|
126
40
|
const purchaseHandler = {
|
|
127
41
|
makePurchase: config.purchaseConfig.makePurchase,
|
|
128
42
|
restorePurchases: config.purchaseConfig.restorePurchases,
|
|
@@ -131,36 +45,36 @@ export const initialize = async (config: HeliumConfig) => {
|
|
|
131
45
|
// Update download status to inProgress
|
|
132
46
|
updateDownloadStatus('inProgress');
|
|
133
47
|
|
|
48
|
+
// Ensure these don't get added more than once
|
|
49
|
+
heliumEventEmitter.removeAllListeners('helium_paywall_event');
|
|
50
|
+
heliumEventEmitter.removeAllListeners('paywallEventHandlers');
|
|
51
|
+
heliumEventEmitter.removeAllListeners('helium_make_purchase');
|
|
52
|
+
heliumEventEmitter.removeAllListeners('helium_restore_purchases');
|
|
53
|
+
|
|
134
54
|
// Set up event listeners
|
|
135
55
|
heliumEventEmitter.addListener(
|
|
136
56
|
'helium_paywall_event',
|
|
137
|
-
(event:
|
|
57
|
+
(event: HeliumPaywallEvent) => {
|
|
138
58
|
// Handle download status events
|
|
139
59
|
if (event.type === 'paywallsDownloadSuccess') {
|
|
140
60
|
updateDownloadStatus('success');
|
|
141
61
|
} else if (event.type === 'paywallsDownloadError') {
|
|
142
62
|
updateDownloadStatus('failed');
|
|
143
63
|
}
|
|
144
|
-
// Handle fallback view visibility
|
|
145
|
-
else if (event.type === 'paywallOpen' && event.paywallTemplateName === 'Fallback') {
|
|
146
|
-
if (fallbackRef.current) {
|
|
147
|
-
fallbackRef.current.setNativeProps({
|
|
148
|
-
style: { display: 'flex' }
|
|
149
|
-
});
|
|
150
|
-
}
|
|
151
|
-
} else if (event.type === 'paywallClose' && event.paywallTemplateName === 'Fallback') {
|
|
152
|
-
if (fallbackRef.current) {
|
|
153
|
-
fallbackRef.current.setNativeProps({
|
|
154
|
-
style: { display: 'none' }
|
|
155
|
-
});
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
64
|
|
|
159
65
|
// Forward all events to the callback provided in config
|
|
160
66
|
config.onHeliumPaywallEvent(event);
|
|
161
67
|
}
|
|
162
68
|
);
|
|
163
69
|
|
|
70
|
+
// Set up paywall event handlers listener
|
|
71
|
+
heliumEventEmitter.addListener(
|
|
72
|
+
'paywallEventHandlers',
|
|
73
|
+
(event: HeliumPaywallEvent) => {
|
|
74
|
+
callPaywallEventHandlers(event);
|
|
75
|
+
}
|
|
76
|
+
);
|
|
77
|
+
|
|
164
78
|
// Set up purchase event listener using the determined handler
|
|
165
79
|
heliumEventEmitter.addListener(
|
|
166
80
|
'helium_make_purchase',
|
|
@@ -169,7 +83,7 @@ export const initialize = async (config: HeliumConfig) => {
|
|
|
169
83
|
HeliumBridge.handlePurchaseResponse({
|
|
170
84
|
transactionId: event.transactionId,
|
|
171
85
|
status: result.status,
|
|
172
|
-
error: result.error
|
|
86
|
+
error: result.error,
|
|
173
87
|
});
|
|
174
88
|
}
|
|
175
89
|
);
|
|
@@ -181,7 +95,7 @@ export const initialize = async (config: HeliumConfig) => {
|
|
|
181
95
|
const success = await purchaseHandler.restorePurchases();
|
|
182
96
|
HeliumBridge.handleRestoreResponse({
|
|
183
97
|
transactionId: event.transactionId,
|
|
184
|
-
status: success ? 'restored' : 'failed'
|
|
98
|
+
status: success ? 'restored' : 'failed',
|
|
185
99
|
});
|
|
186
100
|
}
|
|
187
101
|
);
|
|
@@ -212,30 +126,30 @@ export const initialize = async (config: HeliumConfig) => {
|
|
|
212
126
|
HeliumBridge.initialize(
|
|
213
127
|
{
|
|
214
128
|
apiKey: config.apiKey,
|
|
215
|
-
fallbackPaywall: viewTag,
|
|
216
|
-
triggers: config.triggers || [],
|
|
217
129
|
customUserId: config.customUserId || null,
|
|
218
130
|
customAPIEndpoint: config.customAPIEndpoint || null,
|
|
219
|
-
customUserTraits:
|
|
131
|
+
customUserTraits:
|
|
132
|
+
config.customUserTraits == null ? {} : config.customUserTraits,
|
|
220
133
|
revenueCatAppUserId: config.revenueCatAppUserId,
|
|
221
134
|
fallbackBundleUrlString: fallbackBundleUrlString,
|
|
222
135
|
fallbackBundleString: fallbackBundleString,
|
|
136
|
+
paywallLoadingConfig: config.paywallLoadingConfig,
|
|
223
137
|
},
|
|
224
138
|
{}
|
|
225
139
|
);
|
|
226
|
-
|
|
140
|
+
|
|
227
141
|
// Mark as initialized after successful initialization
|
|
228
142
|
isInitialized = true;
|
|
229
143
|
};
|
|
230
144
|
|
|
231
|
-
|
|
145
|
+
let paywallEventHandlers: PaywallEventHandlers | undefined;
|
|
146
|
+
let presentOnFallback: (() => void) | undefined;
|
|
232
147
|
export const presentUpsell = ({
|
|
233
148
|
triggerName,
|
|
234
149
|
onFallback,
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
}) => {
|
|
150
|
+
eventHandlers,
|
|
151
|
+
customPaywallTraits,
|
|
152
|
+
}: PresentUpsellParams) => {
|
|
239
153
|
HeliumBridge.canPresentUpsell(
|
|
240
154
|
triggerName,
|
|
241
155
|
(canPresent: boolean, reason: string) => {
|
|
@@ -249,9 +163,13 @@ export const presentUpsell = ({
|
|
|
249
163
|
}
|
|
250
164
|
|
|
251
165
|
try {
|
|
252
|
-
|
|
166
|
+
paywallEventHandlers = eventHandlers;
|
|
167
|
+
presentOnFallback = onFallback;
|
|
168
|
+
HeliumBridge.presentUpsell(triggerName, customPaywallTraits || null);
|
|
253
169
|
} catch (error) {
|
|
254
170
|
console.log('[Helium] Present error', error);
|
|
171
|
+
paywallEventHandlers = undefined;
|
|
172
|
+
presentOnFallback = undefined;
|
|
255
173
|
onFallback?.();
|
|
256
174
|
HeliumBridge.fallbackOpenOrCloseEvent(triggerName, true, 'presented');
|
|
257
175
|
}
|
|
@@ -259,6 +177,60 @@ export const presentUpsell = ({
|
|
|
259
177
|
);
|
|
260
178
|
};
|
|
261
179
|
|
|
180
|
+
function callPaywallEventHandlers(event: HeliumPaywallEvent) {
|
|
181
|
+
if (paywallEventHandlers) {
|
|
182
|
+
switch (event.type) {
|
|
183
|
+
case 'paywallOpen':
|
|
184
|
+
paywallEventHandlers?.onOpen?.({
|
|
185
|
+
type: 'paywallOpen',
|
|
186
|
+
triggerName: event.triggerName ?? 'unknown',
|
|
187
|
+
paywallName: event.paywallName ?? 'unknown',
|
|
188
|
+
isSecondTry: event.isSecondTry ?? false,
|
|
189
|
+
viewType: 'presented',
|
|
190
|
+
});
|
|
191
|
+
break;
|
|
192
|
+
case 'paywallClose':
|
|
193
|
+
paywallEventHandlers?.onClose?.({
|
|
194
|
+
type: 'paywallClose',
|
|
195
|
+
triggerName: event.triggerName ?? 'unknown',
|
|
196
|
+
paywallName: event.paywallName ?? 'unknown',
|
|
197
|
+
isSecondTry: event.isSecondTry ?? false,
|
|
198
|
+
});
|
|
199
|
+
if (!event.isSecondTry) {
|
|
200
|
+
paywallEventHandlers = undefined;
|
|
201
|
+
}
|
|
202
|
+
presentOnFallback = undefined;
|
|
203
|
+
break;
|
|
204
|
+
case 'paywallDismissed':
|
|
205
|
+
paywallEventHandlers?.onDismissed?.({
|
|
206
|
+
type: 'paywallDismissed',
|
|
207
|
+
triggerName: event.triggerName ?? 'unknown',
|
|
208
|
+
paywallName: event.paywallName ?? 'unknown',
|
|
209
|
+
isSecondTry: event.isSecondTry ?? false,
|
|
210
|
+
});
|
|
211
|
+
break;
|
|
212
|
+
case 'purchaseSucceeded':
|
|
213
|
+
paywallEventHandlers?.onPurchaseSucceeded?.({
|
|
214
|
+
type: 'purchaseSucceeded',
|
|
215
|
+
productId: event.productId ?? 'unknown',
|
|
216
|
+
triggerName: event.triggerName ?? 'unknown',
|
|
217
|
+
paywallName: event.paywallName ?? 'unknown',
|
|
218
|
+
isSecondTry: event.isSecondTry ?? false,
|
|
219
|
+
});
|
|
220
|
+
break;
|
|
221
|
+
case 'paywallSkipped':
|
|
222
|
+
paywallEventHandlers = undefined;
|
|
223
|
+
presentOnFallback = undefined;
|
|
224
|
+
break;
|
|
225
|
+
case 'paywallOpenFailed':
|
|
226
|
+
paywallEventHandlers = undefined;
|
|
227
|
+
presentOnFallback?.();
|
|
228
|
+
presentOnFallback = undefined;
|
|
229
|
+
break;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
262
234
|
export const hideUpsell = () => {
|
|
263
235
|
HeliumBridge.hideUpsell();
|
|
264
236
|
};
|
|
@@ -295,52 +267,13 @@ export const handleDeepLink = async (url: string | null): Promise<boolean> => {
|
|
|
295
267
|
console.log('[Helium] Handled deep link:', handled);
|
|
296
268
|
resolve(handled);
|
|
297
269
|
});
|
|
270
|
+
} else {
|
|
271
|
+
resolve(false);
|
|
298
272
|
}
|
|
299
273
|
});
|
|
300
274
|
};
|
|
301
275
|
|
|
302
|
-
// Update the UpsellView component to handle the style prop
|
|
303
|
-
export const UpsellView: React.FC<HeliumUpsellViewProps & {
|
|
304
|
-
fallbackViewProps?: Record<string, any>;
|
|
305
|
-
fallbackViewWrapperStyles?: Record<string, any>;
|
|
306
|
-
}> = ({ trigger, fallbackViewProps, fallbackViewWrapperStyles }) => {
|
|
307
|
-
const { downloadStatus } = useHelium();
|
|
308
|
-
|
|
309
|
-
const showFallback = downloadStatus === 'notStarted' ||
|
|
310
|
-
downloadStatus === 'inProgress' ||
|
|
311
|
-
downloadStatus === 'failed';
|
|
312
|
-
|
|
313
|
-
useEffect(() => {
|
|
314
|
-
if (showFallback && FallbackViewComponent) {
|
|
315
|
-
HeliumBridge.fallbackOpenOrCloseEvent(trigger, true, 'embedded');
|
|
316
|
-
}
|
|
317
|
-
return () => {
|
|
318
|
-
if (showFallback && FallbackViewComponent) {
|
|
319
|
-
HeliumBridge.fallbackOpenOrCloseEvent(trigger, false, 'embedded');
|
|
320
|
-
}
|
|
321
|
-
};
|
|
322
|
-
}, [showFallback, trigger]);
|
|
323
|
-
|
|
324
|
-
// If download status is notStarted or inProgress, we haven't fully initialized yet
|
|
325
|
-
// In this case, we should render the fallback view
|
|
326
|
-
if (showFallback) {
|
|
327
|
-
// If we have a fallback view component, render it
|
|
328
|
-
if (FallbackViewComponent) {
|
|
329
|
-
return (
|
|
330
|
-
<View style={fallbackViewWrapperStyles}>
|
|
331
|
-
<FallbackViewComponent {...fallbackViewProps} />
|
|
332
|
-
</View>
|
|
333
|
-
);
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
return null;
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
// Use NativeHeliumUpsellView directly
|
|
340
|
-
return <NativeHeliumUpsellView trigger={trigger} />;
|
|
341
|
-
};
|
|
342
|
-
|
|
343
276
|
export const HELIUM_CTA_NAMES = {
|
|
344
277
|
SCHEDULE_CALL: 'schedule_call',
|
|
345
278
|
SUBSCRIBE_BUTTON: 'subscribe_button',
|
|
346
|
-
}
|
|
279
|
+
};
|
package/src/types.ts
CHANGED
|
@@ -1,9 +1,18 @@
|
|
|
1
|
-
export type HeliumTransactionStatus =
|
|
1
|
+
export type HeliumTransactionStatus =
|
|
2
|
+
| 'purchased'
|
|
3
|
+
| 'failed'
|
|
4
|
+
| 'cancelled'
|
|
5
|
+
| 'pending'
|
|
6
|
+
| 'restored';
|
|
2
7
|
export type HeliumPurchaseResult = {
|
|
3
8
|
status: HeliumTransactionStatus;
|
|
4
9
|
error?: string; // Optional error message
|
|
5
10
|
};
|
|
6
|
-
export type HeliumDownloadStatus =
|
|
11
|
+
export type HeliumDownloadStatus =
|
|
12
|
+
| 'success'
|
|
13
|
+
| 'failed'
|
|
14
|
+
| 'inProgress'
|
|
15
|
+
| 'notStarted';
|
|
7
16
|
|
|
8
17
|
// --- Purchase Configuration Types ---
|
|
9
18
|
|
|
@@ -28,6 +37,133 @@ export function createCustomPurchaseConfig(callbacks: {
|
|
|
28
37
|
};
|
|
29
38
|
}
|
|
30
39
|
|
|
40
|
+
export type TriggerLoadingConfig = {
|
|
41
|
+
/** Whether to show loading state for this trigger. Set to nil to use the global `useLoadingState` setting. */
|
|
42
|
+
useLoadingState?: boolean;
|
|
43
|
+
/** Maximum seconds to show loading for this trigger. Set to nil to use the global `loadingBudget` setting. */
|
|
44
|
+
loadingBudget?: number;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export type HeliumPaywallLoadingConfig = {
|
|
48
|
+
/**
|
|
49
|
+
* Whether to show a loading state while fetching paywall configuration.
|
|
50
|
+
* When true, shows a loading view for up to `loadingBudget` seconds before falling back.
|
|
51
|
+
* Default: true
|
|
52
|
+
*/
|
|
53
|
+
useLoadingState?: boolean;
|
|
54
|
+
/**
|
|
55
|
+
* Maximum time (in seconds) to show the loading state before displaying fallback.
|
|
56
|
+
* After this timeout, the fallback view will be shown even if the paywall is still downloading.
|
|
57
|
+
* Default: 2.0 seconds
|
|
58
|
+
*/
|
|
59
|
+
loadingBudget?: number;
|
|
60
|
+
/**
|
|
61
|
+
* Optional per-trigger loading configuration overrides.
|
|
62
|
+
* Use this to customize loading behavior for specific triggers.
|
|
63
|
+
* Keys are trigger names, values are TriggerLoadingConfig instances.
|
|
64
|
+
* Example: Disable loading for "onboarding" trigger while keeping it for others.
|
|
65
|
+
*/
|
|
66
|
+
perTriggerLoadingConfig?: Record<string, TriggerLoadingConfig>;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
// Event handler types for per-presentation event handling
|
|
70
|
+
export interface PaywallEventHandlers {
|
|
71
|
+
onOpen?: (event: PaywallOpenEvent) => void;
|
|
72
|
+
onClose?: (event: PaywallCloseEvent) => void;
|
|
73
|
+
onDismissed?: (event: PaywallDismissedEvent) => void;
|
|
74
|
+
onPurchaseSucceeded?: (event: PurchaseSucceededEvent) => void;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Typed event interfaces
|
|
78
|
+
export interface PaywallOpenEvent {
|
|
79
|
+
type: 'paywallOpen';
|
|
80
|
+
triggerName: string;
|
|
81
|
+
paywallName: string;
|
|
82
|
+
isSecondTry: boolean;
|
|
83
|
+
viewType?: 'presented' | 'embedded' | 'triggered';
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export interface PaywallCloseEvent {
|
|
87
|
+
type: 'paywallClose';
|
|
88
|
+
triggerName: string;
|
|
89
|
+
paywallName: string;
|
|
90
|
+
isSecondTry: boolean;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export interface PaywallDismissedEvent {
|
|
94
|
+
type: 'paywallDismissed';
|
|
95
|
+
triggerName: string;
|
|
96
|
+
paywallName: string;
|
|
97
|
+
isSecondTry: boolean;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export interface PurchaseSucceededEvent {
|
|
101
|
+
type: 'purchaseSucceeded';
|
|
102
|
+
productId: string;
|
|
103
|
+
triggerName: string;
|
|
104
|
+
paywallName: string;
|
|
105
|
+
isSecondTry: boolean;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export type HeliumPaywallEvent = {
|
|
109
|
+
type:
|
|
110
|
+
| 'paywallOpen'
|
|
111
|
+
| 'paywallClose'
|
|
112
|
+
| 'paywallDismissed'
|
|
113
|
+
| 'paywallOpenFailed'
|
|
114
|
+
| 'paywallSkipped'
|
|
115
|
+
| 'paywallButtonPressed'
|
|
116
|
+
| 'productSelected'
|
|
117
|
+
| 'purchasePressed'
|
|
118
|
+
| 'purchaseSucceeded'
|
|
119
|
+
| 'purchaseCancelled'
|
|
120
|
+
| 'purchaseFailed'
|
|
121
|
+
| 'purchaseRestored'
|
|
122
|
+
| 'purchaseRestoreFailed'
|
|
123
|
+
| 'purchasePending'
|
|
124
|
+
| 'initializeStart'
|
|
125
|
+
| 'paywallsDownloadSuccess'
|
|
126
|
+
| 'paywallsDownloadError'
|
|
127
|
+
| 'paywallWebViewRendered';
|
|
128
|
+
triggerName?: string;
|
|
129
|
+
paywallName?: string;
|
|
130
|
+
/**
|
|
131
|
+
* @deprecated Use `paywallName` instead.
|
|
132
|
+
*/
|
|
133
|
+
paywallTemplateName?: string;
|
|
134
|
+
productId?: string;
|
|
135
|
+
/**
|
|
136
|
+
* @deprecated Use `productId` instead.
|
|
137
|
+
*/
|
|
138
|
+
productKey?: string;
|
|
139
|
+
ctaName?: string;
|
|
140
|
+
paywallDownloadTimeTakenMS?: number;
|
|
141
|
+
templateDownloadTimeTakenMS?: number;
|
|
142
|
+
imagesDownloadTimeTakenMS?: number;
|
|
143
|
+
stylesDownloadTimeTakenMS?: number;
|
|
144
|
+
fontsDownloadTimeTakenMS?: number;
|
|
145
|
+
bundleDownloadTimeMS?: number;
|
|
146
|
+
dismissAll?: boolean;
|
|
147
|
+
isSecondTry?: boolean;
|
|
148
|
+
error?: string;
|
|
149
|
+
/**
|
|
150
|
+
* @deprecated Use `error` instead.
|
|
151
|
+
*/
|
|
152
|
+
errorDescription?: string;
|
|
153
|
+
/**
|
|
154
|
+
* Unix timestamp in seconds
|
|
155
|
+
*/
|
|
156
|
+
timestamp?: number;
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
export type PresentUpsellParams = {
|
|
160
|
+
triggerName: string;
|
|
161
|
+
/** Optional. This will be called when paywall fails to show due to an unsuccessful paywall download or if an invalid trigger is provided. */
|
|
162
|
+
onFallback?: () => void;
|
|
163
|
+
eventHandlers?: PaywallEventHandlers;
|
|
164
|
+
customPaywallTraits?: Record<string, any>;
|
|
165
|
+
};
|
|
166
|
+
|
|
31
167
|
// --- Main Helium Configuration ---
|
|
32
168
|
export interface HeliumConfig {
|
|
33
169
|
/** Your Helium API Key */
|
|
@@ -35,12 +171,13 @@ export interface HeliumConfig {
|
|
|
35
171
|
/** Configuration for handling purchases. Can be custom functions or a pre-built handler config. */
|
|
36
172
|
purchaseConfig: HeliumPurchaseConfig;
|
|
37
173
|
/** Callback for receiving all Helium paywall events. */
|
|
38
|
-
onHeliumPaywallEvent: (event:
|
|
174
|
+
onHeliumPaywallEvent: (event: HeliumPaywallEvent) => void;
|
|
39
175
|
|
|
40
176
|
// Optional configurations
|
|
41
|
-
|
|
177
|
+
/** Fallback bundle in the rare situation that paywall is not ready to be shown. Highly recommended. See docs at https://docs.tryhelium.com/guides/fallback-bundle#react-native */
|
|
42
178
|
fallbackBundle?: object;
|
|
43
|
-
|
|
179
|
+
/** Configure loading behavior for paywalls that are mid-download. */
|
|
180
|
+
paywallLoadingConfig?: HeliumPaywallLoadingConfig;
|
|
44
181
|
customUserId?: string;
|
|
45
182
|
customAPIEndpoint?: string;
|
|
46
183
|
customUserTraits?: Record<string, any>;
|