Show pre-sale close time as a duration before the event starts.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Michilis
2026-09-17 15:40:30 +00:00
co-authored by Cursor
parent a70333f5e4
commit 0b7f0a474e
5 changed files with 30 additions and 16 deletions
@@ -5,7 +5,7 @@ import Link from 'next/link';
import Image from 'next/image';
import { useLanguage } from '@/context/LanguageContext';
import { eventsApi, Event } from '@/lib/api';
import { formatPrice, formatDateLong, formatTime, eventSpotsLeft, isEventSoldOut, isPresaleClosed } from '@/lib/utils';
import { formatPrice, formatDateLong, formatTime, eventSpotsLeft, isEventSoldOut, isPresaleClosed, parseDate, formatDurationWords } from '@/lib/utils';
import Card from '@/components/ui/Card';
import Button from '@/components/ui/Button';
import ShareButtons from '@/components/ShareButtons';
@@ -72,6 +72,10 @@ export default function EventDetailClient({ eventId, initialEvent }: EventDetail
// Pre-sale closure (server-computed cutoff); same mount guard as isPastEvent
const presaleClosed = mounted ? isPresaleClosed(event) : false;
const canBook = !isSoldOut && !isCancelled && !isPastEvent && !presaleClosed && (event.status === 'published' || event.status === 'unlisted');
// Effective lead time (event override or site default), derived from the server cutoff
const presaleLeadMinutes = event.presaleClosesAt
? Math.max(0, Math.round((parseDate(event.startDatetime).getTime() - parseDate(event.presaleClosesAt).getTime()) / 60_000))
: null;
// Booking card content - reused for mobile and desktop positions
const BookingCardContent = () => (
@@ -153,11 +157,13 @@ export default function EventDetailClient({ eventId, initialEvent }: EventDetail
</Button>
)}
{canBook && !event.externalBookingEnabled && event.presaleClosesAt && (
<p className="mt-3 text-center text-xs text-gray-500">
{t('events.details.registrationClosesAt', {
date: `${formatDate(event.presaleClosesAt)} ${fmtTime(event.presaleClosesAt)}`,
})}
{canBook && !event.externalBookingEnabled && presaleLeadMinutes !== null && (
<p className="mt-3 text-center text-xs text-gray-400">
{presaleLeadMinutes > 0
? t('events.details.presaleClosesBefore', {
duration: formatDurationWords(presaleLeadMinutes, locale as 'en' | 'es'),
})
: t('events.details.presaleClosesAtStart')}
</p>
)}