Initialize frontend project with Next.js, Tailwind CSS, and essential configurations

This commit is contained in:
pacnpal
2025-02-23 16:01:56 -05:00
parent 8404e4d3d5
commit 5bcbcae2cd
31 changed files with 8882 additions and 56 deletions

View 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 }
);
}
}