import { NextResponse } from "next/server"; import { auth } from "@clerk/nextjs/server"; import { eq, sql } from "@fitai/database"; import { db, users as usersTable, gyms as gymsTable } from "@fitai/database"; import { ensureUserSynced } from "@/lib/sync-user"; import { getDatabase } from "@/lib/database"; import log from "@/lib/logger"; async function ensureGymsTable() { await db.run(sql` CREATE TABLE IF NOT EXISTS gyms ( id TEXT PRIMARY KEY, name TEXT NOT NULL, location TEXT, status TEXT NOT NULL CHECK (status IN ('active','inactive')) DEFAULT 'active', admin_user_id TEXT NOT NULL, created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL ) `); } // GET /api/gyms // Lists active gyms for selection (grid) export async function GET() { try { const { userId } = await auth(); if (!userId) { return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); } const appDb = await getDatabase(); const currentUser = await ensureUserSynced(userId, appDb); if (!currentUser) { return NextResponse.json({ error: "Forbidden" }, { status: 403 }); } if (currentUser.role !== "admin" && currentUser.role !== "superAdmin") { return NextResponse.json({ error: "Forbidden" }, { status: 403 }); } await ensureGymsTable(); let rows = await db .select() .from(gymsTable) .where(eq(gymsTable.status, "active")) .orderBy(sql`created_at DESC`) .all(); if (currentUser.role !== "superAdmin") { if (!currentUser.gymId) { return NextResponse.json({ error: "No gym assigned" }, { status: 403 }); } rows = rows.filter((row) => row.id === currentUser.gymId); } return NextResponse.json(rows); } catch (error) { log.error("Failed to get gyms", error); return new NextResponse("Internal Server Error", { status: 500 }); } } // POST /api/gyms // Create a gym. Allowed roles: superAdmin, admin. // - admin: can only create gyms for themselves (adminUserId = current user) // - superAdmin: can create for self or specify adminUserId export async function POST(req: Request) { try { await ensureGymsTable(); const { userId } = await auth(); if (!userId) return new NextResponse("Unauthorized", { status: 401 }); const appDb = await getDatabase(); const currentUser = await ensureUserSynced(userId, appDb); if ( !currentUser || (currentUser.role !== "admin" && currentUser.role !== "superAdmin") ) { return new NextResponse("Forbidden", { status: 403 }); } const body = await req.json().catch(() => null); if (!body || typeof body !== "object") { return new NextResponse("Invalid JSON body", { status: 400 }); } const name = String(body.name ?? "").trim(); const location = body.location ? String(body.location).trim() : null; let adminUserId: string | null = body.adminUserId ? String(body.adminUserId) : null; if (!name) { return NextResponse.json({ error: "name is required" }, { status: 400 }); } // Enforce admin ownership rules if (currentUser.role === "admin") { adminUserId = currentUser.id; } else if (currentUser.role === "superAdmin") { adminUserId = adminUserId || currentUser.id; } // Basic check that adminUserId exists and is an admin or superAdmin const adminRow = await db .select() .from(usersTable) .where(eq(usersTable.id, adminUserId!)) .get(); if ( !adminRow || (adminRow.role !== "admin" && adminRow.role !== "superAdmin") ) { return NextResponse.json( { error: "adminUserId must reference an admin or superAdmin" }, { status: 400 }, ); } const id = generateId(); const nowTs = new Date(); // Use Drizzle's insert method instead of raw SQL await db.insert(gymsTable).values({ id, name, location: location ?? null, status: "active", adminUserId: adminUserId!, createdAt: nowTs, updatedAt: nowTs, }); // Assign the admin to this gym immediately after creation await db .update(usersTable) .set({ gymId: id, updatedAt: nowTs }) .where(eq(usersTable.id, adminUserId!)); const created = await db .select() .from(gymsTable) .where(eq(gymsTable.id, id)) .get(); return NextResponse.json(created, { status: 201 }); } catch (error) { log.error("Failed to create gym", error); return new NextResponse("Internal Server Error", { status: 500 }); } } function generateId(): string { // Simple URL-safe id generator return ( Math.random().toString(36).slice(2, 10) + Math.random().toString(36).slice(2, 10) ); }