mirror of
https://github.com/siop-spelev/siop2.git
synced 2026-08-08 20:51:53 +00:00
Serveur : updatedAt exposé au détail OT ; baseUpdatedAt optionnel sur transition/coche/bilan → 409 « Conflit de version » contextualisé (qui, quand) ; toute écriture secondaire (coche, bilan, commentaire, conso, MO) fait avancer la version — sans version fournie, le web est inchangé. ADR-003 : sécurité & protocole de routage mobile (qui vit où sur l'appareil, purge complète à la déconnexion — correctif réel : la file et le cache persisté survivaient au logout). Mobile : file persistée AsyncStorage rejouée dans l'ordre — succès → propagation de la version fraîche aux saisies restantes du même OT (nos écritures ne se conflictent pas entre elles, un écart étranger reste détecté) ; coupure → tout attend ; refus → CONFLIT, la file s'arrête, l'humain tranche (voir l'OT / rejouer sur version à jour / abandonner). Transitions, coches, bilan et photos (D5, compressées ~1600 px) passent par la file avec patch optimiste du cache ; écran Synchro (badge tabbar ambre/rouge) ; préchargement parc + référentiels (le bilan hors-ligne a ses vocabulaires). Recette « mode avion » 13/13 en Expo web piloté : gestes hors-ligne → 3 en file → modification concurrente de Salma → conflit tranché → serveur Terminé avec bilan. 17 tests jest-expo, 74 tests API. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
72 lines
2.3 KiB
TypeScript
72 lines
2.3 KiB
TypeScript
import { Tabs } from 'expo-router';
|
|
import { Text, type ColorValue } from 'react-native';
|
|
import { useAssets, useReferenceValues } from '@/api/exploitation';
|
|
import { useFile } from '@/file/store';
|
|
import { useTokens } from '@/theme/tokens';
|
|
|
|
/** La tabbar de la maquette R4. Les onglets à venir restent visibles
|
|
* (périmètre annoncé, même patron que la sidebar web) mais mènent à un
|
|
* écran « disponible en R4.x ». */
|
|
|
|
function Pic({ glyphe, couleur }: { glyphe: string; couleur: ColorValue }) {
|
|
return <Text style={{ fontSize: 17, color: couleur, lineHeight: 20 }}>{glyphe}</Text>;
|
|
}
|
|
|
|
export default function CoquilleTabs() {
|
|
const t = useTokens();
|
|
const file = useFile();
|
|
const conflits = file.some((s) => s.statut === 'CONFLIT');
|
|
// D1 « lecture locale » : le parc (scan D4) et les référentiels du bilan
|
|
// se préchargent dès l'entrée — le sous-sol n'attend pas qu'on y pense.
|
|
useAssets();
|
|
useReferenceValues();
|
|
return (
|
|
<Tabs
|
|
screenOptions={{
|
|
headerShown: false,
|
|
tabBarActiveTintColor: t.primaire,
|
|
tabBarInactiveTintColor: t.encre3,
|
|
tabBarStyle: { backgroundColor: t.surface, borderTopColor: t.bordure },
|
|
tabBarLabelStyle: { fontFamily: 'Manrope_700Bold', fontSize: 10 },
|
|
sceneStyle: { backgroundColor: t.fond },
|
|
}}
|
|
>
|
|
<Tabs.Screen
|
|
name="journee"
|
|
options={{
|
|
title: 'Ma journée',
|
|
tabBarIcon: ({ color }) => <Pic glyphe="☰" couleur={color} />,
|
|
}}
|
|
/>
|
|
<Tabs.Screen
|
|
name="scanner"
|
|
options={{
|
|
title: 'Scanner',
|
|
tabBarIcon: ({ color }) => <Pic glyphe="▣" couleur={color} />,
|
|
}}
|
|
/>
|
|
<Tabs.Screen
|
|
name="preventif"
|
|
options={{
|
|
title: 'Préventif',
|
|
tabBarIcon: ({ color }) => <Pic glyphe="✓" couleur={color} />,
|
|
}}
|
|
/>
|
|
<Tabs.Screen
|
|
name="synchro"
|
|
options={{
|
|
title: 'Synchro',
|
|
tabBarIcon: ({ color }) => <Pic glyphe="⇅" couleur={color} />,
|
|
tabBarBadge: file.length || undefined,
|
|
tabBarBadgeStyle: {
|
|
backgroundColor: conflits ? t.prioBloque : t.stAttente,
|
|
color: '#fff',
|
|
fontFamily: 'Manrope_800ExtraBold',
|
|
fontSize: 10,
|
|
},
|
|
}}
|
|
/>
|
|
</Tabs>
|
|
);
|
|
}
|