Files
setrip/README.md
T
2026-04-20 00:25:05 +07:00

4.6 KiB

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 /login melalui 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

  1. Setelah login, organizer membuka Buat Trip (/create-trip) dari navbar, halaman /trips, beranda, atau tombol mengambang (+).
  2. Halaman form (app/create-trip/page.tsx) memvalidasi sesi di client; jika belum login, ditampilkan ajakan login.
  3. Organizer mengisi judul, gunung, lokasi, deskripsi (opsional), rentang tanggal (DatePicker), maks peserta, harga (format Rupiah), dan URL gambar opsional (ImageUrlInput).
  4. Submit memanggil server action createTripAction (features/trip/actions.ts):
    • Memastikan ada sesi.
    • Mem-parse dan memvalidasi input dengan Zod (features/trip/schemas.ts).
    • tripService.createTrip menulis trip baru ke database lewat tripRepo.create, menghubungkan organizerId ke user yang login, dan menyimpan gambar jika ada.
  5. 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

  1. Beranda (/) dan Open Trip (/trips) menampilkan trip dengan status OPEN dan tanggal berangkat tidak di masa lalu (tripService.getOpenTrips + filter di repository).
  2. Filter pencarian (TripFilter) mengirim query string; daftar trip disaring di server.
  3. Dari kartu trip (TripCard), pengguna membuka detail /trips/[id] (app/trips/[id]/page.tsx):
    • Peserta aktif = baris TripParticipant yang statusnya bukan CANCELLED.
    • Slot tersisa dan progress bar memakai jumlah peserta aktif tersebut.
  4. Join (JoinTripButton + joinTripAction):
    • Jika belum login: tautan ke /login.
    • Jika trip bukan OPEN dan user belum join: pendaftaran ditutup (kecuali user sudah terdaftar dan ingin membatalkan, mengikuti logika UI).
    • tripService.joinTrip memeriksa: trip ada, status OPEN, bukan organizer, belum terdaftar aktif, kapasitas belum penuh; lalu menambah atau mengaktifkan kembali partisipasi (lihat bagian perbaikan bug di bawah).
  5. Jika jumlah peserta aktif mencapai maxParticipants, status trip diperbarui menjadi FULL.
  6. Batal ikut memanggil cancelJoinActiontripService.cancelJoin: partisipasi ditandai CANCELLED; jika trip sebelumnya FULL dan 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)

  1. Join lagi setelah “Batal ikut”
    Satu user hanya boleh satu baris partisipasi per trip (@@unique([tripId, userId])). Kode lama mencoba create lagi setelah status CANCELLED, sehingga bisa gagal dengan pelanggaran unik. Sekarang jika sudah ada baris CANCELLED, partisipasi diaktifkan kembali (CONFIRMED) lewat participantRepo.reactivate, bukan insert baru.

  2. Jumlah peserta di kartu / daftar
    _count.participants di query listing sebelumnya menghitung semua baris termasuk yang CANCELLED, sehingga “slot tersisa” di TripCard bisa salah. Count sekarang hanya menghitung peserta dengan status bukan CANCELLED.

  3. Segar halaman setelah join/batal/buat trip
    Setelah aksi trip, cache halaman /trips dan / ikut di-revalidatePath agar jumlah slot dan daftar di beranda konsisten tanpa harus refresh manual.

Learn More