rn-onboarding-analytics 1.0.0 → 1.1.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/README.md +3 -3
- package/lib/module/spill-onboarding/analytics.js +12 -5
- package/lib/module/spill-onboarding/analytics.js.map +1 -1
- package/lib/module/spill-onboarding/components/OnboardingPaywallPanel.js +299 -0
- package/lib/module/spill-onboarding/components/OnboardingPaywallPanel.js.map +1 -0
- package/lib/module/spill-onboarding/index.js +49 -6
- package/lib/module/spill-onboarding/index.js.map +1 -1
- package/lib/typescript/src/spill-onboarding/analytics.d.ts +1 -1
- package/lib/typescript/src/spill-onboarding/analytics.d.ts.map +1 -1
- package/lib/typescript/src/spill-onboarding/components/OnboardingPaywallPanel.d.ts +4 -0
- package/lib/typescript/src/spill-onboarding/components/OnboardingPaywallPanel.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 +61 -3
- package/lib/typescript/src/spill-onboarding/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/spill-onboarding/analytics.ts +18 -5
- package/src/spill-onboarding/components/OnboardingPaywallPanel.tsx +346 -0
- package/src/spill-onboarding/index.tsx +68 -18
- package/src/spill-onboarding/types.ts +68 -3
|
@@ -161,7 +161,7 @@ export interface OnboardingProps {
|
|
|
161
161
|
/** Ordered list of steps to render. */
|
|
162
162
|
steps: OnboardingStep[];
|
|
163
163
|
/** Called when the user completes the final step. */
|
|
164
|
-
onComplete: () => void;
|
|
164
|
+
onComplete: (planId?: string) => void;
|
|
165
165
|
/** Called when the user skips the onboarding. */
|
|
166
166
|
onSkip?: () => void;
|
|
167
167
|
/** Notifies consumers when the active step index changes. */
|
|
@@ -184,9 +184,67 @@ export interface OnboardingProps {
|
|
|
184
184
|
fonts?: OnboardingFonts | string;
|
|
185
185
|
/**
|
|
186
186
|
* API Key for analytics.
|
|
187
|
-
*
|
|
187
|
+
* Optional. If not provided, analytics will be disabled.
|
|
188
188
|
*/
|
|
189
|
-
apiKey
|
|
189
|
+
apiKey?: string;
|
|
190
|
+
/**
|
|
191
|
+
* If true, analytics events will be logged to console but not sent to the server.
|
|
192
|
+
* Useful for development.
|
|
193
|
+
*/
|
|
194
|
+
isDev?: boolean;
|
|
195
|
+
/**
|
|
196
|
+
* Optional Paywall panel content.
|
|
197
|
+
* If provided, it will be shown after the last step.
|
|
198
|
+
*/
|
|
199
|
+
paywallPanel?: OnboardingPaywallPanelConfig;
|
|
200
|
+
}
|
|
201
|
+
export interface PaywallPlan {
|
|
202
|
+
id: string;
|
|
203
|
+
title: string;
|
|
204
|
+
price: string;
|
|
205
|
+
interval?: string;
|
|
206
|
+
features?: string[];
|
|
190
207
|
}
|
|
208
|
+
/**
|
|
209
|
+
* Props for the paywall panel.
|
|
210
|
+
*/
|
|
211
|
+
export interface OnboardingPaywallPanelProps {
|
|
212
|
+
/** Callback invoked when the user taps the main action button. */
|
|
213
|
+
onPressContinue: (planId: string) => void;
|
|
214
|
+
/** Title content. */
|
|
215
|
+
title?: string | ReactNode;
|
|
216
|
+
/** Subtitle content. */
|
|
217
|
+
subtitle?: string | ReactNode;
|
|
218
|
+
/** List of plans to display. */
|
|
219
|
+
plans: PaywallPlan[];
|
|
220
|
+
/**
|
|
221
|
+
* Button content. Either a simple string label or a render function.
|
|
222
|
+
*/
|
|
223
|
+
button: string | (({ onPress }: {
|
|
224
|
+
onPress: () => void;
|
|
225
|
+
}) => ReactNode);
|
|
226
|
+
/** Optional image shown on the paywall panel. */
|
|
227
|
+
image?: ImageSourcePropType | (() => ReactNode);
|
|
228
|
+
/** Helper text displayed above the continue button. */
|
|
229
|
+
helperTextContinue?: string;
|
|
230
|
+
/** Link for restore purchase action. */
|
|
231
|
+
onRestorePurchase?: {
|
|
232
|
+
text?: string;
|
|
233
|
+
onPress: () => void;
|
|
234
|
+
};
|
|
235
|
+
/** Link for terms of service action. */
|
|
236
|
+
onTerms?: {
|
|
237
|
+
text?: string;
|
|
238
|
+
onPress: () => void;
|
|
239
|
+
};
|
|
240
|
+
/** Link for privacy policy action. */
|
|
241
|
+
onPrivacy?: {
|
|
242
|
+
text?: string;
|
|
243
|
+
onPress: () => void;
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
type OnboardingPaywallPanelConfig = Omit<OnboardingPaywallPanelProps, 'onPressContinue'> | (({ onPressContinue, }: {
|
|
247
|
+
onPressContinue: (planId: string) => void;
|
|
248
|
+
}) => ReactNode);
|
|
191
249
|
export {};
|
|
192
250
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/spill-onboarding/types.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/spill-onboarding/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -8,9 +8,9 @@ const API_URL = 'https://api.freesupabase.shop/api/track';
|
|
|
8
8
|
export const trackEvent = async (
|
|
9
9
|
apiKey: string | undefined,
|
|
10
10
|
eventType: string,
|
|
11
|
-
metaData: any = {}
|
|
11
|
+
metaData: any = {},
|
|
12
|
+
isDev: boolean = false
|
|
12
13
|
) => {
|
|
13
|
-
const token = apiKey;
|
|
14
14
|
const appName =
|
|
15
15
|
Constants.expoConfig?.name ||
|
|
16
16
|
Constants.manifest?.name ||
|
|
@@ -25,7 +25,7 @@ export const trackEvent = async (
|
|
|
25
25
|
language: primaryLocale?.languageCode,
|
|
26
26
|
};
|
|
27
27
|
|
|
28
|
-
if (!
|
|
28
|
+
if (!isDev && !apiKey) {
|
|
29
29
|
console.error(
|
|
30
30
|
JSON.stringify({
|
|
31
31
|
error: 'Go to `https://freesupabase.shop/docs` to get an app token',
|
|
@@ -35,13 +35,26 @@ export const trackEvent = async (
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
const payload = {
|
|
38
|
-
app_id:
|
|
38
|
+
app_id: apiKey,
|
|
39
39
|
eventType,
|
|
40
40
|
userAgent: `React Native (${Platform.OS})`,
|
|
41
41
|
sourceUrl: appName,
|
|
42
42
|
metaData: extendedMetaData,
|
|
43
43
|
};
|
|
44
44
|
|
|
45
|
+
if (isDev) {
|
|
46
|
+
console.log(
|
|
47
|
+
'🚧 [Dev Mode] Analytics Event (Not Sent):',
|
|
48
|
+
JSON.stringify(payload, null, 2)
|
|
49
|
+
);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (!apiKey) {
|
|
54
|
+
console.log('⚠️ Analytics: No API Key provided, event not sent.');
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
45
58
|
console.log('📡 Sending Analytics Event:', JSON.stringify(payload, null, 2));
|
|
46
59
|
|
|
47
60
|
try {
|
|
@@ -49,7 +62,7 @@ export const trackEvent = async (
|
|
|
49
62
|
method: 'POST',
|
|
50
63
|
headers: {
|
|
51
64
|
'Content-Type': 'application/json',
|
|
52
|
-
'Authorization': `Bearer ${
|
|
65
|
+
'Authorization': `Bearer ${apiKey}`,
|
|
53
66
|
},
|
|
54
67
|
body: JSON.stringify(payload),
|
|
55
68
|
});
|
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
import { useMemo, useState } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
Image,
|
|
4
|
+
StyleSheet,
|
|
5
|
+
Text,
|
|
6
|
+
View,
|
|
7
|
+
TouchableOpacity,
|
|
8
|
+
ScrollView,
|
|
9
|
+
Dimensions,
|
|
10
|
+
} from 'react-native';
|
|
11
|
+
import { useTheme } from '../../utils/ThemeContext';
|
|
12
|
+
import type { Theme } from '../../utils/theme';
|
|
13
|
+
import PrimaryButton from '../buttons/PrimaryButton';
|
|
14
|
+
import { fontSizes, lineHeights } from '../../utils/fontStyles';
|
|
15
|
+
import type { OnboardingPaywallPanelProps } from '../types';
|
|
16
|
+
|
|
17
|
+
const { height: screenHeight } = Dimensions.get('window');
|
|
18
|
+
|
|
19
|
+
function OnboardingPaywallPanel({
|
|
20
|
+
onPressContinue,
|
|
21
|
+
title,
|
|
22
|
+
subtitle,
|
|
23
|
+
button,
|
|
24
|
+
image,
|
|
25
|
+
plans,
|
|
26
|
+
helperTextContinue,
|
|
27
|
+
onRestorePurchase,
|
|
28
|
+
onTerms,
|
|
29
|
+
onPrivacy,
|
|
30
|
+
}: OnboardingPaywallPanelProps) {
|
|
31
|
+
const { theme } = useTheme();
|
|
32
|
+
const styles = useMemo(() => createStyles(theme), [theme]);
|
|
33
|
+
const [selectedPlanId, setSelectedPlanId] = useState<string>(
|
|
34
|
+
plans[0]?.id || ''
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
const selectedPlan = plans.find((p) => p.id === selectedPlanId);
|
|
38
|
+
|
|
39
|
+
const renderTitle = () => {
|
|
40
|
+
if (!title) return null;
|
|
41
|
+
if (typeof title === 'string') {
|
|
42
|
+
return (
|
|
43
|
+
<Text style={[styles.text, styles.line1, styles.titleText]}>
|
|
44
|
+
{title}
|
|
45
|
+
</Text>
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
return title;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const renderSubtitle = () => {
|
|
52
|
+
if (!subtitle) return null;
|
|
53
|
+
if (typeof subtitle === 'string') {
|
|
54
|
+
return (
|
|
55
|
+
<Text style={[styles.text, styles.line2, styles.subtitleText]}>
|
|
56
|
+
{subtitle}
|
|
57
|
+
</Text>
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
return subtitle;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const renderFeatures = () => {
|
|
64
|
+
if (!selectedPlan?.features || selectedPlan.features.length === 0)
|
|
65
|
+
return null;
|
|
66
|
+
|
|
67
|
+
return (
|
|
68
|
+
<View style={styles.featuresContainer}>
|
|
69
|
+
{selectedPlan.features.map((feature, index) => (
|
|
70
|
+
<View key={index} style={styles.featureRow}>
|
|
71
|
+
<Text style={styles.checkIcon}>✓</Text>
|
|
72
|
+
<Text style={styles.featureText}>{feature}</Text>
|
|
73
|
+
</View>
|
|
74
|
+
))}
|
|
75
|
+
</View>
|
|
76
|
+
);
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const renderPlans = () => {
|
|
80
|
+
return (
|
|
81
|
+
<View style={styles.plansContainer}>
|
|
82
|
+
{plans.map((plan) => {
|
|
83
|
+
const isSelected = plan.id === selectedPlanId;
|
|
84
|
+
return (
|
|
85
|
+
<TouchableOpacity
|
|
86
|
+
key={plan.id}
|
|
87
|
+
style={[styles.planCard, isSelected && styles.planCardSelected]}
|
|
88
|
+
onPress={() => setSelectedPlanId(plan.id)}
|
|
89
|
+
activeOpacity={0.8}
|
|
90
|
+
>
|
|
91
|
+
<View>
|
|
92
|
+
<Text
|
|
93
|
+
style={[
|
|
94
|
+
styles.planTitle,
|
|
95
|
+
isSelected && styles.planTitleSelected,
|
|
96
|
+
]}
|
|
97
|
+
>
|
|
98
|
+
{plan.title}
|
|
99
|
+
</Text>
|
|
100
|
+
{plan.interval && (
|
|
101
|
+
<Text
|
|
102
|
+
style={[
|
|
103
|
+
styles.planInterval,
|
|
104
|
+
isSelected && styles.planIntervalSelected,
|
|
105
|
+
]}
|
|
106
|
+
>
|
|
107
|
+
{plan.interval}
|
|
108
|
+
</Text>
|
|
109
|
+
)}
|
|
110
|
+
</View>
|
|
111
|
+
<Text
|
|
112
|
+
style={[
|
|
113
|
+
styles.planPrice,
|
|
114
|
+
isSelected && styles.planPriceSelected,
|
|
115
|
+
]}
|
|
116
|
+
>
|
|
117
|
+
{plan.price}
|
|
118
|
+
</Text>
|
|
119
|
+
</TouchableOpacity>
|
|
120
|
+
);
|
|
121
|
+
})}
|
|
122
|
+
</View>
|
|
123
|
+
);
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
const renderButton = () => {
|
|
127
|
+
const handlePress = () => onPressContinue(selectedPlanId);
|
|
128
|
+
|
|
129
|
+
if (typeof button === 'string') {
|
|
130
|
+
return <PrimaryButton text={button} onPress={handlePress} />;
|
|
131
|
+
}
|
|
132
|
+
return button({ onPress: handlePress });
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
const renderFooterLinks = () => {
|
|
136
|
+
if (!onRestorePurchase && !onTerms && !onPrivacy) return null;
|
|
137
|
+
|
|
138
|
+
return (
|
|
139
|
+
<View style={styles.footerLinksContainer}>
|
|
140
|
+
{onRestorePurchase && (
|
|
141
|
+
<TouchableOpacity onPress={onRestorePurchase.onPress}>
|
|
142
|
+
<Text style={styles.footerLinkText}>{onRestorePurchase.text}</Text>
|
|
143
|
+
</TouchableOpacity>
|
|
144
|
+
)}
|
|
145
|
+
|
|
146
|
+
{onRestorePurchase && (onTerms || onPrivacy) && (
|
|
147
|
+
<Text style={styles.footerLinkSeparator}>•</Text>
|
|
148
|
+
)}
|
|
149
|
+
|
|
150
|
+
{onTerms && (
|
|
151
|
+
<TouchableOpacity onPress={onTerms.onPress}>
|
|
152
|
+
<Text style={styles.footerLinkText}>{onTerms.text}</Text>
|
|
153
|
+
</TouchableOpacity>
|
|
154
|
+
)}
|
|
155
|
+
|
|
156
|
+
{onTerms && onPrivacy && (
|
|
157
|
+
<Text style={styles.footerLinkSeparator}>•</Text>
|
|
158
|
+
)}
|
|
159
|
+
|
|
160
|
+
{onPrivacy && (
|
|
161
|
+
<TouchableOpacity onPress={onPrivacy.onPress}>
|
|
162
|
+
<Text style={styles.footerLinkText}>{onPrivacy.text}</Text>
|
|
163
|
+
</TouchableOpacity>
|
|
164
|
+
)}
|
|
165
|
+
</View>
|
|
166
|
+
);
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
return (
|
|
170
|
+
<ScrollView
|
|
171
|
+
style={styles.container}
|
|
172
|
+
contentContainerStyle={styles.contentContainer}
|
|
173
|
+
showsVerticalScrollIndicator={false}
|
|
174
|
+
bounces={false}
|
|
175
|
+
>
|
|
176
|
+
{typeof image === 'function'
|
|
177
|
+
? image()
|
|
178
|
+
: image && (
|
|
179
|
+
<Image source={image} style={styles.image} resizeMode="cover" />
|
|
180
|
+
)}
|
|
181
|
+
|
|
182
|
+
<View style={styles.contentWrapper}>
|
|
183
|
+
<View style={styles.headerContainer}>
|
|
184
|
+
{renderTitle()}
|
|
185
|
+
{renderSubtitle()}
|
|
186
|
+
</View>
|
|
187
|
+
|
|
188
|
+
{renderFeatures()}
|
|
189
|
+
|
|
190
|
+
{renderPlans()}
|
|
191
|
+
|
|
192
|
+
{helperTextContinue && (
|
|
193
|
+
<Text style={styles.helperText}>{helperTextContinue}</Text>
|
|
194
|
+
)}
|
|
195
|
+
|
|
196
|
+
{renderButton()}
|
|
197
|
+
|
|
198
|
+
{renderFooterLinks()}
|
|
199
|
+
</View>
|
|
200
|
+
</ScrollView>
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export default OnboardingPaywallPanel;
|
|
205
|
+
|
|
206
|
+
const createStyles = (theme: Theme) =>
|
|
207
|
+
StyleSheet.create({
|
|
208
|
+
container: {
|
|
209
|
+
flex: 1,
|
|
210
|
+
backgroundColor: theme.bg.secondary,
|
|
211
|
+
},
|
|
212
|
+
contentContainer: {
|
|
213
|
+
paddingBottom: 40,
|
|
214
|
+
},
|
|
215
|
+
contentWrapper: {
|
|
216
|
+
paddingHorizontal: 16,
|
|
217
|
+
marginTop: -32,
|
|
218
|
+
paddingTop: 32,
|
|
219
|
+
borderTopLeftRadius: 32,
|
|
220
|
+
borderTopRightRadius: 32,
|
|
221
|
+
backgroundColor: theme.bg.secondary,
|
|
222
|
+
},
|
|
223
|
+
image: {
|
|
224
|
+
alignSelf: 'center',
|
|
225
|
+
width: '100%',
|
|
226
|
+
height: screenHeight * 0.3,
|
|
227
|
+
},
|
|
228
|
+
headerContainer: {
|
|
229
|
+
alignItems: 'center',
|
|
230
|
+
marginBottom: 24,
|
|
231
|
+
marginTop: 8,
|
|
232
|
+
},
|
|
233
|
+
text: {
|
|
234
|
+
fontSize: fontSizes.xxl,
|
|
235
|
+
lineHeight: lineHeights.xxl,
|
|
236
|
+
textAlign: 'center',
|
|
237
|
+
},
|
|
238
|
+
line1: {
|
|
239
|
+
color: theme.text.primary,
|
|
240
|
+
},
|
|
241
|
+
line2: {
|
|
242
|
+
marginTop: 8,
|
|
243
|
+
color: theme.text.secondary,
|
|
244
|
+
fontSize: fontSizes.md,
|
|
245
|
+
lineHeight: lineHeights.md,
|
|
246
|
+
},
|
|
247
|
+
titleText: {
|
|
248
|
+
fontFamily: theme.fonts.introTitle,
|
|
249
|
+
fontWeight: 'bold',
|
|
250
|
+
},
|
|
251
|
+
subtitleText: {
|
|
252
|
+
fontFamily: theme.fonts.introSubtitle,
|
|
253
|
+
},
|
|
254
|
+
featuresContainer: {
|
|
255
|
+
marginBottom: 24,
|
|
256
|
+
paddingHorizontal: 8,
|
|
257
|
+
},
|
|
258
|
+
featureRow: {
|
|
259
|
+
flexDirection: 'row',
|
|
260
|
+
alignItems: 'center',
|
|
261
|
+
marginBottom: 12,
|
|
262
|
+
},
|
|
263
|
+
checkIcon: {
|
|
264
|
+
color: theme.bg.accent,
|
|
265
|
+
fontSize: fontSizes.lg,
|
|
266
|
+
marginRight: 12,
|
|
267
|
+
fontWeight: 'bold',
|
|
268
|
+
},
|
|
269
|
+
featureText: {
|
|
270
|
+
color: theme.text.primary,
|
|
271
|
+
fontSize: fontSizes.md,
|
|
272
|
+
fontWeight: '500',
|
|
273
|
+
},
|
|
274
|
+
plansContainer: {
|
|
275
|
+
gap: 12,
|
|
276
|
+
marginBottom: 24,
|
|
277
|
+
},
|
|
278
|
+
planCard: {
|
|
279
|
+
flexDirection: 'row',
|
|
280
|
+
alignItems: 'center',
|
|
281
|
+
justifyContent: 'space-between',
|
|
282
|
+
padding: 16,
|
|
283
|
+
borderRadius: 16,
|
|
284
|
+
backgroundColor: theme.bg.secondary,
|
|
285
|
+
borderWidth: 1,
|
|
286
|
+
borderColor: theme.bg.label,
|
|
287
|
+
// Shadow for elevation
|
|
288
|
+
shadowColor: '#000',
|
|
289
|
+
shadowOffset: { width: 0, height: 2 },
|
|
290
|
+
shadowOpacity: 0.05,
|
|
291
|
+
shadowRadius: 4,
|
|
292
|
+
elevation: 2,
|
|
293
|
+
},
|
|
294
|
+
planCardSelected: {
|
|
295
|
+
borderColor: theme.bg.accent,
|
|
296
|
+
backgroundColor: theme.bg.secondary,
|
|
297
|
+
borderWidth: 2,
|
|
298
|
+
},
|
|
299
|
+
planTitle: {
|
|
300
|
+
fontSize: fontSizes.md,
|
|
301
|
+
fontWeight: '600',
|
|
302
|
+
color: theme.text.primary,
|
|
303
|
+
},
|
|
304
|
+
planTitleSelected: {
|
|
305
|
+
color: theme.text.primary,
|
|
306
|
+
fontWeight: '700',
|
|
307
|
+
},
|
|
308
|
+
planInterval: {
|
|
309
|
+
fontSize: fontSizes.sm,
|
|
310
|
+
color: theme.text.secondary,
|
|
311
|
+
marginTop: 2,
|
|
312
|
+
},
|
|
313
|
+
planIntervalSelected: {
|
|
314
|
+
color: theme.text.secondary,
|
|
315
|
+
},
|
|
316
|
+
planPrice: {
|
|
317
|
+
fontSize: fontSizes.lg,
|
|
318
|
+
fontWeight: '700',
|
|
319
|
+
color: theme.text.primary,
|
|
320
|
+
},
|
|
321
|
+
planPriceSelected: {
|
|
322
|
+
color: theme.bg.accent,
|
|
323
|
+
},
|
|
324
|
+
helperText: {
|
|
325
|
+
textAlign: 'center',
|
|
326
|
+
color: theme.text.secondary,
|
|
327
|
+
fontSize: fontSizes.sm,
|
|
328
|
+
marginBottom: 12,
|
|
329
|
+
fontWeight: '500',
|
|
330
|
+
},
|
|
331
|
+
footerLinksContainer: {
|
|
332
|
+
flexDirection: 'row',
|
|
333
|
+
justifyContent: 'center',
|
|
334
|
+
alignItems: 'center',
|
|
335
|
+
marginTop: 24,
|
|
336
|
+
gap: 8,
|
|
337
|
+
},
|
|
338
|
+
footerLinkText: {
|
|
339
|
+
fontSize: fontSizes.md,
|
|
340
|
+
color: theme.text.secondary,
|
|
341
|
+
},
|
|
342
|
+
footerLinkSeparator: {
|
|
343
|
+
fontSize: fontSizes.xs,
|
|
344
|
+
color: theme.text.secondary,
|
|
345
|
+
},
|
|
346
|
+
});
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
} from 'react-native';
|
|
9
9
|
import { useTheme } from '../utils/ThemeContext';
|
|
10
10
|
import OnboardingIntroPanel from './components/OnboardingIntroPanel';
|
|
11
|
+
import OnboardingPaywallPanel from './components/OnboardingPaywallPanel';
|
|
11
12
|
import { useSharedValue, withTiming } from 'react-native-reanimated';
|
|
12
13
|
import OnboardingStepPanel from './components/OnboardingStepPanel';
|
|
13
14
|
import OnboardingStepContainer from './components/OnboardingStepContainer';
|
|
@@ -31,6 +32,8 @@ function SpillOnboarding({
|
|
|
31
32
|
background,
|
|
32
33
|
skipButton,
|
|
33
34
|
apiKey,
|
|
35
|
+
isDev,
|
|
36
|
+
paywallPanel: paywallPanelProps,
|
|
34
37
|
}: OnboardingProps) {
|
|
35
38
|
const { theme } = useTheme();
|
|
36
39
|
|
|
@@ -40,6 +43,7 @@ function SpillOnboarding({
|
|
|
40
43
|
const [step, setStep] = useState(-1);
|
|
41
44
|
const currentStep = step >= 0 ? steps[step] : undefined;
|
|
42
45
|
const firstStep = steps[0];
|
|
46
|
+
const isPaywall = step === steps.length;
|
|
43
47
|
|
|
44
48
|
const onStepChange = useCallback(
|
|
45
49
|
(stepNumber: number) => {
|
|
@@ -47,6 +51,9 @@ function SpillOnboarding({
|
|
|
47
51
|
if (index === -1) {
|
|
48
52
|
return 'Intro';
|
|
49
53
|
}
|
|
54
|
+
if (index === steps.length) {
|
|
55
|
+
return 'Paywall';
|
|
56
|
+
}
|
|
50
57
|
const s = steps[index];
|
|
51
58
|
if (!s) {
|
|
52
59
|
return 'Unknown';
|
|
@@ -69,14 +76,19 @@ function SpillOnboarding({
|
|
|
69
76
|
setStep(stepNumber);
|
|
70
77
|
onStepChangeProps?.(stepNumber);
|
|
71
78
|
|
|
72
|
-
trackEvent(
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
79
|
+
trackEvent(
|
|
80
|
+
apiKey,
|
|
81
|
+
'step_change',
|
|
82
|
+
{
|
|
83
|
+
from_index: step,
|
|
84
|
+
to_index: stepNumber,
|
|
85
|
+
from_step: fromStepName,
|
|
86
|
+
to_step: toStepName,
|
|
87
|
+
},
|
|
88
|
+
isDev
|
|
89
|
+
);
|
|
78
90
|
},
|
|
79
|
-
[onStepChangeProps, apiKey, step, steps]
|
|
91
|
+
[onStepChangeProps, apiKey, step, steps, isDev]
|
|
80
92
|
);
|
|
81
93
|
|
|
82
94
|
useEffect(() => {
|
|
@@ -120,7 +132,11 @@ function SpillOnboarding({
|
|
|
120
132
|
|
|
121
133
|
const onNextPress = () => {
|
|
122
134
|
if (step === steps.length - 1) {
|
|
123
|
-
|
|
135
|
+
if (paywallPanelProps) {
|
|
136
|
+
onStepChange(steps.length);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
trackEvent(apiKey, 'complete', {}, isDev);
|
|
124
140
|
return onComplete();
|
|
125
141
|
}
|
|
126
142
|
|
|
@@ -158,6 +174,27 @@ function SpillOnboarding({
|
|
|
158
174
|
);
|
|
159
175
|
};
|
|
160
176
|
|
|
177
|
+
const onPaywallContinue = (planId: string) => {
|
|
178
|
+
trackEvent(apiKey, 'paywall_select', { plan_id: planId }, isDev);
|
|
179
|
+
trackEvent(apiKey, 'complete', { plan_id: planId }, isDev);
|
|
180
|
+
onComplete(planId);
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
const renderPaywallPanel = () => {
|
|
184
|
+
if (!paywallPanelProps) return null;
|
|
185
|
+
|
|
186
|
+
if (typeof paywallPanelProps === 'function') {
|
|
187
|
+
return paywallPanelProps({ onPressContinue: onPaywallContinue });
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
return (
|
|
191
|
+
<OnboardingPaywallPanel
|
|
192
|
+
onPressContinue={onPaywallContinue}
|
|
193
|
+
{...paywallPanelProps}
|
|
194
|
+
/>
|
|
195
|
+
);
|
|
196
|
+
};
|
|
197
|
+
|
|
161
198
|
const renderStepContent = () => {
|
|
162
199
|
if (!currentStep) {
|
|
163
200
|
return null;
|
|
@@ -185,12 +222,17 @@ function SpillOnboarding({
|
|
|
185
222
|
};
|
|
186
223
|
|
|
187
224
|
const currentStepImage: ImageSourcePropType | undefined = useMemo(() => {
|
|
225
|
+
if (isPaywall) {
|
|
226
|
+
// Paywall image is rendered inside the panel scrollview
|
|
227
|
+
return undefined;
|
|
228
|
+
}
|
|
229
|
+
|
|
188
230
|
if (!currentStep) {
|
|
189
231
|
return firstStep?.image;
|
|
190
232
|
}
|
|
191
233
|
|
|
192
234
|
return currentStep.image;
|
|
193
|
-
}, [currentStep, firstStep?.image]);
|
|
235
|
+
}, [currentStep, firstStep?.image, isPaywall]);
|
|
194
236
|
|
|
195
237
|
const onboardingContent = (
|
|
196
238
|
<View style={styles.container} ref={screen.ref}>
|
|
@@ -210,15 +252,19 @@ function SpillOnboarding({
|
|
|
210
252
|
background={background}
|
|
211
253
|
/>
|
|
212
254
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
255
|
+
{isPaywall ? (
|
|
256
|
+
<View style={styles.fullScreenPanel}>{renderPaywallPanel()}</View>
|
|
257
|
+
) : (
|
|
258
|
+
<OnboardingStepContainer
|
|
259
|
+
currentStep={currentStep}
|
|
260
|
+
animationDuration={animationDuration}
|
|
261
|
+
showCloseButton={showCloseButton}
|
|
262
|
+
renderStepContent={renderStepContent}
|
|
263
|
+
onSkip={onSkip}
|
|
264
|
+
ref={stepPanel.ref}
|
|
265
|
+
skipButton={skipButton}
|
|
266
|
+
/>
|
|
267
|
+
)}
|
|
222
268
|
</View>
|
|
223
269
|
);
|
|
224
270
|
|
|
@@ -248,4 +294,8 @@ const createStyles = (theme: Theme) =>
|
|
|
248
294
|
left: 0,
|
|
249
295
|
right: 0,
|
|
250
296
|
},
|
|
297
|
+
fullScreenPanel: {
|
|
298
|
+
flex: 1,
|
|
299
|
+
zIndex: 10,
|
|
300
|
+
},
|
|
251
301
|
});
|