Add navigation for previous and next days in public booking
This commit is contained in:
@@ -108,6 +108,8 @@ type BookingShellProps = {
|
|||||||
onSelectDate: (date: string) => void;
|
onSelectDate: (date: string) => void;
|
||||||
onPreviousDays: () => void;
|
onPreviousDays: () => void;
|
||||||
onNextDays: () => void;
|
onNextDays: () => void;
|
||||||
|
onPreviousDay: () => void;
|
||||||
|
onNextDay: () => void;
|
||||||
onSelectSport: (sportId: string) => void;
|
onSelectSport: (sportId: string) => void;
|
||||||
onSelectCourt: (courtId: string) => void;
|
onSelectCourt: (courtId: string) => void;
|
||||||
onSelectSlot: (slot: SelectedSlot) => void;
|
onSelectSlot: (slot: SelectedSlot) => void;
|
||||||
@@ -527,9 +529,6 @@ function PublicBookingDesktop(props: BookingShellProps) {
|
|||||||
sportSelectionRequired,
|
sportSelectionRequired,
|
||||||
errorMessage,
|
errorMessage,
|
||||||
autoAdjustedDateNotice,
|
autoAdjustedDateNotice,
|
||||||
onPreviousDays,
|
|
||||||
onNextDays,
|
|
||||||
onSelectDate,
|
|
||||||
onSelectSport,
|
onSelectSport,
|
||||||
onSelectCourt,
|
onSelectCourt,
|
||||||
onSelectSlot,
|
onSelectSlot,
|
||||||
@@ -538,6 +537,8 @@ function PublicBookingDesktop(props: BookingShellProps) {
|
|||||||
const currentStep = getStep(selectedSlot, props.form.formState.isValid);
|
const currentStep = getStep(selectedSlot, props.form.formState.isValid);
|
||||||
const completedSteps = getCompletedSteps(selectedSlot, props.form.formState.isValid);
|
const completedSteps = getCompletedSteps(selectedSlot, props.form.formState.isValid);
|
||||||
const selectedDay = dayOptions.find((option) => option.value === selectedDate);
|
const selectedDay = dayOptions.find((option) => option.value === selectedDate);
|
||||||
|
const currentDayIndex = dayOptions.findIndex((option) => option.value === selectedDate);
|
||||||
|
const canGoBackButton = canGoBack || currentDayIndex > 0;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PublicBookingPageChrome
|
<PublicBookingPageChrome
|
||||||
@@ -635,9 +636,9 @@ function PublicBookingDesktop(props: BookingShellProps) {
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="flex size-11 items-center justify-center border-r border-white/10 transition hover:bg-white/[0.06]"
|
className="flex size-11 items-center justify-center border-r border-white/10 transition hover:bg-white/[0.06]"
|
||||||
onClick={onPreviousDays}
|
onClick={props.onPreviousDay}
|
||||||
disabled={!canGoBack}
|
disabled={!canGoBackButton}
|
||||||
aria-label="Mostrar días anteriores"
|
aria-label="Día anterior"
|
||||||
>
|
>
|
||||||
<ChevronLeft className="size-5" />
|
<ChevronLeft className="size-5" />
|
||||||
</button>
|
</button>
|
||||||
@@ -648,8 +649,8 @@ function PublicBookingDesktop(props: BookingShellProps) {
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="flex size-11 items-center justify-center border-l border-white/10 transition hover:bg-white/[0.06]"
|
className="flex size-11 items-center justify-center border-l border-white/10 transition hover:bg-white/[0.06]"
|
||||||
onClick={onNextDays}
|
onClick={props.onNextDay}
|
||||||
aria-label="Mostrar próximos días"
|
aria-label="Día siguiente"
|
||||||
>
|
>
|
||||||
<ChevronRight className="size-5" />
|
<ChevronRight className="size-5" />
|
||||||
</button>
|
</button>
|
||||||
@@ -670,44 +671,6 @@ function PublicBookingDesktop(props: BookingShellProps) {
|
|||||||
<CourtDetails court={selectedCourt} />
|
<CourtDetails court={selectedCourt} />
|
||||||
<SelectedSlotCard {...props} />
|
<SelectedSlotCard {...props} />
|
||||||
</div>
|
</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>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
</PublicBookingPageChrome>
|
</PublicBookingPageChrome>
|
||||||
@@ -757,10 +720,10 @@ function PublicBookingMobile(props: BookingShellProps) {
|
|||||||
<span className="px-2 text-sm text-white/76">Fecha</span>
|
<span className="px-2 text-sm text-white/76">Fecha</span>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={props.onPreviousDays}
|
onClick={props.onPreviousDay}
|
||||||
disabled={!props.canGoBack}
|
disabled={!props.canGoBack}
|
||||||
className="flex size-9 items-center justify-center rounded-md border border-white/10 bg-white/[0.035] disabled:opacity-35"
|
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" />
|
<ChevronLeft className="size-4" />
|
||||||
</button>
|
</button>
|
||||||
@@ -770,9 +733,9 @@ function PublicBookingMobile(props: BookingShellProps) {
|
|||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
type="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]"
|
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" />
|
<ChevronRight className="size-4" />
|
||||||
</button>
|
</button>
|
||||||
@@ -804,43 +767,6 @@ function PublicBookingMobile(props: BookingShellProps) {
|
|||||||
<SelectedSlotCard {...props} compact />
|
<SelectedSlotCard {...props} compact />
|
||||||
</div>
|
</div>
|
||||||
</Panel>
|
</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>
|
</div>
|
||||||
</PublicBookingPageChrome>
|
</PublicBookingPageChrome>
|
||||||
);
|
);
|
||||||
@@ -1298,6 +1224,7 @@ export function PublicBookingPage({ complexSlug }: PublicBookingPageProps) {
|
|||||||
const availabilityQuery = useQuery({
|
const availabilityQuery = useQuery({
|
||||||
queryKey: ['public-booking-availability', complexSlug, selectedDate, selectedSportId],
|
queryKey: ['public-booking-availability', complexSlug, selectedDate, selectedSportId],
|
||||||
enabled: Boolean(selectedDate),
|
enabled: Boolean(selectedDate),
|
||||||
|
placeholderData: (previousData) => previousData,
|
||||||
queryFn: () =>
|
queryFn: () =>
|
||||||
apiClient.publicBookings.getAvailability(complexSlug, {
|
apiClient.publicBookings.getAvailability(complexSlug, {
|
||||||
date: selectedDate,
|
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 = {
|
const shellProps: BookingShellProps = {
|
||||||
complexName: availabilityQuery.data?.complexName,
|
complexName: availabilityQuery.data?.complexName,
|
||||||
complexAddress: availabilityQuery.data?.complexAddress,
|
complexAddress: availabilityQuery.data?.complexAddress,
|
||||||
@@ -1543,6 +1506,8 @@ export function PublicBookingPage({ complexSlug }: PublicBookingPageProps) {
|
|||||||
onSelectDate: selectDate,
|
onSelectDate: selectDate,
|
||||||
onPreviousDays: goToPreviousDays,
|
onPreviousDays: goToPreviousDays,
|
||||||
onNextDays: goToNextDays,
|
onNextDays: goToNextDays,
|
||||||
|
onPreviousDay: goToPreviousDay,
|
||||||
|
onNextDay: goToNextDay,
|
||||||
onSelectSport: (sportId) => {
|
onSelectSport: (sportId) => {
|
||||||
setSelectedSportId(sportId);
|
setSelectedSportId(sportId);
|
||||||
setSelectedCourtId(undefined);
|
setSelectedCourtId(undefined);
|
||||||
|
|||||||
Reference in New Issue
Block a user