import { notFound } from "next/navigation"; import { getServerSession } from "next-auth"; import Link from "next/link"; import { authOptions } from "@/lib/auth"; import { tripService } from "@/server/services/trip.service"; import { trustService } from "@/server/services/trust.service"; import { formatRupiah } from "@/lib/utils"; import { formatTripCalendarDateRangeLong } from "@/lib/trip-dates"; import { JoinTripButton } from "@/features/trip/components/join-trip-button"; import { OrganizerJoinRequests } from "@/features/trip/components/organizer-join-requests"; import { OrganizerTrustPanel } from "@/features/trip/components/organizer-trust-panel"; import { TripProgramBlock } from "@/features/trip/components/trip-program-block"; import { OrganizerPaymentQueue } from "@/features/booking/components/organizer-payment-queue"; import { ImageGallery } from "@/features/trip/components/image-gallery"; import { TripReviewSection } from "@/features/review/components/trip-review-section"; import { isPastTripLastDayForReview, isTripDepartureDayPast, } from "@/lib/trip-dates"; export default async function TripDetailPage({ params, }: { params: Promise<{ id: string }>; }) { const { id } = await params; const session = await getServerSession(authOptions); let trip; try { trip = await tripService.getTripById(id); } catch { notFound(); } const organizerTrust = await trustService.getOrganizerTrust( trip.organizerId ); const activeParticipants = trip.participants.filter( (p) => p.status !== "CANCELLED" ); const confirmedParticipants = activeParticipants.filter( (p) => p.status === "CONFIRMED" ); const pendingParticipants = activeParticipants.filter( (p) => p.status === "PENDING" ); const participantCount = activeParticipants.length; const confirmedCount = confirmedParticipants.length; const spotsLeft = trip.maxParticipants - participantCount; const fillPercent = Math.min( (participantCount / trip.maxParticipants) * 100, 100 ); const isOrganizer = session?.user?.id === trip.organizerId; const currentParticipation = session?.user ? trip.participants.find( (p) => p.userId === session.user.id && p.status !== "CANCELLED" ) : null; const isDeparturePast = isTripDepartureDayPast(trip.date); const canReview = !!session?.user && !isOrganizer && currentParticipation?.status === "CONFIRMED" && isPastTripLastDayForReview(trip.date, trip.endDate); const myReview = session?.user ? trip.reviews.find((r) => r.userId === session.user.id) ?? null : null; const averageRating = trip.reviews.length > 0 ? Math.round( (trip.reviews.reduce((s, r) => s + r.rating, 0) / trip.reviews.length) * 10 ) / 10 : null; const paymentPendingParticipants = activeParticipants.filter( (p) => p.markedPaidAt && !p.paymentConfirmedAt ); return (
{/* Breadcrumb */}
Open Trip / {trip.mountain}
{/* Image Gallery */} {/* Title bar */}

{trip.title}

๐Ÿ”๏ธ {trip.mountain}

{trip.status}
{/* Info Grid */}
๐Ÿ“

Lokasi

{trip.location}

๐Ÿ“…

Tanggal

{formatTripCalendarDateRangeLong(trip.date, trip.endDate)}

๐Ÿ’ฐ

Harga

{formatRupiah(trip.price)}

๐Ÿ‘ค

Organizer

{trip.organizer.name}

{/* Participant Progress */}
Peserta {participantCount}{" "} / {trip.maxParticipants}
= 100 ? "bg-amber-500" : fillPercent >= 70 ? "bg-secondary-500" : "bg-primary-500" }`} style={{ width: `${fillPercent}%` }} />

Maksimal {trip.maxParticipants} orang. Saat ini {participantCount}{" "} mendaftar, {confirmedCount} sudah disetujui organizer.

{spotsLeft > 0 ? `Masih ada ${spotsLeft} tempat โ€” yuk gabung!` : "Trip sudah penuh"} {confirmedCount < participantCount && ( <> {" "} ยท {participantCount - confirmedCount} menunggu persetujuan organizer )}

{/* Description */} {trip.description && (

Deskripsi Trip

{trip.description}

)} {isOrganizer && pendingParticipants.length > 0 && ( ({ id: p.id, user: p.user, markedPaidAt: p.markedPaidAt, }))} /> )} {isOrganizer && paymentPendingParticipants.length > 0 && ( ({ id: p.id, user: p.user, joinStatus: p.status === "PENDING" ? ("PENDING" as const) : ("CONFIRMED" as const), }))} /> )} {/* Action */} ({ id: r.id, rating: r.rating, comment: r.comment, createdAt: r.createdAt, user: r.user, }))} averageRating={averageRating} canReview={canReview} myReview={ myReview ? { rating: myReview.rating, comment: myReview.comment } : null } /> {/* Peserta yang sudah disetujui organizer (publik) */}

Peserta terkonfirmasi ({confirmedCount})

{confirmedCount === 0 ? (

Belum ada peserta yang dikonfirmasi.{" "} {pendingParticipants.length > 0 ? "Cek permintaan join di atas untuk menyetujui peserta." : "Jadilah yang pertama mendaftar! ๐ŸŽ’"}

) : (
{confirmedParticipants.map((p) => (
{p.user.name.charAt(0).toUpperCase()}
{p.user.name}
))}
)}
); }