Skip to content

Commit 3ada7d9

Browse files
chore: address review comment style
1 parent fbc26f3 commit 3ada7d9

4 files changed

Lines changed: 23 additions & 86 deletions

File tree

packages/app-store/office365calendar/lib/CalendarService.ts

Lines changed: 8 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -320,12 +320,8 @@ class Office365CalendarService implements Calendar {
320320
}
321321

322322
/**
323-
* Updates an Office365 calendar event and handles seated attendee-only updates.
324-
*
325-
* @param uid - Office365 event identifier to update.
326-
* @param event - Calendar event data to send to Microsoft Graph.
327-
* @param externalCalendarId - Optional Office365 calendar identifier containing the event.
328-
* @returns Updated Office365 event details.
323+
* Seated bookings split event-detail and attendee patches because Exchange can turn combined
324+
* attendee-list mutations into organizer-level updates for everyone on the event.
329325
*/
330326
async updateEvent(
331327
uid: string,
@@ -348,7 +344,6 @@ class Office365CalendarService implements Calendar {
348344
rescheduledEvent = await handleErrorsJson<Event>(response);
349345
}
350346

351-
// Build the full translated event object
352347
const translatedEvent = this.translateEvent(event, rescheduledEvent);
353348

354349
let response: Response;
@@ -386,26 +381,17 @@ class Office365CalendarService implements Calendar {
386381
lastError = err instanceof Error ? err : new Error(String(err));
387382

388383
if (attempt < MAX_RETRIES) {
389-
// Exponential backoff before next attempt
384+
// Exchange can lag after the first seated-booking patch, so retry attendee sync briefly.
390385
const backoff = BACKOFF_MS * 2 ** (attempt - 1);
391386
this.log.warn(
392387
`PATCH_ATTENDEES attempt ${attempt}/${MAX_RETRIES} failed for event uid=${uid}, retrying in ${backoff}ms`,
393388
{ err }
394389
);
395-
await new Promise(
396-
/**
397-
* Resolves the retry delay after the computed backoff.
398-
*
399-
* @param resolve - Promise resolver called when the delay completes.
400-
* @returns Timeout handle created for the retry delay.
401-
*/
402-
(resolve) => setTimeout(resolve, backoff)
403-
);
390+
await new Promise((resolve) => setTimeout(resolve, backoff));
404391
}
405392
}
406393
}
407394

408-
// Retry failure handling for PATCH 2
409395
if (lastError) {
410396
let httpStatus: number | undefined;
411397
let httpBody: unknown;
@@ -415,14 +401,7 @@ class Office365CalendarService implements Calendar {
415401
try {
416402
httpBody = await patch2Response.json();
417403
} catch {
418-
httpBody = await patch2Response.text().catch(
419-
/**
420-
* Provides a fallback body when the Graph response text cannot be read.
421-
*
422-
* @returns Fallback response body message.
423-
*/
424-
() => "unable to read response body"
425-
);
404+
httpBody = await patch2Response.text().catch(() => "unable to read response body");
426405
}
427406
}
428407

@@ -445,7 +424,6 @@ class Office365CalendarService implements Calendar {
445424
);
446425
}
447426

448-
// PATCH 2 succeeded — use its response for the return value below
449427
response = patch2Response!;
450428
} else {
451429
response = await this.fetcher(eventEndpoint, {
@@ -470,12 +448,8 @@ class Office365CalendarService implements Calendar {
470448
}
471449

472450
/**
473-
* Deletes an Office365 event from the same calendar that stored its reference.
474-
*
475-
* @param uid - Office365 event identifier to delete.
476-
* @param _event - Calendar event associated with the deletion.
477-
* @param externalCalendarId - Optional Office365 calendar identifier containing the event.
478-
* @returns A promise that resolves when Microsoft Graph accepts the delete.
451+
* Selected Outlook calendars require their own Graph delete path; the default-calendar path
452+
* cannot remove events created outside the primary calendar.
479453
*/
480454
async deleteEvent(uid: string, _event: CalendarEvent, externalCalendarId?: string | null): Promise<void> {
481455
try {
@@ -493,12 +467,7 @@ class Office365CalendarService implements Calendar {
493467
}
494468

495469
/**
496-
* Builds the Graph event URL for default or explicitly selected calendars.
497-
*
498-
* @param endpoint - Graph user endpoint for the credential.
499-
* @param uid - Office365 event identifier.
500-
* @param externalCalendarId - Optional selected calendar identifier.
501-
* @returns Microsoft Graph event endpoint for the target calendar.
470+
* Graph separates default-calendar events from explicitly selected calendar events at the URL level.
502471
*/
503472
private getEventEndpoint(endpoint: string, uid: string, externalCalendarId?: string | null) {
504473
return externalCalendarId

packages/emails/templates/attendee-scheduled-email.ts

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,8 @@ export default class AttendeeScheduledEmail extends BaseEmail {
1515
t: TFunction;
1616

1717
/**
18-
* Builds an attendee scheduled email with seated attendee visibility applied.
19-
*
20-
* @param calEvent - Calendar event used to render the scheduled email.
21-
* @param attendee - Recipient attendee for the scheduled email.
22-
* @param showAttendees - Optional override for displaying other seated attendees.
23-
* @returns A configured attendee scheduled email instance.
18+
* Seated booking confirmations render from the recipient's perspective so later attendees do
19+
* not inherit the first attendee's name in Outlook-generated invite content.
2420
*/
2521
constructor(calEvent: CalendarEvent, attendee: Person, showAttendees?: boolean | undefined) {
2622
super();
@@ -38,15 +34,7 @@ export default class AttendeeScheduledEmail extends BaseEmail {
3834
if (shouldShowAttendees) {
3935
attendees = [
4036
attendee,
41-
...calEvent.attendees.filter(
42-
/**
43-
* Keeps the current attendee first by removing duplicate attendee entries.
44-
*
45-
* @param eventAttendee - Attendee from the original calendar event.
46-
* @returns Whether the attendee should remain after the recipient.
47-
*/
48-
(eventAttendee) => eventAttendee.email !== attendee.email
49-
),
37+
...calEvent.attendees.filter((eventAttendee) => eventAttendee.email !== attendee.email),
5038
];
5139
}
5240

packages/features/bookings/lib/handleSeats/cancel/cancelAttendeeSeat.ts

Lines changed: 8 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,8 @@ import type { BookingToDelete } from "../../handleCancelBooking";
2323
import { getSeatCalendarReferences, OFFICE365_CALENDAR_TYPE } from "../lib/seatCalendarReferences";
2424

2525
/**
26-
* Creates a stable key for comparing Office365 references across seat and booking storage.
27-
*
28-
* @param reference - Office365 calendar reference to compare.
29-
* @returns Stable key for identifying the same Office365 event reference.
26+
* Booking-level fallback can contain multiple Office365 refs, so compare every provider identity
27+
* field before deciding which event was already handled.
3028
*/
3129
const getOffice365ReferenceKey = (
3230
reference: Pick<
@@ -43,12 +41,8 @@ const getOffice365ReferenceKey = (
4341
]);
4442

4543
/**
46-
* Cancels a single attendee seat and updates affected integrations.
47-
*
48-
* @param data - Seat cancellation input and booking data.
49-
* @param dataForWebhooks - Webhook and calendar event data for cancellation side effects.
50-
* @param eventTypeMetadata - Event type metadata used for cancellation notifications.
51-
* @returns A promise that resolves after the attendee seat cancellation is processed.
44+
* Seat cancellation must preserve the group booking while isolating provider cleanup to the
45+
* attendee who is leaving.
5246
*/
5347
async function cancelAttendeeSeat(
5448
data: {
@@ -115,6 +109,7 @@ async function cancelAttendeeSeat(
115109
seatReference.metadata,
116110
OFFICE365_CALENDAR_TYPE
117111
);
112+
// Pre-fix seated bookings stored Office365 refs on the booking, so keep that fallback for cleanup.
118113
const bookingLevelOffice365References = bookingToDelete.references.filter(
119114
(reference) => reference.type === OFFICE365_CALENDAR_TYPE
120115
);
@@ -149,6 +144,7 @@ async function cancelAttendeeSeat(
149144
return true;
150145
}
151146

147+
// Per-seat Office365 events are deleted directly; shared updates would notify attendees who are staying.
152148
if (seatOffice365CalendarReferences.length > 0) {
153149
return false;
154150
}
@@ -180,15 +176,8 @@ async function cancelAttendeeSeat(
180176
};
181177
}
182178

183-
const attendees = evt.attendees.filter(
184-
/**
185-
* Removes the canceled attendee from the shared event attendee list.
186-
*
187-
* @param evtAttendee - Calendar event attendee to inspect.
188-
* @returns Whether the attendee should remain on the shared event.
189-
*/
190-
(evtAttendee) => attendee.email !== evtAttendee.email
191-
);
179+
// Shared non-Office365 integrations still update the attendee list, so keep the leaving seat out.
180+
const attendees = evt.attendees.filter((evtAttendee) => attendee.email !== evtAttendee.email);
192181
const updatedEvt = {
193182
...evt,
194183
attendees,

packages/features/bookings/lib/service/RegularBookingService.ts

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -488,13 +488,8 @@ async function validateRescheduleRestrictions({
488488
}
489489

490490
/**
491-
* Creates or reschedules a regular booking and records integration references.
492-
*
493-
* @param this - Regular booking service instance bound to the handler.
494-
* @param input - Booking request data and platform context.
495-
* @param deps - Service dependencies used by the booking flow.
496-
* @param bookingDataSchemaGetter - Optional schema factory for booking data validation.
497-
* @returns Booking response containing created references and seat metadata.
491+
* Calendar references are recorded here because cancellation and reschedule flows need provider
492+
* event IDs after the booking transaction completes.
498493
*/
499494
async function handler(
500495
this: RegularBookingService,
@@ -2454,13 +2449,8 @@ async function handler(
24542449

24552450
if (!booking) throw new HttpError({ statusCode: 400, message: "Booking failed" });
24562451

2452+
// Single-seat cancellation deletes by provider UID, so only concrete Office365 events belong in seat metadata.
24572453
const office365SeatReferences = referencesToCreate.filter(
2458-
/**
2459-
* Keeps valid Office365 references created for a seated booking seat.
2460-
*
2461-
* @param reference - Calendar reference created during booking.
2462-
* @returns Whether the reference should be stored on the booking seat.
2463-
*/
24642454
(reference) => reference.type === OFFICE365_CALENDAR_TYPE && reference.uid
24652455
);
24662456
const shouldPersistOffice365SeatReferences =
@@ -2484,6 +2474,7 @@ async function handler(
24842474
});
24852475

24862476
if (shouldPersistOffice365SeatReferences && evt.attendeeSeatId) {
2477+
// Seat metadata must persist with booking references or Outlook cleanup loses the per-attendee event.
24872478
await deps.prismaClient.$transaction([
24882479
bookingUpdate,
24892480
deps.prismaClient.bookingSeat.update({

0 commit comments

Comments
 (0)