mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-28 20:47:03 -05:00
Initialize frontend project with Next.js, Tailwind CSS, and essential configurations
This commit is contained in:
217
frontend/src/app/api/parks/route.ts
Normal file
217
frontend/src/app/api/parks/route.ts
Normal file
@@ -0,0 +1,217 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import prisma from '@/lib/prisma';
|
||||
import { ParkListResponse, Park } from '@/types/api';
|
||||
|
||||
export async function GET(
|
||||
request: NextRequest
|
||||
): Promise<NextResponse<ParkListResponse>> {
|
||||
try {
|
||||
// Get query parameters
|
||||
const { searchParams } = new URL(request.url);
|
||||
const page = parseInt(searchParams.get('page') || '1');
|
||||
const limit = parseInt(searchParams.get('limit') || '10');
|
||||
const search = searchParams.get('search') || '';
|
||||
const status = searchParams.get('status') || undefined;
|
||||
|
||||
// Calculate pagination
|
||||
const skip = (page - 1) * limit;
|
||||
|
||||
// Build where clause
|
||||
const where = {
|
||||
AND: [
|
||||
search ? {
|
||||
OR: [
|
||||
{ name: { contains: search, mode: 'insensitive' } },
|
||||
{ description: { contains: search, mode: 'insensitive' } },
|
||||
],
|
||||
} : {},
|
||||
status ? { status } : {},
|
||||
],
|
||||
};
|
||||
|
||||
// Ensure database connection is initialized
|
||||
if (!prisma) {
|
||||
throw new Error('Database connection not initialized');
|
||||
}
|
||||
|
||||
// Fetch parks with relationships
|
||||
const [parks, total] = await Promise.all([
|
||||
prisma.park.findMany({
|
||||
where,
|
||||
skip,
|
||||
take: limit,
|
||||
orderBy: {
|
||||
name: 'asc',
|
||||
},
|
||||
include: {
|
||||
creator: {
|
||||
select: {
|
||||
id: true,
|
||||
username: true,
|
||||
email: true,
|
||||
},
|
||||
},
|
||||
owner: true,
|
||||
areas: true,
|
||||
reviews: {
|
||||
include: {
|
||||
user: {
|
||||
select: {
|
||||
id: true,
|
||||
username: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
photos: {
|
||||
include: {
|
||||
user: {
|
||||
select: {
|
||||
id: true,
|
||||
username: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
prisma.park.count({ where }),
|
||||
]);
|
||||
|
||||
// Transform dates and format response
|
||||
const formattedParks = parks.map(park => ({
|
||||
...park,
|
||||
opening_date: park.opening_date?.toISOString().split('T')[0],
|
||||
closing_date: park.closing_date?.toISOString().split('T')[0],
|
||||
created_at: park.created_at.toISOString(),
|
||||
updated_at: park.updated_at.toISOString(),
|
||||
// Format nested dates
|
||||
areas: park.areas.map(area => ({
|
||||
...area,
|
||||
opening_date: area.opening_date?.toISOString().split('T')[0],
|
||||
closing_date: area.closing_date?.toISOString().split('T')[0],
|
||||
created_at: area.created_at.toISOString(),
|
||||
updated_at: area.updated_at.toISOString(),
|
||||
})),
|
||||
reviews: park.reviews.map(review => ({
|
||||
...review,
|
||||
created_at: review.created_at.toISOString(),
|
||||
updated_at: review.updated_at.toISOString(),
|
||||
})),
|
||||
photos: park.photos.map(photo => ({
|
||||
...photo,
|
||||
created_at: photo.created_at.toISOString(),
|
||||
updated_at: photo.updated_at.toISOString(),
|
||||
})),
|
||||
}));
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
data: formattedParks,
|
||||
metadata: {
|
||||
page,
|
||||
limit,
|
||||
total,
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error fetching parks:', error);
|
||||
return NextResponse.json(
|
||||
{
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Failed to fetch parks',
|
||||
},
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export async function POST(
|
||||
request: NextRequest
|
||||
): Promise<NextResponse<ParkListResponse>> {
|
||||
try {
|
||||
// Ensure user is authenticated
|
||||
const userToken = request.headers.get('x-user-token');
|
||||
if (!userToken) {
|
||||
return NextResponse.json(
|
||||
{
|
||||
success: false,
|
||||
error: 'Unauthorized',
|
||||
},
|
||||
{ status: 401 }
|
||||
);
|
||||
}
|
||||
|
||||
const data = await request.json();
|
||||
|
||||
// Validate required fields
|
||||
if (!data.name) {
|
||||
return NextResponse.json(
|
||||
{
|
||||
success: false,
|
||||
error: 'Name is required',
|
||||
},
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
// Generate slug from name
|
||||
const slug = data.name
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9]+/g, '-')
|
||||
.replace(/(^-|-$)/g, '');
|
||||
|
||||
// Ensure database connection is initialized
|
||||
if (!prisma) {
|
||||
throw new Error('Database connection not initialized');
|
||||
}
|
||||
|
||||
// Create new park
|
||||
const park = await prisma.park.create({
|
||||
data: {
|
||||
name: data.name,
|
||||
slug,
|
||||
description: data.description,
|
||||
status: data.status || 'OPERATING',
|
||||
location: data.location,
|
||||
opening_date: data.opening_date ? new Date(data.opening_date) : null,
|
||||
closing_date: data.closing_date ? new Date(data.closing_date) : null,
|
||||
operating_season: data.operating_season,
|
||||
size_acres: data.size_acres,
|
||||
website: data.website,
|
||||
creatorId: parseInt(data.creatorId),
|
||||
ownerId: data.ownerId ? parseInt(data.ownerId) : null,
|
||||
},
|
||||
include: {
|
||||
creator: {
|
||||
select: {
|
||||
id: true,
|
||||
username: true,
|
||||
email: true,
|
||||
},
|
||||
},
|
||||
owner: true,
|
||||
},
|
||||
});
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
data: {
|
||||
...park,
|
||||
opening_date: park.opening_date?.toISOString().split('T')[0],
|
||||
closing_date: park.closing_date?.toISOString().split('T')[0],
|
||||
created_at: park.created_at.toISOString(),
|
||||
updated_at: park.updated_at.toISOString(),
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error creating park:', error);
|
||||
return NextResponse.json(
|
||||
{
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Failed to create park',
|
||||
},
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user