auth, trips and join trips
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
-- CreateEnum
|
||||
CREATE TYPE "TripStatus" AS ENUM ('OPEN', 'FULL', 'CLOSED', 'COMPLETED');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "ParticipantStatus" AS ENUM ('PENDING', 'CONFIRMED', 'CANCELLED');
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "User" (
|
||||
"id" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"email" TEXT NOT NULL,
|
||||
"password" TEXT NOT NULL,
|
||||
"image" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "User_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Trip" (
|
||||
"id" TEXT NOT NULL,
|
||||
"title" TEXT NOT NULL,
|
||||
"description" TEXT,
|
||||
"mountain" TEXT NOT NULL,
|
||||
"location" TEXT NOT NULL,
|
||||
"date" TIMESTAMP(3) NOT NULL,
|
||||
"maxParticipants" INTEGER NOT NULL,
|
||||
"price" INTEGER NOT NULL,
|
||||
"image" TEXT,
|
||||
"status" "TripStatus" NOT NULL DEFAULT 'OPEN',
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"organizerId" TEXT NOT NULL,
|
||||
|
||||
CONSTRAINT "Trip_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "TripParticipant" (
|
||||
"id" TEXT NOT NULL,
|
||||
"status" "ParticipantStatus" NOT NULL DEFAULT 'PENDING',
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"tripId" TEXT NOT NULL,
|
||||
"userId" TEXT NOT NULL,
|
||||
|
||||
CONSTRAINT "TripParticipant_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "User_email_key" ON "User"("email");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "TripParticipant_tripId_userId_key" ON "TripParticipant"("tripId", "userId");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Trip" ADD CONSTRAINT "Trip_organizerId_fkey" FOREIGN KEY ("organizerId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "TripParticipant" ADD CONSTRAINT "TripParticipant_tripId_fkey" FOREIGN KEY ("tripId") REFERENCES "Trip"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "TripParticipant" ADD CONSTRAINT "TripParticipant_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
@@ -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"
|
||||
@@ -0,0 +1,68 @@
|
||||
generator client {
|
||||
provider = "prisma-client"
|
||||
output = "../app/generated/prisma"
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "postgresql"
|
||||
}
|
||||
|
||||
model User {
|
||||
id String @id @default(cuid())
|
||||
name String
|
||||
email String @unique
|
||||
password String
|
||||
image String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
trips Trip[]
|
||||
participations TripParticipant[]
|
||||
}
|
||||
|
||||
model Trip {
|
||||
id String @id @default(cuid())
|
||||
title String
|
||||
description String?
|
||||
mountain String
|
||||
location String
|
||||
date DateTime
|
||||
maxParticipants Int
|
||||
price Int
|
||||
image String?
|
||||
status TripStatus @default(OPEN)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
organizerId String
|
||||
organizer User @relation(fields: [organizerId], references: [id])
|
||||
|
||||
participants TripParticipant[]
|
||||
}
|
||||
|
||||
model TripParticipant {
|
||||
id String @id @default(cuid())
|
||||
status ParticipantStatus @default(PENDING)
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
tripId String
|
||||
trip Trip @relation(fields: [tripId], references: [id])
|
||||
|
||||
userId String
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
|
||||
@@unique([tripId, userId])
|
||||
}
|
||||
|
||||
enum TripStatus {
|
||||
OPEN
|
||||
FULL
|
||||
CLOSED
|
||||
COMPLETED
|
||||
}
|
||||
|
||||
enum ParticipantStatus {
|
||||
PENDING
|
||||
CONFIRMED
|
||||
CANCELLED
|
||||
}
|
||||
+282
@@ -0,0 +1,282 @@
|
||||
import "dotenv/config";
|
||||
import { PrismaClient } from "../app/generated/prisma/client";
|
||||
import { PrismaPg } from "@prisma/adapter-pg";
|
||||
import bcrypt from "bcryptjs";
|
||||
|
||||
const adapter = new PrismaPg({
|
||||
connectionString: process.env.DATABASE_URL!,
|
||||
});
|
||||
const prisma = new PrismaClient({ adapter });
|
||||
|
||||
async function main() {
|
||||
console.log("🌱 Seeding database...\n");
|
||||
|
||||
// ==================== USERS ====================
|
||||
|
||||
const password = await bcrypt.hash("password123", 12);
|
||||
|
||||
// Organizer
|
||||
const organizer1 = await prisma.user.upsert({
|
||||
where: { email: "andi@setrip.id" },
|
||||
update: {},
|
||||
create: {
|
||||
name: "Andi Pendaki",
|
||||
email: "andi@setrip.id",
|
||||
password,
|
||||
},
|
||||
});
|
||||
|
||||
const organizer2 = await prisma.user.upsert({
|
||||
where: { email: "rina@setrip.id" },
|
||||
update: {},
|
||||
create: {
|
||||
name: "Rina Explorer",
|
||||
email: "rina@setrip.id",
|
||||
password,
|
||||
},
|
||||
});
|
||||
|
||||
// User biasa (join trip)
|
||||
const user1 = await prisma.user.upsert({
|
||||
where: { email: "budi@gmail.com" },
|
||||
update: {},
|
||||
create: {
|
||||
name: "Budi Santoso",
|
||||
email: "budi@gmail.com",
|
||||
password,
|
||||
},
|
||||
});
|
||||
|
||||
const user2 = await prisma.user.upsert({
|
||||
where: { email: "sari@gmail.com" },
|
||||
update: {},
|
||||
create: {
|
||||
name: "Sari Dewi",
|
||||
email: "sari@gmail.com",
|
||||
password,
|
||||
},
|
||||
});
|
||||
|
||||
const user3 = await prisma.user.upsert({
|
||||
where: { email: "doni@gmail.com" },
|
||||
update: {},
|
||||
create: {
|
||||
name: "Doni Prasetyo",
|
||||
email: "doni@gmail.com",
|
||||
password,
|
||||
},
|
||||
});
|
||||
|
||||
const user4 = await prisma.user.upsert({
|
||||
where: { email: "maya@gmail.com" },
|
||||
update: {},
|
||||
create: {
|
||||
name: "Maya Putri",
|
||||
email: "maya@gmail.com",
|
||||
password,
|
||||
},
|
||||
});
|
||||
|
||||
console.log("✅ Users created");
|
||||
console.log(" Organizer: andi@setrip.id, rina@setrip.id");
|
||||
console.log(" Users: budi@gmail.com, sari@gmail.com, doni@gmail.com, maya@gmail.com");
|
||||
console.log(" Password semua: password123\n");
|
||||
|
||||
// ==================== TRIPS ====================
|
||||
|
||||
const now = new Date();
|
||||
|
||||
const trip1 = await prisma.trip.create({
|
||||
data: {
|
||||
title: "Open Trip Papandayan Weekend",
|
||||
description: `Pendakian santai ke Gunung Papandayan, cocok untuk pemula!
|
||||
|
||||
📍 Meeting Point: Alun-alun Garut, 05:00 WIB
|
||||
🎒 Fasilitas: Transport PP, guide, tenda, makan 3x
|
||||
⚠️ Bawa: Sleeping bag, jaket, headlamp, air 2L
|
||||
|
||||
Itinerary:
|
||||
- Sabtu: Berangkat → Basecamp → Summit → Camp
|
||||
- Minggu: Sunrise → Turun → Pulang`,
|
||||
mountain: "Gunung Papandayan",
|
||||
location: "Garut, Jawa Barat",
|
||||
date: new Date(now.getTime() + 3 * 24 * 60 * 60 * 1000), // 3 hari lagi
|
||||
maxParticipants: 10,
|
||||
price: 250000,
|
||||
status: "OPEN",
|
||||
organizerId: organizer1.id,
|
||||
},
|
||||
});
|
||||
|
||||
const trip2 = await prisma.trip.create({
|
||||
data: {
|
||||
title: "Pendakian Ciremai via Apuy",
|
||||
description: `Trip ke puncak tertinggi Jawa Barat! 🏔️
|
||||
|
||||
📍 Meeting Point: Stasiun Kuningan, 04:00 WIB
|
||||
🎒 Fasilitas: Transport lokal, guide, logistik
|
||||
⚠️ Level: Menengah — perlu stamina baik
|
||||
|
||||
Itinerary:
|
||||
- Hari 1: Basecamp → Pos 3 → Camp
|
||||
- Hari 2: Summit attack → Turun → Pulang`,
|
||||
mountain: "Gunung Ciremai",
|
||||
location: "Kuningan, Jawa Barat",
|
||||
date: new Date(now.getTime() + 5 * 24 * 60 * 60 * 1000), // 5 hari lagi
|
||||
maxParticipants: 8,
|
||||
price: 350000,
|
||||
status: "OPEN",
|
||||
organizerId: organizer1.id,
|
||||
},
|
||||
});
|
||||
|
||||
const trip3 = await prisma.trip.create({
|
||||
data: {
|
||||
title: "Sunrise Trip Gede-Pangrango",
|
||||
description: `Combo 2 puncak sekaligus! Gede + Pangrango.
|
||||
|
||||
📍 Meeting Point: Cibodas, 22:00 WIB (malam)
|
||||
🎒 Fasilitas: Guide, tenda, makan
|
||||
⚠️ Level: Advance — night hike
|
||||
|
||||
Start malam, summit saat sunrise. View epic dijamin!`,
|
||||
mountain: "Gunung Gede",
|
||||
location: "Bogor/Cianjur, Jawa Barat",
|
||||
date: new Date(now.getTime() + 6 * 24 * 60 * 60 * 1000), // 6 hari lagi
|
||||
maxParticipants: 12,
|
||||
price: 280000,
|
||||
status: "OPEN",
|
||||
organizerId: organizer2.id,
|
||||
},
|
||||
});
|
||||
|
||||
const trip4 = await prisma.trip.create({
|
||||
data: {
|
||||
title: "Trip Hemat Tangkuban Parahu",
|
||||
description: `Trip santai ke kawah Tangkuban Parahu. Cocok buat first-timer!
|
||||
|
||||
📍 Meeting Point: Lembang, 07:00 WIB
|
||||
🎒 Fasilitas: Transport, snack, guide
|
||||
⚠️ Level: Easy — bisa pakai sandal gunung
|
||||
|
||||
Explore Kawah Ratu, Kawah Domas, foto-foto, terus makan sate maranggi!`,
|
||||
mountain: "Gunung Tangkuban Parahu",
|
||||
location: "Bandung, Jawa Barat",
|
||||
date: new Date(now.getTime() + 2 * 24 * 60 * 60 * 1000), // 2 hari lagi
|
||||
maxParticipants: 15,
|
||||
price: 120000,
|
||||
status: "OPEN",
|
||||
organizerId: organizer2.id,
|
||||
},
|
||||
});
|
||||
|
||||
const trip5 = await prisma.trip.create({
|
||||
data: {
|
||||
title: "Malabar Night Hike",
|
||||
description: `Night hike ke Gunung Malabar — view kota Bandung dari atas!
|
||||
|
||||
📍 Meeting Point: Pangalengan, 20:00 WIB
|
||||
🎒 Fasilitas: Guide, teh hangat di puncak
|
||||
⚠️ Bawa: Headlamp WAJIB, jaket tebal
|
||||
|
||||
Trip ringan, 3-4 jam naik. Cocok buat yang mau healing malam-malam.`,
|
||||
mountain: "Gunung Malabar",
|
||||
location: "Bandung, Jawa Barat",
|
||||
date: new Date(now.getTime() + 4 * 24 * 60 * 60 * 1000), // 4 hari lagi
|
||||
maxParticipants: 10,
|
||||
price: 150000,
|
||||
status: "OPEN",
|
||||
organizerId: organizer1.id,
|
||||
},
|
||||
});
|
||||
|
||||
const trip6 = await prisma.trip.create({
|
||||
data: {
|
||||
title: "Guntur Challenge Trip",
|
||||
description: `Trip ke Gunung Guntur — jalur menantang tapi worth it!
|
||||
|
||||
📍 Meeting Point: Alun-alun Garut, 04:30 WIB
|
||||
🎒 Fasilitas: Transport, guide, logistik
|
||||
⚠️ Level: Hard — medan berbatu & terjal
|
||||
|
||||
Buat yang suka challenge. Pemandangan kawah aktif dari dekat!`,
|
||||
mountain: "Gunung Guntur",
|
||||
location: "Garut, Jawa Barat",
|
||||
date: new Date(now.getTime() + 10 * 24 * 60 * 60 * 1000), // 10 hari lagi
|
||||
maxParticipants: 8,
|
||||
price: 300000,
|
||||
status: "OPEN",
|
||||
organizerId: organizer2.id,
|
||||
},
|
||||
});
|
||||
|
||||
console.log("✅ 6 Trips created\n");
|
||||
|
||||
// ==================== PARTICIPANTS ====================
|
||||
|
||||
// Trip 1 (Papandayan) — 3 peserta
|
||||
await prisma.tripParticipant.createMany({
|
||||
data: [
|
||||
{ tripId: trip1.id, userId: user1.id, status: "CONFIRMED" },
|
||||
{ tripId: trip1.id, userId: user2.id, status: "CONFIRMED" },
|
||||
{ tripId: trip1.id, userId: user3.id, status: "CONFIRMED" },
|
||||
],
|
||||
});
|
||||
|
||||
// Trip 2 (Ciremai) — 2 peserta
|
||||
await prisma.tripParticipant.createMany({
|
||||
data: [
|
||||
{ tripId: trip2.id, userId: user1.id, status: "CONFIRMED" },
|
||||
{ tripId: trip2.id, userId: user4.id, status: "CONFIRMED" },
|
||||
],
|
||||
});
|
||||
|
||||
// Trip 3 (Gede) — 4 peserta
|
||||
await prisma.tripParticipant.createMany({
|
||||
data: [
|
||||
{ tripId: trip3.id, userId: user1.id, status: "CONFIRMED" },
|
||||
{ tripId: trip3.id, userId: user2.id, status: "CONFIRMED" },
|
||||
{ tripId: trip3.id, userId: user3.id, status: "CONFIRMED" },
|
||||
{ tripId: trip3.id, userId: user4.id, status: "CONFIRMED" },
|
||||
],
|
||||
});
|
||||
|
||||
// Trip 4 (Tangkuban Parahu) — 5 peserta
|
||||
await prisma.tripParticipant.createMany({
|
||||
data: [
|
||||
{ tripId: trip4.id, userId: user1.id, status: "CONFIRMED" },
|
||||
{ tripId: trip4.id, userId: user2.id, status: "CONFIRMED" },
|
||||
{ tripId: trip4.id, userId: user3.id, status: "CONFIRMED" },
|
||||
{ tripId: trip4.id, userId: user4.id, status: "CONFIRMED" },
|
||||
{ tripId: trip4.id, userId: organizer1.id, status: "CONFIRMED" },
|
||||
],
|
||||
});
|
||||
|
||||
// Trip 5 (Malabar) — 1 peserta
|
||||
await prisma.tripParticipant.createMany({
|
||||
data: [
|
||||
{ tripId: trip5.id, userId: user2.id, status: "CONFIRMED" },
|
||||
],
|
||||
});
|
||||
|
||||
// Trip 6 (Guntur) — belum ada peserta
|
||||
|
||||
console.log("✅ Participants joined trips");
|
||||
console.log(" Papandayan: 3/10 peserta");
|
||||
console.log(" Ciremai: 2/8 peserta");
|
||||
console.log(" Gede: 4/12 peserta");
|
||||
console.log(" Tangkuban Parahu: 5/15 peserta");
|
||||
console.log(" Malabar: 1/10 peserta");
|
||||
console.log(" Guntur: 0/8 peserta\n");
|
||||
|
||||
console.log("🎉 Seed complete!");
|
||||
}
|
||||
|
||||
main()
|
||||
.catch((e) => {
|
||||
console.error("❌ Seed failed:", e);
|
||||
process.exit(1);
|
||||
})
|
||||
.finally(async () => {
|
||||
await prisma.$disconnect();
|
||||
});
|
||||
Reference in New Issue
Block a user