Consolidate profile and security into AccountTab, add shared dashboard components, and move awaiting-approval payment messages to translations. Co-authored-by: Cursor <cursoragent@cursor.com>
96 lines
2.9 KiB
TypeScript
96 lines
2.9 KiB
TypeScript
'use client';
|
|
|
|
import clsx from 'clsx';
|
|
import type { UserTicket, Payment } from '@/lib/api';
|
|
|
|
// One logical status per meaning, mapped to a single pale colour everywhere.
|
|
// confirmed -> pale green
|
|
// awaiting -> pale amber (user said they paid, admin checking)
|
|
// unpaid -> pale red
|
|
// attended -> pale blue (replaces the raw "checked_in" value)
|
|
// cancelled -> pale gray
|
|
export type DashStatus =
|
|
| 'confirmed'
|
|
| 'awaiting'
|
|
| 'unpaid'
|
|
| 'attended'
|
|
| 'cancelled';
|
|
|
|
/**
|
|
* Collapse a ticket status + payment status into a single user-facing status.
|
|
* Never surface raw values like "checked_in" or "pending_approval".
|
|
*/
|
|
export function deriveTicketStatus(
|
|
ticketStatus?: string,
|
|
paymentStatus?: string
|
|
): DashStatus {
|
|
if (ticketStatus === 'checked_in') return 'attended';
|
|
if (ticketStatus === 'cancelled') return 'cancelled';
|
|
if (paymentStatus === 'paid' || ticketStatus === 'confirmed') return 'confirmed';
|
|
if (paymentStatus === 'pending_approval') return 'awaiting';
|
|
return 'unpaid';
|
|
}
|
|
|
|
/** Status for a standalone payment record (Payments tab). */
|
|
export function derivePaymentStatus(paymentStatus?: string): DashStatus {
|
|
if (paymentStatus === 'paid') return 'confirmed';
|
|
if (paymentStatus === 'pending_approval') return 'awaiting';
|
|
if (paymentStatus === 'refunded') return 'cancelled';
|
|
return 'unpaid';
|
|
}
|
|
|
|
export function statusLabel(status: DashStatus, locale: string): string {
|
|
const labels: Record<DashStatus, { en: string; es: string }> = {
|
|
confirmed: { en: 'Confirmed', es: 'Confirmado' },
|
|
awaiting: { en: 'Awaiting approval', es: 'Esperando aprobación' },
|
|
unpaid: { en: 'Unpaid', es: 'No pagado' },
|
|
attended: { en: 'Attended', es: 'Asistió' },
|
|
cancelled: { en: 'Cancelled', es: 'Cancelado' },
|
|
};
|
|
return locale === 'es' ? labels[status].es : labels[status].en;
|
|
}
|
|
|
|
const PILL_STYLES: Record<DashStatus, string> = {
|
|
confirmed: 'bg-green-100 text-green-800',
|
|
awaiting: 'bg-amber-100 text-amber-800',
|
|
unpaid: 'bg-red-100 text-red-700',
|
|
attended: 'bg-blue-100 text-blue-800',
|
|
cancelled: 'bg-gray-100 text-gray-600',
|
|
};
|
|
|
|
export function StatusPill({
|
|
status,
|
|
locale,
|
|
className,
|
|
}: {
|
|
status: DashStatus;
|
|
locale: string;
|
|
className?: string;
|
|
}) {
|
|
return (
|
|
<span
|
|
className={clsx(
|
|
'inline-flex items-center rounded-full px-3 py-1 text-xs font-medium whitespace-nowrap',
|
|
PILL_STYLES[status],
|
|
className
|
|
)}
|
|
>
|
|
{statusLabel(status, locale)}
|
|
</span>
|
|
);
|
|
}
|
|
|
|
/** Convenience: derive + render a pill straight from a ticket. */
|
|
export function TicketStatusPill({
|
|
ticket,
|
|
locale,
|
|
className,
|
|
}: {
|
|
ticket: Pick<UserTicket, 'status'> & { payment?: Pick<Payment, 'status'> | null };
|
|
locale: string;
|
|
className?: string;
|
|
}) {
|
|
const status = deriveTicketStatus(ticket.status, ticket.payment?.status);
|
|
return <StatusPill status={status} locale={locale} className={className} />;
|
|
}
|