import { requireAuth } from "@/lib/jwt"; import { sql, query } from "@/lib/db"; import { isServiceId, requireDriverProfile } from "@/lib/driver"; import { SERVICES, type ServiceId } from "@/constants/services"; // GET — the signed-in user's own driver profile, or 403 (code: ONBOARD) when // they haven't onboarded yet. The client uses the code to show the form. export async function GET(req: Request) { const result = await requireDriverProfile(req); if ("error" in result) return result.error; const { auth, driverId } = result; const rows = await sql` SELECT id, first_name, last_name, profile_image_url, car_image_url, car_seats, rating, service, online, car_model, user_id FROM drivers WHERE id = ${driverId} `; return Response.json({ data: rows[0], userId: auth.userId }); } // POST — onboarding. A driver-role user creates their one linked drivers row. // The user must carry role='driver' (set on sign-up / role.tsx) so a rider // can't silently become a driver by hitting this endpoint. export async function POST(req: Request) { const auth = requireAuth(req); if ("error" in auth) return auth.error; try { const body = await req.json(); const { car_model, car_seats, service, profile_image_url, car_image_url } = body; // The user must be flagged a driver to onboard a driver profile. const users = await sql<{ role: string | null; name: string | null }>` SELECT role, name FROM users WHERE id = ${auth.userId} `; if (!users[0] || users[0].role !== "driver") { return Response.json( { error: "Only driver accounts can onboard a driver profile." }, { status: 403 }, ); } if (!isServiceId(service)) { return Response.json( { error: `service must be one of: ${SERVICES.map((s) => s.id).join(", ")}.` }, { status: 400 }, ); } const seats = Number(car_seats); if (!Number.isInteger(seats) || seats < 1 || seats > 8) { return Response.json( { error: "car_seats must be a whole number between 1 and 8." }, { status: 400 }, ); } const [firstName, ...rest] = (users[0].name ?? "").split(" "); // One profile per driver user. The partial unique index on user_id // guarantees this at the DB level; surface a clean 409 on collision. try { const rows = await sql` INSERT INTO drivers ( user_id, first_name, last_name, profile_image_url, car_image_url, car_seats, rating, service, car_model, online ) VALUES ( ${auth.userId}, ${firstName || "Driver"}, ${rest.join(" ") || ""}, ${profile_image_url ?? null}, ${car_image_url ?? null}, ${seats}, 5.0, ${service as ServiceId}, ${car_model ?? null}, FALSE ) RETURNING id, service, online `; return Response.json({ data: rows[0] }, { status: 201 }); } catch (error) { if ((error as { code?: string }).code === "23505") { return Response.json( { error: "Driver profile already exists." }, { status: 409 }, ); } throw error; } } catch (error) { console.error("[DRIVER_PROFILE_POST]: ", error); return Response.json({ error: "Internal Server Error" }, { status: 500 }); } } // PATCH — update mutable profile fields, most importantly the online toggle. export async function PATCH(req: Request) { const result = await requireDriverProfile(req); if ("error" in result) return result.error; try { const body = await req.json(); const { online, car_model, car_seats, service } = body; const updates: string[] = []; const values: (string | number | boolean | null)[] = []; let idx = 1; const push = (col: string, value: string | number | boolean | null) => { updates.push(`${col} = $${idx++}`); values.push(value); }; if (typeof online === "boolean") push("online", online); if (typeof car_model === "string" || car_model === null) push("car_model", car_model); if (car_seats !== undefined) { const seats = Number(car_seats); if (!Number.isInteger(seats) || seats < 1 || seats > 8) { return Response.json( { error: "car_seats must be a whole number between 1 and 8." }, { status: 400 }, ); } push("car_seats", seats); } if (service !== undefined) { if (!isServiceId(service)) { return Response.json( { error: "Invalid service." }, { status: 400 }, ); } push("service", service as string); } if (updates.length === 0) { return Response.json({ error: "No fields to update." }, { status: 400 }); } values.push(result.driverId); const rows = await query( `UPDATE drivers SET ${updates.join(", ")} WHERE id = $${idx} RETURNING *`, values, ); return Response.json({ data: rows[0] }); } catch (error) { console.error("[DRIVER_PROFILE_PATCH]: ", error); return Response.json({ error: "Internal Server Error" }, { status: 500 }); } }