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"); // Clean existing data (order matters for FK) await prisma.tripReview.deleteMany(); await prisma.tripParticipant.deleteMany(); await prisma.tripImage.deleteMany(); await prisma.trip.deleteMany(); await prisma.user.deleteMany(); // ==================== USERS ==================== const password = await bcrypt.hash("password123", 12); // Organizer const dede = await prisma.user.create({ data: { name: "Dede Inoen", email: "dede.inoen@setrip.id", password, isVerified: true, }, }); const panji = await prisma.user.create({ data: { name: "Panji Petualang", email: "panji@setrip.id", password, isVerified: true, }, }); const fiersa = await prisma.user.create({ data: { name: "Fiersa Besari", email: "fiersa@setrip.id", password, }, }); // User biasa (peserta) const budi = await prisma.user.create({ data: { name: "Budi Santoso", email: "budi@gmail.com", password, }, }); const sari = await prisma.user.create({ data: { name: "Sari Dewi", email: "sari@gmail.com", password, }, }); const doni = await prisma.user.create({ data: { name: "Doni Prasetyo", email: "doni@gmail.com", password, }, }); const maya = await prisma.user.create({ data: { name: "Maya Putri", email: "maya@gmail.com", password, }, }); const raka = await prisma.user.create({ data: { name: "Raka Aditya", email: "raka@gmail.com", password, }, }); console.log("βœ… Users created"); console.log(" Organizer: dede.inoen@setrip.id, panji@setrip.id, fiersa@setrip.id"); console.log(" Peserta: budi, sari, doni, maya, raka @gmail.com"); console.log(" Password semua: password123\n"); // ==================== TRIPS + IMAGES ==================== /** * Tanggal disimpan eksplisit di UTC agar filter `from`/`to` (YYYY-MM-DD UTC) * cocok dengan yang tampil di daftar. * * - Multi hari: isi `endDate` = hari terakhir trip (UTC). * - Satu hari / night hike satu malam: `endDate` null β€” filter memakai instan `date` * dalam rentang hari UTC yang sama (jam tetap masuk hari itu). */ const utc = (y: number, m0: number, d: number, h = 12, min = 0) => new Date(Date.UTC(y, m0, d, h, min, 0, 0)); // Unsplash mountain photos (URL CDN publik, gratis, stabil). // Slug ID di komentar = id di unsplash.com/photos/{slug} buat ditelusuri ulang. const img = (id: string) => `https://images.unsplash.com/photo-${id}?w=1200&q=80&auto=format&fit=crop`; const MOUNTAIN_PHOTOS = { papandayan1: img("1554629947-334ff61d85dc"), // xfngap_DToE papandayan2: img("1464822759023-fed622ff2c3b"), // Bkci_8qcdvQ papandayan3: img("1454496522488-7a8e488e8606"), // 9wg5jCEPBsw ciremai1: img("1480497490787-505ec076689f"), // 6bKxagnIDtk ciremai2: img("1483728642387-6c3bdd6c93e5"), // YFFGkE3y4F8 ciremai3: img("1502085671122-2d218cd434e6"), // NNmiv6zcFvk gede1: img("1478059299873-f047d8c5fe1a"), // DXQB5D1njMY gede2: img("1519681393784-d120267933ba"), // z8ct_Q3oCqM gede3: img("1501785888041-af3ef285b470"), // T7K4aEPoGGk gede4: img("1540979388789-6cee28a1cdc9"), // eUFfY6cwjSU tangkuban1: img("1506905925346-21bda4d32df4"), // 1527pjeb6jg tangkuban2: img("1490682143684-14369e18dce8"), // 8c6eS43iq1o malabar1: img("1494548162494-384bba4ab999"), // xP_AGmeEa6s malabar2: img("1500964757637-c85e8a162699"), // twukN12EN7c malabar3: img("1549880181-56a44cf4a9a5"), // ePpaQC2c1xA guntur1: img("1558883493-8b86ff880fec"), // vaG8rOJLDHo guntur2: img("1554629947-334ff61d85dc"), // reuse β€” xfngap_DToE guntur3: img("1464822759023-fed622ff2c3b"), // reuse β€” Bkci_8qcdvQ } as const; // --- Trip 1: Papandayan (by Dede Inoen) β€” 2 hari --- const trip1 = await prisma.trip.create({ data: { title: "Open Trip Papandayan Weekend", description: `Pendakian santai ke Gunung Papandayan, cocok untuk pemula! ⚠️ Bawa: Sleeping bag, jaket, headlamp, air 2L`, meetingPoint: "Alun-alun Garut (depan pendopo), Sabtu 05:00 WIB β€” detail grup WA.", itinerary: `Sabtu β€’ 05:00 Meeting & briefing β€’ 07:00 Berangkat menuju basecamp β€’ 12:00 Makan siang trail β€’ 15:00 Camp area Pondok Salada Minggu β€’ 04:00 Summit attack β€’ 08:00 Sarap & packing β€’ 11:00 Turun β€’ 16:00 Estimasi kembali ke Garut`, whatsIncluded: `β€’ Transport PP Garut–basecamp β€’ Guide lokal β€’ Tenda tim (kapasitas sesuai muatan) β€’ Konsumsi: makan 3x + snack`, whatsExcluded: `β€’ Tiket masuk TNGGP β€’ Sleeping bag & matras pribadi β€’ Asuransi perjalanan`, mountain: "Gunung Papandayan", location: "Garut, Jawa Barat", date: utc(2026, 3, 23, 8, 0), endDate: utc(2026, 3, 24, 18, 0), maxParticipants: 10, price: 250000, status: "OPEN", organizerId: dede.id, images: { create: [ { url: MOUNTAIN_PHOTOS.papandayan1, caption: "Kawah Papandayan", order: 0 }, { url: MOUNTAIN_PHOTOS.papandayan2, caption: "Track menuju puncak", order: 1 }, { url: MOUNTAIN_PHOTOS.papandayan3, caption: "Camping ground Pondok Salada", order: 2 }, ], }, }, }); // --- Trip 2: Ciremai (by Panji Petualang) β€” 2 hari --- 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: utc(2026, 3, 25, 4, 0), endDate: utc(2026, 3, 26, 18, 0), maxParticipants: 8, price: 350000, status: "OPEN", organizerId: panji.id, images: { create: [ { url: MOUNTAIN_PHOTOS.ciremai1, caption: "Puncak Ciremai 3.078 mdpl", order: 0 }, { url: MOUNTAIN_PHOTOS.ciremai2, caption: "Jalur pendakian via Apuy", order: 1 }, { url: MOUNTAIN_PHOTOS.ciremai3, caption: "Sunrise dari puncak", order: 2 }, ], }, }, }); // --- Trip 3: Gede-Pangrango (by Fiersa Besari) β€” 2 hari --- 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: utc(2026, 3, 27, 22, 0), endDate: utc(2026, 3, 28, 16, 0), maxParticipants: 12, price: 280000, status: "OPEN", organizerId: fiersa.id, images: { create: [ { url: MOUNTAIN_PHOTOS.gede1, caption: "Puncak Gunung Gede", order: 0 }, { url: MOUNTAIN_PHOTOS.gede2, caption: "Surya Kencana padang edelweis", order: 1 }, { url: MOUNTAIN_PHOTOS.gede3, caption: "Blue lake / Danau Biru", order: 2 }, { url: MOUNTAIN_PHOTOS.gede4, caption: "Night hike track Cibodas", order: 3 }, ], }, }, }); // --- Trip 4: Tangkuban Parahu (by Dede Inoen) β€” 1 hari --- 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: utc(2026, 3, 22, 0, 0), endDate: null, maxParticipants: 15, price: 120000, status: "OPEN", organizerId: dede.id, images: { create: [ { url: MOUNTAIN_PHOTOS.tangkuban1, caption: "Kawah Ratu", order: 0 }, { url: MOUNTAIN_PHOTOS.tangkuban2, caption: "Kawah Domas", order: 1 }, ], }, }, }); // --- Trip 5: Malabar (by Fiersa Besari) β€” 1 hari (night hike, `endDate` null) --- 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: utc(2026, 3, 20, 14, 0), endDate: null, maxParticipants: 10, price: 150000, status: "OPEN", organizerId: fiersa.id, images: { create: [ { url: MOUNTAIN_PHOTOS.malabar1, caption: "Puncak Malabar malam hari", order: 0 }, { url: MOUNTAIN_PHOTOS.malabar2, caption: "View Bandung dari atas", order: 1 }, { url: MOUNTAIN_PHOTOS.malabar3, caption: "Track pendakian", order: 2 }, ], }, }, }); // --- Trip 6: Guntur (by Panji Petualang) β€” 2 hari --- 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: utc(2026, 3, 30, 4, 0), endDate: utc(2026, 4, 1, 18, 0), maxParticipants: 8, price: 300000, status: "OPEN", organizerId: panji.id, images: { create: [ { url: MOUNTAIN_PHOTOS.guntur1, caption: "Kawah aktif Gunung Guntur", order: 0 }, { url: MOUNTAIN_PHOTOS.guntur2, caption: "Jalur berbatu menuju puncak", order: 1 }, { url: MOUNTAIN_PHOTOS.guntur3, caption: "View dari puncak", order: 2 }, ], }, }, }); console.log("βœ… 6 Trips + images created (tanggal UTC + endDate untuk trip multi hari)\n"); console.log( ` Guntur: ${trip6.title} ${trip6.date.toISOString().slice(0, 10)} β†’ ${trip6.endDate?.toISOString().slice(0, 10) ?? "-"}\n` ); // ==================== PARTICIPANTS ==================== await prisma.tripParticipant.createMany({ data: [ // Papandayan β€” 4 peserta { tripId: trip1.id, userId: budi.id, status: "CONFIRMED" }, { tripId: trip1.id, userId: sari.id, status: "CONFIRMED" }, { tripId: trip1.id, userId: doni.id, status: "CONFIRMED" }, { tripId: trip1.id, userId: raka.id, status: "CONFIRMED" }, // Ciremai β€” 2 peserta { tripId: trip2.id, userId: budi.id, status: "CONFIRMED" }, { tripId: trip2.id, userId: maya.id, status: "CONFIRMED" }, // Gede β€” 5 peserta { tripId: trip3.id, userId: budi.id, status: "CONFIRMED" }, { tripId: trip3.id, userId: sari.id, status: "CONFIRMED" }, { tripId: trip3.id, userId: doni.id, status: "CONFIRMED" }, { tripId: trip3.id, userId: maya.id, status: "CONFIRMED" }, { tripId: trip3.id, userId: raka.id, status: "CONFIRMED" }, // Tangkuban Parahu β€” 5 peserta { tripId: trip4.id, userId: budi.id, status: "CONFIRMED" }, { tripId: trip4.id, userId: sari.id, status: "CONFIRMED" }, { tripId: trip4.id, userId: doni.id, status: "CONFIRMED" }, { tripId: trip4.id, userId: maya.id, status: "CONFIRMED" }, { tripId: trip4.id, userId: raka.id, status: "CONFIRMED" }, // Malabar β€” 2 peserta { tripId: trip5.id, userId: sari.id, status: "CONFIRMED" }, { tripId: trip5.id, userId: maya.id, status: "CONFIRMED" }, // Guntur β€” 0 peserta ], }); console.log("βœ… Participants joined"); console.log(" Papandayan: 4/10 | Ciremai: 2/8 | Gede: 5/12"); console.log(" Tangkuban Parahu: 5/15 | Malabar: 2/10 | Guntur: 0/8\n"); console.log("πŸŽ‰ Seed complete!"); } main() .catch((e) => { console.error("❌ Seed failed:", e); process.exit(1); }) .finally(async () => { await prisma.$disconnect(); });