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 401449201c
commit 730b165f9c
31 changed files with 8882 additions and 56 deletions

View File

@@ -0,0 +1,116 @@
-- CreateExtension
CREATE EXTENSION IF NOT EXISTS "postgis";
-- CreateEnum
CREATE TYPE "ParkStatus" AS ENUM ('OPERATING', 'CLOSED_TEMP', 'CLOSED_PERM', 'UNDER_CONSTRUCTION', 'DEMOLISHED', 'RELOCATED');
-- CreateTable
CREATE TABLE "User" (
"id" SERIAL PRIMARY KEY,
"email" TEXT NOT NULL,
"username" TEXT NOT NULL,
"password" TEXT,
"dateJoined" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"isActive" BOOLEAN NOT NULL DEFAULT true,
"isStaff" BOOLEAN NOT NULL DEFAULT false,
"isSuperuser" BOOLEAN NOT NULL DEFAULT false,
"lastLogin" TIMESTAMP(3)
);
-- CreateTable
CREATE TABLE "Park" (
"id" SERIAL PRIMARY KEY,
"name" TEXT NOT NULL,
"slug" TEXT NOT NULL,
"description" TEXT,
"status" "ParkStatus" NOT NULL DEFAULT 'OPERATING',
"location" JSONB,
"opening_date" DATE,
"closing_date" DATE,
"operating_season" TEXT,
"size_acres" DECIMAL(10,2),
"website" TEXT,
"average_rating" DECIMAL(3,2),
"ride_count" INTEGER,
"coaster_count" INTEGER,
"creatorId" INTEGER,
"ownerId" INTEGER,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMP(3) NOT NULL
);
-- CreateTable
CREATE TABLE "ParkArea" (
"id" SERIAL PRIMARY KEY,
"name" TEXT NOT NULL,
"slug" TEXT NOT NULL,
"description" TEXT,
"opening_date" DATE,
"closing_date" DATE,
"parkId" INTEGER NOT NULL,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMP(3) NOT NULL
);
-- CreateTable
CREATE TABLE "Company" (
"id" SERIAL PRIMARY KEY,
"name" TEXT NOT NULL,
"website" TEXT,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMP(3) NOT NULL
);
-- CreateTable
CREATE TABLE "Review" (
"id" SERIAL PRIMARY KEY,
"content" TEXT NOT NULL,
"rating" INTEGER NOT NULL,
"parkId" INTEGER NOT NULL,
"userId" INTEGER NOT NULL,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMP(3) NOT NULL
);
-- CreateTable
CREATE TABLE "Photo" (
"id" SERIAL PRIMARY KEY,
"url" TEXT NOT NULL,
"caption" TEXT,
"parkId" INTEGER,
"reviewId" INTEGER,
"userId" INTEGER NOT NULL,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMP(3) NOT NULL
);
-- CreateIndex
CREATE UNIQUE INDEX "User_email_key" ON "User"("email");
CREATE UNIQUE INDEX "User_username_key" ON "User"("username");
CREATE UNIQUE INDEX "Park_slug_key" ON "Park"("slug");
CREATE UNIQUE INDEX "ParkArea_parkId_slug_key" ON "ParkArea"("parkId", "slug");
-- AddForeignKey
ALTER TABLE "Park" ADD CONSTRAINT "Park_creatorId_fkey" FOREIGN KEY ("creatorId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE;
ALTER TABLE "Park" ADD CONSTRAINT "Park_ownerId_fkey" FOREIGN KEY ("ownerId") REFERENCES "Company"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "ParkArea" ADD CONSTRAINT "ParkArea_parkId_fkey" FOREIGN KEY ("parkId") REFERENCES "Park"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Review" ADD CONSTRAINT "Review_parkId_fkey" FOREIGN KEY ("parkId") REFERENCES "Park"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
ALTER TABLE "Review" ADD CONSTRAINT "Review_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Photo" ADD CONSTRAINT "Photo_parkId_fkey" FOREIGN KEY ("parkId") REFERENCES "Park"("id") ON DELETE SET NULL ON UPDATE CASCADE;
ALTER TABLE "Photo" ADD CONSTRAINT "Photo_reviewId_fkey" FOREIGN KEY ("reviewId") REFERENCES "Review"("id") ON DELETE SET NULL ON UPDATE CASCADE;
ALTER TABLE "Photo" ADD CONSTRAINT "Photo_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- CreateIndex
CREATE INDEX "Park_slug_idx" ON "Park"("slug");
CREATE INDEX "ParkArea_slug_idx" ON "ParkArea"("slug");
CREATE INDEX "Review_parkId_idx" ON "Review"("parkId");
CREATE INDEX "Review_userId_idx" ON "Review"("userId");
CREATE INDEX "Photo_parkId_idx" ON "Photo"("parkId");
CREATE INDEX "Photo_reviewId_idx" ON "Photo"("reviewId");
CREATE INDEX "Photo_userId_idx" ON "Photo"("userId");

View File

@@ -0,0 +1,3 @@
# Please do not edit this file manually
# It should be added in your version-control system (e.g., Git)
provider = "postgresql"

View File

@@ -0,0 +1,137 @@
// This is your Prisma schema file
generator client {
provider = "prisma-client-js"
previewFeatures = ["postgresqlExtensions"]
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
extensions = [postgis]
}
// Core user model
model User {
id Int @id @default(autoincrement())
email String @unique
username String @unique
password String?
dateJoined DateTime @default(now())
isActive Boolean @default(true)
isStaff Boolean @default(false)
isSuperuser Boolean @default(false)
lastLogin DateTime?
createdParks Park[] @relation("ParkCreator")
reviews Review[]
photos Photo[]
}
// Park model
model Park {
id Int @id @default(autoincrement())
name String
slug String @unique
description String? @db.Text
status ParkStatus @default(OPERATING)
location Json? // Store PostGIS point as JSON for now
// Details
opening_date DateTime? @db.Date
closing_date DateTime? @db.Date
operating_season String?
size_acres Decimal? @db.Decimal(10, 2)
website String?
// Statistics
average_rating Decimal? @db.Decimal(3, 2)
ride_count Int?
coaster_count Int?
// Relationships
creator User? @relation("ParkCreator", fields: [creatorId], references: [id])
creatorId Int?
owner Company? @relation(fields: [ownerId], references: [id])
ownerId Int?
areas ParkArea[]
reviews Review[]
photos Photo[]
// Metadata
created_at DateTime @default(now())
updated_at DateTime @updatedAt
@@index([slug])
}
// Park Area model
model ParkArea {
id Int @id @default(autoincrement())
name String
slug String
description String? @db.Text
opening_date DateTime? @db.Date
closing_date DateTime? @db.Date
park Park @relation(fields: [parkId], references: [id], onDelete: Cascade)
parkId Int
created_at DateTime @default(now())
updated_at DateTime @updatedAt
@@unique([parkId, slug])
@@index([slug])
}
// Company model (for park owners)
model Company {
id Int @id @default(autoincrement())
name String
website String?
parks Park[]
created_at DateTime @default(now())
updated_at DateTime @updatedAt
}
// Review model
model Review {
id Int @id @default(autoincrement())
content String @db.Text
rating Int
park Park @relation(fields: [parkId], references: [id])
parkId Int
user User @relation(fields: [userId], references: [id])
userId Int
photos Photo[]
created_at DateTime @default(now())
updated_at DateTime @updatedAt
@@index([parkId])
@@index([userId])
}
// Photo model
model Photo {
id Int @id @default(autoincrement())
url String
caption String?
park Park? @relation(fields: [parkId], references: [id])
parkId Int?
review Review? @relation(fields: [reviewId], references: [id])
reviewId Int?
user User @relation(fields: [userId], references: [id])
userId Int
created_at DateTime @default(now())
updated_at DateTime @updatedAt
@@index([parkId])
@@index([reviewId])
@@index([userId])
}
enum ParkStatus {
OPERATING
CLOSED_TEMP
CLOSED_PERM
UNDER_CONSTRUCTION
DEMOLISHED
RELOCATED
}

148
frontend/prisma/seed.ts Normal file
View File

@@ -0,0 +1,148 @@
import { PrismaClient, ParkStatus } from '@prisma/client';
const prisma = new PrismaClient();
async function main() {
// Create test users
const user1 = await prisma.user.create({
data: {
email: 'admin@thrillwiki.com',
username: 'admin',
password: 'hashed_password_here',
isActive: true,
isStaff: true,
isSuperuser: true,
},
});
const user2 = await prisma.user.create({
data: {
email: 'testuser@thrillwiki.com',
username: 'testuser',
password: 'hashed_password_here',
isActive: true,
},
});
// Create test companies
const company1 = await prisma.company.create({
data: {
name: 'Universal Parks & Resorts',
website: 'https://www.universalparks.com',
},
});
const company2 = await prisma.company.create({
data: {
name: 'Cedar Fair Entertainment Company',
website: 'https://www.cedarfair.com',
},
});
// Create test parks
const park1 = await prisma.park.create({
data: {
name: 'Universal Studios Florida',
slug: 'universal-studios-florida',
description: 'Movie and TV-based theme park in Orlando, Florida',
status: ParkStatus.OPERATING,
location: {
latitude: 28.4742,
longitude: -81.4678,
},
opening_date: new Date('1990-06-07'),
operating_season: 'Year-round',
size_acres: 108,
website: 'https://www.universalorlando.com',
average_rating: 4.5,
ride_count: 25,
coaster_count: 2,
creatorId: user1.id,
ownerId: company1.id,
areas: {
create: [
{
name: 'Production Central',
slug: 'production-central',
description: 'The main entrance area of the park',
opening_date: new Date('1990-06-07'),
},
{
name: 'New York',
slug: 'new-york',
description: 'Themed after New York City streets',
opening_date: new Date('1990-06-07'),
},
],
},
},
});
const park2 = await prisma.park.create({
data: {
name: 'Cedar Point',
slug: 'cedar-point',
description: 'The Roller Coaster Capital of the World',
status: ParkStatus.OPERATING,
location: {
latitude: 41.4822,
longitude: -82.6837,
},
opening_date: new Date('1870-05-01'),
operating_season: 'May through October',
size_acres: 364,
website: 'https://www.cedarpoint.com',
average_rating: 4.8,
ride_count: 71,
coaster_count: 17,
creatorId: user1.id,
ownerId: company2.id,
areas: {
create: [
{
name: 'FrontierTown',
slug: 'frontiertown',
description: 'Western-themed area of the park',
opening_date: new Date('1968-05-01'),
},
{
name: 'Millennium Island',
slug: 'millennium-island',
description: 'Home of the Millennium Force',
opening_date: new Date('2000-05-13'),
},
],
},
},
});
// Create test reviews
await prisma.review.create({
data: {
content: 'Amazing theme park with great attention to detail!',
rating: 5,
parkId: park1.id,
userId: user2.id,
},
});
await prisma.review.create({
data: {
content: 'Best roller coasters in the world!',
rating: 5,
parkId: park2.id,
userId: user2.id,
},
});
console.log('Seed data created successfully');
}
main()
.catch((e) => {
console.error('Error creating seed data:', e);
process.exit(1);
})
.finally(async () => {
await prisma.$disconnect();
});