Skip to content

fix: incorrect slot duration when rescheduling bookings#23290

Merged
anikdhabal merged 19 commits intocalcom:mainfrom
sahitya-chandra:cal-6307
Sep 3, 2025
Merged

fix: incorrect slot duration when rescheduling bookings#23290
anikdhabal merged 19 commits intocalcom:mainfrom
sahitya-chandra:cal-6307

Conversation

@sahitya-chandra
Copy link
Member

@sahitya-chandra sahitya-chandra commented Aug 22, 2025

What does this PR do?

Visual Demo (For contributors especially)

Screencast.from.2025-08-23.02-59-22.webm

A visual demonstration is strongly recommended, for both the original and new change (video / image - any one).

Video Demo (if applicable):

  • Show screen recordings of the issue or feature.
  • Demonstrate how to reproduce the issue, the behavior before and after the change.

Image Demo (if applicable):

  • Add side-by-side screenshots of the original and updated change.
  • Highlight any significant change(s).

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

@vercel
Copy link

vercel bot commented Aug 22, 2025

@sahitya-chandra is attempting to deploy a commit to the cal Team on Vercel.

A member of the Team first needs to authorize it.

@graphite-app graphite-app bot added the community Created by Linear-GitHub Sync label Aug 22, 2025
@graphite-app graphite-app bot requested a review from a team August 22, 2025 20:08
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 22, 2025

Walkthrough

The PR modifies packages/features/bookings/Booker/store.ts. It removes logic that, during rescheduling (when rescheduleUid and bookingData are present), computed the original booking duration from bookingData.startTime and bookingData.endTime and then set selectedDuration and the duration query parameter. Now, in that branch, only selectedTimeslot is cleared (set to null). No public API changes are introduced.

Assessment against linked issues

Objective Addressed Explanation
Ensure slot length reflects current event type length during reschedule instead of the original booking length (#23284, CAL-6307)

Assessment against linked issues: Out-of-scope changes

(no out-of-scope changes identified)

Possibly related PRs


📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 8082a41 and 9c27949.

📒 Files selected for processing (1)
  • packages/features/bookings/Booker/store.ts (0 hunks)
💤 Files with no reviewable changes (1)
  • packages/features/bookings/Booker/store.ts
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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 or @coderabbit 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.

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.

@github-actions github-actions bot added booking-page area: booking page, public booking page, booker event-types area: event types, event-types 🐛 bug Something isn't working labels Aug 22, 2025
@dosubot dosubot bot added the bookings area: bookings, availability, timezones, double booking label Aug 22, 2025
@graphite-app
Copy link

graphite-app bot commented Aug 22, 2025

Graphite Automations

"Add consumer team as reviewer" took an action on this PR • (08/22/25)

1 reviewer was added to this PR based on Keith Williams's automation.

"Add community label" took an action on this PR • (08/22/25)

1 label was added to this PR based on Keith Williams's automation.

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 (3)
packages/features/bookings/Booker/utils/event.ts (3)

100-116: Reschedule duration fix is directionally correct; preserve non-reschedule behavior with a conditional fallback.

Passing duration directly fixes the stale slot-length on reschedule, but it also drops the previous fallback to the store (selectedDuration). That can regress non-reschedule flows where we relied on the store to persist the user’s last-picked duration.

Recommend: Only bypass the store when rescheduling. Else, keep the original fallback to preserve UX.

Apply:

@@
-  const rescheduleUid = searchParams?.get("rescheduleUid");
+  const rescheduleUid = searchParams?.get("rescheduleUid");
+  // During reschedule, prefer the latest event-type duration (prop).
+  // Otherwise, preserve user's selected duration from the store.
+  const effectiveDuration = rescheduleUid ? duration : (durationFromStore ?? duration);
@@
-    month: monthFromStore ?? month,
-    duration,
+    month: monthFromStore ?? month,
+    duration: effectiveDuration,

Verification (manual):

  • Create a 15-min event type, book it, then change to 60 min.
  • Start reschedule flow (URL contains rescheduleUid): available slots should be 60 min.
  • New booking flow (no rescheduleUid), after manually picking a non-default duration once: navigating months should continue honoring selectedDuration from the store.

If your intent is to always ignore store duration even outside reschedule, please add a code comment documenting the new precedence and add an e2e to lock it. I can help add either path with tests.


115-115: Use object shorthand for clarity.

useApiV2: useApiV2 can be shortened to useApiV2.

-    useApiV2: useApiV2,
+    useApiV2,

75-90: Remove unused prop or plumb it through.

fromRedirectOfNonOrgLink?: boolean; is declared in the args type but not used. Either remove it or wire it into downstream calls if intended.

Option A — remove now:

   teamMemberEmail?: string | null;
-  fromRedirectOfNonOrgLink?: boolean;
   isTeamEvent?: boolean;
   useApiV2?: boolean;

Option B — if needed later, add a TODO with reasoning to avoid confusion.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between d2f8076 and 6f3459a.

📒 Files selected for processing (1)
  • packages/features/bookings/Booker/utils/event.ts (1 hunks)
🧰 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/utils/event.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/utils/event.ts
**/*.{ts,tsx,js,jsx}

⚙️ CodeRabbit configuration file

Flag default exports and encourage named exports. Named exports provide better tree-shaking, easier refactoring, and clearer imports. Exempt main components like pages, layouts, and components that serve as the primary export of a module.

Files:

  • packages/features/bookings/Booker/utils/event.ts
⏰ 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: Tests / Unit
  • GitHub Check: Type check / check-types
  • GitHub Check: Linters / lint

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 (2)
packages/features/bookings/components/event-meta/Duration.tsx (2)

115-121: Use stable keys: prefer the duration value as the React key (avoid index).

Index keys can cause unnecessary re-mounts if the list changes. Durations are unique and stable, so use duration as the key.

Apply this diff:

-              key={index}
+              key={duration}

17-26: Avoid mutating the mins parameter in getDurationFormatted for clarity.

Reassigning function parameters (mins %= 60) is harder to read and can be error-prone. Use a local variable.

Apply this diff:

-  const hours = Math.floor(mins / 60);
-  mins %= 60;
+  const hours = Math.floor(mins / 60);
+  const remainMins = mins % 60;
@@
-  if (mins > 0) {
+  if (remainMins > 0) {
@@
-        : t("multiple_duration_timeUnit_short", { count: mins, unit: "minute" });
+        : t("multiple_duration_timeUnit_short", { count: remainMins, unit: "minute" });
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 6f3459a and 0bf80ff.

📒 Files selected for processing (1)
  • packages/features/bookings/components/event-meta/Duration.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/components/event-meta/Duration.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/components/event-meta/Duration.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/components/event-meta/Duration.tsx

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

♻️ Duplicate comments (1)
packages/features/bookings/components/event-meta/Duration.tsx (1)

72-82: LGTM: Fix correctly gates syncing to single-duration and preserves user picks for multi/dynamic.

The early-return plus hasMultiple guard prevents snap-backs on multi-duration/dynamic events, while single-duration events now track event.length changes (reschedule case). This directly addresses CAL-6307/#23284 without introducing UX regressions. Nice work.

🧹 Nitpick comments (1)
packages/features/bookings/components/event-meta/Duration.tsx (1)

72-82: Prefer nullish check over truthy for selectedDuration.

Using !selectedDuration conflates undefined with any falsy value. If 0 ever becomes a valid duration, this will misbehave. Use a nullish check to be precise.

Apply this minimal diff:

-    if (!selectedDuration && (hasMultiple || isDynamicEvent)) {
+    if (selectedDuration == null && (hasMultiple || isDynamicEvent)) {

Note: If you adopt 0-minute as a valid value in the future, review other truthy checks (e.g., the conditional render at Line 104 and the scroll effect at Line 87).

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 0bf80ff and 38558ad.

📒 Files selected for processing (1)
  • packages/features/bookings/components/event-meta/Duration.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/components/event-meta/Duration.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/components/event-meta/Duration.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/components/event-meta/Duration.tsx
⏰ 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). (2)
  • GitHub Check: Tests / Unit
  • GitHub Check: Type check / check-types

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/components/event-meta/Duration.tsx (5)

73-74: Make hasMultiple robust to empty arrays

If multipleDuration is present but empty (e.g., []), the current truthy check treats it as “has multiple,” which can misclassify single-duration events and inhibit the reschedule sync path. Use a non-empty check.

-    const hasMultiple = !!event.metadata?.multipleDuration;
+    const hasMultiple = (event.metadata?.multipleDuration?.length ?? 0) > 0;

87-91: Null-check selectedDuration to future-proof zero-valued durations

Use an explicit null/undefined check instead of a truthy check in the scroll-into-view effect to avoid breaking if 0 ever becomes a valid duration.

-      if (selectedDuration && itemRefs.current[selectedDuration]) {
+      if (selectedDuration != null && itemRefs.current[selectedDuration]) {

104-105: Render guard should also use explicit null/undefined check

This keeps behavior consistent with the effect logic and avoids hiding the UI if 0 is ever valid.

-  return selectedDuration ? (
+  return selectedDuration != null ? (

102-103: Fallback durations should apply only when metadata is missing or empty

If multipleDuration is an empty array, the current code renders nothing. Prefer falling back to the default set when empty.

-  const durations = event?.metadata?.multipleDuration || [15, 30, 60, 90];
+  const durationsMeta = event?.metadata?.multipleDuration;
+  const durations = durationsMeta && durationsMeta.length > 0 ? durationsMeta : [15, 30, 60, 90];

121-126: Use stable keys for list items

Using index as a key can cause incorrect item identity if durations change order. Duration values are unique and stable—prefer them for keys.

-              key={index}
+              key={duration}
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 38558ad and 7207041.

📒 Files selected for processing (1)
  • packages/features/bookings/components/event-meta/Duration.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/components/event-meta/Duration.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/components/event-meta/Duration.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/components/event-meta/Duration.tsx
🔇 Additional comments (1)
packages/features/bookings/components/event-meta/Duration.tsx (1)

72-81: Reschedule bug fix is correct and avoids overriding user picks

Gating the sync to single-duration events and early-returning for multi/dynamic events is the right approach. This should make reschedules reflect updated event.length while preserving manual selections for multi/dynamic types.

Quick sanity checks:

  • Single-duration: create 15m event, book, change to 60m, open reschedule. Expect selectedDuration = 60.
  • Multi-duration: event.length = 60; pick 30; ensure selection doesn’t snap back.
  • Dynamic: no forced overrides after initial set when unset.

@sahitya-chandra
Copy link
Member Author

sahitya-chandra commented Aug 25, 2025

@supalarry sir, I have found that durationFromStore in packages/features/bookings/Booker/utils/event.ts is responsible for setting the updated duration of the event-type and making the api call to fetch the slot related info for it but on changing the event type length the durationFromStore remains the same as old event length and it is not getting updated in packages/features/bookings/components/event-meta/Duration.tsx because of some conditional statements

So I have pushed the required code, can you have a look at the PR.
I have also added the video above at the start...

@sahitya-chandra
Copy link
Member Author

@kart1ka @volnei sir can you review this PR also

@github-actions
Copy link
Contributor

github-actions bot commented Aug 28, 2025

E2E results are ready!

Copy link
Contributor

@kart1ka kart1ka left a comment

Choose a reason for hiding this comment

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

Left a comment

Comment on lines 72 to 81
// For multi-duration or dynamic events, set only once on mount and preserve user picks.
const hasMultiple = !!event.metadata?.multipleDuration;
if (selectedDuration == null && (hasMultiple || isDynamicEvent)) {
setSelectedDuration(event.length);
return;
}
// For single-duration events, always sync to current event.length (reschedule case).
if (!hasMultiple && !isDynamicEvent && selectedDuration !== event.length) {
setSelectedDuration(event.length);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Since we’re calling setSelectedDuration(event.length) in both cases, we can simplify this into a single if statement.

Copy link
Member Author

Choose a reason for hiding this comment

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

@kart1ka done sir

@anikdhabal anikdhabal marked this pull request as draft September 3, 2025 14:02
@sahitya-chandra
Copy link
Member Author

sahitya-chandra commented Sep 3, 2025

@anikdhabal sir is this code not working ??

@anikdhabal anikdhabal marked this pull request as ready for review September 3, 2025 14:16
Copy link
Contributor

@anikdhabal anikdhabal left a comment

Choose a reason for hiding this comment

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

Looks good

@anikdhabal anikdhabal merged commit cbc27a7 into calcom:main Sep 3, 2025
33 of 37 checks passed
@sahitya-chandra sahitya-chandra deleted the cal-6307 branch September 3, 2025 15:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

booking-page area: booking page, public booking page, booker bookings area: bookings, availability, timezones, double booking 🐛 bug Something isn't working community Created by Linear-GitHub Sync event-types area: event types, event-types ready-for-e2e size/S

Projects

None yet

Development

Successfully merging this pull request may close these issues.

incorrect slot length when changing event type length and then rescheduling it

4 participants