import { NextRequest, NextResponse } from "next/server"; import { auth } from "@clerk/nextjs/server"; import { getDatabase } from "@/lib/database"; import { ensureUserSynced } from "@/lib/sync-user"; import log from "@/lib/logger"; /** * GET /api/trainer-client * Get trainer-client assignments * * Query params: * - trainerId: string (optional) - Filter by trainer * - clientId: string (optional) - Filter by client */ export async function GET(request: NextRequest) { try { const { userId: authUserId } = await auth(); if (!authUserId) { return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); } const db = await getDatabase(); const currentUser = await ensureUserSynced(authUserId, db); if (!currentUser) { return NextResponse.json({ error: "Forbidden" }, { status: 403 }); } // Only admins and superadmins can view all assignments if (currentUser.role !== "admin" && currentUser.role !== "superAdmin") { return NextResponse.json( { error: "Only admins can view trainer-client assignments" }, { status: 403 }, ); } const { searchParams } = new URL(request.url); const trainerId = searchParams.get("trainerId"); const clientId = searchParams.get("clientId"); if (trainerId && clientId) { const [trainer, client] = await Promise.all([ db.getUserById(trainerId), db.getUserById(clientId), ]); if (!trainer || !client) { return NextResponse.json({ error: "User not found" }, { status: 404 }); } if ( currentUser.role !== "superAdmin" && (!currentUser.gymId || trainer.gymId !== currentUser.gymId || client.gymId !== currentUser.gymId) ) { return NextResponse.json( { error: "Cannot access assignments from other gyms" }, { status: 403 }, ); } } if (trainerId && !clientId) { const trainer = await db.getUserById(trainerId); if (!trainer) { return NextResponse.json( { error: "Trainer not found" }, { status: 404 }, ); } if ( currentUser.role !== "superAdmin" && (!currentUser.gymId || trainer.gymId !== currentUser.gymId) ) { return NextResponse.json( { error: "Cannot access assignments from other gyms" }, { status: 403 }, ); } } if (!trainerId && clientId) { const client = await db.getUserById(clientId); if (!client) { return NextResponse.json( { error: "Client not found" }, { status: 404 }, ); } if ( currentUser.role !== "superAdmin" && (!currentUser.gymId || client.gymId !== currentUser.gymId) ) { return NextResponse.json( { error: "Cannot access assignments from other gyms" }, { status: 403 }, ); } } let assignments = trainerId ? await db.getTrainerClientAssignments(trainerId) : await db.getAllTrainerClientAssignments(); if (clientId) { assignments = assignments.filter((a) => a.clientId === clientId); } if (currentUser.role !== "superAdmin") { if (!currentUser.gymId) { return NextResponse.json({ error: "No gym assigned" }, { status: 403 }); } const involvedUserIds = Array.from( new Set( assignments.flatMap((assignment) => [ assignment.trainerId, assignment.clientId, ]), ), ); const users = await Promise.all( involvedUserIds.map((userId) => db.getUserById(userId)), ); const gymByUserId = new Map( users .filter((user): user is NonNullable => !!user) .map((user) => [user.id, user.gymId]), ); assignments = assignments.filter((assignment) => { const trainerGymId = gymByUserId.get(assignment.trainerId); const clientGymId = gymByUserId.get(assignment.clientId); return ( trainerGymId === currentUser.gymId && clientGymId === currentUser.gymId ); }); } return NextResponse.json({ assignments }); } catch (error) { log.error("Failed to get trainer-client assignments", error); return NextResponse.json( { error: "Internal server error" }, { status: 500 }, ); } } /** * POST /api/trainer-client * Create a new trainer-client assignment */ export async function POST(request: NextRequest) { try { const { userId: authUserId } = await auth(); if (!authUserId) { return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); } const db = await getDatabase(); const currentUser = await ensureUserSynced(authUserId, db); if (!currentUser) { return NextResponse.json({ error: "Forbidden" }, { status: 403 }); } // Only admins can create assignments if (currentUser.role !== "admin" && currentUser.role !== "superAdmin") { return NextResponse.json( { error: "Only admins can assign trainers to clients" }, { status: 403 }, ); } const body = await request.json(); const { trainerId, clientId } = body; if (!trainerId || !clientId) { return NextResponse.json( { error: "trainerId and clientId are required" }, { status: 400 }, ); } // Verify trainer exists and has trainer role const trainer = await db.getUserById(trainerId); if (!trainer) { return NextResponse.json({ error: "Trainer not found" }, { status: 404 }); } if (trainer.role !== "trainer" && trainer.role !== "admin") { return NextResponse.json( { error: "User must be a trainer or admin" }, { status: 400 }, ); } // Verify client exists const client = await db.getUserById(clientId); if (!client) { return NextResponse.json({ error: "Client not found" }, { status: 404 }); } if (client.role !== "client") { return NextResponse.json( { error: "User must be a client" }, { status: 400 }, ); } if ( currentUser.role !== "superAdmin" && (!currentUser.gymId || trainer.gymId !== currentUser.gymId || client.gymId !== currentUser.gymId) ) { return NextResponse.json( { error: "Cannot assign users from other gyms" }, { status: 403 }, ); } // Check if assignment already exists const existingAssignments = await db.getTrainerClientAssignments(trainerId); const existingAssignment = existingAssignments.find( (a) => a.clientId === clientId && a.isActive, ); if (existingAssignment) { return NextResponse.json( { error: "Trainer is already assigned to this client" }, { status: 409 }, ); } // Create the assignment const assignment = await db.createTrainerClientAssignment({ trainerId, clientId, assignedAt: new Date(), assignedBy: currentUser.id, isActive: true, }); log.info("Trainer-client assignment created", { trainerId, clientId, assignedBy: currentUser.id, }); return NextResponse.json({ assignment }, { status: 201 }); } catch (error) { log.error("Failed to create trainer-client assignment", error); return NextResponse.json( { error: "Internal server error" }, { status: 500 }, ); } }