Skip to content

Conversation

sean-brydon
Copy link
Member

@sean-brydon sean-brydon commented Aug 6, 2025

What does this PR do?

  • Fixes an issue in the Booker atom wherein previously we were not able to use multiple instance of the Booker widget on the same page. If we would use multiple Booker widgets the state would change in both of them even though one of them would be toggled
  • This fix ensures each instance of the Booker atom widget uses a store of its own instead of sharing a global instance that all the widgets can access which was the previous approach

Visual Demo:

Screen.Recording.2025-08-11.at.6.14.02.PM.mov

Mandatory Tasks (DO NOT REMOVE)

  • I have self-reviewed the code (A decent size PR without self-review might be rejected).
  • (N/A) I have updated the developer docs in /docs if this PR makes changes that would require a documentation change. If N/A, write N/A here and check the checkbox.
  • (N/A) I confirm automated tests are in place that prove my fix is effective or that my feature works.

How should this be tested?

For the web app these are the steps:

  1. Run the web app in local
  2. Go to the public profile page of user and navigate to one of his events and try to book them via the booker
  3. There should not be any change in the behaviour of the Booker widget for the web app so ideally it should stay the same

For platform these are the steps:

  1. Run the examples app we have here
  2. Go to booking.tsx in the examples app and copy the code for Booker atom here and paste it just under to make another instance of the same Booker widget appear
  3. In both of the Booker atom widgets you need to either comment out the prop allowUpdatingUrlParams or set it to false
  4. Try to change something in one atom and see if the state of the other widget changes or not

Copy link
Contributor

github-actions bot commented Aug 6, 2025

Hey there and thank you for opening this pull request! 👋🏼

We require pull request titles to follow the Conventional Commits specification and it looks like your proposed title needs to be adjusted.

Details:

No release type found in pull request title "fix manage test error". Add a prefix to indicate what kind of release this pull request corresponds to. For reference, see https://www.conventionalcommits.org/

Available types:
 - feat: A new feature
 - fix: A bug fix
 - docs: Documentation only changes
 - style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
 - refactor: A code change that neither fixes a bug nor adds a feature
 - perf: A code change that improves performance
 - test: Adding missing tests or correcting existing tests
 - build: Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)
 - ci: Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs)
 - chore: Other changes that don't modify src or test files
 - revert: Reverts a previous commit

@keithwillcode keithwillcode added consumer core area: core, team members only labels Aug 6, 2025
Copy link
Contributor

coderabbitai bot commented Aug 6, 2025

Walkthrough

Adds a React context provider for the Booker zustand store (BookerStoreProvider) plus selector and initializer hooks (useBookerStoreContext, useInitializeBookerStoreContext) and a factory-based store (createBookerStore) while preserving a default useBookerStore. Migrates most components, hooks, platform wrappers, embeds, and tests from the module-level store hook to the new context hook. Centralizes selectedTimeslot flow from AvailableTimeSlots into BookEventForm and EventMeta. Adds test utilities to render components with a mocked BookerStore context.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

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 Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch rajiv-demo

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.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

vercel bot commented Aug 6, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

2 Skipped Deployments
Project Deployment Preview Comments Updated (UTC)
cal ⬜️ Ignored Aug 14, 2025 10:38am
cal-eu ⬜️ Ignored Aug 14, 2025 10:38am

@Ryukemeister Ryukemeister changed the title fix manage test error fix: multiple widgets for Booker atom Aug 10, 2025
devin-ai-integration bot and others added 2 commits August 11, 2025 07:01
…t tests

- Create reusable test utility in test-utils.tsx with comprehensive mock store
- Update Booker.test.tsx to use context-based testing approach
- Fix DatePicker tests in both bookings and calendars packages
- Simulate auto-advance behavior for month navigation tests
- All 14 previously failing tests now pass

Co-Authored-By: [email protected] <[email protected]>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🔭 Outside diff range comments (1)
packages/features/bookings/Booker/Booker.tsx (1)

231-305: Missing useMemo dependencies cause stale timeslot and props in BookEventForm

EventBooker depends on selectedTimeslot (passed to BookEventForm and used to compute isTimeslotUnavailable), confirmButtonDisabled, customClassNames, isInstantMeeting, and schedule (used in onCancel) but these aren’t in the dependency array. This can keep the form from updating when selecting a different slot and leave other props stale.

Add the missing dependencies:

   }, [
     bookerFormErrorRef,
     instantVideoMeetingUrl,
     bookerState,
     bookingForm,
     errors,
     event,
     expiryTime,
     extraOptions,
     formErrors,
     handleBookEvent,
     handleVerifyEmail,
     key,
     loadingStates,
     onGoBackInstantMeeting,
     renderConfirmNotVerifyEmailButtonCond,
     seatedEventData,
     setSeatedEventData,
     setSelectedTimeslot,
     isPlatform,
     shouldRenderCaptcha,
     isVerificationCodeSending,
     unavailableTimeSlots,
+    selectedTimeslot,
+    confirmButtonDisabled,
+    customClassNames,
+    isInstantMeeting,
+    schedule,
   ]);
♻️ Duplicate comments (6)
packages/platform/atoms/booker/BookerPlatformWrapper.tsx (3)

9-13: Remove legacy store imports; use only context APIs

You're now using the context-based store. Keep imports from BookerStoreProvider and drop the legacy singleton imports to avoid accidental cross-instance coupling and unused imports.

Apply:

 import {
   BookerStoreProvider,
   useInitializeBookerStoreContext,
   useBookerStoreContext,
 } from "@calcom/features/bookings/Booker/BookerStoreProvider";
-import { useBookerStore, useInitializeBookerStore } from "@calcom/features/bookings/Booker/store";
+import type { BookerStore } from "@calcom/features/bookings/Booker/store";
#!/bin/bash
# Verify no lingering legacy singleton imports remain across the repo
rg -n --no-heading $'@calcom/features/bookings/Booker/store' | rg -n --no-heading 'useBookerStore\\(|useInitializeBookerStore\\(' || true

# Verify all context-based imports are used within a Provider
rg -n --no-heading $'useBookerStoreContext\\(|useInitializeBookerStoreContext\\(' -A 2 -B 2
rg -n --no-heading $'BookerStoreProvider'

Also applies to: 17-17


182-197: Double initialization: remove legacy useInitializeBookerStore to prevent cross-widget leaks

You correctly initialize via useInitializeBookerStoreContext here. However, you still call the legacy useInitializeBookerStore above. That reintroduces the global singleton and can leak state between widgets.

Action:

  • Delete the legacy initializer block above (Lines 166–181).
  • With the import cleanup suggested earlier, this avoids initializing the global store entirely.

Remove the following block (shown for clarity):

useInitializeBookerStore({
  ...props,
  teamMemberEmail,
  crmAppSlug,
  crmOwnerRecordType,
  crmRecordId: props.crmRecordId,
  eventId: event?.data?.id,
  rescheduleUid: props.rescheduleUid ?? null,
  bookingUid: props.bookingUid ?? null,
  layout: layout,
  org: props.entity?.orgSlug,
  username,
  bookingData,
  isPlatform: true,
  allowUpdatingUrlParams,
});

72-75: Stop subscribing to the legacy global store in onBookerStateChange; scope it to the context store

The effect still uses useBookerStore.subscribe/getState and types getStateValues off the legacy store, which breaks isolation across widgets. Select from the context-scoped store instead.

Follow-up changes:

  • Type the selector against the store type.
  • Drive the callback using a context selector so it only reacts to this instance’s state.

Add the type import (already suggested in imports comment):

import type { BookerStore } from "@calcom/features/bookings/Booker/store";

Update the selector typing:

const getStateValues = useCallback((state: BookerStore): BookerStoreValues => {
  return Object.fromEntries(Object.entries(state).filter(([_, v]) => typeof v !== "function")) as BookerStoreValues;
}, []);

Replace the effect with a context-scoped subscription:

const scopedStateValues = useBookerStoreContext(getStateValues);

useEffect(() => {
  if (!onBookerStateChange) return;
  // Initial call and subsequent debounced updates scoped to this provider
  debouncedStateChange(scopedStateValues, onBookerStateChange);
  return () => {
    debouncedStateChange.cancel();
  };
}, [scopedStateValues, onBookerStateChange, debouncedStateChange]);

Also applies to: 90-96, 112-129

packages/features/embed/Embed.tsx (2)

14-19: Don’t mix context-based reader with legacy initializer; remove useInitializeBookerStore import

You’ve added BookerStoreProvider and context hooks (good), but still import the legacy useInitializeBookerStore. This can mutate a different, global store and break isolation.

Apply:

 import {
   BookerStoreProvider,
   useInitializeBookerStoreContext,
   useBookerStoreContext,
 } from "@calcom/features/bookings/Booker/BookerStoreProvider";
-import { useInitializeBookerStore } from "@calcom/features/bookings/Booker/store";

268-275: Initialize via context only (correct)

Using useInitializeBookerStoreContext with username/eventSlug/eventId/layout/org/isTeamEvent is the right approach. Remove the legacy initializer call above (Lines 260–267) to avoid double-initialization.

Apply removal inside EmailEmbed:

-  useInitializeBookerStore({
-    username,
-    eventSlug: eventType?.slug ?? "",
-    eventId: eventType?.id,
-    layout: BookerLayouts.MONTH_VIEW,
-    org: orgSlug,
-    isTeamEvent,
-  });
packages/features/bookings/Booker/Booker.tsx (1)

408-414: Confirm EventMeta accepts and consumes selectedTimeslot

You’re passing selectedTimeslot to EventMeta. Ensure its props include selectedTimeslot?: string | null and that it’s used inside the component as intended.

Run:

#!/bin/bash
# Check EventMeta props for `selectedTimeslot`
rg -n 'type .*EventMeta.*Props|interface .*EventMeta.*Props' -A15 packages/features/bookings/Booker/components/EventMeta.tsx
rg -n --fixed-strings 'selectedTimeslot' packages/features/bookings/Booker/components/EventMeta.tsx
🧹 Nitpick comments (4)
packages/features/bookings/Booker/components/hooks/useBookerTime.ts (1)

9-9: Simplify the selector: select the primitive directly and drop shallow.

You’re selecting a single primitive; the extra array allocation and shallow compare are unnecessary. Zustand’s default equality for primitives is sufficient.

Apply this diff within the current line range:

-  const [timezoneFromBookerStore] = useBookerStoreContext((state) => [state.timezone], shallow);
+  const timezoneFromBookerStore = useBookerStoreContext((state) => state.timezone);

And remove the (now unused) import at the top of this file:

// Remove this import
import { shallow } from "zustand/shallow";
packages/platform/atoms/booker/BookerPlatformWrapper.tsx (1)

198-199: Nit: avoid selecting unused setter to reduce re-render noise

You select setDayCount but never use it. Select only dayCount.

-const [dayCount] = useBookerStoreContext((state) => [state.dayCount, state.setDayCount], shallow);
+const dayCount = useBookerStoreContext((state) => state.dayCount);
packages/features/bookings/Booker/Booker.tsx (2)

93-94: Avoid double subscriptions by selecting value and setter together

You’re subscribing twice to the store for selectedDate and setSelectedDate. Combine them into a single selector tuple with shallow to reduce subscriptions.

Apply this diff:

-const selectedDate = useBookerStoreContext((state) => state.selectedDate);
-const setSelectedDate = useBookerStoreContext((state) => state.setSelectedDate);
+const [selectedDate, setSelectedDate] = useBookerStoreContext(
+  (state) => [state.selectedDate, state.setSelectedDate],
+  shallow
+);

195-198: Stabilize the time-slot select handler with useCallback

onAvailableTimeSlotSelect is recreated on every render which can cause extra rerenders downstream. Wrap it in useCallback.

Apply this diff:

-  const onAvailableTimeSlotSelect = (time: string) => {
-    setSelectedTimeslot(time);
-  };
+  const onAvailableTimeSlotSelect = useCallback((time: string) => {
+    setSelectedTimeslot(time);
+  }, [setSelectedTimeslot]);

Add this import at the top (outside the selected range):

import { useCallback, useEffect, useMemo, useRef } from "react";
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 14d85d9 and 8e6f937.

📒 Files selected for processing (6)
  • packages/features/bookings/Booker/Booker.tsx (7 hunks)
  • packages/features/bookings/Booker/components/DatePicker.tsx (2 hunks)
  • packages/features/bookings/Booker/components/hooks/useBookerTime.ts (1 hunks)
  • packages/features/calendars/DatePicker.tsx (3 hunks)
  • packages/features/embed/Embed.tsx (4 hunks)
  • packages/platform/atoms/booker/BookerPlatformWrapper.tsx (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/features/calendars/DatePicker.tsx
  • packages/features/bookings/Booker/components/DatePicker.tsx
🧰 Additional context used
📓 Path-based instructions (3)
**/*.ts

📄 CodeRabbit Inference Engine (.cursor/rules/review.mdc)

**/*.ts: For Prisma queries, only select data you need; never use include, always use select
Ensure the credential.key field is never returned from tRPC endpoints or APIs

Files:

  • packages/features/bookings/Booker/components/hooks/useBookerTime.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/bookings/Booker/components/hooks/useBookerTime.ts
  • packages/features/bookings/Booker/Booker.tsx
  • packages/platform/atoms/booker/BookerPlatformWrapper.tsx
  • packages/features/embed/Embed.tsx
**/*.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/bookings/Booker/Booker.tsx
  • packages/platform/atoms/booker/BookerPlatformWrapper.tsx
  • packages/features/embed/Embed.tsx
🧬 Code Graph Analysis (4)
packages/features/bookings/Booker/components/hooks/useBookerTime.ts (1)
packages/features/bookings/Booker/BookerStoreProvider.tsx (1)
  • useBookerStoreContext (24-35)
packages/features/bookings/Booker/Booker.tsx (1)
packages/features/bookings/Booker/BookerStoreProvider.tsx (1)
  • useBookerStoreContext (24-35)
packages/platform/atoms/booker/BookerPlatformWrapper.tsx (2)
packages/features/bookings/Booker/BookerStoreProvider.tsx (3)
  • useBookerStoreContext (24-35)
  • useInitializeBookerStoreContext (37-113)
  • BookerStoreProvider (15-22)
packages/platform/atoms/booker/types.ts (2)
  • BookerPlatformWrapperAtomPropsForIndividual (92-96)
  • BookerPlatformWrapperAtomPropsForTeam (98-103)
packages/features/embed/Embed.tsx (3)
packages/features/bookings/Booker/BookerStoreProvider.tsx (3)
  • useInitializeBookerStoreContext (37-113)
  • useBookerStoreContext (24-35)
  • BookerStoreProvider (15-22)
packages/embeds/embed-core/src/types.ts (1)
  • BookerLayouts (6-6)
packages/features/embed/types/index.d.ts (1)
  • EmbedType (6-6)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Install dependencies / Yarn install & cache
  • GitHub Check: Atoms E2E Tests
🔇 Additional comments (10)
packages/features/bookings/Booker/components/hooks/useBookerTime.ts (1)

3-3: Verify BookerStoreProvider wraps all useBookerTime call sites

I ran the repo-wide search you suggested. Summary:

  • useBookerTime is used across multiple places (examples):

    • packages/platform/atoms/hooks/bookings/useHandleBookEvent.ts
    • packages/features/embed/Embed.tsx
    • packages/features/calendars/weeklyview/components/event/Empty.tsx
    • packages/features/calendars/weeklyview/components/currentTime/index.tsx
    • packages/features/bookings/components/AvailableTimes.tsx
    • packages/features/bookings/Booker/components/EventMeta.tsx
    • packages/features/bookings/Booker/utils/event.ts
    • packages/features/bookings/Booker/components/BookEventForm/BookEventForm.tsx
  • BookerStoreProvider placements found (wrap roots / common wrappers / tests):

    • packages/features/embed/Embed.tsx
    • packages/platform/atoms/booker/BookerWebWrapper.tsx
    • packages/platform/atoms/booker/BookerPlatformWrapper.tsx
    • packages/platform/atoms/availability/AvailabilitySettings.tsx (modal)
    • tests (e.g. packages/features/calendars/tests/DatePicker.test.tsx)
  • Items needing explicit attention:

    • Files that appear to mix the legacy store API and the new context-based API (please confirm intentional):
      • packages/features/bookings/components/event-meta/Occurences.tsx (uses useBookerStore and useBookerTime)
      • packages/features/bookings/Booker/components/hooks/useBookings.ts (imports useBookerStore from store)
    • Double-check platform atom hooks (e.g. packages/platform/atoms/hooks/useSlots.ts, useHandleBookEvent.ts) are only invoked within components wrapped by BookerStoreProvider in the platform wrappers.

If you'd like, I can run a follow-up script that cross-references each useBookerTime file with known provider-wrapping entrypoints to try to flag any call sites that are likely rendered outside a provider.

packages/platform/atoms/booker/BookerPlatformWrapper.tsx (1)

584-592: Provider wrapping looks correct

Wrapping the internal component with BookerStoreProvider at the public boundary ensures per-instance isolation. Good move.

packages/features/embed/Embed.tsx (3)

277-291: Context-based reads/writes LGTM

Reading month/selectedDate/selectedDatesAndTimes and writing setSelectedDate/setMonth/setSelectedDatesAndTimes/setSelectedTimeslot/setTimezone via useBookerStoreContext is aligned with the per-instance store design.


702-705: Scoped selection LGTM

Selecting [month, selectedDatesAndTimes] from the context store is correct and avoids cross-widget leakage.


1385-1413: Correct: wrap the embed dialog tree with BookerStoreProvider

This ensures EmailEmbed and preview consumers have a scoped store instance. Solid.

packages/features/bookings/Booker/Booker.tsx (5)

88-91: Good use of context selector with shallow equality

Switching to useBookerStoreContext and selecting [state, setState] with shallow prevents unnecessary rerenders. LGTM.


108-116: LGTM on store usage for seatedEventData and dayCount

Consistent tuple selection with shallow for seatedEventData and dayCount looks correct and performant.


235-235: Verified — BookEventForm props include timeslot: string | null; no change required

BookEventFormProps declares timeslot as string | null and the component guards for a missing timeslot, so timeslot={selectedTimeslot} is aligned.

  • packages/features/bookings/Booker/components/BookEventForm/BookEventForm.tsx — type BookEventFormProps includes timeslot: string | null (declaration and usage around lines 27/46 and checks at ~94–100).
  • packages/features/bookings/Booker/Booker.tsx — passing prop at line ~235: timeslot={selectedTimeslot}

Snippet:
timeslot={selectedTimeslot}


495-495: AvailableTimeSlots: onAvailableTimeSlotSelect is present and required — no change needed

AvailableTimeSlotsProps already declares onAvailableTimeSlotSelect: (time: string) => void and the handler in Booker.tsx matches and is passed through, so the original suggestion to make it optional is incorrect.

  • packages/features/bookings/Booker/components/AvailableTimeSlots.tsx
    • line 52: onAvailableTimeSlotSelect: (time: string) => void;
    • lines 76 / 151 / 167: destructure/use/call the prop
  • packages/features/bookings/Booker/Booker.tsx
    • line 195: const onAvailableTimeSlotSelect = (time: string) => { ... }
    • line 495: onAvailableTimeSlotSelect={onAvailableTimeSlotSelect}

Note: The “Timeslot” vs “TimeSlot” naming inconsistency is a minor, non-blocking style issue you may want to standardize later.

Likely an incorrect or invalid review comment.


13-13: Verified — Booker is always rendered inside BookerStoreProvider (or mocked in tests)

I searched the repo and confirmed there are no direct, unwrapped production usages of . Key locations:

  • packages/platform/atoms/booker/BookerPlatformWrapper.tsx — BookerPlatformWrapper exports the component wrapped in .
  • packages/platform/atoms/booker/BookerWebWrapper.tsx — BookerWebWrapper exports the component wrapped in .
  • packages/features/embed/Embed.tsx — EmbedDialog content is wrapped in .
  • packages/features/bookings/Booker/tests/test-utils.tsx — tests use renderWithBookerStore which provides BookStoreContext.Provider (mock store) when rendering .

Note: packages/features/bookings/Booker/Booker.tsx exports Booker without embedding a provider (expected). Consumers must continue to use the provided wrappers (or the test helper) when rendering Booker.

No fixes required.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🔭 Outside diff range comments (2)
packages/features/troubleshooter/Troubleshooter.tsx (2)

31-33: CSS variable name typo breaks layout on non-lg breakpoints

The CSS custom property is misspelled as --troublehooster-meta-width but referenced as --troubleshooter-meta-width (and correctly set for lg: only). This causes gridTemplateColumns to reference an undefined variable on mobile/tablet, likely breaking the layout.

Apply this diff to fix the variable name consistently:

-            ? "[--troublehooster-meta-width:0px]"
-            : "[--troublehooster-meta-width:250px] lg:[--troubleshooter-meta-width:430px]"
+            ? "[--troubleshooter-meta-width:0px]"
+            : "[--troubleshooter-meta-width:250px] lg:[--troubleshooter-meta-width:430px]"

57-59: Invalid Tailwind arbitrary value class: use ml-[-1px]

ml[-1px] is invalid Tailwind syntax; it should be ml-[-1px]. This class currently won’t apply.

Apply this diff:

-          <div className="ml[-1px] border-subtle  sticky top-0 [grid-area:main]">
+          <div className="ml-[-1px] border-subtle sticky top-0 [grid-area:main]">
🧹 Nitpick comments (1)
packages/features/troubleshooter/Troubleshooter.tsx (1)

21-23: Nit: fix hook name typo for consistency

Consider renaming useInitalizeTroubleshooterStore to useInitializeTroubleshooterStore for clarity and consistency across the codebase. If you proceed, update the import on Line 8 and all call sites.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8e6f937 and 9f24f02.

📒 Files selected for processing (1)
  • packages/features/troubleshooter/Troubleshooter.tsx (2 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.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/Troubleshooter.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/features/troubleshooter/Troubleshooter.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Install dependencies / Yarn install & cache
  • GitHub Check: Atoms E2E Tests
🔇 Additional comments (2)
packages/features/troubleshooter/Troubleshooter.tsx (2)

1-1: Import of BookerStoreProvider aligns with per-instance store objective

This import is correct and consistent with the PR goal to scope Booker store per subtree.


67-71: Unconditional BookerStoreProvider is OK here — no nested Booker stores found

Repo scan shows Troubleshooter is only mounted from the dedicated page and not inside an existing Booker provider, so the unconditional provider does not create a double-wrap in current usage.

  • packages/features/troubleshooter/Troubleshooter.tsx — wraps TroubleshooterComponent with (lines ~66–71).
  • apps/web/modules/availability/troubleshoot/troubleshoot-view.tsx — dynamically imports and renders the Troubleshooter (TroubleshooterClientOnly); there is no upstream BookerStoreProvider at that integration point.
  • BookerStoreProvider is used in other places (e.g. packages/platform/atoms/booker/BookerWebWrapper.tsx, packages/platform/atoms/booker/BookerPlatformWrapper.tsx) but those files do not render Troubleshooter.

Conclusion: No change required for this PR. If you plan to render Troubleshooter inside an already-wrapped Booker subtree in the future, consider a provider-if-missing / boundary pattern in a follow-up.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/features/bookings/Booker/components/Section.tsx (1)

47-54: Rename local variable to avoid confusion with framer-motion’s layout prop

Using layout as a local variable while also setting the layout prop on <m.div> is easy to misread. Rename the local variable for clarity.

-  const layout = useBookerStoreContext((state) => state.layout);
+  const currentLayout = useBookerStoreContext((state) => state.layout);
@@
-    gridClassName = gridAreaClassNameMap[area[layout] || area.default];
+    gridClassName = gridAreaClassNameMap[area[currentLayout] || area.default];
📜 Review details

Configuration used: CodeRabbit UI
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 settings in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 9f24f02 and a27e129.

📒 Files selected for processing (1)
  • packages/features/bookings/Booker/components/Section.tsx (2 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.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/bookings/Booker/components/Section.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/features/bookings/Booker/components/Section.tsx
🧬 Code Graph Analysis (1)
packages/features/bookings/Booker/components/Section.tsx (1)
packages/features/bookings/Booker/BookerStoreProvider.tsx (1)
  • useBookerStoreContext (24-35)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
  • GitHub Check: Production builds / Build Web App
  • GitHub Check: Production builds / Build Docs
  • GitHub Check: Production builds / Build Atoms
  • GitHub Check: Production builds / Build API v2
  • GitHub Check: Production builds / Build API v1
  • GitHub Check: Tests / Unit
  • GitHub Check: Type check / check-types
  • GitHub Check: Linters / lint
  • GitHub Check: Atoms E2E Tests

import { m } from "framer-motion";
import { forwardRef } from "react";

import { useBookerStoreContext } from "@calcom/features/bookings/Booker/BookerStoreProvider";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Context store migration looks good; verify all usages are wrapped in BookerStoreProvider

Switching to useBookerStoreContext is correct for isolating store instances. However, this hook throws if no provider is present (see BookerStoreProvider.tsx Lines 23-34). Please verify every render path of BookerSection sits under BookerStoreProvider to avoid runtime errors in downstream apps, embeds, and examples.

Run this script to surface candidate files that reference BookerSection without any obvious BookerStoreProvider import/usage in the same file (heuristic; may include false positives if the provider is higher up the tree):


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find files that import or use BookerSection
files=$(rg -n --glob '!**/node_modules/**' -e 'import\s+{?\s*BookerSection\b' -e '<BookerSection\b' --no-heading | cut -d: -f1 | sort -u)

echo "Files referencing BookerSection:"
echo "$files" | sed 's/^/  - /'

echo
echo "Candidates to review (no explicit BookerStoreProvider reference in the same file):"
while read -r f; do
  if [[ -z "$f" ]]; then continue; fi
  if rg -q 'BookerStoreProvider|<BookerStoreProvider' "$f"; then
    echo "[OK] $f"
  else
    echo "[CHECK] $f"
  fi
done <<< "$files"

Length of output: 301


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find files that reference BookerSection (import, JSX usage, or any mention)
mapfile -t files < <(rg --hidden --glob '!**/node_modules/**' -n -l 'BookerSection' || true)

if [ ${#files[@]} -eq 0 ]; then
  echo "No files referencing BookerSection found."
  exit 0
fi

echo "Files referencing BookerSection:"
for f in "${files[@]}"; do
  echo "  - $f"
done

echo
echo "Candidates to review (no explicit BookerStoreProvider reference in the same file):"
for f in "${files[@]}"; do
  if rg -n --hidden --glob '!**/node_modules/**' -e 'BookerStoreProvider' -e '<BookerStoreProvider' -- "$f" >/dev/null; then
    echo "[OK] $f"
  else
    echo "[CHECK] $f"
  fi
done

Length of output: 211


Run a robust search for BookerSection usages and whether BookerStoreProvider is present

Previous attempt hit a shell /dev/fd issue — run the script below to re-check.


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find files that reference BookerSection (import, JSX usage, or any mention)
files=$(rg --hidden --glob '!**/node_modules/**' -n -l 'BookerSection' || true)

if [ -z "$files" ]; then
  echo "No files referencing BookerSection found."
  exit 0
fi

echo "Files referencing BookerSection:"
echo "$files" | sed 's/^/  - /'

echo
echo "Candidates to review (no explicit BookerStoreProvider reference in the same file):"
echo "$files" | while IFS= read -r f; do
  if [ -z "$f" ]; then continue; fi
  if rg -n --hidden --glob '!**/node_modules/**' -e 'BookerStoreProvider' -e '<BookerStoreProvider' -- "$f" >/dev/null 2>&1; then
    echo "[OK] $f"
  else
    echo "[CHECK] $f"
  fi
done

Length of output: 2407


Wrap or mock BookerSection usages outside BookerStoreProvider — mock needs a fix

I searched the repo for BookerSection usages. Results:

  • packages/features/bookings/Booker/Booker.tsx — [OK] (contains BookerStoreProvider)
  • packages/features/bookings/Booker/components/Section.tsx — [OK]
  • packages/features/bookings/Booker/components/mocks/Section.tsx — [CHECK] (no BookerStoreProvider found)

Action required: update the mock at packages/features/bookings/Booker/components/mocks/Section.tsx to either wrap the mock export with BookerStoreProvider or mock useBookerStoreContext (so the hook cannot throw during tests/renders).

🤖 Prompt for AI Agents
In packages/features/bookings/Booker/components/__mocks__/Section.tsx around
line 5, the mock for BookerSection can call useBookerStoreContext outside a
BookerStoreProvider causing the hook to throw in tests; update the mock to
either wrap the mocked component export with BookerStoreProvider (so consumers
render inside the provider) or replace the mock implementation to stub
useBookerStoreContext (e.g., jest.mock the hook to return a safe default) so the
hook is never invoked against a missing provider during tests.

@supalarry supalarry self-requested a review August 14, 2025 10:49
Copy link
Member

@CarinaWolli CarinaWolli left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested the web app booker, and everything is still working as it should

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🐛 bug Something isn't working consumer core area: core, team members only platform Anything related to our platform plan ready-for-e2e
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants