Files
tabatago/app/player/[id].tsx
Millian Lamiaux 5888aac08e refactor screens, navigation & player for new architecture
Simplify Home, Activity, Profile, Complete, Player, and Program screens
to work with the new Supabase-driven data layer. Update root and tab
layouts. Add Settings, Terms, and Zone routes. Add OfflineBanner
component and progressStore. Update all player sub-components to use
the refreshed design system tokens.
2026-04-21 21:50:48 +02:00

83 lines
2.3 KiB
TypeScript

/**
* TabataFit Player Screen
* Loads a WorkoutProgram from Supabase and renders the Tabata player.
*/
import React from 'react'
import { View, Text } from 'react-native'
import { useLocalSearchParams } from 'expo-router'
import {
isWorkoutProgramId,
parseWorkoutProgramId,
fetchProgramById,
workoutProgramToTabataSession,
} from '@/src/shared/data/workoutPrograms'
import { TabataPlayerScreen } from '@/src/features/player/TabataPlayerScreen'
import type { TabataSession } from '@/src/shared/types/program'
import type { WorkoutProgram } from '@/src/shared/types/workoutProgram'
import { NAVY, TEXT } from '@/src/shared/constants/colors'
export default function PlayerScreen() {
const { id } = useLocalSearchParams<{ id: string }>()
const sessionId = id ?? ''
if (!isWorkoutProgramId(sessionId)) {
return <Message text="Programme invalide" />
}
return <WorkoutProgramPlayerScreen compositeId={sessionId} />
}
function WorkoutProgramPlayerScreen({ compositeId }: { compositeId: string }) {
const [state, setState] = React.useState<
| { status: 'loading' }
| { status: 'error' }
| { status: 'ready'; session: TabataSession; program: WorkoutProgram }
>({ status: 'loading' })
React.useEffect(() => {
let cancelled = false
async function load() {
const parsed = parseWorkoutProgramId(compositeId)
if (!parsed) {
if (!cancelled) setState({ status: 'error' })
return
}
const program = await fetchProgramById(parsed.programId)
if (cancelled) return
if (!program) {
setState({ status: 'error' })
return
}
setState({
status: 'ready',
session: workoutProgramToTabataSession(program),
program,
})
}
load()
return () => {
cancelled = true
}
}, [compositeId])
if (state.status === 'loading') return <Message text="Chargement..." />
if (state.status === 'error') return <Message text="Programme non trouvé" />
return <TabataPlayerScreen session={state.session} program={state.program} />
}
function Message({ text }: { text: string }) {
return (
<View
style={{
flex: 1,
backgroundColor: NAVY[900],
justifyContent: 'center',
alignItems: 'center',
}}
>
<Text style={{ color: TEXT.SECONDARY }}>{text}</Text>
</View>
)
}