@@ -6,12 +6,22 @@ import { router } from 'expo-router';
66import { usePersonalBests } from "@/hooks/usePersonalBests" ;
77import { Dialog } from '@/components/ui/Dialog' ;
88import { Button } from '@/components/ui/Button' ;
9+ import { useWorkout } from '@/contexts/WorkoutContext' ;
10+ import { BarChart } from 'react-native-chart-kit' ;
11+ import { useEffect } from 'react' ;
12+ import { ProgressChart } from 'react-native-chart-kit' ;
913
1014const { width } = Dimensions . get ( 'window' ) ;
1115//console.log(" 1 HomeScreen about to be rendered rendered");
16+
1217const HomeScreen = ( ) => {
13- //console.log("2 HomeScreen rendered");
18+ const { workouts , getWorkouts } = useWorkout ( ) ; // <- include getWorkouts
1419 const { user } = useAuth ( ) ;
20+
21+ useEffect ( ( ) => {
22+ getWorkouts ( ) ;
23+ } , [ ] ) ;
24+
1525 if ( ! user ) {
1626 console . warn ( "User context is undefined" ) ;
1727 return null ;
@@ -38,6 +48,59 @@ const HomeScreen = () => {
3848 return 'Obesity Class 3' ;
3949 } , [ bmiValue ] ) ;
4050
51+ const range = '7' ; // fixed
52+
53+ const getDateLabels = ( days : number ) => {
54+ const labels = [ ] ;
55+ for ( let i = days - 1 ; i >= 0 ; i -- ) {
56+ const d = new Date ( ) ;
57+ d . setDate ( d . getDate ( ) - i ) ;
58+
59+ // Skip every other label if days > 7
60+ const skip = days === 14 ? 2 : days === 30 ? 3 : 1 ;
61+ if ( i % skip !== 0 ) {
62+ labels . push ( '' ) ;
63+ } else {
64+ labels . push ( d . toLocaleDateString ( 'en-US' , { month : 'short' , day : 'numeric' } ) ) ;
65+ }
66+ }
67+ return labels ;
68+ } ;
69+
70+
71+
72+ const { labels, data } = useMemo ( ( ) => {
73+ const nameToDuration : Record < string , number > = { } ;
74+
75+ workouts
76+ . filter ( w => w . is_completed && w . name && ( w . updated_at || w . completed_date ) )
77+ . forEach ( w => {
78+ const end = new Date ( w . updated_at ?? w . completed_date ) . getTime ( ) ;
79+ const start = new Date ( w . created_at ) . getTime ( ) ;
80+ const duration = Math . round ( ( end - start ) / 60000 ) ; // in minutes
81+
82+ const name = w . name . trim ( ) ;
83+ if ( ! nameToDuration [ name ] ) {
84+ nameToDuration [ name ] = 0 ;
85+ }
86+ nameToDuration [ name ] += duration ;
87+ } ) ;
88+
89+ const sorted = Object . entries ( nameToDuration )
90+ . filter ( ( [ name , minutes ] ) => minutes > 0 )
91+ . sort ( ( a , b ) => b [ 1 ] - a [ 1 ] ) ; // descending
92+
93+ return {
94+ labels : sorted . map ( ( [ name ] ) => name ) ,
95+ data : sorted . map ( ( [ , duration ] ) => duration ) ,
96+ } ;
97+ } , [ workouts ] ) ;
98+
99+
100+
101+
102+ //console.log("workouts", JSON.stringify(workouts, null, 2));
103+
41104 const [ showBmiDialog , setShowBmiDialog ] = useState ( false ) ;
42105
43106 const workoutProgressData = [ 20 , 40 , 30 , 60 , 90 , 80 , 70 ] ;
@@ -50,8 +113,8 @@ const HomeScreen = () => {
50113 const { pbs, loading } = usePersonalBests ( ) ;
51114 const testPbs = pbs . length === 0 ? [ { metric : "Deadlift" , value : 315 , date : "2025-05-27" } ] : pbs ;
52115
53- console . log ( 'PBS LOADED:' , pbs ) ;
54- console . log ( "Rendering personal bests section. pbs:" , pbs , "loading:" , loading ) ;
116+ // console.log('PBS LOADED:', pbs);
117+ // console.log("Rendering personal bests section. pbs:", pbs, "loading:", loading);
55118
56119 return (
57120 < SafeAreaView style = { styles . container } >
@@ -90,68 +153,45 @@ const HomeScreen = () => {
90153
91154 { /* Workout Progress */ }
92155 < View style = { styles . progressSection } >
93- < View style = { styles . progressHeader } >
94- < Text style = { styles . sectionTitle } > Workout Progress</ Text >
95- < TouchableOpacity onPress = { ( ) => { /* toggle weekly/monthly */ } } >
96- < Text style = { styles . periodToggle } > Weekly ▼</ Text >
97- </ TouchableOpacity >
98- </ View >
99- < LineChart
100- data = { {
101- labels : workoutDays ,
102- datasets : [
103- {
104- data : workoutProgressData ,
105- color : ( ) => '#B07FFD' ,
106- strokeWidth : 2 ,
107- } ,
108- ] ,
109- } }
110- width = { width - 64 }
111- height = { 100 }
112- chartConfig = { {
113- backgroundGradientFrom : '#fff' ,
114- backgroundGradientTo : '#fff' ,
115- color : ( ) => '#B07FFD' ,
116- strokeWidth : 2 ,
117- } }
118- bezier
119- style = { styles . progressChart }
120- />
121- < View style = { styles . daysRow } >
122- { workoutDays . map ( day => (
123- < Text key = { day } style = { styles . dayText } > { day } </ Text >
124- ) ) }
125- </ View >
126- </ View >
156+ < View style = { styles . progressHeader } >
157+ < Text style = { styles . sectionTitle } > Workout Minutes</ Text >
158+ </ View >
127159
128- { /* Latest Workout */ }
129- < View style = { [ styles . latestSection , { backgroundColor : '#f0f0f0' } ] } >
130- < View style = { styles . sectionHeader } >
131- < Text style = { styles . sectionTitle } > Latest Workout</ Text >
132- < TouchableOpacity onPress = { ( ) => alert ( 'Workout List not yet implemented' ) } >
133- < Text style = { styles . seeMore } > See more</ Text >
134- </ TouchableOpacity >
135- </ View >
136- { latestWorkouts . map ( w => (
137- < TouchableOpacity key = { w . id } style = { styles . workoutItem } onPress = { ( ) => alert ( 'Workout Details not yet implemented' ) } >
138- < Image source = { w . icon } style = { styles . workoutIcon } />
139- < View style = { styles . workoutInfo } >
140- < Text style = { styles . workoutType } > { w . type } </ Text >
141- < Text style = { styles . workoutMeta } > { w . calories } Calories Burn | { w . duration } </ Text >
142- </ View >
143- < Image source = { require ( '../assets/images/arrow-right.png' ) } style = { styles . arrowIcon } />
144- </ TouchableOpacity >
145- ) ) }
146- </ View >
160+ < View style = { { alignItems : 'center' } } >
161+ < BarChart
162+ data = { { labels, datasets : [ { data } ] } }
163+ width = { Math . max ( width , labels . length * 60 ) }
164+ height = { 220 }
165+ fromZero
166+ showValuesOnTopOfBars
167+ withInnerLines = { true }
168+ withHorizontalLabels = { false } // Hide Y-axis labels only
169+ chartConfig = { {
170+ backgroundGradientFrom : '#fff' ,
171+ backgroundGradientTo : '#fff' ,
172+ color : ( ) => '#70A1FF' ,
173+ decimalPlaces : 0 ,
174+ barPercentage : 0.6 ,
175+ propsForBackgroundLines : {
176+ stroke : '#E0E0E0' ,
177+ } ,
178+ formatYLabel : ( yValue ) => `${ yValue } m` ,
179+ } }
180+ style = { {
181+ marginVertical : 8 ,
182+ borderRadius : 16 ,
183+ } }
184+ />
185+ </ View >
186+
187+
188+
189+ </ View >
147190
148191 { /* Personal Bests */ }
149192 < View style = { [ styles . latestSection , { paddingBottom : 16 } ] } >
150193 < View style = { styles . sectionHeader } >
151194 < Text style = { styles . sectionTitle } > Personal Bests</ Text >
152- < TouchableOpacity onPress = { ( ) => alert ( 'Full Personal Bests screen not implemented' ) } >
153- < Text style = { styles . seeMore } > See more</ Text >
154- </ TouchableOpacity >
155195 </ View >
156196
157197 { loading ? (
0 commit comments