Files
mikicvi 40c56770a2 feat: implement admin blocks management feature
- Added AdminBlocksManagement component for managing court blocks.
- Implemented functionality to create, edit, and delete blocks.
- Integrated fetching of courts and blocks from the API.
- Added validation for block creation and editing forms.
- Enhanced UI with responsive design for mobile and desktop views.
- Created database migration for court_blocks table and updated users table with theme_preference.
2025-12-29 17:04:16 +00:00

129 lines
3.5 KiB
TypeScript

import { NextRequest, NextResponse } from 'next/server';
import { db } from '@/lib/db';
import { courtBlocks, courts } from '@/lib/db/schema';
import { eq } from 'drizzle-orm';
import { getSession } from '@/lib/session';
import { logActivity, ACTIONS, ENTITY_TYPES } from '@/lib/activity-logger';
export async function PUT(request: NextRequest, context: { params: Promise<{ id: string }> }) {
try {
const session = await getSession();
if (!session || session.role !== 'admin') {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
const { id } = await context.params;
const { courtId, date, startTime, endTime, reason } = await request.json();
if (!date || !startTime || !endTime || !reason) {
return NextResponse.json(
{ error: 'Missing required fields: date, startTime, endTime, reason' },
{ status: 400 }
);
}
// Check if block exists
const existingBlock = await db.select().from(courtBlocks).where(eq(courtBlocks.id, id)).limit(1);
if (existingBlock.length === 0) {
return NextResponse.json({ error: 'Block not found' }, { status: 404 });
}
// 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 set blocks for past dates' }, { status: 400 });
}
// If courtId is provided, verify it exists
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 });
}
}
// Update the block
const [updatedBlock] = await db
.update(courtBlocks)
.set({
courtId: courtId || null,
date,
startTime,
endTime,
reason,
})
.where(eq(courtBlocks.id, id))
.returning();
// Log activity
await logActivity({
userId: session.userId,
action: ACTIONS.BLOCK_UPDATE,
entityType: ENTITY_TYPES.COURT_BLOCK,
entityId: id,
details: {
courtId: courtId || 'all',
date,
startTime,
endTime,
reason,
},
});
return NextResponse.json({
block: updatedBlock,
message: 'Block updated successfully',
});
} catch (error) {
console.error('Error updating block:', error);
return NextResponse.json({ error: 'Internal server error' }, { status: 500 });
}
}
export async function DELETE(request: NextRequest, context: { params: Promise<{ id: string }> }) {
try {
const session = await getSession();
if (!session || session.role !== 'admin') {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
const { id } = await context.params;
// Check if block exists
const existingBlock = await db.select().from(courtBlocks).where(eq(courtBlocks.id, id)).limit(1);
if (existingBlock.length === 0) {
return NextResponse.json({ error: 'Block not found' }, { status: 404 });
}
const block = existingBlock[0];
// Delete the block
await db.delete(courtBlocks).where(eq(courtBlocks.id, id));
// Log activity
await logActivity({
userId: session.userId,
action: ACTIONS.BLOCK_DELETE,
entityType: ENTITY_TYPES.COURT_BLOCK,
entityId: id,
details: {
courtId: block.courtId || 'all',
date: block.date,
startTime: block.startTime,
endTime: block.endTime,
reason: block.reason,
},
});
return NextResponse.json({ message: 'Block deleted successfully' });
} catch (error) {
console.error('Error deleting block:', error);
return NextResponse.json({ error: 'Internal server error' }, { status: 500 });
}
}