mirror of
https://github.com/siop-spelev/siop2.git
synced 2026-08-08 12:41:54 +00:00
feat(r6): mobile ouvert à tous les rôles — maquette + socle R6.1
R4 avait délibérément fermé le mobile au Technicien. Le référent demande l'ouverture à tous les rôles avec les mêmes droits qu'au web — nouvelle release R6 (R4 est close, R4.1/4.2/4.3 déjà pris par le socle mobile technicien d'origine, pas de réouverture ni de collision de numérotation). Maquette (docs/02-design/maquettes/maquette-mobile-tous-roles.html, 7 écrans) validée par le référent : D1 barre d'onglets adaptative par rôle (Technicien/Technicien limité inchangés + onglet Menu ajouté) ; D2 le Menu reprend à l'identique les 4 groupes du web, même matrice de permissions ; D3 groupe sans lien visible masqué en entier ; D4 le mobile porte les actions courantes par famille, pas les flux de gestion les plus denses ; D5 aucune logique de permission propre au mobile. R6.1 — socle : usePermissions() mobile calqué sur le web ; barre d'onglets adaptative (ongletsVisibles par rôle, href:null masque sans retirer du navigateur) ; Accueil (dashboard réel pour Administrateur/Gestionnaire/ Dispatcher/Vue seule, aucun chiffre inventé) ; OT (liste complète, viewOther déjà géré serveur, réutilise la fiche OT R4 telle quelle) ; Menu (groupes filtrés, vide masqué) ; Demandes (PanneauDemandes — un seul composant pour tous les rôles : création/suivi Demandeur, approbation/ rejet Gestionnaire/Dispatcher/Administrateur, lecture Vue seule). Familles pas encore portées : écran « à venir » plutôt qu'un lien mort. Typecheck propre, 17 tests Jest, lint 5/5 paquets. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,12 +1,19 @@
|
||||
import { Tabs } from 'expo-router';
|
||||
import { Text, type ColorValue } from 'react-native';
|
||||
import { useAssets, useReferenceValues } from '@/api/exploitation';
|
||||
import { useMe } from '@/auth/session';
|
||||
import { ongletsVisibles } from '@/auth/roles';
|
||||
import { usePermissions } from '@/auth/use-permissions';
|
||||
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 ». */
|
||||
/** Barre d'onglets ADAPTATIVE (maquette « mobile ouvert à tous les rôles »,
|
||||
* D1) : le Technicien/Technicien limité gardent exactement leurs 4 onglets
|
||||
* terrain R4, inchangés. Les autres rôles reçoivent Accueil/OT/Menu (ou une
|
||||
* variante plus étroite — Demandeur, Vue seule — selon leurs droits,
|
||||
* `ongletsVisibles`). Tous les écrans sont toujours déclarés : `href: null`
|
||||
* masque un onglet de la barre sans le retirer du navigateur (le Menu peut
|
||||
* toujours y pousser directement). */
|
||||
|
||||
function Pic({ glyphe, couleur }: { glyphe: string; couleur: ColorValue }) {
|
||||
return <Text style={{ fontSize: 17, color: couleur, lineHeight: 20 }}>{glyphe}</Text>;
|
||||
@@ -16,10 +23,19 @@ export default function CoquilleTabs() {
|
||||
const t = useTokens();
|
||||
const file = useFile();
|
||||
const conflits = file.some((s) => s.statut === 'CONFLIT');
|
||||
const { data: me } = useMe();
|
||||
const { can } = usePermissions();
|
||||
const visibles = ongletsVisibles(me?.role.name);
|
||||
// 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();
|
||||
// Le Demandeur n'a pas ASSETS.view (seulement /assets/options) : inutile
|
||||
// d'appeler /assets pour lui, l'API répondrait 403.
|
||||
const peutAssets = can('ASSETS', 'view');
|
||||
useAssets({ enabled: peutAssets });
|
||||
useReferenceValues({ enabled: peutAssets });
|
||||
|
||||
const cacher = (nom: string) => (visibles.has(nom) ? undefined : null);
|
||||
|
||||
return (
|
||||
<Tabs
|
||||
screenOptions={{
|
||||
@@ -34,6 +50,7 @@ export default function CoquilleTabs() {
|
||||
<Tabs.Screen
|
||||
name="journee"
|
||||
options={{
|
||||
href: cacher('journee'),
|
||||
title: 'Ma journée',
|
||||
tabBarIcon: ({ color }) => <Pic glyphe="☰" couleur={color} />,
|
||||
}}
|
||||
@@ -41,6 +58,7 @@ export default function CoquilleTabs() {
|
||||
<Tabs.Screen
|
||||
name="scanner"
|
||||
options={{
|
||||
href: cacher('scanner'),
|
||||
title: 'Scanner',
|
||||
tabBarIcon: ({ color }) => <Pic glyphe="▣" couleur={color} />,
|
||||
}}
|
||||
@@ -48,6 +66,7 @@ export default function CoquilleTabs() {
|
||||
<Tabs.Screen
|
||||
name="preventif"
|
||||
options={{
|
||||
href: cacher('preventif'),
|
||||
title: 'Préventif',
|
||||
tabBarIcon: ({ color }) => <Pic glyphe="✓" couleur={color} />,
|
||||
}}
|
||||
@@ -55,6 +74,7 @@ export default function CoquilleTabs() {
|
||||
<Tabs.Screen
|
||||
name="synchro"
|
||||
options={{
|
||||
href: cacher('synchro'),
|
||||
title: 'Synchro',
|
||||
tabBarIcon: ({ color }) => <Pic glyphe="⇅" couleur={color} />,
|
||||
tabBarBadge: file.length || undefined,
|
||||
@@ -66,6 +86,38 @@ export default function CoquilleTabs() {
|
||||
},
|
||||
}}
|
||||
/>
|
||||
<Tabs.Screen
|
||||
name="accueil"
|
||||
options={{
|
||||
href: cacher('accueil'),
|
||||
title: 'Accueil',
|
||||
tabBarIcon: ({ color }) => <Pic glyphe="⌂" couleur={color} />,
|
||||
}}
|
||||
/>
|
||||
<Tabs.Screen
|
||||
name="ot"
|
||||
options={{
|
||||
href: cacher('ot'),
|
||||
title: 'OT',
|
||||
tabBarIcon: ({ color }) => <Pic glyphe="☰" couleur={color} />,
|
||||
}}
|
||||
/>
|
||||
<Tabs.Screen
|
||||
name="nouvelle-demande"
|
||||
options={{
|
||||
href: cacher('nouvelle-demande'),
|
||||
title: 'Nouvelle demande',
|
||||
tabBarIcon: ({ color }) => <Pic glyphe="+" couleur={color} />,
|
||||
}}
|
||||
/>
|
||||
<Tabs.Screen
|
||||
name="menu"
|
||||
options={{
|
||||
href: cacher('menu'),
|
||||
title: 'Menu',
|
||||
tabBarIcon: ({ color }) => <Pic glyphe="☷" couleur={color} />,
|
||||
}}
|
||||
/>
|
||||
</Tabs>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user