-
Notifications
You must be signed in to change notification settings - Fork 12k
fix: duplicate getSchedule call #23256
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
a886472
2e41a8f
4655327
b734d79
b3ae586
30b3819
7e796f8
9dbe491
5ef1456
b15df01
8974752
f16924c
31505c7
8b95177
4adb242
6d71623
0d6d0be
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| import { shallow } from "zustand/shallow"; | ||
|
|
||
| import { useBookerStoreContext } from "@calcom/features/bookings/Booker/BookerStoreProvider"; | ||
| import { trpc } from "@calcom/trpc/react"; | ||
|
|
||
| export type useEventReturnType = ReturnType<typeof useEvent>; | ||
|
|
||
| /** | ||
| * Wrapper hook around the trpc query that fetches | ||
| * the event currently viewed in the booker. It will get | ||
| * the current event slug and username from the booker store. | ||
| * | ||
| * Using this hook means you only need to use one hook, instead | ||
| * of combining multiple conditional hooks. | ||
| */ | ||
| export const useEvent = (props?: { fromRedirectOfNonOrgLink?: boolean; disabled?: boolean }) => { | ||
| const [username, eventSlug, isTeamEvent, org] = useBookerStoreContext( | ||
| (state) => [state.username, state.eventSlug, state.isTeamEvent, state.org], | ||
| shallow | ||
| ); | ||
|
|
||
| const event = trpc.viewer.public.event.useQuery( | ||
| { | ||
| username: username ?? "", | ||
| eventSlug: eventSlug ?? "", | ||
| isTeamEvent, | ||
| org: org ?? null, | ||
| fromRedirectOfNonOrgLink: props?.fromRedirectOfNonOrgLink, | ||
| }, | ||
| { | ||
| refetchOnWindowFocus: false, | ||
| enabled: !props?.disabled && Boolean(username) && Boolean(eventSlug), | ||
| } | ||
| ); | ||
|
|
||
| return { | ||
| data: event?.data, | ||
| isSuccess: event?.isSuccess, | ||
| isError: event?.isError, | ||
| isPending: event?.isPending, | ||
| }; | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -70,8 +70,6 @@ const Day = ({ | |
| away, | ||
| emoji, | ||
| customClassName, | ||
| showMonthTooltip, | ||
| isFirstDayOfNextMonth, | ||
| ...props | ||
| }: JSX.IntrinsicElements["button"] & { | ||
| active: boolean; | ||
|
|
@@ -82,12 +80,11 @@ const Day = ({ | |
| dayContainer?: string; | ||
| dayActive?: string; | ||
| }; | ||
| showMonthTooltip?: boolean; | ||
| isFirstDayOfNextMonth?: boolean; | ||
| }) => { | ||
| const { t } = useLocale(); | ||
| const enabledDateButtonEmbedStyles = useEmbedStyles("enabledDateButton"); | ||
| const disabledDateButtonEmbedStyles = useEmbedStyles("disabledDateButton"); | ||
| const [month] = useBookerStoreContext((state) => [state.month], shallow); | ||
|
|
||
|
Comment on lines
+87
to
88
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Day now hard-depends on Booker store — breaks consumers outside Booker.
Apply this refactor: @@
const Day = ({
date,
active,
disabled,
away,
emoji,
customClassName,
...props
}: JSX.IntrinsicElements["button"] & {
active: boolean;
date: Dayjs;
away?: boolean;
emoji?: string | null;
customClassName?: {
dayContainer?: string;
dayActive?: string;
};
+ // Key for comparing whether a given day belongs to the currently browsed month (YYYY-MM)
+ monthKey?: string | null;
}) => {
const { t } = useLocale();
const enabledDateButtonEmbedStyles = useEmbedStyles("enabledDateButton");
const disabledDateButtonEmbedStyles = useEmbedStyles("disabledDateButton");
- const [month] = useBookerStoreContext((state) => [state.month], shallow);
+ // If no monthKey provided, default to the day's own month so comparisons safely no-op
+ const monthKey = props.monthKey ?? date.format("YYYY-MM");
@@
- const content =
- !disabled && month !== date.format("YYYY-MM") ? (
+ const content =
+ !disabled && monthKey !== date.format("YYYY-MM") ? (
<Tooltip content={date.format("MMMM")}>{buttonContent}</Tooltip>
) : (
buttonContent
);
@@
- {month !== date.format("YYYY-MM") && date.date() === 1 && (
+ {monthKey !== date.format("YYYY-MM") && date.date() === 1 && (
<div
className={classNames(
"absolute top-0 z-10 mx-auto w-fit rounded-full font-semibold uppercase tracking-wide",
active ? "text-white" : "text-default",
disabled && "bg-emphasis"
)}
style={{
fontSize: "10px",
lineHeight: "13px",
padding: disabled ? "0 3px" : "3px 3px 3px 4px",
}}>
{date.format("MMM")}
</div>
)}And pass the key from @@
- <DayComponent
+ <DayComponent
+ monthKey={browsingDate.format("YYYY-MM")}
customClassName={{
dayContainer: customClassName?.datePickerDate,
dayActive: customClassName?.datePickerDateActive,
}}
date={day}Also applies to: 123-129, 132-146 |
||
| const buttonContent = ( | ||
| <button | ||
|
|
@@ -123,15 +120,16 @@ const Day = ({ | |
| </button> | ||
| ); | ||
|
|
||
| const content = showMonthTooltip ? ( | ||
| <Tooltip content={date.format("MMMM")}>{buttonContent}</Tooltip> | ||
| ) : ( | ||
| buttonContent | ||
| ); | ||
| const content = | ||
| !disabled && month !== date.format("YYYY-MM") ? ( | ||
| <Tooltip content={date.format("MMMM")}>{buttonContent}</Tooltip> | ||
| ) : ( | ||
| buttonContent | ||
| ); | ||
|
|
||
| return ( | ||
| <> | ||
| {isFirstDayOfNextMonth && ( | ||
| {month !== date.format("YYYY-MM") && date.date() === 1 && ( | ||
| <div | ||
| className={classNames( | ||
| "absolute top-0 z-10 mx-auto w-fit rounded-full font-semibold uppercase tracking-wide", | ||
|
|
@@ -198,7 +196,6 @@ const Days = ({ | |
| const totalDays = daysInMonth(browsingDate); | ||
|
|
||
| const showNextMonthDays = isSecondWeekOver && !isCompact; | ||
|
|
||
| // Only apply end-of-month logic for main monthly view (not compact sidebar) | ||
| if (showNextMonthDays) { | ||
| const startDay = 8; | ||
|
|
@@ -262,7 +259,6 @@ const Days = ({ | |
| const oooInfo = daySlots.find((slot) => slot.away) || null; | ||
|
|
||
| const isNextMonth = day.month() !== browsingDate.month(); | ||
| const isFirstDayOfNextMonth = isSecondWeekOver && !isCompact && isNextMonth && day.date() === 1; | ||
|
|
||
| const included = includedDates?.includes(dateKey); | ||
| const excluded = excludedDates.includes(dateKey); | ||
|
|
@@ -272,27 +268,25 @@ const Days = ({ | |
| const away = isOOOAllDay; | ||
|
|
||
| const disabled = away ? !oooInfo?.toUser : isNextMonth ? !hasAvailableSlots : !included || excluded; | ||
|
|
||
| return { | ||
| day, | ||
| disabled, | ||
| away, | ||
| emoji: oooInfo?.emoji, | ||
| isFirstDayOfNextMonth, | ||
| }; | ||
| }); | ||
|
|
||
| const hasDatesLoaded = Boolean(daysToRenderForTheMonth.find((day) => !day.disabled)); | ||
|
|
||
| /** | ||
| * Takes care of selecting a valid date in the month if the selected date is not available in the month | ||
| */ | ||
|
|
||
| const useHandleInitialDateSelection = () => { | ||
| // Let's not do something for now in case of multiple selected dates as behaviour is unclear and it's not needed at the moment | ||
| if (selected instanceof Array) { | ||
| if (!hasDatesLoaded || selected instanceof Array) { | ||
| return; | ||
| } | ||
| const firstAvailableDateOfTheMonth = daysToRenderForTheMonth.find((day) => !day.disabled)?.day; | ||
|
|
||
| const isSelectedDateAvailable = selected | ||
| ? daysToRenderForTheMonth.some(({ day, disabled }) => { | ||
| if (day && yyyymmdd(day) === yyyymmdd(selected) && !disabled) return true; | ||
|
|
@@ -303,20 +297,16 @@ const Days = ({ | |
| // If selected date not available in the month, select the first available date of the month | ||
| const shouldOmitUpdatingParams = selected?.isValid() ? false : true; // In case a date is selected and it is not available, then we have to change search params | ||
| props.onChange(firstAvailableDateOfTheMonth, shouldOmitUpdatingParams); | ||
| } | ||
| if (isSelectedDateAvailable) { | ||
| } else if (isSelectedDateAvailable) { | ||
| props.onChange(dayjs(selected), true); | ||
| } | ||
| if (!firstAvailableDateOfTheMonth) { | ||
| props.onChange(null); | ||
| } | ||
| }; | ||
|
|
||
| useEffect(useHandleInitialDateSelection); | ||
| useEffect(useHandleInitialDateSelection, [hasDatesLoaded, month]); | ||
|
|
||
| return ( | ||
| <> | ||
| {daysToRenderForTheMonth.map(({ day, disabled, away, emoji, isFirstDayOfNextMonth }, idx) => ( | ||
| {daysToRenderForTheMonth.map(({ day, disabled, away, emoji }, idx) => ( | ||
| <div key={day === null ? `e-${idx}` : `day-${day.format()}`} className="relative w-full pt-[100%]"> | ||
| {day === null ? ( | ||
| <div key={`e-${idx}`} /> | ||
|
|
@@ -342,8 +332,6 @@ const Days = ({ | |
| active={isActive(day)} | ||
| away={away} | ||
| emoji={emoji} | ||
| showMonthTooltip={showNextMonthDays && !disabled && day.month() !== browsingDate.month()} | ||
| isFirstDayOfNextMonth={isFirstDayOfNextMonth} | ||
| /> | ||
| )} | ||
| </div> | ||
|
|
@@ -407,6 +395,7 @@ const DatePicker = ({ | |
| onMonthChange(browsingDate.add(newMonth, "month")); | ||
| } | ||
| }; | ||
|
|
||
| const month = browsingDate | ||
| ? new Intl.DateTimeFormat(i18n.language, { month: "long" }).format( | ||
| new Date(browsingDate.year(), browsingDate.month()) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,14 +16,15 @@ import { | |
| useInitializeBookerStoreContext, | ||
| useBookerStoreContext, | ||
| } from "@calcom/features/bookings/Booker/BookerStoreProvider"; | ||
| import { useEvent } from "@calcom/features/bookings/Booker/hooks/useEvent"; | ||
| import { useScheduleForEvent } from "@calcom/features/bookings/Booker/hooks/useScheduleForEvent"; | ||
| import { useInitializeBookerStore } from "@calcom/features/bookings/Booker/store"; | ||
|
Comment on lines
+19
to
21
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Verification agent 🧩 Analysis chainImport path migration looks good. Hooks repointing aligns with the new module layout. Please ensure all legacy imports are removed across the repo. Run to confirm no remaining legacy imports: Also applies to: 25-27 🏁 Script executed: #!/bin/bash
rg -nP '(utils/event|schedules/lib/use-schedule/)' --type=ts --type=tsx -C2Length of output: 105 🏁 Script executed: #!/bin/bash
# Re-run legacy-import search without relying on ripgrep’s --type filter
rg -nP '(utils/event|schedules/lib/use-schedule/)' -g '*.ts' -g '*.tsx' -C2Length of output: 3625 Legacy import references detected – migration incomplete The grep search uncovered several remaining imports from the old
Please replace these legacy imports with their new equivalents under 🤖 Prompt for AI Agents |
||
| import { useEvent, useScheduleForEvent } from "@calcom/features/bookings/Booker/utils/event"; | ||
| import DatePicker from "@calcom/features/calendars/DatePicker"; | ||
| import { Dialog } from "@calcom/features/components/controlled-dialog"; | ||
| import { TimezoneSelect } from "@calcom/features/components/timezone-select"; | ||
| import { useNonEmptyScheduleDays } from "@calcom/features/schedules/hooks/useNonEmptyScheduleDays"; | ||
| import { useSlotsForDate } from "@calcom/features/schedules/hooks/useSlotsForDate"; | ||
| import type { Slot } from "@calcom/features/schedules/lib/use-schedule/types"; | ||
| import { useNonEmptyScheduleDays } from "@calcom/features/schedules/lib/use-schedule/useNonEmptyScheduleDays"; | ||
| import { useSlotsForDate } from "@calcom/features/schedules/lib/use-schedule/useSlotsForDate"; | ||
| import { APP_NAME, DEFAULT_LIGHT_BRAND_COLOR, DEFAULT_DARK_BRAND_COLOR } from "@calcom/lib/constants"; | ||
| import { weekdayToWeekIndex } from "@calcom/lib/dayjs"; | ||
| import { useCompatSearchParams } from "@calcom/lib/hooks/useCompatSearchParams"; | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Import path migration looks good; check for stragglers.
The new hooks path aligns with the PR direction.
Run to find any remaining imports of the old path:
🏁 Script executed:
Length of output: 105
🏁 Script executed:
Length of output: 790
🏁 Script executed:
Length of output: 745
Remaining import stragglers detected – please migrate these to the new hooks path
The import-path migration for
useNonEmptyScheduleDaysis correct, but the following files still reference the old@calcom/features/schedules/lib/use-schedule/*paths. Update each of these to the new hooks location (@calcom/features/schedules/hooks/...):• packages/features/bookings/Booker/components/AvailableTimeSlots.tsx (line 10)
• packages/features/bookings/components/AvailableTimes.tsx (line 12)
• packages/features/schedules/hooks/useSchedule.ts (line 6)
• packages/platform/atoms/booker/BookerPlatformWrapper.tsx (line 20)
• packages/features/embed/Embed.tsx (line 27)
For example, replace:
and
Once all of these imports are updated, the old path stragglers will be cleared and this migration can be approved.
🤖 Prompt for AI Agents