import type { Metadata } from "next"; import Link from "next/link"; import { Suspense } from "react"; import { getServerSession } from "next-auth"; import { authOptions } from "@/lib/auth"; import { tripService } from "@/server/services/trip.service"; import { profileRepo } from "@/server/repositories/profile.repo"; import { TripCard } from "@/features/trip/components/trip-card"; import { TripFilter } from "@/features/trip/components/trip-filter"; import { siteConfig } from "@/lib/site"; import { categoryLabel, isActivityCategory } from "@/lib/activity-category"; import { isVibe } from "@/lib/vibe"; import type { GroupSize } from "@/server/repositories/trip.repo"; import { Plus, Search, Tent } from "lucide-react"; const GROUP_SIZES: GroupSize[] = ["SMALL", "MEDIUM", "LARGE"]; function isGroupSize(value: unknown): value is GroupSize { return typeof value === "string" && (GROUP_SIZES as string[]).includes(value); } interface TripsPageProps { searchParams: Promise<{ q?: string; from?: string; to?: string; category?: string; vibe?: string; groupSize?: string; }>; } export async function generateMetadata({ searchParams, }: TripsPageProps): Promise { const { q, category: categoryParam } = await searchParams; const category = isActivityCategory(categoryParam) ? categoryParam : undefined; const categoryName = category ? categoryLabel(category) : null; const title = q ? `Cari Teman Trip "${q}" — Gabung Bareng` : categoryName ? `Cari Teman ${categoryName} — Daftar Open Trip Aktif` : "Cari Teman Trip & Aktivitas — Daftar Open Trip Aktif"; const description = q ? `Hasil pencarian "${q}" di ${siteConfig.name}. Temukan teman seperjalanan, lihat trip & organizer terverifikasi, langsung gabung.` : categoryName ? `Daftar open trip ${categoryName.toLowerCase()} di ${siteConfig.name}. Pilih trip, kenal calon teman seperjalanan, dan gabung bareng — grup kecil & organizer terverifikasi.` : `Daftar open trip aktif di ${siteConfig.name} — hiking, camping, snorkeling, city trip, dan aktivitas bareng lainnya. Pilih trip, kenal calon teman seperjalanan, dan gabung bareng — grup kecil & organizer terverifikasi.`; return { title, description, alternates: { canonical: "/trips" }, openGraph: { title, description, url: "/trips" }, }; } export default async function TripsPage({ searchParams }: TripsPageProps) { const params = await searchParams; const category = isActivityCategory(params.category) ? params.category : undefined; const vibe = isVibe(params.vibe) ? params.vibe : undefined; const groupSize = isGroupSize(params.groupSize) ? params.groupSize : undefined; const hasFilters = Boolean( params.q || params.from || params.to || category || vibe || groupSize ); const filters = { q: params.q, from: params.from, to: params.to, category, vibe, groupSize, }; const session = await getServerSession(authOptions); const [trips, allTrips, viewerProfile] = await Promise.all([ tripService.getOpenTrips(filters), hasFilters ? tripService.getOpenTrips() : null, session?.user?.id ? profileRepo.findByUserId(session.user.id) : Promise.resolve(null), ]); const totalCount = hasFilters ? allTrips!.length : trips.length; const viewerInterests = viewerProfile?.interests ?? []; return (

{category ? `Cari Teman ${categoryLabel(category)}` : "Cari Teman Trip & Aktivitas"}

{hasFilters ? `${trips.length} dari ${totalCount} trip ditemukan` : `${trips.length} trip tersedia — pilih, kenalan, lalu gabung`}

Buat Trip
{/* Filter */}
{trips.length === 0 ? (
{hasFilters ? ( ) : ( )}

{hasFilters ? "Tidak ada trip yang cocok" : "Belum ada trip tersedia"}

{hasFilters ? "Coba ubah kata kunci atau rentang tanggal pencarian" : "Jadilah yang pertama membuat open trip di sini!"}

{!hasFilters && ( Buat Trip Baru )}
) : (
{trips.map((trip, index) => ( ({ id: p.id, name: p.user.name, image: p.user.image, interests: p.user.profile?.interests ?? [], }))} viewerInterests={viewerInterests} /> ))}
)}
); }