feat: explore tab, React Query data layer, programs, sync, analytics, testing infrastructure
- Replace browse tab with Supabase-connected explore tab with filters - Add React Query for data fetching with loading states - Add 3 structured programs with weekly progression - Add Supabase anonymous auth sync service - Add PostHog analytics with screen tracking and events - Add comprehensive test strategy (Vitest + Maestro E2E) - Add RevenueCat subscription system with DEV simulation - Add i18n translations for new screens (EN/FR/DE/ES) - Add data deletion modal, sync consent modal - Add assessment screen and program routes - Add GitHub Actions CI workflow - Update activity store with sync integration
This commit is contained in:
@@ -116,6 +116,7 @@ function ProblemScreen({ onNext }: { onNext: () => void }) {
|
||||
<View style={styles.bottomAction}>
|
||||
<Pressable
|
||||
style={styles.ctaButton}
|
||||
testID="onboarding-problem-cta"
|
||||
onPress={() => {
|
||||
haptics.buttonTap()
|
||||
onNext()
|
||||
@@ -179,6 +180,7 @@ function EmpathyScreen({
|
||||
return (
|
||||
<Pressable
|
||||
key={item.id}
|
||||
testID={`barrier-${item.id}`}
|
||||
style={[
|
||||
styles.barrierCard,
|
||||
selected && styles.barrierCardSelected,
|
||||
@@ -206,6 +208,7 @@ function EmpathyScreen({
|
||||
<View style={styles.bottomAction}>
|
||||
<Pressable
|
||||
style={[styles.ctaButton, barriers.length === 0 && styles.ctaButtonDisabled]}
|
||||
testID="onboarding-empathy-continue"
|
||||
onPress={() => {
|
||||
if (barriers.length > 0) {
|
||||
haptics.buttonTap()
|
||||
@@ -350,6 +353,7 @@ function SolutionScreen({ onNext }: { onNext: () => void }) {
|
||||
<View style={styles.bottomAction}>
|
||||
<Pressable
|
||||
style={styles.ctaButton}
|
||||
testID="onboarding-solution-cta"
|
||||
onPress={() => {
|
||||
haptics.buttonTap()
|
||||
onNext()
|
||||
@@ -467,6 +471,7 @@ function WowScreen({ onNext }: { onNext: () => void }) {
|
||||
<Animated.View style={[styles.bottomAction, { opacity: ctaOpacity }]}>
|
||||
<Pressable
|
||||
style={styles.ctaButton}
|
||||
testID="onboarding-wow-cta"
|
||||
onPress={() => {
|
||||
if (ctaReady) {
|
||||
haptics.buttonTap()
|
||||
@@ -556,6 +561,7 @@ function PersonalizationScreen({
|
||||
placeholderTextColor={colors.text.hint}
|
||||
autoCapitalize="words"
|
||||
autoCorrect={false}
|
||||
testID="name-input"
|
||||
/>
|
||||
</View>
|
||||
|
||||
@@ -568,6 +574,7 @@ function PersonalizationScreen({
|
||||
{LEVELS.map((item) => (
|
||||
<Pressable
|
||||
key={item.value}
|
||||
testID={`level-${item.value}`}
|
||||
style={[
|
||||
styles.segmentButton,
|
||||
level === item.value && styles.segmentButtonActive,
|
||||
@@ -598,6 +605,7 @@ function PersonalizationScreen({
|
||||
{GOALS.map((item) => (
|
||||
<Pressable
|
||||
key={item.value}
|
||||
testID={`goal-${item.value}`}
|
||||
style={[
|
||||
styles.segmentButton,
|
||||
goal === item.value && styles.segmentButtonActive,
|
||||
@@ -628,6 +636,7 @@ function PersonalizationScreen({
|
||||
{FREQUENCIES.map((item) => (
|
||||
<Pressable
|
||||
key={item.value}
|
||||
testID={`frequency-${item.value}x`}
|
||||
style={[
|
||||
styles.segmentButton,
|
||||
frequency === item.value && styles.segmentButtonActive,
|
||||
@@ -658,6 +667,7 @@ function PersonalizationScreen({
|
||||
<View style={{ marginTop: SPACING[8] }}>
|
||||
<Pressable
|
||||
style={[styles.ctaButton, !name.trim() && styles.ctaButtonDisabled]}
|
||||
testID="onboarding-personalization-continue"
|
||||
onPress={() => {
|
||||
if (name.trim()) {
|
||||
haptics.buttonTap()
|
||||
@@ -828,6 +838,7 @@ function PaywallScreen({
|
||||
<View style={styles.pricingCards}>
|
||||
{/* Annual */}
|
||||
<Pressable
|
||||
testID="plan-yearly"
|
||||
style={[
|
||||
styles.pricingCard,
|
||||
selectedPlan === 'premium-yearly' && styles.pricingCardSelected,
|
||||
@@ -852,6 +863,7 @@ function PaywallScreen({
|
||||
|
||||
{/* Monthly */}
|
||||
<Pressable
|
||||
testID="plan-monthly"
|
||||
style={[
|
||||
styles.pricingCard,
|
||||
selectedPlan === 'premium-monthly' && styles.pricingCardSelected,
|
||||
@@ -870,6 +882,7 @@ function PaywallScreen({
|
||||
{/* CTA */}
|
||||
<Pressable
|
||||
style={[styles.trialButton, isPurchasing && styles.ctaButtonDisabled]}
|
||||
testID="subscribe-button"
|
||||
onPress={handlePurchase}
|
||||
disabled={isPurchasing}
|
||||
>
|
||||
@@ -886,17 +899,21 @@ function PaywallScreen({
|
||||
</View>
|
||||
|
||||
{/* Restore Purchases */}
|
||||
<Pressable style={styles.restoreButton} onPress={handleRestore}>
|
||||
<Pressable style={styles.restoreButton} onPress={handleRestore} testID="restore-purchases">
|
||||
<StyledText size={14} color={colors.text.hint}>
|
||||
{t('onboarding.paywall.restorePurchases')}
|
||||
</StyledText>
|
||||
</Pressable>
|
||||
|
||||
{/* Skip */}
|
||||
<Pressable style={styles.skipButton} onPress={() => {
|
||||
track('onboarding_paywall_skipped')
|
||||
onSkip()
|
||||
}}>
|
||||
<Pressable
|
||||
style={styles.skipButton}
|
||||
testID="skip-paywall"
|
||||
onPress={() => {
|
||||
track('onboarding_paywall_skipped')
|
||||
onSkip()
|
||||
}}
|
||||
>
|
||||
<StyledText size={14} color={colors.text.hint}>
|
||||
{t('onboarding.paywall.skipButton')}
|
||||
</StyledText>
|
||||
@@ -1241,6 +1258,7 @@ function createStyles(colors: ThemeColors) {
|
||||
flex: 1,
|
||||
paddingVertical: SPACING[5],
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
borderRadius: RADIUS.GLASS_CARD,
|
||||
...colors.glass.base,
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user