Add navigation for previous and next days in public booking

This commit is contained in:
Jose Selesan
2026-05-19 11:02:32 -03:00
parent 57416bf53a
commit e9bd759fa5

View File

@@ -108,6 +108,8 @@ type BookingShellProps = {
onSelectDate: (date: string) => void;
onPreviousDays: () => void;
onNextDays: () => void;
onPreviousDay: () => void;
onNextDay: () => void;
onSelectSport: (sportId: string) => void;
onSelectCourt: (courtId: string) => void;
onSelectSlot: (slot: SelectedSlot) => void;
@@ -527,9 +529,6 @@ function PublicBookingDesktop(props: BookingShellProps) {
sportSelectionRequired,
errorMessage,
autoAdjustedDateNotice,
onPreviousDays,
onNextDays,
onSelectDate,
onSelectSport,
onSelectCourt,
onSelectSlot,
@@ -538,6 +537,8 @@ function PublicBookingDesktop(props: BookingShellProps) {
const currentStep = getStep(selectedSlot, props.form.formState.isValid);
const completedSteps = getCompletedSteps(selectedSlot, props.form.formState.isValid);
const selectedDay = dayOptions.find((option) => option.value === selectedDate);
const currentDayIndex = dayOptions.findIndex((option) => option.value === selectedDate);
const canGoBackButton = canGoBack || currentDayIndex > 0;
return (
<PublicBookingPageChrome
@@ -635,9 +636,9 @@ function PublicBookingDesktop(props: BookingShellProps) {
<button
type="button"
className="flex size-11 items-center justify-center border-r border-white/10 transition hover:bg-white/[0.06]"
onClick={onPreviousDays}
disabled={!canGoBack}
aria-label="Mostrar días anteriores"
onClick={props.onPreviousDay}
disabled={!canGoBackButton}
aria-label="Día anterior"
>
<ChevronLeft className="size-5" />
</button>
@@ -648,8 +649,8 @@ function PublicBookingDesktop(props: BookingShellProps) {
<button
type="button"
className="flex size-11 items-center justify-center border-l border-white/10 transition hover:bg-white/[0.06]"
onClick={onNextDays}
aria-label="Mostrar próximos días"
onClick={props.onNextDay}
aria-label="Día siguiente"
>
<ChevronRight className="size-5" />
</button>
@@ -670,44 +671,6 @@ function PublicBookingDesktop(props: BookingShellProps) {
<CourtDetails court={selectedCourt} />
<SelectedSlotCard {...props} />
</div>
<Panel className="p-5">
<h3 className="font-semibold">Cambiá de día</h3>
<div className="mt-4 grid grid-cols-[36px_repeat(7,minmax(0,1fr))_36px] items-stretch gap-3">
<button
type="button"
onClick={onPreviousDays}
disabled={!canGoBack}
className="flex items-center justify-center rounded-md bg-white/[0.04] text-white transition hover:bg-white/[0.08] disabled:opacity-35"
aria-label="Mostrar días anteriores"
>
<ChevronLeft className="size-5" />
</button>
{dayOptions.map((option) => (
<button
key={option.value}
type="button"
onClick={() => onSelectDate(option.value)}
className={`rounded-md border px-3 py-3 text-center transition ${
selectedDate === option.value
? 'border-emerald-500 bg-emerald-500/18 text-white'
: 'border-white/10 bg-white/[0.035] text-white/76 hover:bg-white/[0.06]'
}`}
>
<span className="block text-base font-semibold capitalize">{option.weekday}</span>
<span className="mt-1 block text-sm">{option.dayMonth}</span>
</button>
))}
<button
type="button"
onClick={onNextDays}
className="flex items-center justify-center rounded-md bg-white/[0.04] text-white transition hover:bg-white/[0.08]"
aria-label="Mostrar próximos días"
>
<ChevronRight className="size-5" />
</button>
</div>
</Panel>
</section>
</div>
</PublicBookingPageChrome>
@@ -757,10 +720,10 @@ function PublicBookingMobile(props: BookingShellProps) {
<span className="px-2 text-sm text-white/76">Fecha</span>
<button
type="button"
onClick={props.onPreviousDays}
onClick={props.onPreviousDay}
disabled={!props.canGoBack}
className="flex size-9 items-center justify-center rounded-md border border-white/10 bg-white/[0.035] disabled:opacity-35"
aria-label="Mostrar días anteriores"
aria-label="Día anterior"
>
<ChevronLeft className="size-4" />
</button>
@@ -770,9 +733,9 @@ function PublicBookingMobile(props: BookingShellProps) {
</div>
<button
type="button"
onClick={props.onNextDays}
onClick={props.onNextDay}
className="flex size-9 items-center justify-center rounded-md border border-white/10 bg-white/[0.035]"
aria-label="Mostrar próximos días"
aria-label="Día siguiente"
>
<ChevronRight className="size-4" />
</button>
@@ -804,43 +767,6 @@ function PublicBookingMobile(props: BookingShellProps) {
<SelectedSlotCard {...props} compact />
</div>
</Panel>
<Panel className="p-3">
<div className="grid grid-cols-[32px_repeat(5,minmax(0,1fr))_32px] gap-2">
<button
type="button"
onClick={props.onPreviousDays}
disabled={!props.canGoBack}
className="flex items-center justify-center rounded-md bg-white/[0.04] disabled:opacity-35"
aria-label="Mostrar días anteriores"
>
<ChevronLeft className="size-4" />
</button>
{props.dayOptions.map((option) => (
<button
key={option.value}
type="button"
onClick={() => props.onSelectDate(option.value)}
className={`rounded-md border px-1 py-2 text-center transition ${
props.selectedDate === option.value
? 'border-emerald-500 bg-emerald-500/18 text-white'
: 'border-white/10 bg-white/[0.035] text-white/70'
}`}
>
<span className="block text-xs font-semibold capitalize">{option.weekday}</span>
<span className="block text-[11px]">{option.shortDay}</span>
</button>
))}
<button
type="button"
onClick={props.onNextDays}
className="flex items-center justify-center rounded-md bg-white/[0.04]"
aria-label="Mostrar próximos días"
>
<ChevronRight className="size-4" />
</button>
</div>
</Panel>
</div>
</PublicBookingPageChrome>
);
@@ -1298,6 +1224,7 @@ export function PublicBookingPage({ complexSlug }: PublicBookingPageProps) {
const availabilityQuery = useQuery({
queryKey: ['public-booking-availability', complexSlug, selectedDate, selectedSportId],
enabled: Boolean(selectedDate),
placeholderData: (previousData) => previousData,
queryFn: () =>
apiClient.publicBookings.getAvailability(complexSlug, {
date: selectedDate,
@@ -1516,6 +1443,42 @@ export function PublicBookingPage({ complexSlug }: PublicBookingPageProps) {
});
};
const goToPreviousDay = () => {
const currentIndex = dayOptions.findIndex((o) => o.value === selectedDate);
if (currentIndex > 0) {
const prevDate = dayOptions[currentIndex - 1].value;
setSelectedDate(prevDate);
setSelectedSlot(null);
setAutoAdjustedDateNotice(null);
return;
}
if (windowStartOffset > 0) {
const newOffset = windowStartOffset - 1;
const newStartDate = toIsoDateLocal(addDays(today, newOffset));
setWindowStartOffset(newOffset);
setSelectedDate(newStartDate);
setSelectedSlot(null);
setAutoAdjustedDateNotice(null);
}
};
const goToNextDay = () => {
const currentIndex = dayOptions.findIndex((o) => o.value === selectedDate);
if (currentIndex < dayOptions.length - 1) {
const nextDate = dayOptions[currentIndex + 1].value;
setSelectedDate(nextDate);
setSelectedSlot(null);
setAutoAdjustedDateNotice(null);
return;
}
const newOffset = windowStartOffset + 1;
const nextDate = toIsoDateLocal(addDays(today, newOffset));
setWindowStartOffset(newOffset);
setSelectedDate(nextDate);
setSelectedSlot(null);
setAutoAdjustedDateNotice(null);
};
const shellProps: BookingShellProps = {
complexName: availabilityQuery.data?.complexName,
complexAddress: availabilityQuery.data?.complexAddress,
@@ -1543,6 +1506,8 @@ export function PublicBookingPage({ complexSlug }: PublicBookingPageProps) {
onSelectDate: selectDate,
onPreviousDays: goToPreviousDays,
onNextDays: goToNextDays,
onPreviousDay: goToPreviousDay,
onNextDay: goToNextDay,
onSelectSport: (sportId) => {
setSelectedSportId(sportId);
setSelectedCourtId(undefined);