fix: corrections post-audit (traçabilité, identité État, accents, graphique mobile)
Backend: - table audits réellement alimentée via trait Auditable (observers Eloquent) sur Utilisateur, SaisieTracker, Feed, Emotion ; mot de passe jamais loggé - 4 nouveaux tests (19/19 au total) Frontend web: - en-tête/pied République Française ajoutés aux pages connexion/inscription - bouton variant danger réellement rouge (tokens erreur DSFR) Mobile: - ~30 libellés ré-accentués (Intensité, Succès, Déconnexion, Répartition...) - Colors.secondary = rouge Marianne #E1000F (différenciation cartes/icônes) - vrai camembert SVG des rapports (react-native-svg) Docs: plans oraux mis à jour (audits actif, 29 tests, stockage JWT en Q/R) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -6,7 +6,7 @@ export default function TabLayout() {
|
||||
return (
|
||||
<Tabs
|
||||
screenOptions={{
|
||||
tabBarActiveTintColor: Colors.secondary,
|
||||
tabBarActiveTintColor: Colors.primary,
|
||||
tabBarInactiveTintColor: Colors.gray[400],
|
||||
tabBarStyle: {
|
||||
backgroundColor: Colors.white,
|
||||
|
||||
@@ -49,7 +49,7 @@ export default function DashboardScreen() {
|
||||
</View>
|
||||
<View style={styles.statCard}>
|
||||
<Text style={styles.statValue}>{rapport.stats.intensite_moyenne?.toFixed(1) || '—'}</Text>
|
||||
<Text style={styles.statLabel}>Intensite moy.</Text>
|
||||
<Text style={styles.statLabel}>Intensité moy.</Text>
|
||||
</View>
|
||||
<View style={styles.statCard}>
|
||||
<Text style={styles.statValue}>{rapport.stats.emotion_dominante?.icone || '—'}</Text>
|
||||
@@ -63,7 +63,7 @@ export default function DashboardScreen() {
|
||||
{recentSaisies.length > 0 && (
|
||||
<View style={styles.recentContainer}>
|
||||
<View style={styles.sectionHeader}>
|
||||
<Text style={styles.sectionTitle}>Dernieres emotions</Text>
|
||||
<Text style={styles.sectionTitle}>Dernières émotions</Text>
|
||||
<TouchableOpacity onPress={() => router.push('/(tabs)/journal')}>
|
||||
<Text style={styles.seeAll}>Tout voir</Text>
|
||||
</TouchableOpacity>
|
||||
@@ -76,7 +76,7 @@ export default function DashboardScreen() {
|
||||
<View style={styles.saisieContent}>
|
||||
<Text style={styles.saisieEmotion}>{saisie.emotion?.nom}</Text>
|
||||
<Text style={styles.saisieDate}>
|
||||
{new Date(saisie.date_saisie).toLocaleDateString('fr-FR')} — Intensite: {saisie.intensite}/10
|
||||
{new Date(saisie.date_saisie).toLocaleDateString('fr-FR')} — Intensité: {saisie.intensite}/10
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
@@ -7,7 +7,7 @@ export default function InfoLayout() {
|
||||
screenOptions={{
|
||||
headerStyle: { backgroundColor: Colors.white },
|
||||
headerTitleStyle: { fontWeight: '700', color: Colors.black },
|
||||
headerTintColor: Colors.secondary,
|
||||
headerTintColor: Colors.primary,
|
||||
}}
|
||||
>
|
||||
<Stack.Screen name="index" options={{ title: 'Infos' }} />
|
||||
|
||||
@@ -38,7 +38,7 @@ export default function EditEntryScreen() {
|
||||
note: note.trim() || undefined,
|
||||
date_saisie: dateSaisie,
|
||||
});
|
||||
Alert.alert('Succes', 'Saisie modifiee !', [
|
||||
Alert.alert('Succès', 'Saisie modifiée !', [
|
||||
{ text: 'OK', onPress: () => router.back() },
|
||||
]);
|
||||
} catch {
|
||||
@@ -60,13 +60,13 @@ export default function EditEntryScreen() {
|
||||
|
||||
{/* Emotion */}
|
||||
<View style={styles.section}>
|
||||
<Text style={styles.label}>Emotion</Text>
|
||||
<Text style={styles.label}>Émotion</Text>
|
||||
<EmotionPicker value={emotionId} onChange={setEmotionId} />
|
||||
</View>
|
||||
|
||||
{/* Intensite */}
|
||||
<View style={styles.section}>
|
||||
<Text style={styles.label}>Intensite</Text>
|
||||
<Text style={styles.label}>Intensité</Text>
|
||||
<View style={styles.intensityContainer}>
|
||||
<Text style={styles.intensityValue}>{intensite}</Text>
|
||||
<Text style={styles.intensityUnit}>/10</Text>
|
||||
@@ -95,7 +95,7 @@ export default function EditEntryScreen() {
|
||||
style={styles.textArea}
|
||||
value={note}
|
||||
onChangeText={setNote}
|
||||
placeholder="Decrivez ce que vous ressentez..."
|
||||
placeholder="Décrivez ce que vous ressentez..."
|
||||
multiline
|
||||
numberOfLines={4}
|
||||
textAlignVertical="top"
|
||||
|
||||
@@ -45,7 +45,7 @@ export default function JournalScreen() {
|
||||
<View style={[styles.badge, { backgroundColor: `${item.emotion?.couleur}20` }]}>
|
||||
<Text style={[styles.badgeText, { color: item.emotion?.couleur }]}>{item.emotion?.nom}</Text>
|
||||
</View>
|
||||
<Text style={styles.intensityText}>Intensite: {item.intensite}/10</Text>
|
||||
<Text style={styles.intensityText}>Intensité: {item.intensite}/10</Text>
|
||||
</View>
|
||||
<View style={styles.intensityBar}>
|
||||
<View style={[styles.intensityFill, { width: `${item.intensite * 10}%`, backgroundColor: item.emotion?.couleur || Colors.primary }]} />
|
||||
@@ -76,7 +76,7 @@ export default function JournalScreen() {
|
||||
<View style={styles.empty}>
|
||||
<Ionicons name="book-outline" size={48} color={Colors.gray[300]} />
|
||||
<Text style={styles.emptyTitle}>Aucune saisie</Text>
|
||||
<Text style={styles.emptyText}>Commencez par enregistrer votre premiere emotion</Text>
|
||||
<Text style={styles.emptyText}>Commencez par enregistrer votre première émotion</Text>
|
||||
</View>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -22,7 +22,7 @@ export default function NewEntryScreen() {
|
||||
note: note.trim() || undefined,
|
||||
date_saisie: new Date().toISOString().split('T')[0],
|
||||
});
|
||||
Alert.alert('Succes', 'Saisie enregistree !', [
|
||||
Alert.alert('Succès', 'Saisie enregistrée !', [
|
||||
{ text: 'OK', onPress: () => router.back() },
|
||||
]);
|
||||
} catch {
|
||||
@@ -67,7 +67,7 @@ export default function NewEntryScreen() {
|
||||
{/* Step 2: Intensity */}
|
||||
{step === 2 && (
|
||||
<View>
|
||||
<Text style={styles.stepTitle}>A quel point ressentez-vous cette emotion ?</Text>
|
||||
<Text style={styles.stepTitle}>À quel point ressentez-vous cette émotion ?</Text>
|
||||
<View style={styles.intensityContainer}>
|
||||
<Text style={styles.intensityValue}>{intensite}</Text>
|
||||
<Text style={styles.intensityLabel}>/10</Text>
|
||||
@@ -115,7 +115,7 @@ export default function NewEntryScreen() {
|
||||
style={styles.textArea}
|
||||
value={note}
|
||||
onChangeText={setNote}
|
||||
placeholder="Decrivez ce que vous ressentez, ce qui a declenche cette emotion..."
|
||||
placeholder="Décrivez ce que vous ressentez, ce qui a déclenché cette émotion..."
|
||||
multiline
|
||||
numberOfLines={5}
|
||||
textAlignVertical="top"
|
||||
|
||||
@@ -3,6 +3,7 @@ import { View, Text, StyleSheet, ScrollView, TouchableOpacity } from 'react-nati
|
||||
import { Ionicons } from '@expo/vector-icons';
|
||||
import { useRapport } from '@/hooks/useRapport';
|
||||
import { Colors } from '@/lib/colors';
|
||||
import EmotionPieChart from '@/components/EmotionPieChart';
|
||||
|
||||
type Period = 'week' | 'month' | 'quarter' | 'year';
|
||||
|
||||
@@ -10,7 +11,7 @@ const PERIODS: { value: Period; label: string }[] = [
|
||||
{ value: 'week', label: 'Semaine' },
|
||||
{ value: 'month', label: 'Mois' },
|
||||
{ value: 'quarter', label: 'Trimestre' },
|
||||
{ value: 'year', label: 'Annee' },
|
||||
{ value: 'year', label: 'Année' },
|
||||
];
|
||||
|
||||
export default function ReportsScreen() {
|
||||
@@ -50,10 +51,10 @@ export default function ReportsScreen() {
|
||||
<View style={styles.statCard}>
|
||||
<Ionicons name="trending-up" size={20} color={Colors.secondary} />
|
||||
<Text style={styles.statValue}>{rapport.stats.intensite_moyenne?.toFixed(1) || '—'}</Text>
|
||||
<Text style={styles.statLabel}>Intensite moy.</Text>
|
||||
<Text style={styles.statLabel}>Intensité moy.</Text>
|
||||
</View>
|
||||
<View style={styles.statCard}>
|
||||
<Ionicons name="heart" size={20} color={Colors.rougeMarianne} />
|
||||
<Ionicons name="heart" size={20} color={rapport.stats.emotion_dominante?.couleur || Colors.blueFranceSun} />
|
||||
<Text style={styles.statValue}>{rapport.stats.emotion_dominante?.icone || '—'}</Text>
|
||||
<Text style={styles.statLabel}>{rapport.stats.emotion_dominante?.nom || 'Aucune'}</Text>
|
||||
</View>
|
||||
@@ -69,7 +70,19 @@ export default function ReportsScreen() {
|
||||
{/* Repartition */}
|
||||
{rapport.repartition.length > 0 && (
|
||||
<View style={styles.section}>
|
||||
<Text style={styles.sectionTitle}>Repartition des emotions</Text>
|
||||
<Text style={styles.sectionTitle}>Répartition des émotions</Text>
|
||||
|
||||
{/* Camembert (donut) — équivalent mobile du graphique Recharts du web */}
|
||||
<EmotionPieChart
|
||||
data={rapport.repartition.map((item) => ({
|
||||
nom: item.nom,
|
||||
couleur: item.couleur,
|
||||
count: item.count,
|
||||
pourcentage: item.pourcentage,
|
||||
}))}
|
||||
/>
|
||||
|
||||
<Text style={styles.subSectionTitle}>Détail par émotion</Text>
|
||||
{rapport.repartition.map((item) => (
|
||||
<View key={item.nom} style={styles.repartitionItem}>
|
||||
<View style={styles.repartitionHeader}>
|
||||
@@ -92,7 +105,7 @@ export default function ReportsScreen() {
|
||||
) : (
|
||||
<View style={styles.empty}>
|
||||
<Ionicons name="bar-chart-outline" size={48} color={Colors.gray[300]} />
|
||||
<Text style={styles.emptyText}>Pas de donnees pour cette periode</Text>
|
||||
<Text style={styles.emptyText}>Pas de données pour cette période</Text>
|
||||
</View>
|
||||
)}
|
||||
</ScrollView>
|
||||
@@ -120,6 +133,7 @@ const styles = StyleSheet.create({
|
||||
periodInfoText: { fontSize: 13, color: Colors.gray[400], textAlign: 'center' },
|
||||
section: { marginBottom: 24 },
|
||||
sectionTitle: { fontSize: 18, fontWeight: '700', color: Colors.black, marginBottom: 16 },
|
||||
subSectionTitle: { fontSize: 14, fontWeight: '700', color: Colors.gray[600], marginBottom: 12, marginTop: 4 },
|
||||
repartitionItem: { marginBottom: 16 },
|
||||
repartitionHeader: { flexDirection: 'row', alignItems: 'center', marginBottom: 6 },
|
||||
colorDot: { width: 10, height: 10, borderRadius: 5, marginRight: 8 },
|
||||
|
||||
@@ -9,10 +9,10 @@ export default function ProfileScreen() {
|
||||
const { user, logout } = useAuthStore();
|
||||
|
||||
const handleLogout = () => {
|
||||
Alert.alert('Deconnexion', 'Voulez-vous vous deconnecter ?', [
|
||||
Alert.alert('Déconnexion', 'Voulez-vous vous déconnecter ?', [
|
||||
{ text: 'Annuler', style: 'cancel' },
|
||||
{
|
||||
text: 'Se deconnecter',
|
||||
text: 'Se déconnecter',
|
||||
style: 'destructive',
|
||||
onPress: async () => {
|
||||
await logout();
|
||||
@@ -44,14 +44,14 @@ export default function ProfileScreen() {
|
||||
<View style={styles.menuCard}>
|
||||
<MenuItem icon="person-outline" label="Informations personnelles" />
|
||||
<MenuItem icon="lock-closed-outline" label="Changer le mot de passe" />
|
||||
<MenuItem icon="shield-checkmark-outline" label="Donnees personnelles (RGPD)" />
|
||||
<MenuItem icon="shield-checkmark-outline" label="Données personnelles (RGPD)" />
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View style={styles.menuSection}>
|
||||
<Text style={styles.sectionTitle}>Application</Text>
|
||||
<View style={styles.menuCard}>
|
||||
<MenuItem icon="information-circle-outline" label="A propos de CESIZen" />
|
||||
<MenuItem icon="information-circle-outline" label="À propos de CESIZen" />
|
||||
<MenuItem icon="document-text-outline" label="Conditions d'utilisation" />
|
||||
</View>
|
||||
</View>
|
||||
@@ -59,7 +59,7 @@ export default function ProfileScreen() {
|
||||
{/* Logout */}
|
||||
<TouchableOpacity style={styles.logoutBtn} onPress={handleLogout}>
|
||||
<Ionicons name="log-out-outline" size={20} color={Colors.error} />
|
||||
<Text style={styles.logoutText}>Se deconnecter</Text>
|
||||
<Text style={styles.logoutText}>Se déconnecter</Text>
|
||||
</TouchableOpacity>
|
||||
|
||||
<Text style={styles.version}>CESIZen v1.0.0</Text>
|
||||
|
||||
@@ -35,7 +35,7 @@ export default function LoginScreen() {
|
||||
<ScrollView contentContainerStyle={styles.scrollContent} keyboardShouldPersistTaps="handled">
|
||||
<View style={styles.header}>
|
||||
<Text style={styles.logo}>CESIZen</Text>
|
||||
<Text style={styles.subtitle}>Votre compagnon de sante mentale</Text>
|
||||
<Text style={styles.subtitle}>Votre compagnon de santé mentale</Text>
|
||||
</View>
|
||||
|
||||
<View style={styles.form}>
|
||||
|
||||
Reference in New Issue
Block a user