import { requireAuth } from "@/lib/jwt"; import { requireDriverProfile } from "@/lib/driver"; import { sql } from "@/lib/db"; import { CONNECTED_STATUS_ARRAY } from "@/lib/ride-lifecycle"; // GET — the Chat tab's default view. Returns the caller's currently-active // ride that has the other party assigned (so a conversation can open), or // null when there's nothing to chat about. The caller is auto-detected: a // rider by default, or a driver when ?role=driver is passed (the driver app // hits this with role=driver since the same account could in principle be a // rider elsewhere). // // We try the rider path first. If the signed-in user owns an active ride // with a driver assigned, that's their conversation. Otherwise, if they have // a driver profile, we look for a ride they're assigned to. Either way the // response carries the caller's `role` and a `peer` summary for the header. type ActiveRideRow = { ride_id: number; status: string; role: "rider" | "driver"; peer_name: string; peer_avatar: string | null; peer_service: string | null; peer_car_model: string | null; }; // The client (chat.tsx, call.tsx) expects `peer` nested per the ChatActiveRide // type, not the flat peer_* columns the query returns. const toActiveRide = (row: ActiveRideRow) => ({ ride_id: row.ride_id, status: row.status, role: row.role, peer: { name: row.peer_name, avatar: row.peer_avatar, service: row.peer_service, car_model: row.peer_car_model, }, }); export async function GET(req: Request) { const auth = requireAuth(req); if ("error" in auth) return auth.error; const wantsDriver = new URL(req.url).searchParams.get("role") === "driver"; try { // Rider path: a ride this user owns that's active and has a driver. if (!wantsDriver) { const riderRides = await sql` SELECT r.ride_id, r.status, 'rider' AS role, CONCAT_WS(' ', d.first_name, d.last_name) AS peer_name, d.profile_image_url AS peer_avatar, d.service AS peer_service, d.car_model AS peer_car_model FROM rides r JOIN drivers d ON d.id = r.driver_id WHERE r.user_id = ${auth.userId} AND r.status = ANY(${CONNECTED_STATUS_ARRAY}::text[]) AND r.driver_id IS NOT NULL ORDER BY r.created_at DESC LIMIT 1 `; if (riderRides[0]) return Response.json({ data: toActiveRide(riderRides[0]) }); } // Driver path: a ride this user (as a driver) is assigned to and is active. const driver = await requireDriverProfile(req); if (!("error" in driver)) { const driverRides = await sql` SELECT r.ride_id, r.status, 'driver' AS role, u.name AS peer_name, NULL::text AS peer_avatar, r.service AS peer_service, NULL::text AS peer_car_model FROM rides r JOIN users u ON u.id = r.user_id WHERE r.driver_id = ${driver.driverId} AND r.status = ANY(${CONNECTED_STATUS_ARRAY}::text[]) ORDER BY r.created_at DESC LIMIT 1 `; if (driverRides[0]) return Response.json({ data: toActiveRide(driverRides[0]) }); } return Response.json({ data: null }); } catch (error) { console.error("[GET_ACTIVE_CHAT]: ", error); return Response.json({ error: "Internal Server Error." }, { status: 500 }); } }