import { NextRequest, NextResponse } from 'next/server'; import { db } from '@/lib/db'; import { courtBlocks, courts, users, announcements } from '@/lib/db/schema'; import { eq, gte, asc } 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 || session.role !== 'admin') { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); } const { searchParams } = new URL(request.url); const includeExpired = searchParams.get('includeExpired') === 'true'; // Get today's date const today = new Date().toISOString().split('T')[0]; // Fetch blocks with court and creator info let query = db .select({ id: courtBlocks.id, courtId: courtBlocks.courtId, date: courtBlocks.date, startTime: courtBlocks.startTime, endTime: courtBlocks.endTime, reason: courtBlocks.reason, createdBy: courtBlocks.createdBy, createdAt: courtBlocks.createdAt, court: { id: courts.id, name: courts.name, }, creator: { id: users.id, name: users.name, surname: users.surname, }, }) .from(courtBlocks) .leftJoin(courts, eq(courtBlocks.courtId, courts.id)) .innerJoin(users, eq(courtBlocks.createdBy, users.id)); const rawBlocks = includeExpired ? await query.orderBy(asc(courtBlocks.date), asc(courtBlocks.startTime)) : await query .where(gte(courtBlocks.date, today)) .orderBy(asc(courtBlocks.date), asc(courtBlocks.startTime)); // Transform to flat structure for frontend const blocks = rawBlocks.map((block) => ({ id: block.id, courtId: block.courtId, courtName: block.court?.name || null, date: block.date, startTime: block.startTime, endTime: block.endTime, reason: block.reason, createdBy: block.createdBy, creatorName: block.creator ? `${block.creator.name} ${block.creator.surname}` : 'Unknown', createdAt: block.createdAt, })); return NextResponse.json({ blocks }); } catch (error) { console.error('Error fetching blocks:', error); return NextResponse.json({ error: 'Internal server error' }, { status: 500 }); } } export async function POST(request: NextRequest) { try { const session = await getSession(); if (!session || session.role !== 'admin') { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); } const { courtId, date, startTime, endTime, reason, createAnnouncement } = await request.json(); if (!date || !startTime || !endTime || !reason) { return NextResponse.json( { error: 'Missing required fields: date, startTime, endTime, reason' }, { status: 400 } ); } // Validate date is not in the past const blockDate = new Date(date); const today = new Date(); today.setHours(0, 0, 0, 0); if (blockDate < today) { return NextResponse.json({ error: 'Cannot create blocks for past dates' }, { status: 400 }); } // Get court name if courtId is provided let courtName = 'All Courts'; if (courtId) { const court = await db.select().from(courts).where(eq(courts.id, courtId)).limit(1); if (court.length === 0) { return NextResponse.json({ error: 'Court not found' }, { status: 400 }); } courtName = court[0].name; } // Create the block const blockId = crypto.randomUUID(); const [newBlock] = await db .insert(courtBlocks) .values({ id: blockId, courtId: courtId || null, // null means all courts date, startTime, endTime, reason, createdBy: session.userId, createdAt: new Date(), }) .returning(); // Log activity await logActivity({ userId: session.userId, action: ACTIONS.BLOCK_CREATE, entityType: ENTITY_TYPES.COURT_BLOCK, entityId: blockId, details: { courtId: courtId || 'all', date, startTime, endTime, reason, }, }); // Optionally create an announcement that expires when the block ends let announcementCreated = false; if (createAnnouncement) { const formattedDate = new Date(date).toLocaleDateString('en-IE', { weekday: 'long', day: 'numeric', month: 'long', year: 'numeric', }); // Set expiry to end of block day at the end time const expiryDate = new Date(date); const [endHour] = endTime.split(':').map(Number); expiryDate.setHours(endHour, 0, 0, 0); await db.insert(announcements).values({ id: crypto.randomUUID(), title: `${reason} - ${formattedDate}`, content: `${courtName} will be unavailable on ${formattedDate} from ${startTime} to ${endTime} due to: ${reason}`, priority: 'high', expiresAt: expiryDate, isActive: true, createdAt: new Date(), updatedAt: new Date(), }); announcementCreated = true; } return NextResponse.json({ block: newBlock, announcementCreated, message: 'Block created successfully', }); } catch (error) { console.error('Error creating block:', error); return NextResponse.json({ error: 'Internal server error' }, { status: 500 }); } }