Skip to content

Comments

refactor: booking-list-state-management#23803

Closed
hemantmm wants to merge 17 commits intocalcom:mainfrom
hemantmm:booking-list-state-management
Closed

refactor: booking-list-state-management#23803
hemantmm wants to merge 17 commits intocalcom:mainfrom
hemantmm:booking-list-state-management

Conversation

@hemantmm
Copy link
Contributor

closes: #22214

What does this PR do?

✅ Extracted useDialogState hook
✅ Extracted useBookingFormState hook
✅ Replaced scattered useState calls
✅ Improved separation of concerns
✅ Enhanced testability

Mandatory Tasks (DO NOT REMOVE)

  • I have self-reviewed the code (A decent size PR without self-review might be rejected).
  • 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.
  • I confirm automated tests are in place that prove my fix is effective or that my feature works.

How should this be tested?

  • Are there environment variables that should be set?
  • What are the minimal test data to have?
  • What is expected (happy path) to have (input and output)?
  • Any other important info that could help to test that PR

Checklist

  • I haven't read the contributing guide
  • My code doesn't follow the style guidelines of this project
  • I haven't commented my code, particularly in hard-to-understand areas
  • I haven't checked if my changes generate no new warnings

@hemantmm hemantmm requested a review from a team September 12, 2025 15:40
@hemantmm hemantmm requested a review from a team as a code owner September 12, 2025 15:40
@vercel
Copy link

vercel bot commented Sep 12, 2025

@hemantmm is attempting to deploy a commit to the cal Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 12, 2025

Important

Review skipped

More than 25% of the files skipped due to max files limit. The review is being skipped to prevent a low-quality review.

128 files out of 292 files are above the max files limit of 100. Please upgrade to Pro plan to get higher limits.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

Adds a new hook, useBookingItemState, that centralizes ten dialog booleans and a rejectionReason and exposes openDialog/closeDialog/toggleDialog/resetDialogs. BookingListItem was refactored to consume dialogState and use openDialog/closeDialog for all dialog controls instead of many local useState flags; onClick handlers and dialog prop wiring were updated accordingly. Several dialog components (RescheduleDialog, ReassignDialog, EditLocationDialog, AddGuestsDialog, ChargeCardDialog, ViewRecordingsDialog, MeetingSessionDetailsDialog, RerouteDialog, NoShowAttendeesDialog) now receive boolean isOpen and (isOpen: boolean) => void setters routed through the new hook. ChargeCardDialog renamed its interface and added local chargeError handling. DialogContent gained an optional enableOverflow prop. A test import path for TooltipProvider was updated.

Possibly related PRs

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Out of Scope Changes Check ⚠️ Warning The PR includes changes that appear out of scope for the BookingListItem refactor: a breaking rename and prop-type change in ChargeCardDialog, an added enableOverflow prop on DialogContent in platform atoms, and unrelated test import/mocking path updates; these touch public interfaces and cross-package components and therefore warrant separate review or justification. Split unrelated API or cross-package changes into separate PRs or provide explicit justification and migration notes in this PR, add/update tests for altered public interfaces, and run a repo-wide type and usage check to identify and fix consumers impacted by the ChargeCardDialog and DialogContent signature changes before merging.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (3 passed)
Check name Status Explanation
Title Check ✅ Passed The title "refactor: booking-list-state-management" succinctly and accurately summarizes the primary change — refactoring and centralizing state management for booking list items — and is clear and specific enough for a teammate scanning PR history to understand the main intent.
Linked Issues Check ✅ Passed The code changes implement a centralized dialog state hook (useBookingItemState) and wire BookingListItem and its dialogs to a uniform openDialog/closeDialog API, which directly addresses the linked issues' objectives to remove scattered useState calls, centralize dialog/form state, provide a consistent API, reduce tight coupling/prop drilling, and improve testability.
Description Check ✅ Passed The PR description is related to the changeset: it references the linked issues (#22214, CAL-6026), explains that dialog/form state was centralized via extracted hooks, and lists the main goals and checklist items, so it meets the lenient description check.

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

Comment @coderabbitai help to get the list of available commands and usage tips.

@graphite-app graphite-app bot added the community Created by Linear-GitHub Sync label Sep 12, 2025
@graphite-app graphite-app bot requested a review from a team September 12, 2025 15:40
@github-actions github-actions bot added Stale 🐛 bug Something isn't working 💻 refactor labels Sep 12, 2025
@dosubot dosubot bot added the 🧹 Improvements Improvements to existing features. Mostly UX/UI label Sep 12, 2025
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: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
packages/platform/atoms/src/components/ui/dialog.tsx (1)

54-66: enableOverflow is declared but unused and is leaked as an invalid DOM attribute.

The prop currently has no effect and is spread onto the DOM (e.g., enableoverflow=""). Implement behavior and avoid leaking the prop.

Apply:

-const DialogContent = React.forwardRef<
-  React.ElementRef<typeof DialogPrimitives.Content>,
-  React.ComponentPropsWithoutRef<typeof DialogPrimitives.Content> & { enableOverflow?: boolean }
->(({ className, children, ...props }, ref) => (
+const DialogContent = React.forwardRef<
+  React.ElementRef<typeof DialogPrimitives.Content>,
+  React.ComponentPropsWithoutRef<typeof DialogPrimitives.Content> & { enableOverflow?: boolean; closeLabel?: string }
+>(({ className, children, enableOverflow, closeLabel, ...props }, ref) => (
   <>
     <DialogPortal>
       <div className="calcom-atoms">
         <DialogOverlay />
         <DialogPrimitives.Content
           ref={ref}
           className={cn(
-            "bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border p-6 shadow-lg duration-200 sm:rounded-lg",
+            "bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border p-6 shadow-lg duration-200 sm:rounded-lg",
+            enableOverflow ? "overflow-visible" : "overflow-y-auto",
             className
           )}
           {...props}>
           {children}
-          <DialogPrimitives.Close className="ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute right-4 top-4 rounded-sm opacity-70 transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:pointer-events-none">
+          <DialogPrimitives.Close
+            aria-label={closeLabel ?? "Close"}
+            className="ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute right-4 top-4 rounded-sm opacity-70 transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:pointer-events-none">
             <Icon name="x" className="h-4 w-4" />
-            <span className="sr-only">Close</span>
+            <span className="sr-only">{closeLabel ?? "Close"}</span>
           </DialogPrimitives.Close>
         </DialogPrimitives.Content>
       </div>
     </DialogPortal>
   </>
 ));

Follow-up: pass a localized closeLabel from callers if needed (e.g., closeLabel={t("close")}).

apps/web/components/dialog/ChargeCardDialog.tsx (1)

26-35: Localize all user-facing strings and normalize error messages.

  • "Charge successful" is hard-coded. Use t().
  • Server error messages may be keys; prefer t(error.message) with a sane fallback.
 onSuccess: () => {
   utils.viewer.bookings.invalidate();
   setIsOpenDialog(false);
   setChargeError(null);
-  showToast("Charge successful", "success");
+  showToast(t("charge_successful"), "success");
 },
 onError: (error) => {
-  setChargeError(error.message || t("error_charging_card"));
+  // Try to translate known keys; fall back to raw message or generic error.
+  const translated = t(error.message as any);
+  setChargeError(translated !== error.message ? translated : error.message || t("error_charging_card"));
 },
apps/web/components/booking/BookingListItem.tsx (1)

469-475: Localize “(Optional)”.

Avoid hard-coded English. Use t("optional") and compose parentheses in JSX.

-              label={
-                <>
-                  {t("rejection_reason")}
-                  <span className="text-subtle font-normal"> (Optional)</span>
-                </>
-              }
+              label={
+                <>
+                  {t("rejection_reason")}
+                  <span className="text-subtle font-normal"> ({t("optional")})</span>
+                </>
+              }
🧹 Nitpick comments (5)
apps/web/components/dialog/ChargeCardDialog.tsx (1)

53-58: Add accessible announcement for error block.

Improve SR experience when errors appear.

-            {chargeError && (
-              <div className="mt-4 flex text-red-500">
+            {chargeError && (
+              <div className="mt-4 flex text-red-500" role="alert" aria-live="polite">
                 <Icon name="triangle-alert" className="mr-2 h-5 w-5 " aria-hidden="true" />
                 <p className="text-sm">{chargeError}</p>
               </div>
             )}
apps/web/components/booking/hooks/useBookingItemState.ts (3)

16-29: Avoid duplicating initial dialog state.

Extract a shared constant and reuse it for initialization and reset.

-export function useBookingItemState() {
-  const [rejectionReason, setRejectionReason] = useState<string>("");
-  const [dialogState, setDialogState] = useState<DialogState>({
+const initialDialogState: DialogState = {
     reschedule: false,
     reassign: false,
     editLocation: false,
     addGuests: false,
     chargeCard: false,
     viewRecordings: false,
     meetingSessionDetails: false,
     noShowAttendees: false,
     rejection: false,
     reroute: false,
-  });
+};
+
+export function useBookingItemState() {
+  const [rejectionReason, setRejectionReason] = useState<string>("");
+  const [dialogState, setDialogState] = useState<DialogState>(initialDialogState);

31-51: Stabilize handlers to reduce re-renders.

Wrap openDialog/closeDialog/toggleDialog with useCallback.

-import { useState } from "react";
+import { useCallback, useState } from "react";
...
-  const openDialog = (dialog: keyof DialogState) => {
+  const openDialog = useCallback((dialog: keyof DialogState) => {
     setDialogState((prevState) => ({
       ...prevState,
       [dialog]: true,
     }));
-  };
+  }, []);
...
-  const closeDialog = (dialog: keyof DialogState) => {
+  const closeDialog = useCallback((dialog: keyof DialogState) => {
     setDialogState((prevState) => ({
       ...prevState,
       [dialog]: false,
     }));
-  };
+  }, []);
...
-  const toggleDialog = (dialog: keyof DialogState) => {
+  const toggleDialog = useCallback((dialog: keyof DialogState) => {
     setDialogState((prevState) => ({
       ...prevState,
       [dialog]: !prevState[dialog],
     }));
-  };
+  }, []);

52-66: Provide a convenience “openExclusiveDialog” helper.

Prevents multiple dialogs being open simultaneously with one call site change.

   // Helper function to reset all dialogs (useful when one action should close others)
   const resetDialogs = () => {
-    setDialogState({
-      reschedule: false,
-      reassign: false,
-      editLocation: false,
-      addGuests: false,
-      chargeCard: false,
-      viewRecordings: false,
-      meetingSessionDetails: false,
-      noShowAttendees: false,
-      rejection: false,
-      reroute: false,
-    });
+    setDialogState(initialDialogState);
   };
+
+  const openExclusiveDialog = (dialog: keyof DialogState) => {
+    setDialogState({ ...initialDialogState, [dialog]: true });
+  };

Export openExclusiveDialog alongside others if useful to callers.

apps/web/components/booking/BookingListItem.tsx (1)

1290-1290: Prefer named export for components.

Default export makes refactors and tree-shaking harder. Consider export { BookingListItem }; and update imports.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 74288b0 and fba095d.

📒 Files selected for processing (5)
  • apps/web/components/booking/BookingListItem.tsx (12 hunks)
  • apps/web/components/booking/hooks/useBookingItemState.ts (1 hunks)
  • apps/web/components/dialog/ChargeCardDialog.tsx (1 hunks)
  • packages/features/bookings/Booker/components/BookEventForm/BookingFields.test.tsx (1 hunks)
  • packages/platform/atoms/src/components/ui/dialog.tsx (1 hunks)
🧰 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/src/components/ui/dialog.tsx
  • packages/features/bookings/Booker/components/BookEventForm/BookingFields.test.tsx
  • apps/web/components/dialog/ChargeCardDialog.tsx
  • apps/web/components/booking/BookingListItem.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/src/components/ui/dialog.tsx
  • packages/features/bookings/Booker/components/BookEventForm/BookingFields.test.tsx
  • apps/web/components/booking/hooks/useBookingItemState.ts
  • apps/web/components/dialog/ChargeCardDialog.tsx
  • apps/web/components/booking/BookingListItem.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/src/components/ui/dialog.tsx
  • packages/features/bookings/Booker/components/BookEventForm/BookingFields.test.tsx
  • apps/web/components/booking/hooks/useBookingItemState.ts
  • apps/web/components/dialog/ChargeCardDialog.tsx
  • apps/web/components/booking/BookingListItem.tsx
**/*.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:

  • apps/web/components/booking/hooks/useBookingItemState.ts
🧠 Learnings (2)
📚 Learning: 2025-08-27T13:32:46.887Z
Learnt from: supalarry
PR: calcom/cal.com#23364
File: apps/api/v2/src/ee/event-types/event-types_2024_06_14/transformers/internal-to-api/internal-to-api.spec.ts:295-296
Timestamp: 2025-08-27T13:32:46.887Z
Learning: In calcom/cal.com, when transforming booking fields from internal to API format, tests in organizations-event-types.e2e-spec.ts already expect name field label and placeholder to be empty strings ("") rather than undefined. PR changes that set these to explicit empty strings are typically fixing implementation to match existing test expectations rather than breaking changes.

Applied to files:

  • packages/features/bookings/Booker/components/BookEventForm/BookingFields.test.tsx
📚 Learning: 2025-09-08T09:34:46.661Z
Learnt from: CarinaWolli
PR: calcom/cal.com#23421
File: packages/features/ee/workflows/components/AddActionDialog.tsx:171-174
Timestamp: 2025-09-08T09:34:46.661Z
Learning: In packages/features/ee/workflows/components/AddActionDialog.tsx, the actionOptions prop is guaranteed to never be empty according to maintainer CarinaWolli, so defensive checks for empty arrays are not necessary.

Applied to files:

  • apps/web/components/booking/BookingListItem.tsx
🧬 Code graph analysis (1)
apps/web/components/booking/BookingListItem.tsx (6)
apps/web/components/booking/hooks/useBookingItemState.ts (1)
  • useBookingItemState (16-77)
apps/web/components/dialog/ReassignDialog.tsx (1)
  • ReassignDialog (63-328)
apps/web/components/dialog/AddGuestsDialog.tsx (1)
  • AddGuestsDialog (20-104)
apps/web/components/dialog/ChargeCardDialog.tsx (1)
  • ChargeCardDialog (19-79)
packages/features/ee/video/MeetingSessionDetailsDialog.tsx (1)
  • MeetingSessionDetailsDialog (172-201)
packages/features/components/controlled-dialog/index.tsx (1)
  • Dialog (23-26)
🔇 Additional comments (7)
packages/features/bookings/Booker/components/BookEventForm/BookingFields.test.tsx (1)

8-8: TooltipProvider migration looks good.

Import path switch to the internal UI provider is consistent with the PR direction. No changes needed.

apps/web/components/booking/BookingListItem.tsx (6)

69-70: Centralized state hook import — good move.

This aligns with the PR objectives and reduces prop drilling.


131-133: Adoption of useBookingItemState — LGTM.

Clear separation of UI and state; API is easy to test.


157-162: Close rejection dialog on successful reject — correct.

Matches UX expectations.


260-267: Pending actions wiring — good.

Using openDialog("rejection") removes duplicated boolean state.


360-369: Edit actions wiring — good.

Consistent pattern across dialogs.


377-393: After-event actions wiring — good.

Edge-case for single attendee is handled; multi-attendee flows into dialog.

Signed-off-by: Hemant M Mehta <hemant29mehta@gmail.com>
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

♻️ Duplicate comments (3)
apps/web/components/booking/BookingListItem.tsx (3)

286-292: Bug: mis-destructured useState and stale local dialog state for Edit Location.

const [setIsOpenLocationDialog] = useState(false); assigns the state value to a setter-named var and later calls it like a setter. Also, this local state is obsolete given the centralized dialog state. Remove it and call closeDialog("editLocation") on success.

Apply:

-  const [setIsOpenLocationDialog] = useState(false);
@@
   const setLocationMutation = trpc.viewer.bookings.editLocation.useMutation({
     onSuccess: () => {
       showToast(t("location_updated"), "success");
-      setIsOpenLocationDialog(false);
+      closeDialog("editLocation");
       utils.viewer.bookings.invalidate();
     },

726-728: Fix: setIsOpenDialog must accept the boolean “open” (RerouteDialog still using zero-arg).

Pass the boolean and mirror the pattern used elsewhere to avoid incorrect closes and type mismatches.

-          setIsOpenDialog={() => closeDialog("reroute")}
+          setIsOpenDialog={(open) => (open ? openDialog("reroute") : closeDialog("reroute"))}

724-729: Convert zero-arg dialog handlers to accept and forward the (open: boolean) argument

Found zero-arg handlers — verify which are used as dialog onOpenChange/setters and change them to accept (open: boolean) and pass that value to the state setter or close/open helper:

  • packages/app-store/routing-forms/components/_components/TestForm.tsx:161 — const onClose = () => { ... }
  • packages/app-store/hitpay/components/HitpayPaymentComponent.tsx:72 — const onClose = () => { ... }
  • apps/ui-playground/content/design/components/toast.basic.tsx:39 — const onClose = () => { ... }
  • packages/features/ee/organizations/pages/settings/delegationCredential.tsx:361 — const onCreateClick = () => setCreateEditDialog({ isOpen: true, delegation: null });

If any are passed to a Dialog's onOpenChange or similar, change to e.g. const onClose = (open: boolean) => setDialogOpen(open) or forward open to closeDialog.

🧹 Nitpick comments (1)
apps/web/components/booking/BookingListItem.tsx (1)

467-471: Localize “(Optional)”.

Per TSX i18n guidelines, avoid hardcoded text. Wrap with t().

-                  <span className="text-subtle font-normal"> (Optional)</span>
+                  <span className="text-subtle font-normal"> ({t("optional")})</span>
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between fba095d and 5552fc0.

📒 Files selected for processing (1)
  • apps/web/components/booking/BookingListItem.tsx (12 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:

  • apps/web/components/booking/BookingListItem.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:

  • apps/web/components/booking/BookingListItem.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:

  • apps/web/components/booking/BookingListItem.tsx
🧠 Learnings (1)
📚 Learning: 2025-09-08T09:34:46.661Z
Learnt from: CarinaWolli
PR: calcom/cal.com#23421
File: packages/features/ee/workflows/components/AddActionDialog.tsx:171-174
Timestamp: 2025-09-08T09:34:46.661Z
Learning: In packages/features/ee/workflows/components/AddActionDialog.tsx, the actionOptions prop is guaranteed to never be empty according to maintainer CarinaWolli, so defensive checks for empty arrays are not necessary.

Applied to files:

  • apps/web/components/booking/BookingListItem.tsx
🧬 Code graph analysis (1)
apps/web/components/booking/BookingListItem.tsx (6)
apps/web/components/booking/hooks/useBookingItemState.ts (1)
  • useBookingItemState (16-77)
apps/web/components/dialog/ReassignDialog.tsx (1)
  • ReassignDialog (63-328)
apps/web/components/dialog/AddGuestsDialog.tsx (1)
  • AddGuestsDialog (20-104)
apps/web/components/dialog/ChargeCardDialog.tsx (1)
  • ChargeCardDialog (19-79)
packages/features/ee/video/MeetingSessionDetailsDialog.tsx (1)
  • MeetingSessionDetailsDialog (172-201)
packages/features/components/controlled-dialog/index.tsx (1)
  • Dialog (23-26)
⏰ 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 (3)
apps/web/components/booking/BookingListItem.tsx (3)

68-68: Good move: centralized dialog/form state via useBookingItemState.

This reduces prop-drilling and standardizes open/close flows. Nice.

Also applies to: 130-132


259-266: Action handlers now consistently drive dialogs via openDialog — LGTM.

The mapping is clear and removes scattered setters.

Also applies to: 355-365, 371-389


399-401: Dialog open/close contract fixed to accept boolean — nice consistency.

These updates align with (open: boolean) => void expectations across dialogs and prevent accidental closes on open.

Also applies to: 403-411, 415-418, 420-423, 426-431, 436-439, 441-449, 451-457, 459-461

Signed-off-by: Hemant M Mehta <hemant29mehta@gmail.com>
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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/web/components/booking/BookingListItem.tsx (1)

289-296: EditLocationDialog doesn’t close after save (local state is orphaned).

setIsOpenLocationDialog(false) toggles an unused local state; the dialog is driven by dialogState.editLocation. Close it via the central controller and remove the dead state.

-  const [, setIsOpenLocationDialog] = useState(false);
-  // const [setIsOpenLocationDialog] = useState(false);
+  // (removed) local dialog state; use centralized dialog controller instead

   const setLocationMutation = trpc.viewer.bookings.editLocation.useMutation({
     onSuccess: () => {
       showToast(t("location_updated"), "success");
-      setIsOpenLocationDialog(false);
+      closeDialog("editLocation");
       utils.viewer.bookings.invalidate();
     },
♻️ Duplicate comments (1)
apps/web/components/booking/BookingListItem.tsx (1)

728-733: Fix RerouteDialog handler signature (uses zero-arg closer).

This regresses the earlier fix: children expect (open: boolean) => void. Passing a zero-arg function can break types and closes on both transitions.

-        <RerouteDialog
-          isOpenDialog={dialogState.reroute}
-          setIsOpenDialog={() => closeDialog("reroute")}
-          booking={{ ...parsedBooking, eventType: parsedBooking.eventType }}
-        />
+        <RerouteDialog
+          isOpenDialog={dialogState.reroute}
+          setIsOpenDialog={(open) => (open ? openDialog("reroute") : closeDialog("reroute"))}
+          booking={{ ...parsedBooking, eventType: parsedBooking.eventType }}
+        />
🧹 Nitpick comments (1)
apps/web/components/booking/BookingListItem.tsx (1)

1-3: Drop file-wide eslint disables; fix the root causes instead.

These global disables hide real issues. You can remove both by eliminating the any usage below and letting Prettier run.

Apply:

-/* eslint-disable @typescript-eslint/no-explicit-any */
-
-/* eslint-disable prettier/prettier */
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 5552fc0 and e8422f1.

📒 Files selected for processing (1)
  • apps/web/components/booking/BookingListItem.tsx (15 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:

  • apps/web/components/booking/BookingListItem.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:

  • apps/web/components/booking/BookingListItem.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:

  • apps/web/components/booking/BookingListItem.tsx
🧠 Learnings (1)
📚 Learning: 2025-09-08T09:34:46.661Z
Learnt from: CarinaWolli
PR: calcom/cal.com#23421
File: packages/features/ee/workflows/components/AddActionDialog.tsx:171-174
Timestamp: 2025-09-08T09:34:46.661Z
Learning: In packages/features/ee/workflows/components/AddActionDialog.tsx, the actionOptions prop is guaranteed to never be empty according to maintainer CarinaWolli, so defensive checks for empty arrays are not necessary.

Applied to files:

  • apps/web/components/booking/BookingListItem.tsx
🧬 Code graph analysis (1)
apps/web/components/booking/BookingListItem.tsx (6)
apps/web/components/booking/hooks/useBookingItemState.ts (1)
  • useBookingItemState (16-77)
apps/web/components/dialog/ReassignDialog.tsx (1)
  • ReassignDialog (63-328)
apps/web/components/dialog/AddGuestsDialog.tsx (1)
  • AddGuestsDialog (20-104)
apps/web/components/dialog/ChargeCardDialog.tsx (1)
  • ChargeCardDialog (19-79)
packages/features/ee/video/MeetingSessionDetailsDialog.tsx (1)
  • MeetingSessionDetailsDialog (172-201)
packages/features/components/controlled-dialog/index.tsx (1)
  • Dialog (23-26)
⏰ 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). (3)
  • GitHub Check: Linters / lint
  • GitHub Check: Type check / check-types
  • GitHub Check: Tests / Unit
🔇 Additional comments (3)
apps/web/components/booking/BookingListItem.tsx (3)

132-135: Nice: centralized dialog/form state adoption is clean.

useBookingItemState integration reads well and simplifies the component.


403-406: LGTM: onOpenChange handlers now accept the boolean “open” argument.

The handlers correctly branch on open to avoid closing during open transitions.

Also applies to: 409-414, 419-421, 424-427, 430-435, 440-443, 446-453, 455-461, 463-466


428-436: Confirm gating condition for ChargeCardDialog.

It renders only when booking.paid && booking.payment[0]. If the intended flow is “charge when not yet paid,” this should likely be !booking.paid && booking.payment[0]. If getAfterEventActions already hides the action once paid, leave as-is.

Comment on lines +823 to 825
.map((date: { toString: () => any }) => date.toString())
.includes(recurringDate.toString())
);
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Avoid brittle Date string comparisons; use timestamps (also removes any).

Comparing toString() is locale/zone dependent and typed as any here. Compare epoch milliseconds instead.

-        .map((date: { toString: () => any }) => date.toString())
-        .includes(recurringDate.toString())
+        .map((date: Date) => new Date(date).getTime())
+        .includes(new Date(recurringDate).getTime())
-                    .map((date: { toString: () => any }) => date.toString())
-                    .includes(aDate.toString());
+                    .map((date: Date) => new Date(date).getTime())
+                    .includes(new Date(aDate).getTime());

Optional: precompute a Set<number> of cancelled timestamps with useMemo to avoid re-mapping in both places.

Also applies to: 841-843

🤖 Prompt for AI Agents
In apps/web/components/booking/BookingListItem.tsx around lines 823-825 (and
similarly at 841-843), replace brittle Date.toString() comparisons with epoch
millisecond comparisons: map the dates to date.getTime() (typed as number)
instead of toString(), and compare recurringDate.getTime() to those numbers; to
avoid repeated mapping and remove the use of any, precompute a Set<number> of
cancelled timestamps using useMemo (dependent on the cancelled dates array) and
then use set.has(recurringDate.getTime()) for membership checks.

Signed-off-by: Hemant M Mehta <hemant29mehta@gmail.com>
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

🧹 Nitpick comments (5)
packages/features/bookings/Booker/components/BookEventForm/BookingFields.test.tsx (5)

14-18: Make the PhoneInput mock resilient to hoisting.

Use vi.importActual in the mock factory; avoid referencing a separately imported symbol.

-// Mock PhoneInput to avoid calling the lazy import
-vi.mock("@calcom/features/components/phone-input/PhoneInput", () => {
-  return {
-    default: PhoneInput,
-  };
-});
+// Mock PhoneInput with the actual non-lazy module to avoid dynamic import in tests
+vi.mock("@calcom/features/components/phone-input/PhoneInput", async () => {
+  const mod = await vi.importActual<
+    typeof import("@calcom/features/components/phone-input/PhoneInput")
+  >("@calcom/features/components/phone-input/PhoneInput");
+  return { default: mod.default };
+});

Additionally remove the now-unused top-level import:

-import PhoneInput from "@calcom/features/components/phone-input/PhoneInput";

139-147: Escape dynamic labels used as RegExp patterns.

Labels like "https://google.com" contain regex metacharacters and can cause unintended matches.

+// escape user-provided strings before constructing RegExp
+const escapeRegExp = (s: string) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
+
 const component = {
   getName: ({ label = "your_name" }: { label?: string } = {}) =>
     screen.getByRole("textbox", {
-      name: new RegExp(label),
+      name: new RegExp(escapeRegExp(label), "i"),
     }) as HTMLInputElement,
   getEmail: () => screen.getByRole("textbox", { name: /email/i }) as HTMLInputElement,
   getLocationRadioOption: ({ label }: { label: string }) =>
-    screen.getByRole("radio", { name: new RegExp(label) }) as HTMLInputElement,
+    screen.getByRole("radio", { name: new RegExp(escapeRegExp(label), "i") }) as HTMLInputElement,

158-169: Avoid brittle placeholder assumptions for location inputs.

Make placeholder selection data-driven instead of throwing.

   fillRadioInputLocation: ({ label, inputValue }: { label: string; inputValue?: string }) => {
     fireEvent.click(component.getLocationRadioOption({ label }));
 
     if (inputValue) {
-      let placeholder = label;
-      if (label === "attendee_phone_number") {
-        placeholder = "enter_phone_number";
-      } else {
-        // radioInput doesn't have a label, so we need to identify by placeholder
-        throw new Error("Tell me how to identify the placeholder for this location input");
-      }
+      const placeholders: Record<string, string> = {
+        attendee_phone_number: "enter_phone_number",
+      };
+      const placeholder = placeholders[label];
+      if (!placeholder) {
+        throw new Error(`Missing placeholder mapping for location label: ${label}`);
+      }
       fireEvent.change(component.getLocationRadioInput({ placeholder }), {
         target: { value: inputValue },
       });
     }
   },

204-208: Truthiness check can skip valid "0" values.

Be explicit when checking for an entered optionValue.

-    if (value.optionValue) {
+    if (typeof value.optionValue === "string" && value.optionValue.length > 0) {
       expect(component.getLocationRadioInput({ placeholder: "enter_phone_number" }).value).toEqual(
         formattedValue
       );
     }

153-176: Prefer userEvent over fireEvent for typing.

userEvent better simulates real user input and blur/selection behavior; helpful for inputs with formatting.

If feasible in this repo, replace change calls with userEvent.type and click with userEvent.click.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between e8422f1 and de8ea0d.

📒 Files selected for processing (1)
  • packages/features/bookings/Booker/components/BookEventForm/BookingFields.test.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/features/bookings/Booker/components/BookEventForm/BookingFields.test.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/BookEventForm/BookingFields.test.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/features/bookings/Booker/components/BookEventForm/BookingFields.test.tsx
🧠 Learnings (1)
📚 Learning: 2025-08-27T13:32:46.887Z
Learnt from: supalarry
PR: calcom/cal.com#23364
File: apps/api/v2/src/ee/event-types/event-types_2024_06_14/transformers/internal-to-api/internal-to-api.spec.ts:295-296
Timestamp: 2025-08-27T13:32:46.887Z
Learning: In calcom/cal.com, when transforming booking fields from internal to API format, tests in organizations-event-types.e2e-spec.ts already expect name field label and placeholder to be empty strings ("") rather than undefined. PR changes that set these to explicit empty strings are typically fixing implementation to match existing test expectations rather than breaking changes.

Applied to files:

  • packages/features/bookings/Booker/components/BookEventForm/BookingFields.test.tsx
🔇 Additional comments (1)
packages/features/bookings/Booker/components/BookEventForm/BookingFields.test.tsx (1)

8-8: Remaining @radix-ui/react-tooltip imports found — confirm intended migration

rg shows many files still import "@radix-ui/react-tooltip" while BookingFields.test.tsx now imports from "@calcom/ui/components/tooltip".

  • Examples: apps/web/lib/app-providers.tsx, apps/web/lib/app-providers-app-dir.tsx, packages/features/calendars/tests/DatePicker.test.tsx, packages/features/form-builder/FormBuilder.test.tsx, packages/features/schedules/components/date-override-list.test.tsx, packages/ui/components/form/inputs/input.test.tsx, apps/ui-playground/app/design/layout.tsx.
  • Note: packages/platform/atoms/vite.config.ts maps "@radix-ui/react-tooltip" → packages/platform/atoms/src/components/ui/tooltip.tsx, and that file exports TooltipProvider. Decide whether that alias is intentional or whether all imports should be standardized to "@calcom/ui/components/tooltip".
  • Action required: either (A) update the remaining imports to "@calcom/ui/components/tooltip", or (B) confirm and document that the vite alias is the intended single source and leave imports as-is.

@github-actions github-actions bot removed the Stale label Sep 13, 2025
Signed-off-by: Hemant M Mehta <hemant29mehta@gmail.com>
@github-actions github-actions bot added the Stale label Sep 13, 2025
hemantmm and others added 2 commits September 13, 2025 09:35
Signed-off-by: Hemant M Mehta <hemant29mehta@gmail.com>
@github-actions github-actions bot removed the Stale label Sep 14, 2025
@github-actions github-actions bot added the Stale label Sep 14, 2025
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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
apps/web/components/booking/BookingListItem.tsx (2)

289-306: EditLocation dialog doesn’t close after save; leftover local state.

setIsOpenLocationDialog(false) updates an unused local state. Use the centralized state to close.

-  const [, setIsOpenLocationDialog] = useState(false);
+  // Local dialog state not needed; use centralized dialog state.

   const setLocationMutation = trpc.viewer.bookings.editLocation.useMutation({
     onSuccess: () => {
       showToast(t("location_updated"), "success");
-      setIsOpenLocationDialog(false);
+      closeDialog("editLocation");
       utils.viewer.bookings.invalidate();
     },

329-334: Potential runtime crash: calling .concat on possibly undefined arrays.

When booking.recurringInfo is undefined, this throws. Guard and default to empty arrays.

-  const recurringDates = booking.recurringInfo?.bookings[BookingStatus.ACCEPTED]
-    .concat(booking.recurringInfo?.bookings[BookingStatus.CANCELLED])
-    .concat(booking.recurringInfo?.bookings[BookingStatus.PENDING])
-    .sort((date1: Date, date2: Date) => date1.getTime() - date2.getTime());
+  const recurringDates = booking.recurringInfo
+    ? [
+        ...(booking.recurringInfo.bookings[BookingStatus.ACCEPTED] ?? []),
+        ...(booking.recurringInfo.bookings[BookingStatus.CANCELLED] ?? []),
+        ...(booking.recurringInfo.bookings[BookingStatus.PENDING] ?? []),
+      ].sort((d1: Date, d2: Date) => d1.getTime() - d2.getTime())
+    : undefined;
♻️ Duplicate comments (2)
apps/web/components/booking/BookingListItem.tsx (2)

730-732: RerouteDialog: pass the boolean “open” to handler (one leftover).

Align with the pattern used elsewhere to avoid closing on open transitions.

-          setIsOpenDialog={() => closeDialog("reroute")}
+          setIsOpenDialog={(open) => (open ? openDialog("reroute") : closeDialog("reroute"))}

823-826: Avoid brittle Date.toString() comparisons and remove any.

Compare epoch milliseconds; also fixes the any typing.

-      !booking.recurringInfo?.bookings[BookingStatus.CANCELLED]
-        .map((date: { toString: () => any }) => date.toString())
-        .includes(recurringDate.toString())
+      !booking.recurringInfo?.bookings[BookingStatus.CANCELLED]
+        .map((date: Date) => new Date(date).getTime())
+        .includes(recurringDate.getTime())
-          booking.recurringInfo?.bookings[BookingStatus.CANCELLED]
-            .map((date: { toString: () => any }) => date.toString())
-            .includes(aDate.toString());
+          booking.recurringInfo?.bookings[BookingStatus.CANCELLED]
+            .map((date: Date) => new Date(date).getTime())
+            .includes(aDate.getTime());

Optional: precompute a Set<number> of cancelled timestamps with useMemo and use set.has(aDate.getTime()) to avoid re-mapping on every render.

Also applies to: 839-843

🧹 Nitpick comments (5)
apps/web/components/booking/BookingListItem.tsx (5)

1-3: Drop file-wide linter disables; fix the root “any” usages instead.

These blanket disables hide real issues. After fixing the Date string comparisons below, they won’t be needed.

-/* eslint-disable @typescript-eslint/no-explicit-any */
-
-/* eslint-disable prettier/prettier */

1140-1140: NoShowAttendeesDialog: onOpenChange should accept the boolean parameter.

Prevents closing on open transitions and matches the Dialog contract.

-    <Dialog open={isOpen} onOpenChange={() => setIsOpen(false)}>
+    <Dialog open={isOpen} onOpenChange={(open) => setIsOpen(open)}>

524-531: Add noopener for security when using target="_blank".

Prevents window.opener hijacking.

-                          <a
+                          <a
                             href={locationToDisplay}
                             onClick={(e) => e.stopPropagation()}
                             target="_blank"
                             title={locationToDisplay}
-                            rel="noreferrer"
+                            rel="noreferrer noopener"
                             className="text-sm leading-6 text-blue-600 hover:underline dark:text-blue-400">

472-474: Localize “Optional”.

Avoid hardcoded English; wrap in t().

-                  <span className="text-subtle font-normal"> (Optional)</span>
+                  <span className="text-subtle font-normal"> ({t("optional")})</span>

175-178: Minor perf: compute “now” once for time comparisons.

Reduces repeated new Date() calls in a list item render.

-  const isUpcoming = new Date(booking.endTime) >= new Date();
-  const isOngoing = isUpcoming && new Date() >= new Date(booking.startTime);
-  const isBookingInPast = new Date(booking.endTime) < new Date();
+  const now = Date.now();
+  const isUpcoming = new Date(booking.endTime).getTime() >= now;
+  const isOngoing = isUpcoming && now >= new Date(booking.startTime).getTime();
+  const isBookingInPast = new Date(booking.endTime).getTime() < now;
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 7dab750 and cf16693.

📒 Files selected for processing (1)
  • apps/web/components/booking/BookingListItem.tsx (15 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:

  • apps/web/components/booking/BookingListItem.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:

  • apps/web/components/booking/BookingListItem.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:

  • apps/web/components/booking/BookingListItem.tsx
🧠 Learnings (3)
📚 Learning: 2025-08-22T16:38:00.225Z
Learnt from: bandhan-majumder
PR: calcom/cal.com#23192
File: packages/lib/server/service/InsightsBookingBaseService.ts:814-816
Timestamp: 2025-08-22T16:38:00.225Z
Learning: In the InsightsBookingBaseService (packages/lib/server/service/InsightsBookingBaseService.ts), when filtering for "accepted" bookings in getMembersStatsWithCount(), using `endTime <= now()` in the SQL condition should be avoided as it conflicts with existing date filtering logic. The components already handle completion filtering by setting `endDate: currentTime` in their query parameters, making additional SQL-level endTime filtering unnecessary and potentially problematic.

Applied to files:

  • apps/web/components/booking/BookingListItem.tsx
📚 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:

  • apps/web/components/booking/BookingListItem.tsx
📚 Learning: 2025-09-08T09:34:46.661Z
Learnt from: CarinaWolli
PR: calcom/cal.com#23421
File: packages/features/ee/workflows/components/AddActionDialog.tsx:171-174
Timestamp: 2025-09-08T09:34:46.661Z
Learning: In packages/features/ee/workflows/components/AddActionDialog.tsx, the actionOptions prop is guaranteed to never be empty according to maintainer CarinaWolli, so defensive checks for empty arrays are not necessary.

Applied to files:

  • apps/web/components/booking/BookingListItem.tsx
🧬 Code graph analysis (1)
apps/web/components/booking/BookingListItem.tsx (4)
apps/web/components/booking/hooks/useBookingItemState.ts (1)
  • useBookingItemState (16-77)
apps/web/components/dialog/ReassignDialog.tsx (1)
  • ReassignDialog (63-328)
apps/web/components/dialog/ChargeCardDialog.tsx (1)
  • ChargeCardDialog (19-79)
packages/features/ee/video/MeetingSessionDetailsDialog.tsx (1)
  • MeetingSessionDetailsDialog (172-201)
⏰ 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 (3)
apps/web/components/booking/BookingListItem.tsx (3)

71-71: Centralized dialog state hook integration looks good.

Clean replacement of scattered useState with a single source of truth.

Also applies to: 133-135


403-406: Boolean-aware dialog handlers: nice consistency.

All these use (open) => open ? openDialog(...) : closeDialog(...), matching child contracts and preventing accidental closures.

Also applies to: 407-415, 419-422, 424-427, 430-435, 439-443, 445-454, 455-462, 463-466


400-436: Scan for zero-arg dialog closers across the repo

Sandbox ripgrep couldn't search/verify; run these locally and paste results:

rg -nP -C2 --hidden --glob '!node_modules/**' '\b(onOpenChange|setIsOpen[A-Za-z0-9_])\b\s=\s*{\s*(\s*)\s*=>\s*(closeDialog(|set[A-Za-z0-9_]+\s*(\sfalse\s))'

rg -nP -C2 --hidden --glob '!node_modules/**' '(\sopen(?:\s:\sboolean)?\s)\s*=>\s*(closeDialog(|set[A-Za-z0-9_]+\s*(\sfalse\s))'

Check apps/web/components/booking/BookingListItem.tsx lines 400-436 (also 438-466, 728-734, 1101-1169).

@github-actions github-actions bot removed the Stale label Sep 15, 2025
@github-actions github-actions bot added the Stale label Sep 17, 2025
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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
apps/web/components/booking/BookingListItem.tsx (2)

288-299: Remove leftover local location dialog state; close the centralized dialog on success.

setIsOpenLocationDialog(false) controls an unused local state, so the Edit Location dialog won’t close after success. Use closeDialog("editLocation") and delete the legacy useState.

Apply:

-  const [, setIsOpenLocationDialog] = useState(false);
-  // const [setIsOpenLocationDialog] = useState(false);
-      setIsOpenLocationDialog(false);
+      closeDialog("editLocation");

431-439: Fix ChargeCardDialog render condition; it won’t render when action is available.

The action to “charge card” typically appears when payment is pending (i.e., !booking.paid). Currently, the dialog is only rendered when booking.paid, so clicking the action won’t show anything.

Render the dialog when pending payment exists:

-      {booking.paid && booking.payment[0] && (
+      {showPendingPayment && booking.payment[0] && (
         <ChargeCardDialog
           isOpenDialog={dialogState.chargeCard}
           setIsOpenDialog={(open) => (open ? openDialog("chargeCard") : closeDialog("chargeCard"))}
           bookingId={booking.id}
           paymentAmount={booking.payment[0].amount}
           paymentCurrency={booking.payment[0].currency}
         />
       )}
🧹 Nitpick comments (1)
apps/web/components/booking/BookingListItem.tsx (1)

1-3: Remove file-wide eslint disables; fix root causes instead.

These blanket disables hide real issues. The no-explicit-any is only needed due to brittle date string comparisons below; and prettier should not be disabled repo-wide.

Apply:

-/* eslint-disable @typescript-eslint/no-explicit-any */
-
-/* eslint-disable prettier/prettier */
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between cf16693 and a4eec6a.

📒 Files selected for processing (1)
  • apps/web/components/booking/BookingListItem.tsx (15 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:

  • apps/web/components/booking/BookingListItem.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:

  • apps/web/components/booking/BookingListItem.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:

  • apps/web/components/booking/BookingListItem.tsx
🧠 Learnings (3)
📚 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:

  • apps/web/components/booking/BookingListItem.tsx
📚 Learning: 2025-09-18T13:38:50.936Z
Learnt from: hariombalhara
PR: calcom/cal.com#23913
File: packages/features/bookings/Booker/components/hooks/usePrefetch.ts:43-50
Timestamp: 2025-09-18T13:38:50.936Z
Learning: In usePrefetch hook in packages/features/bookings/Booker/components/hooks/usePrefetch.ts, the !isNaN() checks before comparing monthAfterAdding1Month !== monthAfterAddingExtraDaysColumnView are intentional to prevent the NaN !== NaN issue where NaN values would incorrectly be considered different, leading to wrong monthCount calculations.

Applied to files:

  • apps/web/components/booking/BookingListItem.tsx
📚 Learning: 2025-09-08T09:34:46.661Z
Learnt from: CarinaWolli
PR: calcom/cal.com#23421
File: packages/features/ee/workflows/components/AddActionDialog.tsx:171-174
Timestamp: 2025-09-08T09:34:46.661Z
Learning: In packages/features/ee/workflows/components/AddActionDialog.tsx, the actionOptions prop is guaranteed to never be empty according to maintainer CarinaWolli, so defensive checks for empty arrays are not necessary.

Applied to files:

  • apps/web/components/booking/BookingListItem.tsx
🧬 Code graph analysis (1)
apps/web/components/booking/BookingListItem.tsx (4)
apps/web/components/booking/hooks/useBookingItemState.ts (1)
  • useBookingItemState (16-77)
apps/web/components/dialog/ReassignDialog.tsx (1)
  • ReassignDialog (63-328)
apps/web/components/dialog/ChargeCardDialog.tsx (1)
  • ChargeCardDialog (19-79)
packages/features/ee/video/MeetingSessionDetailsDialog.tsx (1)
  • MeetingSessionDetailsDialog (172-201)
⏰ 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). (3)
  • GitHub Check: Linters / lint
  • GitHub Check: Tests / Unit
  • GitHub Check: Type check / check-types
🔇 Additional comments (13)
apps/web/components/booking/BookingListItem.tsx (13)

71-71: Nice centralization of dialog state.

Import and usage of useBookingItemState aligns with PR goals and removes scattered useState.

Also applies to: 133-135


159-163: Correct: close rejection dialog on success.

closeDialog("rejection") on REJECTED is the right cleanup.


262-272: LGTM: pending actions wired to centralized open/confirm.

Consistent openDialog("rejection") and confirm handler looks good.


357-372: LGTM: edit actions mapped to dialog openers.

Uniform openDialog("<id>") usage is clear and consistent.


375-401: LGTM: after-event actions mapped; no-show attendees flow handled.

Opens dialogs via centralized API; single-attendee branch directly mutates as expected.


405-409: LGTM: RescheduleDialog setIsOpenDialog uses boolean signature.


410-417: LGTM: ReassignDialog wired with correct boolean onOpenChange signature.


422-424: LGTM: EditLocationDialog uses centralized open/close.


441-446: LGTM: ViewRecordingsDialog boolean handler is correct.


448-456: LGTM: MeetingSessionDetailsDialog gated and wired correctly.


458-464: LGTM: NoShowAttendeesDialog uses (open:boolean) => void signature.


466-469: LGTM: Rejection reason dialog uses proper boolean onOpenChange.


826-828: Replace brittle Date.toString() comparisons with epoch milliseconds.

toString() is locale/zone dependent and forced any typing. Use timestamps; this also lets you drop the file-level no-explicit-any disable.

Apply:

-      !booking.recurringInfo?.bookings[BookingStatus.CANCELLED]
-        .map((date: { toString: () => any }) => date.toString())
-        .includes(recurringDate.toString())
+      !booking.recurringInfo?.bookings[BookingStatus.CANCELLED]
+        .map((date: Date) => new Date(date).getTime())
+        .includes(new Date(recurringDate).getTime())
-                  booking.recurringInfo?.bookings[BookingStatus.CANCELLED]
-                    .map((date: { toString: () => any }) => date.toString())
-                    .includes(aDate.toString());
+                  booking.recurringInfo?.bookings[BookingStatus.CANCELLED]
+                    .map((date: Date) => new Date(date).getTime())
+                    .includes(new Date(aDate).getTime());

Optional: precompute a Set of cancelled timestamps with useMemo.

Also applies to: 844-845

Comment on lines 731 to 735
{isBookingFromRoutingForm && (
<RerouteDialog
isOpenDialog={rerouteDialogIsOpen}
setIsOpenDialog={setRerouteDialogIsOpen}
isOpenDialog={dialogState.reroute}
setIsOpenDialog={() => closeDialog("reroute")}
booking={{ ...parsedBooking, eventType: parsedBooking.eventType }}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Use boolean open argument for RerouteDialog’s setIsOpenDialog.

Passing a zero-arg closer breaks the expected signature and can close on open transitions.

Apply:

-        <RerouteDialog
-          isOpenDialog={dialogState.reroute}
-          setIsOpenDialog={() => closeDialog("reroute")}
-          booking={{ ...parsedBooking, eventType: parsedBooking.eventType }}
-        />
+        <RerouteDialog
+          isOpenDialog={dialogState.reroute}
+          setIsOpenDialog={(open) => (open ? openDialog("reroute") : closeDialog("reroute"))}
+          booking={{ ...parsedBooking, eventType: parsedBooking.eventType }}
+        />
📝 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.

Suggested change
{isBookingFromRoutingForm && (
<RerouteDialog
isOpenDialog={rerouteDialogIsOpen}
setIsOpenDialog={setRerouteDialogIsOpen}
isOpenDialog={dialogState.reroute}
setIsOpenDialog={() => closeDialog("reroute")}
booking={{ ...parsedBooking, eventType: parsedBooking.eventType }}
{isBookingFromRoutingForm && (
<RerouteDialog
isOpenDialog={dialogState.reroute}
setIsOpenDialog={(open) => (open ? openDialog("reroute") : closeDialog("reroute"))}
booking={{ ...parsedBooking, eventType: parsedBooking.eventType }}
/>
)}
🤖 Prompt for AI Agents
In apps/web/components/booking/BookingListItem.tsx around lines 731 to 735, the
RerouteDialog is currently given a zero-arg closer which breaks the expected
setIsOpenDialog(open: boolean) signature; update the prop to pass a one-arg
function that accepts the boolean open value and forwards it to your dialog
state handler (for example, call your close/open handler with the dialog key
"reroute" and the open boolean) so the dialog opens/closes correctly on state
transitions.

Signed-off-by: Hemant M Mehta <hemant29mehta@gmail.com>
@github-actions github-actions bot added the ❗️ migrations contains migration files label Sep 24, 2025
@hemantmm
Copy link
Contributor Author

closing due to upstream issue.

@hemantmm hemantmm closed this Sep 24, 2025
@hemantmm hemantmm deleted the booking-list-state-management branch September 24, 2025 13:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🐛 bug Something isn't working community Created by Linear-GitHub Sync 🧹 Improvements Improvements to existing features. Mostly UX/UI ❗️ migrations contains migration files 💻 refactor size/L Stale

Projects

None yet

Development

Successfully merging this pull request may close these issues.

BookingListItem component needs state management refactoring for maintainability

1 participant