rn-onboarding-analytics 1.7.5 → 1.7.6
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/README.md +9 -10
- package/lib/module/spill-onboarding/analytics.js +2 -1
- package/lib/module/spill-onboarding/analytics.js.map +1 -1
- package/lib/module/spill-onboarding/components/OnboardingImageContainer.js +13 -22
- package/lib/module/spill-onboarding/components/OnboardingImageContainer.js.map +1 -1
- package/lib/module/spill-onboarding/components/OnboardingIntroPanel.js +11 -6
- package/lib/module/spill-onboarding/components/OnboardingIntroPanel.js.map +1 -1
- package/lib/module/spill-onboarding/components/OnboardingPaywallPanel.js +127 -107
- package/lib/module/spill-onboarding/components/OnboardingPaywallPanel.js.map +1 -1
- package/lib/module/spill-onboarding/components/OnboardingStepContainer.js +2 -1
- package/lib/module/spill-onboarding/components/OnboardingStepContainer.js.map +1 -1
- package/lib/module/spill-onboarding/hooks/useLogDev.js +24 -0
- package/lib/module/spill-onboarding/hooks/useLogDev.js.map +1 -0
- package/lib/module/spill-onboarding/index.js +16 -6
- package/lib/module/spill-onboarding/index.js.map +1 -1
- package/lib/module/utils/theme.js +22 -3
- package/lib/module/utils/theme.js.map +1 -1
- package/lib/typescript/src/spill-onboarding/analytics.d.ts.map +1 -1
- package/lib/typescript/src/spill-onboarding/components/OnboardingImageContainer.d.ts +4 -2
- package/lib/typescript/src/spill-onboarding/components/OnboardingImageContainer.d.ts.map +1 -1
- package/lib/typescript/src/spill-onboarding/components/OnboardingIntroPanel.d.ts +1 -1
- package/lib/typescript/src/spill-onboarding/components/OnboardingIntroPanel.d.ts.map +1 -1
- package/lib/typescript/src/spill-onboarding/components/OnboardingPaywallPanel.d.ts +1 -1
- package/lib/typescript/src/spill-onboarding/components/OnboardingPaywallPanel.d.ts.map +1 -1
- package/lib/typescript/src/spill-onboarding/hooks/useLogDev.d.ts +7 -0
- package/lib/typescript/src/spill-onboarding/hooks/useLogDev.d.ts.map +1 -0
- package/lib/typescript/src/spill-onboarding/index.d.ts +1 -1
- package/lib/typescript/src/spill-onboarding/index.d.ts.map +1 -1
- package/lib/typescript/src/spill-onboarding/types.d.ts +38 -14
- package/lib/typescript/src/spill-onboarding/types.d.ts.map +1 -1
- package/lib/typescript/src/utils/theme.d.ts +1 -0
- package/lib/typescript/src/utils/theme.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/spill-onboarding/analytics.ts +2 -4
- package/src/spill-onboarding/components/OnboardingImageContainer.tsx +21 -25
- package/src/spill-onboarding/components/OnboardingIntroPanel.tsx +15 -4
- package/src/spill-onboarding/components/OnboardingPaywallPanel.tsx +170 -114
- package/src/spill-onboarding/components/OnboardingStepContainer.tsx +1 -0
- package/src/spill-onboarding/hooks/useLogDev.ts +26 -0
- package/src/spill-onboarding/index.tsx +21 -4
- package/src/spill-onboarding/types.ts +44 -14
- package/src/utils/theme.ts +21 -3
|
@@ -9,6 +9,10 @@ import {
|
|
|
9
9
|
Dimensions,
|
|
10
10
|
Platform,
|
|
11
11
|
} from 'react-native';
|
|
12
|
+
import {
|
|
13
|
+
useSafeAreaInsets,
|
|
14
|
+
SafeAreaView,
|
|
15
|
+
} from 'react-native-safe-area-context';
|
|
12
16
|
import {
|
|
13
17
|
initConnection,
|
|
14
18
|
getSubscriptions,
|
|
@@ -21,12 +25,14 @@ import {
|
|
|
21
25
|
type PurchaseError,
|
|
22
26
|
} from 'react-native-iap';
|
|
23
27
|
import { useTheme } from '../../utils/ThemeContext';
|
|
24
|
-
import type
|
|
28
|
+
import { type Theme, resolveTheme } from '../../utils/theme';
|
|
25
29
|
import PrimaryButton from '../buttons/PrimaryButton';
|
|
26
30
|
import SkipButton from '../buttons/SkipButton';
|
|
27
31
|
import { fontSizes, lineHeights } from '../../utils/fontStyles';
|
|
28
32
|
import type { OnboardingPaywallPanelProps, PlatformSku } from '../types';
|
|
29
33
|
import Skeleton from './Skeleton';
|
|
34
|
+
import { trackEvent } from '../analytics';
|
|
35
|
+
import { useLogDev } from '../hooks/useLogDev';
|
|
30
36
|
|
|
31
37
|
const { height: screenHeight } = Dimensions.get('window');
|
|
32
38
|
|
|
@@ -45,9 +51,25 @@ function OnboardingPaywallPanel({
|
|
|
45
51
|
onPrivacy,
|
|
46
52
|
subscriptionSkus,
|
|
47
53
|
onPurchaseResult,
|
|
54
|
+
apiKey,
|
|
55
|
+
isDev,
|
|
56
|
+
colors,
|
|
57
|
+
design,
|
|
58
|
+
theme: themeProp,
|
|
48
59
|
}: OnboardingPaywallPanelProps) {
|
|
49
|
-
const { theme } = useTheme();
|
|
50
|
-
|
|
60
|
+
const { theme: contextTheme } = useTheme();
|
|
61
|
+
|
|
62
|
+
const theme = useMemo(() => {
|
|
63
|
+
return resolveTheme(themeProp, contextTheme, 'dark');
|
|
64
|
+
}, [contextTheme, themeProp]);
|
|
65
|
+
|
|
66
|
+
const insets = useSafeAreaInsets();
|
|
67
|
+
const styles = useMemo(
|
|
68
|
+
() => createStyles(theme, colors, !!image, insets),
|
|
69
|
+
[theme, colors, image, insets]
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
const logDev = useLogDev(!!isDev);
|
|
51
73
|
|
|
52
74
|
// Initialize selectedPlanId based on available configuration
|
|
53
75
|
const initialPlanId = useMemo(() => {
|
|
@@ -422,7 +444,19 @@ function OnboardingPaywallPanel({
|
|
|
422
444
|
|
|
423
445
|
const renderButton = () => {
|
|
424
446
|
const handlePress = async () => {
|
|
425
|
-
|
|
447
|
+
logDev('OnboardingPaywallPanel: handlePress', { selectedPlanId });
|
|
448
|
+
|
|
449
|
+
// Track purchase attempt
|
|
450
|
+
trackEvent(
|
|
451
|
+
apiKey,
|
|
452
|
+
'purchase_attempt',
|
|
453
|
+
{
|
|
454
|
+
plan_id: selectedPlanId,
|
|
455
|
+
design,
|
|
456
|
+
},
|
|
457
|
+
isDev
|
|
458
|
+
);
|
|
459
|
+
|
|
426
460
|
if ((subscriptionSkus || products) && selectedPlanId) {
|
|
427
461
|
try {
|
|
428
462
|
let result;
|
|
@@ -436,7 +470,7 @@ function OnboardingPaywallPanel({
|
|
|
436
470
|
'subscriptionPeriodNumberIOS' in iapProduct ||
|
|
437
471
|
'subscriptionOfferDetails' in iapProduct;
|
|
438
472
|
|
|
439
|
-
|
|
473
|
+
logDev('OnboardingPaywallPanel: Processing purchase', {
|
|
440
474
|
isSubscription,
|
|
441
475
|
productId: iapProduct.productId,
|
|
442
476
|
});
|
|
@@ -449,7 +483,7 @@ function OnboardingPaywallPanel({
|
|
|
449
483
|
?.offerToken;
|
|
450
484
|
}
|
|
451
485
|
|
|
452
|
-
|
|
486
|
+
logDev('OnboardingPaywallPanel: Requesting subscription', {
|
|
453
487
|
sku: selectedPlanId,
|
|
454
488
|
offerToken,
|
|
455
489
|
});
|
|
@@ -460,10 +494,9 @@ function OnboardingPaywallPanel({
|
|
|
460
494
|
}),
|
|
461
495
|
});
|
|
462
496
|
} else {
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
);
|
|
497
|
+
logDev('OnboardingPaywallPanel: Requesting one-time purchase', {
|
|
498
|
+
sku: selectedPlanId,
|
|
499
|
+
});
|
|
467
500
|
result = await requestPurchase({
|
|
468
501
|
sku: selectedPlanId,
|
|
469
502
|
});
|
|
@@ -471,12 +504,12 @@ function OnboardingPaywallPanel({
|
|
|
471
504
|
} else {
|
|
472
505
|
// Fallback if product not found in fetched list but ID exists
|
|
473
506
|
// Try subscription first as default legacy behavior
|
|
474
|
-
|
|
507
|
+
logDev(
|
|
475
508
|
'OnboardingPaywallPanel: Product not in IAP list, attempting fallback purchase',
|
|
476
509
|
selectedPlanId
|
|
477
510
|
);
|
|
478
511
|
try {
|
|
479
|
-
|
|
512
|
+
logDev(
|
|
480
513
|
'OnboardingPaywallPanel: Fallback - attempting requestSubscription',
|
|
481
514
|
selectedPlanId
|
|
482
515
|
);
|
|
@@ -486,7 +519,7 @@ function OnboardingPaywallPanel({
|
|
|
486
519
|
'OnboardingPaywallPanel: Fallback requestSubscription failed',
|
|
487
520
|
subErr
|
|
488
521
|
);
|
|
489
|
-
|
|
522
|
+
logDev(
|
|
490
523
|
'OnboardingPaywallPanel: Fallback - attempting requestPurchase',
|
|
491
524
|
selectedPlanId
|
|
492
525
|
);
|
|
@@ -509,14 +542,33 @@ function OnboardingPaywallPanel({
|
|
|
509
542
|
data: result,
|
|
510
543
|
});
|
|
511
544
|
}
|
|
545
|
+
|
|
546
|
+
// Track successful purchase
|
|
547
|
+
trackEvent(
|
|
548
|
+
apiKey,
|
|
549
|
+
'purchase_success',
|
|
550
|
+
{
|
|
551
|
+
plan_id: selectedPlanId,
|
|
552
|
+
design,
|
|
553
|
+
},
|
|
554
|
+
isDev
|
|
555
|
+
);
|
|
512
556
|
} catch (err) {
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
557
|
+
logDev('PaywallScreen: Purchase failed', err);
|
|
558
|
+
|
|
559
|
+
// Track failed purchase
|
|
560
|
+
trackEvent(
|
|
561
|
+
apiKey,
|
|
562
|
+
'purchase_failed',
|
|
563
|
+
{
|
|
564
|
+
plan_id: selectedPlanId,
|
|
565
|
+
design,
|
|
566
|
+
error:
|
|
567
|
+
typeof err === 'object' ? JSON.stringify(err) : String(err),
|
|
568
|
+
},
|
|
569
|
+
isDev
|
|
570
|
+
);
|
|
571
|
+
|
|
520
572
|
if (onPurchaseResult) {
|
|
521
573
|
onPurchaseResult({
|
|
522
574
|
status: 'error',
|
|
@@ -571,7 +623,15 @@ function OnboardingPaywallPanel({
|
|
|
571
623
|
};
|
|
572
624
|
|
|
573
625
|
const handleClose = () => {
|
|
574
|
-
|
|
626
|
+
logDev('[OnboardingPaywallPanel] Close button pressed');
|
|
627
|
+
trackEvent(
|
|
628
|
+
apiKey,
|
|
629
|
+
'paywall_close',
|
|
630
|
+
{
|
|
631
|
+
design,
|
|
632
|
+
},
|
|
633
|
+
isDev
|
|
634
|
+
);
|
|
575
635
|
if (onClose) {
|
|
576
636
|
onClose();
|
|
577
637
|
} else {
|
|
@@ -580,19 +640,21 @@ function OnboardingPaywallPanel({
|
|
|
580
640
|
};
|
|
581
641
|
|
|
582
642
|
return (
|
|
583
|
-
<
|
|
643
|
+
<SafeAreaView style={styles.mainContainer} edges={['top', 'bottom']}>
|
|
584
644
|
{onClose && (
|
|
585
645
|
<View style={styles.closeButton} pointerEvents="box-none">
|
|
586
646
|
<SkipButton onPress={handleClose} />
|
|
587
647
|
</View>
|
|
588
648
|
)}
|
|
589
|
-
|
|
590
|
-
{
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
649
|
+
{image && (
|
|
650
|
+
<View style={styles.headerImageContainer}>
|
|
651
|
+
{typeof image === 'function'
|
|
652
|
+
? image()
|
|
653
|
+
: image && (
|
|
654
|
+
<Image source={image} style={styles.image} resizeMode="cover" />
|
|
655
|
+
)}
|
|
656
|
+
</View>
|
|
657
|
+
)}
|
|
596
658
|
|
|
597
659
|
<View style={styles.sheetContainer}>
|
|
598
660
|
<ScrollView
|
|
@@ -622,186 +684,180 @@ function OnboardingPaywallPanel({
|
|
|
622
684
|
{renderButton()}
|
|
623
685
|
</View>
|
|
624
686
|
</View>
|
|
625
|
-
</
|
|
687
|
+
</SafeAreaView>
|
|
626
688
|
);
|
|
627
689
|
}
|
|
628
690
|
|
|
629
691
|
export default OnboardingPaywallPanel;
|
|
630
692
|
|
|
631
|
-
const createStyles = (
|
|
693
|
+
const createStyles = (
|
|
694
|
+
theme: Theme,
|
|
695
|
+
colors?: OnboardingPaywallPanelProps['colors'],
|
|
696
|
+
hasImage?: boolean,
|
|
697
|
+
insets?: { top: number; bottom: number; left: number; right: number }
|
|
698
|
+
) =>
|
|
632
699
|
StyleSheet.create({
|
|
633
700
|
mainContainer: {
|
|
634
701
|
flex: 1,
|
|
635
|
-
backgroundColor: theme.bg.secondary,
|
|
702
|
+
backgroundColor: colors?.background?.primary || theme.bg.secondary,
|
|
636
703
|
},
|
|
637
704
|
closeButton: {
|
|
638
705
|
position: 'absolute',
|
|
639
|
-
top: (
|
|
706
|
+
top: (insets?.top || 0) + 8,
|
|
640
707
|
right: 16,
|
|
641
|
-
zIndex:
|
|
708
|
+
zIndex: 10,
|
|
642
709
|
},
|
|
643
710
|
headerImageContainer: {
|
|
644
|
-
height: screenHeight * 0.
|
|
711
|
+
height: screenHeight * 0.35,
|
|
712
|
+
width: '100%',
|
|
713
|
+
},
|
|
714
|
+
image: {
|
|
645
715
|
width: '100%',
|
|
716
|
+
height: '100%',
|
|
646
717
|
},
|
|
647
718
|
sheetContainer: {
|
|
648
719
|
flex: 1,
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
overflow: '
|
|
720
|
+
backgroundColor: colors?.background?.primary || theme.bg.secondary,
|
|
721
|
+
borderTopLeftRadius: hasImage ? 24 : 0,
|
|
722
|
+
borderTopRightRadius: hasImage ? 24 : 0,
|
|
723
|
+
marginTop: hasImage ? -24 : 0,
|
|
724
|
+
overflow: 'hidden',
|
|
654
725
|
},
|
|
655
726
|
container: {
|
|
656
727
|
flex: 1,
|
|
657
728
|
},
|
|
658
729
|
contentContainer: {
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
paddingHorizontal: 8,
|
|
663
|
-
marginBottom: 40,
|
|
664
|
-
paddingTop: 4,
|
|
665
|
-
backgroundColor: theme.bg.secondary,
|
|
730
|
+
padding: 24,
|
|
731
|
+
paddingTop: hasImage ? 32 : (insets?.top || 0) + 40,
|
|
732
|
+
paddingBottom: 120, // Add padding for footer
|
|
666
733
|
},
|
|
667
734
|
contentWrapper: {
|
|
668
|
-
|
|
669
|
-
paddingTop: 32,
|
|
670
|
-
},
|
|
671
|
-
image: {
|
|
672
|
-
width: '100%',
|
|
673
|
-
height: '100%',
|
|
735
|
+
flex: 1,
|
|
674
736
|
},
|
|
675
737
|
headerContainer: {
|
|
676
738
|
alignItems: 'center',
|
|
677
|
-
marginBottom:
|
|
678
|
-
marginTop: 8,
|
|
739
|
+
marginBottom: 32,
|
|
679
740
|
},
|
|
680
741
|
text: {
|
|
681
|
-
fontSize: fontSizes.xxl,
|
|
682
|
-
lineHeight: lineHeights.xxl,
|
|
683
742
|
textAlign: 'center',
|
|
743
|
+
color: colors?.text?.primary || theme.text.primary,
|
|
684
744
|
},
|
|
685
745
|
line1: {
|
|
686
|
-
|
|
746
|
+
fontSize: fontSizes.xl,
|
|
747
|
+
fontWeight: '700',
|
|
748
|
+
marginBottom: 12,
|
|
749
|
+
lineHeight: lineHeights.xl,
|
|
687
750
|
},
|
|
688
751
|
line2: {
|
|
689
|
-
marginTop: 8,
|
|
690
|
-
color: theme.text.secondary,
|
|
691
752
|
fontSize: fontSizes.md,
|
|
753
|
+
color: colors?.text?.secondary || theme.text.secondary,
|
|
692
754
|
lineHeight: lineHeights.md,
|
|
755
|
+
marginTop: 4,
|
|
693
756
|
},
|
|
694
757
|
titleText: {
|
|
695
|
-
|
|
696
|
-
fontWeight: 'bold',
|
|
758
|
+
color: colors?.text?.primary || theme.text.primary,
|
|
697
759
|
},
|
|
698
760
|
subtitleText: {
|
|
699
|
-
|
|
761
|
+
color: colors?.text?.secondary || theme.text.secondary,
|
|
700
762
|
},
|
|
701
763
|
featuresContainer: {
|
|
702
|
-
marginBottom:
|
|
703
|
-
paddingHorizontal: 8,
|
|
764
|
+
marginBottom: 32,
|
|
704
765
|
},
|
|
705
766
|
featureRow: {
|
|
706
767
|
flexDirection: 'row',
|
|
707
768
|
alignItems: 'center',
|
|
708
|
-
marginBottom:
|
|
769
|
+
marginBottom: 16,
|
|
709
770
|
},
|
|
710
771
|
checkIcon: {
|
|
711
|
-
|
|
712
|
-
|
|
772
|
+
fontSize: 18,
|
|
773
|
+
color: colors?.background?.accent || theme.bg.accent,
|
|
713
774
|
marginRight: 12,
|
|
714
775
|
fontWeight: 'bold',
|
|
715
776
|
},
|
|
716
777
|
featureText: {
|
|
717
|
-
color: theme.text.primary,
|
|
718
778
|
fontSize: fontSizes.md,
|
|
719
|
-
|
|
779
|
+
color: colors?.text?.primary || theme.text.primary,
|
|
780
|
+
flex: 1,
|
|
781
|
+
lineHeight: lineHeights.md,
|
|
720
782
|
},
|
|
721
783
|
plansContainer: {
|
|
722
|
-
gap: 12,
|
|
723
784
|
marginBottom: 24,
|
|
785
|
+
gap: 12,
|
|
724
786
|
},
|
|
725
787
|
planCard: {
|
|
726
788
|
flexDirection: 'row',
|
|
727
|
-
alignItems: 'center',
|
|
728
789
|
justifyContent: 'space-between',
|
|
790
|
+
alignItems: 'center',
|
|
729
791
|
padding: 16,
|
|
730
|
-
|
|
731
|
-
borderRadius: 16,
|
|
732
|
-
backgroundColor: theme.bg.secondary,
|
|
792
|
+
borderRadius: 12,
|
|
733
793
|
borderWidth: 1,
|
|
734
|
-
borderColor: theme.bg.label,
|
|
735
|
-
|
|
736
|
-
shadowColor: '#000',
|
|
737
|
-
shadowOffset: { width: 0, height: 2 },
|
|
738
|
-
shadowOpacity: 0.05,
|
|
739
|
-
shadowRadius: 4,
|
|
740
|
-
elevation: 2,
|
|
794
|
+
borderColor: colors?.background?.label || theme.bg.label,
|
|
795
|
+
backgroundColor: 'transparent',
|
|
741
796
|
},
|
|
742
797
|
planCardSelected: {
|
|
743
|
-
borderColor: theme.bg.accent,
|
|
744
|
-
backgroundColor: theme.bg.label,
|
|
745
|
-
borderWidth: 2,
|
|
798
|
+
borderColor: colors?.background?.accent || theme.bg.accent,
|
|
799
|
+
backgroundColor: colors?.background?.label || theme.bg.label,
|
|
746
800
|
},
|
|
747
801
|
planTitle: {
|
|
748
802
|
fontSize: fontSizes.md,
|
|
749
803
|
fontWeight: '600',
|
|
750
|
-
color: theme.text.primary,
|
|
804
|
+
color: colors?.text?.primary || theme.text.primary,
|
|
805
|
+
marginBottom: 4,
|
|
751
806
|
},
|
|
752
807
|
planTitleSelected: {
|
|
753
|
-
color: theme.text.primary,
|
|
754
|
-
fontWeight: '700',
|
|
808
|
+
color: colors?.text?.primary || theme.text.primary,
|
|
755
809
|
},
|
|
756
810
|
planInterval: {
|
|
757
811
|
fontSize: fontSizes.sm,
|
|
758
|
-
color: theme.text.secondary,
|
|
759
|
-
marginTop: 2,
|
|
812
|
+
color: colors?.text?.secondary || theme.text.secondary,
|
|
760
813
|
},
|
|
761
814
|
planIntervalSelected: {
|
|
762
|
-
color: theme.text.secondary,
|
|
815
|
+
color: colors?.text?.secondary || theme.text.secondary,
|
|
763
816
|
},
|
|
764
817
|
planPrice: {
|
|
765
818
|
fontSize: fontSizes.lg,
|
|
766
819
|
fontWeight: '700',
|
|
767
|
-
color: theme.text.primary,
|
|
820
|
+
color: colors?.text?.primary || theme.text.primary,
|
|
768
821
|
},
|
|
769
822
|
planPriceSelected: {
|
|
770
|
-
color: theme.
|
|
823
|
+
color: colors?.text?.primary || theme.text.primary,
|
|
771
824
|
},
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
alignSelf: 'flex-start',
|
|
779
|
-
},
|
|
780
|
-
helperTextBadge: {
|
|
781
|
-
color: theme.text.contrast,
|
|
782
|
-
fontSize: fontSizes.xs,
|
|
783
|
-
fontWeight: '600',
|
|
825
|
+
footerContainer: {
|
|
826
|
+
padding: 24,
|
|
827
|
+
paddingBottom: (insets?.bottom || 0) + 16,
|
|
828
|
+
borderTopWidth: 1,
|
|
829
|
+
borderTopColor: colors?.background?.label || theme.bg.label,
|
|
830
|
+
backgroundColor: colors?.background?.primary || theme.bg.secondary,
|
|
784
831
|
},
|
|
785
832
|
helperText: {
|
|
786
833
|
textAlign: 'center',
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
marginBottom:
|
|
790
|
-
fontWeight: '500',
|
|
834
|
+
fontSize: fontSizes.xs,
|
|
835
|
+
color: colors?.text?.secondary || theme.text.secondary,
|
|
836
|
+
marginBottom: 16,
|
|
791
837
|
},
|
|
792
838
|
footerLinksContainer: {
|
|
793
839
|
flexDirection: 'row',
|
|
794
840
|
justifyContent: 'center',
|
|
795
841
|
alignItems: 'center',
|
|
796
|
-
marginTop:
|
|
797
|
-
|
|
842
|
+
marginTop: 24,
|
|
843
|
+
marginBottom: 12,
|
|
798
844
|
},
|
|
799
845
|
footerLinkText: {
|
|
800
|
-
fontSize: fontSizes.
|
|
801
|
-
color: theme.text.secondary,
|
|
846
|
+
fontSize: fontSizes.xs,
|
|
847
|
+
color: colors?.text?.secondary || theme.text.secondary,
|
|
848
|
+
textDecorationLine: 'underline',
|
|
802
849
|
},
|
|
803
850
|
footerLinkSeparator: {
|
|
804
851
|
fontSize: fontSizes.xs,
|
|
805
|
-
color: theme.text.secondary,
|
|
852
|
+
color: colors?.text?.secondary || theme.text.secondary,
|
|
853
|
+
marginHorizontal: 8,
|
|
854
|
+
},
|
|
855
|
+
helperTextContainer: {
|
|
856
|
+
marginTop: 4,
|
|
857
|
+
},
|
|
858
|
+
helperTextBadge: {
|
|
859
|
+
fontSize: fontSizes.xs,
|
|
860
|
+
color: colors?.background?.accent || theme.bg.accent,
|
|
861
|
+
fontWeight: '600',
|
|
806
862
|
},
|
|
807
863
|
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { useCallback } from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Helper function to log messages with the Dev Mode prefix.
|
|
5
|
+
* Can be used outside of React components.
|
|
6
|
+
*/
|
|
7
|
+
export const logDevMessage = (isDev: boolean, message: string, data?: any) => {
|
|
8
|
+
if (isDev) {
|
|
9
|
+
if (data) {
|
|
10
|
+
console.log(`🚧 [Dev Mode] ${message}`, JSON.stringify(data, null, 2));
|
|
11
|
+
} else {
|
|
12
|
+
console.log(`🚧 [Dev Mode] ${message}`);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const useLogDev = (isDev: boolean) => {
|
|
18
|
+
const log = useCallback(
|
|
19
|
+
(message: string, data?: any) => {
|
|
20
|
+
logDevMessage(isDev, message, data);
|
|
21
|
+
},
|
|
22
|
+
[isDev]
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
return log;
|
|
26
|
+
};
|
|
@@ -18,6 +18,7 @@ import { type OnboardingProps } from './types';
|
|
|
18
18
|
import useMeasureHeight from './hooks/useMeasureHeight';
|
|
19
19
|
import { type Theme } from '../utils/theme';
|
|
20
20
|
import { trackEvent } from './analytics';
|
|
21
|
+
import { useLogDev } from './hooks/useLogDev';
|
|
21
22
|
|
|
22
23
|
function SpillOnboarding({
|
|
23
24
|
animationDuration = 500,
|
|
@@ -34,8 +35,10 @@ function SpillOnboarding({
|
|
|
34
35
|
isDev,
|
|
35
36
|
paywallPanel: paywallPanelProps,
|
|
36
37
|
backButtonIcon,
|
|
38
|
+
colors,
|
|
37
39
|
}: OnboardingProps) {
|
|
38
40
|
const { theme } = useTheme();
|
|
41
|
+
const logDev = useLogDev(!!isDev);
|
|
39
42
|
|
|
40
43
|
const styles = useMemo(() => createStyles(theme), [theme]);
|
|
41
44
|
const backgroundSpillProgress = useSharedValue(0);
|
|
@@ -67,7 +70,7 @@ function SpillOnboarding({
|
|
|
67
70
|
const fromStepName = getStepName(step);
|
|
68
71
|
const toStepName = getStepName(stepNumber);
|
|
69
72
|
|
|
70
|
-
|
|
73
|
+
logDev('Onboarding Step Change:', {
|
|
71
74
|
from: fromStepName,
|
|
72
75
|
to: toStepName,
|
|
73
76
|
index: stepNumber,
|
|
@@ -88,7 +91,7 @@ function SpillOnboarding({
|
|
|
88
91
|
isDev
|
|
89
92
|
);
|
|
90
93
|
},
|
|
91
|
-
[onStepChangeProps, apiKey, step, steps, isDev]
|
|
94
|
+
[onStepChangeProps, apiKey, step, steps, isDev, logDev]
|
|
92
95
|
);
|
|
93
96
|
|
|
94
97
|
useEffect(() => {
|
|
@@ -202,6 +205,9 @@ function SpillOnboarding({
|
|
|
202
205
|
<OnboardingPaywallPanel
|
|
203
206
|
onPressContinue={handleContinue}
|
|
204
207
|
onClose={handleClose}
|
|
208
|
+
apiKey={apiKey}
|
|
209
|
+
isDev={isDev}
|
|
210
|
+
colors={colors}
|
|
205
211
|
{...otherProps}
|
|
206
212
|
/>
|
|
207
213
|
);
|
|
@@ -227,7 +233,7 @@ function SpillOnboarding({
|
|
|
227
233
|
buttonLabel={currentStep.buttonLabel}
|
|
228
234
|
onBackPress={onBackPress}
|
|
229
235
|
onNextPress={onNextPress}
|
|
230
|
-
buttonPrimary={
|
|
236
|
+
buttonPrimary={false}
|
|
231
237
|
showBackButton={currentStep.showBackButton ?? showBackButton}
|
|
232
238
|
backButtonIcon={currentStep.backButtonIcon ?? backButtonIcon}
|
|
233
239
|
/>
|
|
@@ -263,13 +269,24 @@ function SpillOnboarding({
|
|
|
263
269
|
<OnboardingImageContainer
|
|
264
270
|
currentStep={currentStep}
|
|
265
271
|
currentStepImage={currentStepImage}
|
|
266
|
-
position={currentStep?.position ?? firstStep?.position ?? 'top'}
|
|
267
272
|
animationDuration={animationDuration}
|
|
268
273
|
backgroundSpillProgress={backgroundSpillProgress}
|
|
269
274
|
screenHeight={screen.height}
|
|
270
275
|
introPanel={introPanel}
|
|
271
276
|
stepPanel={stepPanel}
|
|
272
277
|
background={background}
|
|
278
|
+
propimageStyle={
|
|
279
|
+
typeof introPanelProps !== 'function'
|
|
280
|
+
? introPanelProps.propimageStyle
|
|
281
|
+
: undefined
|
|
282
|
+
}
|
|
283
|
+
// If introPanel.image is a function, do NOT render it in ImageContainer
|
|
284
|
+
// because it's already rendered in OnboardingIntroPanel
|
|
285
|
+
hideImage={
|
|
286
|
+
!currentStep &&
|
|
287
|
+
typeof introPanelProps !== 'function' &&
|
|
288
|
+
typeof introPanelProps.image === 'function'
|
|
289
|
+
}
|
|
273
290
|
/>
|
|
274
291
|
|
|
275
292
|
{isPaywall ? (
|