'use client' import type { BookingUser } from './types' import { useRef } from 'react' import type { PaginationListColumnType } from '@/types' import type { PaginatedListHandle } from '@/components/PaginatedList' import Button from '@/components/formElements/Button' import FileCheckIcon from '@/components/icons/FileCheckIcon' import PaginatedList from '@/components/PaginatedList' import AdminTableActions from '@/components/ui/AdminTableActions' import AdminTableViewButton from '@/components/ui/AdminTableViewButton' import StatusChip from '@/components/ui/StatusChip' import { APP_ROUTES } from '@/constants/routes' import { BOOKING_STATUS_FILTER_ITEMS, getBookingStatus } from '@/constants/status' import { formatPersonName, coerceToString } from '@/helpers' import { checkInBookingAsAdmin } from '@/services/eventManagement' import { API_ROUTES } from '@/services/config' import { formatIranianMobile, formatPersianDate } from '@/lib/formatters' import useAdminAction from '@/hooks/useAdminAction' // Bookings tab columns — copied from app/(dashboard)/bookings/page.tsx, // minus the `eventId` column (this list is already scoped to one event via // urlParams.filters). Cancel/refund stay on their existing flows — an // organizer cannot cancel a single booking either (business-rules.md), only // check-in is exposed here, mirroring the host's own attendance action. // `search` is a filter-only synthetic column (hideInTable) — its value // round-trips as filters.search, matched server-side (adminList in // bookings.service.ts) against booking code and guest first/last name, the // same lookup a host's attendance search covers. const bookingsColumns: PaginationListColumnType[] = [ { field: 'search', label: 'جستجو (کد رزرو یا نام مهمان)', filterable: true, sortable: false, type: 'text', hideInTable: true }, { field: 'bookingCode', label: 'کد رزرو', filterable: false, sortable: false, type: 'text' }, { field: 'userId', label: 'مهمان', filterable: false, sortable: false, type: 'text' }, { field: 'status', label: 'وضعیت', filterable: true, sortable: true, type: 'select', filterItems: BOOKING_STATUS_FILTER_ITEMS }, { field: 'cancellationReason', label: 'دلیل لغو', filterable: false, sortable: false, type: 'text' }, { field: 'checkedInAt', label: 'چک‌این', filterable: false, sortable: false, type: 'date' }, { field: 'createdAt', label: 'تاریخ ثبت', filterable: false, sortable: true, type: 'date' }, { field: 'actions', label: 'عملیات' }, ] interface AdminEventBookingsTabProps { eventId: string eventStatus: string onCheckedIn?: () => void } const AdminEventBookingsTab = ({ eventId, eventStatus, onCheckedIn }: AdminEventBookingsTabProps) => { const bookingsListRef = useRef(null) const { pendingId, runAction } = useAdminAction() const handleCheckIn = (bookingId: string) => runAction( bookingId, async () => { await checkInBookingAsAdmin(bookingId) bookingsListRef.current?.refresh() onCheckedIn?.() }, 'حضور مهمان ثبت شد' ) return (
{{ userId: (row) => { const user = row.user as BookingUser | undefined if (!user) return '—' const name = formatPersonName(user.firstName ?? undefined, user.lastName ?? undefined) return (
{name} {formatIranianMobile(user.mobile)}
) }, status: (_row, cellValue) => { const { label, chipColor } = getBookingStatus(coerceToString(cellValue)) return ( ) }, cancellationReason: (row, cellValue) => { const reason = coerceToString(cellValue).trim() const isCancelledLike = row.status === 'cancelled' || row.status === 'refunded' if (!isCancelledLike || !reason) return '—' return ( {reason} ) }, checkedInAt: (_row, cellValue) => formatPersianDate(cellValue), createdAt: (_row, cellValue) => formatPersianDate(cellValue), actions: (row) => { const user = row.user as BookingUser | undefined const bookingId = row.id as string const canCheckIn = row.status === 'confirmed' && !row.checkedInAt && ['published', 'full'].includes(eventStatus) return ( {user ? ( ) : null} {canCheckIn ? ( ) : null} ) }, }}
) } export default AdminEventBookingsTab