Skip to content

Conversation

@dhairyashiil
Copy link
Member

@dhairyashiil dhairyashiil commented Nov 18, 2025

What does this PR do?

Host/Admin/Owner: (remove single attendee)

Screen.Recording.2025-11-18.at.7.02.58.AM.mov

Attendee:

Screen.Recording.2025-11-18.at.7.04.22.AM.mov

Host/Admin/Owner: (remove multiple attendee)

Screen.Recording.2025-11-18.at.7.15.35.AM.mov

Host/Admin/Owner: (remove all)

Screen.Recording.2025-11-18.at.7.18.06.AM.mov

Summary by cubic

Add seat removal to seated bookings with a simple UI and backend support for removing one or more attendees, with clear, localized emails. Addresses CAL-5058 by enabling organizers/admins/owners to remove seats while attendees can only remove their own.

  • New Features

    • Added RemoveBookingSeatsDialog to select and remove seats on upcoming seated bookings.
    • New “Remove seats” action in the booking actions dropdown with store state.
    • Attendees only see their own seat; organizers/admins/owners can remove any seat; backend enforces permissions.
    • Cancel API now accepts seatReferenceUids; repository helpers added to bulk delete seats and attendees, and update external calendar/video integrations.
  • Bug Fixes

    • Emails distinguish host-removed vs attendee-cancelled seats, send per-attendee in their locale, and send a single summary email to the host for multiple removals.
    • Require a cancellation reason when the host, admin, or owner removes seats; improved input validation and error messages.
    • Viewer bookings now include attendee name in seat references for clearer UI labels.

Written for commit cec162e. Summary will update automatically on new commits.

@dhairyashiil dhairyashiil requested a review from a team as a code owner November 18, 2025 00:52
@vercel
Copy link

vercel bot commented Nov 18, 2025

@dhairyashiil 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 Nov 18, 2025
@github-actions github-actions bot added consumer Medium priority Created by Linear-GitHub Sync seats area: seats, guest meetings, multiple people ✨ feature New feature or request labels Nov 18, 2025
@graphite-app graphite-app bot requested a review from a team November 18, 2025 00:52
@keithwillcode keithwillcode added the community-interns The team responsible for reviewing, testing and shipping low/medium community PRs label Nov 18, 2025
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

6 issues found across 19 files

Prompt for AI agents (all 6 issues)

Understand the root cause of the following 6 issues and fix them.


<file name="packages/emails/templates/organizer-multiple-attendees-cancelled-seat-email.ts">

<violation number="1" location="packages/emails/templates/organizer-multiple-attendees-cancelled-seat-email.ts:54">
Rule violated: **Enforce Singular Naming for Single-Item Functions**

`getAttendeeNames()` returns a single string but its plural name implies a collection, violating the singular-naming rule for single-value functions and making callers expect a list instead of the formatted string. Rename the method (and its call sites) to a singular name that reflects the single string return value.</violation>

<violation number="2" location="packages/emails/templates/organizer-multiple-attendees-cancelled-seat-email.ts:77">
Fallback attendee name is hardcoded as &quot;Guest&quot; instead of using the translation function, so the email ignores localization when no attendee name is available.</violation>
</file>

<file name="packages/emails/src/templates/OrganizerAttendeeCancelledSeatEmail.tsx">

<violation number="1" location="packages/emails/src/templates/OrganizerAttendeeCancelledSeatEmail.tsx:12">
Derive the translation function the same way as OrganizerScheduledEmail so subtitle text respects a provided team member’s locale.</violation>

<violation number="2" location="packages/emails/src/templates/OrganizerAttendeeCancelledSeatEmail.tsx:20">
Use the translation function for the “Guest” fallback so the attendee name placeholder remains localized.</violation>
</file>

<file name="apps/web/components/booking/actions/BookingActionsDropdown.tsx">

<violation number="1" location="apps/web/components/booking/actions/BookingActionsDropdown.tsx:246">
The new remove-seats action is never considered in `hasAnyAvailableActions()`, so if it is the only available action the dropdown is suppressed and the feature cannot be triggered. Update the availability check to include `removeSeatsAction`.

(Based on your team&#39;s feedback about ensuring all async operations have proper error handling.) [FEEDBACK_USED]</violation>
</file>

<file name="packages/emails/src/templates/AttendeeCancelledSeatEmail.tsx">

<violation number="1" location="packages/emails/src/templates/AttendeeCancelledSeatEmail.tsx:17">
Placing `{...props}` before the explicit `title/subject/subtitle/callToAction` forces the component to ignore any caller-supplied values for those props, even though the type still allows them. Move the spread back to the end so callers can override defaults as before.</violation>
</file>

Reply to cubic to teach it or ask questions. Re-run a review with @cubic-dev-ai review this PR

@vercel
Copy link

vercel bot commented Nov 18, 2025

Deployment failed with the following error:

The provided GitHub repository does not contain the requested branch or commit reference. Please ensure the repository is not empty.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

4 issues found across 19 files

Prompt for AI agents (all 4 issues)

Understand the root cause of the following 4 issues and fix them.


<file name="packages/emails/templates/organizer-multiple-attendees-cancelled-seat-email.ts">

<violation number="1" location="packages/emails/templates/organizer-multiple-attendees-cancelled-seat-email.ts:68">
`getTextBody` always uses the plural action keys (“were_removed”/“have_cancelled”), so the plain-text organizer email reads “Alice were removed/ have cancelled” when only one seat is removed. Mirror the HTML template and pick singular vs. plural keys based on attendeeCount for correct localization.</violation>
</file>

<file name="packages/features/bookings/lib/handleCancelBooking.ts">

<violation number="1" location="packages/features/bookings/lib/handleCancelBooking.ts:86">
Defaulting `seatReferenceUids` to an empty array and always invoking `cancelAttendeeSeat` makes every non-seat cancellation throw “At least one seat must be selected,” effectively blocking normal booking cancellations.</violation>
</file>

<file name="apps/web/components/booking/RemoveBookingSeatsDialog.tsx">

<violation number="1" location="apps/web/components/booking/RemoveBookingSeatsDialog.tsx:48">
Admins or owners who are also seated are misclassified as “just attendees”, so the dialog only ever exposes their own seat even though elevated roles should be able to remove any seat. Add an explicit permission check (role/team ownership) before entering the attendee-only branch so privileged users keep access to all seats.</violation>

<violation number="2" location="apps/web/components/booking/RemoveBookingSeatsDialog.tsx:89">
The fallback seat label is hard-coded as &quot;Seat …&quot; instead of being localized via t(), so it won’t translate. Wrap the fallback in t() with a dedicated key and pass the truncated reference as interpolation.</violation>
</file>

Reply to cubic to teach it or ask questions. Re-run a review with @cubic-dev-ai review this PR

skipCancellationReasonValidation = false,
} = bookingCancelInput.parse(body);

const seatReferenceUids = seatReferenceUid ? [seatReferenceUid] : rawSeatReferenceUids || [];
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Nov 18, 2025

Choose a reason for hiding this comment

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

Defaulting seatReferenceUids to an empty array and always invoking cancelAttendeeSeat makes every non-seat cancellation throw “At least one seat must be selected,” effectively blocking normal booking cancellations.

Prompt for AI agents
Address the following comment on packages/features/bookings/lib/handleCancelBooking.ts at line 86:

<comment>Defaulting `seatReferenceUids` to an empty array and always invoking `cancelAttendeeSeat` makes every non-seat cancellation throw “At least one seat must be selected,” effectively blocking normal booking cancellations.</comment>

<file context>
@@ -76,11 +76,15 @@ async function handler(input: CancelBookingInput) {
     skipCancellationReasonValidation = false,
   } = bookingCancelInput.parse(body);
+
+  const seatReferenceUids = seatReferenceUid ? [seatReferenceUid] : rawSeatReferenceUids || [];
+
   const bookingToDelete = await getBookingToDelete(id, uid);
</file context>
Fix with Cubic

Copy link
Contributor

@volnei volnei left a comment

Choose a reason for hiding this comment

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

@dhairyashiil unit tests are failing. Can you check please?

@github-actions github-actions bot marked this pull request as draft November 18, 2025 10:43
@dhairyashiil dhairyashiil marked this pull request as ready for review November 19, 2025 12:38
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

4 issues found across 19 files

Prompt for AI agents (all 4 issues)

Understand the root cause of the following 4 issues and fix them.


<file name="apps/web/components/booking/actions/BookingActionsDropdown.tsx">

<violation number="1" location="apps/web/components/booking/actions/BookingActionsDropdown.tsx:423">
`RemoveBookingSeatsDialog` already invalidates bookings and shows the success toast before invoking `onSuccess`, so this callback now fires the same toast/refetch twice, creating duplicate messaging and redundant work for every removal.</violation>
</file>

<file name="apps/web/components/booking/RemoveBookingSeatsDialog.tsx">

<violation number="1" location="apps/web/components/booking/RemoveBookingSeatsDialog.tsx:89">
Fallback seat labels are hard-coded in English (&quot;Seat …&quot;) instead of going through t(), which breaks localization policy. Please wrap the fallback label in a translation key (e.g., t(&quot;seat_reference_fallback&quot;, { referenceUid: … })).</violation>
</file>

<file name="packages/emails/templates/organizer-multiple-attendees-cancelled-seat-email.ts">

<violation number="1" location="packages/emails/templates/organizer-multiple-attendees-cancelled-seat-email.ts:70">
The text body uses the translation key &quot;attendees_cancelled_seats_text&quot;, but that key does not exist in any locale file, so the organizer will see the raw key string instead of a localized sentence.</violation>
</file>

<file name="packages/features/bookings/lib/handleCancelBooking.ts">

<violation number="1" location="packages/features/bookings/lib/handleCancelBooking.ts:86">
Omitting seatReferenceUids now lets any attendee cancel the entire booking: cancelAttendeeSeat returns early on an empty array, and without a host/admin guard the handler falls through to full booking cancellation. Reintroduce an authorization check that rejects non‑hosts whenever no seat references are provided.</violation>
</file>

Reply to cubic to teach it or ask questions. Re-run a review with @cubic-dev-ai review this PR

@dhairyashiil dhairyashiil marked this pull request as draft November 19, 2025 15:12
@github-actions
Copy link
Contributor

This PR has been marked as stale due to inactivity. If you're still working on it or need any help, please let us know or update the PR to keep it active.

@github-actions github-actions bot added the Stale label Nov 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 community-interns The team responsible for reviewing, testing and shipping low/medium community PRs consumer ✨ feature New feature or request Medium priority Created by Linear-GitHub Sync seats area: seats, guest meetings, multiple people size/XXL Stale

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[CAL-5058] Allow to remove seats from a booking

3 participants