diff --git a/prisma/seed.ts b/prisma/seed.ts index 2b6fa21..ec4c350 100644 --- a/prisma/seed.ts +++ b/prisma/seed.ts @@ -18,12 +18,55 @@ const prisma = new PrismaClient({ adapter }); // Helpers // ============================================================================ +/** Tanggal absolut UTC — dipakai untuk data yang tidak boleh bergeser (tanggal lahir). */ const utc = (y: number, m0: number, d: number, h = 12, min = 0) => new Date(Date.UTC(y, m0, d, h, min, 0, 0)); +/** Waktu seed dijalankan — basis semua tanggal relatif. */ +const SEED_NOW = new Date(); + +/** + * Tanggal relatif terhadap waktu seed dijalankan — bikin seeder *evergreen*: + * kapan pun di-run, trip "OPEN" selalu di masa depan dan "COMPLETED" di masa + * lalu. `offsetDays` negatif = lampau, positif = mendatang. Hasil = tengah + * malam UTC, sinkron dengan trip yang dibuat lewat form (`tripStoredInstantFromYmd`). + */ +function relDate(offsetDays: number): Date { + const d = new Date(SEED_NOW); + d.setUTCDate(d.getUTCDate() + offsetDays); + d.setUTCHours(0, 0, 0, 0); + return d; +} + const img = (id: string) => `https://images.unsplash.com/photo-${id}?w=1200&q=80&auto=format&fit=crop`; +/** + * Kumpulan foto Unsplash per kategori — di-reuse antar trip supaya tidak ada + * URL gambar yang 404. Semua id sudah terverifikasi valid. + */ +const PHOTO = { + hiking: [ + "1554629947-334ff61d85dc", + "1464822759023-fed622ff2c3b", + "1480497490787-505ec076689f", + "1502085671122-2d218cd434e6", + ], + camping: ["1504280390367-361c6d9f38f4", "1517824806704-9040b037703b"], + beach: [ + "1583212292454-1fe6229603b7", + "1559825481-12a05cc00344", + "1507525428034-b723cf961d3e", + "1519046904884-53103b34b206", + ], + diving: ["1544551763-46a013bb70d5", "1566024287286-457247b70310"], + city: ["1596402184320-417e7178b2cd", "1583309217394-d191d747bc66"], + culinary: ["1565299624946-b28f40a0ae38"], + concert: ["1470229722913-7c0e2dbbafd3"], + workshop: ["1452587925148-ce544e77e70d", "1444080748397-f442aa95c3e5"], + retreat: ["1545389336-cf090694435e", "1518609878373-06d740f60d8b"], +} as const; + const SEED_PASSWORD = "password123"; // ============================================================================ @@ -248,13 +291,79 @@ const ITIN_RETREAT: SeedItineraryItem[] = [ { day: 3, startTime: "14:00", activity: "Trip resmi ditutup" }, ]; +const ITIN_PRAU: SeedItineraryItem[] = [ + { day: 1, startTime: "13:00", endTime: "13:30", activity: "Meeting & registrasi di basecamp Patak Banteng, Dieng" }, + { day: 1, startTime: "13:30", endTime: "14:00", activity: "Briefing + repacking + pemanasan" }, + { day: 1, startTime: "14:00", endTime: "17:00", activity: "Trekking Pos 1 — Pos 2 — Pos 3 menuju area camp puncak" }, + { day: 1, startTime: "17:00", endTime: "18:30", activity: "Setup tenda + makan sore + sunset" }, + { day: 1, startTime: "18:30", endTime: "21:00", activity: "Api unggun, kopi, sharing antar peserta" }, + { day: 1, startTime: "21:00", activity: "Istirahat" }, + { day: 2, startTime: "04:30", endTime: "05:00", activity: "Bangun + jalan ke spot sunrise" }, + { day: 2, startTime: "05:00", endTime: "06:30", activity: "Golden sunrise + Bukit Teletubbies + foto bareng" }, + { day: 2, startTime: "06:30", endTime: "08:30", activity: "Kembali ke camp + sarapan" }, + { day: 2, startTime: "08:30", endTime: "10:00", activity: "Beres tenda + repacking" }, + { day: 2, startTime: "10:00", endTime: "12:00", activity: "Turun ke basecamp Patak Banteng" }, + { day: 2, startTime: "12:00", activity: "Bersih-bersih, bubar grup" }, +]; + +const ITIN_BROMO: SeedItineraryItem[] = [ + { day: 1, startTime: "00:00", endTime: "00:30", activity: "Meeting di Cemoro Lawang + briefing" }, + { day: 1, startTime: "00:30", endTime: "03:00", activity: "Jeep menuju Penanjakan + posisi spot sunrise" }, + { day: 1, startTime: "03:00", endTime: "05:30", activity: "Menunggu + sunrise di view point Penanjakan" }, + { day: 1, startTime: "05:30", endTime: "07:00", activity: "Jeep ke lautan pasir + Pura Luhur Poten" }, + { day: 1, startTime: "07:00", endTime: "08:30", activity: "Trek tangga ke kawah Bromo" }, + { day: 1, startTime: "08:30", endTime: "10:00", activity: "Bukit Teletubbies + Pasir Berbisik (sesi foto)" }, + { day: 1, startTime: "10:00", endTime: "11:00", activity: "Sarapan + bersih-bersih" }, + { day: 1, startTime: "11:00", activity: "Bubar grup" }, +]; + +const ITIN_NUSAPENIDA: SeedItineraryItem[] = [ + { day: 1, startTime: "06:00", endTime: "06:30", activity: "Meeting di Sanur, Bali + briefing" }, + { day: 1, startTime: "06:30", endTime: "07:30", activity: "Fast boat Sanur menuju Nusa Penida" }, + { day: 1, startTime: "07:30", endTime: "09:30", activity: "Kelingking Beach — spot ikonik tebing T-Rex" }, + { day: 1, startTime: "09:30", endTime: "11:00", activity: "Angel's Billabong + Broken Beach" }, + { day: 1, startTime: "11:00", endTime: "12:30", activity: "Makan siang + istirahat" }, + { day: 1, startTime: "12:30", endTime: "14:30", activity: "Crystal Bay — snorkeling + santai pantai" }, + { day: 1, startTime: "14:30", endTime: "15:30", activity: "Fast boat kembali ke Sanur" }, + { day: 1, startTime: "15:30", activity: "Tiba di Sanur, bubar grup" }, +]; + +const ITIN_RINJANI: SeedItineraryItem[] = [ + { day: 1, startTime: "06:00", endTime: "07:00", activity: "Meeting & registrasi di basecamp Sembalun" }, + { day: 1, startTime: "07:00", endTime: "08:00", activity: "Sarapan + briefing + repacking bareng porter" }, + { day: 1, startTime: "08:00", endTime: "13:00", activity: "Trek Sembalun → Pos 1 → Pos 2 (sabana luas)" }, + { day: 1, startTime: "13:00", endTime: "14:00", activity: "ISHOMA di Pos 2" }, + { day: 1, startTime: "14:00", endTime: "17:00", activity: "Lanjut ke Pos 3 — Plawangan Sembalun" }, + { day: 1, startTime: "17:00", endTime: "19:00", activity: "Setup tenda + makan malam + sunset" }, + { day: 1, startTime: "19:00", activity: "Istirahat (summit dini hari)" }, + { day: 2, startTime: "02:00", endTime: "02:30", activity: "Bangun + minuman hangat + briefing summit" }, + { day: 2, startTime: "02:30", endTime: "06:00", activity: "Summit attack ke puncak Rinjani (3.726 mdpl)" }, + { day: 2, startTime: "06:00", endTime: "07:30", activity: "Sunrise di puncak + foto bareng" }, + { day: 2, startTime: "07:30", endTime: "10:30", activity: "Turun ke Plawangan + sarapan" }, + { day: 2, startTime: "10:30", endTime: "14:30", activity: "Turun ke Danau Segara Anak" }, + { day: 2, startTime: "14:30", endTime: "17:00", activity: "Camp di tepi danau + berendam air panas" }, + { day: 2, startTime: "17:00", endTime: "19:00", activity: "Makan malam + santai di tepi danau" }, + { day: 2, startTime: "19:00", activity: "Istirahat" }, + { day: 3, startTime: "06:00", endTime: "07:30", activity: "Sarapan + beres tenda" }, + { day: 3, startTime: "07:30", endTime: "13:00", activity: "Trek turun via Senaru (hutan tropis)" }, + { day: 3, startTime: "13:00", endTime: "14:00", activity: "Makan siang di basecamp Senaru" }, + { day: 3, startTime: "14:00", activity: "Bersih-bersih, bubar grup" }, +]; + // ============================================================================ -// 1. Cleanup — urutan FK aware (Payment → Booking → Review → Image → -// Participant → Trip → OrgVerification → Profile → Account → User). -// Seed wajib idempotent supaya `npm run seed` bisa di-run berulang. +// 1. Cleanup — hapus SEMUA data lama supaya tiap `npm run seed` mulai dari nol. +// Urutan FK-aware: Refund/Payout → Payment → Booking → Review → Image → +// Itinerary → Participant → Trip → OrgVerification → Profile → Account → +// User. Tabel log operasional (email/cron/audit) juga dibersihkan. // ============================================================================ async function cleanup() { + // Log operasional — tidak punya FK ke data inti, aman dihapus duluan. + await prisma.emailJob.deleteMany(); + await prisma.emailSent.deleteMany(); + await prisma.cronRun.deleteMany(); + await prisma.adminActionLog.deleteMany(); + // Refund & Payout pakai onDelete: Restrict ke Booking/Payment, jadi mereka // wajib dihapus duluan sebelum Booking/Payment bisa dibersihkan. await prisma.refund.deleteMany(); @@ -335,6 +444,30 @@ const SEED_USERS: SeedUser[] = [ vibe: "CHILL", }, }, + { + key: "rangga", + name: "Rangga Wisesa", + email: "rangga@setrip.id", + profile: { + bio: "Founder komunitas trip Jawa Timur. Hobi sunrise hunting & curug.", + city: "Malang", + interests: ["hiking", "camping", "fotografi"], + instagram: "rangga.wisesa", + vibe: "HARDCORE", + }, + }, + { + key: "ayu", + name: "Ayu Lestari", + email: "ayu@setrip.id", + profile: { + bio: "Open trip organizer Bali & NTT. Cinta laut, anti drama.", + city: "Denpasar", + interests: ["diving", "snorkeling", "island hopping"], + instagram: "ayu.lestari", + vibe: "BALANCED", + }, + }, // Peserta { key: "budi", @@ -393,6 +526,52 @@ const SEED_USERS: SeedUser[] = [ vibe: "HARDCORE", }, }, + { + key: "intan", + name: "Intan Permata", + email: "intan@gmail.com", + profile: { + bio: "Pencinta sunrise & kopi gunung. Lagi ngumpulin teman seperjalanan.", + city: "Bandung", + interests: ["hiking", "fotografi", "kuliner"], + instagram: "intan.permata", + vibe: "BALANCED", + }, + }, + { + key: "galih", + name: "Galih Nugraha", + email: "galih@gmail.com", + profile: { + bio: "Weekend hiker dari Semarang. Suka camping & ngobrol sampai pagi.", + city: "Semarang", + interests: ["hiking", "camping"], + vibe: "BALANCED", + }, + }, + { + key: "wina", + name: "Wina Oktaviani", + email: "wina@gmail.com", + profile: { + bio: "Beach person. Kerja remote, jalan tiap ada libur panjang.", + city: "Jakarta", + interests: ["snorkeling", "island hopping", "fotografi"], + instagram: "wina.okta", + vibe: "CHILL", + }, + }, + { + key: "bayu", + name: "Bayu Saputra", + email: "bayu@gmail.com", + profile: { + bio: "Hobi naik gunung sejak kuliah. Target: 7 summit Jawa.", + city: "Malang", + interests: ["hiking", "diving"], + vibe: "HARDCORE", + }, + }, ]; type UserMap = Record; @@ -480,6 +659,28 @@ const SEED_VERIFICATIONS: SeedVerification[] = [ bankAccountName: "Fiersa Besari", status: "APPROVED", }, + { + userKey: "rangga", + fullName: "Rangga Wisesa", + nik: "3573010101010004", + birthDate: utc(1991, 7, 20, 0, 0), + address: "Jl. Ijen No. 23, Malang, Jawa Timur", + bankName: "BRI", + bankAccountNumber: "3344556677", + bankAccountName: "Rangga Wisesa", + status: "APPROVED", + }, + { + userKey: "ayu", + fullName: "Ayu Lestari", + nik: "5171010101010005", + birthDate: utc(1993, 10, 8, 0, 0), + address: "Jl. Danau Tamblingan No. 5, Denpasar, Bali", + bankName: "BCA", + bankAccountNumber: "7788990011", + bankAccountName: "Ayu Lestari", + status: "APPROVED", + }, // Demo admin queue: PENDING + REJECTED { userKey: "doni", @@ -539,9 +740,9 @@ async function seedVerifications(users: UserMap, adminId: string) { } // ============================================================================ -// 4. Trips — mix masa depan (OPEN) & masa lalu (COMPLETED) + 1 CLOSED. -// Vibe diisi supaya filter & matching demo-able. -// Trip masa lalu jadi pondasi review + trust score. +// 4. Trips — semua tanggal RELATIF terhadap waktu seed (lihat `relDate`): +// COMPLETED/CLOSED < hari ini, OPEN/FULL > hari ini. Referensi destinasi +// & kisaran harga diambil dari listing open trip populer di Indonesia. // ============================================================================ interface SeedTripImage { @@ -570,81 +771,122 @@ interface SeedTrip { images: SeedTripImage[]; } -// 2026-05-10 = today (per CLAUDE.md). Trip masa lalu < hari ini, masa depan > hari ini. +/** Bangun daftar gambar dari pool kategori. */ +function pics( + pool: readonly string[], + captions: string[] +): SeedTripImage[] { + return captions.map((caption, i) => ({ + url: img(pool[i % pool.length]), + caption, + })); +} + const SEED_TRIPS: SeedTrip[] = [ - // ============ MASA LALU (sudah selesai — ada review) ============ + // ============ MASA LALU (COMPLETED — ada review) ============ { key: "past_papandayan", organizerKey: "dede", category: "HIKING", - title: "Open Trip Papandayan — Maret 2026", - description: `Pendakian santai ke Gunung Papandayan, batch Maret. Cocok untuk pemula.`, + title: "Open Trip Papandayan — Batch Lalu", + description: `Pendakian santai ke Gunung Papandayan. Cocok untuk pemula.`, meetingPoint: "Alun-alun Garut, 05:00 WIB", itineraryItems: ITIN_PAPANDAYAN, destination: "Gunung Papandayan", location: "Garut, Jawa Barat", - date: utc(2026, 2, 14, 22, 0), - endDate: utc(2026, 2, 15, 18, 0), + date: relDate(-67), + endDate: relDate(-66), maxParticipants: 10, price: 250000, vibe: "BALANCED", status: "COMPLETED", - images: [ - { url: img("1554629947-334ff61d85dc"), caption: "Kawah Papandayan" }, - { url: img("1464822759023-fed622ff2c3b"), caption: "Track menuju puncak" }, - ], + images: pics(PHOTO.hiking, ["Kawah Papandayan", "Track menuju puncak"]), }, { key: "past_pahawang", organizerKey: "panji", category: "SNORKELING", - title: "Snorkeling Pulau Pahawang — Februari 2026", - description: `Trip snorkeling batch Februari. Cuaca bersahabat, visibility 10m+.`, + title: "Snorkeling Pulau Pahawang — Batch Lalu", + description: `Trip snorkeling batch lalu. Cuaca bersahabat, visibility 10m+.`, meetingPoint: "Dermaga Ketapang, Lampung Selatan, 07:00 WIB", itineraryItems: ITIN_PAHAWANG, destination: "Pulau Pahawang Kecil", location: "Lampung Selatan, Lampung", - date: utc(2026, 1, 21, 0, 0), + date: relDate(-88), endDate: null, maxParticipants: 10, price: 380000, vibe: "CHILL", status: "COMPLETED", - images: [ - { url: img("1583212292454-1fe6229603b7"), caption: "Snorkeling di Pahawang" }, - ], + images: pics(PHOTO.beach, ["Snorkeling di Pahawang"]), }, { key: "past_culinary", organizerKey: "dede", category: "CULINARY", - title: "Kulineran Street Food Bandung — April 2026", - description: `Food tour batch April. 8 spot legend dilibas dalam satu hari.`, + title: "Kulineran Street Food Bandung — Batch Lalu", + description: `Food tour batch lalu. 8 spot legend dilibas dalam satu hari.`, meetingPoint: "Stasiun Bandung pintu utara, 09:00 WIB", itineraryItems: ITIN_CULINARY, destination: "Street Food Tour Bandung", location: "Bandung, Jawa Barat", - date: utc(2026, 3, 12, 0, 0), + date: relDate(-38), endDate: null, maxParticipants: 8, price: 175000, vibe: "CHILL", status: "COMPLETED", - images: [ - { url: img("1565299624946-b28f40a0ae38"), caption: "Street food" }, - ], + images: pics(PHOTO.culinary, ["Street food Bandung"]), }, + { + key: "past_prau", + organizerKey: "rangga", + category: "HIKING", + title: "Open Trip Gunung Prau Dieng — Batch Lalu", + description: `Sunrise camp di Prau, batch lalu. Cuaca cerah, lautan awan sempurna.`, + meetingPoint: "Basecamp Patak Banteng, Dieng, 13:00 WIB", + itineraryItems: ITIN_PRAU, + destination: "Gunung Prau", + location: "Wonosobo, Jawa Tengah", + date: relDate(-25), + endDate: relDate(-24), + maxParticipants: 15, + price: 320000, + vibe: "BALANCED", + status: "COMPLETED", + images: pics(PHOTO.hiking, ["Sunrise Gunung Prau", "Bukit Teletubbies"]), + }, + { + key: "past_nusapenida", + organizerKey: "ayu", + category: "ISLAND_HOPPING", + title: "Nusa Penida West Tour — Batch Lalu", + description: `One day tour Nusa Penida sisi barat. Kelingking, Crystal Bay, dan kawan-kawan.`, + meetingPoint: "Pantai Sanur, Bali, 06:00 WITA", + itineraryItems: ITIN_NUSAPENIDA, + destination: "Nusa Penida Barat", + location: "Klungkung, Bali", + date: relDate(-45), + endDate: null, + maxParticipants: 14, + price: 600000, + vibe: "BALANCED", + status: "COMPLETED", + images: pics(PHOTO.beach, ["Kelingking Beach", "Crystal Bay"]), + }, + + // ============ TRIP DIBATALKAN (CLOSED) ============ { key: "past_workshop_cancelled", organizerKey: "panji", category: "WORKSHOP", - title: "Workshop Astrofotografi Bromo — Januari 2026 (BATAL)", + title: "Workshop Astrofotografi Bromo (BATAL)", description: `Cuaca tidak mendukung. Trip dibatalkan H-3, peserta refund 100%.`, meetingPoint: "-", destination: "Astrofotografi Bromo", location: "Probolinggo, Jawa Timur", - date: utc(2026, 0, 18, 22, 0), - endDate: utc(2026, 0, 19, 12, 0), + date: relDate(-110), + endDate: relDate(-109), maxParticipants: 6, price: 950000, vibe: "HARDCORE", @@ -653,6 +895,106 @@ const SEED_TRIPS: SeedTrip[] = [ }, // ============ MASA DEPAN (OPEN — fitur join + bayar bisa di-test) ============ + { + key: "open_kotatua", + organizerKey: "fiersa", + category: "CITY_TRIP", + title: "Heritage Walk Kota Tua Jakarta", + description: `Jalan kaki menyusuri Batavia lama bareng pemandu sejarah. + +🚶 Santai, ramah pemula — cocok buat after-office Sabtu`, + meetingPoint: "Stasiun Jakarta Kota (BEOS), Sabtu 07:00 WIB", + whatsIncluded: `• Pemandu sejarah lokal +• Tiket Museum Fatahillah +• Snack + air mineral`, + whatsExcluded: `• Transport ke Kota Tua +• Makan siang`, + destination: "Kota Tua Jakarta", + location: "Jakarta Barat", + date: relDate(6), + endDate: null, + maxParticipants: 15, + price: 95000, + vibe: "CHILL", + status: "OPEN", + images: pics(PHOTO.city, ["Museum Fatahillah", "Sudut Kota Tua"]), + }, + { + key: "open_prau", + organizerKey: "rangga", + category: "HIKING", + title: "Open Trip Gunung Prau via Patak Banteng", + description: `Golden sunrise terbaik se-Jawa Tengah. 🌄 + +⛰️ Track pendek 2–3 jam — paling ramah pemula +🎒 Bawa: jaket tebal, sleeping bag, headlamp`, + meetingPoint: "Basecamp Patak Banteng, Dieng, Sabtu 13:00 WIB", + itineraryItems: ITIN_PRAU, + whatsIncluded: `• Tenda + matras tim +• Guide lokal +• Konsumsi 3x + air panas +• Tiket masuk + simaksi`, + whatsExcluded: `• Transport ke Dieng +• Sleeping bag pribadi`, + destination: "Gunung Prau", + location: "Wonosobo, Jawa Tengah", + date: relDate(7), + endDate: relDate(8), + maxParticipants: 15, + price: 320000, + vibe: "BALANCED", + status: "OPEN", + images: pics(PHOTO.hiking, ["Sunrise Gunung Prau", "Camp area puncak"]), + }, + { + key: "open_culinary", + organizerKey: "dede", + category: "CULINARY", + title: "Kulineran Street Food Bandung", + description: `Hopping 8 spot kuliner legend Bandung dalam satu hari. + +🍜 Cocok buat foodie & first-timer`, + meetingPoint: "Stasiun Bandung pintu utara, 09:00 WIB", + itineraryItems: ITIN_CULINARY, + whatsIncluded: `• Transport angkot/grup +• Tour leader food explorer +• Sample setiap spot (8 tempat)`, + whatsExcluded: `• Pembelian extra di luar sample`, + destination: "Street Food Tour Bandung", + location: "Bandung, Jawa Barat", + date: relDate(8), + endDate: null, + maxParticipants: 8, + price: 175000, + vibe: "CHILL", + status: "OPEN", + images: pics(PHOTO.culinary, ["Street food Bandung"]), + }, + { + key: "open_seribu", + organizerKey: "panji", + category: "SNORKELING", + title: "Open Trip Pulau Harapan 2D1N", + description: `Snorkeling hopping ala Maladewa-nya Jakarta. 🏝️ + +✅ Trip ini sudah PENUH — pantau jadwal batch berikutnya`, + meetingPoint: "Pelabuhan Kaliadem Muara Angke, Sabtu 06:00 WIB", + whatsIncluded: `• Kapal PP + boat hopping +• Homestay 1 malam +• Alat snorkel +• Makan 4x + BBQ`, + whatsExcluded: `• Transport ke Muara Angke +• Sewa kamera underwater`, + destination: "Pulau Harapan", + location: "Kepulauan Seribu, DKI Jakarta", + date: relDate(9), + endDate: relDate(10), + maxParticipants: 6, + price: 475000, + vibe: "CHILL", + status: "FULL", + images: pics(PHOTO.beach, ["Pasir putih Pulau Harapan", "Spot snorkeling"]), + }, { key: "open_papandayan", organizerKey: "dede", @@ -672,40 +1014,40 @@ const SEED_TRIPS: SeedTrip[] = [ • Asuransi perjalanan`, destination: "Gunung Papandayan", location: "Garut, Jawa Barat", - date: utc(2026, 5, 13, 22, 0), - endDate: utc(2026, 5, 14, 18, 0), + date: relDate(10), + endDate: relDate(11), maxParticipants: 10, price: 250000, vibe: "BALANCED", status: "OPEN", - images: [ - { url: img("1554629947-334ff61d85dc"), caption: "Kawah Papandayan" }, - { url: img("1464822759023-fed622ff2c3b"), caption: "Track menuju puncak" }, - ], + images: pics(PHOTO.hiking, ["Kawah Papandayan", "Track menuju puncak"]), }, { - key: "open_ciremai", - organizerKey: "panji", + key: "open_bromo", + organizerKey: "rangga", category: "HIKING", - title: "Pendakian Ciremai via Apuy", - description: `Trip ke puncak tertinggi Jawa Barat! 🏔️ + title: "Bromo Sunrise Midnight Trip", + description: `Berburu sunrise legendaris Bromo dari Penanjakan. 🌅 -📍 Meeting Point: Stasiun Kuningan, 04:00 WIB -⚠️ Level: Menengah — perlu stamina baik`, - meetingPoint: "Stasiun Kuningan, Sabtu 04:00 WIB", - itineraryItems: ITIN_CIREMAI, - destination: "Gunung Ciremai", - location: "Kuningan, Jawa Barat", - date: utc(2026, 5, 23, 4, 0), - endDate: utc(2026, 5, 24, 18, 0), - maxParticipants: 8, - price: 350000, - vibe: "HARDCORE", +🚙 Naik jeep 4x4 — gak perlu trekking berat +📷 Spot foto: kawah, lautan pasir, Bukit Teletubbies`, + meetingPoint: "Cemoro Lawang, Probolinggo, 00:00 WIB", + itineraryItems: ITIN_BROMO, + whatsIncluded: `• Jeep wisata 4x4 +• Guide lokal +• Tiket masuk kawasan TNBTS +• Sarapan ringan`, + whatsExcluded: `• Transport ke Cemoro Lawang +• Sewa kuda ke kawah`, + destination: "Gunung Bromo", + location: "Probolinggo, Jawa Timur", + date: relDate(12), + endDate: null, + maxParticipants: 12, + price: 475000, + vibe: "BALANCED", status: "OPEN", - images: [ - { url: img("1480497490787-505ec076689f"), caption: "Puncak Ciremai 3.078 mdpl" }, - { url: img("1502085671122-2d218cd434e6"), caption: "Sunrise dari puncak" }, - ], + images: pics(PHOTO.hiking, ["Sunrise Bromo", "Lautan pasir"]), }, { key: "open_camping", @@ -727,16 +1069,165 @@ const SEED_TRIPS: SeedTrip[] = [ • Snack tambahan`, destination: "Ranca Upas", location: "Bandung Selatan, Jawa Barat", - date: utc(2026, 5, 16, 6, 0), - endDate: utc(2026, 5, 17, 12, 0), + date: relDate(13), + endDate: relDate(14), maxParticipants: 12, price: 220000, vibe: "CHILL", status: "OPEN", - images: [ - { url: img("1504280390367-361c6d9f38f4"), caption: "Tenda di hutan pinus" }, - { url: img("1517824806704-9040b037703b"), caption: "Sunset di camp" }, - ], + images: pics(PHOTO.camping, ["Tenda di hutan pinus", "Sunset di camp"]), + }, + { + key: "open_semarang_kuliner", + organizerKey: "rangga", + category: "CULINARY", + title: "Kulineran Heritage Semarang", + description: `Susur kuliner legendaris Semarang sambil jalan di Kota Lama. + +🥟 Lumpia, tahu gimbal, nasi ayam, sampai es puter`, + meetingPoint: "Stasiun Semarang Tawang, 09:00 WIB", + whatsIncluded: `• Tour leader food explorer +• Sample 7 spot kuliner +• Air mineral`, + whatsExcluded: `• Transport ke Semarang +• Pembelian di luar sample`, + destination: "Kuliner Kota Lama Semarang", + location: "Semarang, Jawa Tengah", + date: relDate(15), + endDate: null, + maxParticipants: 10, + price: 185000, + vibe: "CHILL", + status: "OPEN", + images: pics(PHOTO.culinary, ["Kuliner Semarang"]), + }, + { + key: "open_nusapenida", + organizerKey: "ayu", + category: "ISLAND_HOPPING", + title: "Nusa Penida West One Day Trip", + description: `Eksplor spot ikonik Nusa Penida sisi barat dalam sehari. + +🏝️ Kelingking, Angel's Billabong, Broken Beach, Crystal Bay`, + meetingPoint: "Pantai Sanur, Bali, 06:00 WITA", + itineraryItems: ITIN_NUSAPENIDA, + whatsIncluded: `• Fast boat PP Sanur–Nusa Penida +• Mobil + sopir lokal seharian +• Makan siang +• Tiket masuk semua spot`, + whatsExcluded: `• Transport ke Sanur +• Alat snorkel (sewa di lokasi)`, + destination: "Nusa Penida Barat", + location: "Klungkung, Bali", + date: relDate(16), + endDate: null, + maxParticipants: 14, + price: 625000, + vibe: "BALANCED", + status: "OPEN", + images: pics(PHOTO.beach, ["Kelingking Beach", "Broken Beach"]), + }, + { + key: "open_citytrip", + organizerKey: "fiersa", + category: "CITY_TRIP", + title: "City Trip Jogja Hidden Gems", + description: `Bukan Malioboro lagi. Trip jelajah Jogja sisi 'lokal'. + +🚐 Mobil grup, bukan tour bus`, + meetingPoint: "Stasiun Tugu Yogyakarta, Sabtu 08:00 WIB", + itineraryItems: ITIN_CITYTRIP, + whatsIncluded: `• Transport mobil grup 2 hari +• Tour leader lokal +• Makan 3x (kuliner lokal) +• Tiket masuk semua spot`, + whatsExcluded: `• Transport ke Jogja +• Penginapan (rekomendasi disediakan)`, + destination: "Yogyakarta", + location: "Yogyakarta", + date: relDate(18), + endDate: relDate(19), + maxParticipants: 8, + price: 650000, + vibe: "BALANCED", + status: "OPEN", + images: pics(PHOTO.city, ["Tamansari", "Sudut Jogja"]), + }, + { + key: "open_ciremai", + organizerKey: "panji", + category: "HIKING", + title: "Pendakian Ciremai via Apuy", + description: `Trip ke puncak tertinggi Jawa Barat! 🏔️ + +📍 Meeting Point: Stasiun Kuningan, 04:00 WIB +⚠️ Level: Menengah — perlu stamina baik`, + meetingPoint: "Stasiun Kuningan, Sabtu 04:00 WIB", + itineraryItems: ITIN_CIREMAI, + whatsIncluded: `• Transport PP Kuningan–basecamp +• Guide + porter logistik +• Tenda tim + konsumsi 4x +• Simaksi`, + whatsExcluded: `• Sleeping bag pribadi +• Asuransi perjalanan`, + destination: "Gunung Ciremai", + location: "Kuningan, Jawa Barat", + date: relDate(20), + endDate: relDate(21), + maxParticipants: 8, + price: 350000, + vibe: "HARDCORE", + status: "OPEN", + images: pics(PHOTO.hiking, ["Puncak Ciremai 3.078 mdpl", "Sunrise dari puncak"]), + }, + { + key: "open_sentul_camp", + organizerKey: "rangga", + category: "CAMPING", + title: "Camping & Curug Hunting Sentul", + description: `Camping di tepi sungai + main air di curug-curug Sentul. + +💧 Leuwi Hejo, Leuwi Lieuk — air jernih kebiruan`, + meetingPoint: "Pertigaan Sentul City, Bogor, Sabtu 09:00 WIB", + whatsIncluded: `• Tenda + matras + sleeping bag +• Guide curug lokal +• Makan 3x + BBQ malam +• Tiket masuk semua curug`, + whatsExcluded: `• Transport ke Sentul +• Sandal gunung pribadi`, + destination: "Curug Leuwi Hejo", + location: "Bogor, Jawa Barat", + date: relDate(22), + endDate: relDate(23), + maxParticipants: 14, + price: 265000, + vibe: "CHILL", + status: "OPEN", + images: pics(PHOTO.camping, ["Camp tepi sungai", "Curug Leuwi Hejo"]), + }, + { + key: "open_merbabu", + organizerKey: "panji", + category: "HIKING", + title: "Pendakian Merbabu via Suwanting", + description: `Sabana Merbabu yang ikonik — salah satu jalur terindah di Jawa. 🌾 + +⚠️ Level: Menengah–lanjut, jalur panjang & menanjak`, + meetingPoint: "Basecamp Suwanting, Magelang, Sabtu 05:00 WIB", + whatsIncluded: `• Guide + porter logistik +• Tenda tim + konsumsi 4x +• Simaksi + tiket masuk`, + whatsExcluded: `• Transport ke Magelang +• Sleeping bag & jaket pribadi`, + destination: "Gunung Merbabu", + location: "Magelang, Jawa Tengah", + date: relDate(24), + endDate: relDate(25), + maxParticipants: 10, + price: 375000, + vibe: "HARDCORE", + status: "OPEN", + images: pics(PHOTO.hiking, ["Sabana Merbabu", "Jalur Suwanting"]), }, { key: "open_snorkel", @@ -757,159 +1248,39 @@ const SEED_TRIPS: SeedTrip[] = [ • Penginapan Sabtu malam`, destination: "Pulau Pahawang Kecil", location: "Lampung Selatan, Lampung", - date: utc(2026, 5, 30, 0, 0), + date: relDate(27), endDate: null, maxParticipants: 10, price: 380000, vibe: "CHILL", status: "OPEN", - images: [ - { url: img("1583212292454-1fe6229603b7"), caption: "Snorkeling di Pahawang" }, - { url: img("1559825481-12a05cc00344"), caption: "Pasir putih Pahawang Kecil" }, - ], + images: pics(PHOTO.beach, ["Snorkeling di Pahawang", "Pasir putih Pahawang"]), }, { - key: "open_diving", - organizerKey: "fiersa", + key: "open_lembongan_dive", + organizerKey: "ayu", category: "DIVING", - title: "Fun Dive Tulamben — USS Liberty Wreck", - description: `Dive trip ke USS Liberty Wreck. + title: "Fun Dive Nusa Lembongan — Manta Point", + description: `Diving bareng manta ray raksasa di Manta Bay! 🐠 -⚠️ Sertifikasi minimal: Open Water (PADI/SSI)`, - meetingPoint: "Dive shop Tulamben, 06:30 WITA", - itineraryItems: ITIN_DIVING, - whatsIncluded: `• 2x dive guided -• Full gear rental -• Tank & weight -• Konsumsi siang`, - whatsExcluded: `• Transport ke Bali -• Penginapan +⚠️ Sertifikasi minimal: Open Water (PADI/SSI) +🌊 Arus sedang — bukan untuk dive pertama`, + meetingPoint: "Dive center Sanur, Bali, 07:00 WITA", + whatsIncluded: `• 2x dive guided (Manta Point + Crystal Bay) +• Full gear + tank & weight +• Fast boat PP +• Makan siang`, + whatsExcluded: `• Transport ke Sanur • Sertifikasi (cek validitas)`, - destination: "USS Liberty Wreck", - location: "Tulamben, Karangasem, Bali", - date: utc(2026, 6, 4, 0, 0), - endDate: utc(2026, 6, 5, 12, 0), + destination: "Manta Point Nusa Lembongan", + location: "Klungkung, Bali", + date: relDate(29), + endDate: relDate(30), maxParticipants: 6, - price: 1850000, + price: 1550000, vibe: "HARDCORE", status: "OPEN", - images: [ - { url: img("1544551763-46a013bb70d5"), caption: "Wreck dive Tulamben" }, - { url: img("1566024287286-457247b70310"), caption: "Reef Tulamben" }, - ], - }, - { - key: "open_islandhop", - organizerKey: "panji", - category: "ISLAND_HOPPING", - title: "Karimun Jawa Island Hopping 3D2N", - description: `Hopping 5 pulau favorit di Karimun Jawa. - -🏝️ Cocok untuk solo traveler & couple`, - meetingPoint: "Pelabuhan Kartini Jepara, Jumat 07:00 WIB", - itineraryItems: ITIN_ISLANDHOP, - whatsIncluded: `• Tiket kapal feri PP Jepara–Karimun -• Homestay 2 malam (twin sharing) -• Boat hopping 2 hari -• Alat snorkel -• Makan 6x`, - whatsExcluded: `• Transport ke Jepara -• Tiket pesawat`, - destination: "Kepulauan Karimun Jawa", - location: "Jepara, Jawa Tengah", - date: utc(2026, 6, 12, 0, 0), - endDate: utc(2026, 6, 14, 18, 0), - maxParticipants: 12, - price: 1450000, - vibe: "BALANCED", - status: "OPEN", - images: [ - { url: img("1507525428034-b723cf961d3e"), caption: "Pantai Karimun" }, - { url: img("1519046904884-53103b34b206"), caption: "Boat hopping" }, - ], - }, - { - key: "open_citytrip", - organizerKey: "fiersa", - category: "CITY_TRIP", - title: "City Trip Jogja Hidden Gems", - description: `Bukan Malioboro lagi. Trip jelajah Jogja sisi 'lokal'. - -🚐 Mobil grup, bukan tour bus`, - meetingPoint: "Stasiun Tugu Yogyakarta, Sabtu 08:00 WIB", - itineraryItems: ITIN_CITYTRIP, - whatsIncluded: `• Transport mobil grup 2 hari -• Tour leader lokal -• Makan 3x (kuliner lokal) -• Tiket masuk semua spot`, - whatsExcluded: `• Transport ke Jogja -• Penginapan (rekomendasi disediakan)`, - destination: "Yogyakarta", - location: "Yogyakarta", - date: utc(2026, 5, 22, 0, 0), - endDate: utc(2026, 5, 23, 20, 0), - maxParticipants: 8, - price: 650000, - vibe: "BALANCED", - status: "OPEN", - images: [ - { url: img("1596402184320-417e7178b2cd"), caption: "Tamansari" }, - { url: img("1583309217394-d191d747bc66"), caption: "Sudut Jogja" }, - ], - }, - { - key: "open_culinary", - organizerKey: "dede", - category: "CULINARY", - title: "Kulineran Street Food Bandung", - description: `Hopping 8 spot kuliner legend Bandung dalam satu hari. - -🍜 Cocok buat foodie & first-timer`, - meetingPoint: "Stasiun Bandung pintu utara, 09:00 WIB", - itineraryItems: ITIN_CULINARY, - whatsIncluded: `• Transport angkot/grup -• Tour leader food explorer -• Sample setiap spot (8 tempat)`, - whatsExcluded: `• Pembelian extra di luar sample`, - destination: "Street Food Tour Bandung", - location: "Bandung, Jawa Barat", - date: utc(2026, 5, 17, 0, 0), - endDate: null, - maxParticipants: 8, - price: 175000, - vibe: "CHILL", - status: "OPEN", - images: [ - { url: img("1565299624946-b28f40a0ae38"), caption: "Street food" }, - ], - }, - { - key: "open_concert", - organizerKey: "fiersa", - category: "CONCERT", - title: "Nonton Coldplay Bareng — Music of the Spheres Jakarta", - description: `Cari teman buat nonton Coldplay tapi gak mau nonton sendirian? Gabung grup ini. - -🎤 Tiket BUKAN termasuk — peserta bawa tiket masing-masing -🤝 Grup hanya untuk koordinasi meet-up & after-party`, - meetingPoint: "Plaza GBK, depan loket Cat 1, 17:00 WIB", - itineraryItems: ITIN_CONCERT, - whatsIncluded: `• Koordinasi grup -• Foto bareng pre-show -• After-party dinner di Senayan`, - whatsExcluded: `• Tiket konser (bawa sendiri!) -• Transport ke GBK`, - destination: "Coldplay — Music of the Spheres", - location: "Stadion Utama GBK, Jakarta", - date: utc(2026, 6, 20, 10, 0), - endDate: null, - maxParticipants: 6, - price: 0, // Free trip — booking langsung PAID saat di-confirm - vibe: "BALANCED", - status: "OPEN", - images: [ - { url: img("1470229722913-7c0e2dbbafd3"), caption: "Konser malam" }, - ], + images: pics(PHOTO.diving, ["Manta ray", "Reef Nusa Lembongan"]), }, { key: "open_workshop", @@ -930,16 +1301,221 @@ const SEED_TRIPS: SeedTrip[] = [ • Transport ke Pangalengan`, destination: "Fotografi Lanskap", location: "Pangalengan, Bandung Selatan", - date: utc(2026, 6, 6, 0, 0), - endDate: utc(2026, 6, 7, 18, 0), + date: relDate(30), + endDate: relDate(31), maxParticipants: 6, price: 850000, vibe: "BALANCED", status: "OPEN", - images: [ - { url: img("1452587925148-ce544e77e70d"), caption: "Sunrise kebun teh" }, - { url: img("1444080748397-f442aa95c3e5"), caption: "Workshop on-field" }, - ], + images: pics(PHOTO.workshop, ["Sunrise kebun teh", "Workshop on-field"]), + }, + { + key: "open_diving", + organizerKey: "fiersa", + category: "DIVING", + title: "Fun Dive Tulamben — USS Liberty Wreck", + description: `Dive trip ke USS Liberty Wreck. + +⚠️ Sertifikasi minimal: Open Water (PADI/SSI)`, + meetingPoint: "Dive shop Tulamben, 06:30 WITA", + itineraryItems: ITIN_DIVING, + whatsIncluded: `• 2x dive guided +• Full gear rental +• Tank & weight +• Konsumsi siang`, + whatsExcluded: `• Transport ke Bali +• Penginapan +• Sertifikasi (cek validitas)`, + destination: "USS Liberty Wreck", + location: "Tulamben, Karangasem, Bali", + date: relDate(33), + endDate: relDate(34), + maxParticipants: 6, + price: 1850000, + vibe: "HARDCORE", + status: "OPEN", + images: pics(PHOTO.diving, ["Wreck dive Tulamben", "Reef Tulamben"]), + }, + { + key: "open_festival", + organizerKey: "fiersa", + category: "CONCERT", + title: "Nonton Festival Musik Bareng — Pestapora", + description: `Cari rombongan buat nonton festival musik biar gak sendirian? + +🎫 Tiket BUKAN termasuk — peserta bawa masing-masing +🤝 Grup untuk koordinasi meet-up, line-up favorit & pulang bareng`, + meetingPoint: "Gate utama venue, 15:00 WIB", + whatsIncluded: `• Koordinasi grup + grup WA +• Foto bareng +• Atur jadwal nonton line-up favorit`, + whatsExcluded: `• Tiket festival (bawa sendiri!) +• Transport ke venue`, + destination: "Festival Musik Pestapora", + location: "Jakarta", + date: relDate(33), + endDate: null, + maxParticipants: 8, + price: 0, + vibe: "BALANCED", + status: "OPEN", + images: pics(PHOTO.concert, ["Festival musik"]), + }, + { + key: "open_rinjani", + organizerKey: "ayu", + category: "HIKING", + title: "Pendakian Rinjani Summit 3D2N via Sembalun", + description: `Summit Rinjani 3.726 mdpl + camp di tepi Danau Segara Anak. 🏔️ + +⚠️ Level: LANJUT — wajib fisik prima & pengalaman gunung +🔥 Salah satu pendakian terbaik di Indonesia`, + meetingPoint: "Basecamp Sembalun, Lombok Timur, 06:00 WITA", + itineraryItems: ITIN_RINJANI, + whatsIncluded: `• Guide + porter + tenda tim +• Konsumsi 8x selama trek +• Simaksi TN Gunung Rinjani +• Transport basecamp PP Mataram`, + whatsExcluded: `• Tiket pesawat ke Lombok +• Sleeping bag & carrier pribadi +• Asuransi perjalanan`, + destination: "Gunung Rinjani", + location: "Lombok Timur, NTB", + date: relDate(35), + endDate: relDate(37), + maxParticipants: 10, + price: 2750000, + vibe: "HARDCORE", + status: "OPEN", + images: pics(PHOTO.hiking, ["Puncak Rinjani", "Danau Segara Anak"]), + }, + { + key: "open_belitung", + organizerKey: "ayu", + category: "ISLAND_HOPPING", + title: "Belitung Island Hopping 3D2N", + description: `Pulau-pulau batu granit raksasa & pantai pasir sehalus tepung. + +🪨 Pulau Lengkuas (mercusuar), Pulau Batu Berlayar, Tanjung Tinggi`, + meetingPoint: "Bandara H.A.S. Hanandjoeddin, Tanjung Pandan", + whatsIncluded: `• Penginapan 2 malam +• Boat hopping + alat snorkel +• Mobil + sopir selama trip +• Makan 6x`, + whatsExcluded: `• Tiket pesawat ke Belitung +• Pengeluaran pribadi`, + destination: "Kepulauan Belitung", + location: "Belitung, Bangka Belitung", + date: relDate(38), + endDate: relDate(39), + maxParticipants: 12, + price: 1350000, + vibe: "BALANCED", + status: "OPEN", + images: pics(PHOTO.beach, ["Pulau Lengkuas", "Pantai batu granit"]), + }, + { + key: "open_islandhop", + organizerKey: "panji", + category: "ISLAND_HOPPING", + title: "Karimun Jawa Island Hopping 3D2N", + description: `Hopping 5 pulau favorit di Karimun Jawa. + +🏝️ Cocok untuk solo traveler & couple`, + meetingPoint: "Pelabuhan Kartini Jepara, Jumat 07:00 WIB", + itineraryItems: ITIN_ISLANDHOP, + whatsIncluded: `• Tiket kapal feri PP Jepara–Karimun +• Homestay 2 malam (twin sharing) +• Boat hopping 2 hari +• Alat snorkel +• Makan 6x`, + whatsExcluded: `• Transport ke Jepara +• Tiket pesawat`, + destination: "Kepulauan Karimun Jawa", + location: "Jepara, Jawa Tengah", + date: relDate(40), + endDate: relDate(42), + maxParticipants: 12, + price: 1450000, + vibe: "BALANCED", + status: "OPEN", + images: pics(PHOTO.beach, ["Pantai Karimun", "Boat hopping"]), + }, + { + key: "open_ijen", + organizerKey: "rangga", + category: "HIKING", + title: "Kawah Ijen Blue Fire Tour", + description: `Fenomena api biru langka — hanya ada 2 di dunia. 🔥💙 + +⚠️ Trek malam, wajib masker gas (disediakan) +🌅 Lanjut sunrise di kawah belerang toska`, + meetingPoint: "Pos Paltuding, Banyuwangi, 00:30 WIB", + whatsIncluded: `• Guide lokal + masker gas +• Tiket masuk kawasan +• Sarapan + kopi`, + whatsExcluded: `• Transport ke Banyuwangi +• Sewa headlamp`, + destination: "Kawah Ijen", + location: "Banyuwangi, Jawa Timur", + date: relDate(41), + endDate: relDate(42), + maxParticipants: 12, + price: 525000, + vibe: "HARDCORE", + status: "OPEN", + images: pics(PHOTO.hiking, ["Kawah Ijen", "Sunrise di kawah"]), + }, + { + key: "open_concert", + organizerKey: "fiersa", + category: "CONCERT", + title: "Nonton Coldplay Bareng — Music of the Spheres Jakarta", + description: `Cari teman buat nonton Coldplay tapi gak mau nonton sendirian? Gabung grup ini. + +🎤 Tiket BUKAN termasuk — peserta bawa tiket masing-masing +🤝 Grup hanya untuk koordinasi meet-up & after-party`, + meetingPoint: "Plaza GBK, depan loket Cat 1, 17:00 WIB", + itineraryItems: ITIN_CONCERT, + whatsIncluded: `• Koordinasi grup +• Foto bareng pre-show +• After-party dinner di Senayan`, + whatsExcluded: `• Tiket konser (bawa sendiri!) +• Transport ke GBK`, + destination: "Coldplay — Music of the Spheres", + location: "Stadion Utama GBK, Jakarta", + date: relDate(45), + endDate: null, + maxParticipants: 6, + price: 0, + vibe: "BALANCED", + status: "OPEN", + images: pics(PHOTO.concert, ["Konser malam"]), + }, + { + key: "open_komodo", + organizerKey: "ayu", + category: "ISLAND_HOPPING", + title: "Sailing Komodo 3D2N — Open Trip Phinisi", + description: `Live-on-board kapal phinisi keliling Taman Nasional Komodo. ⛵ + +🦎 Pulau Padar, Pink Beach, ketemu komodo, Manta Point`, + meetingPoint: "Pelabuhan Labuan Bajo, Flores, 08:00 WITA", + whatsIncluded: `• Kapal phinisi (kabin sharing) 2 malam +• Makan 8x + snack +• Alat snorkel +• Tiket masuk TN Komodo + ranger`, + whatsExcluded: `• Tiket pesawat ke Labuan Bajo +• Tipping kru kapal`, + destination: "Taman Nasional Komodo", + location: "Labuan Bajo, NTT", + date: relDate(50), + endDate: relDate(52), + maxParticipants: 16, + price: 3650000, + vibe: "BALANCED", + status: "OPEN", + images: pics(PHOTO.beach, ["Pulau Padar", "Pink Beach Komodo"]), }, { key: "open_retreat", @@ -961,16 +1537,39 @@ const SEED_TRIPS: SeedTrip[] = [ • Treatment spa opsional`, destination: "Mindfulness Retreat Ubud", location: "Ubud, Gianyar, Bali", - date: utc(2026, 6, 26, 0, 0), - endDate: utc(2026, 6, 28, 14, 0), + date: relDate(52), + endDate: relDate(54), maxParticipants: 8, price: 2400000, vibe: "CHILL", status: "OPEN", - images: [ - { url: img("1545389336-cf090694435e"), caption: "Yoga di sawah Ubud" }, - { url: img("1518609878373-06d740f60d8b"), caption: "Villa retreat" }, - ], + images: pics(PHOTO.retreat, ["Yoga di sawah Ubud", "Villa retreat"]), + }, + { + key: "open_yoga_retreat", + organizerKey: "fiersa", + category: "RETREAT", + title: "Weekend Yoga & Digital Detox — Selabintana", + description: `Lepas dari notifikasi 2 hari penuh di kaki Gunung Gede. + +📵 Digital detox — HP dititip saat sesi +🧘 Yoga, hiking ringan, journaling`, + meetingPoint: "Resort Selabintana, Sukabumi, Sabtu 13:00 WIB", + whatsIncluded: `• Penginapan resort 1 malam +• Yoga 3 sesi + meditasi +• Hiking ringan berpemandu +• Konsumsi sehat 4x`, + whatsExcluded: `• Transport ke Sukabumi +• Treatment tambahan`, + destination: "Yoga Retreat Selabintana", + location: "Sukabumi, Jawa Barat", + date: relDate(58), + endDate: relDate(60), + maxParticipants: 10, + price: 1950000, + vibe: "CHILL", + status: "OPEN", + images: pics(PHOTO.retreat, ["Sesi yoga pagi", "Resort di kaki gunung"]), }, ]; @@ -1071,65 +1670,147 @@ const SEED_PARTICIPANTS: SeedParticipant[] = [ { tripKey: "past_culinary", userKey: "doni", intent: "PAID" }, { tripKey: "past_culinary", userKey: "raka", intent: "CANCELLED" }, // batal H-1 + { tripKey: "past_prau", userKey: "budi", intent: "PAID" }, + { tripKey: "past_prau", userKey: "intan", intent: "PAID" }, + { tripKey: "past_prau", userKey: "galih", intent: "PAID" }, + + { tripKey: "past_nusapenida", userKey: "sari", intent: "PAID" }, + { tripKey: "past_nusapenida", userKey: "wina", intent: "PAID" }, + { tripKey: "past_nusapenida", userKey: "bayu", intent: "PAID" }, + // CLOSED trip — peserta yang ke-refund (di-mark CANCELLED) { tripKey: "past_workshop_cancelled", userKey: "budi", intent: "CANCELLED" }, { tripKey: "past_workshop_cancelled", userKey: "doni", intent: "CANCELLED" }, // ---------- TRIP MASA DEPAN — mix state ---------- - // Papandayan — campur semua state biar dashboard organizer kaya - { tripKey: "open_papandayan", userKey: "budi", intent: "PAID" }, - { tripKey: "open_papandayan", userKey: "sari", intent: "MARKED_PAID" }, - { tripKey: "open_papandayan", userKey: "doni", intent: "AWAITING_PAY" }, - { tripKey: "open_papandayan", userKey: "raka", intent: "PENDING_REQUEST" }, + // Kota Tua + { tripKey: "open_kotatua", userKey: "galih", intent: "PAID" }, + { tripKey: "open_kotatua", userKey: "wina", intent: "PAID" }, + { tripKey: "open_kotatua", userKey: "intan", intent: "PAID" }, + { tripKey: "open_kotatua", userKey: "raka", intent: "PENDING_REQUEST" }, - // Ciremai — 2 confirmed paid - { tripKey: "open_ciremai", userKey: "budi", intent: "PAID" }, - { tripKey: "open_ciremai", userKey: "maya", intent: "AWAITING_PAY" }, + // Prau + { tripKey: "open_prau", userKey: "intan", intent: "PAID" }, + { tripKey: "open_prau", userKey: "galih", intent: "AWAITING_PAY" }, + { tripKey: "open_prau", userKey: "bayu", intent: "PENDING_REQUEST" }, - // Camping — 5 peserta variasi - { tripKey: "open_camping", userKey: "budi", intent: "PAID" }, - { tripKey: "open_camping", userKey: "sari", intent: "PAID" }, - { tripKey: "open_camping", userKey: "doni", intent: "MARKED_PAID" }, - { tripKey: "open_camping", userKey: "maya", intent: "AWAITING_PAY" }, - { tripKey: "open_camping", userKey: "raka", intent: "PENDING_REQUEST" }, - - // Snorkeling - { tripKey: "open_snorkel", userKey: "sari", intent: "PAID" }, - { tripKey: "open_snorkel", userKey: "maya", intent: "MARKED_PAID" }, - { tripKey: "open_snorkel", userKey: "raka", intent: "PENDING_REQUEST" }, - - // Diving — mahal, sedikit peserta - { tripKey: "open_diving", userKey: "doni", intent: "AWAITING_PAY" }, - - // Island hop - { tripKey: "open_islandhop", userKey: "budi", intent: "PAID" }, - { tripKey: "open_islandhop", userKey: "sari", intent: "PAID" }, - { tripKey: "open_islandhop", userKey: "maya", intent: "MARKED_PAID" }, - { tripKey: "open_islandhop", userKey: "raka", intent: "PENDING_REQUEST" }, - - // City trip - { tripKey: "open_citytrip", userKey: "budi", intent: "PAID" }, - { tripKey: "open_citytrip", userKey: "maya", intent: "PAID" }, - { tripKey: "open_citytrip", userKey: "sari", intent: "PENDING_REQUEST" }, - - // Culinary — penuh + // Culinary Bandung — penuh joiner { tripKey: "open_culinary", userKey: "budi", intent: "PAID" }, { tripKey: "open_culinary", userKey: "sari", intent: "PAID" }, { tripKey: "open_culinary", userKey: "doni", intent: "PAID" }, { tripKey: "open_culinary", userKey: "maya", intent: "PAID" }, { tripKey: "open_culinary", userKey: "raka", intent: "PAID" }, - // Concert (FREE) — Booking langsung PAID + // Pulau Harapan — FULL (6 peserta = maxParticipants) + { tripKey: "open_seribu", userKey: "budi", intent: "PAID" }, + { tripKey: "open_seribu", userKey: "sari", intent: "PAID" }, + { tripKey: "open_seribu", userKey: "maya", intent: "PAID" }, + { tripKey: "open_seribu", userKey: "raka", intent: "PAID" }, + { tripKey: "open_seribu", userKey: "intan", intent: "PAID" }, + { tripKey: "open_seribu", userKey: "galih", intent: "PAID" }, + + // Papandayan — campur semua state biar dashboard organizer kaya + { tripKey: "open_papandayan", userKey: "budi", intent: "PAID" }, + { tripKey: "open_papandayan", userKey: "sari", intent: "MARKED_PAID" }, + { tripKey: "open_papandayan", userKey: "doni", intent: "AWAITING_PAY" }, + { tripKey: "open_papandayan", userKey: "raka", intent: "PENDING_REQUEST" }, + + // Bromo + { tripKey: "open_bromo", userKey: "budi", intent: "PAID" }, + { tripKey: "open_bromo", userKey: "wina", intent: "PAID" }, + { tripKey: "open_bromo", userKey: "raka", intent: "MARKED_PAID" }, + { tripKey: "open_bromo", userKey: "intan", intent: "PENDING_REQUEST" }, + + // Camping Ranca Upas + { tripKey: "open_camping", userKey: "budi", intent: "PAID" }, + { tripKey: "open_camping", userKey: "sari", intent: "PAID" }, + { tripKey: "open_camping", userKey: "doni", intent: "MARKED_PAID" }, + { tripKey: "open_camping", userKey: "maya", intent: "AWAITING_PAY" }, + { tripKey: "open_camping", userKey: "raka", intent: "PENDING_REQUEST" }, + + // Kuliner Semarang + { tripKey: "open_semarang_kuliner", userKey: "budi", intent: "PAID" }, + { tripKey: "open_semarang_kuliner", userKey: "galih", intent: "PAID" }, + { tripKey: "open_semarang_kuliner", userKey: "bayu", intent: "MARKED_PAID" }, + + // Nusa Penida + { tripKey: "open_nusapenida", userKey: "sari", intent: "PAID" }, + { tripKey: "open_nusapenida", userKey: "maya", intent: "PAID" }, + { tripKey: "open_nusapenida", userKey: "wina", intent: "MARKED_PAID" }, + + // City trip Jogja + { tripKey: "open_citytrip", userKey: "budi", intent: "PAID" }, + { tripKey: "open_citytrip", userKey: "maya", intent: "PAID" }, + { tripKey: "open_citytrip", userKey: "sari", intent: "PENDING_REQUEST" }, + + // Ciremai + { tripKey: "open_ciremai", userKey: "budi", intent: "PAID" }, + { tripKey: "open_ciremai", userKey: "maya", intent: "AWAITING_PAY" }, + + // Camping & curug Sentul + { tripKey: "open_sentul_camp", userKey: "intan", intent: "PAID" }, + { tripKey: "open_sentul_camp", userKey: "wina", intent: "AWAITING_PAY" }, + { tripKey: "open_sentul_camp", userKey: "raka", intent: "PENDING_REQUEST" }, + + // Merbabu + { tripKey: "open_merbabu", userKey: "galih", intent: "PAID" }, + { tripKey: "open_merbabu", userKey: "bayu", intent: "AWAITING_PAY" }, + + // Snorkeling Pahawang + { tripKey: "open_snorkel", userKey: "sari", intent: "PAID" }, + { tripKey: "open_snorkel", userKey: "maya", intent: "MARKED_PAID" }, + { tripKey: "open_snorkel", userKey: "raka", intent: "PENDING_REQUEST" }, + + // Diving Lembongan + { tripKey: "open_lembongan_dive", userKey: "doni", intent: "PAID" }, + { tripKey: "open_lembongan_dive", userKey: "bayu", intent: "AWAITING_PAY" }, + + // Diving Tulamben + { tripKey: "open_diving", userKey: "doni", intent: "AWAITING_PAY" }, + + // Festival (FREE) — Booking langsung PAID + { tripKey: "open_festival", userKey: "raka", intent: "FREE_CONFIRMED" }, + { tripKey: "open_festival", userKey: "bayu", intent: "FREE_CONFIRMED" }, + { tripKey: "open_festival", userKey: "galih", intent: "PENDING_REQUEST" }, + + // Rinjani + { tripKey: "open_rinjani", userKey: "doni", intent: "AWAITING_PAY" }, + { tripKey: "open_rinjani", userKey: "bayu", intent: "PENDING_REQUEST" }, + + // Belitung + { tripKey: "open_belitung", userKey: "wina", intent: "PAID" }, + { tripKey: "open_belitung", userKey: "bayu", intent: "PAID" }, + { tripKey: "open_belitung", userKey: "doni", intent: "PENDING_REQUEST" }, + + // Island hop Karimun + { tripKey: "open_islandhop", userKey: "budi", intent: "PAID" }, + { tripKey: "open_islandhop", userKey: "sari", intent: "PAID" }, + { tripKey: "open_islandhop", userKey: "maya", intent: "MARKED_PAID" }, + { tripKey: "open_islandhop", userKey: "raka", intent: "PENDING_REQUEST" }, + + // Kawah Ijen + { tripKey: "open_ijen", userKey: "doni", intent: "PENDING_REQUEST" }, + { tripKey: "open_ijen", userKey: "raka", intent: "PENDING_REQUEST" }, + + // Concert Coldplay (FREE) { tripKey: "open_concert", userKey: "maya", intent: "FREE_CONFIRMED" }, { tripKey: "open_concert", userKey: "raka", intent: "FREE_CONFIRMED" }, { tripKey: "open_concert", userKey: "sari", intent: "PENDING_REQUEST" }, - // Workshop + // Komodo + { tripKey: "open_komodo", userKey: "budi", intent: "AWAITING_PAY" }, + { tripKey: "open_komodo", userKey: "intan", intent: "PENDING_REQUEST" }, + + // Workshop fotografi { tripKey: "open_workshop", userKey: "doni", intent: "PAID" }, { tripKey: "open_workshop", userKey: "sari", intent: "AWAITING_PAY" }, - // Retreat — niche + // Retreat Ubud { tripKey: "open_retreat", userKey: "maya", intent: "PENDING_REQUEST" }, + + // Yoga retreat Selabintana + { tripKey: "open_yoga_retreat", userKey: "maya", intent: "PENDING_REQUEST" }, + { tripKey: "open_yoga_retreat", userKey: "sari", intent: "PENDING_REQUEST" }, ]; interface BookingPlan { @@ -1303,6 +1984,42 @@ const SEED_REVIEWS: SeedReview[] = [ rating: 3, comment: "Seru tapi rute pagi-siang kepadetan, jadwal molor 1 jam.", }, + { + tripKey: "past_prau", + userKey: "budi", + rating: 5, + comment: "Sunrise Prau emang gak boong. Track-nya pendek, cocok bawa pemula.", + }, + { + tripKey: "past_prau", + userKey: "intan", + rating: 4, + comment: "Pemandangan juara. Camp area agak rame karena weekend, tapi tim handle dengan baik.", + }, + { + tripKey: "past_prau", + userKey: "galih", + rating: 5, + comment: "Bang Rangga ramah, logistik lengkap. Kopi pagi di puncak gak terlupakan.", + }, + { + tripKey: "past_nusapenida", + userKey: "sari", + rating: 5, + comment: "Kelingking Beach se-keren itu aslinya. Sopir + guide-nya enak diajak ngobrol.", + }, + { + tripKey: "past_nusapenida", + userKey: "wina", + rating: 4, + comment: "Spotnya bagus semua, cuma antrian foto di Kelingking lumayan panjang. Overall puas.", + }, + { + tripKey: "past_nusapenida", + userKey: "bayu", + rating: 5, + comment: "Crystal Bay jernih banget buat snorkeling. Mbak Ayu organizer yang rapi.", + }, ]; async function seedReviews(trips: TripMap, users: UserMap) { @@ -1329,7 +2046,7 @@ async function seedReviews(trips: TripMap, users: UserMap) { async function main() { console.log("🌱 Seeding database...\n"); - console.log("⏳ Cleanup tabel lama..."); + console.log("⏳ Cleanup — hapus semua data lama..."); await cleanup(); console.log("⏳ Seed users + profile..."); @@ -1350,18 +2067,26 @@ async function main() { console.log("⏳ Seed reviews..."); await seedReviews(trips, users); + const countBy = (s: SeedTrip["status"]) => + SEED_TRIPS.filter((t) => t.status === s).length; + const organizerCount = SEED_VERIFICATIONS.filter( + (v) => v.status === "APPROVED" + ).length; + console.log(` -✅ Selesai. Ringkasan: - ${SEED_USERS.length} users (1 admin, 3 organizer, ${SEED_USERS.length - 4} peserta) - ${SEED_VERIFICATIONS.length} organizer verifications (3 APPROVED, 1 PENDING, 1 REJECTED) - ${SEED_TRIPS.length} trips (3 COMPLETED + 1 CLOSED + ${SEED_TRIPS.filter((t) => t.status === "OPEN").length} OPEN) +✅ Selesai. Database fresh. Ringkasan: + ${SEED_USERS.length} users (1 admin, ${organizerCount} organizer terverifikasi, sisanya peserta) + ${SEED_VERIFICATIONS.length} organizer verifications (${organizerCount} APPROVED, 1 PENDING, 1 REJECTED) + ${SEED_TRIPS.length} trips (${countBy("COMPLETED")} COMPLETED, ${countBy("CLOSED")} CLOSED, ${countBy("OPEN")} OPEN, ${countBy("FULL")} FULL) ${SEED_PARTICIPANTS.length} participants (mix PENDING/CONFIRMED/CANCELLED) ${SEED_REVIEWS.length} reviews +📅 Semua tanggal relatif terhadap hari seed dijalankan — trip OPEN selalu di masa depan. + 🔐 Login info: Admin : admin@setrip.id - Organizer : dede.inoen@setrip.id, panji@setrip.id, fiersa@setrip.id - Peserta : budi/sari/doni/maya/raka @gmail.com + Organizer : dede.inoen@setrip.id, panji@setrip.id, fiersa@setrip.id, rangga@setrip.id, ayu@setrip.id + Peserta : budi/sari/doni/maya/raka/intan/galih/wina/bayu @gmail.com Password : ${SEED_PASSWORD} `); }