import { NextRequest, NextResponse } from 'next/server'; import { db } from '@/lib/db'; import { bookings, courts } from '@/lib/db/schema'; import { eq, and } from 'drizzle-orm'; import { getSession } from '@/lib/session'; import { logActivity, ACTIONS, ENTITY_TYPES } from '@/lib/activity-logger'; export async function GET(request: NextRequest) { try { const session = await getSession(); if (!session) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); } const userBookings = await db .select({ id: bookings.id, courtId: bookings.courtId, date: bookings.date, startTime: bookings.startTime, endTime: bookings.endTime, status: bookings.status, notes: bookings.notes, createdAt: bookings.createdAt, court: { id: courts.id, name: courts.name, }, }) .from(bookings) .innerJoin(courts, eq(bookings.courtId, courts.id)) .where(eq(bookings.userId, session.userId)); return NextResponse.json({ bookings: userBookings }); } catch (error) { console.error('Error fetching bookings:', error); return NextResponse.json({ error: 'Internal server error' }, { status: 500 }); } } export async function POST(request: NextRequest) { try { const session = await getSession(); if (!session) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); } const { courtId, date, timeSlot } = await request.json(); if (!courtId || !date || !timeSlot) { return NextResponse.json( { error: 'Missing required fields: courtId, date, timeSlot', }, { status: 400 } ); } // Parse timeSlot (e.g., "14:00") to get start and end times const startTime = timeSlot; const [hours, minutes] = timeSlot.split(':').map(Number); const endTime = `${String(hours + 1).padStart(2, '0')}:${String(minutes).padStart(2, '0')}`; // Validate booking date is not in the past const bookingDate = new Date(date); const today = new Date(); today.setHours(0, 0, 0, 0); if (bookingDate < today) { return NextResponse.json( { error: 'Cannot book dates in the past', }, { status: 400 } ); } // Check if court exists and is active const court = await db.select().from(courts).where(eq(courts.id, courtId)).limit(1); if (court.length === 0 || !court[0].isActive) { return NextResponse.json( { error: 'Court not found or inactive', }, { status: 400 } ); } // Check if slot is already booked const existingBooking = await db .select() .from(bookings) .where( and( eq(bookings.courtId, courtId), eq(bookings.date, date), eq(bookings.startTime, startTime), eq(bookings.status, 'active') ) ) .limit(1); if (existingBooking.length > 0) { return NextResponse.json( { error: 'Time slot already booked', }, { status: 400 } ); } // Create the booking const [newBooking] = await db .insert(bookings) .values({ id: crypto.randomUUID(), userId: session.userId, courtId, date, startTime, endTime, status: 'active', createdAt: new Date(), updatedAt: new Date(), }) .returning(); // Log the activity await logActivity({ userId: session.userId, action: ACTIONS.BOOKING_CREATE, entityType: ENTITY_TYPES.BOOKING, entityId: newBooking.id, details: { courtId, courtName: court[0].name, date, startTime, endTime, }, request, }); return NextResponse.json({ booking: newBooking, message: 'Booking created successfully', }); } catch (error) { console.error('Error creating booking:', error); return NextResponse.json({ error: 'Internal server error' }, { status: 500 }); } }