265 lines
7.3 KiB
TypeScript
265 lines
7.3 KiB
TypeScript
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<typeof user> => !!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 },
|
|
);
|
|
}
|
|
}
|