Admin: stats privacy toggle, clickable event rows, fix payment method display

- Add useStatsPrivacy hook with localStorage persistence for stats visibility
- Single event page: desktop privacy button, hide capacity chip when stats hidden
- Events list: row/card click navigates to event detail; stopPropagation on actions
- Backend GET /tickets: include payment for each ticket (removes N+1)
- Bookings page: use list payment data, show — when payment method unknown

Made-with: Cursor
This commit is contained in:
Michilis
2026-03-10 01:10:42 +00:00
parent 2f45966932
commit e09ff4ed60
5 changed files with 102 additions and 34 deletions

View File

@@ -59,19 +59,13 @@ export default function AdminBookingsPage() {
ticketsApi.getAll(),
eventsApi.getAll(),
]);
const ticketsWithDetails = await Promise.all(
ticketsRes.tickets.map(async (ticket) => {
try {
const { ticket: fullTicket } = await ticketsApi.getById(ticket.id);
return fullTicket;
} catch {
return ticket;
}
})
);
setTickets(ticketsWithDetails);
const ticketsWithEvent = ticketsRes.tickets.map((ticket) => ({
...ticket,
event: eventsRes.events.find((e) => e.id === ticket.eventId),
}));
setTickets(ticketsWithEvent);
setEvents(eventsRes.events);
} catch (error) {
toast.error('Failed to load bookings');
@@ -153,7 +147,8 @@ export default function AdminBookingsPage() {
}
};
const getPaymentMethodLabel = (provider: string) => {
const getPaymentMethodLabel = (provider: string | null) => {
if (provider == null) return '—';
const labels: Record<string, string> = {
cash: locale === 'es' ? 'Efectivo en el Evento' : 'Cash at Event',
bank_transfer: locale === 'es' ? 'Transferencia Bancaria' : 'Bank Transfer',
@@ -164,13 +159,13 @@ export default function AdminBookingsPage() {
return labels[provider] || provider;
};
const getDisplayProvider = (ticket: TicketWithDetails) => {
const getDisplayProvider = (ticket: TicketWithDetails): string | null => {
if (ticket.payment?.provider) return ticket.payment.provider;
if (ticket.bookingId) {
const sibling = tickets.find(t => t.bookingId === ticket.bookingId && t.payment?.provider);
return sibling?.payment?.provider ?? 'cash';
const sibling = tickets.find((t) => t.bookingId === ticket.bookingId && t.payment?.provider);
return sibling?.payment?.provider ?? null;
}
return 'cash';
return null;
};
const filteredTickets = tickets.filter((ticket) => {