mirror of
https://github.com/siop-spelev/siop2.git
synced 2026-08-08 12:41:54 +00:00
feat(r4.1): socle mobile Expo — connexion démo, Ma journée, lecture hors-ligne
apps/mobile (Expo SDK 57, TS strict, workspace pnpm) : connexion e-mail/mdp + sélecteur démo ADR-002 (uniquement si l'API l'expose), tabbar de la maquette validée (onglets futurs marqués R4.2/R4.3), « Ma journée » triée priorité puis échéance (fonction pure testée), urgence en tête, pastille de synchro. D1 en actes (lecture) : cache TanStack persisté dans AsyncStorage (7 jours), NetInfo → onlineManager + bandeau hors-ligne horodaté ; jeton en SecureStore ; tokens light/dark répliqués et testés ; client typé régénéré depuis docs/openapi.json (règle d'or). API : CORS_ORIGINS opt-in (vide par défaut) — Expo web/debug seulement, le web de prod reste derrière le proxy, les apps natives n'ont pas d'Origin. Vérifié 10/10 en Expo web piloté (connexion démo Ahmed → Ma journée scopée → hors-ligne servie du cache → retour) ; 6 tests jest-expo ; lint racine étendu (react-hooks) ; job CI mobile, deploy en dépend. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
77
apps/mobile/app/_layout.tsx
Normal file
77
apps/mobile/app/_layout.tsx
Normal file
@@ -0,0 +1,77 @@
|
||||
import {
|
||||
Manrope_400Regular,
|
||||
Manrope_600SemiBold,
|
||||
Manrope_700Bold,
|
||||
Manrope_800ExtraBold,
|
||||
useFonts,
|
||||
} from '@expo-google-fonts/manrope';
|
||||
import NetInfo from '@react-native-community/netinfo';
|
||||
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||
import { createAsyncStoragePersister } from '@tanstack/query-async-storage-persister';
|
||||
import { onlineManager, QueryClient } from '@tanstack/react-query';
|
||||
import { PersistQueryClientProvider } from '@tanstack/react-query-persist-client';
|
||||
import { Stack } from 'expo-router';
|
||||
import { StatusBar } from 'expo-status-bar';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { HorsLigneProvider } from '@/auth/session';
|
||||
import { useTokens } from '@/theme/tokens';
|
||||
|
||||
/** Racine de l'app (D1 validée) : le cache TanStack est PERSISTÉ dans
|
||||
* AsyncStorage — les OT lus restent lisibles hors-ligne, y compris après
|
||||
* redémarrage. NetInfo pilote onlineManager (pas de retry dans le vide)
|
||||
* et le drapeau hors-ligne des écrans. */
|
||||
|
||||
const queryClient = new QueryClient({
|
||||
defaultOptions: {
|
||||
queries: {
|
||||
staleTime: 60_000,
|
||||
gcTime: 7 * 24 * 3600_000, // une semaine de lecture hors-ligne
|
||||
retry: 1,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const persister = createAsyncStoragePersister({
|
||||
storage: AsyncStorage,
|
||||
key: 'siop.cache',
|
||||
});
|
||||
|
||||
export default function RacineApp() {
|
||||
const t = useTokens();
|
||||
const [horsLigne, setHorsLigne] = useState(false);
|
||||
const [polices] = useFonts({
|
||||
Manrope_400Regular,
|
||||
Manrope_600SemiBold,
|
||||
Manrope_700Bold,
|
||||
Manrope_800ExtraBold,
|
||||
});
|
||||
|
||||
useEffect(
|
||||
() =>
|
||||
NetInfo.addEventListener((etat) => {
|
||||
const enLigne = !!etat.isConnected;
|
||||
onlineManager.setOnline(enLigne);
|
||||
setHorsLigne(!enLigne);
|
||||
}),
|
||||
[],
|
||||
);
|
||||
|
||||
if (!polices) return null;
|
||||
|
||||
return (
|
||||
<PersistQueryClientProvider
|
||||
client={queryClient}
|
||||
persistOptions={{ persister, maxAge: 7 * 24 * 3600_000 }}
|
||||
>
|
||||
<HorsLigneProvider valeur={horsLigne}>
|
||||
<StatusBar style="auto" />
|
||||
<Stack
|
||||
screenOptions={{
|
||||
headerShown: false,
|
||||
contentStyle: { backgroundColor: t.fond },
|
||||
}}
|
||||
/>
|
||||
</HorsLigneProvider>
|
||||
</PersistQueryClientProvider>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user