react-native-purchases-ui 8.11.9 → 9.0.0

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/src/index.tsx CHANGED
@@ -19,12 +19,13 @@ import {
19
19
  import React, { type ReactNode, useEffect, useState } from "react";
20
20
  import { shouldUsePreviewAPIMode } from "./utils/environment";
21
21
  import { previewNativeModuleRNCustomerCenter, previewNativeModuleRNPaywalls } from "./preview/nativeModules";
22
+ import { PreviewPaywall } from "./preview/previewComponents";
22
23
 
23
24
  export { PAYWALL_RESULT } from "@revenuecat/purchases-typescript-internal";
24
25
 
25
26
  const LINKING_ERROR =
26
27
  `The package 'react-native-purchases-ui' doesn't seem to be linked. Make sure: \n\n` +
27
- Platform.select({ios: "- You have run 'pod install'\n", default: ''}) +
28
+ '- You have run \'pod install\'\n' +
28
29
  '- You rebuilt the app after installing the package\n';
29
30
 
30
31
 
@@ -42,21 +43,118 @@ if (!RNCustomerCenter) {
42
43
  throw new Error(LINKING_ERROR);
43
44
  }
44
45
 
45
- const eventEmitter = new NativeEventEmitter(RNPaywalls);
46
- const customerCenterEventEmitter = new NativeEventEmitter(RNCustomerCenter);
46
+ const NativePaywall = !usingPreviewAPIMode && UIManager.getViewManagerConfig('Paywall') != null
47
+ ? requireNativeComponent<FullScreenPaywallViewProps>('Paywall')
48
+ : null;
47
49
 
48
- const InternalPaywall =
49
- UIManager.getViewManagerConfig('Paywall') != null
50
- ? requireNativeComponent<FullScreenPaywallViewProps>('Paywall')
51
- : () => {
52
- throw new Error(LINKING_ERROR);
53
- };
54
-
55
- const InternalPaywallFooterView = UIManager.getViewManagerConfig('Paywall') != null
50
+ const NativePaywallFooter = !usingPreviewAPIMode && UIManager.getViewManagerConfig('Paywall') != null
56
51
  ? requireNativeComponent<InternalFooterPaywallViewProps>('RCPaywallFooterView')
57
- : () => {
58
- throw new Error(LINKING_ERROR);
59
- };
52
+ : null;
53
+
54
+ const eventEmitter = usingPreviewAPIMode ? null : new NativeEventEmitter(RNPaywalls);
55
+ const customerCenterEventEmitter = usingPreviewAPIMode ? null : new NativeEventEmitter(RNCustomerCenter);
56
+
57
+ const InternalPaywall: React.FC<FullScreenPaywallViewProps> = ({
58
+ style,
59
+ children,
60
+ options,
61
+ onPurchaseStarted,
62
+ onPurchaseCompleted,
63
+ onPurchaseError,
64
+ onPurchaseCancelled,
65
+ onRestoreStarted,
66
+ onRestoreCompleted,
67
+ onRestoreError,
68
+ onDismiss,
69
+ }) => {
70
+ if (usingPreviewAPIMode) {
71
+ return (
72
+ <PreviewPaywall
73
+ offering={options?.offering}
74
+ displayCloseButton={options?.displayCloseButton}
75
+ fontFamily={options?.fontFamily}
76
+ onPurchaseStarted={onPurchaseStarted}
77
+ onPurchaseCompleted={onPurchaseCompleted}
78
+ onPurchaseError={onPurchaseError}
79
+ onPurchaseCancelled={onPurchaseCancelled}
80
+ onRestoreStarted={onRestoreStarted}
81
+ onRestoreCompleted={onRestoreCompleted}
82
+ onRestoreError={onRestoreError}
83
+ onDismiss={onDismiss}
84
+ />
85
+ );
86
+ } else if (!!NativePaywall) {
87
+ return (
88
+ <NativePaywall
89
+ style={style}
90
+ children={children}
91
+ options={options}
92
+ onPurchaseStarted={(event: any) => onPurchaseStarted && onPurchaseStarted(event.nativeEvent)}
93
+ onPurchaseCompleted={(event: any) => onPurchaseCompleted && onPurchaseCompleted(event.nativeEvent)}
94
+ onPurchaseError={(event: any) => onPurchaseError && onPurchaseError(event.nativeEvent)}
95
+ onPurchaseCancelled={() => onPurchaseCancelled && onPurchaseCancelled()}
96
+ onRestoreStarted={() => onRestoreStarted && onRestoreStarted()}
97
+ onRestoreCompleted={(event: any) => onRestoreCompleted && onRestoreCompleted(event.nativeEvent)}
98
+ onRestoreError={(event: any) => onRestoreError && onRestoreError(event.nativeEvent)}
99
+ onDismiss={() => onDismiss && onDismiss()}
100
+ />
101
+ );
102
+ }
103
+
104
+ throw new Error(LINKING_ERROR);
105
+ };
106
+
107
+ const InternalPaywallFooterView: React.FC<InternalFooterPaywallViewProps> = ({
108
+ style,
109
+ children,
110
+ options,
111
+ onPurchaseStarted,
112
+ onPurchaseCompleted,
113
+ onPurchaseError,
114
+ onPurchaseCancelled,
115
+ onRestoreStarted,
116
+ onRestoreCompleted,
117
+ onRestoreError,
118
+ onDismiss,
119
+ onMeasure,
120
+ }) => {
121
+ if (usingPreviewAPIMode) {
122
+ return (
123
+ <PreviewPaywall
124
+ offering={options?.offering}
125
+ displayCloseButton={true}
126
+ fontFamily={options?.fontFamily}
127
+ onPurchaseStarted={onPurchaseStarted}
128
+ onPurchaseCompleted={onPurchaseCompleted}
129
+ onPurchaseError={onPurchaseError}
130
+ onPurchaseCancelled={onPurchaseCancelled}
131
+ onRestoreStarted={onRestoreStarted}
132
+ onRestoreCompleted={onRestoreCompleted}
133
+ onRestoreError={onRestoreError}
134
+ onDismiss={onDismiss}
135
+ />
136
+ );
137
+ } else if (!!NativePaywallFooter) {
138
+ return (
139
+ <NativePaywallFooter
140
+ style={style}
141
+ children={children}
142
+ options={options}
143
+ onPurchaseStarted={(event: any) => onPurchaseStarted && onPurchaseStarted(event.nativeEvent)}
144
+ onPurchaseCompleted={(event: any) => onPurchaseCompleted && onPurchaseCompleted(event.nativeEvent)}
145
+ onPurchaseError={(event: any) => onPurchaseError && onPurchaseError(event.nativeEvent)}
146
+ onPurchaseCancelled={() => onPurchaseCancelled && onPurchaseCancelled()}
147
+ onRestoreStarted={() => onRestoreStarted && onRestoreStarted()}
148
+ onRestoreCompleted={(event: any) => onRestoreCompleted && onRestoreCompleted(event.nativeEvent)}
149
+ onRestoreError={(event: any) => onRestoreError && onRestoreError(event.nativeEvent)}
150
+ onDismiss={() => onDismiss && onDismiss()}
151
+ onMeasure={onMeasure}
152
+ />
153
+ );
154
+ }
155
+
156
+ throw new Error(LINKING_ERROR);
157
+ };
60
158
 
61
159
  export interface PresentPaywallParams {
62
160
  /**
@@ -162,7 +260,7 @@ type InternalFooterPaywallViewProps = FooterPaywallViewProps & {
162
260
  onMeasure?: ({height}: { height: number }) => void;
163
261
  };
164
262
 
165
- export type CustomerCenterManagementOption =
263
+ export type CustomerCenterManagementOption =
166
264
  | 'cancel'
167
265
  | 'custom_url'
168
266
  | 'missing_purchase'
@@ -171,7 +269,7 @@ export type CustomerCenterManagementOption =
171
269
  | 'unknown'
172
270
  | string; // This is to prevent breaking changes when the native SDK adds new options
173
271
 
174
- export type CustomerCenterManagementOptionEvent =
272
+ export type CustomerCenterManagementOptionEvent =
175
273
  | { option: 'custom_url'; url: string }
176
274
  | { option: Exclude<CustomerCenterManagementOption, 'custom_url'>; url: null };
177
275
 
@@ -180,22 +278,22 @@ export interface CustomerCenterCallbacks {
180
278
  * Called when a feedback survey is completed with the selected option ID.
181
279
  */
182
280
  onFeedbackSurveyCompleted?: ({feedbackSurveyOptionId}: { feedbackSurveyOptionId: string }) => void;
183
-
281
+
184
282
  /**
185
283
  * Called when the manage subscriptions section is being shown.
186
284
  */
187
285
  onShowingManageSubscriptions?: () => void;
188
-
286
+
189
287
  /**
190
288
  * Called when a restore operation is completed successfully.
191
289
  */
192
290
  onRestoreCompleted?: ({customerInfo}: { customerInfo: CustomerInfo }) => void;
193
-
291
+
194
292
  /**
195
293
  * Called when a restore operation fails.
196
294
  */
197
295
  onRestoreFailed?: ({error}: { error: PurchasesError }) => void;
198
-
296
+
199
297
  /**
200
298
  * Called when a restore operation starts.
201
299
  */
@@ -205,7 +303,7 @@ export interface CustomerCenterCallbacks {
205
303
  * Called when a refund request starts with the product identifier. iOS-only callback.
206
304
  */
207
305
  onRefundRequestStarted?: ({productIdentifier}: { productIdentifier: string }) => void;
208
-
306
+
209
307
  /**
210
308
  * Called when a refund request completes with status information. iOS-only callback.
211
309
  */
@@ -254,7 +352,7 @@ export default class RevenueCatUI {
254
352
  displayCloseButton = RevenueCatUI.Defaults.PRESENT_PAYWALL_DISPLAY_CLOSE_BUTTON,
255
353
  fontFamily,
256
354
  }: PresentPaywallParams = {}): Promise<PAYWALL_RESULT> {
257
- RevenueCatUI.logWarningIfPreviewAPIMode("presentPaywall");
355
+ RevenueCatUI.logWarningIfPreviewAPIMode("presentPaywall");
258
356
  return RNPaywalls.presentPaywall(
259
357
  offering?.identifier ?? null,
260
358
  displayCloseButton,
@@ -281,7 +379,7 @@ export default class RevenueCatUI {
281
379
  displayCloseButton = RevenueCatUI.Defaults.PRESENT_PAYWALL_DISPLAY_CLOSE_BUTTON,
282
380
  fontFamily,
283
381
  }: PresentPaywallIfNeededParams): Promise<PAYWALL_RESULT> {
284
- RevenueCatUI.logWarningIfPreviewAPIMode("presentPaywallIfNeeded");
382
+ RevenueCatUI.logWarningIfPreviewAPIMode("presentPaywallIfNeeded");
285
383
  return RNPaywalls.presentPaywallIfNeeded(
286
384
  requiredEntitlementIdentifier,
287
385
  offering?.identifier ?? null,
@@ -302,19 +400,23 @@ export default class RevenueCatUI {
302
400
  onRestoreCompleted,
303
401
  onRestoreError,
304
402
  onDismiss,
305
- }) => (
306
- <InternalPaywall options={options}
307
- children={children}
308
- onPurchaseStarted={(event: any) => onPurchaseStarted && onPurchaseStarted(event.nativeEvent)}
309
- onPurchaseCompleted={(event: any) => onPurchaseCompleted && onPurchaseCompleted(event.nativeEvent)}
310
- onPurchaseError={(event: any) => onPurchaseError && onPurchaseError(event.nativeEvent)}
311
- onPurchaseCancelled={() => onPurchaseCancelled && onPurchaseCancelled()}
312
- onRestoreStarted={() => onRestoreStarted && onRestoreStarted()}
313
- onRestoreCompleted={(event: any) => onRestoreCompleted && onRestoreCompleted(event.nativeEvent)}
314
- onRestoreError={(event: any) => onRestoreError && onRestoreError(event.nativeEvent)}
315
- onDismiss={() => onDismiss && onDismiss()}
316
- style={[{flex: 1}, style]}/>
317
- );
403
+ }) => {
404
+ return (
405
+ <InternalPaywall
406
+ options={options}
407
+ children={children}
408
+ onPurchaseStarted={onPurchaseStarted}
409
+ onPurchaseCompleted={onPurchaseCompleted}
410
+ onPurchaseError={onPurchaseError}
411
+ onPurchaseCancelled={onPurchaseCancelled}
412
+ onRestoreStarted={onRestoreStarted}
413
+ onRestoreCompleted={onRestoreCompleted}
414
+ onRestoreError={onRestoreError}
415
+ onDismiss={onDismiss}
416
+ style={[{flex: 1}, style]}
417
+ />
418
+ );
419
+ };
318
420
 
319
421
  public static OriginalTemplatePaywallFooterContainerView: React.FC<FooterPaywallViewProps> = ({
320
422
  style,
@@ -345,13 +447,13 @@ export default class RevenueCatUI {
345
447
  setPaddingBottom(20 + bottom);
346
448
  };
347
449
 
348
- const subscription = eventEmitter.addListener(
450
+ const subscription = eventEmitter?.addListener(
349
451
  'safeAreaInsetsDidChange',
350
452
  handleSafeAreaInsetsChange
351
453
  );
352
454
 
353
455
  return () => {
354
- subscription.remove();
456
+ subscription?.remove();
355
457
  };
356
458
  }, []);
357
459
 
@@ -367,14 +469,14 @@ export default class RevenueCatUI {
367
469
  android: {marginTop: -20, height}
368
470
  })}
369
471
  options={options}
370
- onPurchaseStarted={(event: any) => onPurchaseStarted && onPurchaseStarted(event.nativeEvent)}
371
- onPurchaseCompleted={(event: any) => onPurchaseCompleted && onPurchaseCompleted(event.nativeEvent)}
372
- onPurchaseError={(event: any) => onPurchaseError && onPurchaseError(event.nativeEvent)}
373
- onPurchaseCancelled={() => onPurchaseCancelled && onPurchaseCancelled()}
374
- onRestoreStarted={() => onRestoreStarted && onRestoreStarted()}
375
- onRestoreCompleted={(event: any) => onRestoreCompleted && onRestoreCompleted(event.nativeEvent)}
376
- onRestoreError={(event: any) => onRestoreError && onRestoreError(event.nativeEvent)}
377
- onDismiss={() => onDismiss && onDismiss()}
472
+ onPurchaseStarted={onPurchaseStarted}
473
+ onPurchaseCompleted={onPurchaseCompleted}
474
+ onPurchaseError={onPurchaseError}
475
+ onPurchaseCancelled={onPurchaseCancelled}
476
+ onRestoreStarted={onRestoreStarted}
477
+ onRestoreCompleted={onRestoreCompleted}
478
+ onRestoreError={onRestoreError}
479
+ onDismiss={onDismiss}
378
480
  onMeasure={(event: any) => setHeight(event.nativeEvent.measurements.height)}
379
481
  />
380
482
  </View>
@@ -383,7 +485,7 @@ export default class RevenueCatUI {
383
485
 
384
486
  /**
385
487
  * Presents the customer center to the user.
386
- *
488
+ *
387
489
  * @param {PresentCustomerCenterParams} params - Optional parameters for presenting the customer center.
388
490
  * @returns {Promise<void>} A promise that resolves when the customer center is presented.
389
491
  */
@@ -393,73 +495,89 @@ export default class RevenueCatUI {
393
495
  const callbacks = params.callbacks as CustomerCenterCallbacks;
394
496
 
395
497
  if (callbacks.onFeedbackSurveyCompleted) {
396
- const subscription = customerCenterEventEmitter.addListener(
498
+ const subscription = customerCenterEventEmitter?.addListener(
397
499
  'onFeedbackSurveyCompleted',
398
- (event: { feedbackSurveyOptionId: string }) => callbacks.onFeedbackSurveyCompleted &&
500
+ (event: { feedbackSurveyOptionId: string }) => callbacks.onFeedbackSurveyCompleted &&
399
501
  callbacks.onFeedbackSurveyCompleted(event)
400
502
  );
401
- subscriptions.push(subscription);
503
+ if (subscription) {
504
+ subscriptions.push(subscription);
505
+ }
402
506
  }
403
507
 
404
508
  if (callbacks.onShowingManageSubscriptions) {
405
- const subscription = customerCenterEventEmitter.addListener(
509
+ const subscription = customerCenterEventEmitter?.addListener(
406
510
  'onShowingManageSubscriptions',
407
511
  () => callbacks.onShowingManageSubscriptions && callbacks.onShowingManageSubscriptions()
408
512
  );
409
- subscriptions.push(subscription);
513
+ if (subscription) {
514
+ subscriptions.push(subscription);
515
+ }
410
516
  }
411
517
 
412
518
  if (callbacks.onRestoreCompleted) {
413
- const subscription = customerCenterEventEmitter.addListener(
519
+ const subscription = customerCenterEventEmitter?.addListener(
414
520
  'onRestoreCompleted',
415
- (event: { customerInfo: CustomerInfo }) => callbacks.onRestoreCompleted &&
521
+ (event: { customerInfo: CustomerInfo }) => callbacks.onRestoreCompleted &&
416
522
  callbacks.onRestoreCompleted(event)
417
523
  );
418
- subscriptions.push(subscription);
524
+ if (subscription) {
525
+ subscriptions.push(subscription);
526
+ }
419
527
  }
420
528
 
421
529
  if (callbacks.onRestoreFailed) {
422
- const subscription = customerCenterEventEmitter.addListener(
530
+ const subscription = customerCenterEventEmitter?.addListener(
423
531
  'onRestoreFailed',
424
- (event: { error: PurchasesError }) => callbacks.onRestoreFailed &&
532
+ (event: { error: PurchasesError }) => callbacks.onRestoreFailed &&
425
533
  callbacks.onRestoreFailed(event)
426
534
  );
427
- subscriptions.push(subscription);
535
+ if (subscription) {
536
+ subscriptions.push(subscription);
537
+ }
428
538
  }
429
539
 
430
540
  if (callbacks.onRestoreStarted) {
431
- const subscription = customerCenterEventEmitter.addListener(
541
+ const subscription = customerCenterEventEmitter?.addListener(
432
542
  'onRestoreStarted',
433
543
  () => callbacks.onRestoreStarted && callbacks.onRestoreStarted()
434
544
  );
435
- subscriptions.push(subscription);
545
+ if (subscription) {
546
+ subscriptions.push(subscription);
547
+ }
436
548
  }
437
549
 
438
550
  if (callbacks.onRefundRequestStarted) {
439
- const subscription = customerCenterEventEmitter.addListener(
551
+ const subscription = customerCenterEventEmitter?.addListener(
440
552
  'onRefundRequestStarted',
441
- (event: { productIdentifier: string }) => callbacks.onRefundRequestStarted &&
553
+ (event: { productIdentifier: string }) => callbacks.onRefundRequestStarted &&
442
554
  callbacks.onRefundRequestStarted(event)
443
555
  );
444
- subscriptions.push(subscription);
556
+ if (subscription) {
557
+ subscriptions.push(subscription);
558
+ }
445
559
  }
446
560
 
447
561
  if (callbacks.onRefundRequestCompleted) {
448
- const subscription = customerCenterEventEmitter.addListener(
562
+ const subscription = customerCenterEventEmitter?.addListener(
449
563
  'onRefundRequestCompleted',
450
- (event: { productIdentifier: string; refundRequestStatus: REFUND_REQUEST_STATUS }) => callbacks.onRefundRequestCompleted &&
564
+ (event: { productIdentifier: string; refundRequestStatus: REFUND_REQUEST_STATUS }) => callbacks.onRefundRequestCompleted &&
451
565
  callbacks.onRefundRequestCompleted(event)
452
566
  );
453
- subscriptions.push(subscription);
567
+ if (subscription) {
568
+ subscriptions.push(subscription);
569
+ }
454
570
  }
455
571
 
456
572
  if (callbacks.onManagementOptionSelected) {
457
- const subscription = customerCenterEventEmitter.addListener(
573
+ const subscription = customerCenterEventEmitter?.addListener(
458
574
  'onManagementOptionSelected',
459
- (event: CustomerCenterManagementOptionEvent) => callbacks.onManagementOptionSelected &&
575
+ (event: CustomerCenterManagementOptionEvent) => callbacks.onManagementOptionSelected &&
460
576
  callbacks.onManagementOptionSelected(event)
461
577
  );
462
- subscriptions.push(subscription);
578
+ if (subscription) {
579
+ subscriptions.push(subscription);
580
+ }
463
581
  }
464
582
 
465
583
  // Return a promise that resolves when the customer center is dismissed
@@ -478,7 +596,7 @@ export default class RevenueCatUI {
478
596
  */
479
597
  public static PaywallFooterContainerView: React.FC<FooterPaywallViewProps> =
480
598
  RevenueCatUI.OriginalTemplatePaywallFooterContainerView;
481
-
599
+
482
600
  private static logWarningIfPreviewAPIMode(methodName: string) {
483
601
  if (usingPreviewAPIMode) {
484
602
  // tslint:disable-next-line:no-console
@@ -0,0 +1,171 @@
1
+ import React from 'react';
2
+ import { View, Text, StyleSheet, TouchableOpacity } from 'react-native';
3
+ import {
4
+ type CustomerInfo,
5
+ type PurchasesError,
6
+ type PurchasesOffering,
7
+ type PurchasesPackage,
8
+ type PurchasesStoreTransaction,
9
+ } from "@revenuecat/purchases-typescript-internal";
10
+
11
+ export interface PreviewPaywallProps {
12
+ offering?: PurchasesOffering | null;
13
+ displayCloseButton?: boolean;
14
+ fontFamily?: string | null;
15
+ onPurchaseStarted?: ({packageBeingPurchased}: { packageBeingPurchased: PurchasesPackage }) => void;
16
+ onPurchaseCompleted?: ({
17
+ customerInfo,
18
+ storeTransaction
19
+ }: { customerInfo: CustomerInfo, storeTransaction: PurchasesStoreTransaction }) => void;
20
+ onPurchaseError?: ({error}: { error: PurchasesError }) => void;
21
+ onPurchaseCancelled?: () => void;
22
+ onRestoreStarted?: () => void;
23
+ onRestoreCompleted?: ({customerInfo}: { customerInfo: CustomerInfo }) => void;
24
+ onRestoreError?: ({error}: { error: PurchasesError }) => void;
25
+ onDismiss?: () => void;
26
+ }
27
+
28
+ export const PreviewPaywall: React.FC<PreviewPaywallProps> = ({
29
+ displayCloseButton = true,
30
+ fontFamily,
31
+ onDismiss,
32
+ }) => {
33
+ const handleClose = () => {
34
+ onDismiss?.();
35
+ };
36
+
37
+ const textStyle = fontFamily ? { fontFamily } : undefined;
38
+
39
+ return (
40
+ <View style={styles.container}>
41
+ <View style={styles.header}>
42
+ <Text style={[styles.title, textStyle]}>
43
+ Preview Paywall
44
+ </Text>
45
+ {displayCloseButton && (
46
+ <TouchableOpacity onPress={handleClose} style={styles.closeButton}>
47
+ <Text style={styles.closeButtonText}>✕</Text>
48
+ </TouchableOpacity>
49
+ )}
50
+ </View>
51
+
52
+ <View style={styles.content}>
53
+ <Text style={[styles.notSupportedMessage, textStyle]}>
54
+ Web paywalls are not supported yet.
55
+ </Text>
56
+ <Text style={[styles.fakeMessage, textStyle]}>
57
+ This is a fake preview implementation.
58
+ </Text>
59
+ <Text style={[styles.previewMode, textStyle]}>
60
+ Currently in preview mode
61
+ </Text>
62
+
63
+ <TouchableOpacity style={styles.closePaywallButton} onPress={handleClose}>
64
+ <Text style={[styles.closePaywallButtonText, textStyle]}>
65
+ Close Paywall
66
+ </Text>
67
+ </TouchableOpacity>
68
+ </View>
69
+ </View>
70
+ );
71
+ };
72
+
73
+ const styles = StyleSheet.create({
74
+ container: {
75
+ flex: 1,
76
+ backgroundColor: '#ffffff',
77
+ borderRadius: 12,
78
+ overflow: 'hidden',
79
+ maxWidth: 400,
80
+ maxHeight: 600,
81
+ },
82
+ header: {
83
+ flexDirection: 'row',
84
+ justifyContent: 'space-between',
85
+ alignItems: 'center',
86
+ padding: 20,
87
+ borderBottomWidth: 1,
88
+ borderBottomColor: '#e0e0e0',
89
+ },
90
+ title: {
91
+ fontSize: 24,
92
+ fontWeight: 'bold',
93
+ color: '#333333',
94
+ },
95
+ closeButton: {
96
+ width: 30,
97
+ height: 30,
98
+ borderRadius: 15,
99
+ backgroundColor: '#f0f0f0',
100
+ justifyContent: 'center',
101
+ alignItems: 'center',
102
+ },
103
+ closeButtonText: {
104
+ fontSize: 16,
105
+ color: '#666666',
106
+ },
107
+ content: {
108
+ flex: 1,
109
+ padding: 20,
110
+ justifyContent: 'center',
111
+ alignItems: 'center',
112
+ },
113
+ notSupportedMessage: {
114
+ fontSize: 18,
115
+ fontWeight: 'bold',
116
+ color: '#333333',
117
+ textAlign: 'center',
118
+ marginBottom: 16,
119
+ },
120
+ fakeMessage: {
121
+ fontSize: 16,
122
+ color: '#666666',
123
+ textAlign: 'center',
124
+ marginBottom: 8,
125
+ },
126
+ previewMode: {
127
+ fontSize: 14,
128
+ color: '#999999',
129
+ textAlign: 'center',
130
+ marginBottom: 32,
131
+ },
132
+ closePaywallButton: {
133
+ backgroundColor: '#007AFF',
134
+ padding: 16,
135
+ borderRadius: 8,
136
+ minWidth: 120,
137
+ alignItems: 'center',
138
+ },
139
+ closePaywallButtonText: {
140
+ fontSize: 16,
141
+ fontWeight: 'bold',
142
+ color: '#ffffff',
143
+ },
144
+ description: {
145
+ fontSize: 16,
146
+ color: '#666666',
147
+ marginBottom: 20,
148
+ textAlign: 'center',
149
+ },
150
+ optionButton: {
151
+ backgroundColor: '#f8f9fa',
152
+ padding: 16,
153
+ borderRadius: 8,
154
+ marginBottom: 12,
155
+ alignItems: 'center',
156
+ },
157
+ optionButtonText: {
158
+ fontSize: 16,
159
+ color: '#333333',
160
+ },
161
+ footer: {
162
+ padding: 20,
163
+ borderTopWidth: 1,
164
+ borderTopColor: '#e0e0e0',
165
+ },
166
+ disclaimer: {
167
+ fontSize: 12,
168
+ color: '#999999',
169
+ textAlign: 'center',
170
+ },
171
+ });
@@ -1,18 +1,22 @@
1
- import { NativeModules } from "react-native";
1
+ import { NativeModules, Platform } from "react-native";
2
2
 
3
3
  /**
4
4
  * Detects if the app is running in an environment where native modules are not available
5
- * (like Expo Go) or if the required native modules are missing.
5
+ * (like Expo Go or Web) or if the required native modules are missing.
6
6
  *
7
7
  * @returns {boolean} True if the app is running in an environment where native modules are not available
8
- * (like Expo Go) or if the required native modules are missing.
8
+ * (like Expo Go or Web) or if the required native modules are missing.
9
9
  */
10
10
  export function shouldUsePreviewAPIMode(): boolean {
11
- let usePreviewAPIMode = isExpoGo();
12
- if (usePreviewAPIMode) {
11
+ if (isExpoGo()) {
13
12
  console.log('Expo Go app detected. Using RevenueCat in Preview API Mode.');
13
+ return true;
14
+ } else if (isWebPlatform()) {
15
+ console.log('Web platform detected. Using RevenueCat in Preview API Mode.');
16
+ return true;
17
+ } else {
18
+ return false;
14
19
  }
15
- return usePreviewAPIMode;
16
20
  }
17
21
 
18
22
  declare global {
@@ -32,4 +36,11 @@ function isExpoGo(): boolean {
32
36
  }
33
37
 
34
38
  return !!globalThis.expo?.modules?.ExpoGo;
39
+ }
40
+
41
+ /**
42
+ * Detects if the app is running on web platform
43
+ */
44
+ function isWebPlatform(): boolean {
45
+ return Platform.OS === 'web';
35
46
  }