Skip to content

Conversation

iharsh02
Copy link
Contributor

What does this PR do?

Follow-up PR - #18770

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
cal-5045.mp4
image

Copy link

vercel bot commented Jul 16, 2025

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

A member of the Team first needs to authorize it.

Copy link
Contributor

coderabbitai bot commented Jul 16, 2025

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

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

"""

Walkthrough

The changes introduce an email verification step before allowing booking cancellation or viewing booking details when the current user is not authenticated and no valid email parameter is present in the URL. The CancelBooking component refactors cancellation logic into a dedicated async function and accepts new optional props for userEmail and attendees. The Success component in the booking single view manages state for displaying an email verification dialog, validating the entered email against the booking's user and attendees, and conditionally obfuscates personally identifiable information when verification is absent. Localization strings are updated to reflect the broader verification context. End-to-end tests are updated to simulate the new email verification flow prior to cancellation or rescheduling actions.

Assessment against linked issues

Objective Addressed Explanation
Show a dialog to input email address if cancelledBy is not in URL and user is not logged in (CAL-5045, #18717) The Success component displays a verification dialog when no session or valid email param exists.
Prevent cancellation unless input matches booking user or attendee email (CAL-5045, #18717) The verification dialog validates the entered email against the booking's user and attendees.
Only allow dialog closure if email matches a booking email (CAL-5045, #18717) The dialog cannot close without successful email verification; errors are shown otherwise.
Always set cancelledBy when cancelling a booking (CAL-5045, #18717) The cancellation request includes the verified email as cancelledBy ensuring proper attribution.

Assessment against linked issues: Out-of-scope changes

No out-of-scope changes were found.
"""

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~15 minutes

✨ Finishing Touches
🧪 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.

Copy link
Contributor

github-actions bot commented Jul 16, 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 "feat : Add email input dialog to /booking/uid page". 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

@graphite-app graphite-app bot added the community Created by Linear-GitHub Sync label Jul 16, 2025
@graphite-app graphite-app bot requested a review from a team July 16, 2025 07:03
@github-actions github-actions bot added Medium priority Created by Linear-GitHub Sync ✨ feature New feature or request labels Jul 16, 2025
Copy link

graphite-app bot commented Jul 16, 2025

Graphite Automations

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

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

"Add community label" took an action on this PR • (07/16/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: 2

🔭 Outside diff range comments (1)
apps/web/modules/bookings/views/bookings-single-view.tsx (1)

865-872: Avoid unsafe cast & ensure fallbacks for optional fields

bookingInfo?.user?.email is optional. Casting it to string hides the undefined case at compile-time but the runtime value can still be undefined, which will break the new e-mail-verification flow inside CancelBooking.
Likewise, bookingInfo?.attendees can be undefined, yet CancelBooking presumably iterates over it.

-                              attendees: bookingInfo?.attendees,
-                              userEmail: bookingInfo?.user?.email as string,
+                              attendees: bookingInfo.attendees ?? [],
+                              userEmail:
+                                bookingInfo?.user?.email ??
+                                bookingInfo?.userPrimaryEmail ??
+                                "", // empty string handled inside CancelBooking

Adjust the CancelBooking prop types if they currently mark these fields as required.
This prevents runtime errors and keeps the types honest.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between a84e898 and e03902b.

📒 Files selected for processing (5)
  • apps/web/components/booking/CancelBooking.tsx (6 hunks)
  • apps/web/modules/bookings/views/bookings-single-view.tsx (1 hunks)
  • apps/web/playwright/booking-seats.e2e.ts (2 hunks)
  • apps/web/public/static/locales/en/common.json (1 hunks)
  • packages/features/schedules/components/Schedule.tsx (0 hunks)
💤 Files with no reviewable changes (1)
  • packages/features/schedules/components/Schedule.tsx
🧰 Additional context used
🧠 Learnings (3)
apps/web/modules/bookings/views/bookings-single-view.tsx (1)
Learnt from: eunjae-lee
PR: calcom/cal.com#22106
File: packages/features/insights/components/FailedBookingsByField.tsx:65-71
Timestamp: 2025-07-15T12:59:34.341Z
Learning: In the FailedBookingsByField component (packages/features/insights/components/FailedBookingsByField.tsx), although routingFormId is typed as optional in useInsightsParameters, the system automatically enforces a routing form filter, so routingFormId is always present in practice. This means the data always contains only one entry, making the single-entry destructuring approach safe.
apps/web/public/static/locales/en/common.json (1)

undefined

<retrieved_learning>
Learnt from: bandhan-majumder
PR: #22359
File: packages/lib/server/locales/en/common.json:1336-1339
Timestamp: 2025-07-14T16:31:45.201Z
Learning: When making localization changes for new features, it's often safer to add new strings rather than modify existing ones to avoid breaking existing functionality that depends on the original strings. This approach allows for feature-specific customization while maintaining backward compatibility.
</retrieved_learning>

apps/web/components/booking/CancelBooking.tsx (1)
Learnt from: eunjae-lee
PR: calcom/cal.com#22106
File: packages/features/insights/components/FailedBookingsByField.tsx:65-71
Timestamp: 2025-07-15T12:59:34.341Z
Learning: In the FailedBookingsByField component (packages/features/insights/components/FailedBookingsByField.tsx), although routingFormId is typed as optional in useInsightsParameters, the system automatically enforces a routing form filter, so routingFormId is always present in practice. This means the data always contains only one entry, making the single-entry destructuring approach safe.
🧬 Code Graph Analysis (1)
apps/web/components/booking/CancelBooking.tsx (1)
packages/ui/components/form/index.ts (1)
  • Input (21-21)
⏰ 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). (3)
  • GitHub Check: Codacy Static Code Analysis
  • GitHub Check: Install dependencies / Yarn install & cache
  • GitHub Check: Security Check
🔇 Additional comments (5)
apps/web/public/static/locales/en/common.json (1)

2504-2506: Colon alignment & style inconsistency—remove leading spaces before :

Across this i18n file, key-value pairs are written without a space before the colon.
The two new entries proceed_with_cancellation_description and proceed_with_cancellation_error introduce a leading space before the colon, breaking the prevailing style and creating noisy diffs later.

-"proceed_with_cancellation_description" : "Please enter the email address used for this booking to proceed with cancellation",
-"proceed_with_cancellation_error" : "Email doesn't match the booking email",
+"proceed_with_cancellation_description": "Please enter the email address used for this booking to proceed with cancellation",
+"proceed_with_cancellation_error": "Email doesn't match the booking email",

[ suggest_nitpick ]

apps/web/playwright/booking-seats.e2e.ts (1)

127-170: LGTM! Test correctly implements the new email verification flow.

The test properly handles the email verification requirement by:

  1. Destructuring the user object to access the email
  2. Following the correct sequence: confirm → verify email → submit

This aligns with the new CancelBooking component behavior.

apps/web/components/booking/CancelBooking.tsx (3)

12-13: Imports and type updates look good.

The Dialog components and Input are correctly imported, and the booking type additions support the email verification functionality.

Also applies to: 80-81


124-126: Well-structured refactoring with proper state management.

The extraction of cancellation logic into handleCancellation improves code organization. The verifyAndCancel function correctly implements conditional verification based on whether currentUserEmail is available (logged-in users skip verification).

Also applies to: 137-183


286-324: Well-implemented verification dialog.

The Dialog component is properly structured with:

  • Appropriate test IDs that match the e2e tests
  • Clear error handling and display
  • Proper state cleanup on cancel
  • Accessible form inputs

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.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: 4

🧹 Nitpick comments (1)
apps/web/modules/bookings/views/bookings-single-view.tsx (1)

423-432: Consider enhancing email obfuscation for better privacy.

The current implementation might reveal too much information for short email usernames. Consider:

  1. Ensuring minimum obfuscation even for short usernames
  2. Partially obfuscating the domain for additional privacy
 const obfuscateEmail = (email: string) => {
   if (!email || !email.includes("@")) return obfuscate(email, 2);
   const [user, domain] = email.split("@");
-  return `${obfuscate(user, 2)}@${domain}`;
+  // Ensure at least 3 dots for privacy
+  const obfuscatedUser = user.length <= 2 ? user[0] + "•••" : obfuscate(user, 2);
+  // Optionally obfuscate domain for additional privacy
+  const [domainName, ...domainParts] = domain.split(".");
+  const obfuscatedDomain = domainParts.length > 0 
+    ? `${obfuscate(domainName, 2)}.${domainParts.join(".")}`
+    : domain;
+  return `${obfuscatedUser}@${obfuscatedDomain}`;
 };
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between a6c06e1 and da1c051.

📒 Files selected for processing (4)
  • apps/web/components/booking/CancelBooking.tsx (4 hunks)
  • apps/web/modules/bookings/views/bookings-single-view.tsx (9 hunks)
  • apps/web/playwright/booking-seats.e2e.ts (5 hunks)
  • apps/web/public/static/locales/en/common.json (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • apps/web/public/static/locales/en/common.json
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/web/playwright/booking-seats.e2e.ts
  • apps/web/components/booking/CancelBooking.tsx
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{js,jsx,ts,tsx}

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

Flag excessive Day.js use in performance-critical code. Functions like .add, .diff, .isBefore, and .isAfter are slow, especially in timezone mode. Prefer .utc() for better performance. Where possible, replace with native Date and direct .valueOf() comparisons for faster execution. Recommend using native methods or Day.js .utc() consistently in hot paths like loops.

Files:

  • apps/web/modules/bookings/views/bookings-single-view.tsx
🧠 Learnings (2)
📓 Common learnings
Learnt from: Anshumancanrock
PR: calcom/cal.com#22570
File: apps/web/modules/signup-view.tsx:253-253
Timestamp: 2025-07-21T21:33:23.371Z
Learning: In signup-view.tsx, when checking if redirectUrl contains certain strings, using explicit && checks (redirectUrl && redirectUrl.includes()) is preferred over optional chaining (redirectUrl?.includes()) to ensure the result is always a boolean rather than potentially undefined. This approach provides cleaner boolean contracts for downstream conditional logic.
Learnt from: eunjae-lee
PR: calcom/cal.com#22106
File: packages/features/insights/components/FailedBookingsByField.tsx:65-71
Timestamp: 2025-07-15T12:59:34.389Z
Learning: In the FailedBookingsByField component (packages/features/insights/components/FailedBookingsByField.tsx), although routingFormId is typed as optional in useInsightsParameters, the system automatically enforces a routing form filter, so routingFormId is always present in practice. This means the data always contains only one entry, making the single-entry destructuring approach safe.
apps/web/modules/bookings/views/bookings-single-view.tsx (2)

Learnt from: eunjae-lee
PR: #22106
File: packages/features/insights/components/FailedBookingsByField.tsx:65-71
Timestamp: 2025-07-15T12:59:34.389Z
Learning: In the FailedBookingsByField component (packages/features/insights/components/FailedBookingsByField.tsx), although routingFormId is typed as optional in useInsightsParameters, the system automatically enforces a routing form filter, so routingFormId is always present in practice. This means the data always contains only one entry, making the single-entry destructuring approach safe.

Learnt from: Anshumancanrock
PR: #22570
File: apps/web/modules/signup-view.tsx:253-253
Timestamp: 2025-07-21T21:33:23.371Z
Learning: In signup-view.tsx, when checking if redirectUrl contains certain strings, using explicit && checks (redirectUrl && redirectUrl.includes()) is preferred over optional chaining (redirectUrl?.includes()) to ensure the result is always a boolean rather than potentially undefined. This approach provides cleaner boolean contracts for downstream conditional logic.

⏰ 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: Codacy Static Code Analysis
🔇 Additional comments (7)
apps/web/modules/bookings/views/bookings-single-view.tsx (7)

8-8: LGTM! Import statements are appropriate for the new functionality.

The added hooks (useCallback, useMemo) and UI components (Dialog, Input) are correctly imported for implementing the email verification feature.

Also applies to: 53-53, 56-56


86-89: Well-structured email validation schema.

Good use of Zod for input validation with clear error messages.


158-158: Proper state management for authentication and verification flow.

Good addition of session status and well-organized state variables for the email verification dialog.

Also applies to: 198-201


434-442: Well-implemented email validation logic.

Good use of useCallback for performance optimization and proper case-insensitive email comparison.


455-462: Clean implementation of URL parameter update.

Good use of router.replace with scroll preservation.


464-484: Robust email verification handler with proper error handling.

Good use of try-finally to ensure loading state cleanup. The validation flow is well-structured.


704-737: Comprehensive PII protection implementation.

Excellent consistent application of obfuscation across all sensitive fields including names, emails, and phone numbers.

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: 2

♻️ Duplicate comments (5)
apps/web/modules/bookings/views/bookings-single-view.tsx (5)

434-442: Email validation logic is correctly implemented.

The case-insensitive email comparison and proper memoization with bookingInfo dependency are appropriate.


444-453: Effect logic is correct but has dependency issues.

The verification dialog display logic properly checks session state and email validity.


486-493: PII visibility logic is correct but has duplication.

The logic properly determines when to show personally identifiable information based on session or valid email.


963-964: Props correctly passed with type safety concern.

The attendees prop is properly passed. The userEmail type casting issue has been previously identified.


1240-1240: Good improvements but missing loading state.

The dialog now uses translations for the title, but the verify button still needs the loading prop as suggested in the past review.

Also applies to: 1257-1259

🧹 Nitpick comments (1)
apps/web/modules/bookings/views/bookings-single-view.tsx (1)

423-426: Good implementation with minor improvement needed.

The obfuscation function works well, but consider using Math.min to prevent potential issues when visibleChars exceeds string length:

 const obfuscate = (value: string, visibleChars = 1) => {
   if (!value) return "";
-  return value.substring(0, visibleChars) + "•".repeat(Math.max(0, value.length - visibleChars));
+  const chars = Math.min(visibleChars, value.length);
+  return value.substring(0, chars) + "•".repeat(Math.max(0, value.length - chars));
 };
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between da1c051 and 290ad23.

📒 Files selected for processing (1)
  • apps/web/modules/bookings/views/bookings-single-view.tsx (9 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{js,jsx,ts,tsx}

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

Flag excessive Day.js use in performance-critical code. Functions like .add, .diff, .isBefore, and .isAfter are slow, especially in timezone mode. Prefer .utc() for better performance. Where possible, replace with native Date and direct .valueOf() comparisons for faster execution. Recommend using native methods or Day.js .utc() consistently in hot paths like loops.

Files:

  • apps/web/modules/bookings/views/bookings-single-view.tsx
🧠 Learnings (2)
📓 Common learnings
Learnt from: Anshumancanrock
PR: calcom/cal.com#22570
File: apps/web/modules/signup-view.tsx:253-253
Timestamp: 2025-07-21T21:33:23.371Z
Learning: In signup-view.tsx, when checking if redirectUrl contains certain strings, using explicit && checks (redirectUrl && redirectUrl.includes()) is preferred over optional chaining (redirectUrl?.includes()) to ensure the result is always a boolean rather than potentially undefined. This approach provides cleaner boolean contracts for downstream conditional logic.
Learnt from: eunjae-lee
PR: calcom/cal.com#22106
File: packages/features/insights/components/FailedBookingsByField.tsx:65-71
Timestamp: 2025-07-15T12:59:34.389Z
Learning: In the FailedBookingsByField component (packages/features/insights/components/FailedBookingsByField.tsx), although routingFormId is typed as optional in useInsightsParameters, the system automatically enforces a routing form filter, so routingFormId is always present in practice. This means the data always contains only one entry, making the single-entry destructuring approach safe.
apps/web/modules/bookings/views/bookings-single-view.tsx (5)

Learnt from: eunjae-lee
PR: #22106
File: packages/features/insights/components/FailedBookingsByField.tsx:65-71
Timestamp: 2025-07-15T12:59:34.389Z
Learning: In the FailedBookingsByField component (packages/features/insights/components/FailedBookingsByField.tsx), although routingFormId is typed as optional in useInsightsParameters, the system automatically enforces a routing form filter, so routingFormId is always present in practice. This means the data always contains only one entry, making the single-entry destructuring approach safe.

Learnt from: Anshumancanrock
PR: #22570
File: apps/web/modules/signup-view.tsx:253-253
Timestamp: 2025-07-21T21:33:23.371Z
Learning: In signup-view.tsx, when checking if redirectUrl contains certain strings, using explicit && checks (redirectUrl && redirectUrl.includes()) is preferred over optional chaining (redirectUrl?.includes()) to ensure the result is always a boolean rather than potentially undefined. This approach provides cleaner boolean contracts for downstream conditional logic.

Learnt from: alishaz-polymath
PR: #22304
File: packages/features/eventtypes/components/MultiplePrivateLinksController.tsx:92-94
Timestamp: 2025-07-16T06:42:27.024Z
Learning: In the MultiplePrivateLinksController component (packages/features/eventtypes/components/MultiplePrivateLinksController.tsx), the currentLink.maxUsageCount ?? 1 fallback in the openSettingsDialog function is intentional. Missing maxUsageCount values indicate old/legacy private links that existed before the expiration feature was added, and they should default to single-use behavior (1) for backward compatibility.

Learnt from: eunjae-lee
PR: #22702
File: packages/lib/server/service/insightsBooking.ts:120-124
Timestamp: 2025-07-24T08:39:06.185Z
Learning: In the InsightsBookingService (packages/lib/server/service/insightsBooking.ts), the constructor stores null for invalid options or filters but this is handled safely through null checks in buildFilterConditions() and buildAuthorizationConditions() methods. The service uses defensive programming to return safe fallback conditions (null or NOTHING_CONDITION) rather than throwing errors on invalid inputs.

Learnt from: CR
PR: calcom/cal.com#0
File: .cursor/rules/review.mdc:0-0
Timestamp: 2025-07-21T13:54:11.770Z
Learning: Applies to frontend/**/*.{js,jsx,ts,tsx} : Always use t() for text localization in frontend code; direct text embedding should trigger a warning.

⏰ 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: Codacy Static Code Analysis
🔇 Additional comments (10)
apps/web/modules/bookings/views/bookings-single-view.tsx (10)

8-8: LGTM!

The addition of useCallback, useEffect, useMemo, and useState hooks is appropriate for the new email verification functionality.


53-53: LGTM!

The Dialog and Input components are correctly imported for the email verification dialog implementation.

Also applies to: 56-56


86-88: LGTM!

The email validation schema with proper error messages is well-defined and follows best practices for form validation.


158-158: LGTM!

Good addition of sessionStatus to prevent race conditions when checking session state.


198-201: LGTM!

The email verification state variables are properly initialized with appropriate types and default values.


428-432: LGTM!

The email obfuscation preserves the domain for better user recognition while protecting the username portion.


455-462: LGTM!

The URL update logic correctly preserves existing parameters and prevents unwanted scrolling.


464-484: LGTM!

The verification handler properly validates input, manages loading state, and provides clear error feedback.


701-714: LGTM!

Host information is properly obfuscated when PII cannot be shown, maintaining UI consistency while protecting privacy.


719-736: LGTM!

Attendee information obfuscation is consistently applied across all PII fields (name, phone, email).

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 (4)
apps/web/modules/bookings/views/bookings-single-view.tsx (4)

444-454: Well-structured dialog visibility logic.

The effect correctly handles the loading state and uses functional setState to optimize re-renders. The logic appropriately shows the verification dialog only when needed.


486-494: Efficient PII visibility computation.

Good use of useMemo with proper dependencies. The logic correctly determines when to show personally identifiable information.


963-965: Props correctly updated for CancelBooking.

The additional props are properly passed to support the email verification flow in the cancellation process.


1231-1263: Fix critical issues in dialog implementation.

There are several issues that need to be addressed:

  1. Line 1234 has a critical bug - setShowVerificationDialog is not being called
  2. Dialog title should use translation instead of hardcoded text
  3. Missing loading state on the verify button

Apply these fixes:

 <Dialog
   open={showVerificationDialog}
   onOpenChange={() => {
-    setShowVerificationDialog;
+    // Prevent closing - handled by onPointerDownOutside and onEscapeKeyDown
   }}
   data-testid="verify-email-dialog">
   <DialogContent
     onPointerDownOutside={(e) => e.preventDefault()}
     onEscapeKeyDown={(e) => e.preventDefault()}>
-    <DialogHeader title="Verify your email" />
+    <DialogHeader title={t("verify_email")} />
     <div className="space-y-4 py-4">
       <p className="text-default text-sm">{t("verification_email_dialog_description")}</p>
       <Input
         data-testid="verify-email-input"
         type="email"
         placeholder={t("verification_email_input_placeholder")}
         value={verificationEmail}
         onChange={(e) => setVerificationEmail(e.target.value)}
         className="mb-2"
       />
       {verificationError && (
         <p data-testid="verify-email-error" className="text-error text-sm">
           {verificationError}
         </p>
       )}
       <div className="flex justify-end space-x-2">
-        <Button onClick={handleVerification} disabled={isVerifying} data-testid="verify-email-trigger">
+        <Button onClick={handleVerification} disabled={isVerifying} loading={isVerifying} data-testid="verify-email-trigger">
           {t("verify")}
         </Button>
       </div>
     </div>
   </DialogContent>
 </Dialog>
🧹 Nitpick comments (1)
apps/web/modules/bookings/views/bookings-single-view.tsx (1)

423-433: Well-implemented PII obfuscation utilities.

The obfuscation logic properly masks sensitive information while maintaining some readability. Good defensive programming with the null checks.

Consider extracting the bullet character as a constant for consistency:

+const OBFUSCATION_CHAR = "•";
+
 const obfuscate = (value: string, visibleChars = 1) => {
   if (!value) return "";
-  return value.substring(0, visibleChars) + "•".repeat(Math.max(0, value.length - visibleChars));
+  return value.substring(0, visibleChars) + OBFUSCATION_CHAR.repeat(Math.max(0, value.length - visibleChars));
 };
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 290ad23 and 672504e.

📒 Files selected for processing (2)
  • apps/web/modules/bookings/views/bookings-single-view.tsx (9 hunks)
  • apps/web/public/static/locales/en/common.json (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/web/public/static/locales/en/common.json
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{js,jsx,ts,tsx}

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

Flag excessive Day.js use in performance-critical code. Functions like .add, .diff, .isBefore, and .isAfter are slow, especially in timezone mode. Prefer .utc() for better performance. Where possible, replace with native Date and direct .valueOf() comparisons for faster execution. Recommend using native methods or Day.js .utc() consistently in hot paths like loops.

Files:

  • apps/web/modules/bookings/views/bookings-single-view.tsx
🧠 Learnings (2)
📓 Common learnings
Learnt from: Anshumancanrock
PR: calcom/cal.com#22570
File: apps/web/modules/signup-view.tsx:253-253
Timestamp: 2025-07-21T21:33:23.371Z
Learning: In signup-view.tsx, when checking if redirectUrl contains certain strings, using explicit && checks (redirectUrl && redirectUrl.includes()) is preferred over optional chaining (redirectUrl?.includes()) to ensure the result is always a boolean rather than potentially undefined. This approach provides cleaner boolean contracts for downstream conditional logic.
Learnt from: eunjae-lee
PR: calcom/cal.com#22106
File: packages/features/insights/components/FailedBookingsByField.tsx:65-71
Timestamp: 2025-07-15T12:59:34.389Z
Learning: In the FailedBookingsByField component (packages/features/insights/components/FailedBookingsByField.tsx), although routingFormId is typed as optional in useInsightsParameters, the system automatically enforces a routing form filter, so routingFormId is always present in practice. This means the data always contains only one entry, making the single-entry destructuring approach safe.
apps/web/modules/bookings/views/bookings-single-view.tsx (6)

Learnt from: eunjae-lee
PR: #22106
File: packages/features/insights/components/FailedBookingsByField.tsx:65-71
Timestamp: 2025-07-15T12:59:34.389Z
Learning: In the FailedBookingsByField component (packages/features/insights/components/FailedBookingsByField.tsx), although routingFormId is typed as optional in useInsightsParameters, the system automatically enforces a routing form filter, so routingFormId is always present in practice. This means the data always contains only one entry, making the single-entry destructuring approach safe.

Learnt from: Anshumancanrock
PR: #22570
File: apps/web/modules/signup-view.tsx:253-253
Timestamp: 2025-07-21T21:33:23.371Z
Learning: In signup-view.tsx, when checking if redirectUrl contains certain strings, using explicit && checks (redirectUrl && redirectUrl.includes()) is preferred over optional chaining (redirectUrl?.includes()) to ensure the result is always a boolean rather than potentially undefined. This approach provides cleaner boolean contracts for downstream conditional logic.

Learnt from: alishaz-polymath
PR: #22304
File: packages/features/eventtypes/components/MultiplePrivateLinksController.tsx:92-94
Timestamp: 2025-07-16T06:42:27.024Z
Learning: In the MultiplePrivateLinksController component (packages/features/eventtypes/components/MultiplePrivateLinksController.tsx), the currentLink.maxUsageCount ?? 1 fallback in the openSettingsDialog function is intentional. Missing maxUsageCount values indicate old/legacy private links that existed before the expiration feature was added, and they should default to single-use behavior (1) for backward compatibility.

Learnt from: eunjae-lee
PR: #22702
File: packages/lib/server/service/insightsBooking.ts:120-124
Timestamp: 2025-07-24T08:39:06.185Z
Learning: In the InsightsBookingService (packages/lib/server/service/insightsBooking.ts), the constructor stores null for invalid options or filters but this is handled safely through null checks in buildFilterConditions() and buildAuthorizationConditions() methods. The service uses defensive programming to return safe fallback conditions (null or NOTHING_CONDITION) rather than throwing errors on invalid inputs.

Learnt from: CR
PR: calcom/cal.com#0
File: .cursor/rules/review.mdc:0-0
Timestamp: 2025-07-21T13:54:11.770Z
Learning: Applies to frontend/**/*.{js,jsx,ts,tsx} : Always use t() for text localization in frontend code; direct text embedding should trigger a warning.

Learnt from: CarinaWolli
PR: #22296
File: packages/lib/bookings/filterHostsBySameRoundRobinHost.ts:41-42
Timestamp: 2025-07-22T11:42:47.623Z
Learning: The filterHostsBySameRoundRobinHost function in packages/lib/bookings/filterHostsBySameRoundRobinHost.ts has a known limitation where it doesn't work correctly with fixed hosts or round robin groups. This is pre-existing technical debt that was already broken before the round robin groups feature. CarinaWolli has documented this in Linear issue CAL-6134 for future fix.

⏰ 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: Codacy Static Code Analysis
🔇 Additional comments (6)
apps/web/modules/bookings/views/bookings-single-view.tsx (6)

8-8: LGTM! Proper imports and validation schema.

The added React hooks and UI component imports are appropriate for the email verification feature. The Zod schema correctly validates email format with clear error messages.

Also applies to: 53-53, 56-56, 86-89


158-158: Good state management setup.

Properly tracking session loading status and initializing all necessary state variables for the email verification flow.

Also applies to: 198-201


434-443: Correctly implemented email validation.

Good use of useCallback with proper dependencies. The case-insensitive email comparison is appropriate and the validation logic correctly checks all relevant emails.


455-463: Clean URL parameter handling.

Good practice using router.replace with scroll: false to update the URL without affecting browser history or scroll position.


464-485: Robust email verification handler.

Excellent error handling with Zod validation, proper loading state management using try/finally, and clear error messaging.


701-735: Consistent PII protection throughout the UI.

All personally identifiable information is properly obfuscated when canShowPII is false, including names, emails, and phone numbers. Good consistent implementation pattern.

@iharsh02
Copy link
Contributor Author

@CarinaWolli @anikdhabal

Changes done :

  • Obfuscated all PII (names, emails) when no session or searchParams exist.
  • show the dialog immediately when visiting /booking/uid if no session and searchParams avail
  • Always set the cancelled by

Preview :

feat-cal-5045.1.mp4

@kart1ka
Copy link
Contributor

kart1ka commented Jul 29, 2025

@CarinaWolli @anikdhabal

Changes done :

  • Obfuscated all PII (names, emails) when no session or searchParams exist.
  • show the dialog immediately when visiting /booking/uid if no session and searchParams avail
  • Always set the cancelled by

Preview :

feat-cal-5045.1.mp4

As per the comment by @CarinaWolli we should not display the booking page at all and not just obfuscate the booking details. In your video I could see that booking page is still being displayed before the dialog box opens.

@kart1ka kart1ka marked this pull request as draft July 30, 2025 03:00
@iharsh02
Copy link
Contributor Author

@CarinaWolli @anikdhabal

Changes done :

  • Obfuscated all PII (names, emails) when no session or searchParams exist.
  • show the dialog immediately when visiting /booking/uid if no session and searchParams avail
  • Always set the cancelled by

Preview :

feat-cal-5045.1.mp4

As per the comment by @CarinaWolli we should not display the booking page at all and not just obfuscate the booking details. In your video I could see that booking page is still being displayed before the dialog box opens.

cal.mp4

@CarinaWolli
Copy link
Member

The dialog looks good now 🙏 @kart1ka could you do another code review?

@kart1ka
Copy link
Contributor

kart1ka commented Aug 4, 2025

The dialog looks good now 🙏 @kart1ka could you do another code review?

I will review.

@alishaz-polymath
Copy link
Member

Hey @kart1ka can we please prioritize a review here and get this over the line?

@kart1ka kart1ka changed the title feat : Add email input dialog to /booking/uid page feat: Add email input dialog to /booking/uid page Aug 11, 2025
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 few comments.

Comment on lines +424 to +432
const isValidBookingEmail = useCallback(
(email: string) => {
return (
bookingInfo?.attendees?.some((attendee) => attendee.email.toLowerCase() === email.toLowerCase()) ||
email.toLowerCase() === bookingInfo?.user?.email.toLowerCase()
);
},
[bookingInfo]
);
Copy link
Contributor

Choose a reason for hiding this comment

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

We should do a server side validation instead of checking the email client side.

}, [session, sessionStatus, isValidBookingEmail, emailParam]);

const updateSearchParams = useCallback(
async (email: string) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
async (email: string) => {
(email: string) => {

async (email: string) => {
const params = new URLSearchParams(searchParams.toString());
params.set("email", email);
await router.replace(`?${params.toString()}`, { scroll: false });
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
await router.replace(`?${params.toString()}`, { scroll: false });
router.replace(`?${params.toString()}`, { scroll: false });

Copy link
Contributor

This PR is being marked as stale due to inactivity.

@github-actions github-actions bot added the Stale label Aug 26, 2025
@kart1ka kart1ka self-assigned this Aug 26, 2025
@github-actions github-actions bot removed the Stale label Aug 27, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
community Created by Linear-GitHub Sync ✨ feature New feature or request Medium priority Created by Linear-GitHub Sync ready-for-e2e
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[CAL-5045] Add email input dialog to /booking/uid page
5 participants