Skip to content

Comments

feat: Add email confirmation feature#24273

Closed
Parship999 wants to merge 8 commits intocalcom:mainfrom
Parship999:feat-email-confirmation
Closed

feat: Add email confirmation feature#24273
Parship999 wants to merge 8 commits intocalcom:mainfrom
Parship999:feat-email-confirmation

Conversation

@Parship999
Copy link

What does this PR do?

This PR implements an optional feature that allows Cal.com event owners to require bookers to enter their email address twice to prevent typos.

Visual Demo (For contributors especially)

Untitled design (2) Untitled design (3)

Video Demo (if applicable):

Screen.Recording.2025-10-04.222341.mp4

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?

  • Enable Email Confirmation Setting:
    • Go to Event Setup -> Basics page
    • Enable "Ask booker to confirm their email twice" checkbox
    • Save the event type
  • Test Booking Flow:
    • Visit the booking page for the event type
    • Verify you see two email fields: "Email Address" and "Confirm email address"

Parship Chowdhury added 2 commits October 4, 2025 22:29
Signed-off-by: Parship Chowdhury <i.am.parship@gmail.com>
Signed-off-by: Parship Chowdhury <i.am.parship@gmail.com>
@Parship999 Parship999 requested a review from a team as a code owner October 4, 2025 17:25
@CLAassistant
Copy link

CLAassistant commented Oct 4, 2025

CLA assistant check
All committers have signed the CLA.

@github-actions github-actions bot added Low priority Created by Linear-GitHub Sync Stale ✨ feature New feature or request 🙋🏻‍♂️help wanted Help from the community is appreciated labels Oct 4, 2025
@graphite-app graphite-app bot added the community Created by Linear-GitHub Sync label Oct 4, 2025
@vercel
Copy link

vercel bot commented Oct 4, 2025

@Parship999 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 requested a review from a team October 4, 2025 17:26
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 4, 2025

Warning

Rate limit exceeded

@Parship999 has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 8 minutes and 9 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 3854907 and 81f1fa5.

📒 Files selected for processing (1)
  • packages/features/bookings/Booker/components/BookEventForm/BookingFields.tsx (3 hunks)

Walkthrough

Adds a boolean metadata field requireEmailConfirmation to event-type metadata schema and surfaces it in EventSetupTab via a SettingsToggle that updates metadata.requireEmailConfirmation. The booking form now receives eventType.metadata; BookingFields accepts eventMetadata and, when requireEmailConfirmation is true and the view is not a reschedule, renders an additional emailConfirmation field next to email. getBookingResponsesSchema and its preprocess now enforce presence and equality of emailConfirmation with email when required, and useBookingForm wires this validation into the form. A public locale key email_confirmation_mismatch_error was added.

Possibly related PRs

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Out of Scope Changes Check ⚠️ Warning Beyond the email confirmation feature, the pull request alters JSON parse error handling in getBookingResponsesSchema to swallow parse failures silently, which is unrelated to the linked issue’s objectives and introduces new behavior outside the scope of email confirmation. Consider removing or isolating the JSON parse error handling change into a separate pull request or provide justification for its inclusion under the email confirmation feature.
✅ Passed checks (4 passed)
Check name Status Explanation
Title Check ✅ Passed The pull request title “feat: Add email confirmation feature” precisely and concisely summarizes the main change—adding an email confirmation option—without unnecessary detail or noise, directly reflecting the implemented feature of requiring bookers to confirm their email address twice.
Linked Issues Check ✅ Passed The changes implement the primary objective from issue #13266 by adding an optional setting for bookers to confirm their email twice, enforcing matching inputs to reduce typos without adding unrelated functionality, which aligns with the issue’s low-friction requirement while deferring domain-suggestion enhancements as future work.
Description Check ✅ Passed The pull request description clearly relates to the changeset by outlining the new email confirmation feature, referencing linked issues, showing visual demos, and providing testing steps specific to the implemented functionality.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.

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.

@dosubot dosubot bot added the booking-page area: booking page, public booking page, booker label Oct 4, 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: 4

Caution

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

⚠️ Outside diff range comments (1)
packages/features/bookings/Booker/components/BookEventForm/BookingFields.tsx (1)

26-36: Type the new prop to avoid unknown-in-boolean pitfalls

Record<string, unknown> makes requireEmailConfirmation unknown and unsafe in conditions. Narrow the prop type to encode the expected shape.

-  eventMetadata?: Record<string, unknown>;
+  eventMetadata?: { requireEmailConfirmation?: boolean };
🧹 Nitpick comments (3)
packages/features/bookings/Booker/components/hooks/useBookingForm.ts (2)

56-80: Remove duplicate emailConfirmation validation; keep it in getBookingResponsesSchema

Validation is already implemented in getBookingResponsesSchema. Duplicating here can cause double errors and divergence. Centralize in one place.

   const bookingFormSchema = z
     .object({
       responses: event
         ? getBookingResponsesSchema({
             bookingFields: event.bookingFields,
             view: rescheduleUid ? "reschedule" : "booking",
             eventMetadata: event.metadata || undefined,
           })
         : // Fallback until event is loaded.
           z.object({}),
-    })
-    .passthrough()
-    .superRefine((data, ctx) => {
-      if (event?.metadata?.requireEmailConfirmation && !rescheduleUid) {
-        const responses = data.responses as Record<string, unknown>;
-        const email = responses?.email;
-        const emailConfirmation = responses?.emailConfirmation;
-
-        // check if email confirmation field is required and empty
-        if (!emailConfirmation) {
-          ctx.addIssue({
-            code: z.ZodIssueCode.custom,
-            message: "Invalid input",
-            path: ["responses", "emailConfirmation"],
-          });
-        }
-        // check if emails don't match
-        else if (email && emailConfirmation && email !== emailConfirmation) {
-          ctx.addIssue({
-            code: z.ZodIssueCode.custom,
-            message: "Invalid input",
-            path: ["responses", "emailConfirmation"],
-          });
-        }
-      }
-    });
+    }).passthrough();

122-122: Double-check reset effect dependencies

Adding bookingForm and initialValues may trigger extra resets depending on object identity. If unintended, consider keeping [key] only.

packages/features/bookings/lib/getBookingResponsesSchema.ts (1)

111-113: Fix misleading comment after JSON.parse catch

We still assign parsedValue below; the comment claims otherwise. Adjust the comment or early-return to truly skip assignment. Suggest updating the comment for clarity.

-          } catch {
-            // If parsing fails, we don't add the field to newResponses
-          }
+          } catch {
+            // If parsing fails, we fall back to the default parsedValue (empty option/value)
+          }
📜 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 a4be822 and e9ffc9e.

📒 Files selected for processing (7)
  • apps/web/public/static/locales/en/common.json (1 hunks)
  • packages/features/bookings/Booker/components/BookEventForm/BookEventForm.tsx (1 hunks)
  • packages/features/bookings/Booker/components/BookEventForm/BookingFields.tsx (3 hunks)
  • packages/features/bookings/Booker/components/hooks/useBookingForm.ts (3 hunks)
  • packages/features/bookings/lib/getBookingResponsesSchema.ts (5 hunks)
  • packages/features/eventtypes/components/tabs/setup/EventSetupTab.tsx (2 hunks)
  • packages/prisma/zod-utils.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/review.mdc)

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

Files:

  • packages/features/bookings/Booker/components/hooks/useBookingForm.ts
  • packages/prisma/zod-utils.ts
  • packages/features/bookings/lib/getBookingResponsesSchema.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/review.mdc)

Flag excessive Day.js use in performance-critical code; prefer native Date or Day.js .utc() in hot paths like loops

Files:

  • packages/features/bookings/Booker/components/hooks/useBookingForm.ts
  • packages/features/bookings/Booker/components/BookEventForm/BookingFields.tsx
  • packages/prisma/zod-utils.ts
  • packages/features/bookings/Booker/components/BookEventForm/BookEventForm.tsx
  • packages/features/eventtypes/components/tabs/setup/EventSetupTab.tsx
  • packages/features/bookings/lib/getBookingResponsesSchema.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/components/hooks/useBookingForm.ts
  • packages/features/bookings/Booker/components/BookEventForm/BookingFields.tsx
  • packages/prisma/zod-utils.ts
  • packages/features/bookings/Booker/components/BookEventForm/BookEventForm.tsx
  • packages/features/eventtypes/components/tabs/setup/EventSetupTab.tsx
  • packages/features/bookings/lib/getBookingResponsesSchema.ts
**/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/review.mdc)

Always use t() for text localization in frontend code; direct text embedding should trigger a warning

Files:

  • packages/features/bookings/Booker/components/BookEventForm/BookingFields.tsx
  • packages/features/bookings/Booker/components/BookEventForm/BookEventForm.tsx
  • packages/features/eventtypes/components/tabs/setup/EventSetupTab.tsx
🧠 Learnings (1)
📓 Common learnings
Learnt from: anglerfishlyy
PR: calcom/cal.com#0
File: :0-0
Timestamp: 2025-08-27T16:39:38.192Z
Learning: anglerfishlyy successfully implemented CAL-3076 email invitation feature for Cal.com team event-types in PR #23312. The feature allows inviting people via email directly from assignment flow, with automatic team invitation if email doesn't belong to existing team member. Implementation includes Host type modifications (userId?: number, email?: string, isPending?: boolean), CheckedTeamSelect component updates with CreatableSelect, TRPC schema validation with zod email validation, and integration with existing teamInvite system.
🧬 Code graph analysis (4)
packages/features/bookings/Booker/components/hooks/useBookingForm.ts (1)
packages/features/bookings/types.ts (1)
  • BookerEvent (34-69)
packages/features/bookings/Booker/components/BookEventForm/BookingFields.tsx (1)
packages/features/form-builder/FormBuilderField.tsx (1)
  • FormBuilderField (65-137)
packages/features/eventtypes/components/tabs/setup/EventSetupTab.tsx (1)
packages/ui/components/form/switch/SettingsToggle.tsx (1)
  • SettingsToggle (29-125)
packages/features/bookings/lib/getBookingResponsesSchema.ts (2)
packages/features/form-builder/schema.ts (1)
  • ALL_VIEWS (11-11)
packages/prisma/zod-utils.ts (1)
  • bookingResponses (141-164)
⏰ 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: Install dependencies / Yarn install & cache
  • GitHub Check: Codacy Static Code Analysis

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
@github-actions github-actions bot removed the Stale label Oct 5, 2025
@Parship999 Parship999 closed this Oct 6, 2025
@Parship999 Parship999 reopened this Oct 6, 2025
@github-actions github-actions bot added the Stale label Oct 6, 2025
@Parship999
Copy link
Author

Parship999 commented Oct 7, 2025

yes I was thinking the same about the error message, will change

Parship Chowdhury added 3 commits October 7, 2025 15:34
Signed-off-by: Parship Chowdhury <i.am.parship@gmail.com>
Signed-off-by: Parship Chowdhury <i.am.parship@gmail.com>
Signed-off-by: Parship Chowdhury <i.am.parship@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

🧹 Nitpick comments (1)
packages/features/bookings/lib/getBookingResponsesSchema.ts (1)

34-65: Narrow eventMetadata to the flag we actually use

Typing this as Record<string, unknown> forces downstream unknown checks. Since we only read requireEmailConfirmation, narrow the shape here and in preprocess to tighten the contract and avoid casts.

-}: CommonParams & { eventMetadata?: Record<string, unknown> }) {
+}: CommonParams & { eventMetadata?: { requireEmailConfirmation?: boolean } }) {
@@
-  eventMetadata?: Record<string, unknown>;
+  eventMetadata?: { requireEmailConfirmation?: boolean };
📜 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 fc57c35 and e2080c1.

📒 Files selected for processing (3)
  • apps/web/public/static/locales/en/common.json (2 hunks)
  • packages/features/bookings/Booker/components/hooks/useBookingForm.ts (3 hunks)
  • packages/features/bookings/lib/getBookingResponsesSchema.ts (5 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/components/hooks/useBookingForm.ts
  • packages/features/bookings/lib/getBookingResponsesSchema.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/review.mdc)

Flag excessive Day.js use in performance-critical code; prefer native Date or Day.js .utc() in hot paths like loops

Files:

  • packages/features/bookings/Booker/components/hooks/useBookingForm.ts
  • packages/features/bookings/lib/getBookingResponsesSchema.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/components/hooks/useBookingForm.ts
  • packages/features/bookings/lib/getBookingResponsesSchema.ts
🧬 Code graph analysis (2)
packages/features/bookings/Booker/components/hooks/useBookingForm.ts (1)
packages/features/bookings/types.ts (1)
  • BookerEvent (34-69)
packages/features/bookings/lib/getBookingResponsesSchema.ts (2)
packages/features/form-builder/schema.ts (1)
  • ALL_VIEWS (11-11)
packages/prisma/zod-utils.ts (1)
  • bookingResponses (141-164)
⏰ 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: Codacy Static Code Analysis

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

🧹 Nitpick comments (2)
packages/features/bookings/Booker/components/hooks/useBookingForm.ts (2)

57-83: Verify email presence before requiring confirmation.

The validation requires emailConfirmation (lines 67-73) regardless of whether email exists in responses. While mismatch validation (line 75) correctly guards with email && emailConfirmation, the required-field check does not. If the email field is optional or missing, we'd still demand confirmation of a non-existent value.

Consider adding an email presence check at line 67:

-        // check if email confirmation field is required and empty
-        if (!emailConfirmation) {
+        // check if email confirmation field is required and empty
+        if (email && !emailConfirmation) {
           ctx.addIssue({

This ensures we only require confirmation when there's an email to confirm. If your product requirement guarantees that requireEmailConfirmation is only enabled when email is required, document that assumption in a comment for maintainability.


121-125: Dependency array is correct but could be streamlined.

The effect now includes bookingForm, initialValues, and key. While technically correct:

  • bookingForm is stable (from useForm) and satisfies ESLint's exhaustive-deps rule.
  • key and initialValues overlap—initialValues changes whenever key changes (both derived from useInitialFormValues).

The current approach is defensive and explicit, which is fine. If you want to simplify, initialValues alone might suffice (since it captures all relevant changes including key), but keeping all three documents intent clearly.

📜 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 2b2765c and 3854907.

📒 Files selected for processing (1)
  • packages/features/bookings/Booker/components/hooks/useBookingForm.ts (3 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/components/hooks/useBookingForm.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/review.mdc)

Flag excessive Day.js use in performance-critical code; prefer native Date or Day.js .utc() in hot paths like loops

Files:

  • packages/features/bookings/Booker/components/hooks/useBookingForm.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/components/hooks/useBookingForm.ts
🧠 Learnings (1)
📓 Common learnings
Learnt from: anglerfishlyy
PR: calcom/cal.com#0
File: :0-0
Timestamp: 2025-08-27T16:39:38.192Z
Learning: anglerfishlyy successfully implemented CAL-3076 email invitation feature for Cal.com team event-types in PR #23312. The feature allows inviting people via email directly from assignment flow, with automatic team invitation if email doesn't belong to existing team member. Implementation includes Host type modifications (userId?: number, email?: string, isPending?: boolean), CheckedTeamSelect component updates with CreatableSelect, TRPC schema validation with zod email validation, and integration with existing teamInvite system.
🧬 Code graph analysis (1)
packages/features/bookings/Booker/components/hooks/useBookingForm.ts (1)
packages/features/bookings/types.ts (1)
  • BookerEvent (34-69)
🔇 Additional comments (2)
packages/features/bookings/Booker/components/hooks/useBookingForm.ts (2)

14-15: LGTM!

The metadata field addition enables the hook to consume email confirmation settings from event configuration.


45-55: LGTM!

Event metadata is correctly passed to the schema generator, enabling field-level validation to access the requireEmailConfirmation flag.

…kingFields.tsx

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
@Parship999
Copy link
Author

@anikdhabal Can you please review this PR?

@pallava-joshi
Copy link
Contributor

hey, the type checks were failing, but aside from that, I discussed it with the team. They prefer showing a user warning instead (not in favour of multiple inputs, as they put it). Closing this PR for now. Thanks for contributing, really appreciate your effort!

@Parship999
Copy link
Author

hey, the type checks were failing, but aside from that, I discussed it with the team. They prefer showing a user warning instead (not in favour of multiple inputs, as they put it). Closing this PR for now. Thanks for contributing, really appreciate your effort!

Thanks for the update! Can I help with the user warning part in any way?

@pallava-joshi
Copy link
Contributor

thanks but i already opened a PR for that. you can help with the other issues that are still opened :)

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 community Created by Linear-GitHub Sync ✨ feature New feature or request 🙋🏻‍♂️help wanted Help from the community is appreciated Low priority Created by Linear-GitHub Sync size/L

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Low friction intelligent email verification for bookers

5 participants