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:
@@ -1,8 +1,10 @@
|
||||
import { useState } from 'react';
|
||||
import { View, Text, TextInput, TouchableOpacity, StyleSheet, KeyboardAvoidingView, Platform, ScrollView } from 'react-native';
|
||||
import { Link, useRouter } from 'expo-router';
|
||||
import { View, Text, StyleSheet, KeyboardAvoidingView, Platform, ScrollView } from 'react-native';
|
||||
import { useRouter } from 'expo-router';
|
||||
import { Ionicons } from '@expo/vector-icons';
|
||||
import { Colors } from '@/lib/colors';
|
||||
import { FontSize, FontWeight, Radius, Spacing } from '@/lib/theme';
|
||||
import { AppBar, Button, Card, TextField } from '@/components/ui';
|
||||
|
||||
const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
|
||||
@@ -28,20 +30,27 @@ export default function ForgotPasswordScreen() {
|
||||
if (submitted) {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<View style={styles.success}>
|
||||
<View style={styles.successIcon}>
|
||||
<AppBar title="Demande enregistrée" />
|
||||
<View style={styles.successWrap}>
|
||||
<View style={styles.iconCircle}>
|
||||
<Ionicons name="mail-open" size={32} color={Colors.primary} />
|
||||
</View>
|
||||
<Text style={styles.successTitle}>Demande enregistrée</Text>
|
||||
<Text style={styles.successTitle}>Vérifiez votre boîte mail</Text>
|
||||
<Text style={styles.successText}>
|
||||
Si l'adresse <Text style={styles.bold}>{email}</Text> est associée à un compte CESIZen, un email contenant les instructions de réinitialisation sera envoyé.
|
||||
Si l'adresse <Text style={styles.bold}>{email}</Text> est associée à un compte CESIZen,
|
||||
un email contenant les instructions de réinitialisation sera envoyé.
|
||||
</Text>
|
||||
<Text style={styles.successText}>
|
||||
Si vous ne recevez rien sous 24h, contactez votre administrateur.
|
||||
</Text>
|
||||
<TouchableOpacity style={styles.button} onPress={() => router.replace('/auth/login')}>
|
||||
<Text style={styles.buttonText}>Retour à la connexion</Text>
|
||||
</TouchableOpacity>
|
||||
<View style={styles.successAction}>
|
||||
<Button
|
||||
title="Retour à la connexion"
|
||||
icon="arrow-back-outline"
|
||||
onPress={() => router.replace('/auth/login')}
|
||||
fullWidth
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
@@ -49,64 +58,64 @@ export default function ForgotPasswordScreen() {
|
||||
|
||||
return (
|
||||
<KeyboardAvoidingView style={styles.container} behavior={Platform.OS === 'ios' ? 'padding' : 'height'}>
|
||||
<AppBar title="Mot de passe oublié" subtitle="Réinitialisez votre accès" />
|
||||
<ScrollView contentContainerStyle={styles.scrollContent} keyboardShouldPersistTaps="handled">
|
||||
<View style={styles.header}>
|
||||
<Text style={styles.logo}>Mot de passe oublié ?</Text>
|
||||
<Text style={styles.subtitle}>
|
||||
Entrez votre adresse email. Si elle est associée à un compte, vous recevrez les instructions pour réinitialiser votre mot de passe.
|
||||
</Text>
|
||||
</View>
|
||||
<Text style={styles.intro}>
|
||||
Entrez votre adresse email. Si elle est associée à un compte, vous recevrez les
|
||||
instructions pour réinitialiser votre mot de passe.
|
||||
</Text>
|
||||
|
||||
<View style={styles.form}>
|
||||
<View style={styles.inputGroup}>
|
||||
<Text style={styles.label}>Email</Text>
|
||||
<TextInput
|
||||
style={styles.input}
|
||||
value={email}
|
||||
onChangeText={(v) => { setEmail(v); setError(null); }}
|
||||
placeholder="votre@email.com"
|
||||
keyboardType="email-address"
|
||||
autoCapitalize="none"
|
||||
autoCorrect={false}
|
||||
<Card padding={Spacing.xl} elevated>
|
||||
<TextField
|
||||
label="Email"
|
||||
value={email}
|
||||
onChangeText={(v) => { setEmail(v); setError(null); }}
|
||||
placeholder="votre@email.com"
|
||||
keyboardType="email-address"
|
||||
autoCapitalize="none"
|
||||
autoComplete="email"
|
||||
error={error ?? undefined}
|
||||
required
|
||||
/>
|
||||
|
||||
<Button
|
||||
title="Envoyer les instructions"
|
||||
onPress={handleSubmit}
|
||||
icon="paper-plane-outline"
|
||||
fullWidth
|
||||
/>
|
||||
|
||||
<View style={styles.backRow}>
|
||||
<Button
|
||||
title="Retour à la connexion"
|
||||
variant="tertiary"
|
||||
size="sm"
|
||||
onPress={() => router.replace('/auth/login')}
|
||||
/>
|
||||
{error && <Text style={styles.errorText}>{error}</Text>}
|
||||
</View>
|
||||
|
||||
<TouchableOpacity style={styles.button} onPress={handleSubmit}>
|
||||
<Text style={styles.buttonText}>Envoyer les instructions</Text>
|
||||
</TouchableOpacity>
|
||||
|
||||
<View style={styles.footer}>
|
||||
<Link href="/auth/login" asChild>
|
||||
<TouchableOpacity>
|
||||
<Text style={styles.link}>Retour à la connexion</Text>
|
||||
</TouchableOpacity>
|
||||
</Link>
|
||||
</View>
|
||||
</View>
|
||||
</Card>
|
||||
</ScrollView>
|
||||
</KeyboardAvoidingView>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: { flex: 1, backgroundColor: Colors.white },
|
||||
scrollContent: { flexGrow: 1, justifyContent: 'center', padding: 24 },
|
||||
header: { alignItems: 'center', marginBottom: 32 },
|
||||
logo: { fontSize: 26, fontWeight: '800', color: Colors.black, textAlign: 'center' },
|
||||
subtitle: { fontSize: 14, color: Colors.gray[500], marginTop: 10, textAlign: 'center', lineHeight: 20 },
|
||||
form: { backgroundColor: Colors.gray[50], borderRadius: 4, padding: 24, borderWidth: 1, borderColor: Colors.gray[200] },
|
||||
inputGroup: { marginBottom: 16 },
|
||||
label: { fontSize: 14, fontWeight: '600', color: Colors.black, marginBottom: 6 },
|
||||
input: { backgroundColor: Colors.gray[100], borderTopLeftRadius: 4, borderTopRightRadius: 4, borderBottomWidth: 2, borderBottomColor: Colors.black, paddingHorizontal: 16, paddingVertical: 14, fontSize: 16, color: Colors.black },
|
||||
errorText: { color: Colors.error, marginTop: 6, fontSize: 12 },
|
||||
button: { backgroundColor: Colors.primary, borderRadius: 4, paddingVertical: 16, alignItems: 'center', marginTop: 8 },
|
||||
buttonText: { fontSize: 16, fontWeight: '700', color: Colors.white },
|
||||
footer: { alignItems: 'center', marginTop: 20 },
|
||||
link: { color: Colors.primary, fontSize: 14, fontWeight: '600', textDecorationLine: 'underline' },
|
||||
success: { padding: 24, alignItems: 'center', flex: 1, justifyContent: 'center' },
|
||||
successIcon: { width: 72, height: 72, borderRadius: 999, backgroundColor: `${Colors.primary}15`, justifyContent: 'center', alignItems: 'center', marginBottom: 20 },
|
||||
successTitle: { fontSize: 22, fontWeight: '800', color: Colors.black, marginBottom: 12 },
|
||||
successText: { fontSize: 14, color: Colors.gray[600], textAlign: 'center', lineHeight: 20, marginBottom: 12 },
|
||||
bold: { fontWeight: '700', color: Colors.black },
|
||||
container: { flex: 1, backgroundColor: Colors.gray[50] },
|
||||
scrollContent: { flexGrow: 1, justifyContent: 'center', padding: Spacing.xl },
|
||||
intro: { fontSize: FontSize.sm, color: Colors.gray[600], lineHeight: 20, marginBottom: Spacing.xl, textAlign: 'center' },
|
||||
backRow: { alignItems: 'center', marginTop: Spacing.sm },
|
||||
successWrap: { flex: 1, justifyContent: 'center', alignItems: 'center', padding: Spacing.xl },
|
||||
iconCircle: {
|
||||
width: 72,
|
||||
height: 72,
|
||||
borderRadius: Radius.pill,
|
||||
backgroundColor: '#E3E3FD',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
marginBottom: Spacing.lg,
|
||||
},
|
||||
successTitle: { fontSize: FontSize.xl, fontWeight: FontWeight.heavy, color: Colors.black, marginBottom: Spacing.md, textAlign: 'center' },
|
||||
successText: { fontSize: FontSize.sm, color: Colors.gray[600], textAlign: 'center', lineHeight: 20, marginBottom: Spacing.md },
|
||||
bold: { fontWeight: FontWeight.bold, color: Colors.black },
|
||||
successAction: { alignSelf: 'stretch', marginTop: Spacing.lg },
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user