Massive backend refactoring done

This commit is contained in:
AG
2025-12-10 14:56:20 +02:00
parent 502943f7d0
commit 95a5e37748
47 changed files with 1898 additions and 1416 deletions

View File

@@ -85,9 +85,9 @@ export const useTracker = (props: any) => { // Props ignored/removed
// Function to reload Quick Log session
const loadQuickLogSession = async () => {
try {
const response = await api.get<{ success: boolean; session?: WorkoutSession }>('/sessions/quick-log');
if (response.success && response.session) {
setQuickLogSession(response.session);
const response = await api.get<any>('/sessions/quick-log');
if (response.success && response.data?.session) {
setQuickLogSession(response.data.session);
}
} catch (error) {
console.error("Failed to load quick log session:", error);

View File

@@ -142,7 +142,7 @@ export const ActiveWorkoutProvider: React.FC<{ children: React.ReactNode }> = ({
// or similar. I need to type the response properly or cast it.
// Assuming response.newSet needs to be added.
if (response.success && response.newSet) {
if (response && response.newSet) {
setActiveSession(prev => prev ? ({
...prev,
sets: [...prev.sets, response.newSet]

View File

@@ -1,21 +1,35 @@
import { User, UserRole, UserProfile } from '../types';
import { api, setAuthToken, removeAuthToken } from './api';
interface ApiResponse<T> {
success: boolean;
data: T;
error?: string;
}
export const getUsers = async (): Promise<{ success: boolean; users?: User[]; error?: string }> => {
try {
const res = await api.get('/auth/users');
return res;
} catch (e) {
return { success: false, error: 'Failed to fetch users' };
const res = await api.get<ApiResponse<{ users: User[] }>>('/auth/users');
if (res.success && res.data) {
return { success: true, users: res.data.users };
}
return { success: false, error: res.error };
} catch (e: any) {
try {
const err = JSON.parse(e.message);
return { success: false, error: err.error || 'Failed to fetch users' };
} catch {
return { success: false, error: 'Failed to fetch users' };
}
}
};
export const login = async (email: string, password: string): Promise<{ success: boolean; user?: User; error?: string }> => {
try {
const res = await api.post('/auth/login', { email, password });
if (res.success) {
setAuthToken(res.token);
return { success: true, user: res.user };
const res = await api.post<ApiResponse<{ user: User, token: string }>>('/auth/login', { email, password });
if (res.success && res.data) {
setAuthToken(res.data.token);
return { success: true, user: res.data.user };
}
return { success: false, error: res.error };
} catch (e: any) {
@@ -30,9 +44,9 @@ export const login = async (email: string, password: string): Promise<{ success:
export const createUser = async (email: string, password: string): Promise<{ success: boolean; error?: string }> => {
try {
const res = await api.post('/auth/register', { email, password });
if (res.success) {
setAuthToken(res.token);
const res = await api.post<ApiResponse<{ user: User, token: string }>>('/auth/register', { email, password });
if (res.success && res.data) {
setAuthToken(res.data.token);
return { success: true };
}
return { success: false, error: res.error };
@@ -48,50 +62,74 @@ export const createUser = async (email: string, password: string): Promise<{ suc
export const deleteUser = async (userId: string) => {
try {
const res = await api.delete(`/auth/users/${userId}`);
const res = await api.delete<ApiResponse<any>>(`/auth/users/${userId}`);
return res;
} catch (e) {
return { success: false, error: 'Failed to delete user' };
} catch (e: any) {
try {
const err = JSON.parse(e.message);
return { success: false, error: err.error || 'Failed to delete user' };
} catch {
return { success: false, error: 'Failed to delete user' };
}
}
};
export const toggleBlockUser = async (userId: string, block: boolean) => {
try {
const res = await api.patch(`/auth/users/${userId}/block`, { block });
const res = await api.patch<ApiResponse<any>>(`/auth/users/${userId}/block`, { block });
return res;
} catch (e) {
return { success: false, error: 'Failed to update user status' };
} catch (e: any) {
try {
const err = JSON.parse(e.message);
return { success: false, error: err.error || 'Failed to update user status' };
} catch {
return { success: false, error: 'Failed to update user status' };
}
}
};
export const adminResetPassword = async (userId: string, newPass: string) => {
try {
const res = await api.post(`/auth/users/${userId}/reset-password`, { newPassword: newPass });
const res = await api.post<ApiResponse<any>>(`/auth/users/${userId}/reset-password`, { newPassword: newPass });
return res;
} catch (e) {
return { success: false, error: 'Failed to reset password' };
} catch (e: any) {
try {
const err = JSON.parse(e.message);
return { success: false, error: err.error || 'Failed to reset password' };
} catch {
return { success: false, error: 'Failed to reset password' };
}
}
};
export const updateUserProfile = async (userId: string, profile: Partial<UserProfile>): Promise<{ success: boolean; error?: string }> => {
try {
const res = await api.patch('/auth/profile', profile);
const res = await api.patch<ApiResponse<any>>('/auth/profile', profile);
return res;
} catch (e) {
return { success: false, error: 'Failed to update profile' };
} catch (e: any) {
try {
const err = JSON.parse(e.message);
return { success: false, error: err.error || 'Failed to update profile' };
} catch {
return { success: false, error: 'Failed to update profile' };
}
}
};
export const changePassword = async (userId: string, newPassword: string) => {
try {
const res = await api.post('/auth/change-password', { userId, newPassword });
const res = await api.post<ApiResponse<any>>('/auth/change-password', { userId, newPassword });
if (!res.success) {
console.error('Failed to change password:', res.error);
}
return res;
} catch (e) {
console.error(e);
return { success: false, error: 'Network error' };
} catch (e: any) {
try {
const err = JSON.parse(e.message);
return { success: false, error: err.error || 'Network error' };
} catch {
return { success: false, error: 'Network error' };
}
}
};
@@ -103,9 +141,12 @@ export const getCurrentUserProfile = (userId: string): UserProfile | undefined =
export const getMe = async (): Promise<{ success: boolean; user?: User; error?: string }> => {
try {
const res = await api.get('/auth/me');
return res;
} catch (e) {
const res = await api.get<ApiResponse<{ user: User }>>('/auth/me');
if (res.success && res.data) {
return { success: true, user: res.data.user };
}
return { success: false, error: res.error };
} catch (e: any) {
return { success: false, error: 'Failed to fetch user' };
}
};

View File

@@ -1,23 +1,30 @@
import { ExerciseDef, WorkoutSet } from '../types';
import { api } from './api';
interface ApiResponse<T> {
success: boolean;
data: T;
error?: string;
}
export const getExercises = async (userId: string): Promise<ExerciseDef[]> => {
try {
return await api.get<ExerciseDef[]>('/exercises');
const res = await api.get<ApiResponse<ExerciseDef[]>>('/exercises');
return res.data || [];
} catch {
return [];
}
};
export const saveExercise = async (userId: string, exercise: ExerciseDef): Promise<void> => {
await api.post('/exercises', exercise);
await api.post<ApiResponse<any>>('/exercises', exercise);
};
export const getLastSetForExercise = async (userId: string, exerciseId: string): Promise<WorkoutSet | undefined> => {
try {
const response = await api.get<{ success: boolean; set?: WorkoutSet }>(`/exercises/${exerciseId}/last-set`);
if (response.success && response.set) {
return response.set;
const response = await api.get<ApiResponse<{ set?: WorkoutSet }>>(`/exercises/${exerciseId}/last-set`);
if (response.success && response.data?.set) {
return response.data.set;
}
return undefined;
} catch (error) {

View File

@@ -2,6 +2,12 @@ import { WorkoutSession, UserProfile, WorkoutPlan } from '../types';
import { api } from './api';
import { generateId } from '../utils/uuid';
interface ApiResponse<T> {
success: boolean;
data: T;
error?: string;
}
interface FitnessChatOptions {
history: WorkoutSession[];
userProfile?: UserProfile;
@@ -111,15 +117,15 @@ export const createFitnessChat = (
return {
sendMessage: async (userMessage: string) => {
const res = await api.post('/ai/chat', {
const res = await api.post<ApiResponse<{ response: string }>>('/ai/chat', {
systemInstruction,
userMessage,
sessionId
});
return {
text: res.response,
text: res.data.response,
response: {
text: () => res.response
text: () => res.data.response
}
};
}

View File

@@ -1,18 +1,25 @@
import { WorkoutPlan } from '../types';
import { api } from './api';
interface ApiResponse<T> {
success: boolean;
data: T;
error?: string;
}
export const getPlans = async (userId: string): Promise<WorkoutPlan[]> => {
try {
return await api.get<WorkoutPlan[]>('/plans');
const res = await api.get<ApiResponse<WorkoutPlan[]>>('/plans');
return res.data || [];
} catch {
return [];
}
};
export const savePlan = async (userId: string, plan: WorkoutPlan): Promise<void> => {
await api.post('/plans', plan);
await api.post<ApiResponse<any>>('/plans', plan);
};
export const deletePlan = async (userId: string, id: string): Promise<void> => {
await api.delete(`/plans/${id}`);
await api.delete<ApiResponse<any>>(`/plans/${id}`);
};

View File

@@ -13,9 +13,16 @@ interface ApiSession extends Omit<WorkoutSession, 'startTime' | 'endTime' | 'set
})[];
}
interface ApiResponse<T> {
success: boolean;
data: T;
error?: string;
}
export const getSessions = async (userId: string): Promise<WorkoutSession[]> => {
try {
const sessions = await api.get<ApiSession[]>('/sessions');
const response = await api.get<ApiResponse<ApiSession[]>>('/sessions');
const sessions = response.data || [];
// Convert ISO date strings to timestamps
return sessions.map((session) => ({
...session,
@@ -33,16 +40,17 @@ export const getSessions = async (userId: string): Promise<WorkoutSession[]> =>
};
export const saveSession = async (userId: string, session: WorkoutSession): Promise<void> => {
await api.post('/sessions', session);
await api.post<ApiResponse<any>>('/sessions', session);
};
export const getActiveSession = async (userId: string): Promise<WorkoutSession | null> => {
try {
const response = await api.get<{ success: boolean; session?: ApiSession }>('/sessions/active');
if (!response.success || !response.session) {
const response = await api.get<ApiResponse<{ session: ApiSession | null }>>('/sessions/active');
if (!response.success || !response.data?.session) {
return null;
}
const session = response.session;
const session = response.data.session;
// Convert ISO date strings to timestamps
return {
...session,
@@ -60,29 +68,35 @@ export const getActiveSession = async (userId: string): Promise<WorkoutSession |
};
export const updateActiveSession = async (userId: string, session: WorkoutSession): Promise<void> => {
await api.put('/sessions/active', session);
await api.put<ApiResponse<any>>('/sessions/active', session);
};
export const deleteSetFromActiveSession = async (userId: string, setId: string): Promise<void> => {
await api.delete(`/sessions/active/set/${setId}`);
await api.delete<ApiResponse<any>>(`/sessions/active/set/${setId}`);
};
export const updateSetInActiveSession = async (userId: string, setId: string, setData: Partial<WorkoutSet>): Promise<WorkoutSet> => {
const response = await api.put<{ success: boolean; updatedSet: WorkoutSet }>(`/sessions/active/set/${setId}`, setData);
return response.updatedSet;
const response = await api.put<ApiResponse<{ updatedSet: ApiSession['sets'][0] }>>(`/sessions/active/set/${setId}`, setData);
const updatedSet = response.data.updatedSet;
return {
...updatedSet,
exerciseName: updatedSet.exercise?.name || 'Unknown',
type: updatedSet.exercise?.type || ExerciseType.STRENGTH
} as WorkoutSet;
};
export const deleteActiveSession = async (userId: string): Promise<void> => {
await api.delete('/sessions/active');
await api.delete<ApiResponse<any>>('/sessions/active');
};
export const deleteSession = async (userId: string, id: string): Promise<void> => {
await api.delete(`/sessions/${id}`);
await api.delete<ApiResponse<any>>(`/sessions/${id}`);
};
export const addSetToActiveSession = async (userId: string, setData: any): Promise<any> => {
return await api.post('/sessions/active/log-set', setData);
const response = await api.post<ApiResponse<any>>('/sessions/active/log-set', setData);
return response.data;
};
export const deleteAllUserData = (userId: string) => {

View File

@@ -1,23 +1,16 @@
import { BodyWeightRecord } from '../types';
import { api } from './api';
const API_URL = '/api';
interface ApiResponse<T> {
success: boolean;
data: T;
error?: string;
}
export const getWeightHistory = async (): Promise<BodyWeightRecord[]> => {
const token = localStorage.getItem('token');
if (!token) return [];
try {
const response = await fetch(`${API_URL}/weight`, {
headers: {
'Authorization': `Bearer ${token}`
}
});
if (!response.ok) {
throw new Error('Failed to fetch weight history');
}
return await response.json();
const res = await api.get<ApiResponse<BodyWeightRecord[]>>('/weight');
return res.data || [];
} catch (error) {
console.error('Error fetching weight history:', error);
return [];
@@ -25,27 +18,12 @@ export const getWeightHistory = async (): Promise<BodyWeightRecord[]> => {
};
export const logWeight = async (weight: number, dateStr?: string): Promise<BodyWeightRecord | null> => {
const token = localStorage.getItem('token');
if (!token) return null;
try {
// Default to today if no date provided
const date = dateStr || new Date().toISOString().split('T')[0];
const response = await fetch(`${API_URL}/weight`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
body: JSON.stringify({ weight, dateStr: date })
});
if (!response.ok) {
throw new Error('Failed to log weight');
}
return await response.json();
const res = await api.post<ApiResponse<BodyWeightRecord>>('/weight', { weight, dateStr: date });
return res.data;
} catch (error) {
console.error('Error logging weight:', error);
return null;