149 lines
4.5 KiB
TypeScript
149 lines
4.5 KiB
TypeScript
import { NextRequest, NextResponse } from "next/server";
|
|
import { getDatabase } from "../../../../lib/database/index";
|
|
import { auth } from "@clerk/nextjs/server";
|
|
import log from "@/lib/logger";
|
|
import { fitnessProfileSchema } from "@/lib/validation/schemas";
|
|
import {
|
|
validateRequestBody,
|
|
validationErrorResponse,
|
|
} from "@/lib/validation/helpers";
|
|
import { getFitnessProfilesByGym } from "@/lib/gym-context";
|
|
import { ensureUserSynced } from "@/lib/sync-user";
|
|
|
|
export async function POST(request: NextRequest) {
|
|
try {
|
|
const db = await getDatabase();
|
|
|
|
// Validate request body
|
|
const validation = await validateRequestBody(request, fitnessProfileSchema);
|
|
|
|
if (!validation.success) {
|
|
log.warn("Fitness profile validation failed", {
|
|
errors: validation.errors,
|
|
});
|
|
return validationErrorResponse(validation.errors);
|
|
}
|
|
|
|
const profileData = validation.data;
|
|
|
|
// Check if user exists
|
|
const user = await db.getUserById(profileData.userId);
|
|
if (!user) {
|
|
return NextResponse.json({ error: "User not found" }, { status: 404 });
|
|
}
|
|
|
|
// Check if profile already exists
|
|
const existingProfile = await db.getFitnessProfileByUserId(
|
|
profileData.userId,
|
|
);
|
|
|
|
let profile;
|
|
if (existingProfile) {
|
|
// Update - omit userId from update data
|
|
const { userId, ...updateData } = profileData;
|
|
profile = await db.updateFitnessProfile(userId, updateData as any);
|
|
} else {
|
|
// Create - omit userId since the function signature expects it separately
|
|
const { userId, ...createData } = profileData;
|
|
profile = await db.createFitnessProfile({ userId, ...createData } as any);
|
|
}
|
|
|
|
return NextResponse.json(
|
|
{
|
|
message: "Fitness profile saved successfully",
|
|
profile,
|
|
},
|
|
{ status: 201 },
|
|
);
|
|
} catch (error) {
|
|
log.error("Failed to save fitness profile", error);
|
|
return NextResponse.json(
|
|
{ error: "Internal server error" },
|
|
{ status: 500 },
|
|
);
|
|
}
|
|
}
|
|
|
|
export async function GET(request: NextRequest) {
|
|
try {
|
|
// First authenticate
|
|
const { userId: clerkUserId } = await auth();
|
|
if (!clerkUserId) {
|
|
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
|
}
|
|
|
|
const db = await getDatabase();
|
|
const currentUser = await ensureUserSynced(clerkUserId, db);
|
|
|
|
if (!currentUser) {
|
|
return NextResponse.json({ error: "Forbidden" }, { status: 403 });
|
|
}
|
|
|
|
const { searchParams } = new URL(request.url);
|
|
const targetUserId = searchParams.get("userId");
|
|
|
|
// If accessing another user's profile, verify gym access
|
|
if (targetUserId && targetUserId !== clerkUserId) {
|
|
const isStaff =
|
|
currentUser.role === "admin" ||
|
|
currentUser.role === "superAdmin" ||
|
|
currentUser.role === "trainer";
|
|
|
|
if (!isStaff) {
|
|
return NextResponse.json({ error: "Forbidden" }, { status: 403 });
|
|
}
|
|
|
|
// Staff need to verify target user is in same gym
|
|
if (currentUser.role !== "superAdmin") {
|
|
const targetUser = await db.getUserById(targetUserId);
|
|
if (!targetUser || targetUser.gymId !== currentUser.gymId) {
|
|
return NextResponse.json(
|
|
{ error: "Forbidden - Cannot access users from other gyms" },
|
|
{ status: 403 },
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (targetUserId) {
|
|
const profile = await db.getFitnessProfileByUserId(targetUserId);
|
|
if (!profile) {
|
|
return NextResponse.json(
|
|
{ error: "Profile not found" },
|
|
{ status: 404 },
|
|
);
|
|
}
|
|
return NextResponse.json({ profile });
|
|
}
|
|
|
|
// Staff get gym-scoped profiles
|
|
const isStaff =
|
|
currentUser.role === "admin" ||
|
|
currentUser.role === "superAdmin" ||
|
|
currentUser.role === "trainer";
|
|
|
|
if (isStaff) {
|
|
const targetGymId =
|
|
currentUser.role === "superAdmin"
|
|
? (searchParams.get("gymId") ?? undefined)
|
|
: (currentUser.gymId ?? undefined);
|
|
|
|
const profiles = targetGymId
|
|
? await getFitnessProfilesByGym(targetGymId)
|
|
: await db.getAllFitnessProfiles();
|
|
|
|
return NextResponse.json({ profiles });
|
|
}
|
|
|
|
// Regular users only get their own
|
|
const profile = await db.getFitnessProfileByUserId(clerkUserId);
|
|
return NextResponse.json({ profile: profile ? [profile] : [] });
|
|
} catch (error) {
|
|
log.error("Failed to get fitness profiles", error);
|
|
return NextResponse.json(
|
|
{ error: "Internal server error" },
|
|
{ status: 500 },
|
|
);
|
|
}
|
|
}
|