Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 43 additions & 3 deletions apps/web/modules/bookings/components/AvailableTimes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ type SlotItemProps = {
unavailableTimeSlots?: string[];
confirmButtonDisabled?: boolean;
handleSlotClick?: (slot: Slot, isOverlapping: boolean) => void;
bottomBarWidthCh?: number;
};

const SlotItem = ({
Expand All @@ -97,6 +98,7 @@ const SlotItem = ({
unavailableTimeSlots = [],
confirmButtonDisabled,
confirmStepClassNames,
bottomBarWidthCh,
}: SlotItemProps) => {
const { t } = useLocale();

Expand All @@ -112,10 +114,12 @@ const SlotItem = ({
getQueryParam("overlayCalendar") === "true" || localStorage.getItem("overlayCalendarSwitchDefault");

const { timeFormat, timezone } = useBookerTime();

const bookingData = useBookerStoreContext((state) => state.bookingData);
const layout = useBookerStoreContext((state) => state.layout);
const hasTimeSlots = !!seatsPerTimeSlot;
const computedDateWithUsersTimezone = dayjs.utc(slot.time).tz(timezone);
const formattedTime = computedDateWithUsersTimezone.format(timeFormat);

const bookingFull = !!(hasTimeSlots && slot.attendees && slot.attendees >= seatsPerTimeSlot);
const isHalfFull = slot.attendees && seatsPerTimeSlot && slot.attendees / seatsPerTimeSlot >= 0.5;
Expand All @@ -135,6 +139,18 @@ const SlotItem = ({
offset,
});

const slotHour = computedDateWithUsersTimezone.hour();
let bottomBarColor = "bg-sky-500";

if (slotHour >= 6 && slotHour < 12) {
// Morning: 6 AM to 11:59 AM
bottomBarColor = "bg-yellow-400";

} else if (slotHour >= 12 && slotHour < 18) {
// Afternoon: 12 PM to 5:59 PM
bottomBarColor = "bg-orange-400";
}

const onButtonClick = () => {
if (handleSlotClick) {
handleSlotClick(slot, isOverlapping);
Expand All @@ -146,12 +162,14 @@ const SlotItem = ({
seatsPerTimeSlot,
});
}

};

const isTimeslotUnavailable = unavailableTimeSlots.includes(slot.time);
return (
<AnimatePresence>
<div className="flex gap-2">

<Button
key={slot.time}
disabled={
Expand All @@ -169,7 +187,7 @@ const SlotItem = ({
data-time={slot.time}
onClick={onButtonClick}
className={classNames(
`hover:border-brand-default min-h-9 mb-2 flex h-auto w-full grow flex-col justify-center py-2`,
`hover:border-brand-default relative min-h-9 mb-2 flex h-auto w-full grow flex-col justify-center overflow-hidden py-2`,
selectedSlots?.includes(slot.time) && "border-brand-default",
`${customClassNames}`
)}
Expand All @@ -183,7 +201,16 @@ const SlotItem = ({
)}
/>
)}
{computedDateWithUsersTimezone.format(timeFormat)}


<span className="tabular-nums">{formattedTime}</span>

</div>
<div className="pointer-events-none absolute right-0 bottom-0 left-0 flex justify-center" aria-hidden="true">
<span
className={classNames("block h-1 rounded-t-full", bottomBarColor)}
style={{ width: `${Math.max(bottomBarWidthCh ?? 0, formattedTime.length)}ch` }}
/>
</div>
{bookingFull && <p className="text-sm">{t("booking_full")}</p>}
{hasTimeSlots && !bookingFull && (
Expand All @@ -199,7 +226,11 @@ const SlotItem = ({
/>
</p>
)}


</Button>


{!!slot.showConfirmButton && (
<HoverCard.Root>
<HoverCard.Trigger asChild>
Expand Down Expand Up @@ -267,6 +298,15 @@ export const AvailableTimes = ({
...props
}: AvailableTimesProps) => {
const { t } = useLocale();
const { timeFormat, timezone } = useBookerTime();

const bottomBarWidthCh = useMemo(() => {
return slots.reduce((maxWidth, slot) => {
if (slot.away) return maxWidth;
const width = dayjs.utc(slot.time).tz(timezone).format(timeFormat).length;
return Math.max(maxWidth, width);
}, 0);
}, [slots, timeFormat, timezone]);

const oooAllDay = slots.every((slot) => slot.away);
if (oooAllDay) {
Expand All @@ -293,7 +333,7 @@ export const AvailableTimes = ({
{oooBeforeSlots && !oooAfterSlots && <OOOSlot {...slots[0]} />}
{slots.map((slot) => {
if (slot.away) return null;
return <SlotItem key={slot.time} slot={slot} {...props} />;
return <SlotItem key={slot.time} slot={slot} bottomBarWidthCh={bottomBarWidthCh} {...props} />;
})}
{oooAfterSlots && !oooBeforeSlots && <OOOSlot {...slots[slots.length - 1]} className="pb-0" />}
</div>
Expand Down
Loading