Onboarding flow

This commit is contained in:
2026-07-06 22:25:52 +02:00
parent 99cd885833
commit 6b57a2acfc
37 changed files with 1503 additions and 507 deletions

View File

@@ -14,7 +14,7 @@ import {
} from 'react-native';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { Ionicons } from '@expo/vector-icons';
import { router } from 'expo-router';
import { router, useLocalSearchParams } from 'expo-router';
import * as AppleAuthentication from 'expo-apple-authentication';
import Constants from 'expo-constants';
import { useApp } from '../../context/AppContext';
@@ -24,7 +24,7 @@ import { useSafeAnalytics } from '../../services/analytics';
import { PreAuthOnboardingService } from '../../services/preAuthOnboardingService';
import { Language } from '../../types';
const HERO_IMAGE = require('../../assets/welcome_botanical_hero.png');
const HERO_IMAGE = require('../../assets/welcome_hero_vertical.png');
const getCopy = (language: Language) => {
if (language === 'de') {
@@ -71,6 +71,7 @@ export default function LoginScreen() {
const colors = useColors(isDarkMode, colorPalette);
const copy = getCopy(language);
const posthog = useSafeAnalytics();
const params = useLocalSearchParams<{ returnTo?: string; topup?: string }>();
const isExpoGo = Constants.appOwnership === 'expo';
const [email, setEmail] = useState('');
@@ -106,6 +107,16 @@ export default function LoginScreen() {
if (session.isNewUser) {
await AsyncStorage.setItem('greenlens_show_tour', 'true');
}
const returnTo = Array.isArray(params.returnTo) ? params.returnTo[0] : params.returnTo;
const topup = Array.isArray(params.topup) ? params.topup[0] : params.topup;
if (returnTo === 'billing') {
router.replace({ pathname: '/profile/billing', params: topup ? { topup } : undefined });
return;
}
if (returnTo === 'paywall') {
router.replace('/profile/billing?view=paywall&context=out_of_credits');
return;
}
router.replace('/(tabs)');
};
@@ -181,12 +192,13 @@ export default function LoginScreen() {
style={[styles.flex, { backgroundColor: isDarkMode ? '#0a110b' : '#fbfaf3' }]}
behavior={Platform.OS === 'ios' ? 'padding' : undefined}
>
<TouchableOpacity style={styles.backBtn} onPress={() => router.back()} activeOpacity={0.8}>
<Ionicons name="arrow-back" size={20} color="#ffffff" />
</TouchableOpacity>
<ScrollView contentContainerStyle={styles.scroll} keyboardShouldPersistTaps="handled" showsVerticalScrollIndicator={false}>
<ImageBackground source={HERO_IMAGE} style={styles.hero} imageStyle={styles.heroImage}>
<View style={styles.heroOverlay} />
<TouchableOpacity style={styles.backBtn} onPress={() => router.back()} activeOpacity={0.8}>
<Ionicons name="arrow-back" size={20} color="#ffffff" />
</TouchableOpacity>
<View style={styles.heroCopy}>
<Text style={styles.heroTitle}>{copy.headline}</Text>
<Text style={styles.heroSubline}>{copy.subline}</Text>
@@ -283,7 +295,7 @@ export default function LoginScreen() {
)}
</TouchableOpacity>
<TouchableOpacity style={styles.signupLink} onPress={() => router.replace('/auth/signup')} activeOpacity={0.78}>
<TouchableOpacity style={styles.signupLink} onPress={() => router.replace({ pathname: '/auth/signup', params: { returnTo: params.returnTo, topup: params.topup } })} activeOpacity={0.78}>
<Text style={[styles.signupLinkText, { color: colors.textSecondary }]}>
{copy.newHere}{' '}
<Text style={{ color: colors.primary, fontWeight: '800' }}>{copy.create}</Text>
@@ -320,6 +332,8 @@ const styles = StyleSheet.create({
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'rgba(0, 0, 0, 0.28)',
zIndex: 10,
elevation: 10,
},
heroCopy: { gap: 10 },
heroTitle: {