'use client'; import clsx from 'clsx'; import { CheckCircleIcon, ArrowUturnLeftIcon, UserGroupIcon, } from '@heroicons/react/24/outline'; import type { DoorAttendee, DoorPaymentMethod } from '@/lib/api'; import { formatCurrency, parseDate, EVENT_TIMEZONE } from '@/lib/utils'; import { PaymentButtons } from './PaymentButtons'; function checkinTime(checkinAt: string | null): string { if (!checkinAt) return ''; return parseDate(checkinAt).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', timeZone: EVENT_TIMEZONE, }); } const METHOD_LABELS: Record = { cash: 'cash', bitcoin: 'bitcoin', transfer: 'transfer', guest: 'guest', }; /** The second line of a row: everything staff needs to decide in one glance. */ function statusLine(attendee: DoorAttendee, currency: string): string { if (attendee.status === 'cancelled') return 'Cancelled'; if (attendee.checkedIn) { const time = checkinTime(attendee.checkinAt); const how = attendee.doorMethod ? ` · paid ${METHOD_LABELS[attendee.doorMethod]}` : ''; return time ? `Checked in ${time}${how}` : `Checked in${how}`; } const parts: string[] = []; if (attendee.paymentStatus === 'comp') parts.push('Guest'); else if (attendee.paymentStatus === 'paid') parts.push('Paid'); else parts.push(`Unpaid · ${formatCurrency(attendee.amountDue, currency)} due`); if (attendee.isGroupBooking) parts.push('group booking'); if (attendee.status === 'pending') parts.push('pending'); return parts.join(' · '); } export function AttendeeRow({ attendee, currency, price, expanded, flashing, busy, onTap, onPay, }: { attendee: DoorAttendee; currency: string; price: number; expanded: boolean; flashing: boolean; busy: boolean; onTap: () => void; onPay: (method: DoorPaymentMethod, amount: number) => void; }) { const isCancelled = attendee.status === 'cancelled'; const settled = attendee.paymentStatus === 'paid' || attendee.paymentStatus === 'comp'; // A settled, not-yet-arrived attendee is the one-tap case: the whole row checks // them in. Everyone else opens the tenders inline instead. const isOneTap = !isCancelled && !attendee.checkedIn && settled; return (
{expanded && !attendee.checkedIn && (
{isCancelled && (

Reactivate as a walk-in — pick how they are paying.

)}
)} {expanded && attendee.checkedIn && (

Already checked in {attendee.checkinAt ? ` at ${checkinTime(attendee.checkinAt)}` : ''} {attendee.checkedInBy ? ` by ${attendee.checkedInBy}` : ''}.

)}
); }