mirror of
https://github.com/siop-spelev/siop2.git
synced 2026-08-08 12:41:54 +00:00
fix(mobile): déconnexion accessible depuis tous les onglets
Bug remonté par le référent : une fois authentifié, impossible de revenir en arrière ou de se déconnecter. Seule « Ma journée » portait ce contrôle (onLongPress non découvrable) ; les 3 autres onglets n'avaient rien. EnteteTabs() factorise l'entête (composants/ui.tsx) : tap simple + confirmation Alert, rôle affiché = celui du compte connecté (plus de libellé "Technicien" figé — le mobile n'est plus réservé aux techniciens). Réutilisée dans les 4 onglets. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
import { router } from 'expo-router';
|
||||
import { useState, type ReactNode } from 'react';
|
||||
import { Modal, Pressable, ScrollView, Text, View } from 'react-native';
|
||||
import { Alert, Modal, Pressable, ScrollView, Text, View } from 'react-native';
|
||||
import { WORK_ORDER_STATUS_LABELS, type WorkOrderStatus } from '@siop/shared';
|
||||
import { useHorsLigne, useLogout, useMe } from '@/auth/session';
|
||||
import { useTokens, type Tokens } from '@/theme/tokens';
|
||||
|
||||
/** Briques d'écran de la maquette R4 — cartes, chips, boutons, sélecteur. */
|
||||
@@ -263,3 +264,76 @@ export function ChoixTel({
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
/** Entête commune à tous les onglets (D'où qu'on parte, on peut se
|
||||
* déconnecter — trouvée manquante en recette : seule « Ma journée » avait
|
||||
* ce contrôle, ailleurs l'utilisateur se sentait bloqué). Le rôle affiché
|
||||
* est CELUI du compte connecté, pas un libellé figé — le mobile n'est plus
|
||||
* réservé aux techniciens (voir décision élargissant le périmètre). */
|
||||
export function EnteteTabs() {
|
||||
const t = useTokens();
|
||||
const horsLigne = useHorsLigne();
|
||||
const { data: me } = useMe();
|
||||
const logout = useLogout();
|
||||
|
||||
const seDeconnecter = () => {
|
||||
Alert.alert('Se déconnecter ?', me?.displayName ? `Compte : ${me.displayName}` : undefined, [
|
||||
{ text: 'Annuler', style: 'cancel' },
|
||||
{
|
||||
text: 'Se déconnecter',
|
||||
style: 'destructive',
|
||||
onPress: () => void logout().then(() => router.replace('/connexion')),
|
||||
},
|
||||
]);
|
||||
};
|
||||
|
||||
return (
|
||||
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 8 }}>
|
||||
<Text style={{ color: t.safran, fontSize: 15 }}>♦</Text>
|
||||
<Text style={{ fontFamily: 'Manrope_800ExtraBold', fontSize: 17, color: t.encre }}>SIOP</Text>
|
||||
<Text style={{ fontFamily: 'Manrope_600SemiBold', fontSize: 10.5, color: t.encre3 }}>
|
||||
{me?.role.name ?? '·'}
|
||||
</Text>
|
||||
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 6, marginLeft: 'auto' }}>
|
||||
<Text
|
||||
accessibilityLabel="État de synchronisation"
|
||||
style={{
|
||||
fontFamily: 'Manrope_700Bold',
|
||||
fontSize: 10.5,
|
||||
color: horsLigne ? t.stAttente : t.stTermine,
|
||||
backgroundColor: horsLigne ? t.stAttenteFond : t.stTermineFond,
|
||||
paddingHorizontal: 8,
|
||||
paddingVertical: 2,
|
||||
borderRadius: 999,
|
||||
overflow: 'hidden',
|
||||
}}
|
||||
>
|
||||
{horsLigne ? 'Hors-ligne' : 'Synchro à jour'}
|
||||
</Text>
|
||||
<Pressable
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel="Compte et déconnexion"
|
||||
onPress={seDeconnecter}
|
||||
hitSlop={8}
|
||||
style={{
|
||||
width: 26,
|
||||
height: 26,
|
||||
borderRadius: 13,
|
||||
backgroundColor: t.stEncours,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
}}
|
||||
>
|
||||
<Text style={{ color: '#fff', fontFamily: 'Manrope_700Bold', fontSize: 10 }}>
|
||||
{(me?.displayName ?? '·')
|
||||
.split(' ')
|
||||
.map((m) => m[0])
|
||||
.join('')
|
||||
.slice(0, 2)
|
||||
.toUpperCase()}
|
||||
</Text>
|
||||
</Pressable>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user