import { useState, useEffect } from 'react'; import { loadSalesData, type SalesData } from '../../lib/sales-analytics'; import { checkInTicket, refundTicket } from '../../lib/ticket-management'; import { formatCurrency } from '../../lib/event-management'; import AttendeesTable from '../tables/AttendeesTable'; interface AttendeeData { email: string; name: string; ticketCount: number; totalSpent: number; checkedInCount: number; tickets: SalesData[]; } interface AttendeesTabProps { eventId: string; } export default function AttendeesTab({ eventId }: AttendeesTabProps) { const [orders, setOrders] = useState([]); const [attendees, setAttendees] = useState([]); const [searchTerm, setSearchTerm] = useState(''); const [selectedAttendee, setSelectedAttendee] = useState(null); const [showAttendeeDetails, setShowAttendeeDetails] = useState(false); const [checkInFilter, setCheckInFilter] = useState<'all' | 'checked_in' | 'not_checked_in'>('all'); const [loading, setLoading] = useState(true); useEffect(() => { loadData(); }, [eventId]); useEffect(() => { processAttendees(); }, [orders, searchTerm, checkInFilter]); const loadData = async () => { setLoading(true); try { const ordersData = await loadSalesData(eventId); setOrders(ordersData); } catch (_error) { // Handle error silently } finally { setLoading(false); } }; const processAttendees = () => { const attendeeMap = new Map(); orders.forEach(order => { const existing = attendeeMap.get(order.purchaser_email) || { email: order.purchaser_email, name: order.purchaser_name, ticketCount: 0, totalSpent: 0, checkedInCount: 0, tickets: [] }; existing.tickets.push(order); if (!order.refund_status || order.refund_status === null) { existing.ticketCount += 1; existing.totalSpent += order.price; if (order.checked_in) { existing.checkedInCount += 1; } } attendeeMap.set(order.purchaser_email, existing); }); let processedAttendees = Array.from(attendeeMap.values()); // Only show attendees with active tickets (ticketCount > 0) processedAttendees = processedAttendees.filter(attendee => attendee.ticketCount > 0); // Apply search filter if (searchTerm) { const term = searchTerm.toLowerCase(); processedAttendees = processedAttendees.filter(attendee => attendee.name.toLowerCase().includes(term) || attendee.email.toLowerCase().includes(term) ); } // Apply check-in filter if (checkInFilter === 'checked_in') { processedAttendees = processedAttendees.filter(attendee => attendee.checkedInCount === attendee.ticketCount && attendee.ticketCount > 0 ); } else if (checkInFilter === 'not_checked_in') { processedAttendees = processedAttendees.filter(attendee => attendee.checkedInCount === 0 && attendee.ticketCount > 0 ); } setAttendees(processedAttendees); }; const handleViewAttendee = (attendee: AttendeeData) => { setSelectedAttendee(attendee); setShowAttendeeDetails(true); }; const handleCheckInAttendee = async (attendee: AttendeeData) => { const unCheckedTickets = attendee.tickets.filter(ticket => !ticket.checked_in && (!ticket.refund_status || ticket.refund_status === null) ); if (unCheckedTickets.length === 0) return; const ticket = unCheckedTickets[0]; const success = await checkInTicket(ticket.id); if (success) { setOrders(prev => prev.map(order => order.id === ticket.id ? { ...order, checked_in: true } : order )); } }; const handleRefundAttendee = async (attendee: AttendeeData) => { const confirmedTickets = attendee.tickets.filter(ticket => (!ticket.refund_status || ticket.refund_status === null) ); if (confirmedTickets.length === 0) return; const confirmMessage = `Are you sure you want to refund all ${confirmedTickets.length} ticket(s) for ${attendee.name}?`; if (confirm(confirmMessage)) { for (const ticket of confirmedTickets) { await refundTicket(ticket.id); } setOrders(prev => prev.map(order => confirmedTickets.some(t => t.id === order.id) ? { ...order, refund_status: 'completed' } : order )); } }; const handleBulkCheckIn = async () => { const unCheckedTickets = orders.filter(order => !order.checked_in && (!order.refund_status || order.refund_status === null) ); if (unCheckedTickets.length === 0) { alert('No tickets available for check-in'); return; } const confirmMessage = `Are you sure you want to check in all ${unCheckedTickets.length} remaining tickets?`; if (confirm(confirmMessage)) { for (const ticket of unCheckedTickets) { await checkInTicket(ticket.id); } setOrders(prev => prev.map(order => unCheckedTickets.some(t => t.id === order.id) ? { ...order, checked_in: true } : order )); } }; const getAttendeeStats = () => { const totalAttendees = attendees.length; const totalTickets = attendees.reduce((sum, a) => sum + a.ticketCount, 0); const checkedInAttendees = attendees.filter(a => a.checkedInCount > 0).length; const fullyCheckedInAttendees = attendees.filter(a => a.checkedInCount === a.ticketCount && a.ticketCount > 0 ).length; return { totalAttendees, totalTickets, checkedInAttendees, fullyCheckedInAttendees }; }; const stats = getAttendeeStats(); if (loading) { return (
); } return (

Attendees & Check-in

{/* Stats Cards */}
Total Attendees
{stats.totalAttendees}
Total Tickets
{stats.totalTickets}
Partially Checked In
{stats.checkedInAttendees}
Fully Checked In
{stats.fullyCheckedInAttendees}
{/* Filters */}

Filters

setSearchTerm(e.target.value)} placeholder="Search by name or email..." className="w-full px-3 py-2 bg-white/10 border border-white/20 rounded-lg text-white placeholder-white/50 focus:ring-2 focus:ring-blue-500 focus:border-transparent" />
{/* Attendees Table */}
{/* Attendee Details Modal */} {showAttendeeDetails && selectedAttendee && (

Attendee Details

Contact Information

Name:
{selectedAttendee.name}
Email:
{selectedAttendee.email}

Summary

Total Tickets:
{selectedAttendee.ticketCount}
Total Spent:
{formatCurrency(selectedAttendee.totalSpent)}
Checked In:
{selectedAttendee.checkedInCount} / {selectedAttendee.ticketCount}

Tickets

{selectedAttendee.tickets.map((ticket) => (
{ticket.ticket_types.name}
Purchased: {new Date(ticket.created_at).toLocaleDateString()}
ID: {ticket.uuid}
{formatCurrency(ticket.price)}
{(!ticket.refund_status || ticket.refund_status === null) ? 'confirmed' : ticket.refund_status === 'completed' ? 'refunded' : ticket.refund_status === 'pending' ? 'pending' : 'failed'} {ticket.checked_in ? ( Checked In ) : ( Not Checked In )}
))}
{selectedAttendee.checkedInCount < selectedAttendee.ticketCount && ( )} {selectedAttendee.ticketCount > 0 && ( )}
)}
); }