import Image from "next/image"; import Link from "next/link"; import { MapPin, CalendarDays, UserRound, BadgeCheck, Sparkles, } from "lucide-react"; import { formatRupiah } from "@/lib/utils"; import { formatTripCalendarDateRangeLong } from "@/lib/trip-dates"; import { categoryMeta } from "@/lib/activity-category"; import { vibeMeta } from "@/lib/vibe"; import type { ActivityCategory, Vibe } from "@/app/generated/prisma/enums"; interface TripCardParticipant { id: string; name: string; image: string | null; interests: string[]; } interface TripCardProps { id: string; title: string; category: ActivityCategory; vibe?: Vibe | null; destination: string; location: string; date: Date | string; endDate?: Date | string | null; price: number; maxParticipants: number; participantCount: number; organizerName: string; status: string; coverImage?: string | null; priority?: boolean; isVerifiedOrganizer?: boolean; /** Daftar peserta CONFIRMED (subset, untuk preview avatar). Optional. */ participants?: TripCardParticipant[]; /** Interests user yang sedang melihat — untuk hitung overlap. Optional. */ viewerInterests?: string[]; } export function TripCard({ id, title, category, vibe, destination, location, date, endDate, price, maxParticipants, participantCount, organizerName, status, coverImage, priority, isVerifiedOrganizer, participants, viewerInterests, }: TripCardProps) { const spotsLeft = maxParticipants - participantCount; const isSmallGroup = maxParticipants <= 10; const meta = categoryMeta(category); const vMeta = vibe ? vibeMeta(vibe) : null; const previewParticipants = participants?.slice(0, 3) ?? []; const moreCount = participants && participants.length > 3 ? participants.length - 3 : 0; let overlapCount = 0; if (viewerInterests && viewerInterests.length > 0 && participants) { const viewerSet = new Set(viewerInterests.map((i) => i.toLowerCase())); overlapCount = participants.filter((p) => p.interests.some((tag) => viewerSet.has(tag.toLowerCase())) ).length; } return (
{/* Cover Image */}
{coverImage ? ( {title} ) : (
{meta.icon}
)}
{meta.icon} {meta.label} {vMeta && ( {vMeta.icon} {vMeta.label} )}
{status}
{/* Content */}

{title}

{destination}

{location}
{formatTripCalendarDateRangeLong(date, endDate)}
{organizerName} {isVerifiedOrganizer && ( Verified )} {isSmallGroup && ( Small group )}
{(previewParticipants.length > 0 || overlapCount > 0) && (
{previewParticipants.length > 0 && (
{previewParticipants.map((p) => p.image ? ( ) : (
{p.name.charAt(0).toUpperCase()}
) )} {moreCount > 0 && (
+{moreCount}
)}
)} {overlapCount > 0 && ( {overlapCount} peserta sama minat )}
)}
{formatRupiah(price)} 0 ? "text-secondary-600" : "text-amber-600" }`} > {spotsLeft > 0 ? `${spotsLeft} slot tersisa` : "Penuh"}
); }