Conversation
WalkthroughThis PR removes useTimesForSchedule and introduces lib/use-schedule/getTimesForSchedule with tests. It drops prefetchNextMonth across schedule APIs, makes monthCount explicit (default 1), and updates hooks to use getTimesForSchedule. Booker wrappers now compute monthCount only for MONTH_VIEW and stop passing prefetchNextMonth. A new Booker/hooks/useEvent is added; related imports switch from utils/lib to hooks. Types consolidate to UseScheduleForEventReturnType; component prop types updated accordingly. DatePicker and calendars adjust month tooltip/badge logic, derive month from store, and refine initial date selection. Several files update import paths; no broad runtime changes beyond the scheduling window logic. Possibly related PRs
Tip 🔌 Remote MCP (Model Context Protocol) integration is now available!Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats. ✨ Finishing Touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
Status, Documentation and Community
|
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
E2E results are ready! |
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/platform/atoms/booker/BookerPlatformWrapper.tsx (1)
241-252: Guard against undefined columnViewExtraDays and simplify monthCount logicAccessing
bookerLayout.columnViewExtraDays.currentwhen layout is notCOLUMN_VIEWcan throw at runtime. Also, the nested ternary is hard to follow.Apply this refactor to avoid unsafe access and improve readability:
- const monthCount = - ((bookerLayout.layout !== BookerLayouts.WEEK_VIEW && bookerState === "selecting_time") || - bookerLayout.layout === BookerLayouts.COLUMN_VIEW) && - dayjs(date).add(1, "month").month() !== - dayjs(date).add(bookerLayout.columnViewExtraDays.current, "day").month() - ? prefetchNextMonth - ? 3 - : 2 - : prefetchNextMonth - ? 2 - : 1; + const isColumnView = bookerLayout.layout === BookerLayouts.COLUMN_VIEW; + const crossesBoundary = isColumnView + ? dayjs(date).add(1, "month").month() !== + dayjs(date).add(bookerLayout.columnViewExtraDays.current, "day").month() + : false; + + const monthCount = + (((bookerLayout.layout !== BookerLayouts.WEEK_VIEW && bookerState === "selecting_time") || isColumnView) && + crossesBoundary) + ? (prefetchNextMonth ? 3 : 2) + : (prefetchNextMonth ? 2 : 1);
🧹 Nitpick comments (1)
packages/features/schedules/lib/use-schedule/useTimesForSchedule.ts (1)
20-22: Early return window looks correct; confirm intended inclusivityReturning
[startOfMonth, addMonths(startOfMonth, monthCount)]for falsydayCountexpands the full browsing window. Confirm backend expects the end to be exclusive.If the backend expects an inclusive end, you might consider subtracting one day from the end.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (5)
packages/features/bookings/Booker/utils/event.ts(0 hunks)packages/features/schedules/lib/use-schedule/useSchedule.ts(2 hunks)packages/features/schedules/lib/use-schedule/useTimesForSchedule.ts(1 hunks)packages/platform/atoms/booker/BookerPlatformWrapper.tsx(1 hunks)packages/platform/atoms/booker/BookerWebWrapper.tsx(3 hunks)
💤 Files with no reviewable changes (1)
- packages/features/bookings/Booker/utils/event.ts
🧰 Additional context used
📓 Path-based instructions (4)
**/*.tsx
📄 CodeRabbit inference engine (.cursor/rules/review.mdc)
Always use
t()for text localization in frontend code; direct text embedding should trigger a warning
Files:
packages/platform/atoms/booker/BookerPlatformWrapper.tsxpackages/platform/atoms/booker/BookerWebWrapper.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/review.mdc)
Flag excessive Day.js use in performance-critical code; prefer native Date or Day.js
.utc()in hot paths like loops
Files:
packages/platform/atoms/booker/BookerPlatformWrapper.tsxpackages/features/schedules/lib/use-schedule/useTimesForSchedule.tspackages/features/schedules/lib/use-schedule/useSchedule.tspackages/platform/atoms/booker/BookerWebWrapper.tsx
**/*.{ts,tsx,js,jsx}
⚙️ CodeRabbit configuration file
Flag default exports and encourage named exports. Named exports provide better tree-shaking, easier refactoring, and clearer imports. Exempt main components like pages, layouts, and components that serve as the primary export of a module.
Files:
packages/platform/atoms/booker/BookerPlatformWrapper.tsxpackages/features/schedules/lib/use-schedule/useTimesForSchedule.tspackages/features/schedules/lib/use-schedule/useSchedule.tspackages/platform/atoms/booker/BookerWebWrapper.tsx
**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/review.mdc)
**/*.ts: For Prisma queries, only select data you need; never useinclude, always useselect
Ensure thecredential.keyfield is never returned from tRPC endpoints or APIs
Files:
packages/features/schedules/lib/use-schedule/useTimesForSchedule.tspackages/features/schedules/lib/use-schedule/useSchedule.ts
🧠 Learnings (1)
📚 Learning: 2025-07-28T11:50:23.946Z
Learnt from: CR
PR: calcom/cal.com#0
File: .cursor/rules/review.mdc:0-0
Timestamp: 2025-07-28T11:50:23.946Z
Learning: Applies to **/*.{ts,tsx} : Flag excessive Day.js use in performance-critical code; prefer native Date or Day.js `.utc()` in hot paths like loops
Applied to files:
packages/features/schedules/lib/use-schedule/useTimesForSchedule.ts
🧬 Code graph analysis (2)
packages/features/schedules/lib/use-schedule/useTimesForSchedule.ts (1)
packages/features/schedules/lib/use-schedule/useSchedule.ts (1)
UseScheduleWithCacheArgs(14-30)
packages/platform/atoms/booker/BookerWebWrapper.tsx (1)
packages/embeds/embed-core/src/types.ts (1)
BookerLayouts(6-6)
🔇 Additional comments (3)
packages/platform/atoms/booker/BookerWebWrapper.tsx (1)
99-101: dayjs.max is supported via the minMax plugin—no changes needed
- The
minMaxplugin is imported inpackages/dayjs/index.ts(import minmax from "dayjs/plugin/minMax") and registered withdayjs.extend(minmax)on line 25, sodayjs.maxis available everywhere.- There’s no need for a plugin-free fallback in
BookerWebWrapper.tsx; the existing setup already covers this use case.packages/features/schedules/lib/use-schedule/useSchedule.ts (2)
22-23: No explicit monthCount call sites found; default=1 is safeI searched the entire codebase for any explicit monthCount properties in TS/TSX files and found zero occurrences, confirming that no callers were relying on an “unset” value to fetch multiple months.
• Search command:
rg -nP '\bmonthCount\s*:' -C2 -g '*.ts' -g '*.tsx'
→ 0 matchesWith no explicit overrides present, switching the default to
1poses no regression risk.
101-121: Duplicate schedule-fetch gating verified
- API V2 (
useApiV2AvailableSlots) is enabled only when
isCallingApiV2Slots = useApiV2 && Boolean(isTeamEvent) && options.enabled(lines 123–131)- TRPC V1 (
trpc.viewer.slots.getSchedule.useQuery) is enabled only when
options.enabled && !isCallingApiV2Slots(lines 135–140)options.enableditself is gated by!skipGetSchedule(i.e.cal.skipSlotsFetch=true), so setting that flag disables both V1 and V2 queries- A static search found no additional
viewer.slots.getSchedule.useQuerycalls in this fileAll gating logic is correct. Proceed with approval.
| @@ -1,41 +1,42 @@ | |||
| import dayjs from "@calcom/dayjs"; | |||
| import { startOfMonth, startOfDay, isSameMonth, addMonths, addDays } from "date-fns"; | |||
There was a problem hiding this comment.
🛠️ Refactor suggestion
Parsing month via new Date("yyyy-MM") is non‑standard; use date-fns parse to avoid Safari bugs
new Date("2025-08") is implementation-dependent and can be invalid in Safari. Use parse("yyyy-MM", ...) for robust behavior.
-import { startOfMonth, startOfDay, isSameMonth, addMonths, addDays } from "date-fns";
+import { startOfMonth, startOfDay, isSameMonth, addMonths, addDays, parse } from "date-fns";
- const browsingMonthStartDate = startOfMonth(month ? new Date(month) : currentDate);
+ const browsingMonthStartDate = startOfMonth(month ? parse(month, "yyyy-MM", currentDate) : currentDate);Also applies to: 17-18
🤖 Prompt for AI Agents
In packages/features/schedules/lib/use-schedule/useTimesForSchedule.ts around
lines 1 and 17-18, the code currently parses month strings using new
Date("yyyy-MM") which is implementation-dependent and breaks in Safari; replace
that logic by importing parse from date-fns and use parse(monthString,
"yyyy-MM", new Date()) (then wrap with isValid or startOfMonth as needed) so
parsing is deterministic across browsers; update the import line to include
parse and adjust the two locations (lines 17-18 and the earlier use) to use
parse("yyyy-MM", ...) instead of new Date("yyyy-MM").
| const selectedDateObj = new Date(selectedDate); | ||
| startTime = selectedDateObj.toISOString(); | ||
| endTime = addDays(selectedDateObj, dayCount).toISOString(); | ||
| } else if (isSameMonth(browsingMonthStartDate, currentDate)) { | ||
| startTime = startOfDay(currentDate).toISOString(); | ||
| endTime = addDays(startOfDay(currentDate), dayCount).toISOString(); | ||
| } else { | ||
| startTime = monthDayjs.startOf("month").toISOString(); |
There was a problem hiding this comment.
🛠️ Refactor suggestion
selectedDate parsing uses UTC semantics; likely off by timezone vs prior Day.js behavior
new Date("yyyy-MM-dd") parses as UTC, whereas previous Day.js usage typically treated it as local date. This can shift windows by timezone and cause incorrect ranges.
Prefer parsing as a local date with parse("yyyy-MM-dd", ...):
- if (selectedDate) {
- const selectedDateObj = new Date(selectedDate);
- startTime = selectedDateObj.toISOString();
- endTime = addDays(selectedDateObj, dayCount).toISOString();
+ if (selectedDate) {
+ const selectedDateObj = parse(selectedDate, "yyyy-MM-dd", currentDate);
+ startTime = selectedDateObj.toISOString();
+ endTime = addDays(selectedDateObj, dayCount).toISOString();Optionally add a unit test for a non-UTC timezone (e.g., America/Los_Angeles) to prevent regressions.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (selectedDate) { | |
| const selectedDateObj = new Date(selectedDate); | |
| startTime = selectedDateObj.toISOString(); | |
| endTime = addDays(selectedDateObj, dayCount).toISOString(); | |
| } else if (isSameMonth(browsingMonthStartDate, currentDate)) { | |
| startTime = startOfDay(currentDate).toISOString(); | |
| endTime = addDays(startOfDay(currentDate), dayCount).toISOString(); | |
| } else { | |
| if (selectedDate) { | |
| const selectedDateObj = parse(selectedDate, "yyyy-MM-dd", currentDate); | |
| startTime = selectedDateObj.toISOString(); | |
| endTime = addDays(selectedDateObj, dayCount).toISOString(); |
| const monthCount = | ||
| ((bookerLayout.layout !== BookerLayouts.WEEK_VIEW && bookerState === "selecting_time") || | ||
| bookerLayout.layout === BookerLayouts.COLUMN_VIEW) && | ||
| bookerLayout.layout === BookerLayouts.MONTH_VIEW && | ||
| dayjs(date).add(1, "month").month() !== | ||
| dayjs(date).add(bookerLayout.columnViewExtraDays.current, "day").month() | ||
| ? 2 | ||
| ? prefetchNextMonth | ||
| ? 2 | ||
| : 1 | ||
| : undefined; |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Incorrect dependency on columnViewExtraDays for MONTH_VIEW; potential runtime error
monthCount for MONTH_VIEW should not read columnViewExtraDays.current. This can be undefined and will crash. It also doesn’t affect month view logic.
Use only prefetchNextMonth to decide window size in MONTH_VIEW:
- const monthCount =
- bookerLayout.layout === BookerLayouts.MONTH_VIEW &&
- dayjs(date).add(1, "month").month() !==
- dayjs(date).add(bookerLayout.columnViewExtraDays.current, "day").month()
- ? prefetchNextMonth
- ? 2
- : 1
- : undefined;
+ const monthCount =
+ bookerLayout.layout === BookerLayouts.MONTH_VIEW
+ ? (prefetchNextMonth ? 2 : 1)
+ : undefined;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const monthCount = | |
| ((bookerLayout.layout !== BookerLayouts.WEEK_VIEW && bookerState === "selecting_time") || | |
| bookerLayout.layout === BookerLayouts.COLUMN_VIEW) && | |
| bookerLayout.layout === BookerLayouts.MONTH_VIEW && | |
| dayjs(date).add(1, "month").month() !== | |
| dayjs(date).add(bookerLayout.columnViewExtraDays.current, "day").month() | |
| ? 2 | |
| ? prefetchNextMonth | |
| ? 2 | |
| : 1 | |
| : undefined; | |
| const monthCount = | |
| bookerLayout.layout === BookerLayouts.MONTH_VIEW | |
| ? (prefetchNextMonth ? 2 : 1) | |
| : undefined; |
🤖 Prompt for AI Agents
In packages/platform/atoms/booker/BookerWebWrapper.tsx around lines 155 to 162,
the MONTH_VIEW branch incorrectly reads bookerLayout.columnViewExtraDays.current
(which can be undefined) and may crash; replace that logic so monthCount for
MONTH_VIEW does not access columnViewExtraDays at all and instead is determined
solely by prefetchNextMonth (set monthCount = 2 when prefetchNextMonth is true,
otherwise 1); keep the existing conditional structure for non-MONTH_VIEW cases
and ensure no access to .current in the MONTH_VIEW path.
There was a problem hiding this comment.
Actionable comments posted: 1
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
packages/platform/atoms/booker/BookerPlatformWrapper.tsx(1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.tsx
📄 CodeRabbit inference engine (.cursor/rules/review.mdc)
Always use
t()for text localization in frontend code; direct text embedding should trigger a warning
Files:
packages/platform/atoms/booker/BookerPlatformWrapper.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/review.mdc)
Flag excessive Day.js use in performance-critical code; prefer native Date or Day.js
.utc()in hot paths like loops
Files:
packages/platform/atoms/booker/BookerPlatformWrapper.tsx
**/*.{ts,tsx,js,jsx}
⚙️ CodeRabbit configuration file
Flag default exports and encourage named exports. Named exports provide better tree-shaking, easier refactoring, and clearer imports. Exempt main components like pages, layouts, and components that serve as the primary export of a module.
Files:
packages/platform/atoms/booker/BookerPlatformWrapper.tsx
🧬 Code graph analysis (1)
packages/platform/atoms/booker/BookerPlatformWrapper.tsx (1)
packages/embeds/embed-core/src/types.ts (1)
BookerLayouts(6-6)
⏰ Context from checks skipped due to timeout of 180000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: Production builds / Build Web App
- GitHub Check: Production builds / Build API v1
- GitHub Check: Tests / Unit
- GitHub Check: Type check / check-types
- GitHub Check: Codacy Static Code Analysis
| bookerLayout.layout === BookerLayouts.MONTH_VIEW && | ||
| dayjs(date).add(1, "month").month() !== | ||
| dayjs(date).add(bookerLayout.columnViewExtraDays.current, "day").month() | ||
| ? 2 | ||
| ? prefetchNextMonth | ||
| ? 2 | ||
| : 1 | ||
| : undefined; | ||
|
|
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
Critical: monthCount logic references COLUMN_VIEW-only field under MONTH_VIEW, causing incorrect behavior and potential runtime error
The condition guards for BookerLayouts.MONTH_VIEW but then dereferences bookerLayout.columnViewExtraDays.current, which is defined for COLUMN_VIEW. This can be undefined for MONTH_VIEW and lead to an exception or, worse, silently wrong logic for determining monthCount. Conceptually, for month view we only need to choose between 1 or 2 months based on prefetchNextMonth; the extra-days boundary relevant to column view should not factor here.
Recommend simplifying monthCount to rely solely on prefetchNextMonth when layout is MONTH_VIEW:
- const monthCount =
- bookerLayout.layout === BookerLayouts.MONTH_VIEW &&
- dayjs(date).add(1, "month").month() !==
- dayjs(date).add(bookerLayout.columnViewExtraDays.current, "day").month()
- ? prefetchNextMonth
- ? 2
- : 1
- : undefined;
+ const monthCount =
+ bookerLayout.layout === BookerLayouts.MONTH_VIEW
+ ? (prefetchNextMonth ? 2 : 1)
+ : undefined;Follow-ups:
- If you want to avoid unnecessary work, compute
prefetchNextMonthonly in the branch(es) where it’s actually needed (MONTH_VIEW here). That would trim a bit of dayjs work for WEEK/COLUMN views.
Verification:
- Ensure
useTimesForScheduleindeed defaultsmonthCountto1whenundefinedis passed, as assumed by the broader refactor. If that default is applied via parameter destructuring, passingundefinedis fine; if not, you may want to coalesce to1at the call site.
🏁 Script executed:
#!/bin/bash
# Verify monthCount default in useTimesForSchedule
set -euo pipefail
# Locate the hook implementation
fd -a 'useTimesForSchedule.*\.(ts|tsx)'
# Show the function signature and look for a default `monthCount = 1`
rg -n -C3 -P 'export\s+(const|function)\s+useTimesForSchedule\b|function\s+useTimesForSchedule\b'
# Look for param destructuring defaults or internal defaulting of monthCount
rg -n -C2 -P '\bmonthCount\s*=\s*1\b|\bmonthCount\b.*\|\|\s*1' $(fd -a 'useTimesForSchedule.*\.(ts|tsx)')Length of output: 1185
Simplify MONTH_VIEW monthCount logic and remove COLUMN_VIEW-only field
The current monthCount calculation in BookerPlatformWrapper.tsx (lines 242–249) references bookerLayout.columnViewExtraDays.current under BookerLayouts.MONTH_VIEW, which can be undefined in month view and is unnecessary for determining month count. Since useTimesForSchedule defaults monthCount to 1 when passed undefined, we can simplify this logic to rely solely on prefetchNextMonth for month view without altering downstream behavior.
Affected location:
- packages/platform/atoms/booker/BookerPlatformWrapper.tsx (around line 242)
Proposed diff:
- const monthCount =
- bookerLayout.layout === BookerLayouts.MONTH_VIEW &&
- dayjs(date).add(1, "month").month() !==
- dayjs(date).add(bookerLayout.columnViewExtraDays.current, "day").month()
- ? prefetchNextMonth
- ? 2
- : 1
- : undefined;
+ const monthCount =
+ bookerLayout.layout === BookerLayouts.MONTH_VIEW
+ ? (prefetchNextMonth ? 2 : 1)
+ : undefined;– Verified that useTimesForSchedule defines monthCount = 1 by default in its parameter destructuring, so passing undefined would yield the same behavior (defaulting to 1) without extra coalescing. ([script output]).
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| bookerLayout.layout === BookerLayouts.MONTH_VIEW && | |
| dayjs(date).add(1, "month").month() !== | |
| dayjs(date).add(bookerLayout.columnViewExtraDays.current, "day").month() | |
| ? 2 | |
| ? prefetchNextMonth | |
| ? 2 | |
| : 1 | |
| : undefined; | |
| const monthCount = | |
| bookerLayout.layout === BookerLayouts.MONTH_VIEW | |
| ? (prefetchNextMonth ? 2 : 1) | |
| : undefined; |
🤖 Prompt for AI Agents
In packages/platform/atoms/booker/BookerPlatformWrapper.tsx around lines 242 to
249, the MONTH_VIEW monthCount logic incorrectly references
bookerLayout.columnViewExtraDays.current (a COLUMN_VIEW-only field) — remove
that reference and simplify the expression so monthCount for MONTH_VIEW is
determined solely by prefetchNextMonth (e.g., prefetchNextMonth ? 2 :
undefined), relying on useTimesForSchedule to default undefined to 1.
| dayjs(date).add(1, "month").month() !== | ||
| dayjs(date).add(bookerLayout.columnViewExtraDays.current, "day").month() |
There was a problem hiding this comment.
what is this check doing? Do we need this?
CarinaWolli
left a comment
There was a problem hiding this comment.
Fix looks good to me. getSchedule is now only called once and everything is still working as it should
@emrysal I'm seeing that the `startTime` is July 1 instead of August 1. I'm loading the month of August. I know that in terms of perf, this will basically be ignored but we should still fix it.
|
…hat are actually hooks into a hook folder
There was a problem hiding this comment.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/features/bookings/Booker/components/AvailableTimeSlots.tsx (1)
205-208: Refactor AvailableTimeSlots.tsx to correctly derive and apply the browsing‐month badgeThe suggested IIFE in the original comment illegally calls a React hook inside a nested function, violating the Rules of Hooks. Instead, pull the store’s
monthat the top of the component and computeavailableMonthdirectly in the JSX.Locations to update:
- packages/features/bookings/Booker/components/AvailableTimeSlots.tsx
• After line 82 (wheredateis defined) – insert hooks to readstate.monthand derivecurrentMonth.
• At theAvailableTimesHeadercall around lines 180–190 – replace the existingavailableMonth={…}expression.Proposed diff:
--- a/packages/features/bookings/Booker/components/AvailableTimeSlots.tsx +++ b/packages/features/bookings/Booker/components/AvailableTimeSlots.tsx @@ 80,6 +80,9 @@ const AvailableTimeSlots = ({ onAvailableTimeSlotSelect, ...props }) => { const date = selectedDate || dayjs().format("YYYY-MM-DD"); const [layout] = useBookerStoreContext((state) => [state.layout]); const isColumnView = layout === BookerLayouts.COLUMN_VIEW; + + // Derive the browsing month (YYYY-MM) from store, falling back to the current date + const browsingMonth = useBookerStoreContext((state) => state.month); + const currentMonth = browsingMonth ?? dayjs(date).format("YYYY-MM"); return ( <> @@ 180,14 +183,10 @@ const AvailableTimeSlots = ({ onAvailableTimeSlotSelect, ...props }) => { <AvailableTimesHeader customClassNames={{ availableTimeSlotsHeaderContainer: customClassNames?.availableTimeSlotsHeaderContainer, availableTimeSlotsTitle: customClassNames?.availableTimeSlotsTitle, availableTimeSlotsTimeFormatToggle: customClassNames?.availableTimeSlotsTimeFormatToggle, }} key={slots.date} - date={dayjs(slots.date)} + date={dayjs(slots.date)} showTimeFormatToggle={!isColumnView} - availableMonth={ - dayjs(selectedDate).format("MM") !== dayjs(slots.date).format("MM") - ? dayjs(slots.date).format("MMM") - : undefined - } + availableMonth={ + currentMonth !== dayjs(slots.date).format("YYYY-MM") + ? dayjs(slots.date).format("MMM") + : undefined + } />This ensures we adhere to the Rules of Hooks and correctly label the first column of a new browsing month.
🧹 Nitpick comments (18)
packages/features/calendars/DatePicker.tsx (1)
287-301: Use Array.isArray and simplify boolean.Minor safety/readability.
- if (!hasDatesLoaded || selected instanceof Array) { + if (!hasDatesLoaded || Array.isArray(selected)) { return; } @@ - const shouldOmitUpdatingParams = selected?.isValid() ? false : true; // In case a date is selected and it is not available, then we have to change search params + // If a (valid) date was previously selected, update params; otherwise, omit + const shouldOmitUpdatingParams = !selected?.isValid();packages/features/troubleshooter/components/LargeCalendar.tsx (1)
79-85: Localize user-visible strings (“Busy”, “Date Override”).Per guidelines, wrap with
t().+import { useLocale } from "@calcom/lib/hooks/useLocale"; @@ - const events = useMemo(() => { + const { t } = useLocale(); + const events = useMemo(() => { @@ - title: event.title ?? `Busy`, + title: event.title ?? t("busy"), @@ - title: "Date Override", + title: t("date_override"),Also applies to: 111-116
packages/features/schedules/hooks/useSlotsForDate.ts (1)
35-50: Avoid JSON.stringify in effect deps.Serializing on every render is costly; prefer stable deps.
- }, [JSON.stringify(dates), JSON.stringify(slots)]); + }, [dates.join('|'), slots ? Object.keys(slots).join('|') : 'no-slots']);Or switch to a deep-compare hook where available.
packages/features/embed/Embed.tsx (3)
216-219: Open external link with noopener/noreferrer.Prevents opener-based attacks and removes referrer leakage.
- window.open("https://cal.com/help/routing/headless-routing", "_blank"); + window.open("https://cal.com/help/routing/headless-routing", "_blank", "noopener,noreferrer");
959-960: Localize hardcoded UI strings.Several user-facing strings bypass t(). Please wrap them for i18n.
Example:
- <div className="text-default mb-[9px] text-sm">Window sizing</div> + <div className="text-default mb-[9px] text-sm">{t("window_sizing")}</div> ... - <div className="mb-2 text-sm">Button text</div> + <div className="mb-2 text-sm">{t("button_text")}</div> ... - <div className="text-default my-2 text-sm">Display calendar icon</div> + <div className="text-default my-2 text-sm">{t("display_calendar_icon")}</div> ... - <div className="mb-2">Position of button</div> + <div className="mb-2">{t("position_of_button")}</div> ... - <div className="whitespace-nowrap">Button color</div> + <div className="whitespace-nowrap">{t("button_color")}</div> - <div className="whitespace-nowrap">Text color</div> + <div className="whitespace-nowrap">{t("text_color")}</div>Also applies to: 1012-1031, 1038-1053, 1059-1075, 1077-1119
861-876: Use modern Clipboard API with fallback.execCommand is deprecated. Prefer navigator.clipboard with a fallback for non-secure contexts.
- const handleCopyEmailText = () => { + const handleCopyEmailText = async () => { const contentElement = emailContentRef.current; if (contentElement !== null) { - const range = document.createRange(); - range.selectNode(contentElement); - const selection = window.getSelection(); - if (selection) { - selection.removeAllRanges(); - selection.addRange(range); - document.execCommand("copy"); - selection.removeAllRanges(); - } + const html = contentElement.outerHTML; + try { + if ("clipboard" in navigator && "write" in navigator.clipboard && "ClipboardItem" in window) { + const item = new ClipboardItem({ "text/html": new Blob([html], { type: "text/html" }) }); + await (navigator.clipboard as any).write([item]); + } else { + const range = document.createRange(); + range.selectNode(contentElement); + const selection = window.getSelection(); + if (selection) { + selection.removeAllRanges(); + selection.addRange(range); + document.execCommand("copy"); + selection.removeAllRanges(); + } + } + } catch { + // noop: rely on fallback or silent failure + } showToast(t("code_copied"), "success"); } };packages/features/bookings/Booker/components/LargeCalendar.tsx (1)
42-51: Minor: avoid duplicate dayjs conversions inside the loop.Cache dayjs(time) to reuse for start/end construction.
- availableTimeslots[day] = schedule.slots[day].map((slot) => { - const { time, ...rest } = slot; - return { - start: dayjs(time).toDate(), - end: dayjs(time).add(eventDuration, "minutes").toDate(), - ...rest, - }; - }); + availableTimeslots[day] = schedule.slots[day].map(({ time, ...rest }) => { + const d = dayjs(time); + return { start: d.toDate(), end: d.add(eventDuration, "minutes").toDate(), ...rest }; + });packages/features/bookings/Booker/hooks/useEvent.ts (2)
6-6: Name exported types in PascalCase.Prefer UseEventReturnType for consistency with TS type naming.
-export type useEventReturnType = ReturnType<typeof useEvent>; +export type UseEventReturnType = ReturnType<typeof useEvent>;
22-34: Consider cache tuning to reduce redundant refetches.Add staleTime and keepPreviousData to smooth navigation and avoid unnecessary network calls.
const event = trpc.viewer.public.event.useQuery( @@ - { - refetchOnWindowFocus: false, - enabled: !props?.disabled && Boolean(username) && Boolean(eventSlug), - } + { + refetchOnWindowFocus: false, + enabled: !props?.disabled && Boolean(username) && Boolean(eventSlug), + staleTime: 30_000, + keepPreviousData: true, + } );packages/features/bookings/Booker/components/AvailableTimeSlots.tsx (1)
127-138: Guard invalidate behind existence to avoid no-op calls.Already behind a flag, but also short-circuit when schedule has no invalidate.
- if (PUBLIC_INVALIDATE_AVAILABLE_SLOTS_ON_BOOKING_FORM) { + if (PUBLIC_INVALIDATE_AVAILABLE_SLOTS_ON_BOOKING_FORM && schedule?.invalidate) { // Ensures that user has latest available slots when they are about to confirm the booking by filling up the details schedule?.invalidate(); }packages/features/schedules/lib/use-schedule/getTimesForSchedule.test.ts (3)
79-79: Remove stray console.log from testsUnnecessary logging adds noise and can hide flakes. Please remove.
- console.log(new Date().toISOString());
106-110: Avoid redundant toString() on stringtoLocalIsoWithOffset already returns a string. The extra .toString() is redundant.
- expect(toLocalIsoWithOffset(new Date(startTime)).toString().startsWith("2025-08-23T00:00:00")).toBe( + expect(toLocalIsoWithOffset(new Date(startTime)).startsWith("2025-08-23T00:00:00")).toBe( true ); - expect(toLocalIsoWithOffset(new Date(endTime)).toString().startsWith("2025-08-30T00:00:00")).toBe(true); + expect(toLocalIsoWithOffset(new Date(endTime)).startsWith("2025-08-30T00:00:00")).toBe(true);
29-36: Add a test for dayCount <= 0 and invalid month formatTwo gaps to harden behavior:
- When dayCount <= 0, assert we return full-month [start, end].
- If an invalid month string is passed, decide whether to throw or fallback; add a test to lock this in once implementation is updated (see comments in getTimesForSchedule.ts).
I can add targeted test cases once you confirm desired behavior (throw vs fallback).
Also applies to: 52-66, 99-111, 113-127
packages/features/schedules/lib/use-schedule/getTimesForSchedule.ts (3)
10-13: Validate month string to prevent accidental NaN datesparseMonth assumes a well-formed "YYYY-MM". Add a minimal guard to reduce surprises downstream.
-const parseMonth = (monthString: string) => { - const [year, month] = monthString.split("-").map(Number); - return new Date(year, month - 1); -}; +const parseMonth = (monthString: string) => { + const match = /^(\d{4})-(\d{2})$/.exec(monthString); + if (!match) throw new Error(`Invalid month format: ${monthString}`); + const year = Number(match[1]); + const month = Number(match[2]); + if (month < 1 || month > 12) throw new Error(`Invalid month value: ${month}`); + return new Date(year, month - 1); +};
17-25: Normalize non-positive monthCountA non-positive monthCount would produce a backward or zero-length window. Consider clamping to at least 1.
export const getTimesForSchedule = ({ month, - monthCount = 1, + monthCount = 1, selectedDate, dayCount, }: GetTimesForScheduleProps): [string, string] => { + monthCount = Math.max(1, monthCount ?? 1);
21-26: Timezone semantics: compute boundaries in the intended booking timezone (future enhancement)The current logic derives month/day boundaries from the runtime local timezone. If the user-selected timezone differs from the runtime, this can show confusing start dates (e.g., “July 31/July 1” while browsing August). Long-term, consider accepting a timezone parameter and using date-fns-tz to compute startOfMonth/startOfDay in that zone before converting to ISO.
If you want, I can propose a backward-compatible variant of getTimesForSchedule that accepts an optional IANA timezone and adds date-fns-tz with minimal surface area.
Also applies to: 34-49
packages/features/schedules/hooks/useSchedule.ts (1)
76-101: Consider stabilizing the query input object to reduce refetch noiseinput is recreated on every render (new arrays/objects from searchParams, usernameList). If you observe unexpected refetches, memoize derived pieces (e.g., routedTeamMemberIds) or split stable/unstable parts.
packages/features/bookings/Booker/hooks/useScheduleForEvent.ts (1)
71-72: Minor style nit: use property shorthandTiny cleanup opportunity.
- useApiV2: useApiV2, + useApiV2,
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (17)
packages/features/bookings/Booker/Booker.tsx(1 hunks)packages/features/bookings/Booker/components/AvailableTimeSlots.tsx(1 hunks)packages/features/bookings/Booker/components/BookEventForm/BookFormAsModal.tsx(1 hunks)packages/features/bookings/Booker/components/DatePicker.tsx(2 hunks)packages/features/bookings/Booker/components/LargeCalendar.tsx(2 hunks)packages/features/bookings/Booker/hooks/useEvent.ts(1 hunks)packages/features/bookings/Booker/hooks/useScheduleForEvent.ts(1 hunks)packages/features/bookings/Booker/types.ts(2 hunks)packages/features/calendars/DatePicker.tsx(5 hunks)packages/features/embed/Embed.tsx(1 hunks)packages/features/schedules/hooks/useNonEmptyScheduleDays.ts(1 hunks)packages/features/schedules/hooks/useSchedule.ts(4 hunks)packages/features/schedules/hooks/useSlotsForDate.ts(1 hunks)packages/features/schedules/lib/use-schedule/getTimesForSchedule.test.ts(1 hunks)packages/features/schedules/lib/use-schedule/getTimesForSchedule.ts(1 hunks)packages/features/schedules/lib/use-schedule/useTimesForSchedule.ts(0 hunks)packages/features/troubleshooter/components/LargeCalendar.tsx(1 hunks)
💤 Files with no reviewable changes (1)
- packages/features/schedules/lib/use-schedule/useTimesForSchedule.ts
✅ Files skipped from review due to trivial changes (1)
- packages/features/schedules/hooks/useNonEmptyScheduleDays.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/features/bookings/Booker/components/DatePicker.tsx
🧰 Additional context used
📓 Path-based instructions (4)
**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/review.mdc)
**/*.ts: For Prisma queries, only select data you need; never useinclude, always useselect
Ensure thecredential.keyfield is never returned from tRPC endpoints or APIs
Files:
packages/features/schedules/hooks/useSlotsForDate.tspackages/features/schedules/lib/use-schedule/getTimesForSchedule.tspackages/features/schedules/lib/use-schedule/getTimesForSchedule.test.tspackages/features/bookings/Booker/types.tspackages/features/bookings/Booker/hooks/useEvent.tspackages/features/schedules/hooks/useSchedule.tspackages/features/bookings/Booker/hooks/useScheduleForEvent.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/review.mdc)
Flag excessive Day.js use in performance-critical code; prefer native Date or Day.js
.utc()in hot paths like loops
Files:
packages/features/schedules/hooks/useSlotsForDate.tspackages/features/troubleshooter/components/LargeCalendar.tsxpackages/features/bookings/Booker/Booker.tsxpackages/features/bookings/Booker/components/LargeCalendar.tsxpackages/features/schedules/lib/use-schedule/getTimesForSchedule.tspackages/features/schedules/lib/use-schedule/getTimesForSchedule.test.tspackages/features/bookings/Booker/components/BookEventForm/BookFormAsModal.tsxpackages/features/bookings/Booker/types.tspackages/features/bookings/Booker/hooks/useEvent.tspackages/features/bookings/Booker/components/AvailableTimeSlots.tsxpackages/features/embed/Embed.tsxpackages/features/schedules/hooks/useSchedule.tspackages/features/calendars/DatePicker.tsxpackages/features/bookings/Booker/hooks/useScheduleForEvent.ts
**/*.{ts,tsx,js,jsx}
⚙️ CodeRabbit configuration file
Flag default exports and encourage named exports. Named exports provide better tree-shaking, easier refactoring, and clearer imports. Exempt main components like pages, layouts, and components that serve as the primary export of a module.
Files:
packages/features/schedules/hooks/useSlotsForDate.tspackages/features/troubleshooter/components/LargeCalendar.tsxpackages/features/bookings/Booker/Booker.tsxpackages/features/bookings/Booker/components/LargeCalendar.tsxpackages/features/schedules/lib/use-schedule/getTimesForSchedule.tspackages/features/schedules/lib/use-schedule/getTimesForSchedule.test.tspackages/features/bookings/Booker/components/BookEventForm/BookFormAsModal.tsxpackages/features/bookings/Booker/types.tspackages/features/bookings/Booker/hooks/useEvent.tspackages/features/bookings/Booker/components/AvailableTimeSlots.tsxpackages/features/embed/Embed.tsxpackages/features/schedules/hooks/useSchedule.tspackages/features/calendars/DatePicker.tsxpackages/features/bookings/Booker/hooks/useScheduleForEvent.ts
**/*.tsx
📄 CodeRabbit inference engine (.cursor/rules/review.mdc)
Always use
t()for text localization in frontend code; direct text embedding should trigger a warning
Files:
packages/features/troubleshooter/components/LargeCalendar.tsxpackages/features/bookings/Booker/Booker.tsxpackages/features/bookings/Booker/components/LargeCalendar.tsxpackages/features/bookings/Booker/components/BookEventForm/BookFormAsModal.tsxpackages/features/bookings/Booker/components/AvailableTimeSlots.tsxpackages/features/embed/Embed.tsxpackages/features/calendars/DatePicker.tsx
🧠 Learnings (1)
📚 Learning: 2025-08-21T13:44:06.805Z
Learnt from: supalarry
PR: calcom/cal.com#23217
File: apps/api/v2/src/ee/event-types/event-types_2024_06_14/services/output-event-types.service.ts:93-94
Timestamp: 2025-08-21T13:44:06.805Z
Learning: In apps/api/v2/src/ee/event-types/event-types_2024_06_14/event-types.repository.ts, repository functions that use explicit Prisma select clauses (like getEventTypeWithSeats) are used for specific purposes and don't need to include all EventType fields like bookingRequiresAuthentication. These methods don't feed into the general OutputEventTypesService_2024_06_14 flow.
Applied to files:
packages/features/bookings/Booker/hooks/useScheduleForEvent.ts
🧬 Code graph analysis (7)
packages/features/bookings/Booker/components/LargeCalendar.tsx (1)
packages/features/bookings/Booker/hooks/useScheduleForEvent.ts (1)
UseScheduleForEventReturnType(9-9)
packages/features/schedules/lib/use-schedule/getTimesForSchedule.test.ts (1)
packages/features/schedules/lib/use-schedule/getTimesForSchedule.ts (1)
getTimesForSchedule(15-49)
packages/features/bookings/Booker/types.ts (1)
packages/features/bookings/Booker/hooks/useScheduleForEvent.ts (1)
UseScheduleForEventReturnType(9-9)
packages/features/bookings/Booker/hooks/useEvent.ts (3)
packages/features/bookings/Booker/BookerStoreProvider.tsx (1)
useBookerStoreContext(24-35)packages/trpc/server/routers/publicViewer/procedures/event.ts (1)
event(8-12)apps/web/app/_trpc/trpc.ts (1)
trpc(7-7)
packages/features/bookings/Booker/components/AvailableTimeSlots.tsx (1)
packages/features/bookings/Booker/hooks/useScheduleForEvent.ts (1)
UseScheduleForEventReturnType(9-9)
packages/features/schedules/hooks/useSchedule.ts (1)
packages/features/schedules/lib/use-schedule/getTimesForSchedule.ts (1)
getTimesForSchedule(15-49)
packages/features/calendars/DatePicker.tsx (1)
packages/features/bookings/Booker/BookerStoreProvider.tsx (1)
useBookerStoreContext(24-35)
⏰ Context from checks skipped due to timeout of 180000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Install dependencies / Yarn install & cache
🔇 Additional comments (12)
packages/features/calendars/DatePicker.tsx (2)
305-306: Effect dependencies may miss updates when selection changes.If
selectedchanges (e.g., via URL param) after load, the effect won’t re-run. Confirm intent; otherwise includeselectedand a stable marker fordaysToRenderForTheMonth.Suggested adjustment (ensure no loops first):
-useEffect(useHandleInitialDateSelection, [hasDatesLoaded, month]); +useEffect(useHandleInitialDateSelection, [hasDatesLoaded, month, Array.isArray(selected) ? 'multi' : selected?.format?.('YYYY-MM-DD')]);
399-403: Month label vs month key confusion.Here
monthis a localized label (“August”), but elsewhere “month” often denotes a key like “YYYY-MM”. SinceDaysforwardsmonthtoNoAvailabilityDialog, confirm it expects a label, not a key. If it expects a key, passbrowsingDate.format("YYYY-MM")instead.Option if a key is required:
-const month = browsingDate +const monthLabel = browsingDate ? new Intl.DateTimeFormat(i18n.language, { month: "long" }).format( new Date(browsingDate.year(), browsingDate.month()) ) : null; +const month = browsingDate.format("YYYY-MM"); // key…and use
monthLabelfor the header display.packages/features/bookings/Booker/components/BookEventForm/BookFormAsModal.tsx (1)
13-13: No lingering../../utils/eventimports detected.I’ve scanned all
.tsand.tsxfiles underpackages/features/bookingsfor any references to the old../../utils/eventpath and confirmed there are none. The hook import path migration is clean—no further action needed.packages/features/troubleshooter/components/LargeCalendar.tsx (1)
5-5: Updated imports match the new hooks layout.Also applies to: 8-8
packages/features/schedules/hooks/useSlotsForDate.ts (1)
3-3: Type import path update looks correct.packages/features/bookings/Booker/components/LargeCalendar.tsx (1)
11-12: Type import/usage migration is correct.Switch to UseScheduleForEventReturnType aligns with the new hook API.
Also applies to: 21-23
packages/features/bookings/Booker/types.ts (1)
15-16: Consistent public type usage for schedule.Good move to import and use UseScheduleForEventReturnType.
Also applies to: 130-131
packages/features/bookings/Booker/components/AvailableTimeSlots.tsx (1)
8-10: Hook/type migration looks correct.New hooks and UseScheduleForEventReturnType integration are consistent.
Also applies to: 17-24
packages/features/schedules/hooks/useSchedule.ts (2)
6-6: LGTM: deduplicates schedule fetching paths via enabled flagsSwitch to getTimesForSchedule, explicit monthCount default, and gating of TRPC vs API V2 queries look correct and should prevent duplicate getSchedule calls.
Also applies to: 22-23, 40-41, 51-56, 114-121, 136-140
114-121: Duplicate schedule fetch toggles verified – no overlapping queries
- In useSchedule.ts the only schedule-fetch call sites are:
useApiV2AvailableSlots({ …, enabled: isCallingApiV2Slots })trpc.viewer.slots.getSchedule.useQuery(input, { enabled: options.enabled && !isCallingApiV2Slots })- The
isCallingApiV2Slotsflag and its negation ensure that exactly one of these hooks is active at any time, eliminating any possibility of duplicate network calls.- There are no
prefetchNextMonthreferences in useSchedule.ts; the only occurrences of that identifier live in the separate booker wrapper files and do not impact this hook.No further action needed here.
packages/features/bookings/Booker/hooks/useScheduleForEvent.ts (2)
4-4: LGTM: wrapper delegates cleanly to useSchedule and exposes a stable return typeNamed export, new UseScheduleForEventReturnType, and removal of legacy knobs align with the refactor.
Also applies to: 9-10, 20-33, 57-72, 74-82
9-10: No legacyuseScheduleForEventReturnTypeimports detectedI ran the provided grep check:
rg -n -C2 --glob '!**/node_modules/**' -e '\buseScheduleForEventReturnType\b'and confirmed there are zero occurrences of the old alias. All consumers are now importing the new
UseScheduleForEventReturnType.
| import useSkipConfirmStep from "@calcom/features/bookings/Booker/components/hooks/useSkipConfirmStep"; | ||
| import { getQueryParam } from "@calcom/features/bookings/Booker/utils/query-param"; | ||
| import { useNonEmptyScheduleDays } from "@calcom/features/schedules/lib/use-schedule/useNonEmptyScheduleDays"; | ||
| import { useNonEmptyScheduleDays } from "@calcom/features/schedules/hooks/useNonEmptyScheduleDays"; |
There was a problem hiding this comment.
💡 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:
#!/bin/bash
fd -t f -e ts -e tsx | xargs rg -nP '@calcom/features/schedules/lib/use-schedule/useNonEmptyScheduleDays'Length of output: 105
🏁 Script executed:
#!/bin/bash
# Search for any remaining imports under the old schedules lib path
fd -t f -e ts -e tsx | xargs rg -nP '@calcom/features/schedules/lib'Length of output: 790
🏁 Script executed:
#!/bin/bash
# Locate where 'Slot' type is declared in the new hooks directory
fd -t f -e ts packages/features/schedules/hooks | xargs rg -nP 'export (type|interface) Slot\b' -nLength of output: 745
Remaining import stragglers detected – please migrate these to the new hooks path
The import-path migration for useNonEmptyScheduleDays is 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:
-import type { Slot } from "@calcom/features/schedules/lib/use-schedule/types";
+import type { Slot } from "@calcom/features/schedules/hooks/useSchedule";and
-import { getTimesForSchedule } from "@calcom/features/schedules/lib/use-schedule/getTimesForSchedule";
+import { getTimesForSchedule } from "@calcom/features/schedules/hooks/useSchedule";Once all of these imports are updated, the old path stragglers will be cleared and this migration can be approved.
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In packages/features/bookings/Booker/Booker.tsx around line 16 and in the listed
files (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) there are remaining imports
referencing the old path @calcom/features/schedules/lib/use-schedule/*; update
each import to the new hooks path @calcom/features/schedules/hooks/<hookName>
(e.g., replace imports from
@calcom/features/schedules/lib/use-schedule/useNonEmptyScheduleDays with
@calcom/features/schedules/hooks/useNonEmptyScheduleDays), ensure named/default
imports match the exported hook names, run typecheck/build to confirm
resolution, and remove any leftover old-path references.
| const [month] = useBookerStoreContext((state) => [state.month], shallow); | ||
|
|
There was a problem hiding this comment.
Day now hard-depends on Booker store — breaks consumers outside Booker.
Day calls useBookerStoreContext, which throws if no provider is mounted. DatePicker/Day is used outside the Booker flow; this will crash those screens. Pass a month key via props and decouple Day from the Booker store.
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 Days:
@@
- <DayComponent
+ <DayComponent
+ monthKey={browsingDate.format("YYYY-MM")}
customClassName={{
dayContainer: customClassName?.datePickerDate,
dayActive: customClassName?.datePickerDateActive,
}}
date={day}Also applies to: 123-129, 132-146
| 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"; |
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
Import 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 schedules/lib/use-schedule paths. Please update these to the new hooks/modules layout:
-
packages/features/schedules/hooks/useSchedule.ts
• Line 6:import { getTimesForSchedule } from "@calcom/features/schedules/lib/use-schedule/getTimesForSchedule"; -
packages/features/embed/Embed.tsx
• Line 27:import type { Slot } from "@calcom/features/schedules/lib/use-schedule/types"; -
packages/platform/atoms/booker/BookerPlatformWrapper.tsx
• Line 20:import { getTimesForSchedule } from "@calcom/features/schedules/lib/use-schedule/getTimesForSchedule"; -
packages/features/bookings/components/AvailableTimes.tsx
• Line 12:import type { Slot } from "@calcom/features/schedules/lib/use-schedule/types"; -
packages/features/bookings/Booker/components/AvailableTimeSlots.tsx
• Line 10:import type { Slot } from "@calcom/features/schedules/lib/use-schedule/types";
Please replace these legacy imports with their new equivalents under @calcom/features/schedules/hooks (or the updated module paths). Once updated, re-run the grep check to confirm all legacy references are removed.
🤖 Prompt for AI Agents
In packages/features/embed/Embed.tsx around lines 19–27, there's a legacy type
import from "@calcom/features/schedules/lib/use-schedule/types" (Slot); replace
that legacy import with the new hooks module path under
"@calcom/features/schedules/hooks" (import the Slot type from the updated module
— e.g. the new types export in the schedules/hooks/useSchedule module or its
types file), update any other references in this file to use the new
name/location, and then re-run the grep check to confirm no remaining legacy
schedules/lib/use-schedule imports remain.
| const expectedStartTime = toLocalIsoWithOffset(new Date(2025, 9)); | ||
| const expectedEndTime = new Date(2025, 11); | ||
|
|
||
| expect(toLocalIsoWithOffset(new Date(startTime))).toBe(expectedStartTime); | ||
| // expect(toLocalIsoWithOffset(new Date(endTime))).toBe(expectedEndTime); | ||
| } |
There was a problem hiding this comment.
Fix incorrect expected end month and re-enable the assertion
For a single-month selection of "2025-10", end should be 2025-11-01 (not 2025-12-01). Let's correct the expected value and restore the assertion.
- const expectedStartTime = toLocalIsoWithOffset(new Date(2025, 9));
- const expectedEndTime = new Date(2025, 11);
+ const expectedStartTime = toLocalIsoWithOffset(new Date(2025, 9)); // 2025-10-01 local
+ const expectedEndTime = toLocalIsoWithOffset(new Date(2025, 10)); // 2025-11-01 local
expect(toLocalIsoWithOffset(new Date(startTime))).toBe(expectedStartTime);
- // expect(toLocalIsoWithOffset(new Date(endTime))).toBe(expectedEndTime);
+ expect(toLocalIsoWithOffset(new Date(endTime))).toBe(expectedEndTime);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const expectedStartTime = toLocalIsoWithOffset(new Date(2025, 9)); | |
| const expectedEndTime = new Date(2025, 11); | |
| expect(toLocalIsoWithOffset(new Date(startTime))).toBe(expectedStartTime); | |
| // expect(toLocalIsoWithOffset(new Date(endTime))).toBe(expectedEndTime); | |
| } | |
| const expectedStartTime = toLocalIsoWithOffset(new Date(2025, 9)); // 2025-10-01 local | |
| const expectedEndTime = toLocalIsoWithOffset(new Date(2025, 10)); // 2025-11-01 local | |
| expect(toLocalIsoWithOffset(new Date(startTime))).toBe(expectedStartTime); | |
| expect(toLocalIsoWithOffset(new Date(endTime))).toBe(expectedEndTime); |
🤖 Prompt for AI Agents
In packages/features/schedules/lib/use-schedule/getTimesForSchedule.test.ts
around lines 44-49, the expected end month is off-by-one (uses new Date(2025,
11)) and the assertion is commented out; change the expectedEndTime to new
Date(2025, 10) (representing 2025-11-01) and re-enable the commented expect line
so it asserts toLocalIsoWithOffset(new Date(endTime)) equals the corrected
expectedEndTime.
| // Why the non-null assertions? All of these arguments are checked in the enabled condition, | ||
| // and the query will not run if they are null. However, the check in `enabled` does | ||
| // no satisfy typescript. | ||
| let startTime; | ||
| let endTime; | ||
|
|
There was a problem hiding this comment.
🛠️ Refactor suggestion
Remove stale comment and type start/end to avoid implicit any
The comment refers to non-null assertions that no longer exist. Also, startTime/endTime are implicitly any; type them as Date for safety.
- // Why the non-null assertions? All of these arguments are checked in the enabled condition,
- // and the query will not run if they are null. However, the check in `enabled` does
- // no satisfy typescript.
- let startTime;
- let endTime;
+ let startTime: Date;
+ let endTime: Date;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // Why the non-null assertions? All of these arguments are checked in the enabled condition, | |
| // and the query will not run if they are null. However, the check in `enabled` does | |
| // no satisfy typescript. | |
| let startTime; | |
| let endTime; | |
| let startTime: Date; | |
| let endTime: Date; |
🤖 Prompt for AI Agents
In packages/features/schedules/lib/use-schedule/getTimesForSchedule.ts around
lines 28 to 33, remove the stale comment about non-null assertions and replace
the implicit-any declarations for startTime and endTime with explicit typing
(e.g. declare them as Date | undefined or Date depending on usage) so TypeScript
no longer infers any; initialize or narrow their types where they are assigned
so the compiler understands they are valid Dates and update any downstream usage
to handle the typed values.
CarinaWolli
left a comment
There was a problem hiding this comment.
I am still seeing the loading issues for the new month (when it's the end of the month): https://www.loom.com/share/bebb057993cd4d57ae5f0cd9ec3df5a0
|
This PR is being marked as stale due to inactivity. |


What does this PR do?