Skip to content

Commit d79040b

Browse files
committed
Checkpoint for Workouts
2 parents 1acfc9c + 0d04da7 commit d79040b

File tree

10 files changed

+310
-129
lines changed

10 files changed

+310
-129
lines changed

KonditionExpo/app/(tabs)/history.tsx

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,15 @@ import {
1313
import { router } from 'expo-router';
1414
import { apiService, WorkoutResponse } from '@/services/api';
1515
import { useAuth } from '@/contexts/AuthContext';
16+
import axios from 'axios';
1617

1718
const WorkoutHistoryScreen = () => {
1819
const { user } = useAuth();
1920
const [workouts, setWorkouts] = useState<WorkoutResponse[]>([]);
2021
const [loading, setLoading] = useState(true);
2122
const [refreshing, setRefreshing] = useState(false);
2223
const [error, setError] = useState<string | null>(null);
24+
const { token, isAuthenticated, isLoading } = useAuth(); //token of user
2325

2426
const fetchWorkouts = async (isRefresh = false) => {
2527
try {
@@ -30,7 +32,16 @@ const WorkoutHistoryScreen = () => {
3032
}
3133
setError(null);
3234

33-
const workoutData = await apiService.getWorkouts();
35+
//const workoutData = await apiService.getWorkouts(); - Uses old api.ts, idk
36+
37+
const response = await axios.get('http://localhost:8000/api/v1/workouts/', {
38+
headers: {
39+
Authorization: `Bearer ${token}`,
40+
},
41+
});
42+
43+
console.log("Fetched workouts for history: ", response);
44+
const workoutData = response.data;
3445
// Ensure workoutData is an array
3546
if (Array.isArray(workoutData)) {
3647
setWorkouts(workoutData);

KonditionExpo/app/(tabs)/progress.tsx

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useState } from 'react';
1+
import React, { useState, useEffect } from 'react';
22
import {
33
SafeAreaView,
44
View,
@@ -15,7 +15,7 @@ import { useWorkout, Workout } from '@/contexts/WorkoutContext';
1515
import { Button } from '@/components/ui/Button';
1616
import { Input } from '@/components/ui/Input';
1717
import { router } from 'expo-router';
18-
18+
import { useAuth } from '@/contexts/AuthContext';
1919
const { width } = Dimensions.get('window');
2020

2121
interface WorkoutItemProps {
@@ -32,9 +32,7 @@ const WorkoutItem = ({ workout, onPress }: WorkoutItemProps) => {
3232
});
3333
};
3434

35-
const getTotalSets = () => {
36-
return workout.exercises.reduce((total, exercise) => total + exercise.sets.length, 0);
37-
};
35+
console.log("Workout Item: ", workout);
3836

3937
return (
4038
<TouchableOpacity style={styles.workoutItem} onPress={onPress}>
@@ -43,22 +41,40 @@ const WorkoutItem = ({ workout, onPress }: WorkoutItemProps) => {
4341
<Text style={styles.workoutDate}>{formatDate(workout.date)}</Text>
4442
</View>
4543
<View style={styles.workoutStats}>
46-
<Text style={styles.workoutStat}>{workout.exercises.length} exercises</Text>
47-
<Text style={styles.workoutStat}>{getTotalSets()} sets</Text>
48-
<Text style={styles.workoutStat}>{workout.duration}min</Text>
44+
<Text style={styles.workoutStat}>{workout.exercises.sets} sets</Text>
45+
<Text style={styles.workoutStat}>{workout.exercises.reps} reps</Text>
46+
<Text style={styles.workoutStat}>{workout.exercises.weight} weight</Text>
4947
</View>
5048
</TouchableOpacity>
5149
);
5250
};
5351

52+
53+
5454
const ProgressScreen = () => {
55-
const { workouts, currentWorkout, startWorkout } = useWorkout();
55+
const { workouts, currentWorkout, startWorkout, getWorkouts } = useWorkout();
56+
const { isAuthenticated, isLoading } = useAuth();
5657
const [showNewWorkoutModal, setShowNewWorkoutModal] = useState(false);
5758
const [newWorkoutName, setNewWorkoutName] = useState('');
58-
5959
const backgroundColor = '#FFFFFF';
6060
const textColor = '#333';
6161
const tintColor = '#70A1FF';
62+
63+
// ⬇️ Load backend workouts once auth is ready
64+
useEffect(() => {
65+
if (isAuthenticated && !isLoading) {
66+
console.log("Authenticated and loaded in workout context, about to get workouts!")
67+
getWorkouts();
68+
}
69+
}, [isAuthenticated, isLoading]);
70+
71+
if (isLoading || !isAuthenticated) {
72+
return (
73+
<SafeAreaView style={styles.container}>
74+
<Text style={{ textAlign: 'center', marginTop: 100 }}>Loading your progress...</Text>
75+
</SafeAreaView>
76+
);
77+
}
6278

6379
const handleStartWorkout = () => {
6480
if (!newWorkoutName.trim()) {
@@ -206,10 +222,10 @@ const ProgressScreen = () => {
206222
No workouts yet. Start your first workout to track your progress!
207223
</Text>
208224
</View>
209-
) : (
225+
) : (
210226
workouts
211227
.sort((a, b) => b.date.getTime() - a.date.getTime())
212-
.slice(0, 10)
228+
.slice(0, 3) // Should prob just be 3
213229
.map((workout) => (
214230
<WorkoutItem
215231
key={workout.id}

KonditionExpo/app/workout.tsx

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -149,25 +149,21 @@ const WorkoutScreen = () => {
149149
addSetToExercise(exerciseId, newSet);
150150
};
151151

152-
const handleFinishWorkout = () => {
152+
const handleFinishWorkout = async () => {
153153
if (!currentWorkout) return;
154-
155-
Alert.alert(
156-
'Finish Workout',
157-
'Are you sure you want to finish this workout?',
158-
[
159-
{ text: 'Cancel', style: 'cancel' },
160-
{
161-
text: 'Finish',
162-
onPress: () => {
163-
const duration = Math.round((new Date().getTime() - startTime.getTime()) / 60000);
164-
const updatedWorkout = { ...currentWorkout, duration };
165-
endWorkout();
166-
router.replace('/(tabs)');
167-
},
168-
},
169-
]
170-
);
154+
155+
const duration = Math.round((new Date().getTime() - startTime.getTime()) / 60000);
156+
const updatedWorkout = { ...currentWorkout, duration };
157+
158+
console.log("FinishWorkout-UpdatedWorkout: ", updatedWorkout);
159+
160+
try {
161+
await endWorkout(updatedWorkout); // wait for backend POST to complete
162+
router.replace('/(tabs)');
163+
} catch (error) {
164+
console.error("Error finishing workout:", error);
165+
// Optionally show UI feedback
166+
}
171167
};
172168

173169
if (!currentWorkout) {

KonditionExpo/contexts/WorkoutContext.tsx

Lines changed: 90 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
import React, { createContext, useContext, useState, ReactNode } from 'react';
2+
import axios from 'axios';
3+
import { useAuth } from '@/contexts/AuthContext'; // adjust if needed
24

35
export interface Exercise {
46
id: string;
57
name: string;
8+
description?: string;
69
muscle_group: string;
710
type: 'strength' | 'cardio' | 'flexibility';
811
}
@@ -34,11 +37,12 @@ export interface Workout {
3437
interface WorkoutContextType {
3538
workouts: Workout[];
3639
currentWorkout: Workout | null;
37-
addWorkout: (workout: Workout) => void;
40+
addWorkout: (workout: Workout) => Promise<void>; // <-- async now
3841
updateWorkout: (workoutId: string, workout: Workout) => void;
42+
getWorkouts: () => void;
3943
deleteWorkout: (workoutId: string) => void;
4044
startWorkout: (name: string) => void;
41-
endWorkout: () => void;
45+
endWorkout: (updatedWorkout: Workout) => Promise<void>; // <-- async now
4246
addExerciseToCurrentWorkout: (exercise: Exercise) => void;
4347
addSetToExercise: (exerciseId: string, set: Omit<WorkoutSet, 'id'>) => void;
4448
removeSetFromExercise: (exerciseId: string, setId: string) => void;
@@ -50,18 +54,96 @@ const WorkoutContext = createContext<WorkoutContextType | undefined>(undefined);
5054
export const WorkoutProvider = ({ children }: { children: ReactNode }) => {
5155
const [workouts, setWorkouts] = useState<Workout[]>([]);
5256
const [currentWorkout, setCurrentWorkout] = useState<Workout | null>(null);
57+
const { token, isAuthenticated, isLoading } = useAuth(); //token of user
58+
59+
//NO WAIT FOR TOKEN, IS GIVING NULL IN WORKOUT CONTEXT
60+
61+
//console.log("In WorkoutContext - Current User token is: ", token);
5362

5463
const generateId = () => Math.random().toString(36).substr(2, 9);
5564

56-
const addWorkout = (workout: Workout) => {
57-
setWorkouts(prev => [...prev, workout]);
65+
const transformWorkoutForBackend = (workout: Workout) => ({
66+
name: workout.name,
67+
description: workout.notes || null,
68+
scheduled_date: workout.date.toISOString(),
69+
duration_minutes: workout.duration,
70+
exercises: workout.exercises.map(ex => ({
71+
name: ex.exercise.name,
72+
description: ex.exercise.description || null,
73+
category: ex.exercise.muscle_group, // or ex.exercise.type if that's better
74+
sets: ex.sets.length,
75+
reps: ex.sets.reduce((sum, s) => sum + (s.reps || 0), 0),
76+
weight: ex.sets.reduce((max, s) => Math.max(max, s.weight || 0), 0),
77+
})),
78+
});
79+
80+
const addWorkout = async (workout: Workout) => {
81+
try {
82+
const payload = transformWorkoutForBackend(workout);
83+
const response = await axios.post(
84+
'http://localhost:8000/api/v1/workouts/', // Replace with deployment endpoint
85+
payload,
86+
{
87+
headers: {
88+
Authorization: `Bearer ${token}`,
89+
},
90+
}
91+
);
92+
//console.log("Response from POST /workouts: ", response);
93+
const savedWorkout = response.data;
94+
95+
const saved = {
96+
...response.data,
97+
date: new Date(response.data.created_at),
98+
exercises: [], // if backend doesn't return them
99+
duration: response.data.duration_minutes || 0,
100+
};
101+
102+
setWorkouts(prev => [...prev, saved]);
103+
104+
} catch (error) {
105+
console.error('Failed to save workout to backend:', error.response?.data || error.message);
106+
}
58107
};
59108

60-
const updateWorkout = (workoutId: string, updatedWorkout: Workout) => {
109+
const getWorkouts = async () => {
110+
try {
111+
console.log("About to get workouts with token: ", token);
112+
const response = await axios.get('http://localhost:8000/api/v1/workouts/', {
113+
headers: {
114+
Authorization: `Bearer ${token}`,
115+
},
116+
});
117+
118+
//console.log("Get workouts response: ", response);
119+
// Extract array properly
120+
const workoutArray = response.data;
121+
122+
// Convert string dates to Date objects
123+
const parsed = workoutArray.map((w: any) => ({
124+
...w,
125+
date: new Date(w.created_at),
126+
exercises: w.exercises || [], // fallback to empty array
127+
duration: w.duration_minutes || 0,
128+
}));
129+
130+
setWorkouts(parsed);
131+
} catch (error) {
132+
console.error('Failed to load workouts:', error.response?.data || error.message);
133+
}
134+
};
135+
const endWorkout = async (updatedWorkout: Workout) => {
136+
await addWorkout(updatedWorkout);
137+
setCurrentWorkout(null);
138+
};
139+
140+
//Everything below this is old - only updates local state rather than send backend requests
141+
142+
const updateWorkout = (workoutId: string, updatedWorkout: Workout) => { //Old
61143
setWorkouts(prev => prev.map(w => w.id === workoutId ? updatedWorkout : w));
62144
};
63145

64-
const deleteWorkout = (workoutId: string) => {
146+
const deleteWorkout = (workoutId: string) => { // Old
65147
setWorkouts(prev => prev.filter(w => w.id !== workoutId));
66148
};
67149

@@ -76,13 +158,6 @@ export const WorkoutProvider = ({ children }: { children: ReactNode }) => {
76158
setCurrentWorkout(newWorkout);
77159
};
78160

79-
const endWorkout = () => {
80-
if (currentWorkout) {
81-
addWorkout(currentWorkout);
82-
setCurrentWorkout(null);
83-
}
84-
};
85-
86161
const addExerciseToCurrentWorkout = (exercise: Exercise) => {
87162
if (!currentWorkout) return;
88163

@@ -155,11 +230,12 @@ export const WorkoutProvider = ({ children }: { children: ReactNode }) => {
155230
updateWorkout,
156231
deleteWorkout,
157232
startWorkout,
158-
endWorkout,
233+
endWorkout,
159234
addExerciseToCurrentWorkout,
160235
addSetToExercise,
161236
removeSetFromExercise,
162237
updateSet,
238+
getWorkouts,
163239
}}>
164240
{children}
165241
</WorkoutContext.Provider>

0 commit comments

Comments
 (0)