diff --git a/apps/admin/data/fitai.db b/apps/admin/data/fitai.db index 4bb1adc..d3b15b8 100644 Binary files a/apps/admin/data/fitai.db and b/apps/admin/data/fitai.db differ diff --git a/apps/admin/package-lock.json b/apps/admin/package-lock.json index c0bfc6f..66171e3 100644 --- a/apps/admin/package-lock.json +++ b/apps/admin/package-lock.json @@ -22,6 +22,7 @@ "autoprefixer": "^10.4.16", "axios": "^1.13.2", "bcryptjs": "^3.0.3", + "better-sqlite3": "^11.10.0", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "date-fns": "^4.1.0", @@ -112,6 +113,7 @@ "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", @@ -2396,7 +2398,6 @@ "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", @@ -2417,7 +2418,6 @@ "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", "dev": true, "license": "Apache-2.0", - "peer": true, "dependencies": { "dequal": "^2.0.3" } @@ -2427,8 +2427,7 @@ "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@testing-library/jest-dom": { "version": "6.9.1", @@ -2504,8 +2503,7 @@ "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@types/babel__core": { "version": "7.20.5", @@ -2689,6 +2687,7 @@ "integrity": "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==", "devOptional": true, "license": "MIT", + "peer": true, "dependencies": { "csstype": "^3.0.2" } @@ -2699,6 +2698,7 @@ "integrity": "sha512-9KQPoO6mZCi7jcIStSnlOWn2nEF3mNmyr3rIAsGnAbQKYbRLyqmeSc39EVgtxXVia+LMT8j3knZLAZAh+xLmrw==", "dev": true, "license": "MIT", + "peer": true, "peerDependencies": { "@types/react": "^19.2.0" } @@ -2789,6 +2789,7 @@ "integrity": "sha512-6m1I5RmHBGTnUGS113G04DMu3CpSdxCAU/UvtjNWL4Nuf3MW9tQhiJqRlHzChIkhy6kZSAQmc+I1bcGjE3yNKg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.46.3", "@typescript-eslint/types": "8.46.3", @@ -3333,6 +3334,7 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -3988,6 +3990,17 @@ "bcrypt": "bin/bcrypt" } }, + "node_modules/better-sqlite3": { + "version": "11.10.0", + "resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-11.10.0.tgz", + "integrity": "sha512-EwhOpyXiOEL/lKzHz9AW1msWFNzGc/z+LzeB3/jnFJpxu+th2yqvzsSWas1v9jgs9+xiXJcD5A8CJxAG2TaghQ==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "bindings": "^1.5.0", + "prebuild-install": "^7.1.1" + } + }, "node_modules/binary-extensions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", @@ -4062,6 +4075,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.8.19", "caniuse-lite": "^1.0.30001751", @@ -5296,6 +5310,7 @@ "integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -5481,6 +5496,7 @@ "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.9", @@ -8324,18 +8340,6 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/jiti": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", - "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "bin": { - "jiti": "lib/jiti-cli.mjs" - } - }, "node_modules/js-cookie": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz", @@ -8563,7 +8567,6 @@ "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", "dev": true, "license": "MIT", - "peer": true, "bin": { "lz-string": "bin/bin.js" } @@ -9076,6 +9079,7 @@ "resolved": "https://registry.npmjs.org/next/-/next-16.0.1.tgz", "integrity": "sha512-e9RLSssZwd35p7/vOa+hoDFggUZIUbZhIUSLZuETCwrCVvxOs87NamoUzT+vbcNAL8Ld9GobBnWOA6SbV/arOw==", "license": "MIT", + "peer": true, "dependencies": { "@next/env": "16.0.1", "@swc/helpers": "0.5.15", @@ -9744,6 +9748,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", @@ -9881,7 +9886,6 @@ "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", @@ -9897,7 +9901,6 @@ "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=10" }, @@ -9910,8 +9913,7 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/promise-inflight": { "version": "1.0.1", @@ -10043,6 +10045,7 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz", "integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==", "license": "MIT", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -10052,6 +10055,7 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz", "integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==", "license": "MIT", + "peer": true, "dependencies": { "scheduler": "^0.27.0" }, @@ -10064,6 +10068,7 @@ "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.66.0.tgz", "integrity": "sha512-xXBqsWGKrY46ZqaHDo+ZUYiMUgi8suYu5kdrS20EG8KiL7VRQitEbNjm+UcrDYrNi1YLyfpmAeGjCZYXLT9YBw==", "license": "MIT", + "peer": true, "engines": { "node": ">=18.0.0" }, @@ -10087,6 +10092,7 @@ "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz", "integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==", "license": "MIT", + "peer": true, "dependencies": { "@types/use-sync-external-store": "^0.0.6", "use-sync-external-store": "^1.4.0" @@ -10185,7 +10191,8 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/redux-thunk": { "version": "3.1.0", @@ -11638,6 +11645,7 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -11857,6 +11865,7 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -12443,6 +12452,7 @@ "resolved": "https://registry.npmjs.org/zod/-/zod-4.1.12.tgz", "integrity": "sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ==", "license": "MIT", + "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/apps/admin/package.json b/apps/admin/package.json index 54cff00..d2a096a 100644 --- a/apps/admin/package.json +++ b/apps/admin/package.json @@ -25,6 +25,7 @@ "autoprefixer": "^10.4.16", "axios": "^1.13.2", "bcryptjs": "^3.0.3", + "better-sqlite3": "^11.10.0", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "date-fns": "^4.1.0", diff --git a/apps/admin/scripts/migrate-fitness-profile.js b/apps/admin/scripts/migrate-fitness-profile.js new file mode 100644 index 0000000..434d292 --- /dev/null +++ b/apps/admin/scripts/migrate-fitness-profile.js @@ -0,0 +1,33 @@ +const Database = require('better-sqlite3'); +const path = require('path'); + +const dbPath = path.join(__dirname, '../../../data/fitai.db'); +const db = new Database(dbPath); + +console.log('Migrating fitness_profiles table...'); + +try { + // Check if columns exist + const tableInfo = db.prepare('PRAGMA table_info(fitness_profiles)').all(); + const columns = tableInfo.map(c => c.name); + + if (!columns.includes('allergies')) { + console.log('Adding allergies column...'); + db.prepare('ALTER TABLE fitness_profiles ADD COLUMN allergies TEXT').run(); + } else { + console.log('allergies column already exists.'); + } + + if (!columns.includes('injuries')) { + console.log('Adding injuries column...'); + db.prepare('ALTER TABLE fitness_profiles ADD COLUMN injuries TEXT').run(); + } else { + console.log('injuries column already exists.'); + } + + console.log('Migration completed successfully.'); +} catch (error) { + console.error('Migration failed:', error); +} finally { + db.close(); +} diff --git a/apps/admin/src/app/api/fitness-profile/route.ts b/apps/admin/src/app/api/fitness-profile/route.ts index 7b53af3..b5991e3 100644 --- a/apps/admin/src/app/api/fitness-profile/route.ts +++ b/apps/admin/src/app/api/fitness-profile/route.ts @@ -16,10 +16,20 @@ export async function GET(request: NextRequest) { const profile = db .prepare( - `SELECT * FROM fitness_profiles WHERE user_id = ?` + `SELECT * FROM fitness_profiles WHERE userId = ?` ) .get(userId); + if (profile) { + const p = profile as any; + // Parse JSON fields + try { + p.fitnessGoals = JSON.parse(p.fitnessGoals || '[]'); + } catch (e) { + p.fitnessGoals = []; + } + } + return NextResponse.json({ profile: profile || null }); } catch (error) { console.error("Error fetching fitness profile:", error); @@ -45,19 +55,22 @@ export async function POST(request: NextRequest) { weight, age, gender, - fitnessGoal, + fitnessGoals, // Changed from fitnessGoal activityLevel, medicalConditions, allergies, injuries, + exerciseHabits, + dietHabits } = body; // Check if profile exists const existingProfile = db - .prepare(`SELECT id FROM fitness_profiles WHERE user_id = ?`) - .get(userId) as { id: string } | undefined; + .prepare(`SELECT userId FROM fitness_profiles WHERE userId = ?`) + .get(userId) as { userId: string } | undefined; - const now = Date.now(); + const now = new Date().toISOString(); + const fitnessGoalsJson = JSON.stringify(fitnessGoals || []); if (existingProfile) { // Update existing profile @@ -67,52 +80,55 @@ export async function POST(request: NextRequest) { weight = ?, age = ?, gender = ?, - fitness_goal = ?, - activity_level = ?, - medical_conditions = ?, + fitnessGoals = ?, + activityLevel = ?, + medicalConditions = ?, allergies = ?, injuries = ?, - updated_at = ? - WHERE user_id = ?` + exerciseHabits = ?, + dietHabits = ?, + updatedAt = ? + WHERE userId = ?` ).run( height || null, weight || null, age || null, gender || null, - fitnessGoal || null, + fitnessGoalsJson, activityLevel || null, medicalConditions || null, allergies || null, injuries || null, + exerciseHabits || null, + dietHabits || null, now, userId ); return NextResponse.json({ message: "Fitness profile updated successfully", - profileId: existingProfile.id, + userId: userId, }); } else { // Create new profile - const profileId = `fp_${randomBytes(16).toString("hex")}`; - db.prepare( `INSERT INTO fitness_profiles - (id, user_id, height, weight, age, gender, fitness_goal, activity_level, - medical_conditions, allergies, injuries, created_at, updated_at) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` + (userId, height, weight, age, gender, fitnessGoals, activityLevel, + medicalConditions, allergies, injuries, exerciseHabits, dietHabits, createdAt, updatedAt) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` ).run( - profileId, userId, height || null, weight || null, age || null, gender || null, - fitnessGoal || null, + fitnessGoalsJson, activityLevel || null, medicalConditions || null, allergies || null, injuries || null, + exerciseHabits || null, + dietHabits || null, now, now ); @@ -120,7 +136,7 @@ export async function POST(request: NextRequest) { return NextResponse.json( { message: "Fitness profile created successfully", - profileId, + userId, }, { status: 201 } ); diff --git a/apps/admin/src/app/api/users/route.ts b/apps/admin/src/app/api/users/route.ts index aa56c85..c92c772 100644 --- a/apps/admin/src/app/api/users/route.ts +++ b/apps/admin/src/app/api/users/route.ts @@ -1,7 +1,7 @@ import { NextRequest, NextResponse } from "next/server"; import { getDatabase } from "../../../lib/database/index"; import bcrypt from "bcryptjs"; -import { auth } from "@clerk/nextjs/server"; +import { auth, clerkClient } from "@clerk/nextjs/server"; export async function GET(request: NextRequest) { try { @@ -64,9 +64,9 @@ export async function POST(request: NextRequest) { } const body = await request.json(); - const { email, password, firstName, lastName, role, phone } = body; + const { email, firstName, lastName, role, phone } = body; - if (!email || !password || !firstName || !lastName || !role) { + if (!email || !firstName || !lastName || !role) { return NextResponse.json( { error: "Missing required fields" }, { status: 400 }, @@ -75,7 +75,7 @@ export async function POST(request: NextRequest) { // Enforce Hierarchy const allowed = { - superAdmin: ["admin", "trainer", "client"], // Super Admin can create anyone (except maybe another superAdmin via this UI?) + superAdmin: ["admin", "trainer", "client"], admin: ["trainer", "client"], trainer: ["client"], client: [] @@ -89,7 +89,7 @@ export async function POST(request: NextRequest) { ); } - // Check if user already exists + // Check if user already exists locally const existingUser = await db.getUserByEmail(email); if (existingUser) { return NextResponse.json( @@ -98,13 +98,38 @@ export async function POST(request: NextRequest) { ); } - // Hash password - const hashedPassword = await bcrypt.hash(password, 12); + // Create Clerk Invitation + // Note: We pass the role in publicMetadata so it persists when they sign up + try { + const client = await clerkClient(); + await client.invitations.createInvitation({ + emailAddress: email, + publicMetadata: { + role, + }, + ignoreExisting: true // Don't fail if invite exists + }); + } catch (clerkError: any) { + console.error("Clerk invitation error:", clerkError); + // If user already exists in Clerk, we might want to handle it. + // But for now, let's proceed to create local record if invite sent or if they exist. + if (clerkError.errors?.[0]?.code === 'form_identifier_exists') { + return NextResponse.json( + { error: "User already exists in Clerk system" }, + { status: 409 }, + ); + } + return NextResponse.json( + { error: "Failed to send invitation: " + (clerkError.message || "Unknown error") }, + { status: 500 }, + ); + } - // Create user + // Create user in local DB with temporary ID (will be migrated on first login) + // We set a placeholder password since it's required by schema but won't be used const newUserId = await db.createUser({ email, - password: hashedPassword, + password: "INVITED_USER_PENDING", firstName, lastName, role, @@ -121,7 +146,7 @@ export async function POST(request: NextRequest) { }); } - return NextResponse.json({ userId: newUserId.id }, { status: 201 }); + return NextResponse.json({ userId: newUserId.id, message: "Invitation sent" }, { status: 201 }); } catch (error) { console.error("Create user error:", error); return NextResponse.json( diff --git a/apps/admin/src/components/users/UserManagement.tsx b/apps/admin/src/components/users/UserManagement.tsx index 7aa62b4..f4fd447 100644 --- a/apps/admin/src/components/users/UserManagement.tsx +++ b/apps/admin/src/components/users/UserManagement.tsx @@ -139,23 +139,44 @@ export function UserManagement() { }; const handleSaveEdit = async () => { - if (!editForm || !selectedUser) return; + if (!editForm) return; try { - const response = await fetch("/api/users", { - method: "PUT", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ id: selectedUser.id, ...editForm }), - }); - if (response.ok) { - setIsEditing(false); - setEditForm(null); - fetchUsers(); + if (selectedUser) { + // Update existing user + const response = await fetch("/api/users", { + method: "PUT", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ id: selectedUser.id, ...editForm }), + }); + if (response.ok) { + setIsEditing(false); + setEditForm(null); + fetchUsers(); + } else { + alert("Error updating user"); + } } else { - alert("Error updating user"); + // Create (Invite) new user + const response = await fetch("/api/users", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(editForm), + }); + + if (response.ok) { + setIsEditing(false); + setEditForm(null); + fetchUsers(); + alert("Invitation sent successfully!"); + } else { + const errorData = await response.json(); + alert(`Error sending invitation: ${errorData.error}`); + } } } catch (error) { console.error(error); + alert("An unexpected error occurred"); } }; @@ -196,6 +217,22 @@ export function UserManagement() { > Edit User + diff --git a/apps/admin/src/lib/database/sqlite.ts b/apps/admin/src/lib/database/sqlite.ts index ca64116..f7ed088 100644 --- a/apps/admin/src/lib/database/sqlite.ts +++ b/apps/admin/src/lib/database/sqlite.ts @@ -91,6 +91,8 @@ export class SQLiteDatabase implements IDatabase { exerciseHabits TEXT, dietHabits TEXT, medicalConditions TEXT, + allergies TEXT, + injuries TEXT, createdAt DATETIME NOT NULL, updatedAt DATETIME NOT NULL, FOREIGN KEY (userId) REFERENCES users (id) ON DELETE CASCADE @@ -198,6 +200,7 @@ export class SQLiteDatabase implements IDatabase { async deleteUser(id: string): Promise { if (!this.db) throw new Error('Database not connected') + const stmt = this.db.prepare('DELETE FROM users WHERE id = ?') const result = stmt.run(id) return (result.changes || 0) > 0 } @@ -298,15 +301,15 @@ export class SQLiteDatabase implements IDatabase { const stmt = this.db.prepare( `INSERT INTO fitness_profiles (userId, height, weight, age, gender, activityLevel, fitnessGoals, - exerciseHabits, dietHabits, medicalConditions, createdAt, updatedAt) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` + exerciseHabits, dietHabits, medicalConditions, allergies, injuries, createdAt, updatedAt) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` ) stmt.run( profile.userId, profile.height, profile.weight, profile.age, profile.gender, profile.activityLevel, JSON.stringify(profile.fitnessGoals), profile.exerciseHabits, - profile.dietHabits, profile.medicalConditions, profile.createdAt.toISOString(), - profile.updatedAt.toISOString() + profile.dietHabits, profile.medicalConditions, profile.allergies, profile.injuries, + profile.createdAt.toISOString(), profile.updatedAt.toISOString() ) return profile @@ -468,6 +471,8 @@ export class SQLiteDatabase implements IDatabase { exerciseHabits: row.exerciseHabits, dietHabits: row.dietHabits, medicalConditions: row.medicalConditions, + allergies: row.allergies, + injuries: row.injuries, createdAt: new Date(row.createdAt), updatedAt: new Date(row.updatedAt) } diff --git a/apps/admin/src/lib/database/types.ts b/apps/admin/src/lib/database/types.ts index d97db62..4c66185 100644 --- a/apps/admin/src/lib/database/types.ts +++ b/apps/admin/src/lib/database/types.ts @@ -31,6 +31,8 @@ export interface FitnessProfile { exerciseHabits: string; dietHabits: string; medicalConditions: string; + allergies?: string; + injuries?: string; createdAt: Date; updatedAt: Date; } diff --git a/apps/mobile/src/config/api.ts b/apps/mobile/src/config/api.ts index 0ecc78c..646a78f 100644 --- a/apps/mobile/src/config/api.ts +++ b/apps/mobile/src/config/api.ts @@ -1,5 +1,5 @@ export const API_BASE_URL = __DEV__ - ? 'https://5cb23f31d8c1.ngrok-free.app' + ? 'https://390dfd6ece05.ngrok-free.app' : 'https://your-production-url.com' export const API_ENDPOINTS = {