diff --git a/apps/admin/data/fitai.db b/apps/admin/data/fitai.db index c1d83da..eda26cc 100644 Binary files a/apps/admin/data/fitai.db and b/apps/admin/data/fitai.db differ diff --git a/apps/admin/src/app/api/users/gym/route.ts b/apps/admin/src/app/api/users/gym/route.ts index 478b81a..4a14374 100644 --- a/apps/admin/src/app/api/users/gym/route.ts +++ b/apps/admin/src/app/api/users/gym/route.ts @@ -63,7 +63,7 @@ export async function PATCH(req: Request) { gymId, }); await db.run( - sql`UPDATE users SET gym_id = ${gymId ?? null}, updated_at = ${new Date()} WHERE id = ${userId}`, + sql`UPDATE users SET gym_id = ${gymId ?? null}, updated_at = ${Date.now()} WHERE id = ${userId}`, ); console.log("PATCH /api/users/gym update completed"); diff --git a/apps/mobile/src/app/(tabs)/profile.tsx b/apps/mobile/src/app/(tabs)/profile.tsx index f3481ec..7a2d740 100644 --- a/apps/mobile/src/app/(tabs)/profile.tsx +++ b/apps/mobile/src/app/(tabs)/profile.tsx @@ -15,6 +15,8 @@ import { LinearGradient } from "expo-linear-gradient"; import { theme } from "../../styles/theme"; import { AnimatedButton } from "../../components/AnimatedButton"; import { GradientBackground } from "../../components/GradientBackground"; +import { useState } from "react"; +import { API_BASE_URL, API_ENDPOINTS } from "../../config/api"; export default function ProfileScreen() { const { user } = useUser(); @@ -48,13 +50,48 @@ export default function ProfileScreen() { try { setGymsLoading(true); const token = await getToken(); - const res = await fetch("/api/gyms", { + const url = `${API_BASE_URL}${API_ENDPOINTS.GYMS}`; + console.log("Profile.loadGyms fetching:", url); + const res = await fetch(url, { headers: token ? { Authorization: `Bearer ${token}` } : undefined, }); - const data = await res.json(); + const contentType = res.headers.get("content-type") || ""; + if (!res.ok) { + const text = await res.text().catch(() => ""); + console.error("Failed to fetch gyms: non-OK response", { + status: res.status, + body: text?.slice(0, 200), + }); + setGyms([]); + return; + } + if (!contentType.includes("application/json")) { + const text = await res.text().catch(() => ""); + console.error("Failed to fetch gyms: expected JSON", { + contentType, + body: text?.slice(0, 200), + }); + setGyms([]); + return; + } + let data: any = null; + try { + data = await res.json(); + } catch (e) { + const text = await res.text().catch(() => ""); + console.error( + "Failed to parse gyms JSON:", + e, + "body:", + text?.slice(0, 200), + ); + setGyms([]); + return; + } setGyms(Array.isArray(data) ? data : []); } catch (err) { console.error("Failed to fetch gyms:", err); + setGyms([]); } finally { setGymsLoading(false); } @@ -63,7 +100,14 @@ export default function ProfileScreen() { const handleApplyGym = async () => { try { const token = await getToken(); - await fetch("/api/users/gym", { + const url = `${API_BASE_URL}${API_ENDPOINTS.USERS}/gym`; + console.log( + "Profile.handleApplyGym PATCH:", + url, + "gymId:", + selectedGymId, + ); + const res = await fetch(url, { method: "PATCH", headers: { "Content-Type": "application/json", @@ -71,6 +115,30 @@ export default function ProfileScreen() { }, body: JSON.stringify({ gymId: selectedGymId }), }); + const contentType = res.headers.get("content-type") || ""; + if (!res.ok) { + const text = await res.text().catch(() => ""); + console.error("Failed to update gym selection: non-OK response", { + status: res.status, + body: text?.slice(0, 200), + }); + Alert.alert("Error", "Failed to update gym selection"); + return; + } + if (contentType.includes("application/json")) { + try { + const data = await res.json(); + console.log("Gym selection updated:", data); + } catch (e) { + const text = await res.text().catch(() => ""); + console.error( + "Failed to parse update response JSON:", + e, + "body:", + text?.slice(0, 200), + ); + } + } Alert.alert( "Success", selectedGymId ? "Gym selected successfully" : "Proceeding without gym",