diff --git a/back/services/user.service.js b/back/services/user.service.js index 48f09cf..973c9ea 100644 --- a/back/services/user.service.js +++ b/back/services/user.service.js @@ -64,14 +64,9 @@ class UserService { async deleteAccount(userId) { const id = new Types.ObjectId(userId); - const exerciseResult = await ExerciseRecord.deleteMany({ user: id }); - console.log(`๐Ÿ—‘๏ธ [deleteAccount] ExerciseRecords supprimรฉs : ${exerciseResult.deletedCount}`); - - const workoutResult = await Workout.deleteMany({ user: id }); - console.log(`๐Ÿ—‘๏ธ [deleteAccount] Workouts supprimรฉs : ${workoutResult.deletedCount}`); - + await ExerciseRecord.deleteMany({ user: id }); + await Workout.deleteMany({ user: id }); await User.findByIdAndDelete(id); - console.log(`๐Ÿ—‘๏ธ [deleteAccount] Utilisateur supprimรฉ : ${userId}`); } /** diff --git a/front/App.js b/front/App.js index efc7cbb..e45555d 100644 --- a/front/App.js +++ b/front/App.js @@ -6,7 +6,7 @@ import { ToastProvider } from './src/context/ToastContext'; import AppNavigator from './src/navigation'; import DesktopInstallPage from './src/components/web/DesktopInstallPage'; -import ErrorBoundary from './src/components/common/ErrorBoundary'; +import { ErrorBoundary } from './src/components/common'; const isDesktopWeb = Platform.OS === 'web' && diff --git a/front/src/components/brand/AthlyLogo.js b/front/src/components/brand/AthlyLogo.js deleted file mode 100644 index 533c679..0000000 --- a/front/src/components/brand/AthlyLogo.js +++ /dev/null @@ -1,95 +0,0 @@ -import React, { useEffect, useRef } from 'react'; -import { Image, Animated, Easing, StyleSheet } from 'react-native'; - -// Rรฉfรฉrentiel officiel des assets -// type='full' + color='orange' โ†’ logo-orange.png (logo complet, couleur principale) -// type='full' + color='violet' โ†’ logo-violet.png (logo complet, gamification) -// type='icon' + color='orange' โ†’ minimalist-logo-orange.png (icรดne "A" seule) -// type='icon' + color='violet' โ†’ minimalist-logo-violet.png (icรดne "A" seule) -const SOURCES = { - full: { - orange: require('../../../assets/logo-orange.png'), - violet: require('../../../assets/logo-violet.png'), - }, - icon: { - orange: require('../../../assets/minimalist-logo-orange.png'), - violet: require('../../../assets/minimalist-logo-violet.png'), - }, -}; - -// Props : -// type โ€” 'full' (logo complet texte+icรดne) | 'icon' (icรดne "A" seule) -// color โ€” 'orange' | 'violet' -// width โ€” largeur explicite pour type="full" (dรฉfaut 180) -// height โ€” hauteur explicite pour type="full" (dรฉfaut : width ร— 0.67) -// size โ€” taille carrรฉe pour type="icon" (dรฉfaut 40) -// animate โ€” FadeInUp au montage (AuthScreen) -// pulse โ€” respiration lรฉgรจre en boucle (รฉtats de chargement) -// style โ€” styles de positionnement uniquement (margin, alignSelfโ€ฆ) -export default function AthlyLogo({ - type = 'full', - color = 'orange', - width = 180, - height, - size = 40, - animate = false, - pulse = false, - style, -}) { - const opacity = useRef(new Animated.Value(animate ? 0 : 1)).current; - const translateY = useRef(new Animated.Value(animate ? 14 : 0)).current; - const scale = useRef(new Animated.Value(1)).current; - - // FadeInUp โ€” dรฉclenchรฉ une seule fois au montage - useEffect(() => { - if (!animate) return; - Animated.parallel([ - Animated.timing(opacity, { - toValue: 1, duration: 520, delay: 80, - easing: Easing.out(Easing.quad), useNativeDriver: true, - }), - Animated.timing(translateY, { - toValue: 0, duration: 520, delay: 80, - easing: Easing.out(Easing.cubic), useNativeDriver: true, - }), - ]).start(); - }, []); - - // Pulse loop โ€” activรฉ/dรฉsactivรฉ par la prop `pulse` - useEffect(() => { - if (!pulse) { scale.setValue(1); return; } - const loop = Animated.loop( - Animated.sequence([ - Animated.timing(scale, { toValue: 1.07, duration: 900, easing: Easing.inOut(Easing.ease), useNativeDriver: true }), - Animated.timing(scale, { toValue: 1, duration: 900, easing: Easing.inOut(Easing.ease), useNativeDriver: true }), - ]), - ); - loop.start(); - return () => loop.stop(); - }, [pulse]); - - const source = (SOURCES[type] || SOURCES.full)[color] || SOURCES.full.orange; - - const bounds = - type === 'icon' - ? { width: size, height: size } - : { width, height: height ?? Math.round(width * 0.67) }; - - return ( - - - - ); -} diff --git a/front/src/components/buttons/PrimaryButton.js b/front/src/components/buttons/PrimaryButton.js deleted file mode 100644 index a720a73..0000000 --- a/front/src/components/buttons/PrimaryButton.js +++ /dev/null @@ -1,38 +0,0 @@ -// ============================================================================================ -// Composant REUTILISABLE : PrimaryButton -// ============================================================================================ -// Bouton principal (orange) utilisรฉ partout dans l'app. -// Props : -// - label : texte du bouton -// - onPress : fonction ร  exรฉcuter au clic -// -// Avantages : -// โœ” Style centralisรฉ -// โœ” Reutilisable sur plusieurs รฉcrans -// ============================================================================================ - -import React from "react"; -import { TouchableOpacity, Text, StyleSheet } from "react-native"; - -export default function PrimaryButton({ label, onPress }) { - return ( - - {label} - - ); -} - -const styles = StyleSheet.create({ - button: { - backgroundColor: "#ff7a33", - paddingVertical: 16, - borderRadius: 12, - marginTop: 10, - alignItems: "center", - }, - text: { - color: "#fff", - fontWeight: "bold", - fontSize: 16, - }, -}); \ No newline at end of file diff --git a/front/src/components/cards/Card.js b/front/src/components/cards/Card.js deleted file mode 100644 index f9c2935..0000000 --- a/front/src/components/cards/Card.js +++ /dev/null @@ -1,29 +0,0 @@ -// ------------------------------------------------------------- -// Composant Card rรฉutilisable -// ------------------------------------------------------------- -// Ce composant sert de conteneur "carte" pour afficher -// du contenu avec un style uniforme (fond, arrondi, padding, margin). -// Il utilise `props.children` pour englober n'importe quel contenu. -// ------------------------------------------------------------- - -import React from "react"; -import { View, StyleSheet } from "react-native"; -import { Colors } from "../../constants/theme"; - -export default function Card({ children, style }) { - return {children}; -} - -const styles = StyleSheet.create({ - card: { - backgroundColor: Colors.card, // Couleur de fond des cartes - padding: 20, // Padding interne - borderRadius: 16, // Arrondi des coins - marginBottom: 16, // Marge en bas - shadowColor: "#000", // Optionnel : ombre lรฉgรจre pour iOS - shadowOffset: { width: 0, height: 2 }, - shadowOpacity: 0.1, - shadowRadius: 4, - elevation: 3, // Ombre pour Android - }, -}); \ No newline at end of file diff --git a/front/src/components/cards/ExerciseCard.js b/front/src/components/cards/ExerciseCard.js index f5fa7d8..60a7d07 100644 --- a/front/src/components/cards/ExerciseCard.js +++ b/front/src/components/cards/ExerciseCard.js @@ -147,7 +147,7 @@ const styles = StyleSheet.create({ cardInSuperset: { marginHorizontal: 10, marginBottom: 8, - backgroundColor: '#1f1f27', + backgroundColor: Colors.borderSubtle, }, row: { flexDirection: 'row', @@ -157,7 +157,7 @@ const styles = StyleSheet.create({ width: 52, height: 52, borderRadius: 12, - backgroundColor: '#0e0e12', + backgroundColor: Colors.cardInner, justifyContent: 'center', alignItems: 'center', marginRight: 14, diff --git a/front/src/components/cards/SetRow.js b/front/src/components/cards/SetRow.js index 81f8cb1..82ede21 100644 --- a/front/src/components/cards/SetRow.js +++ b/front/src/components/cards/SetRow.js @@ -8,7 +8,7 @@ import { } from 'react-native'; import { Ionicons } from '@expo/vector-icons'; import { Colors } from '../../constants/theme'; -import { haptics } from '../../services/haptics.service'; +import { haptics } from '../../services'; // Ligne de sรฉrie : [-] SET | POIDS (KG) | REPS | VALIDER // diff --git a/front/src/components/cards/StatBox.js b/front/src/components/cards/StatBox.js deleted file mode 100644 index 661c807..0000000 --- a/front/src/components/cards/StatBox.js +++ /dev/null @@ -1,36 +0,0 @@ -// ============================================================================================ -// Composant StatBox -// Petite carte affichant une statistique : valeur + label -// ============================================================================================ - -import React from "react"; -import { View, Text, StyleSheet } from "react-native"; -import { Colors } from "../../constants/theme"; - -export default function StatBox({ value, label }) { - return ( - - {value} - {label} - - ); -} - -const styles = StyleSheet.create({ - box: { - backgroundColor: Colors.card, - width: "30%", - padding: 14, - borderRadius: 14, - }, - value: { - color: Colors.textPrimary, - fontSize: 22, - fontWeight: "bold", - }, - label: { - color: Colors.textSecondary, - marginTop: 4, - fontSize: 12, - }, -}); \ No newline at end of file diff --git a/front/src/components/cards/WorkoutItem.js b/front/src/components/cards/WorkoutItem.js deleted file mode 100644 index 7eb138b..0000000 --- a/front/src/components/cards/WorkoutItem.js +++ /dev/null @@ -1,38 +0,0 @@ -// ============================================================================================ -// Composant REUTILISABLE : WorkoutItem -// ============================================================================================ -// Carte affichant une sรฉance : -// - titre (Push, Pull...) -// - informations complรฉmentaires (nombre d'exercices, durรฉe...) -// - action au clic (ouvrir la sรฉance) -// ============================================================================================ -import React from "react"; -import { View, Text, StyleSheet, TouchableOpacity } from "react-native"; -import { Colors } from "../../constants/theme"; - -export default function WorkoutItem({ title, info, onPress }) { - return ( - - {title} - {info} - - ); -} - -const styles = StyleSheet.create({ - card: { - backgroundColor: Colors.card, - padding: 18, - borderRadius: 14, - marginBottom: 12, - }, - title: { - color: Colors.textPrimary, - fontSize: 16, - fontWeight: "bold", - }, - info: { - color: Colors.textSecondary, - marginTop: 4, - }, -}); diff --git a/front/src/components/common/ActionSheetModal.js b/front/src/components/common/ActionSheetModal.js index ef3f7d2..34789e0 100644 --- a/front/src/components/common/ActionSheetModal.js +++ b/front/src/components/common/ActionSheetModal.js @@ -56,7 +56,7 @@ const styles = StyleSheet.create({ }, card: { width: '100%', - backgroundColor: '#13131C', + backgroundColor: Colors.bgDeep2, borderRadius: 18, borderWidth: 1, borderColor: 'rgba(255,255,255,0.08)', @@ -82,7 +82,7 @@ const styles = StyleSheet.create({ }, optionBtnLast: { marginBottom: 8 }, optionTxt: { color: Colors.textPrimary, fontSize: 15.5, fontWeight: '600' }, - optionTxtDestructive: { color: '#EF4444' }, + optionTxtDestructive: { color: Colors.destructive }, cancelBtn: { height: 50, justifyContent: 'center', diff --git a/front/src/components/common/ConfirmModal.js b/front/src/components/common/ConfirmModal.js index 04aa539..684808f 100644 --- a/front/src/components/common/ConfirmModal.js +++ b/front/src/components/common/ConfirmModal.js @@ -2,6 +2,7 @@ import React from 'react'; import { View, Text, StyleSheet, Modal, TouchableOpacity } from 'react-native'; import { Ionicons } from '@expo/vector-icons'; import { Colors } from '../../constants/theme'; +import { modalStyles } from './modalStyles'; // โ”€โ”€โ”€ ConfirmModal โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ // Modale de confirmation stylisรฉe (fond sombre, carte, boutons) ร  utiliser ร  la @@ -24,25 +25,25 @@ export default function ConfirmModal({ confirmLabel, cancelLabel = 'Annuler', destructive = false, onConfirm, onCancel, }) { - const accent = destructive ? '#EF4444' : Colors.primary; + const accent = destructive ? Colors.destructive : Colors.primary; return ( - - - + + + - {title} - {body ? {body} : null} + {title} + {body ? {body} : null} - {confirmLabel} + {confirmLabel} @@ -55,63 +56,7 @@ export default function ConfirmModal({ } const styles = StyleSheet.create({ - backdrop: { - flex: 1, - backgroundColor: 'rgba(0,0,0,0.82)', - justifyContent: 'center', - alignItems: 'center', - paddingHorizontal: 24, - }, - card: { - width: '100%', - backgroundColor: '#13131C', - borderRadius: 22, - borderWidth: 1, - padding: 28, - alignItems: 'center', - shadowColor: '#000', - shadowOffset: { width: 0, height: 16 }, - shadowOpacity: 0.65, - shadowRadius: 32, - elevation: 20, - }, - iconWrap: { - width: 60, - height: 60, - borderRadius: 18, - borderWidth: 1, - justifyContent: 'center', - alignItems: 'center', - marginBottom: 18, - }, - title: { - color: Colors.textPrimary, - fontSize: 18, - fontWeight: '800', - letterSpacing: -0.3, - marginBottom: 10, - textAlign: 'center', - }, - body: { - color: Colors.textSecondary, - fontSize: 14, - lineHeight: 21, - textAlign: 'center', - marginBottom: 24, - }, - confirmBtn: { - width: '100%', - height: 50, - borderRadius: 13, - justifyContent: 'center', - alignItems: 'center', - marginBottom: 10, - shadowOffset: { width: 0, height: 6 }, - shadowOpacity: 0.40, - shadowRadius: 12, - elevation: 6, - }, - confirmTxt: { color: '#fff', fontSize: 15, fontWeight: '700', letterSpacing: 0.2 }, + confirmSpacing: { marginBottom: 10 }, cancelBtn: { width: '100%', height: 44, borderRadius: 13, justifyContent: 'center', alignItems: 'center' }, cancelTxt: { color: Colors.textMuted, fontSize: 14, fontWeight: '500' }, }); diff --git a/front/src/components/common/InfoModal.js b/front/src/components/common/InfoModal.js index 0aba99b..f7cba07 100644 --- a/front/src/components/common/InfoModal.js +++ b/front/src/components/common/InfoModal.js @@ -1,7 +1,8 @@ import React from 'react'; -import { View, Text, StyleSheet, Modal, TouchableOpacity } from 'react-native'; +import { View, Text, Modal, TouchableOpacity } from 'react-native'; import { Ionicons } from '@expo/vector-icons'; import { Colors } from '../../constants/theme'; +import { modalStyles } from './modalStyles'; // โ”€โ”€โ”€ InfoModal โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ // Alerte ร  un seul bouton (information, erreur, validation simple) โ€” remplace @@ -21,87 +22,28 @@ export default function InfoModal({ visible, icon = 'information-circle-outline', title, body, closeLabel = 'OK', destructive = false, onClose, }) { - const accent = destructive ? '#EF4444' : Colors.primary; + const accent = destructive ? Colors.destructive : Colors.primary; return ( - - - + + + - {title} - {body ? {body} : null} + {title} + {body ? {body} : null} - {closeLabel} + {closeLabel} ); } - -const styles = StyleSheet.create({ - backdrop: { - flex: 1, - backgroundColor: 'rgba(0,0,0,0.82)', - justifyContent: 'center', - alignItems: 'center', - paddingHorizontal: 24, - }, - card: { - width: '100%', - backgroundColor: '#13131C', - borderRadius: 22, - borderWidth: 1, - padding: 28, - alignItems: 'center', - shadowColor: '#000', - shadowOffset: { width: 0, height: 16 }, - shadowOpacity: 0.65, - shadowRadius: 32, - elevation: 20, - }, - iconWrap: { - width: 60, - height: 60, - borderRadius: 18, - borderWidth: 1, - justifyContent: 'center', - alignItems: 'center', - marginBottom: 18, - }, - title: { - color: Colors.textPrimary, - fontSize: 18, - fontWeight: '800', - letterSpacing: -0.3, - marginBottom: 10, - textAlign: 'center', - }, - body: { - color: Colors.textSecondary, - fontSize: 14, - lineHeight: 21, - textAlign: 'center', - marginBottom: 24, - }, - closeBtn: { - width: '100%', - height: 50, - borderRadius: 13, - justifyContent: 'center', - alignItems: 'center', - shadowOffset: { width: 0, height: 6 }, - shadowOpacity: 0.40, - shadowRadius: 12, - elevation: 6, - }, - closeTxt: { color: '#fff', fontSize: 15, fontWeight: '700', letterSpacing: 0.2 }, -}); diff --git a/front/src/components/common/NotificationBanner.js b/front/src/components/common/NotificationBanner.js index 07cc357..f05ff1c 100644 --- a/front/src/components/common/NotificationBanner.js +++ b/front/src/components/common/NotificationBanner.js @@ -1,11 +1,12 @@ import React, { useEffect, useRef } from 'react'; import { View, Text, StyleSheet, Animated } from 'react-native'; import { Ionicons } from '@expo/vector-icons'; +import { Colors } from '../../constants/theme'; const VARIANTS = { error: { icon: 'alert-circle', - color: '#FF4D4D', + color: Colors.error, bg: 'rgba(255, 77, 77, 0.10)', border: 'rgba(255, 77, 77, 0.30)', iconBg: 'rgba(255, 77, 77, 0.15)', @@ -26,7 +27,7 @@ const VARIANTS = { }, success: { icon: 'checkmark-circle', - color: '#44FF88', + color: Colors.success, bg: 'rgba(68, 255, 136, 0.10)', border: 'rgba(68, 255, 136, 0.28)', iconBg: 'rgba(68, 255, 136, 0.15)', diff --git a/front/src/components/common/QuestToast.js b/front/src/components/common/QuestToast.js index 3da6ee3..8c89d99 100644 --- a/front/src/components/common/QuestToast.js +++ b/front/src/components/common/QuestToast.js @@ -79,7 +79,7 @@ export default function QuestToast({ visible, questLabel, isBonus = false, onHid @@ -145,6 +145,6 @@ const styles = StyleSheet.create({ marginTop: 2, }, labelBonus: { - color: '#FFD700', + color: Colors.gold, }, }); diff --git a/front/src/components/common/WeightEntryModal.js b/front/src/components/common/WeightEntryModal.js index 80c61cb..a9c5d13 100644 --- a/front/src/components/common/WeightEntryModal.js +++ b/front/src/components/common/WeightEntryModal.js @@ -98,7 +98,7 @@ const styles = StyleSheet.create({ }, card: { width: '100%', - backgroundColor: '#13131C', + backgroundColor: Colors.bgDeep2, borderRadius: 22, borderWidth: 1, borderColor: `${Colors.primary}38`, diff --git a/front/src/components/common/index.js b/front/src/components/common/index.js new file mode 100644 index 0000000..c913598 --- /dev/null +++ b/front/src/components/common/index.js @@ -0,0 +1,13 @@ +// โ”€โ”€โ”€ Barrel des composants communs โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +// Point d'entrรฉe unique : `import { ConfirmModal, InfoModal } from '../components/common';` +// Rรจgle : ne jamais importer ce barrel depuis un fichier de ce dossier +// (imports directs entre composants communs) pour exclure tout cycle. + +export { default as ActionSheetModal } from './ActionSheetModal'; +export { default as ConfirmModal } from './ConfirmModal'; +export { default as ErrorBoundary } from './ErrorBoundary'; +export { default as InfoModal } from './InfoModal'; +export { default as NotificationBanner } from './NotificationBanner'; +export { default as QuestToast } from './QuestToast'; +export { default as WeightEntryModal } from './WeightEntryModal'; +export { modalStyles } from './modalStyles'; diff --git a/front/src/components/common/modalStyles.js b/front/src/components/common/modalStyles.js new file mode 100644 index 0000000..473e4fc --- /dev/null +++ b/front/src/components/common/modalStyles.js @@ -0,0 +1,69 @@ +import { StyleSheet } from 'react-native'; +import { Colors } from '../../constants/theme'; + +// โ”€โ”€โ”€ modalStyles โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +// Styles partagรฉs par la famille des modales centrรฉes (ConfirmModal, InfoModal). +// Source de vรฉritรฉ unique pour le rendu "carte sombre centrรฉe + badge d'icรดne +// + CTA plein" โ€” toute รฉvolution visuelle de ces modales se fait ici, une fois. +// +// Les accents (couleur du badge, du CTA, des bordures) restent passรฉs en inline +// par chaque modale car ils dรฉpendent d'un รฉtat (destructive โ†’ rouge). + +export const modalStyles = StyleSheet.create({ + backdrop: { + flex: 1, + backgroundColor: 'rgba(0,0,0,0.82)', + justifyContent: 'center', + alignItems: 'center', + paddingHorizontal: 24, + }, + card: { + width: '100%', + backgroundColor: Colors.bgDeep2, + borderRadius: 22, + borderWidth: 1, + padding: 28, + alignItems: 'center', + shadowColor: '#000', + shadowOffset: { width: 0, height: 16 }, + shadowOpacity: 0.65, + shadowRadius: 32, + elevation: 20, + }, + iconWrap: { + width: 60, + height: 60, + borderRadius: 18, + borderWidth: 1, + justifyContent: 'center', + alignItems: 'center', + marginBottom: 18, + }, + title: { + color: Colors.textPrimary, + fontSize: 18, + fontWeight: '800', + letterSpacing: -0.3, + marginBottom: 10, + textAlign: 'center', + }, + body: { + color: Colors.textSecondary, + fontSize: 14, + lineHeight: 21, + textAlign: 'center', + marginBottom: 24, + }, + ctaBtn: { + width: '100%', + height: 50, + borderRadius: 13, + justifyContent: 'center', + alignItems: 'center', + shadowOffset: { width: 0, height: 6 }, + shadowOpacity: 0.40, + shadowRadius: 12, + elevation: 6, + }, + ctaTxt: { color: '#fff', fontSize: 15, fontWeight: '700', letterSpacing: 0.2 }, +}); diff --git a/front/src/components/home/DailyQuestsCard.js b/front/src/components/home/DailyQuestsCard.js index 721d66e..e0476eb 100644 --- a/front/src/components/home/DailyQuestsCard.js +++ b/front/src/components/home/DailyQuestsCard.js @@ -3,7 +3,7 @@ import { View, Text, StyleSheet, ActivityIndicator } from 'react-native'; import { Ionicons } from '@expo/vector-icons'; import { Colors } from '../../constants/theme'; import { useQuests } from '../../context/QuestContext'; -import { QUEST_XP, BONUS_XP } from '../../services/quest.service'; +import { QUEST_XP, BONUS_XP } from '../../services'; export default function DailyQuestsCard() { const { quests, completedCount, bonusClaimed, loading } = useQuests(); @@ -56,13 +56,13 @@ export default function DailyQuestsCard() { Bonus toutes quรชtes : +{BONUS_XP} XP {allDone && ( - + )} @@ -230,5 +230,5 @@ const styles = StyleSheet.create({ fontSize: 10, fontWeight: '600', }, - bonusTextDone: { color: '#FFD700' }, + bonusTextDone: { color: Colors.gold }, }); diff --git a/front/src/components/home/RecoveryRitualsCard.js b/front/src/components/home/RecoveryRitualsCard.js index 82c1d4b..63769a7 100644 --- a/front/src/components/home/RecoveryRitualsCard.js +++ b/front/src/components/home/RecoveryRitualsCard.js @@ -629,7 +629,7 @@ const styles = StyleSheet.create({ }, modalCard: { width: '100%', - backgroundColor: '#13131C', + backgroundColor: Colors.bgDeep2, borderRadius: 26, borderWidth: 1, paddingHorizontal: 24, diff --git a/front/src/components/inventory/ChestOpeningModal.js b/front/src/components/inventory/ChestOpeningModal.js index 5b6a244..c7a8f61 100644 --- a/front/src/components/inventory/ChestOpeningModal.js +++ b/front/src/components/inventory/ChestOpeningModal.js @@ -2,7 +2,7 @@ import React, { useRef, useEffect, useState } from 'react'; import { View, Text, StyleSheet, Modal, TouchableOpacity, Animated, Easing } from 'react-native'; import { Ionicons } from '@expo/vector-icons'; import { Colors } from '../../constants/theme'; -import { ITEM_CATALOG, RARITY_META } from '../../services/inventory.service'; +import { ITEM_CATALOG, RARITY_META } from '../../services'; import BirthdayConfetti from '../profile/BirthdayConfetti'; // โ”€โ”€โ”€ ChestOpeningModal โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ diff --git a/front/src/components/profile/AchievementShowcase.js b/front/src/components/profile/AchievementShowcase.js index 9a7f6f4..13af518 100644 --- a/front/src/components/profile/AchievementShowcase.js +++ b/front/src/components/profile/AchievementShowcase.js @@ -2,7 +2,7 @@ import React, { useState } from 'react'; import { View, Text, StyleSheet, Modal, ScrollView, TouchableOpacity, Pressable, Dimensions } from 'react-native'; import { Ionicons } from '@expo/vector-icons'; import { Colors } from '../../constants/theme'; -import { RARITY_META } from '../../services/inventory.service'; +import { RARITY_META } from '../../services'; import { FeaturedModal, TrophyIcon } from './TrophySlot'; // โ”€โ”€โ”€ AchievementShowcase โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ @@ -78,14 +78,14 @@ const CATEGORY_COLOR = { profile: Colors.rankViolet, collection: Colors.primary, social: '#22D3EE', - heritage: '#FE7439', + heritage: Colors.primary, force: '#DC2626', - exploration: '#22C55E', + exploration: Colors.valid, secret: '#6366F1', corps: '#D1D5DB', regularite: '#10B981', - special: '#FE7439', - ultime: '#FFD700', + special: Colors.primary, + ultime: Colors.gold, }; const CATEGORY_LABELS = { diff --git a/front/src/components/profile/ActivityHeatmap.js b/front/src/components/profile/ActivityHeatmap.js index a934df5..2e6ac92 100644 --- a/front/src/components/profile/ActivityHeatmap.js +++ b/front/src/components/profile/ActivityHeatmap.js @@ -18,7 +18,7 @@ const INTENSITY_COLOR = { 1: '#4D2718', // lรฉger 2: '#85391E', 3: '#C44C24', - 4: '#FE7439', // plein + 4: Colors.primary, // plein }; function monthLabelFor(dateKey) { diff --git a/front/src/components/profile/BirthdatePicker.js b/front/src/components/profile/BirthdatePicker.js index 22e8713..ed596f0 100644 --- a/front/src/components/profile/BirthdatePicker.js +++ b/front/src/components/profile/BirthdatePicker.js @@ -198,7 +198,7 @@ const styles = StyleSheet.create({ }, card: { width: '100%', - backgroundColor: '#13131C', + backgroundColor: Colors.bgDeep2, borderRadius: 22, borderWidth: 1, borderColor: 'rgba(255,255,255,0.09)', diff --git a/front/src/components/profile/BirthdayCelebration.js b/front/src/components/profile/BirthdayCelebration.js index 97dfdcd..b03c30d 100644 --- a/front/src/components/profile/BirthdayCelebration.js +++ b/front/src/components/profile/BirthdayCelebration.js @@ -1,7 +1,7 @@ import React, { useState, useEffect, useCallback } from 'react'; import AsyncStorage from '@react-native-async-storage/async-storage'; import { useAuth } from '../../context/AuthContext'; -import { checkBirthday } from '../../services/reward.service'; +import { checkBirthday } from '../../services'; import BirthdayModal from './BirthdayModal'; const SHOWN_KEY = 'athly:birthday:shown_date:v1'; diff --git a/front/src/components/profile/BirthdayModal.js b/front/src/components/profile/BirthdayModal.js index d326b3b..d8c93ea 100644 --- a/front/src/components/profile/BirthdayModal.js +++ b/front/src/components/profile/BirthdayModal.js @@ -117,7 +117,7 @@ const styles = StyleSheet.create({ }, card: { width: '100%', - backgroundColor: '#13131C', + backgroundColor: Colors.bgDeep2, borderRadius: 22, borderWidth: 1, borderColor: 'rgba(139,92,246,0.35)', diff --git a/front/src/components/profile/BorderPicker.js b/front/src/components/profile/BorderPicker.js index 58fd2cf..63a40ab 100644 --- a/front/src/components/profile/BorderPicker.js +++ b/front/src/components/profile/BorderPicker.js @@ -290,7 +290,7 @@ const styles = StyleSheet.create({ bottom: 0, left: 0, right: 0, - backgroundColor: '#13131C', + backgroundColor: Colors.bgDeep2, borderTopLeftRadius: 28, borderTopRightRadius: 28, paddingTop: 12, @@ -369,7 +369,7 @@ const styles = StyleSheet.create({ width: 16, height: 16, borderRadius: 8, backgroundColor: Colors.primary, alignItems: 'center', justifyContent: 'center', - borderWidth: 1.5, borderColor: '#13131C', + borderWidth: 1.5, borderColor: Colors.bgDeep2, }, itemName: { fontSize: 9, fontWeight: '700', textAlign: 'center', color: Colors.textPrimary }, itemUnlock: { color: Colors.textMuted, fontSize: 8, fontWeight: '500', marginTop: 1, textAlign: 'center' }, diff --git a/front/src/components/profile/EmberParticles.js b/front/src/components/profile/EmberParticles.js index 6b17ffe..98e8e11 100644 --- a/front/src/components/profile/EmberParticles.js +++ b/front/src/components/profile/EmberParticles.js @@ -1,5 +1,6 @@ import React, { useRef, useEffect } from 'react'; import { View, StyleSheet, Animated } from 'react-native'; +import { Colors } from '../../constants/theme'; // โ”€โ”€โ”€ EmberParticles โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ // Braises ascendantes pour les rangs Lรฉgende (171+) et ATHLY GOD (200). @@ -16,7 +17,7 @@ function randomBetween(min, max) { return min + Math.random() * (max - min); } -export default function EmberParticles({ visible = false, color = '#C084FC' }) { +export default function EmberParticles({ visible = false, color = Colors.legendAccent }) { const particles = useRef( Array.from({ length: PARTICLE_COUNT }, (_, i) => ({ y: new Animated.Value(0), diff --git a/front/src/components/profile/HeroLevelCard.js b/front/src/components/profile/HeroLevelCard.js index afa646d..eaf0e0e 100644 --- a/front/src/components/profile/HeroLevelCard.js +++ b/front/src/components/profile/HeroLevelCard.js @@ -2,7 +2,7 @@ import React, { useMemo, useRef, useEffect } from 'react'; import { View, Text, StyleSheet, Animated } from 'react-native'; import { Ionicons } from '@expo/vector-icons'; import { Colors } from '../../constants/theme'; -import { xpToLevel, getRank } from '../../services/stats.service'; +import { xpToLevel, getRank } from '../../services'; import AvatarFrame, { getFrameFootprint } from './AvatarFrame'; const AVATAR_SIZE = 90; diff --git a/front/src/components/profile/LevelUpModal.js b/front/src/components/profile/LevelUpModal.js index 148d162..50fde07 100644 --- a/front/src/components/profile/LevelUpModal.js +++ b/front/src/components/profile/LevelUpModal.js @@ -8,16 +8,16 @@ import BirthdayConfetti from './BirthdayConfetti'; // getRankForLevel() (back/utils/levelHelpers.js), indexรฉ par le libellรฉ // backend puisque cette modale reรงoit `rank` en toutes lettres. const RANK_COLORS = { - 'ATHLY GOD': '#FFD700', - 'Lรฉgende': '#C084FC', - 'Grand Maรฎtre': '#A855F7', - 'Maรฎtre': '#8B5CF6', - 'ร‰lite': '#6E6AF0', - 'Warrior': '#6E6AF0', + 'ATHLY GOD': Colors.gold, + 'Lรฉgende': Colors.legendAccent, + 'Grand Maรฎtre': Colors.rankPurple, + 'Maรฎtre': Colors.rankViolet, + 'ร‰lite': Colors.secondaryAccent, + 'Warrior': Colors.secondaryAccent, 'Compรฉtiteur': '#3B82F6', - 'Athlรจte': '#22C55E', + 'Athlรจte': Colors.valid, 'Initiรฉ': '#FBBF24', - 'Novice': '#FE7439', + 'Novice': Colors.primary, }; // โ”€โ”€โ”€ LevelUpModal โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ @@ -88,7 +88,7 @@ const styles = StyleSheet.create({ }, card: { width: '100%', - backgroundColor: '#13131C', + backgroundColor: Colors.bgDeep2, borderRadius: 22, borderWidth: 1, padding: 28, diff --git a/front/src/components/profile/RecordsShowcasePicker.js b/front/src/components/profile/RecordsShowcasePicker.js index 7f706fa..4675283 100644 --- a/front/src/components/profile/RecordsShowcasePicker.js +++ b/front/src/components/profile/RecordsShowcasePicker.js @@ -2,8 +2,8 @@ import React, { useState, useEffect, useMemo } from 'react'; import { View, Text, StyleSheet, Modal, TouchableOpacity, TextInput, FlatList, ActivityIndicator } from 'react-native'; import { Ionicons } from '@expo/vector-icons'; import { Colors } from '../../constants/theme'; -import { getMyRecords } from '../../services/social.service'; -import { updateRecordsShowcase } from '../../services/profile.service'; +import { getMyRecords } from '../../services'; +import { updateRecordsShowcase } from '../../services'; const MAX_SHOWCASED = 6; @@ -166,7 +166,7 @@ const styles = StyleSheet.create({ justifyContent: 'flex-end', }, sheet: { - backgroundColor: '#13131C', + backgroundColor: Colors.bgDeep2, borderTopLeftRadius: 24, borderTopRightRadius: 24, paddingHorizontal: 20, diff --git a/front/src/components/profile/StreakBadge.js b/front/src/components/profile/StreakBadge.js index ef34ed1..5bd3695 100644 --- a/front/src/components/profile/StreakBadge.js +++ b/front/src/components/profile/StreakBadge.js @@ -6,7 +6,7 @@ import { const SCROLL_MAX_H = Math.round(Dimensions.get('window').height * 0.38); import { Ionicons } from '@expo/vector-icons'; -import { getStreakMultiplier, STREAK_MILESTONES } from '../../services/stats.service'; +import { getStreakMultiplier, STREAK_MILESTONES } from '../../services'; import { Colors } from '../../constants/theme'; // โ”€โ”€โ”€ StreakBonusModal โ€” Roadmap des multiplicateurs โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ @@ -37,7 +37,7 @@ function StreakBonusModal({ visible, streak, onClose }) { {/* Header */} - + Rรฉgularitรฉ & Multiplicateurs @@ -133,7 +133,7 @@ export default function StreakBadge({ streak = 0, compact = false }) { if (streak === 0) return null; - const flameColor = color || '#FE7439'; + const flameColor = color || Colors.primary; const openModal = () => setModalVisible(true); @@ -270,8 +270,8 @@ const ms = StyleSheet.create({ letterSpacing: 1.2, marginBottom: 8, }, currentRow: { flexDirection: 'row', alignItems: 'baseline', marginBottom: 12 }, - currentDays: { color: '#FE7439', fontSize: 36, fontWeight: '900' }, - currentUnit: { color: '#FE7439', fontSize: 16, fontWeight: '600' }, + currentDays: { color: Colors.primary, fontSize: 36, fontWeight: '900' }, + currentUnit: { color: Colors.primary, fontSize: 16, fontWeight: '600' }, multChip: { marginLeft: 10, paddingHorizontal: 10, paddingVertical: 4, borderRadius: 12, borderWidth: 1, diff --git a/front/src/components/profile/TitlePickerModal.js b/front/src/components/profile/TitlePickerModal.js index 0285a31..d3630a3 100644 --- a/front/src/components/profile/TitlePickerModal.js +++ b/front/src/components/profile/TitlePickerModal.js @@ -3,9 +3,9 @@ import { View, Text, StyleSheet, ScrollView, TouchableOpacity, ActivityIndicator import { Ionicons } from '@expo/vector-icons'; import { Colors } from '../../constants/theme'; -import { getTitles, equipTitle } from '../../services/title.service'; -import { RARITY_META } from '../../services/inventory.service'; -import { haptics } from '../../services/haptics.service'; +import { getTitles, equipTitle } from '../../services'; +import { RARITY_META } from '../../services'; +import { haptics } from '../../services'; // โ”€โ”€โ”€ TitleInfoModal โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ // Affiche la quรชte exacte pour un titre encore verrouillรฉ, avec une barre de @@ -188,7 +188,7 @@ const s = StyleSheet.create({ justifyContent: 'center', alignItems: 'center', paddingHorizontal: 20, }, sheet: { - width: '100%', maxHeight: '85%', backgroundColor: '#13131C', + width: '100%', maxHeight: '85%', backgroundColor: Colors.bgDeep2, borderRadius: 24, borderWidth: 1, borderColor: `${Colors.primary}38`, padding: 22, paddingTop: 40, }, @@ -227,7 +227,7 @@ const s = StyleSheet.create({ justifyContent: 'center', alignItems: 'center', paddingHorizontal: 24, }, infoCard: { - width: '100%', backgroundColor: '#13131C', borderRadius: 22, borderWidth: 1, + width: '100%', backgroundColor: Colors.bgDeep2, borderRadius: 22, borderWidth: 1, padding: 28, alignItems: 'center', shadowColor: '#000', shadowOffset: { width: 0, height: 16 }, shadowOpacity: 0.65, shadowRadius: 32, elevation: 20, }, diff --git a/front/src/components/profile/TrophyGrid.js b/front/src/components/profile/TrophyGrid.js index 6918ae3..f9c929b 100644 --- a/front/src/components/profile/TrophyGrid.js +++ b/front/src/components/profile/TrophyGrid.js @@ -1,6 +1,6 @@ import React, { useState } from 'react'; import { View, StyleSheet } from 'react-native'; -import { MAX_FEATURED } from '../../hooks/useFeaturedTrophies'; +import { MAX_FEATURED } from '../../hooks'; import { TrophySlot, EmptySlot, FeaturedModal } from './TrophySlot'; // featuredIds + toggleFeatured proviennent du parent (ProfileScreen via useFeaturedTrophies) diff --git a/front/src/components/social/ActivityFeedModal.js b/front/src/components/social/ActivityFeedModal.js index 21472b6..759c755 100644 --- a/front/src/components/social/ActivityFeedModal.js +++ b/front/src/components/social/ActivityFeedModal.js @@ -3,7 +3,7 @@ import { View, Text, StyleSheet, Modal, TouchableOpacity, ScrollView } from 'rea import { Ionicons } from '@expo/vector-icons'; import { Colors } from '../../constants/theme'; import { useAuth } from '../../context/AuthContext'; -import { getActivityFeed, reactToActivityEvent } from '../../services/social.service'; +import { getActivityFeed, reactToActivityEvent } from '../../services'; // โ”€โ”€โ”€ ActivityFeedModal โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ // Flux d'activitรฉ ยซ Taquineries & High-Fives ยป (Section IV) : au lancement de @@ -138,7 +138,7 @@ const styles = StyleSheet.create({ card: { width: '100%', maxHeight: '78%', - backgroundColor: '#13131C', + backgroundColor: Colors.bgDeep2, borderRadius: 22, borderWidth: 1, borderColor: 'rgba(255,255,255,0.08)', diff --git a/front/src/components/social/AddFriendModal.js b/front/src/components/social/AddFriendModal.js index 0abdba0..ee86b7a 100644 --- a/front/src/components/social/AddFriendModal.js +++ b/front/src/components/social/AddFriendModal.js @@ -120,7 +120,7 @@ const styles = StyleSheet.create({ }, card: { width: '100%', - backgroundColor: '#13131C', + backgroundColor: Colors.bgDeep2, borderRadius: 22, borderWidth: 1, borderColor: `${Colors.primary}38`, diff --git a/front/src/components/social/ExercisePickerModal.js b/front/src/components/social/ExercisePickerModal.js index f6c7f0c..8f227b4 100644 --- a/front/src/components/social/ExercisePickerModal.js +++ b/front/src/components/social/ExercisePickerModal.js @@ -121,7 +121,7 @@ const styles = StyleSheet.create({ justifyContent: 'flex-end', }, sheet: { - backgroundColor: '#13131C', + backgroundColor: Colors.bgDeep2, borderTopLeftRadius: 24, borderTopRightRadius: 24, paddingHorizontal: 20, diff --git a/front/src/components/social/FriendPreviewModal.js b/front/src/components/social/FriendPreviewModal.js index 58e16ec..ee5036a 100644 --- a/front/src/components/social/FriendPreviewModal.js +++ b/front/src/components/social/FriendPreviewModal.js @@ -104,7 +104,7 @@ const styles = StyleSheet.create({ }, card: { width: '100%', - backgroundColor: '#13131C', + backgroundColor: Colors.bgDeep2, borderRadius: 22, borderWidth: 1, borderColor: `${Colors.primary}38`, diff --git a/front/src/components/social/FriendshipLevelUpModal.js b/front/src/components/social/FriendshipLevelUpModal.js index 9663bc5..67cd3ef 100644 --- a/front/src/components/social/FriendshipLevelUpModal.js +++ b/front/src/components/social/FriendshipLevelUpModal.js @@ -8,7 +8,7 @@ import BirthdayConfetti from '../profile/BirthdayConfetti'; // mรชme esprit que RANK_COLORS dans LevelUpModal.js, mais indexรฉ par niveau // d'amitiรฉ (1 ร  5) plutรดt que par rang de niveau de joueur. const FRIENDSHIP_LEVEL_COLORS = { - 1: '#9AA0AE', + 1: Colors.textSecondary, 2: '#FF8FA3', 3: '#FF4D6D', 4: '#E11D48', @@ -87,7 +87,7 @@ const styles = StyleSheet.create({ }, card: { width: '100%', - backgroundColor: '#13131C', + backgroundColor: Colors.bgDeep2, borderRadius: 22, borderWidth: 1, padding: 28, diff --git a/front/src/components/stats/WeightReminderCheck.js b/front/src/components/stats/WeightReminderCheck.js index 0b1cae4..61b8f5d 100644 --- a/front/src/components/stats/WeightReminderCheck.js +++ b/front/src/components/stats/WeightReminderCheck.js @@ -1,7 +1,7 @@ import React, { useState, useEffect, useCallback } from 'react'; import AsyncStorage from '@react-native-async-storage/async-storage'; import { useAuth } from '../../context/AuthContext'; -import { getWeightHistory } from '../../services/weight.service'; +import { getWeightHistory } from '../../services'; import WeightReminderModal from './WeightReminderModal'; import WeightEntryModal from '../common/WeightEntryModal'; diff --git a/front/src/components/stats/WeightReminderModal.js b/front/src/components/stats/WeightReminderModal.js index 407f2a0..7292cb2 100644 --- a/front/src/components/stats/WeightReminderModal.js +++ b/front/src/components/stats/WeightReminderModal.js @@ -54,7 +54,7 @@ const styles = StyleSheet.create({ }, card: { width: '100%', - backgroundColor: '#13131C', + backgroundColor: Colors.bgDeep2, borderRadius: 22, borderWidth: 1, borderColor: `${Colors.primary}38`, diff --git a/front/src/components/stats/XPProgressBar.js b/front/src/components/stats/XPProgressBar.js index 0e465df..924e7cb 100644 --- a/front/src/components/stats/XPProgressBar.js +++ b/front/src/components/stats/XPProgressBar.js @@ -1,7 +1,7 @@ import React from 'react'; import { View, Text, StyleSheet } from 'react-native'; import { Colors } from '../../constants/theme'; -import { xpToLevel } from '../../services/stats.service'; +import { xpToLevel } from '../../services'; // Bar de progression niveau / XP. Reรงoit le total XP cumulรฉ. // Visualise : niveau actuel + barre + xp restant pour next level. diff --git a/front/src/components/tutorial/TutorialOverlay.js b/front/src/components/tutorial/TutorialOverlay.js index b34cf25..6dbf80d 100644 --- a/front/src/components/tutorial/TutorialOverlay.js +++ b/front/src/components/tutorial/TutorialOverlay.js @@ -6,7 +6,7 @@ import { import { Ionicons } from '@expo/vector-icons'; import { useTutorial } from '../../context/TutorialContext'; import { CHAPTER_IDS } from '../../data/tutorialChapters'; -import { haptics } from '../../services/haptics.service'; +import { haptics } from '../../services'; import { Colors } from '../../constants/theme'; // Padding visuel autour du spotlight (lรฉger, ne perturbe pas les coordonnรฉes) @@ -262,7 +262,7 @@ export default function TutorialOverlay({ navigation }) { Passer diff --git a/front/src/components/typography/SectionTitle.js b/front/src/components/typography/SectionTitle.js deleted file mode 100644 index 782dcec..0000000 --- a/front/src/components/typography/SectionTitle.js +++ /dev/null @@ -1,21 +0,0 @@ -// ============================================================================================ -// Composant SectionTitle -// Affiche un titre de section avec un style uniforme -// ============================================================================================ - -import React from "react"; -import { Text, StyleSheet } from "react-native"; -import { Colors } from "../../constants/theme"; - -export default function SectionTitle({ title }) { - return {title}; -} - -const styles = StyleSheet.create({ - section: { - color: Colors.textPrimary, - fontSize: 18, - marginVertical: 16, - fontWeight: "bold", - }, -}); \ No newline at end of file diff --git a/front/src/components/ui/AppToast.js b/front/src/components/ui/AppToast.js index ea8d914..fbeaeb7 100644 --- a/front/src/components/ui/AppToast.js +++ b/front/src/components/ui/AppToast.js @@ -4,13 +4,14 @@ import { } from 'react-native'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { Ionicons } from '@expo/vector-icons'; +import { Colors } from '../../constants/theme'; // โ”€โ”€โ”€ Config par type โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ const TYPE_CONFIG = { - success: { icon: 'checkmark-circle', color: '#22C55E' }, - error: { icon: 'close-circle', color: '#FF4D4D' }, - warning: { icon: 'warning', color: '#F59E0B' }, + success: { icon: 'checkmark-circle', color: Colors.valid }, + error: { icon: 'close-circle', color: Colors.error }, + warning: { icon: 'warning', color: Colors.warningAmber }, info: { icon: 'information-circle', color: '#4A9EFF' }, }; @@ -132,7 +133,7 @@ const styles = StyleSheet.create({ }, message: { flex: 1, - color: '#FFFFFF', + color: Colors.textPrimary, fontSize: 14, fontWeight: '600', lineHeight: 20, diff --git a/front/src/components/web/DesktopInstallPage.js b/front/src/components/web/DesktopInstallPage.js index fe227b0..eb7e80a 100644 --- a/front/src/components/web/DesktopInstallPage.js +++ b/front/src/components/web/DesktopInstallPage.js @@ -1,6 +1,7 @@ import React from 'react'; import { View, Text, Image, StyleSheet } from 'react-native'; import { Ionicons } from '@expo/vector-icons'; +import { Colors } from '../../constants/theme'; const LOGO = require('../../../assets/logo-orange.png'); @@ -60,7 +61,7 @@ export default function DesktopInstallPage() { icon="logo-chrome" title="Chrome" platform="Android" - accent="#FE7439" + accent={Colors.primary} steps={[ 'Ouvrez ce lien dans Chrome sur votre Android', 'Appuyez sur โ‹ฎ (3 points) en haut ร  droite', @@ -71,7 +72,7 @@ export default function DesktopInstallPage() { icon="logo-apple" title="Safari" platform="iPhone ยท iPad" - accent="#6E6AF0" + accent={Colors.secondaryAccent} steps={[ 'Ouvrez ce lien dans Safari sur votre iPhone', 'Appuyez sur l\'icรดne Partager (โ–กโ†‘) en bas', @@ -105,7 +106,7 @@ const s = StyleSheet.create({ card: { width: '100%', maxWidth: 700, - backgroundColor: '#080910', + backgroundColor: Colors.bgAbyss, borderRadius: 24, borderWidth: 1, borderColor: 'rgba(110,106,240,0.18)', @@ -126,7 +127,7 @@ const s = StyleSheet.create({ headline: { fontSize: 32, fontWeight: '800', - color: '#FFFFFF', + color: Colors.textPrimary, textAlign: 'center', letterSpacing: -0.8, marginBottom: 12, @@ -159,7 +160,7 @@ const s = StyleSheet.create({ }, urlText: { fontSize: 15, - color: '#6E6AF0', + color: Colors.secondaryAccent, fontWeight: '600', letterSpacing: 0.2, }, diff --git a/front/src/components/workouts/AddExerciseSheet.js b/front/src/components/workouts/AddExerciseSheet.js index 1c53dd3..d7ae4f8 100644 --- a/front/src/components/workouts/AddExerciseSheet.js +++ b/front/src/components/workouts/AddExerciseSheet.js @@ -203,7 +203,7 @@ const styles = StyleSheet.create({ width: 44, height: 44, borderRadius: 10, - backgroundColor: '#0e0e12', + backgroundColor: Colors.cardInner, alignItems: 'center', justifyContent: 'center', marginRight: 12, diff --git a/front/src/components/workouts/ExerciseHeader.js b/front/src/components/workouts/ExerciseHeader.js index bec7f83..295dad7 100644 --- a/front/src/components/workouts/ExerciseHeader.js +++ b/front/src/components/workouts/ExerciseHeader.js @@ -83,7 +83,7 @@ const styles = StyleSheet.create({ paddingTop: 12, paddingBottom: 22, borderBottomWidth: StyleSheet.hairlineWidth, - borderBottomColor: '#1f1f27', + borderBottomColor: Colors.borderSubtle, }, topRow: { flexDirection: 'row', diff --git a/front/src/components/workouts/LobbyInviteCheck.js b/front/src/components/workouts/LobbyInviteCheck.js index 12550c2..0c05b33 100644 --- a/front/src/components/workouts/LobbyInviteCheck.js +++ b/front/src/components/workouts/LobbyInviteCheck.js @@ -2,7 +2,7 @@ import React, { useState, useEffect, useCallback, useRef } from 'react'; import * as Notifications from 'expo-notifications'; import { Platform } from 'react-native'; import { useAuth } from '../../context/AuthContext'; -import { joinLobby } from '../../services/lobby.service'; +import { joinLobby } from '../../services'; import { navigate } from '../../navigation/navigationRef'; import LobbyInviteModal from './LobbyInviteModal'; diff --git a/front/src/components/workouts/LobbyInviteModal.js b/front/src/components/workouts/LobbyInviteModal.js index 11b0bed..07ddd41 100644 --- a/front/src/components/workouts/LobbyInviteModal.js +++ b/front/src/components/workouts/LobbyInviteModal.js @@ -52,7 +52,7 @@ const styles = StyleSheet.create({ }, card: { width: '100%', - backgroundColor: '#13131C', + backgroundColor: Colors.bgDeep2, borderRadius: 22, borderWidth: 1, borderColor: `${Colors.primary}38`, diff --git a/front/src/components/workouts/LobbyWaitingOverlay.js b/front/src/components/workouts/LobbyWaitingOverlay.js index 4ccc661..54be323 100644 --- a/front/src/components/workouts/LobbyWaitingOverlay.js +++ b/front/src/components/workouts/LobbyWaitingOverlay.js @@ -62,7 +62,7 @@ const styles = StyleSheet.create({ }, card: { width: '100%', - backgroundColor: '#13131C', + backgroundColor: Colors.bgDeep2, borderRadius: 22, borderWidth: 1, borderColor: `${Colors.primary}38`, diff --git a/front/src/components/workouts/MultiLobbyModal.js b/front/src/components/workouts/MultiLobbyModal.js index d597d8f..625640d 100644 --- a/front/src/components/workouts/MultiLobbyModal.js +++ b/front/src/components/workouts/MultiLobbyModal.js @@ -2,8 +2,8 @@ import React, { useState, useEffect, useCallback, useRef } from 'react'; import { View, Text, StyleSheet, Modal, TouchableOpacity, ActivityIndicator, FlatList } from 'react-native'; import { Ionicons } from '@expo/vector-icons'; import { Colors } from '../../constants/theme'; -import { createLobby, getLobby, joinLobby, inviteToLobby, readyLobby, unreadyLobby } from '../../services/lobby.service'; -import { getFriendsList } from '../../services/social.service'; +import { createLobby, getLobby, joinLobby, inviteToLobby, readyLobby, unreadyLobby } from '../../services'; +import { getFriendsList } from '../../services'; import { useUser } from '../../context/UserContext'; const POLL_MS = 3000; @@ -328,7 +328,7 @@ const styles = StyleSheet.create({ }, card: { width: '100%', - backgroundColor: '#13131C', + backgroundColor: Colors.bgDeep2, borderRadius: 22, borderWidth: 1, borderColor: `${Colors.primary}38`, @@ -361,7 +361,7 @@ const styles = StyleSheet.create({ statusDot: { position: 'absolute', bottom: -4, right: -4, width: 16, height: 16, borderRadius: 8, - borderWidth: 1.5, borderColor: '#13131C', + borderWidth: 1.5, borderColor: Colors.bgDeep2, justifyContent: 'center', alignItems: 'center', }, memberName: { color: Colors.textMuted, fontSize: 10.5, fontWeight: '600', marginTop: 5, textAlign: 'center' }, @@ -413,7 +413,7 @@ const styles = StyleSheet.create({ // โ”€โ”€ BonusTableModal โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ tableCard: { width: '100%', - backgroundColor: '#13131C', + backgroundColor: Colors.bgDeep2, borderRadius: 22, borderWidth: 1, borderColor: `${Colors.primary}38`, diff --git a/front/src/components/workouts/MultiLootModal.js b/front/src/components/workouts/MultiLootModal.js index 651f6e3..88528cf 100644 --- a/front/src/components/workouts/MultiLootModal.js +++ b/front/src/components/workouts/MultiLootModal.js @@ -56,7 +56,7 @@ const styles = StyleSheet.create({ }, card: { width: '100%', - backgroundColor: '#13131C', + backgroundColor: Colors.bgDeep2, borderRadius: 24, borderWidth: 1, borderColor: 'rgba(255,215,0,0.4)', diff --git a/front/src/components/workouts/MuscleHierarchyPicker.js b/front/src/components/workouts/MuscleHierarchyPicker.js index 8ad90a7..eca1daf 100644 --- a/front/src/components/workouts/MuscleHierarchyPicker.js +++ b/front/src/components/workouts/MuscleHierarchyPicker.js @@ -168,7 +168,7 @@ const styles = StyleSheet.create({ marginBottom: 10, overflow: 'hidden', borderWidth: 1, - borderColor: '#1f1f27', + borderColor: Colors.borderSubtle, }, groupCardActive: { borderColor: 'rgba(254, 116, 57, 0.5)', @@ -183,7 +183,7 @@ const styles = StyleSheet.create({ width: 42, height: 42, borderRadius: 10, - backgroundColor: '#0e0e12', + backgroundColor: Colors.cardInner, alignItems: 'center', justifyContent: 'center', marginRight: 12, diff --git a/front/src/components/workouts/SetTable.js b/front/src/components/workouts/SetTable.js index 9967e72..a38c5d9 100644 --- a/front/src/components/workouts/SetTable.js +++ b/front/src/components/workouts/SetTable.js @@ -125,7 +125,7 @@ const styles = StyleSheet.create({ justifyContent: 'center', }, headerText: { - color: '#8B95A3', + color: Colors.textDim, fontSize: 11, fontWeight: '700', letterSpacing: 1, diff --git a/front/src/components/workouts/ShortSessionWarningModal.js b/front/src/components/workouts/ShortSessionWarningModal.js index 16bb23d..e4a2fd1 100644 --- a/front/src/components/workouts/ShortSessionWarningModal.js +++ b/front/src/components/workouts/ShortSessionWarningModal.js @@ -80,7 +80,7 @@ const styles = StyleSheet.create({ }, card: { width: '100%', - backgroundColor: '#13131C', + backgroundColor: Colors.bgDeep2, borderRadius: 24, borderWidth: 1, borderColor: 'rgba(255,77,77,0.28)', @@ -88,7 +88,7 @@ const styles = StyleSheet.create({ paddingTop: 32, paddingBottom: 28, alignItems: 'center', - shadowColor: '#FF4D4D', + shadowColor: Colors.error, shadowOffset: { width: 0, height: 12 }, shadowOpacity: 0.25, shadowRadius: 28, diff --git a/front/src/components/workouts/WorkoutHeader.js b/front/src/components/workouts/WorkoutHeader.js deleted file mode 100644 index 41ce9b0..0000000 --- a/front/src/components/workouts/WorkoutHeader.js +++ /dev/null @@ -1,72 +0,0 @@ -import React from 'react'; -import { View, Text, StyleSheet } from 'react-native'; -import { Colors } from '../../constants/theme'; - -// Logo ATHLY (mark + wordmark) pour rester pixel-perfect avec la maquette. -function AthlyLogo() { - return ( - - โ–ณ - ATHLY - - ); -} - -export default function WorkoutHeader({ title = 'Sรฉance', subtitle = null }) { - return ( - - - {title} - {subtitle ? {subtitle} : null} - - - - ); -} - -const styles = StyleSheet.create({ - container: { - flexDirection: 'row', - alignItems: 'center', - justifyContent: 'space-between', - paddingHorizontal: 20, - paddingTop: 40, - paddingBottom: 14, - backgroundColor: Colors.background, - borderBottomWidth: StyleSheet.hairlineWidth, - borderBottomColor: '#1f1f27', - }, - titleBlock: { - flex: 1, - paddingRight: 12, - }, - title: { - color: Colors.textPrimary, - fontSize: 26, - fontWeight: '700', - letterSpacing: 0.2, - }, - subtitle: { - color: Colors.textSecondary, - fontSize: 13, - marginTop: 4, - }, - logoWrap: { - alignItems: 'center', - justifyContent: 'center', - paddingHorizontal: 6, - }, - logoMark: { - color: Colors.primary, - fontSize: 26, - lineHeight: 28, - fontWeight: '900', - marginBottom: 2, - }, - logoText: { - color: Colors.primary, - fontSize: 11, - fontWeight: '900', - letterSpacing: 1.5, - }, -}); diff --git a/front/src/components/workouts/WorkoutRecapModal.js b/front/src/components/workouts/WorkoutRecapModal.js index 43b2073..870a09a 100644 --- a/front/src/components/workouts/WorkoutRecapModal.js +++ b/front/src/components/workouts/WorkoutRecapModal.js @@ -16,8 +16,8 @@ const SCREEN_H = Dimensions.get('window').height; import { Ionicons } from '@expo/vector-icons'; import * as Haptics from 'expo-haptics'; import { Colors } from '../../constants/theme'; -import { xpToLevel, getRank } from '../../services/stats.service'; -import { QUEST_XP, BONUS_XP } from '../../services/quest.service'; +import { xpToLevel, getRank } from '../../services'; +import { QUEST_XP, BONUS_XP } from '../../services'; const LOGO_VIOLET = require('../../../assets/logo-violet.png'); @@ -464,13 +464,13 @@ export default function WorkoutRecapModal({ {streakBonusXP > 0 && ( Bonus Rรฉgularitรฉ ร—{xpMultiplier} - +{streakBonusXP.toLocaleString('fr-FR')} XP + +{streakBonusXP.toLocaleString('fr-FR')} XP )} {questXPEarned > 0 && ( Bonus Quรชtes - +{questXPEarned.toLocaleString('fr-FR')} XP + +{questXPEarned.toLocaleString('fr-FR')} XP )} @@ -557,9 +557,9 @@ export default function WorkoutRecapModal({ ))} {bonusUnlocked ? ( - - Bonus toutes quรชtes - +{BONUS_XP} XP + + Bonus toutes quรชtes + +{BONUS_XP} XP ) : null} diff --git a/front/src/constants/theme.js b/front/src/constants/theme.js index 2bb4801..4142b4a 100644 --- a/front/src/constants/theme.js +++ b/front/src/constants/theme.js @@ -51,9 +51,10 @@ export const Colors = { uniqueBloodGlow: 'rgba(163,0,0,0.65)', // โ”€โ”€ Feedback โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - valid: '#22C55E', // sets / exercices validรฉs (vert chaud) - success: '#44FF88', // XP / gains (vert nรฉon) - error: '#FF4D4D', + valid: '#22C55E', // sets / exercices validรฉs (vert chaud) + success: '#44FF88', // XP / gains (vert nรฉon) + error: '#FF4D4D', + destructive: '#EF4444', // actions destructrices (Supprimerโ€ฆ), accent rouge des modales // โ”€โ”€ Utilitaires โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ chevron: '#888888', diff --git a/front/src/context/CustomExercisesContext.js b/front/src/context/CustomExercisesContext.js index 48cd449..8bfcd38 100644 --- a/front/src/context/CustomExercisesContext.js +++ b/front/src/context/CustomExercisesContext.js @@ -4,7 +4,7 @@ import { addCustomExercise, updateCustomExercise, removeCustomExercise, -} from '../services/customExercises.service'; +} from '../services'; // Context global pour les exercices personnalisรฉs. // - Charge la liste depuis AsyncStorage au montage diff --git a/front/src/context/QuestContext.js b/front/src/context/QuestContext.js index d15a0f6..e60ea5d 100644 --- a/front/src/context/QuestContext.js +++ b/front/src/context/QuestContext.js @@ -12,7 +12,7 @@ import { getTemplateById, QUEST_XP, BONUS_XP, -} from '../services/quest.service'; +} from '../services'; import { useWorkoutLogs } from './WorkoutLogsContext'; const QuestContext = createContext(null); diff --git a/front/src/context/SavedWorkoutsContext.js b/front/src/context/SavedWorkoutsContext.js index da59366..4c69a56 100644 --- a/front/src/context/SavedWorkoutsContext.js +++ b/front/src/context/SavedWorkoutsContext.js @@ -4,7 +4,7 @@ import { saveWorkout, updateSavedWorkout, removeSavedWorkout, -} from '../services/savedWorkouts.service'; +} from '../services'; // Context global pour les sรฉances sauvegardรฉes (favoris / rรฉutilisables). // Chargement initial depuis AsyncStorage, mise ร  jour optimiste aprรจs chaque action. diff --git a/front/src/context/TutorialContext.js b/front/src/context/TutorialContext.js index 87bd0b8..a549e40 100644 --- a/front/src/context/TutorialContext.js +++ b/front/src/context/TutorialContext.js @@ -1,7 +1,7 @@ import React, { createContext, useState, useContext, useCallback, useEffect, useRef } from 'react'; import AsyncStorage from '@react-native-async-storage/async-storage'; -import { TUTORIAL_CHAPTERS, CHAPTER_MAP, CHAPTER_IDS } from '../data/tutorialChapters'; -import { completeOnboarding } from '../services/onboarding.service'; +import { CHAPTER_MAP, CHAPTER_IDS } from '../data/tutorialChapters'; +import { completeOnboarding } from '../services'; const DONE_KEY = 'athly:tutorial:completed:v1'; const PENDING_KEY = 'athly:tutorial:pendingChapter:v1'; diff --git a/front/src/context/WorkoutInProgressContext.js b/front/src/context/WorkoutInProgressContext.js index 1853d4e..8807bf7 100644 --- a/front/src/context/WorkoutInProgressContext.js +++ b/front/src/context/WorkoutInProgressContext.js @@ -1,8 +1,8 @@ import React, { createContext, useContext, useCallback, useMemo } from 'react'; -import useWorkoutState from '../hooks/useWorkoutState'; +import { useWorkoutState } from '../hooks'; import { useWorkoutLogs } from './WorkoutLogsContext'; import { useQuests } from './QuestContext'; -import { buildLogFromWorkout, findNewPRsInLog } from '../services/stats.service'; +import { buildLogFromWorkout, findNewPRsInLog } from '../services'; // Context global pour la sรฉance en cours. // Centralise useWorkoutState : tous les รฉcrans consomment le mรชme รฉtat + actions diff --git a/front/src/context/WorkoutLogsContext.js b/front/src/context/WorkoutLogsContext.js index 8b0f178..7945e1e 100644 --- a/front/src/context/WorkoutLogsContext.js +++ b/front/src/context/WorkoutLogsContext.js @@ -1,7 +1,7 @@ import React, { createContext, useContext, useState, useEffect, useRef, useCallback, useMemo } from 'react'; import { AppState } from 'react-native'; -import { listLogs, addLog, removeLog, totalCumulativeXP, addRitualLog, addBonusXpLog } from '../services/stats.service'; -import { syncXp, retryPendingXpSync } from '../services/xpSync.service'; +import { listLogs, addLog, removeLog, totalCumulativeXP, addRitualLog, addBonusXpLog } from '../services'; +import { syncXp, retryPendingXpSync } from '../services'; // Context global pour l'historique des sรฉances finalisรฉes (logs). // Source de vรฉritรฉ unique pour StatsScreen, ExerciseStatsScreen, ProfileScreen. diff --git a/front/src/hooks/index.js b/front/src/hooks/index.js new file mode 100644 index 0000000..ab25cbd --- /dev/null +++ b/front/src/hooks/index.js @@ -0,0 +1,11 @@ +// โ”€โ”€โ”€ Barrel des hooks โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +// Point d'entrรฉe unique : `import { useAvatarFrame, useEffortTimer } from '../hooks';` +// Les hooks ร  export default sont rรฉ-exportรฉs sous leur nom canonique. + +export { useAvatarFrame } from './useAvatarFrame'; +export { useDevSettings } from './useDevSettings'; +export { default as useEffortTimer, formatDuration } from './useEffortTimer'; +export { default as useExerciseSorting, isFiltering } from './useExerciseSorting'; +export { useFeaturedTrophies, MAX_FEATURED } from './useFeaturedTrophies'; +export { useGoogleAuth } from './useGoogleAuth'; +export { default as useWorkoutState } from './useWorkoutState'; diff --git a/front/src/hooks/useWorkoutState.js b/front/src/hooks/useWorkoutState.js index 0afd2e0..aeb5cbe 100644 --- a/front/src/hooks/useWorkoutState.js +++ b/front/src/hooks/useWorkoutState.js @@ -1,5 +1,5 @@ import { useReducer, useEffect, useRef, useCallback, useMemo } from 'react'; -import API from '../api/api'; +import { createWorkoutDraft, updateWorkoutDraft, finalizeWorkout } from '../services/workouts.service'; // --------------------------------------------------------------------------- // useWorkoutState @@ -229,27 +229,22 @@ export default function useWorkoutState(initial = {}) { isSaving.current = true; try { if (!state.id) { - const res = await API.post('/workouts/draft', { + const workout = await createWorkoutDraft({ name: state.name, exercises: state.exercises, notes: state.notes, - status: 'draft', }); - const data = res && res.data ? res.data : res; - const workout = data && data.workout ? data.workout : null; if (workout) { dispatch({ type: ACTIONS.SET_WORKOUT, payload: { id: workout._id } }); return workout; } return null; } - const res = await API.patch(`/workouts/${state.id}/draft`, { + return await updateWorkoutDraft(state.id, { exercises: state.exercises, notes: state.notes, durationSeconds: state.durationSeconds, }); - const data = res && res.data ? res.data : res; - return data && data.workout ? data.workout : data; } catch (error) { // Pas de Alert ici pour รฉviter le spam โ€” on le centralise dans finalize/handler explicite. return null; @@ -267,13 +262,12 @@ export default function useWorkoutState(initial = {}) { const saved = await saveDraft(); const workoutId = state.id || (saved && (saved._id || saved.id)); if (!workoutId) throw new Error('no_id'); - const res = await API.post(`/workouts/${workoutId}/finalize`, { + const data = await finalizeWorkout(workoutId, { exercises: state.exercises, notes: state.notes, durationSeconds: state.durationSeconds, ...options, }); - const data = res && res.data ? res.data : res; if (data && data.stats) { dispatch({ type: ACTIONS.MARK_FINISHED }); return data.stats; diff --git a/front/src/navigation/index.js b/front/src/navigation/index.js index c1d0963..de3746f 100644 --- a/front/src/navigation/index.js +++ b/front/src/navigation/index.js @@ -19,8 +19,8 @@ import { QuestProvider } from '../context/QuestContext'; import { UserProvider } from '../context/UserContext'; import { TutorialProvider } from '../context/TutorialContext'; import AsyncStorage from '@react-native-async-storage/async-storage'; -import { setupNotificationChannels, ensureDailyRemindersScheduled, getExpoPushToken } from '../services/notificationService'; -import { registerPushToken } from '../services/profile.service'; +import { setupNotificationChannels, ensureDailyRemindersScheduled, getExpoPushToken } from '../services'; +import { registerPushToken } from '../services'; import BirthdayCelebration from '../components/profile/BirthdayCelebration'; import LevelUpCelebration from '../components/profile/LevelUpCelebration'; import ActivityFeedModal from '../components/social/ActivityFeedModal'; diff --git a/front/src/screens/Auth/AuthScreen.js b/front/src/screens/Auth/AuthScreen.js deleted file mode 100644 index e4a3609..0000000 --- a/front/src/screens/Auth/AuthScreen.js +++ /dev/null @@ -1,396 +0,0 @@ -import React, { useState, useRef, useEffect } from 'react'; -import { - View, Text, StyleSheet, TouchableOpacity, Image, - KeyboardAvoidingView, Platform, ActivityIndicator, - Dimensions, Animated, Easing, ScrollView, StatusBar, -} from 'react-native'; -import { SafeAreaView } from 'react-native-safe-area-context'; -import { Ionicons } from '@expo/vector-icons'; - -import { Colors } from '../../constants/theme'; -import AuthInput from '../../components/inputs/AuthInput'; -import { login, register } from '../../services/auth.service'; -import { useAuth } from '../../context/AuthContext'; - -// Imports statiques des assets (chemin : src/screens/Auth/ โ†’ ../../../assets/) -const LOGO_ORANGE = require('../../../assets/logo-orange.png'); -const LOGO_ICON_ORANGE = require('../../../assets/minimalist-logo-orange.png'); - -const { width: _rawW } = Dimensions.get('window'); -const W = Platform.OS === 'web' ? Math.min(430, _rawW) : _rawW; -const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; - -function FadeLoader() { - const opacity = useRef(new Animated.Value(0)).current; - useEffect(() => { - Animated.timing(opacity, { toValue: 1, duration: 220, useNativeDriver: true }).start(); - }, []); - return ( - - - - ); -} - -export default function AuthScreen() { - const { signIn } = useAuth(); - const slideAnim = useRef(new Animated.Value(0)).current; - - // โ”€โ”€ Login state โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - const [loginEmail, setLoginEmail] = useState(''); - const [loginPassword, setLoginPassword] = useState(''); - const [loginLoading, setLoginLoading] = useState(false); - const [loginShowPwd, setLoginShowPwd] = useState(false); - const [loginEmailErr, setLoginEmailErr] = useState(''); - const [loginGlobalErr, setLoginGlobalErr] = useState(''); - - // โ”€โ”€ Register state โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - const [regName, setRegName] = useState(''); - const [regEmail, setRegEmail] = useState(''); - const [regPassword, setRegPassword] = useState(''); - const [regLoading, setRegLoading] = useState(false); - const [regShowPwd, setRegShowPwd] = useState(false); - const [regNameErr, setRegNameErr] = useState(''); - const [regEmailErr, setRegEmailErr] = useState(''); - const [regPwdErr, setRegPwdErr] = useState(''); - const [regGlobalErr, setRegGlobalErr] = useState(''); - - // โ”€โ”€ Slide โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - const slideTo = (panel) => { - Animated.timing(slideAnim, { - toValue: panel === 'login' ? 0 : -W, - duration: 400, - easing: Easing.out(Easing.exp), - useNativeDriver: true, - }).start(); - }; - - // โ”€โ”€ Validators โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - const validateLoginEmail = (val = loginEmail) => { - if (!val) { setLoginEmailErr('Email requis'); return false; } - if (!EMAIL_RE.test(val)) { setLoginEmailErr('Email invalide'); return false; } - setLoginEmailErr(''); return true; - }; - - const validateRegEmail = (val = regEmail) => { - if (!val) { setRegEmailErr('Email requis'); return false; } - if (!EMAIL_RE.test(val)) { setRegEmailErr('Email invalide'); return false; } - setRegEmailErr(''); return true; - }; - - // โ”€โ”€ Handlers โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - const handleLogin = async () => { - if (!validateLoginEmail() || !loginPassword) return; - try { - setLoginLoading(true); - setLoginGlobalErr(''); - const res = await login(loginEmail, loginPassword); - if (res?.token) await signIn(res.token); - else throw new Error(); - } catch { - setLoginGlobalErr('Email ou mot de passe incorrect.'); - } finally { - setLoginLoading(false); - } - }; - - const handleRegister = async () => { - let ok = true; - if (!regName) { setRegNameErr('Nom requis'); ok = false; } else setRegNameErr(''); - if (!validateRegEmail()) ok = false; - if (regPassword.length < 6) { setRegPwdErr('6 caractรจres minimum'); ok = false; } else setRegPwdErr(''); - if (!ok) return; - try { - setRegLoading(true); - setRegGlobalErr(''); - const res = await register({ name: regName, email: regEmail, password: regPassword }); - if (res?.token) await signIn(res.token); - else slideTo('login'); - } catch { - setRegGlobalErr("Erreur lors de l'inscription. Email dรฉjร  utilisรฉ ?"); - } finally { - setRegLoading(false); - } - }; - - return ( - - - - - - - - {/* โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• - PANEL LOGIN - โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• */} - - - - - Bienvenue - Connectez-vous pour continuer - - - { setLoginEmail(v); if (loginEmailErr) validateLoginEmail(v); }} - onBlur={() => validateLoginEmail()} - error={loginEmailErr} - keyboardType="email-address" - autoCapitalize="none" - autoCorrect={false} - /> - - - {loginGlobalErr ? {loginGlobalErr} : null} - - - {loginLoading ? : Se connecter} - - - - Pas encore de compte ? - slideTo('register')}> - S'inscrire - - - - - {/* โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• - PANEL REGISTER - โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• */} - - slideTo('login')}> - - - - - - - Crรฉer un compte - Rejoignez la communautรฉ Athly - - - { setRegName(v); if (regNameErr) setRegNameErr(''); }} - error={regNameErr} - /> - { setRegEmail(v); if (regEmailErr) validateRegEmail(v); }} - onBlur={() => validateRegEmail()} - error={regEmailErr} - keyboardType="email-address" - autoCapitalize="none" - autoCorrect={false} - /> - { - setRegPassword(v); - if (regPwdErr) setRegPwdErr(v.length >= 6 ? '' : '6 caractรจres minimum'); - }} - isPassword - secureTextEntry={!regShowPwd} - showPassword={regShowPwd} - setShowPassword={setRegShowPwd} - error={regPwdErr} - /> - - {regGlobalErr ? {regGlobalErr} : null} - - - {regLoading ? : Crรฉer mon compte} - - - - Dรฉjร  inscrit ? - slideTo('login')}> - Se connecter - - - - - - - - - ); -} - -const styles = StyleSheet.create({ - safeArea: { - flex: 1, - backgroundColor: Colors.backgroundDeep, - }, - kav: { - flex: 1, - backgroundColor: Colors.backgroundDeep, - }, - clipper: { - flex: 1, - overflow: 'hidden', - backgroundColor: Colors.backgroundDeep, - }, - slider: { - flex: 1, - flexDirection: 'row', - width: W * 2, - }, - panel: { - width: W, - backgroundColor: Colors.backgroundDeep, - }, - panelContent: { - paddingHorizontal: 28, - paddingTop: 20, - paddingBottom: 56, - }, - - // โ”€โ”€ Logo Login (image brute, dimensions explicites) โ”€โ”€โ”€โ”€โ”€โ”€ - logoImg: { - width: 180, - height: 120, - alignSelf: 'center', - marginBottom: 30, - marginTop: 4, - }, - // โ”€โ”€ Logo Register (icรดne discrรจte) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - logoSmall: { - width: 26, - height: 26, - alignSelf: 'flex-start', - marginBottom: 20, - opacity: 0.6, - }, - - // โ”€โ”€ Typographie โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - titleBlock: { - marginBottom: 32, - }, - brand: { - color: Colors.textPrimary, - fontSize: 30, - fontWeight: '700', - letterSpacing: -0.5, - marginBottom: 6, - }, - tagline: { - color: Colors.textMuted, - fontSize: 14, - letterSpacing: 0.2, - }, - - // โ”€โ”€ Erreur globale โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - globalError: { - color: Colors.error, - fontSize: 13, - textAlign: 'center', - marginTop: 8, - marginBottom: 4, - }, - - // โ”€โ”€ Bouton principal โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - primaryBtn: { - backgroundColor: Colors.primary, - height: 56, - borderRadius: 14, - justifyContent: 'center', - alignItems: 'center', - marginTop: 24, - shadowColor: Colors.primary, - shadowOffset: { width: 0, height: 8 }, - shadowOpacity: 0.4, - shadowRadius: 16, - elevation: 8, - }, - btnText: { - color: '#fff', - fontSize: 16, - fontWeight: '700', - letterSpacing: 0.4, - }, - - // โ”€โ”€ Lien de bascule โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - switchRow: { - flexDirection: 'row', - justifyContent: 'center', - marginTop: 36, - }, - switchLabel: { - color: Colors.textMuted, - fontSize: 14, - }, - linkBold: { - color: Colors.primary, - fontWeight: '700', - fontSize: 14, - }, - - // โ”€โ”€ Retour โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - backBtn: { - width: 36, - height: 36, - justifyContent: 'center', - marginBottom: 8, - }, -}); diff --git a/front/src/screens/Auth/EmailVerificationScreen.js b/front/src/screens/Auth/EmailVerificationScreen.js index 24b85cf..8c08329 100644 --- a/front/src/screens/Auth/EmailVerificationScreen.js +++ b/front/src/screens/Auth/EmailVerificationScreen.js @@ -8,8 +8,8 @@ import { SafeAreaView } from 'react-native-safe-area-context'; import { Ionicons } from '@expo/vector-icons'; import { Colors } from '../../constants/theme'; -import NotificationBanner from '../../components/common/NotificationBanner'; -import { verifyEmail, resendVerificationEmail } from '../../services/auth.service'; +import { NotificationBanner } from '../../components/common'; +import { verifyEmail, resendVerificationEmail } from '../../services'; import { useAuth } from '../../context/AuthContext'; const CODE_LENGTH = 6; diff --git a/front/src/screens/Auth/ForgotPasswordScreen.js b/front/src/screens/Auth/ForgotPasswordScreen.js index 3057934..bd3d90a 100644 --- a/front/src/screens/Auth/ForgotPasswordScreen.js +++ b/front/src/screens/Auth/ForgotPasswordScreen.js @@ -9,8 +9,8 @@ import { Ionicons } from '@expo/vector-icons'; import { Colors } from '../../constants/theme'; import AuthInput from '../../components/inputs/AuthInput'; -import NotificationBanner from '../../components/common/NotificationBanner'; -import { forgotPassword, resetPassword } from '../../services/auth.service'; +import { NotificationBanner } from '../../components/common'; +import { forgotPassword, resetPassword } from '../../services'; import { useToast } from '../../context/ToastContext'; const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; @@ -33,7 +33,7 @@ function getStrength(pwd) { function StrengthBar({ password }) { const score = getStrength(password); if (!password) return null; - const color = score === 3 ? '#44FF88' : score === 2 ? '#FFA500' : '#FF4D4D'; + const color = score === 3 ? Colors.success : score === 2 ? '#FFA500' : Colors.error; const label = score === 3 ? 'Fort' : score === 2 ? 'Moyen' : 'Faible'; return ( @@ -134,7 +134,7 @@ function WeakPasswordModal({ visible, onImprove, onSave, loading }) { - + Mot de passe simple @@ -182,7 +182,7 @@ const wm = StyleSheet.create({ }, card: { width: '100%', - backgroundColor: '#13131C', + backgroundColor: Colors.bgDeep2, borderRadius: 22, borderWidth: 1, borderColor: 'rgba(245,158,11,0.25)', diff --git a/front/src/screens/Auth/LoginScreen.js b/front/src/screens/Auth/LoginScreen.js index f535d91..e7b9b9f 100644 --- a/front/src/screens/Auth/LoginScreen.js +++ b/front/src/screens/Auth/LoginScreen.js @@ -9,10 +9,10 @@ import { Ionicons } from '@expo/vector-icons'; import { Colors } from '../../constants/theme'; import AuthInput from '../../components/inputs/AuthInput'; -import NotificationBanner from '../../components/common/NotificationBanner'; -import { login, googleLogin } from '../../services/auth.service'; +import { NotificationBanner } from '../../components/common'; +import { login, googleLogin } from '../../services'; import { useAuth } from '../../context/AuthContext'; -import { useGoogleAuth } from '../../hooks/useGoogleAuth'; +import { useGoogleAuth } from '../../hooks'; const LOGO_ORANGE = require('../../../assets/logo-orange.png'); const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; diff --git a/front/src/screens/Auth/RegisterScreen.js b/front/src/screens/Auth/RegisterScreen.js index 04aed33..d9170a7 100644 --- a/front/src/screens/Auth/RegisterScreen.js +++ b/front/src/screens/Auth/RegisterScreen.js @@ -9,9 +9,9 @@ import { Ionicons } from '@expo/vector-icons'; import { Colors } from '../../constants/theme'; import AuthInput from '../../components/inputs/AuthInput'; -import NotificationBanner from '../../components/common/NotificationBanner'; -import { register } from '../../services/auth.service'; -import { haptics } from '../../services/haptics.service'; +import { NotificationBanner } from '../../components/common'; +import { register } from '../../services'; +import { haptics } from '../../services'; const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; const HAS_UPPER = /[A-Z]/; @@ -32,7 +32,7 @@ function getStrength(pwd) { function StrengthBar({ password }) { const score = getStrength(password); if (!password) return null; - const color = score === 3 ? '#44FF88' : score === 2 ? '#FFA500' : '#FF4D4D'; + const color = score === 3 ? Colors.success : score === 2 ? '#FFA500' : Colors.error; const label = score === 3 ? 'Fort' : score === 2 ? 'Moyen' : 'Faible'; return ( @@ -76,7 +76,7 @@ function WeakPasswordModal({ visible, onImprove, onCreate, loading }) { {/* Icรดne */} - + Mot de passe simple @@ -124,7 +124,7 @@ const wm = StyleSheet.create({ }, card: { width: '100%', - backgroundColor: '#13131C', + backgroundColor: Colors.bgDeep2, borderRadius: 22, borderWidth: 1, borderColor: 'rgba(245,158,11,0.25)', @@ -219,7 +219,7 @@ function PseudoRejectedModal({ visible, onClose }) { - + Pseudo non autorisรฉ @@ -251,7 +251,7 @@ const pm = StyleSheet.create({ }, card: { width: '100%', - backgroundColor: '#13131C', + backgroundColor: Colors.bgDeep2, borderRadius: 22, borderWidth: 1, borderColor: 'rgba(239,68,68,0.35)', @@ -271,11 +271,11 @@ const pm = StyleSheet.create({ }, title: { color: Colors.textPrimary, fontSize: 19, fontWeight: '800', letterSpacing: -0.3, marginBottom: 12, textAlign: 'center' }, body: { color: Colors.textSecondary, fontSize: 14, lineHeight: 21, textAlign: 'center', marginBottom: 14 }, - warning: { color: '#EF4444', fontSize: 12.5, fontWeight: '700', lineHeight: 18, textAlign: 'center', marginBottom: 24 }, + warning: { color: Colors.destructive, fontSize: 12.5, fontWeight: '700', lineHeight: 18, textAlign: 'center', marginBottom: 24 }, closeBtn: { width: '100%', height: 50, borderRadius: 13, - backgroundColor: '#EF4444', justifyContent: 'center', alignItems: 'center', - shadowColor: '#EF4444', shadowOffset: { width: 0, height: 6 }, shadowOpacity: 0.35, shadowRadius: 12, elevation: 6, + backgroundColor: Colors.destructive, justifyContent: 'center', alignItems: 'center', + shadowColor: Colors.destructive, shadowOffset: { width: 0, height: 6 }, shadowOpacity: 0.35, shadowRadius: 12, elevation: 6, }, closeTxt: { color: '#fff', fontSize: 15, fontWeight: '700', letterSpacing: 0.2 }, }); diff --git a/front/src/screens/Home/HomeScreen.js b/front/src/screens/Home/HomeScreen.js index a5117ff..35ce1b1 100644 --- a/front/src/screens/Home/HomeScreen.js +++ b/front/src/screens/Home/HomeScreen.js @@ -19,7 +19,7 @@ import { recommendNextMuscleGroup, aggregateGlobal, xpToLevel, -} from '../../services/stats.service'; +} from '../../services'; import { findMuscleGroup } from '../../constants/exerciseFilters'; import { TEMPLATES, @@ -35,7 +35,7 @@ import DailyQuestsCard from '../../components/home/DailyQuestsCard'; import RecoveryRitualsCard from '../../components/home/RecoveryRitualsCard'; import TutorialOverlay from '../../components/tutorial/TutorialOverlay'; import { useTutorial, useTutorialTarget } from '../../context/TutorialContext'; -import { useDevSettings } from '../../hooks/useDevSettings'; +import { useDevSettings } from '../../hooks'; import { MOCK_TUTORIAL_LOGS } from '../../data/mockTutorialStats'; // ร‰cran d'accueil. Bascule entre EmptyHomeState (compte vierge) et รฉtat actif @@ -189,7 +189,7 @@ export default function HomeScreen({ navigation }) { {isTutorialDashboard && ( - + Donnรฉes de dรฉmonstration - disparaรฎtront ร  la fin du chapitre )} @@ -340,7 +340,7 @@ const styles = StyleSheet.create({ borderBottomWidth: 1, borderBottomColor: 'rgba(255,215,0,0.20)', paddingHorizontal: 16, paddingVertical: 8, }, - mockBannerText: { color: '#FFD700', fontSize: 11, fontWeight: '600', flex: 1 }, + mockBannerText: { color: Colors.gold, fontSize: 11, fontWeight: '600', flex: 1 }, scroll: { flex: 1 }, scrollContent: { paddingHorizontal: 20, diff --git a/front/src/screens/Profile/EditProfileScreen.js b/front/src/screens/Profile/EditProfileScreen.js index 841c202..e45a0ba 100644 --- a/front/src/screens/Profile/EditProfileScreen.js +++ b/front/src/screens/Profile/EditProfileScreen.js @@ -10,10 +10,10 @@ import { } from 'react-native'; import { Colors } from '../../constants/theme'; -import API from '../../api/api'; +import { updateMyProfile } from '../../services'; import { useUser } from '../../context/UserContext'; import { useToast } from '../../context/ToastContext'; -import { setBirthdate } from '../../services/reward.service'; +import { setBirthdate } from '../../services'; import BirthdatePicker from '../../components/profile/BirthdatePicker'; // โ”€โ”€โ”€ EditProfileScreen โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ @@ -107,8 +107,8 @@ export default function EditProfileScreen({ navigation }) { ...(parsedRythme !== null && { rythme: parsedRythme }), }; try { - const res = await API.put('/users/me', payload); - if (res.data.success) { + const res = await updateMyProfile(payload); + if (res.success) { refetchUser(); // met ร  jour le UserContext โ†’ ProfileScreen + SettingsScreen sync instantanรฉ showToast('Profil mis ร  jour avec succรจs !', 'success'); navigation.goBack(); @@ -351,7 +351,7 @@ const GRP_BORDER = 'rgba(255,255,255,0.09)'; const SEP = 'rgba(255,255,255,0.07)'; const styles = StyleSheet.create({ - root: { flex: 1, backgroundColor: '#080910' }, + root: { flex: 1, backgroundColor: Colors.bgAbyss }, scroll: { flex: 1 }, scrollContent: { paddingHorizontal: 16, paddingTop: 8 }, diff --git a/front/src/screens/Profile/InventoryScreen.js b/front/src/screens/Profile/InventoryScreen.js index 6796bdc..73a2a3f 100644 --- a/front/src/screens/Profile/InventoryScreen.js +++ b/front/src/screens/Profile/InventoryScreen.js @@ -9,12 +9,12 @@ import { Colors } from '../../constants/theme'; import { useUser } from '../../context/UserContext'; import { useWorkoutLogs } from '../../context/WorkoutLogsContext'; import { useToast } from '../../context/ToastContext'; -import { openChest, useItem, claimUniqueItem, ITEM_CATALOG, RARITY_META } from '../../services/inventory.service'; -import { xpForLevel, xpToLevel } from '../../services/stats.service'; -import { useAvatarFrame } from '../../hooks/useAvatarFrame'; -import { useDevSettings } from '../../hooks/useDevSettings'; +import { openChest, useItem, claimUniqueItem, ITEM_CATALOG, RARITY_META } from '../../services'; +import { xpForLevel, xpToLevel } from '../../services'; +import { useAvatarFrame } from '../../hooks'; +import { useDevSettings } from '../../hooks'; import ChestOpeningModal from '../../components/inventory/ChestOpeningModal'; -import { haptics } from '../../services/haptics.service'; +import { haptics } from '../../services'; import TutorialOverlay from '../../components/tutorial/TutorialOverlay'; import { useTutorial, useTutorialTarget } from '../../context/TutorialContext'; diff --git a/front/src/screens/Profile/ProfileScreen.js b/front/src/screens/Profile/ProfileScreen.js index 337a4b8..01f4864 100644 --- a/front/src/screens/Profile/ProfileScreen.js +++ b/front/src/screens/Profile/ProfileScreen.js @@ -23,16 +23,16 @@ import { xpToLevel, computeStreak, getRank, -} from '../../services/stats.service'; +} from '../../services'; import { resolveExerciseMeta } from '../../data/majorExercises'; -import { getMyRecords } from '../../services/social.service'; -import { getTitles } from '../../services/title.service'; -import { haptics } from '../../services/haptics.service'; -import { RARITY_META } from '../../services/inventory.service'; -import { syncLocalAchievements } from '../../services/reward.service'; -import { useAvatarFrame } from '../../hooks/useAvatarFrame'; -import { useDevSettings } from '../../hooks/useDevSettings'; -import { useFeaturedTrophies } from '../../hooks/useFeaturedTrophies'; +import { getMyRecords } from '../../services'; +import { getTitles } from '../../services'; +import { haptics } from '../../services'; +import { RARITY_META } from '../../services'; +import { syncLocalAchievements } from '../../services'; +import { useAvatarFrame } from '../../hooks'; +import { useDevSettings } from '../../hooks'; +import { useFeaturedTrophies } from '../../hooks'; import { getTheme } from '../../data/profileThemes'; import { evaluateTrophies, ULTIMATE_TROPHY } from '../../data/trophyCatalog'; import TutorialOverlay from '../../components/tutorial/TutorialOverlay'; @@ -296,7 +296,7 @@ export default function ProfileScreen({ navigation }) { /> diff --git a/front/src/screens/Profile/RankRoadmapScreen.js b/front/src/screens/Profile/RankRoadmapScreen.js index d03c56d..2545907 100644 --- a/front/src/screens/Profile/RankRoadmapScreen.js +++ b/front/src/screens/Profile/RankRoadmapScreen.js @@ -10,7 +10,7 @@ import { SafeAreaView } from 'react-native-safe-area-context'; import { Ionicons } from '@expo/vector-icons'; import { LinearGradient } from 'expo-linear-gradient'; import { Colors } from '../../constants/theme'; -import { getRank, xpToLevel } from '../../services/stats.service'; +import { xpToLevel } from '../../services'; import { useWorkoutLogs } from '../../context/WorkoutLogsContext'; import { FRAME_DEFS } from '../../components/profile/AvatarFrame'; @@ -22,7 +22,7 @@ const RANKS = [ levelRange: '0 โ€“ 10', minLevel: 0, maxLevel: 10, - color: '#FE7439', + color: Colors.primary, gradientColors: ['#431A08', '#7C2D12'], frameId: 'none', perks: [ @@ -53,7 +53,7 @@ const RANKS = [ levelRange: '31 โ€“ 50', minLevel: 31, maxLevel: 50, - color: '#22C55E', + color: Colors.valid, gradientColors: ['#052E16', '#14532D'], frameId: 'silver', perks: [ @@ -82,7 +82,7 @@ const RANKS = [ levelRange: '71 โ€“ 90', minLevel: 71, maxLevel: 90, - color: '#6E6AF0', + color: Colors.secondaryAccent, gradientColors: ['#1E1B4B', '#2E2A7A'], frameId: 'warrior', perks: [ @@ -96,7 +96,7 @@ const RANKS = [ levelRange: '91 โ€“ 110', minLevel: 91, maxLevel: 110, - color: '#6E6AF0', + color: Colors.secondaryAccent, gradientColors: ['#0F0F1A', '#1C1C38'], frameId: 'elite', perks: [ @@ -111,7 +111,7 @@ const RANKS = [ levelRange: '111 โ€“ 140', minLevel: 111, maxLevel: 140, - color: '#8B5CF6', + color: Colors.rankViolet, gradientColors: ['#2E1065', '#4C1D95'], frameId: 'master', perks: [ @@ -125,7 +125,7 @@ const RANKS = [ levelRange: '141 โ€“ 170', minLevel: 141, maxLevel: 170, - color: '#A855F7', + color: Colors.rankPurple, gradientColors: ['#3B0764', '#581C87'], frameId: 'grandmaster', perks: [ @@ -139,7 +139,7 @@ const RANKS = [ levelRange: '171 โ€“ 199', minLevel: 171, maxLevel: 199, - color: '#C084FC', + color: Colors.legendAccent, gradientColors: ['#4A044E', '#701A75'], frameId: 'legend', perks: [ @@ -156,7 +156,7 @@ const RANKS = [ levelRange: 'Niv. 200', minLevel: 200, maxLevel: 200, - color: '#FFD700', + color: Colors.gold, gradientColors: ['#431407', '#78350F'], frameId: 'god', perks: [ diff --git a/front/src/screens/Profile/SettingsScreen.js b/front/src/screens/Profile/SettingsScreen.js index 4511499..d3326fa 100644 --- a/front/src/screens/Profile/SettingsScreen.js +++ b/front/src/screens/Profile/SettingsScreen.js @@ -6,29 +6,29 @@ import { import { Ionicons } from '@expo/vector-icons'; import AsyncStorage from '@react-native-async-storage/async-storage'; import { Colors } from '../../constants/theme'; -import ConfirmModal from '../../components/common/ConfirmModal'; -import InfoModal from '../../components/common/InfoModal'; +import { ConfirmModal } from '../../components/common'; +import { InfoModal } from '../../components/common'; import { useAuth } from '../../context/AuthContext'; import { useUser } from '../../context/UserContext'; import { useToast } from '../../context/ToastContext'; import { useSavedWorkouts } from '../../context/SavedWorkoutsContext'; import { useQuests } from '../../context/QuestContext'; import { useCustomExercises } from '../../context/CustomExercisesContext'; -import { deleteAccount } from '../../services/auth.service'; +import { deleteAccount } from '../../services'; import { useWorkoutLogs } from '../../context/WorkoutLogsContext'; import { xpToLevel, xpForLevel, computeStreak, debugAddXP, debugSetLevel, debugAddSessions, debugSimulateReps, debugSetStreak, debugClearDebugLogs, debugResetDailyXP, -} from '../../services/stats.service'; +} from '../../services'; import { PROFILE_THEMES, isThemeLocked } from '../../data/profileThemes'; import { TROPHY_CATALOG, TROPHY_CATEGORIES, ULTIMATE_TROPHY, evaluateTrophies } from '../../data/trophyCatalog'; import { COLLECTION_CATEGORY, BACKEND_CATEGORY_MAP } from '../../data/backendTrophyCategories'; -import { getAchievements } from '../../services/reward.service'; +import { getAchievements } from '../../services'; import { normalizeAchievement } from '../../components/profile/AchievementShowcase'; import { TrophyIcon } from '../../components/profile/TrophySlot'; -import { useDevSettings } from '../../hooks/useDevSettings'; +import { useDevSettings } from '../../hooks'; import { useFocusEffect } from '@react-navigation/native'; import TutorialOverlay from '../../components/tutorial/TutorialOverlay'; import { useTutorial, useTutorialTarget } from '../../context/TutorialContext'; @@ -38,13 +38,13 @@ import { fireTestNotification, scheduleDailyReminder, cancelDailyReminder, -} from '../../services/notificationService'; +} from '../../services'; import { syncBackendLevel, giveChests, generateMockSocial, giveAllItems, simulateChestsOpened, simulateReferral, simulateBirthday, simulateGroup, simulateActivityEvent, simulateStreakBreak, simulateShakeSelf, simulateSearchableFriend, simulateLobbyInvite, giveAllTitles, -} from '../../services/debug.service'; +} from '../../services'; const UNIT_WEIGHT_KEY = 'athly:unit:weight:v1'; const UNIT_DIST_KEY = 'athly:unit:distance:v1'; @@ -1208,7 +1208,7 @@ export default function SettingsScreen({ navigation }) { {/* โ”€โ”€โ”€ Suppression dรฉfinitive du compte โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ */} setDeleteModal1(true)} activeOpacity={0.7}> - + Supprimer le compte @@ -1224,7 +1224,7 @@ export default function SettingsScreen({ navigation }) { - + Bienvenue ร  bord ! @@ -1254,7 +1254,7 @@ export default function SettingsScreen({ navigation }) { - + รŠtes-vous sรปr ? @@ -1280,7 +1280,7 @@ export default function SettingsScreen({ navigation }) { - + Confirmation finale @@ -1440,7 +1440,7 @@ function DevBtn({ label, onPress, disabled, variant = 'default', flex, fullWidth // โ”€โ”€โ”€ Styles โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ const styles = StyleSheet.create({ - root: { flex: 1, backgroundColor: '#080910' }, + root: { flex: 1, backgroundColor: Colors.bgAbyss }, scroll: { flex: 1 }, scrollContent: { paddingHorizontal: 16, paddingTop: 8 }, @@ -1482,7 +1482,7 @@ const styles = StyleSheet.create({ themeItemSel: { backgroundColor: 'rgba(255,255,255,0.07)', borderColor: 'rgba(255,255,255,0.25)' }, themeItemLocked: { opacity: 0.35 }, themeSwatch: { width: 32, height: 32, borderRadius: 16, marginBottom: 5 }, - themeCheck: { position: 'absolute', top: 6, right: 6, width: 14, height: 14, borderRadius: 7, backgroundColor: Colors.primary, alignItems: 'center', justifyContent: 'center', borderWidth: 1.5, borderColor: '#13131C' }, + themeCheck: { position: 'absolute', top: 6, right: 6, width: 14, height: 14, borderRadius: 7, backgroundColor: Colors.primary, alignItems: 'center', justifyContent: 'center', borderWidth: 1.5, borderColor: Colors.bgDeep2 }, themeLockOverlay:{ position: 'absolute', top: 0, left: 0, right: 0, bottom: 0, alignItems: 'center', justifyContent: 'center' }, themeLabel: { color: Colors.textMuted, fontSize: 8, fontWeight: '600', textAlign: 'center' }, themeLabelLocked:{ color: Colors.textMuted }, @@ -1546,7 +1546,7 @@ const styles = StyleSheet.create({ devBtnTextDestructive: { color: Colors.error }, devBtnTextDim: { color: Colors.textMuted }, devBtnTextOrange: { color: '#FF6B00' }, - devBtnTextViolet: { color: '#8B5CF6' }, + devBtnTextViolet: { color: Colors.rankViolet }, devBtnTextDisabled: { color: Colors.textMuted }, devHint: { color: 'rgba(255,215,0,0.40)', fontSize: 10, fontWeight: '500', lineHeight: 14, marginTop: -4 }, @@ -1605,16 +1605,16 @@ const styles = StyleSheet.create({ // โ”€โ”€ Welcome modal (fin tutoriel) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ welcomeCard: { borderColor: 'rgba(110,106,240,0.30)' }, welcomeIconWrap:{ width: 64, height: 64, borderRadius: 20, backgroundColor: 'rgba(110,106,240,0.12)', borderWidth: 1, borderColor: 'rgba(110,106,240,0.30)', justifyContent: 'center', alignItems: 'center', marginBottom: 18 }, - welcomeBtn: { flexDirection: 'row', alignItems: 'center', width: '100%', height: 50, borderRadius: 13, backgroundColor: '#6E6AF0', justifyContent: 'center', marginBottom: 10, shadowColor: '#6E6AF0', shadowOffset: { width: 0, height: 6 }, shadowOpacity: 0.40, shadowRadius: 12, elevation: 6 }, + welcomeBtn: { flexDirection: 'row', alignItems: 'center', width: '100%', height: 50, borderRadius: 13, backgroundColor: Colors.secondaryAccent, justifyContent: 'center', marginBottom: 10, shadowColor: Colors.secondaryAccent, shadowOffset: { width: 0, height: 6 }, shadowOpacity: 0.40, shadowRadius: 12, elevation: 6 }, welcomeBtnTxt: { color: '#fff', fontSize: 15, fontWeight: '700', letterSpacing: 0.2 }, // โ”€โ”€ Delete Account button โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ deleteAccountBtn: { flexDirection: 'row', alignItems: 'center', justifyContent: 'center', marginTop: 12, paddingVertical: 14, borderRadius: 14, borderWidth: 1, borderColor: 'rgba(239,68,68,0.15)', backgroundColor: 'transparent' }, - deleteAccountText: { color: '#FF4D4D', fontSize: 13, fontWeight: '600', opacity: 0.75 }, + deleteAccountText: { color: Colors.error, fontSize: 13, fontWeight: '600', opacity: 0.75 }, // โ”€โ”€ Delete Account Modals โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ dmBackdrop: { flex: 1, backgroundColor: 'rgba(0,0,0,0.82)', justifyContent: 'center', alignItems: 'center', paddingHorizontal: 24 }, - dmCard: { width: '100%', backgroundColor: '#13131C', borderRadius: 22, borderWidth: 1, borderColor: 'rgba(239,68,68,0.22)', padding: 28, alignItems: 'center', shadowColor: '#000', shadowOffset: { width: 0, height: 16 }, shadowOpacity: 0.65, shadowRadius: 32, elevation: 20 }, + dmCard: { width: '100%', backgroundColor: Colors.bgDeep2, borderRadius: 22, borderWidth: 1, borderColor: 'rgba(239,68,68,0.22)', padding: 28, alignItems: 'center', shadowColor: '#000', shadowOffset: { width: 0, height: 16 }, shadowOpacity: 0.65, shadowRadius: 32, elevation: 20 }, dmCardFinal: { borderColor: 'rgba(220,38,38,0.35)' }, dmIconWrap: { width: 60, height: 60, borderRadius: 18, backgroundColor: 'rgba(239,68,68,0.10)', borderWidth: 1, borderColor: 'rgba(239,68,68,0.25)', justifyContent: 'center', alignItems: 'center', marginBottom: 18 }, dmIconFinalWrap:{ width: 60, height: 60, borderRadius: 18, backgroundColor: 'rgba(220,38,38,0.14)', borderWidth: 1, borderColor: 'rgba(220,38,38,0.35)', justifyContent: 'center', alignItems: 'center', marginBottom: 18 }, @@ -1623,7 +1623,7 @@ const styles = StyleSheet.create({ dmKeepBtn: { flexDirection: 'row', alignItems: 'center', width: '100%', height: 50, borderRadius: 13, backgroundColor: Colors.primary, justifyContent: 'center', marginBottom: 10, shadowColor: Colors.primary, shadowOffset: { width: 0, height: 6 }, shadowOpacity: 0.35, shadowRadius: 12, elevation: 6 }, dmKeepTxt: { color: '#fff', fontSize: 15, fontWeight: '700', letterSpacing: 0.2 }, dmContinueBtn: { width: '100%', height: 44, borderRadius: 13, justifyContent: 'center', alignItems: 'center' }, - dmContinueTxt: { color: '#EF4444', fontSize: 14, fontWeight: '600' }, + dmContinueTxt: { color: Colors.destructive, fontSize: 14, fontWeight: '600' }, dmDestroyBtn: { flexDirection: 'row', alignItems: 'center', width: '100%', height: 50, borderRadius: 13, backgroundColor: '#DC2626', justifyContent: 'center', marginBottom: 10, shadowColor: '#DC2626', shadowOffset: { width: 0, height: 6 }, shadowOpacity: 0.45, shadowRadius: 12, elevation: 6 }, dmDestroyTxt: { color: '#fff', fontSize: 15, fontWeight: '700', letterSpacing: 0.2 }, dmBackBtn: { width: '100%', height: 44, borderRadius: 13, justifyContent: 'center', alignItems: 'center' }, diff --git a/front/src/screens/Profile/TrophyRoomScreen.js b/front/src/screens/Profile/TrophyRoomScreen.js index 0b25209..90f73c4 100644 --- a/front/src/screens/Profile/TrophyRoomScreen.js +++ b/front/src/screens/Profile/TrophyRoomScreen.js @@ -17,7 +17,7 @@ import { TROPHY_FILTER_TABS, evaluateTrophies, } from '../../data/trophyCatalog'; -import { useFeaturedTrophies, MAX_FEATURED } from '../../hooks/useFeaturedTrophies'; +import { useFeaturedTrophies } from '../../hooks/useFeaturedTrophies'; import { useFocusEffect } from '@react-navigation/native'; import TutorialOverlay from '../../components/tutorial/TutorialOverlay'; import { useTutorial, useTutorialTarget } from '../../context/TutorialContext'; @@ -100,7 +100,7 @@ function UltimateTile({ unlocked, unlockedCount, totalCount, onPress }) { styles.ultimateTile, unlocked && { borderColor: 'rgba(255,215,0,0.6)', - borderTopColor: '#FFD700', + borderTopColor: Colors.gold, }, { transform: [{ scale }] }, ]}> @@ -118,7 +118,7 @@ function UltimateTile({ unlocked, unlockedCount, totalCount, onPress }) { {/* Icon */} {unlocked ? ( - + {ULTIMATE_TROPHY.label} @@ -150,7 +150,7 @@ function UltimateTile({ unlocked, unlockedCount, totalCount, onPress }) { {unlocked && ( - + DIAMOND ยท ULTIME )} @@ -322,9 +322,9 @@ export default function TrophyRoomScreen({ navigation }) { - + - Trophรฉe Ultime + Trophรฉe Ultime {ultimateUnlocked ? '1/1' : '0/1'} @@ -568,7 +568,7 @@ const styles = StyleSheet.create({ paddingHorizontal: 8, paddingVertical: 4, alignSelf: 'flex-start', borderWidth: 1, borderColor: 'rgba(255,215,0,0.35)', }, - ultimateBadgeText: { color: '#FFD700', fontSize: 9, fontWeight: '900', letterSpacing: 1 }, + ultimateBadgeText: { color: Colors.gold, fontSize: 9, fontWeight: '900', letterSpacing: 1 }, ultimateHint: { color: 'rgba(255,255,255,0.2)', fontSize: 10, fontWeight: '500', textAlign: 'center', marginTop: 12 }, // โ”€โ”€ Tile โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ diff --git a/front/src/screens/Social/FriendProfileScreen.js b/front/src/screens/Social/FriendProfileScreen.js index d86931d..6e738fb 100644 --- a/front/src/screens/Social/FriendProfileScreen.js +++ b/front/src/screens/Social/FriendProfileScreen.js @@ -8,9 +8,9 @@ import { LinearGradient } from 'expo-linear-gradient'; import { Ionicons } from '@expo/vector-icons'; import { Colors } from '../../constants/theme'; import { useToast } from '../../context/ToastContext'; -import { getRank, xpToLevel } from '../../services/stats.service'; -import { getFriendProfile, getMyGroup, shakeMember } from '../../services/social.service'; -import { RARITY_META } from '../../services/inventory.service'; +import { getRank, xpToLevel } from '../../services'; +import { getFriendProfile, getMyGroup, shakeMember } from '../../services'; +import { RARITY_META } from '../../services'; import HeroLevelCard from '../../components/profile/HeroLevelCard'; import StreakBadge from '../../components/profile/StreakBadge'; @@ -174,7 +174,7 @@ export default function FriendProfileScreen({ route, navigation }) { /> diff --git a/front/src/screens/Social/SocialScreen.js b/front/src/screens/Social/SocialScreen.js index 23289c3..ac12fd4 100644 --- a/front/src/screens/Social/SocialScreen.js +++ b/front/src/screens/Social/SocialScreen.js @@ -9,7 +9,7 @@ import { Colors } from '../../constants/theme'; import { useToast } from '../../context/ToastContext'; import { useUser } from '../../context/UserContext'; import { useWorkoutLogs } from '../../context/WorkoutLogsContext'; -import ConfirmModal from '../../components/common/ConfirmModal'; +import { ConfirmModal } from '../../components/common'; import FriendshipLevelUpModal from '../../components/social/FriendshipLevelUpModal'; import FriendPreviewModal from '../../components/social/FriendPreviewModal'; import AddFriendModal from '../../components/social/AddFriendModal'; @@ -18,7 +18,7 @@ import { cancelFriendRequest, removeFriend, getFriendsList, getPendingRequests, getLeaderboard, getExerciseLeaderboard, getMyGroup, inviteToGroup, respondToGroupInvite, shakeMember, checkGroupStreak, leaveGroup, -} from '../../services/social.service'; +} from '../../services'; import { MAJOR_EXERCISES } from '../../data/majorExercises'; import ExercisePickerModal from '../../components/social/ExercisePickerModal'; import TutorialOverlay from '../../components/tutorial/TutorialOverlay'; @@ -26,7 +26,7 @@ import { useTutorial, useTutorialTarget } from '../../context/TutorialContext'; // Podium / classements : positions 1-3 affichรฉes en mรฉdaille colorรฉe plutรดt // qu'en emoji ๐Ÿฅ‡๐Ÿฅˆ๐Ÿฅ‰. -const MEDAL_COLORS = { 1: '#FFD700', 2: '#C0C0C0', 3: '#CD7F32' }; +const MEDAL_COLORS = { 1: Colors.gold, 2: '#C0C0C0', 3: '#CD7F32' }; function MedalBadge({ position, size = 16 }) { const color = MEDAL_COLORS[position]; @@ -439,7 +439,7 @@ function FriendsSegment({ // โ•โ•โ• Segment Classement โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• -const PODIUM_COLORS = ['#FFD700', '#C0C0C0', '#CD7F32']; +const PODIUM_COLORS = [Colors.gold, '#C0C0C0', '#CD7F32']; function LeaderboardSegment({ leaderboard }) { const [mode, setMode] = useState('xp'); // 'xp' | 'records' @@ -879,7 +879,7 @@ function AnimatedRow({ index, children }) { // dans `member.weatherStatus`. Affichรฉ uniquement quand prรฉsent (les listes // amis/requรชtes n'en portent pas โ€” seuls les membres de groupe en ont un). const WEATHER_META = { - done: { icon: 'checkmark-circle', color: '#22C55E', label: 'Sรฉance validรฉe' }, + done: { icon: 'checkmark-circle', color: Colors.valid, label: 'Sรฉance validรฉe' }, active: { icon: 'flash', color: '#FBBF24', label: 'Sรฉance active' }, ready: { icon: 'flame', color: Colors.primary, label: 'Prรชt' }, sleeping: { icon: 'moon', color: Colors.textMuted, label: 'En sommeil' }, diff --git a/front/src/screens/Stats/StatsScreen.js b/front/src/screens/Stats/StatsScreen.js index 6c49d54..2f8252d 100644 --- a/front/src/screens/Stats/StatsScreen.js +++ b/front/src/screens/Stats/StatsScreen.js @@ -8,8 +8,8 @@ import { useFocusEffect } from '@react-navigation/native'; import { Colors } from '../../constants/theme'; import { useWorkoutLogs } from '../../context/WorkoutLogsContext'; import { useUser } from '../../context/UserContext'; -import { aggregateGlobal } from '../../services/stats.service'; -import { getWeightHistory } from '../../services/weight.service'; +import { aggregateGlobal } from '../../services'; +import { getWeightHistory } from '../../services'; import PeriodSegmentedControl from '../../components/stats/PeriodSegmentedControl'; import VolumeBarChart from '../../components/stats/VolumeBarChart'; import MuscleDistributionPieChart from '../../components/stats/MuscleDistributionPieChart'; @@ -18,9 +18,9 @@ import WorkoutCalendar from '../../components/stats/WorkoutCalendar'; import XPProgressBar from '../../components/stats/XPProgressBar'; import WorkoutHistoryList from '../../components/stats/WorkoutHistoryList'; import TutorialOverlay from '../../components/tutorial/TutorialOverlay'; -import WeightEntryModal from '../../components/common/WeightEntryModal'; -import ConfirmModal from '../../components/common/ConfirmModal'; -import InfoModal from '../../components/common/InfoModal'; +import { WeightEntryModal } from '../../components/common'; +import { ConfirmModal } from '../../components/common'; +import { InfoModal } from '../../components/common'; import { useTutorial, useTutorialTarget } from '../../context/TutorialContext'; import { MOCK_TUTORIAL_LOGS } from '../../data/mockTutorialStats'; @@ -189,7 +189,7 @@ export default function StatsScreen({ navigation }) { {/* Bandeau mock data */} {activeChapterId === 'stats' && ( - + Donnรฉes de dรฉmonstration - disparaรฎtront ร  la fin du chapitre )} @@ -368,7 +368,7 @@ const styles = StyleSheet.create({ borderBottomWidth: 1, borderBottomColor: 'rgba(255,215,0,0.25)', paddingHorizontal: 16, paddingVertical: 8, }, - mockBannerText: { color: '#FFD700', fontSize: 11, fontWeight: '600', flex: 1 }, + mockBannerText: { color: Colors.gold, fontSize: 11, fontWeight: '600', flex: 1 }, header: { marginBottom: 16 }, title: { color: Colors.textPrimary, fontSize: 26, fontWeight: '900', letterSpacing: -0.5 }, diff --git a/front/src/screens/Workouts/CustomExercisesScreen.js b/front/src/screens/Workouts/CustomExercisesScreen.js index 6ab409c..0e163b5 100644 --- a/front/src/screens/Workouts/CustomExercisesScreen.js +++ b/front/src/screens/Workouts/CustomExercisesScreen.js @@ -16,8 +16,8 @@ import { secondaryMusclesLabels, primaryEquipmentLabel, } from '../../constants/exerciseFilters'; -import ConfirmModal from '../../components/common/ConfirmModal'; -import InfoModal from '../../components/common/InfoModal'; +import { ConfirmModal } from '../../components/common'; +import { InfoModal } from '../../components/common'; export default function CustomExercisesScreen({ navigation }) { const { items, loading, remove } = useCustomExercises(); @@ -149,7 +149,7 @@ const styles = StyleSheet.create({ paddingTop: 40, paddingBottom: 14, borderBottomWidth: StyleSheet.hairlineWidth, - borderBottomColor: '#1f1f27', + borderBottomColor: Colors.borderSubtle, }, headerTitle: { color: Colors.textPrimary, @@ -174,7 +174,7 @@ const styles = StyleSheet.create({ width: 50, height: 50, borderRadius: 12, - backgroundColor: '#0e0e12', + backgroundColor: Colors.cardInner, alignItems: 'center', justifyContent: 'center', marginRight: 12, diff --git a/front/src/screens/Workouts/EditExerciseScreen.js b/front/src/screens/Workouts/EditExerciseScreen.js index bd0e057..e519796 100644 --- a/front/src/screens/Workouts/EditExerciseScreen.js +++ b/front/src/screens/Workouts/EditExerciseScreen.js @@ -17,8 +17,8 @@ import { EQUIPMENTS, LEVELS } from '../../constants/exerciseFilters'; import SelectableChip from '../../components/workouts/SelectableChip'; import MuscleHierarchyPicker from '../../components/workouts/MuscleHierarchyPicker'; import { useCustomExercises } from '../../context/CustomExercisesContext'; -import ConfirmModal from '../../components/common/ConfirmModal'; -import InfoModal from '../../components/common/InfoModal'; +import { ConfirmModal } from '../../components/common'; +import { InfoModal } from '../../components/common'; // Form add/edit d'un exercice perso. Alignรฉ sur la structure du catalogue (sous-muscles // prรฉcis), donc directement compatible avec le Builder et l'algo de tri. @@ -303,7 +303,7 @@ const styles = StyleSheet.create({ paddingTop: 40, paddingBottom: 14, borderBottomWidth: StyleSheet.hairlineWidth, - borderBottomColor: '#1f1f27', + borderBottomColor: Colors.borderSubtle, }, headerTitle: { color: Colors.textPrimary, diff --git a/front/src/screens/Workouts/ExerciseDetailScreen.js b/front/src/screens/Workouts/ExerciseDetailScreen.js index 6aaee82..b8490e0 100644 --- a/front/src/screens/Workouts/ExerciseDetailScreen.js +++ b/front/src/screens/Workouts/ExerciseDetailScreen.js @@ -18,7 +18,7 @@ import { primaryMuscleLabel, secondaryMusclesLabels, } from '../../constants/exerciseFilters'; -import useEffortTimer from '../../hooks/useEffortTimer'; +import { useEffortTimer } from '../../hooks'; import { useWorkoutInProgress } from '../../context/WorkoutInProgressContext'; import ExerciseHeader from '../../components/workouts/ExerciseHeader'; import SetTable from '../../components/workouts/SetTable'; diff --git a/front/src/screens/Workouts/ExerciseStatsScreen.js b/front/src/screens/Workouts/ExerciseStatsScreen.js index c08cd4c..d2f51d4 100644 --- a/front/src/screens/Workouts/ExerciseStatsScreen.js +++ b/front/src/screens/Workouts/ExerciseStatsScreen.js @@ -10,7 +10,7 @@ import { SafeAreaView } from 'react-native-safe-area-context'; import { Ionicons } from '@expo/vector-icons'; import { Colors } from '../../constants/theme'; import { useWorkoutLogs } from '../../context/WorkoutLogsContext'; -import { aggregateExercise } from '../../services/stats.service'; +import { aggregateExercise } from '../../services'; import ExerciseStatsChart from '../../components/stats/ExerciseStatsChart'; import PRCard from '../../components/stats/PRCard'; diff --git a/front/src/screens/Workouts/ManualWorkoutCreatorScreen.js b/front/src/screens/Workouts/ManualWorkoutCreatorScreen.js index a4ea4f2..1375d82 100644 --- a/front/src/screens/Workouts/ManualWorkoutCreatorScreen.js +++ b/front/src/screens/Workouts/ManualWorkoutCreatorScreen.js @@ -327,7 +327,7 @@ const styles = StyleSheet.create({ paddingTop: 40, paddingBottom: 14, borderBottomWidth: StyleSheet.hairlineWidth, - borderBottomColor: '#1f1f27', + borderBottomColor: Colors.borderSubtle, }, headerTitle: { color: Colors.textPrimary, @@ -403,7 +403,7 @@ const styles = StyleSheet.create({ width: 44, height: 44, borderRadius: 10, - backgroundColor: '#0e0e12', + backgroundColor: Colors.cardInner, alignItems: 'center', justifyContent: 'center', marginRight: 12, @@ -457,7 +457,7 @@ const styles = StyleSheet.create({ stepper: { flexDirection: 'row', alignItems: 'center', - backgroundColor: '#0e0e12', + backgroundColor: Colors.cardInner, borderRadius: 10, paddingHorizontal: 4, }, @@ -475,7 +475,7 @@ const styles = StyleSheet.create({ textAlign: 'center', }, repsInput: { - backgroundColor: '#0e0e12', + backgroundColor: Colors.cardInner, color: Colors.textPrimary, fontSize: 14, fontWeight: '700', @@ -515,7 +515,7 @@ const styles = StyleSheet.create({ paddingBottom: 26, backgroundColor: Colors.background, borderTopWidth: StyleSheet.hairlineWidth, - borderTopColor: '#1f1f27', + borderTopColor: Colors.borderSubtle, }, saveBtn: { flexDirection: 'row', diff --git a/front/src/screens/Workouts/WorkoutBuilderScreen.js b/front/src/screens/Workouts/WorkoutBuilderScreen.js index 2495497..a22d34d 100644 --- a/front/src/screens/Workouts/WorkoutBuilderScreen.js +++ b/front/src/screens/Workouts/WorkoutBuilderScreen.js @@ -281,7 +281,7 @@ const styles = StyleSheet.create({ paddingTop: 40, paddingBottom: 14, borderBottomWidth: StyleSheet.hairlineWidth, - borderBottomColor: '#1f1f27', + borderBottomColor: Colors.borderSubtle, }, headerTitle: { color: Colors.textPrimary, @@ -387,7 +387,7 @@ const styles = StyleSheet.create({ width: 38, height: 38, borderRadius: 9, - backgroundColor: '#0e0e12', + backgroundColor: Colors.cardInner, alignItems: 'center', justifyContent: 'center', marginRight: 10, @@ -418,7 +418,7 @@ const styles = StyleSheet.create({ paddingBottom: 26, backgroundColor: Colors.background, borderTopWidth: StyleSheet.hairlineWidth, - borderTopColor: '#1f1f27', + borderTopColor: Colors.borderSubtle, }, launchBtn: { flexDirection: 'row', diff --git a/front/src/screens/Workouts/WorkoutScreen.js b/front/src/screens/Workouts/WorkoutScreen.js index 1099541..82f548c 100644 --- a/front/src/screens/Workouts/WorkoutScreen.js +++ b/front/src/screens/Workouts/WorkoutScreen.js @@ -10,15 +10,15 @@ import { } from 'react-native'; import { SafeAreaView } from 'react-native-safe-area-context'; import { Ionicons } from '@expo/vector-icons'; -import { haptics } from '../../services/haptics.service'; +import { haptics } from '../../services'; import { Colors } from '../../constants/theme'; -import useExerciseSorting, { isFiltering } from '../../hooks/useExerciseSorting'; +import { useExerciseSorting, isFiltering } from '../../hooks'; import { useWorkoutInProgress } from '../../context/WorkoutInProgressContext'; import { useWorkoutLogs } from '../../context/WorkoutLogsContext'; -import { useDevSettings } from '../../hooks/useDevSettings'; +import { useDevSettings } from '../../hooks'; -import API from '../../api/api'; +import { completeWorkout } from '../../services'; import SortBar from '../../components/workouts/SortBar'; import SupersetGroup from '../../components/workouts/SupersetGroup'; @@ -27,12 +27,12 @@ import InlineExerciseBlock from '../../components/workouts/InlineExerciseBlock'; import AddExerciseSheet from '../../components/workouts/AddExerciseSheet'; import WorkoutRecapModal from '../../components/workouts/WorkoutRecapModal'; import ShortSessionWarningModal from '../../components/workouts/ShortSessionWarningModal'; -import QuestToast from '../../components/common/QuestToast'; -import ConfirmModal from '../../components/common/ConfirmModal'; +import { QuestToast } from '../../components/common'; +import { ConfirmModal } from '../../components/common'; import LobbyMembersBar from '../../components/workouts/LobbyMembersBar'; import LobbyWaitingOverlay from '../../components/workouts/LobbyWaitingOverlay'; import MultiLootModal from '../../components/workouts/MultiLootModal'; -import { getLobby, finishLobby } from '../../services/lobby.service'; +import { getLobby, finishLobby } from '../../services'; const DEFAULT_FILTERS = { muscles: [], levels: [], equipment: [] }; @@ -266,7 +266,7 @@ export default function WorkoutScreen({ route, navigation }) { const result = await actions.finalize({ notes: state.notes, durationSeconds: elapsed, ...opts }); if (state.id) { - API.post(`/workouts/${state.id}/complete`).catch(() => {}); + completeWorkout(state.id).catch(() => {}); } const builtRecapData = { diff --git a/front/src/services/exercise.service.js b/front/src/services/exercise.service.js deleted file mode 100644 index 39400d8..0000000 --- a/front/src/services/exercise.service.js +++ /dev/null @@ -1,9 +0,0 @@ -import API from "../api/api"; - -export function getExerciseRecords(workoutId) { - return API.get(`/exercise/workout/${workoutId}`); -} - -export function addExerciseRecord(data) { - return API.post("/exercise", data); -} \ No newline at end of file diff --git a/front/src/services/index.js b/front/src/services/index.js new file mode 100644 index 0000000..b08f3b8 --- /dev/null +++ b/front/src/services/index.js @@ -0,0 +1,25 @@ +// โ”€โ”€โ”€ Barrel des services โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +// Point d'entrรฉe unique : `import { getFriendsList, haptics } from '../services';` +// Tous les services n'exportent que des fonctions/constantes nommรฉes, sans +// collision de noms (vรฉrifiรฉ) โ€” l'agrรฉgation en `export *` est donc sรปre. +// Rรจgle : ne jamais importer ce barrel DEPUIS un fichier de ce dossier +// (import direct entre services) pour exclure tout cycle de dรฉpendances. + +export * from './auth.service'; +export * from './customExercises.service'; +export * from './debug.service'; +export * from './haptics.service'; +export * from './inventory.service'; +export * from './lobby.service'; +export * from './notificationService'; +export * from './onboarding.service'; +export * from './profile.service'; +export * from './quest.service'; +export * from './reward.service'; +export * from './savedWorkouts.service'; +export * from './social.service'; +export * from './stats.service'; +export * from './title.service'; +export * from './weight.service'; +export * from './workouts.service'; +export * from './xpSync.service'; diff --git a/front/src/services/profile.service.js b/front/src/services/profile.service.js index a5314ec..422ac04 100644 --- a/front/src/services/profile.service.js +++ b/front/src/services/profile.service.js @@ -1,5 +1,12 @@ import API from '../api/api'; +// Met ร  jour les informations du profil (nom, mensurations, objectif, rythmeโ€ฆ). +// Renvoie la rรฉponse brute โ€” l'appelant gรจre le refetch du UserContext. +export async function updateMyProfile(payload) { + const res = await API.put('/users/me', payload); + return res.data; +} + // Synchronise le cadre de profil รฉquipรฉ (forme + couleur) vers le backend, // pour qu'il soit visible sur le profil public par les amis (useAvatarFrame // reste la source de vรฉritรฉ locale pour l'affichage instantanรฉ cรดtรฉ soi-mรชme). diff --git a/front/src/services/workout.service.js b/front/src/services/workout.service.js deleted file mode 100644 index a56a6a5..0000000 --- a/front/src/services/workout.service.js +++ /dev/null @@ -1,28 +0,0 @@ -import API from '../api/api'; - -export async function getWorkouts() { - try { - const response = await API.get('/workouts'); - return response.data.workouts; - } catch { - return []; - } -} - -export async function getWorkout(id) { - try { - const response = await API.get(`/workouts/${id}`); - return response.data.workout; - } catch { - return null; - } -} - -export async function createWorkout(workout) { - try { - const response = await API.post('/workouts', workout); - return response.data.workout; - } catch { - return null; - } -} diff --git a/front/src/services/workouts.service.js b/front/src/services/workouts.service.js new file mode 100644 index 0000000..adb00b9 --- /dev/null +++ b/front/src/services/workouts.service.js @@ -0,0 +1,36 @@ +import API from '../api/api'; + +// โ”€โ”€โ”€ Cycle de vie des sรฉances cรดtรฉ backend โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ +// Draft (auto-save pendant la sรฉance) โ†’ finalize (calcul XP/records serveur) +// โ†’ complete (marquage lรฉger fire-and-forget). Consommรฉ par useWorkoutState +// (draft/finalize) et WorkoutScreen (complete) โ€” les รฉcrans et hooks ne +// touchent jamais l'API brute directement. + +// Crรฉe le brouillon serveur de la sรฉance en cours (premiรจre sauvegarde). +export async function createWorkoutDraft({ name, exercises, notes }) { + const res = await API.post('/workouts/draft', { + name, exercises, notes, status: 'draft', + }); + const data = res && res.data ? res.data : res; + return data && data.workout ? data.workout : null; +} + +// Met ร  jour le brouillon serveur existant (auto-save dรฉbouncรฉ). +export async function updateWorkoutDraft(id, { exercises, notes, durationSeconds }) { + const res = await API.patch(`/workouts/${id}/draft`, { + exercises, notes, durationSeconds, + }); + const data = res && res.data ? res.data : res; + return data && data.workout ? data.workout : data; +} + +// Finalise la sรฉance : le backend recalcule XP, records et stats (anti-cheat). +export async function finalizeWorkout(id, payload) { + const res = await API.post(`/workouts/${id}/finalize`, payload); + return res && res.data ? res.data : res; +} + +// Marque la sรฉance comme terminรฉe โ€” best-effort, jamais bloquant. +export function completeWorkout(id) { + return API.post(`/workouts/${id}/complete`); +} diff --git a/front/src/styles/global.js b/front/src/styles/global.js deleted file mode 100644 index e4fcf5e..0000000 --- a/front/src/styles/global.js +++ /dev/null @@ -1,131 +0,0 @@ -import { StyleSheet } from 'react-native'; -import { Colors } from '../constants/theme'; - -export const globalStyles = StyleSheet.create({ - // โ”€โ”€ Conteneurs โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - safeDeep: { - flex: 1, - backgroundColor: Colors.backgroundDeep, - }, - safeAbyss: { - flex: 1, - backgroundColor: Colors.bgAbyss, - }, - container: { - flex: 1, - backgroundColor: Colors.background, - padding: 16, - }, - scrollContent: { - paddingHorizontal: 20, - paddingBottom: 40, - }, - - // โ”€โ”€ Mise en page โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - centered: { - justifyContent: 'center', - alignItems: 'center', - }, - rowBetween: { - flexDirection: 'row', - justifyContent: 'space-between', - alignItems: 'center', - }, - row: { - flexDirection: 'row', - alignItems: 'center', - }, - flex1: { flex: 1 }, - - // โ”€โ”€ Cards โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - card: { - backgroundColor: Colors.cardDeep, - borderRadius: 16, - padding: 16, - }, - cardLegacy: { - backgroundColor: Colors.card, - borderRadius: 16, - paddingVertical: 14, - paddingHorizontal: 14, - }, - glassCard: { - backgroundColor: Colors.glassBg, - borderWidth: 1, - borderColor: Colors.glassBorder, - borderRadius: 18, - overflow: 'hidden', - }, - - // โ”€โ”€ Typographie โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - title: { - color: Colors.textPrimary, - fontSize: 22, - fontWeight: 'bold', - }, - subtitle: { - color: Colors.textSecondary, - fontSize: 14, - marginTop: 4, - }, - sectionLabel: { - color: Colors.textPrimary, - fontSize: 12, - fontWeight: '800', - letterSpacing: 1.2, - textTransform: 'uppercase', - marginBottom: 10, - }, - sectionLinkText: { - color: Colors.primary, - fontSize: 12, - fontWeight: '700', - }, - - // โ”€โ”€ Boutons โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - primaryBtn: { - backgroundColor: Colors.primary, - borderRadius: 16, - alignItems: 'center', - justifyContent: 'center', - paddingVertical: 15, - shadowColor: Colors.primary, - shadowOffset: { width: 0, height: 6 }, - shadowOpacity: 0.4, - shadowRadius: 14, - elevation: 8, - }, - primaryBtnText: { - color: '#fff', - fontSize: 14, - fontWeight: '800', - }, - ghostBtn: { - borderWidth: 1.5, - borderColor: Colors.primary, - borderRadius: 14, - alignItems: 'center', - justifyContent: 'center', - paddingVertical: 13, - backgroundColor: 'transparent', - }, - ghostBtnText: { - color: Colors.primary, - fontWeight: '700', - fontSize: 14, - }, - - // โ”€โ”€ ร‰crans vides โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - emptyState: { - flex: 1, - alignItems: 'center', - justifyContent: 'center', - paddingHorizontal: 32, - gap: 14, - }, - emptyText: { - color: Colors.textMuted, - fontSize: 14, - textAlign: 'center', - }, -});