Grapevine_Disease_Detection/VinEye/App.tsx
Yanis 05e28b3ebc feat(auth): onboarding flow + local auth (no backend)
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>
2026-05-01 09:33:27 +02:00

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>
);
}