Full local onboarding + auth stack (AsyncStorage only) :
types/auth.ts : User + AuthState
services/auth/
- authStorage.ts : AsyncStorage wrapper avec clés vineye:auth:{user,onboarding-done,terms-accepted-at}
- randomUser.ts : generateGuestUser() avec préfixes localisés FR/EN
(Sommelier/Vendangeur/Caviste/... + suffix Anonyme/Anonymous + #XXXX)
- authValidation.ts : Zod schema factory pour name/email
contexts/AuthContext.tsx : Provider + hook useAuth() avec login(),
loginAsGuest(), logout(), resetAccount(), acceptTerms(),
completeOnboarding(), isLoading hydraté au mount
components/onboarding/ :
- OnboardingButton : variants primary/secondary, loading, disabled
- TermsCheckbox : checkbox custom Reanimated avec scale + opacity anim
- EmailNameForm : form contrôlé avec validation Zod live + erreurs
affichées sous chaque champ après touch
screens/onboarding/ :
- WelcomeScreen : logo + 3 feature cards (Camera/Leaf/Brain) FadeInDown
stagger + CTA "Commencer"
- TermsScreen : 5 sections CGU (usage, dataCollected avec mention
explicite de la géoloc, responsibility, intellectualProperty, contact)
+ footer fixe avec checkbox + bouton continuer disabled tant que pas
coché
- AuthChoiceScreen : EmailNameForm + séparateur "ou" + bouton secondary
"Continuer en invité"
navigation/ :
- OnboardingNavigator : Stack Welcome -> Terms -> AuthChoice (animation
fade)
- RootNavigator : switch dynamique via useAuth().isOnboardingComplete ;
isLoading -> ActivityIndicator centré ; sinon render conditionnel
Onboarding ou Main
App.tsx : AuthProvider wrap autour de NetworkProvider
deps : zod ^4.4.1, expo-crypto ~15.0.9 (pour Crypto.randomUUID())
i18n FR + EN : blocs onboarding.{welcome,terms,authChoice} + auth.errors
+ settings.{account,language} (utilisés par le commit suivant)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
40 lines
1.4 KiB
TypeScript
40 lines
1.4 KiB
TypeScript
import 'react-native-gesture-handler';
|
|
import './global.css';
|
|
import { useEffect } from 'react';
|
|
import { Platform } from 'react-native';
|
|
import { StatusBar } from 'expo-status-bar';
|
|
import * as NavigationBar from 'expo-navigation-bar';
|
|
import { GestureHandlerRootView } from 'react-native-gesture-handler';
|
|
import { SafeAreaProvider } from 'react-native-safe-area-context';
|
|
import { Toaster } from 'sonner-native';
|
|
import { PortalHost } from '@rn-primitives/portal';
|
|
import { AuthProvider } from '@/contexts/AuthContext';
|
|
import { NetworkProvider } from '@/contexts/NetworkContext';
|
|
import { NetworkToastWatcher } from '@/contexts/ToastContext';
|
|
import RootNavigator from '@/navigation/RootNavigator';
|
|
|
|
export default function App() {
|
|
useEffect(() => {
|
|
if (Platform.OS === 'android') {
|
|
NavigationBar.setButtonStyleAsync('dark');
|
|
}
|
|
}, []);
|
|
|
|
return (
|
|
<GestureHandlerRootView style={{ flex: 1 }}>
|
|
<SafeAreaProvider>
|
|
<AuthProvider>
|
|
<NetworkProvider>
|
|
<NetworkToastWatcher>
|
|
<StatusBar style="dark" translucent backgroundColor="transparent" />
|
|
<RootNavigator />
|
|
<PortalHost />
|
|
<Toaster position="bottom-center" offset={120} />
|
|
</NetworkToastWatcher>
|
|
</NetworkProvider>
|
|
</AuthProvider>
|
|
</SafeAreaProvider>
|
|
</GestureHandlerRootView>
|
|
);
|
|
}
|