131 lines
4.0 KiB
TypeScript
131 lines
4.0 KiB
TypeScript
'use client';
|
|
|
|
import {
|
|
ExclamationTriangleIcon,
|
|
CheckCircleIcon,
|
|
} from '@heroicons/react/24/outline';
|
|
import type { UserTicket } from '@/lib/api';
|
|
import { useLanguage } from '@/context/LanguageContext';
|
|
import PayActions from './PayActions';
|
|
import { HoldCountdown } from './Countdown';
|
|
import {
|
|
holdExpiry,
|
|
ticketAmount,
|
|
pyg,
|
|
isAwaitingApproval,
|
|
isOnHold,
|
|
HOLD_THRESHOLD_HOURS,
|
|
} from './helpers';
|
|
|
|
/**
|
|
* The very-top Overview banner. Shown only when a booking needs attention:
|
|
* • unpaid -> red banner naming event + amount, a hold-expiry countdown,
|
|
* and the "Pay now" / "I've paid" actions.
|
|
* • awaiting -> calm amber "payment received, we will confirm it
|
|
* shortly" state with no further action.
|
|
*/
|
|
export default function AttentionBanner({
|
|
ticket,
|
|
locale,
|
|
onChange,
|
|
}: {
|
|
ticket: UserTicket;
|
|
locale: string;
|
|
onChange: () => void;
|
|
}) {
|
|
const { t } = useLanguage();
|
|
const eventTitle =
|
|
(locale === 'es' && ticket.event?.titleEs
|
|
? ticket.event.titleEs
|
|
: ticket.event?.title) || (locale === 'es' ? 'tu evento' : 'your event');
|
|
const { amount, currency } = ticketAmount(ticket);
|
|
|
|
if (isOnHold(ticket)) {
|
|
return (
|
|
<div className="rounded-card border border-slate-200 bg-slate-50 p-4">
|
|
<div className="flex items-start gap-3">
|
|
<ExclamationTriangleIcon className="mt-0.5 h-6 w-6 flex-shrink-0 text-slate-500" />
|
|
<div className="min-w-0 flex-1">
|
|
<p className="font-semibold text-slate-800">
|
|
{locale === 'es'
|
|
? `Tu lugar para ${eventTitle} fue liberado`
|
|
: `Your spot for ${eventTitle} was released`}
|
|
</p>
|
|
<p className="mt-0.5 text-sm text-slate-600">
|
|
{locale === 'es'
|
|
? `El pago no se confirmó dentro de ${HOLD_THRESHOLD_HOURS} horas.`
|
|
: `Payment was not confirmed within ${HOLD_THRESHOLD_HOURS} hours.`}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
<div className="mt-3 sm:pl-9">
|
|
<PayActions
|
|
ticketId={ticket.id}
|
|
amount={amount}
|
|
currency={currency}
|
|
destination={eventTitle}
|
|
locale={locale}
|
|
onPaid={onChange}
|
|
layout="inline"
|
|
size="sm"
|
|
onHold
|
|
/>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
if (isAwaitingApproval(ticket)) {
|
|
return (
|
|
<div className="flex items-start gap-3 rounded-card border border-amber-200 bg-amber-50 p-4">
|
|
<CheckCircleIcon className="mt-0.5 h-6 w-6 flex-shrink-0 text-amber-600" />
|
|
<div>
|
|
<p className="font-semibold text-amber-900">
|
|
{t('dashboard.payment.received')}
|
|
</p>
|
|
<p className="text-sm text-amber-800">
|
|
{t('dashboard.payment.confirmForEvent', {
|
|
amount: pyg(amount, currency),
|
|
event: eventTitle,
|
|
})}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
const expiry = holdExpiry(ticket);
|
|
|
|
return (
|
|
<div className="rounded-card border border-red-200 bg-red-50 p-4">
|
|
<div className="flex items-start gap-3">
|
|
<ExclamationTriangleIcon className="mt-0.5 h-6 w-6 flex-shrink-0 text-red-600" />
|
|
<div className="min-w-0 flex-1">
|
|
<p className="font-semibold text-red-900">
|
|
{locale === 'es'
|
|
? `Debes ${pyg(amount, currency)} para ${eventTitle}`
|
|
: `You owe ${pyg(amount, currency)} for ${eventTitle}`}
|
|
</p>
|
|
{expiry && (
|
|
<p className="mt-0.5 text-sm text-red-700">
|
|
<HoldCountdown target={expiry} locale={locale} />
|
|
</p>
|
|
)}
|
|
</div>
|
|
</div>
|
|
<div className="mt-3 sm:pl-9">
|
|
<PayActions
|
|
ticketId={ticket.id}
|
|
amount={amount}
|
|
currency={currency}
|
|
destination={eventTitle}
|
|
locale={locale}
|
|
onPaid={onChange}
|
|
layout="inline"
|
|
size="sm"
|
|
/>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|