/** * TabataFit Profile Screen * SwiftUI-first settings with native iOS look */ import { View, StyleSheet, ScrollView } from 'react-native' import { useRouter } from 'expo-router' import { useSafeAreaInsets } from 'react-native-safe-area-context' import { Host, List, Section, Switch, LabeledContent, DateTimePicker, Button, VStack, Text, } from '@expo/ui/swift-ui' import { useMemo } from 'react' import { useTranslation } from 'react-i18next' import { useUserStore } from '@/src/shared/stores' import { requestNotificationPermissions, usePurchases } from '@/src/shared/hooks' import { StyledText } from '@/src/shared/components/StyledText' import { useThemeColors, BRAND } from '@/src/shared/theme' import type { ThemeColors } from '@/src/shared/theme/types' import { SPACING, LAYOUT } from '@/src/shared/constants/spacing' const FONTS = { LARGE_TITLE: 34, TITLE_2: 22, CAPTION_1: 12, } // ═══════════════════════════════════════════════════════════════════════════ // MAIN SCREEN // ═══════════════════════════════════════════════════════════════════════════ export default function ProfileScreen() { const { t } = useTranslation('screens') const router = useRouter() const insets = useSafeAreaInsets() const colors = useThemeColors() const styles = useMemo(() => createStyles(colors), [colors]) const profile = useUserStore((s) => s.profile) const settings = useUserStore((s) => s.settings) const updateSettings = useUserStore((s) => s.updateSettings) const { restorePurchases } = usePurchases() const isPremium = profile.subscription !== 'free' const planLabel = isPremium ? 'TabataFit+' : t('profile.freePlan') const handleRestore = async () => { await restorePurchases() } const handleReminderToggle = async (enabled: boolean) => { if (enabled) { const granted = await requestNotificationPermissions() if (!granted) return } updateSettings({ reminders: enabled }) } const handleTimeChange = (date: Date) => { const hh = String(date.getHours()).padStart(2, '0') const mm = String(date.getMinutes()).padStart(2, '0') updateSettings({ reminderTime: `${hh}:${mm}` }) } // Build initial date string for the picker (today at reminderTime) const today = new Date() const [rh, rm] = settings.reminderTime.split(':').map(Number) const pickerDate = new Date(today.getFullYear(), today.getMonth(), today.getDate(), rh, rm) const pickerInitial = pickerDate.toISOString() // Calculate total height for single SwiftUI island // insetGrouped style: ~50px top/bottom margins, section header ~35px, row ~44px const basePadding = 100 // top + bottom margins for insetGrouped // Account section const accountRows = 1 + (isPremium ? 1 : 0) // plan, [+ restore] const accountHeight = 35 + accountRows * 44 // Upgrade section (free users only) const upgradeHeight = isPremium ? 0 : 35 + 80 // header + VStack content // Workout section const workoutHeight = 35 + 3 * 44 // haptics, sound, voice // Notifications section const notificationRows = settings.reminders ? 2 : 1 const notificationHeight = 35 + notificationRows * 44 // About section const aboutHeight = 35 + 2 * 44 // version, privacy // Sign out section const signOutHeight = 44 // single button row const totalHeight = basePadding + accountHeight + upgradeHeight + workoutHeight + notificationHeight + aboutHeight + signOutHeight return ( {/* Header */} {t('profile.title')} {/* Profile Header Card */} {profile.name?.[0] || '?'} {profile.name || t('profile.guest')} {isPremium && ( {planLabel} )} {/* All Settings in Single SwiftUI Island */} {/* Account Section */}
{planLabel} {isPremium && ( )}
{/* Upgrade CTA for Free Users */} {!isPremium && (
{t('profile.upgradeTitle')} {t('profile.upgradeDescription')}
)} {/* Workout Settings */}
updateSettings({ haptics: v })} color={BRAND.PRIMARY} /> updateSettings({ soundEffects: v })} color={BRAND.PRIMARY} /> updateSettings({ voiceCoaching: v })} color={BRAND.PRIMARY} />
{/* Notification Settings */}
{settings.reminders && ( )}
{/* About Section */}
1.0.0
{/* Sign Out */}
) } // ═══════════════════════════════════════════════════════════════════════════ // STYLES // ═══════════════════════════════════════════════════════════════════════════ function createStyles(colors: ThemeColors) { return StyleSheet.create({ container: { flex: 1, backgroundColor: colors.bg.base, }, scrollView: { flex: 1, }, scrollContent: { paddingHorizontal: LAYOUT.SCREEN_PADDING, }, // Profile Header profileHeader: { flexDirection: 'row', alignItems: 'center', paddingVertical: SPACING[5], gap: SPACING[4], }, avatarContainer: { width: 60, height: 60, borderRadius: 30, backgroundColor: BRAND.PRIMARY, alignItems: 'center', justifyContent: 'center', }, profileInfo: { flex: 1, }, premiumBadge: { backgroundColor: 'rgba(255, 107, 53, 0.15)', paddingHorizontal: SPACING[3], paddingVertical: SPACING[1], borderRadius: 12, alignSelf: 'flex-start', marginTop: SPACING[1], }, }) }