feat: migrate icons to SF Symbols, refactor explore tab, add collections/programs data layer

- Replace all Ionicons with native SF Symbols via expo-symbols SymbolView
- Create reusable Icon wrapper component (src/shared/components/Icon.tsx)
- Remove @expo/vector-icons and lucide-react dependencies
- Refactor explore tab with filters, search, and category browsing
- Add collections and programs data with Supabase integration
- Add explore filter store and filter sheet
- Update i18n strings (en, de, es, fr) for new explore features
- Update test mocks and remove stale snapshots
- Add user fitness level to user store and types
This commit is contained in:
Millian Lamiaux
2026-03-25 23:28:51 +01:00
parent f11eb6b9ae
commit b833198e9d
42 changed files with 2006 additions and 1594 deletions

View File

@@ -7,7 +7,7 @@ import { View, StyleSheet, ScrollView, Pressable } from 'react-native'
import { useRouter } from 'expo-router'
import { useSafeAreaInsets } from 'react-native-safe-area-context'
import { LinearGradient } from 'expo-linear-gradient'
import Ionicons from '@expo/vector-icons/Ionicons'
import { Icon } from '@/src/shared/components/Icon'
import { useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
@@ -68,7 +68,7 @@ export default function AssessmentScreen() {
<View style={[styles.container, { paddingTop: insets.top }]}>
<View style={styles.header}>
<Pressable style={styles.backButton} onPress={() => setShowIntro(true)}>
<Ionicons name="arrow-back" size={24} color={colors.text.primary} />
<Icon name="arrow.left" size={24} color={colors.text.primary} />
</Pressable>
<StyledText size={FONTS.TITLE} weight="bold" color={colors.text.primary}>
{t('assessment.title')}
@@ -105,11 +105,11 @@ export default function AssessmentScreen() {
<StyledText size={FONTS.HEADLINE} weight="semibold" color={colors.text.primary} style={styles.tipsTitle}>
{t('assessment.tips')}
</StyledText>
{ASSESSMENT_WORKOUT.tips.map((tip, index) => (
{[1, 2, 3, 4].map((index) => (
<View key={index} style={styles.tipItem}>
<Ionicons name="checkmark-circle-outline" size={18} color={BRAND.PRIMARY} />
<Icon name="checkmark.circle" size={18} color={BRAND.PRIMARY} />
<StyledText size={14} color={colors.text.secondary} style={styles.tipText}>
{tip}
{t(`assessment.tip${index}`)}
</StyledText>
</View>
))}
@@ -126,7 +126,7 @@ export default function AssessmentScreen() {
<StyledText size={16} weight="bold" color="#FFFFFF">
{t('assessment.startAssessment')}
</StyledText>
<Ionicons name="play" size={20} color="#FFFFFF" style={styles.ctaIcon} />
<Icon name="play.fill" size={20} color="#FFFFFF" style={styles.ctaIcon} />
</LinearGradient>
</Pressable>
</View>
@@ -139,7 +139,7 @@ export default function AssessmentScreen() {
{/* Header */}
<View style={styles.header}>
<Pressable style={styles.backButton} onPress={handleSkip}>
<Ionicons name="close" size={24} color={colors.text.primary} />
<Icon name="xmark" size={24} color={colors.text.primary} />
</Pressable>
<View style={styles.placeholder} />
</View>
@@ -152,7 +152,7 @@ export default function AssessmentScreen() {
{/* Hero */}
<View style={styles.heroSection}>
<View style={styles.iconContainer}>
<Ionicons name="clipboard-outline" size={48} color={BRAND.PRIMARY} />
<Icon name="clipboard" size={48} color={BRAND.PRIMARY} />
</View>
<StyledText size={FONTS.LARGE_TITLE} weight="bold" color={colors.text.primary} style={styles.heroTitle}>
@@ -168,7 +168,7 @@ export default function AssessmentScreen() {
<View style={styles.featuresSection}>
<View style={styles.featureItem}>
<View style={styles.featureIcon}>
<Ionicons name="time-outline" size={24} color={BRAND.PRIMARY} />
<Icon name="clock" size={24} color={BRAND.PRIMARY} />
</View>
<View style={styles.featureText}>
<StyledText size={16} weight="semibold" color={colors.text.primary}>
@@ -182,7 +182,7 @@ export default function AssessmentScreen() {
<View style={styles.featureItem}>
<View style={styles.featureIcon}>
<Ionicons name="body-outline" size={24} color={BRAND.PRIMARY} />
<Icon name="figure.stand" size={24} color={BRAND.PRIMARY} />
</View>
<View style={styles.featureText}>
<StyledText size={16} weight="semibold" color={colors.text.primary}>
@@ -196,7 +196,7 @@ export default function AssessmentScreen() {
<View style={styles.featureItem}>
<View style={styles.featureIcon}>
<Ionicons name="barbell-outline" size={24} color={BRAND.PRIMARY} />
<Icon name="dumbbell" size={24} color={BRAND.PRIMARY} />
</View>
<View style={styles.featureText}>
<StyledText size={16} weight="semibold" color={colors.text.primary}>
@@ -250,7 +250,7 @@ export default function AssessmentScreen() {
<StyledText size={16} weight="bold" color="#FFFFFF">
{t('assessment.takeAssessment')}
</StyledText>
<Ionicons name="arrow-forward" size={20} color="#FFFFFF" style={styles.ctaIcon} />
<Icon name="arrow.right" size={20} color="#FFFFFF" style={styles.ctaIcon} />
</LinearGradient>
</Pressable>