feat(mobile): refonte design DSFR complète + partie admin

- écrans auth/dashboard/journal/info/urgence/profil refondus sur le design system
- AppBar institutionnel République Française sur tous les écrans
- partie admin (utilisateurs, contenus, émotions) avec AdminGuard
- entrée Espace administration dans le profil (admins uniquement)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Azmog
2026-06-19 15:22:15 +02:00
parent 2e96e07c7e
commit 7fd27d8dc2
22 changed files with 2102 additions and 910 deletions
+67 -48
View File
@@ -1,6 +1,8 @@
import { View, Text, StyleSheet, ScrollView, TouchableOpacity, Linking, Alert } from 'react-native';
import { View, Text, StyleSheet, ScrollView, Linking, Alert } from 'react-native';
import { Ionicons } from '@expo/vector-icons';
import { Colors } from '@/lib/colors';
import { FontSize, FontWeight, Radius, Spacing } from '@/lib/theme';
import { AppBar, Button, Card } from '@/components/ui';
type Contact = {
nom: string;
@@ -65,61 +67,78 @@ export default function UrgenceScreen() {
};
return (
<ScrollView style={styles.container} contentContainerStyle={styles.content}>
<View style={styles.header}>
<View style={styles.iconBadge}>
<Ionicons name="heart" size={20} color={Colors.error} />
</View>
<Text style={styles.headerTitle}>Vous n'êtes pas seul(e)</Text>
<Text style={styles.headerSubtitle}>
<View style={styles.screen}>
<AppBar title="Urgence" subtitle="Vous n'êtes pas seul(e)" />
<ScrollView style={styles.container} contentContainerStyle={styles.content}>
<Text style={styles.intro}>
Si vous ou un proche traversez une période difficile, ces services sont là pour vous écouter.
</Text>
</View>
{CONTACTS.map((c) => (
<TouchableOpacity key={c.numero} style={styles.card} onPress={() => appeler(c.numero, c.nom)}>
<View style={styles.cardIcon}>
<Ionicons name="call" size={22} color={Colors.error} />
</View>
<View style={styles.cardContent}>
<Text style={styles.cardName}>{c.nom}</Text>
<Text style={styles.cardNumber}>{formatNumero(c.numero)}</Text>
{CONTACTS.map((c) => (
<Card key={c.numero} style={styles.card}>
<View style={styles.cardHeader}>
<View style={styles.cardIcon}>
<Ionicons name="call" size={22} color={Colors.error} />
</View>
<View style={styles.cardHeaderText}>
<Text style={styles.cardName}>{c.nom}</Text>
<Text style={styles.cardNumber}>{formatNumero(c.numero)}</Text>
</View>
</View>
<Text style={styles.cardDescription}>{c.description}</Text>
<Text style={styles.cardAvailability}>{c.disponibilite}</Text>
</View>
<Ionicons name="chevron-forward" size={18} color={Colors.gray[300]} />
</TouchableOpacity>
))}
<View style={styles.cardAvailabilityRow}>
<Ionicons name="time-outline" size={14} color={Colors.gray[500]} />
<Text style={styles.cardAvailability}>{c.disponibilite}</Text>
</View>
<Button
title={`Appeler le ${formatNumero(c.numero)}`}
variant="danger"
icon="call"
fullWidth
onPress={() => appeler(c.numero, c.nom)}
style={styles.cardButton}
/>
</Card>
))}
<View style={styles.warning}>
<Ionicons name="warning" size={18} color={Colors.error} />
<Text style={styles.warningText}>
En cas d'urgence vitale, appelez immédiatement le <Text style={styles.bold}>15</Text> (SAMU) ou le <Text style={styles.bold}>112</Text>.
</Text>
</View>
</ScrollView>
<Card style={styles.warning} padding={Spacing.lg}>
<View style={styles.warningRow}>
<Ionicons name="warning" size={20} color={Colors.error} />
<Text style={styles.warningText}>
En cas d'urgence vitale, appelez immédiatement le <Text style={styles.bold}>15</Text> (SAMU) ou le{' '}
<Text style={styles.bold}>112</Text>.
</Text>
</View>
</Card>
</ScrollView>
</View>
);
}
const styles = StyleSheet.create({
container: { flex: 1, backgroundColor: Colors.white },
content: { padding: 16, paddingBottom: 32 },
header: { marginBottom: 20, alignItems: 'flex-start' },
iconBadge: { width: 40, height: 40, borderRadius: 4, backgroundColor: Colors.errorBg, justifyContent: 'center', alignItems: 'center', marginBottom: 12 },
headerTitle: { fontSize: 22, fontWeight: '800', color: Colors.black, marginBottom: 6 },
headerSubtitle: { fontSize: 14, color: Colors.gray[500], lineHeight: 20 },
card: {
flexDirection: 'row', alignItems: 'center', gap: 14, padding: 16,
backgroundColor: Colors.white, borderRadius: 4, marginBottom: 10,
borderWidth: 1, borderColor: Colors.gray[200],
screen: { flex: 1, backgroundColor: Colors.gray[50] },
container: { flex: 1 },
content: { padding: Spacing.lg, paddingBottom: Spacing.xxl, gap: Spacing.md },
intro: { fontSize: FontSize.sm, color: Colors.gray[500], lineHeight: 20, marginBottom: Spacing.xs },
card: { padding: Spacing.lg, gap: Spacing.sm },
cardHeader: { flexDirection: 'row', alignItems: 'center', gap: Spacing.md },
cardIcon: {
width: 44,
height: 44,
borderRadius: Radius.sm,
backgroundColor: Colors.errorBg,
justifyContent: 'center',
alignItems: 'center',
},
cardIcon: { width: 44, height: 44, borderRadius: 4, backgroundColor: Colors.errorBg, justifyContent: 'center', alignItems: 'center' },
cardContent: { flex: 1 },
cardName: { fontSize: 14, fontWeight: '700', color: Colors.black, marginBottom: 2 },
cardNumber: { fontSize: 20, fontWeight: '800', color: Colors.error, marginBottom: 6 },
cardDescription: { fontSize: 12, color: Colors.gray[500], lineHeight: 17 },
cardAvailability: { fontSize: 11, color: Colors.primary, marginTop: 4, fontWeight: '600' },
warning: { marginTop: 8, padding: 14, borderRadius: 4, backgroundColor: Colors.errorBg, borderWidth: 1, borderColor: Colors.error, flexDirection: 'row', gap: 10, alignItems: 'flex-start' },
warningText: { flex: 1, fontSize: 13, color: Colors.error, lineHeight: 19 },
bold: { fontWeight: '800' },
cardHeaderText: { flex: 1 },
cardName: { fontSize: FontSize.md, fontWeight: FontWeight.bold, color: Colors.black, marginBottom: 2 },
cardNumber: { fontSize: FontSize.xl, fontWeight: FontWeight.heavy, color: Colors.error },
cardDescription: { fontSize: FontSize.xs, color: Colors.gray[600], lineHeight: 19 },
cardAvailabilityRow: { flexDirection: 'row', alignItems: 'center', gap: Spacing.xs },
cardAvailability: { fontSize: FontSize.tiny, color: Colors.gray[500], fontWeight: FontWeight.semibold },
cardButton: { marginTop: Spacing.xs },
warning: { backgroundColor: Colors.errorBg, borderColor: Colors.error },
warningRow: { flexDirection: 'row', gap: Spacing.md, alignItems: 'flex-start' },
warningText: { flex: 1, fontSize: FontSize.xs, color: Colors.error, lineHeight: 19 },
bold: { fontWeight: FontWeight.heavy },
});