SeTrip
Aplikasi open trip pendakian yang mempertemukan organizer (pembuat trip) dengan peserta yang ingin naik gunung bareng atau mencari teman trip.
Stack: Next.js (App Router), NextAuth, Prisma (PostgreSQL), Tailwind CSS.
Alur aplikasi
1. Autentikasi
- Pengguna baru mendaftar di
/register(nama, email, password disimpan di database). - Login di
/loginmelalui NextAuth; sesi dipakai di server action dan di halaman client (misalnya navbar, form buat trip).
Tanpa login, pengguna tetap bisa melihat daftar trip dan detail trip, tetapi tidak bisa membuat trip atau join.
2. Organizer: membuat trip
- Setelah login, organizer membuka Buat Trip (
/create-trip) dari navbar, halaman/trips, beranda, atau tombol mengambang (+). - Halaman form (
app/create-trip/page.tsx) memvalidasi sesi di client; jika belum login, ditampilkan ajakan login. - Organizer mengisi judul, gunung, lokasi, deskripsi (opsional), rentang tanggal (DatePicker), maks peserta, harga (format Rupiah), dan URL gambar opsional (
ImageUrlInput). - Submit memanggil server action
createTripAction(features/trip/actions.ts):- Memastikan ada sesi.
- Mem-parse dan memvalidasi input dengan Zod (
features/trip/schemas.ts). tripService.createTripmenulis trip baru ke database lewattripRepo.create, menghubungkanorganizerIdke user yang login, dan menyimpan gambar jika ada.
- Trip baru berstatus OPEN (default schema), lalu pengguna diarahkan ke detail trip
/trips/[id].
Organizer tidak bisa join trip sendiri; di detail trip tombol join diganti pesan bahwa user adalah organizer.
3. Peserta: mencari trip dan join
- Beranda (
/) dan Open Trip (/trips) menampilkan trip dengan status OPEN dan tanggal berangkat tidak di masa lalu (tripService.getOpenTrips+ filter di repository). - Filter pencarian (
TripFilter) mengirim query string; daftar trip disaring di server. - Dari kartu trip (
TripCard), pengguna membuka detail/trips/[id](app/trips/[id]/page.tsx):- Peserta aktif = baris
TripParticipantyang statusnya bukanCANCELLED. - Slot tersisa dan progress bar memakai jumlah peserta aktif tersebut.
- Peserta aktif = baris
- Join (
JoinTripButton+joinTripAction):- Jika belum login: tautan ke
/login. - Jika trip bukan
OPENdan user belum join: pendaftaran ditutup (kecuali user sudah terdaftar dan ingin membatalkan, mengikuti logika UI). tripService.joinTripmemeriksa: trip ada, statusOPEN, bukan organizer, belum terdaftar aktif, kapasitas belum penuh; lalu menambah atau mengaktifkan kembali partisipasi (lihat bagian perbaikan bug di bawah).
- Jika belum login: tautan ke
- Jika jumlah peserta aktif mencapai
maxParticipants, status trip diperbarui menjadi FULL. - Batal ikut memanggil
cancelJoinAction→tripService.cancelJoin: partisipasi ditandaiCANCELLED; jika trip sebelumnyaFULLdan setelah batal slot kosong lagi, status dikembalikan ke OPEN.
4. Ringkasan peran data
| Konsep | Penyimpanan |
|---|---|
| Trip | Model Trip (judul, gunung, lokasi, tanggal, kuota, harga, status, relasi ke organizer) |
| Peserta | TripParticipant unik per (tripId, userId) dengan status CONFIRMED / CANCELLED (default schema juga mengenal PENDING; alur UI saat ini memakai CONFIRMED saat join) |
Menjalankan secara lokal
Pastikan PostgreSQL berjalan dan variabel DATABASE_URL di .env mengarah ke database yang valid.
npm install
npx prisma migrate dev
npm run seed # opsional: data contoh
npm run dev
Buka http://localhost:3000.
Perbaikan bug (yang relevan dengan join & listing)
-
Join lagi setelah “Batal ikut”
Satu user hanya boleh satu baris partisipasi per trip (@@unique([tripId, userId])). Kode lama mencobacreatelagi setelah statusCANCELLED, sehingga bisa gagal dengan pelanggaran unik. Sekarang jika sudah ada barisCANCELLED, partisipasi diaktifkan kembali (CONFIRMED) lewatparticipantRepo.reactivate, bukan insert baru. -
Jumlah peserta di kartu / daftar
_count.participantsdi query listing sebelumnya menghitung semua baris termasuk yangCANCELLED, sehingga “slot tersisa” diTripCardbisa salah. Count sekarang hanya menghitung peserta dengan status bukanCANCELLED. -
Segar halaman setelah join/batal/buat trip
Setelah aksi trip, cache halaman/tripsdan/ikut di-revalidatePathagar jumlah slot dan daftar di beranda konsisten tanpa harus refresh manual.