Navigation
L'arbre des navigateurs, les noms de routes, la garde d'authentification et les conventions de navigation.
Stack
React Navigation v7. Navigateurs utilisés :
| Package | Rôle |
|---|---|
@react-navigation/native |
NavigationContainer |
@react-navigation/native-stack |
toutes les stacks (createNativeStackNavigator) |
@react-navigation/bottom-tabs |
la barre d'onglets racine |
@react-navigation/material-top-tabs |
les onglets dans l'écran de détail Projet |
@react-navigation/stack |
types uniquement (pour StackNavigationProp) ; aucun createStackNavigator n'est instancié |
Pas de drawer navigator. enableScreens(false) est appelé dans src/App.tsx (native screens désactivés).
Où il est monté
L'unique <NavigationContainer> vit dans src/components/Navigation/NavigationProvider.tsx, monté en bas de l'arbre des providers (voir architecture.md). Deux factories sont créées au niveau du module :
const Tab = createBottomTabNavigator();
export const Stack = createNativeStackNavigator(); // réutilisée par les sous-stacks partagées commonScreen
Arbre des navigateurs
NavigationContainer
└── Tab.Navigator (bottom-tabs, headerShown:false) NavigationProvider.tsx
│ tabBar masquée quand il n'y a pas de token.access_token
├── Home → HomeController
├── ProjectsStack → ProjectsStackScreen (rend UnregistrerStackScreen si pas de token)
│ ├── ProjectsTab → ProjectsTabController
│ ├── ProjectDetail → ProjectScreenTabParent
│ │ └── Tab.Navigator (material-top-tabs) ProjectScreenTabParent.tsx
│ │ ├── ProjectSensorsTab
│ │ ├── ProjectPlansTab
│ │ └── ProjectParametersTab (→ UnitPreference, ShareProject, Thresholds, Alerts…)
│ ├── AddProjectsScreen / EditProjectScreen
│ ├── AddModule / AddTechnicalModule / AddDeformationModuleForm / AddModuleSensor
│ ├── SensorMecaDetails / AddMeasure / AddPlan / PlanScreen
│ ├── AddSensorStack / ElecSensorStack / GatewayStack (sous-stacks partagées imbriquées, ci-dessous)
│ ├── ListGatewaySensors / ScanGateways / SaveGateway
│ ├── SyncManager
│ ├── ModuleDetail / ModuleConfiguration / ModuleThresholds / …
│ ├── ModuleSensorsResync (presentation: 'modal')
│ ├── ModuleSensorsChangeInterval (presentation: 'transparentModal', fade)
│ ├── ModulePutSensorsInStock (transparentModal, fade)
│ ├── ModuleSensorSAVRepport (transparentModal, fade)
│ ├── ModuleExportCsv (transparentModal, fade)
│ ├── Map (presentation: 'modal')
│ ├── Archive* / ProjectThresholds / ShareProject / ProjectAlerts
│ └── UnitPreference (feature : features/unitPreference)
│
├── SensorsStack → SoleSensorsStackScreen (rend UnregistrerStackScreen si pas de token)
│ ├── SoleSensors → SoleSensorController
│ ├── AddSensor / ScanSensors / SaveSensor / AddSoleSensorToProject
│ ├── AddSensorStack / ElecSensorStack (sous-stacks partagées imbriquées)
│ ├── SyncManager
│ └── Map (presentation: 'modal')
│
└── [4e onglet conditionnel]
├── (token) MyAccountStack → MyAccountStackScreen
│ ├── MyAccount / MyInformations / MyNotifications / MyPreferences
│ ├── Wallet / BuyFeatures / Cart
│ ├── OurOffers / OffersMyCart / MyCurrentOffers
│ ├── ValidateCode / PurchaseToken / HelpContact / SyncManager
│ └── Swap (presentation: 'modal')
│
└── (pas de token) UnregistrerStack → UnregistrerStackScreen
├── Welcome (headerShown:false)
├── Register / Login / ForgotPassword
└── AddSuccess
Native-stacks imbriquées partagées (construites depuis la factory Stack exportée, headerShown:false) :
AddSensorStack → AddSensor, ScanSensors, SaveSensor, ScanGateways, SaveGateway
ElecSensorStack → SensorElecDetail, SensorConfiguration, SensorConfigureThresholds,
SensorDistantActions, LiveView, ActionsPage
GatewayStack → GatewayDetail, GatewayConfiguration, GatewayPlannedActions, ListGatewaySensors
Warning
Certains noms de routes se répètent entre stacks (SyncManager, Map, AddSensor, ScanSensors, SaveGateway, AddSuccess). La résolution est relative au navigateur auquel appartient l'écran appelant.
Listes de paramètres typées
Les listes de paramètres vivent dans src/components/Navigation/types/ (alias NavigationTypes), un fichier par stack :
| Fichier | Liste(s) de paramètres |
|---|---|
mainNav.ts |
RootStackParamList (niveau onglets) + RootNavigationProp |
Projects.ts |
ProjectsStackParamList (~40 routes) |
Sensors.ts |
SoleSensorsStackParamList |
MyAccount.ts |
UnregisterStackParamList + RegisterStackParamList |
commonScreen/{AddSensor,ElecSensor,Gateway}.ts |
les trois sous-stacks partagées |
theme.ts |
hook useAppTheme() (pas une liste de paramètres) |
// mainNav.ts
type RootStackParamList = {
Home: undefined;
ProjectsStack: NavigatorScreenParams<ProjectsStackParamList>;
SensorsStack: NavigatorScreenParams<SoleSensorsStackParamList>;
MyAccountStack: NavigatorScreenParams<RegisterStackParamList>;
UnregistrerStack: NavigatorScreenParams<UnregisterStackParamList>;
};
Convention par stack : export type XStackNavigationProp = StackNavigationProp<XStackParamList> et un alias RouteProp par écran. Les écrans les consomment via des hooks typés :
const navigation = useNavigation<ProjectsStackNavigationProp>();
const route = useRoute<ProjectDetailScreenRouteProp>();
Warning
Les navigateurs eux-mêmes sont créés non typés (createNativeStackNavigator() sans générique), donc les types de paramètres ne sont imposés qu'aux sites d'appel via les génériques du hook — pas à l'enregistrement des <Stack.Screen>. Attention à la dérive (quelques routes typées n'ont pas d'écran enregistré et inversement).
Garde d'authentification
Il n'y a aucun basculement impératif de navigateur à la connexion — l'authentification est purement réactive sur le token Redux (store/ducks/token, persisté). Chaque garde vérifie !isNil(token?.access_token) :
NavigationProvidermasque la barre d'onglets et échange le 4e onglet (MyAccountStackvsUnregistrerStack).ProjectsStackScreen/SoleSensorsStackScreenrendent<UnregistrerStackScreen />quand il n'y a pas de token.Login.tsxdispatchesetToken(...); le changement Redux re-rend les gardes et révèle l'UI authentifiée (pas denavigation.reset).
Modales & overlays
Pas de navigateur de modale dédié — les modales utilisent les options presentation de native-stack :
presentation: 'modal'—Map,ModuleSensorsResync,Swap.presentation: 'transparentModal'+animation: 'fade'— les overlays Module*.
Les overlays globaux sont rendus comme frères du navigateur à l'intérieur de NavigationProvider (pas des écrans) : FirmwareUpdate, MessageAlert, HandleSyncMutationOnline, InfoDialog, LoadingAlert, plus le Portal.Host de Paper.
Deep linking
Aucun configuré. <NavigationContainer> n'a pas de prop linking. Le seul Linking.openURL est la redirection de mise à jour du store dans components/VersionChecker. Les notifications push Firebase ne routent pas vers la navigation.
Conventions
- Le hook
useNavigation()est le pattern principal (forme générique typée). Aucun service/ref de navigation personnalisé n'existe. - La
refduNavigationContainersert uniquement à enregistrer l'instrumentation de routing Sentry (Sentry.reactNavigationIntegration()), pas à de la navigation impérative. - La navigation inter-stacks utilise la forme objet :
navigation.navigate('ProjectsStack', { screen: 'ProjectsTab' }). - Le flux « succès » après ajout utilise
CommonActions.resetpour atterrir sur l'écran de détail du nouvel appareil. - La plupart des stacks authentifiées injectent
<SyncManagerButton />enheaderRightviaGET_SCREEN_OPTIONS(colors)(Stack/constant.ts) ;MyAccountStackpréfixe aussi<CartButton />. - Les onglets inactifs sont démontés de force via le wrapper de layout
UnmountOnBlur. - Le thème des en-têtes découle de
useAppTheme()+themeModeRedux, combinant les thèmes Paper et React Navigation.
Fichiers clés
src/components/Navigation/NavigationProvider.tsx— container + ongletssrc/components/Navigation/Stack/*StackScreen.tsx— les quatre stacks principalessrc/components/Navigation/Stack/commonScreen/*.tsx— sous-stacks partagéessrc/components/Navigation/Stack/constant.ts— options d'écran partagéessrc/components/Navigation/types/*— listes de paramètres (aliasNavigationTypes)