From 1b50bfd2eef12f4562a9a65c211036516d7ff542 Mon Sep 17 00:00:00 2001 From: echo Date: Sun, 23 Nov 2025 17:12:14 +0100 Subject: [PATCH] api calls simplified --- apps/admin/data/fitai.db | Bin 73728 -> 73728 bytes apps/mobile/src/api/attendance.ts | 47 ++++++++++++++++++++++ apps/mobile/src/api/client.ts | 18 +++++++++ apps/mobile/src/api/fitnessProfile.ts | 18 ++++----- apps/mobile/src/api/profile.ts | 30 ++++++++++++++ apps/mobile/src/app/(tabs)/attendance.tsx | 36 +++++------------ apps/mobile/src/app/welcome.tsx | 36 ++++++++++------- 7 files changed, 136 insertions(+), 49 deletions(-) create mode 100644 apps/mobile/src/api/attendance.ts create mode 100644 apps/mobile/src/api/client.ts create mode 100644 apps/mobile/src/api/profile.ts diff --git a/apps/admin/data/fitai.db b/apps/admin/data/fitai.db index b0b601a59136faaf155d098f91139f6f7f39a07a..46416c03aeddba428912ab83c11ae634227b771a 100644 GIT binary patch delta 979 zcma)*&ubGw6vwk9n=DDYQ>CTUDs62AEtz#@cV>5XG1Q`n2t5Q^gxFH|$E-x%G}J`! zl*WSx54O4&uRVDTl7sYC{|gJ^LC}l%F9c@`$stzB?ah}5-}n8zH+#pKz2nTmthD*| z;w@?OB7sDk}s#geYG>zQPbm3#xCT``Cr|I2|ItiJ)KiF))p?!l}d(3Tnb}eag)YU^vLJRThr|j4==q@s5vClO7V!g}HJ|a_ZG(m{ zDxO|mr}6LNxmLu3YBSny@ZIQfGpa8ebzTdqwMRpi%rQ(2TWENcfj<5q^*+fjMj0i4 zf0X!V@p7%t;a}EgQy9=`pU)-~ri3-8%nc3Ogdt-X66R9KY>z^p2d0or>SH^`z4<#s zvCnq497FKO=5XkN9(RhJ8xtb-s_^y=Y#Hq-`Sc9Lo0ukJx{V+S4GM|PE$DfOK$nI( zXMW)M3?;L~JuQFl{|GDxTbgbEMSq~TuVoV3RdIc>yRsC&hPS)VwKvkFq8_Ed7xhT} z4hZOgE$|8y#K9h_t*hw`X_TW;lEzV1noAl-SwJ>vyfO+Nxx2OU;id?2k^*1BCvX=m tf_G|9Jpqvj@mY => { + try { + const response = await apiClient.get(API_ENDPOINTS.ATTENDANCE.HISTORY, { + headers: { Authorization: `Bearer ${token}` }, + }); + return response.data; + } catch (error) { + throw error; + } + }, + + checkIn: async (type: string, token: string): Promise => { + try { + await apiClient.post( + API_ENDPOINTS.ATTENDANCE.CHECK_IN, + { type }, + { headers: { Authorization: `Bearer ${token}` } }, + ); + } catch (error) { + throw error; + } + }, + + checkOut: async (token: string): Promise => { + try { + await apiClient.post( + API_ENDPOINTS.ATTENDANCE.CHECK_OUT, + {}, + { headers: { Authorization: `Bearer ${token}` } }, + ); + } catch (error) { + throw error; + } + }, +}; diff --git a/apps/mobile/src/api/client.ts b/apps/mobile/src/api/client.ts new file mode 100644 index 0000000..35ac7f9 --- /dev/null +++ b/apps/mobile/src/api/client.ts @@ -0,0 +1,18 @@ +import axios from 'axios'; +import { API_BASE_URL } from '../config/api'; + +export const apiClient = axios.create({ + baseURL: API_BASE_URL, + headers: { + 'Content-Type': 'application/json', + }, +}); + +// Helper to set the auth token for a request +export const setAuthToken = (token: string) => { + if (token) { + apiClient.defaults.headers.common['Authorization'] = `Bearer ${token}`; + } else { + delete apiClient.defaults.headers.common['Authorization']; + } +}; diff --git a/apps/mobile/src/api/fitnessProfile.ts b/apps/mobile/src/api/fitnessProfile.ts index e535e17..45bc827 100644 --- a/apps/mobile/src/api/fitnessProfile.ts +++ b/apps/mobile/src/api/fitnessProfile.ts @@ -1,5 +1,5 @@ -import axios from "axios"; -import { API_BASE_URL } from "../config/api"; +import { apiClient } from "./client"; +import { API_ENDPOINTS } from "../config/api"; export interface FitnessProfile { id?: string; @@ -22,10 +22,10 @@ export const fitnessProfileApi = { try { console.log( "Getting fitness profile with URL:", - `${API_BASE_URL}/api/users/${userId}/fitness-profile`, + `${API_ENDPOINTS.USERS}/${userId}/fitness-profile`, ); - const response = await axios.get( - `${API_BASE_URL}/api/users/${userId}/fitness-profile`, + const response = await apiClient.get( + `${API_ENDPOINTS.USERS}/${userId}/fitness-profile`, { headers: { Authorization: `Bearer ${token}`, @@ -49,8 +49,8 @@ export const fitnessProfileApi = { token: string, ): Promise => { try { - const response = await axios.put( - `${API_BASE_URL}/api/users/${userId}/fitness-profile`, + const response = await apiClient.put( + `${API_ENDPOINTS.USERS}/${userId}/fitness-profile`, data, { headers: { @@ -74,8 +74,8 @@ export const fitnessProfileApi = { token: string, ): Promise => { try { - const response = await axios.post( - `${API_BASE_URL}/api/users/${data.clientId}/fitness-profile`, + const response = await apiClient.post( + `${API_ENDPOINTS.USERS}/${data.clientId}/fitness-profile`, data, { headers: { diff --git a/apps/mobile/src/api/profile.ts b/apps/mobile/src/api/profile.ts new file mode 100644 index 0000000..5c3eb59 --- /dev/null +++ b/apps/mobile/src/api/profile.ts @@ -0,0 +1,30 @@ +import { apiClient } from "./client"; +import { API_ENDPOINTS } from "../config/api"; + +export interface FitnessProfileData { + userId: string; + height: string; + weight: string; + age: string; + gender: "male" | "female" | "other"; + activityLevel: "sedentary" | "light" | "moderate" | "active" | "very_active"; + fitnessGoals: string[]; + exerciseHabits: string; + dietHabits: string; + medicalConditions: string; +} + +export const profileApi = { + createFitnessProfile: async ( + data: FitnessProfileData, + token: string, + ): Promise => { + try { + await apiClient.post(API_ENDPOINTS.PROFILE.FITNESS, data, { + headers: { Authorization: `Bearer ${token}` }, + }); + } catch (error) { + throw error; + } + }, +}; diff --git a/apps/mobile/src/app/(tabs)/attendance.tsx b/apps/mobile/src/app/(tabs)/attendance.tsx index bab1650..e74b554 100644 --- a/apps/mobile/src/app/(tabs)/attendance.tsx +++ b/apps/mobile/src/app/(tabs)/attendance.tsx @@ -1,16 +1,9 @@ import { View, Text, StyleSheet, TouchableOpacity, ActivityIndicator, ScrollView, Alert } from 'react-native' import { useState, useEffect } from 'react' import { useAuth } from '@clerk/clerk-expo' -import axios from 'axios' -import { API_BASE_URL, API_ENDPOINTS } from '../../config/api' +import { attendanceApi, Attendance } from '../../api/attendance' + -interface Attendance { - id: string - checkInTime: string - checkOutTime?: string - type: string - notes?: string -} export default function AttendanceScreen() { const { getToken, userId } = useAuth() @@ -22,13 +15,10 @@ export default function AttendanceScreen() { try { setLoading(true) const token = await getToken() - const url = `${API_BASE_URL}${API_ENDPOINTS.ATTENDANCE.HISTORY}` - console.log('Fetching attendance from:', url) - const response = await axios.get(url, { - headers: { Authorization: `Bearer ${token}` } - }) + if (!token) return - const data: Attendance[] = response.data + console.log('Fetching attendance history') + const data = await attendanceApi.getHistory(token) setHistory(data) // Check if there's an active check-in (latest one has no checkOutTime) @@ -52,11 +42,9 @@ export default function AttendanceScreen() { const handleCheckIn = async () => { try { const token = await getToken() - await axios.post( - `${API_BASE_URL}${API_ENDPOINTS.ATTENDANCE.CHECK_IN}`, - { type: 'gym' }, - { headers: { Authorization: `Bearer ${token}` } } - ) + if (!token) return + + await attendanceApi.checkIn('gym', token) fetchAttendance() Alert.alert('Success', 'Checked in successfully!') } catch (error: any) { @@ -68,11 +56,9 @@ export default function AttendanceScreen() { const handleCheckOut = async () => { try { const token = await getToken() - await axios.post( - `${API_BASE_URL}${API_ENDPOINTS.ATTENDANCE.CHECK_OUT}`, - {}, - { headers: { Authorization: `Bearer ${token}` } } - ) + if (!token) return + + await attendanceApi.checkOut(token) fetchAttendance() Alert.alert('Success', 'Checked out successfully!') } catch (error: any) { diff --git a/apps/mobile/src/app/welcome.tsx b/apps/mobile/src/app/welcome.tsx index 35c9e8c..c97997f 100644 --- a/apps/mobile/src/app/welcome.tsx +++ b/apps/mobile/src/app/welcome.tsx @@ -1,9 +1,9 @@ import React, { useState } from 'react' import { View, Text, TextInput, TouchableOpacity, StyleSheet, Alert, ScrollView } from 'react-native' import { useRouter } from 'expo-router' -import axios from 'axios' +import { useAuth } from '@clerk/clerk-expo' import * as SecureStore from 'expo-secure-store' -import { API_BASE_URL, API_ENDPOINTS } from '../config/api' +import { profileApi } from '../api/profile' interface FitnessProfile { height: string @@ -31,10 +31,11 @@ export default function WelcomeScreen() { }) const [loading, setLoading] = useState(false) const router = useRouter() + const { getToken } = useAuth() const fitnessGoalsOptions = [ 'Weight Loss', - 'Muscle Gain', + 'Muscle Gain', 'Improve Endurance', 'Better Flexibility', 'General Fitness', @@ -67,26 +68,31 @@ export default function WelcomeScreen() { setLoading(true) try { + const token = await getToken() + if (!token) { + throw new Error('Authentication required') + } + const user = await SecureStore.getItemAsync('user') if (!user) { throw new Error('No user found') } const userData = JSON.parse(user) - - const response = await axios.post( - `${API_BASE_URL}${API_ENDPOINTS.PROFILE.FITNESS}`, + + await profileApi.createFitnessProfile( { userId: userData.id, ...profile - } + }, + token ) - if (response.status === 201) { - Alert.alert('Success', 'Profile completed successfully!', [ - { text: 'OK', onPress: () => router.replace('/(tabs)') } - ]) - } + Alert.alert('Success', 'Profile completed successfully!', [ + { text: 'OK', onPress: () => router.replace('/(tabs)') } + ]) + + } catch (error: any) { console.log('Profile save error:', error) Alert.alert('Error', error.response?.data?.error || 'Failed to save profile. Please try again.') @@ -103,7 +109,7 @@ export default function WelcomeScreen() { Basic Information - + Height (cm) @@ -115,7 +121,7 @@ export default function WelcomeScreen() { placeholder="170" /> - + Weight (kg) - + Gender