fix: false 500s from /api/book/event (#23001)
* fix: false 500 from api/book/event * fix another
This commit is contained in:
@@ -26,11 +26,14 @@ describe("CalendarEventBuilder", () => {
|
||||
})
|
||||
.build();
|
||||
|
||||
expect(event.bookerUrl).toBe("https://cal.com/user/test-slug");
|
||||
expect(event.title).toBe("Test Event");
|
||||
expect(event.startTime).toBe(mockStartTime);
|
||||
expect(event.endTime).toBe(mockEndTime);
|
||||
expect(event.additionalNotes).toBe("Some notes");
|
||||
expect(event).not.toBeNull();
|
||||
if (event) {
|
||||
expect(event.bookerUrl).toBe("https://cal.com/user/test-slug");
|
||||
expect(event.title).toBe("Test Event");
|
||||
expect(event.startTime).toBe(mockStartTime);
|
||||
expect(event.endTime).toBe(mockEndTime);
|
||||
expect(event.additionalNotes).toBe("Some notes");
|
||||
}
|
||||
});
|
||||
|
||||
it("should create an event with event type details", () => {
|
||||
@@ -50,11 +53,14 @@ describe("CalendarEventBuilder", () => {
|
||||
})
|
||||
.build();
|
||||
|
||||
expect(event.type).toBe("test-slug");
|
||||
expect(event.description).toBe("Test description");
|
||||
expect(event.eventTypeId).toBe(123);
|
||||
expect(event.hideCalendarNotes).toBe(true);
|
||||
expect(event.hideCalendarEventDetails).toBe(false);
|
||||
expect(event).not.toBeNull();
|
||||
if (event) {
|
||||
expect(event.type).toBe("test-slug");
|
||||
expect(event.description).toBe("Test description");
|
||||
expect(event.eventTypeId).toBe(123);
|
||||
expect(event.hideCalendarNotes).toBe(true);
|
||||
expect(event.hideCalendarEventDetails).toBe(false);
|
||||
}
|
||||
});
|
||||
|
||||
it("should create an event with organizer details", () => {
|
||||
@@ -82,17 +88,20 @@ describe("CalendarEventBuilder", () => {
|
||||
})
|
||||
.build();
|
||||
|
||||
expect(event.organizer).toEqual({
|
||||
id: 456,
|
||||
name: "John Doe",
|
||||
email: "john@example.com",
|
||||
username: "johndoe",
|
||||
timeZone: "America/New_York",
|
||||
language: {
|
||||
translate: mockTranslate,
|
||||
locale: "en",
|
||||
},
|
||||
});
|
||||
expect(event).not.toBeNull();
|
||||
if (event) {
|
||||
expect(event.organizer).toEqual({
|
||||
id: 456,
|
||||
name: "John Doe",
|
||||
email: "john@example.com",
|
||||
username: "johndoe",
|
||||
timeZone: "America/New_York",
|
||||
language: {
|
||||
translate: mockTranslate,
|
||||
locale: "en",
|
||||
},
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it("should handle nameless organizer", () => {
|
||||
@@ -119,7 +128,10 @@ describe("CalendarEventBuilder", () => {
|
||||
})
|
||||
.build();
|
||||
|
||||
expect(event.organizer.name).toBe("Nameless");
|
||||
expect(event).not.toBeNull();
|
||||
if (event) {
|
||||
expect(event.organizer.name).toBe("Nameless");
|
||||
}
|
||||
});
|
||||
|
||||
it("should create an event with attendees", () => {
|
||||
@@ -158,7 +170,10 @@ describe("CalendarEventBuilder", () => {
|
||||
.withAttendees(attendees)
|
||||
.build();
|
||||
|
||||
expect(event.attendees).toEqual(attendees);
|
||||
expect(event).not.toBeNull();
|
||||
if (event) {
|
||||
expect(event.attendees).toEqual(attendees);
|
||||
}
|
||||
});
|
||||
|
||||
it("should create an event with metadata and responses", () => {
|
||||
@@ -192,10 +207,13 @@ describe("CalendarEventBuilder", () => {
|
||||
})
|
||||
.build();
|
||||
|
||||
expect(event.additionalNotes).toBe("Some notes");
|
||||
expect(event.customInputs).toEqual(customInputs);
|
||||
expect(event.responses).toEqual(responses);
|
||||
expect(event.userFieldsResponses).toEqual(userFieldsResponses);
|
||||
expect(event).not.toBeNull();
|
||||
if (event) {
|
||||
expect(event.additionalNotes).toBe("Some notes");
|
||||
expect(event.customInputs).toEqual(customInputs);
|
||||
expect(event.responses).toEqual(responses);
|
||||
expect(event.userFieldsResponses).toEqual(userFieldsResponses);
|
||||
}
|
||||
});
|
||||
|
||||
it("should create an event with location", () => {
|
||||
@@ -216,8 +234,11 @@ describe("CalendarEventBuilder", () => {
|
||||
})
|
||||
.build();
|
||||
|
||||
expect(event.location).toBe("Conference Room A");
|
||||
expect(event.conferenceCredentialId).toBe(789);
|
||||
expect(event).not.toBeNull();
|
||||
if (event) {
|
||||
expect(event.location).toBe("Conference Room A");
|
||||
expect(event.conferenceCredentialId).toBe(789);
|
||||
}
|
||||
});
|
||||
|
||||
it("should create an event with destination calendar", () => {
|
||||
@@ -229,6 +250,8 @@ describe("CalendarEventBuilder", () => {
|
||||
userId: null,
|
||||
eventTypeId: null,
|
||||
credentialId: null,
|
||||
createdAt: null,
|
||||
updatedAt: null,
|
||||
delegationCredentialId: null,
|
||||
domainWideDelegationCredentialId: null,
|
||||
};
|
||||
@@ -247,7 +270,10 @@ describe("CalendarEventBuilder", () => {
|
||||
.withDestinationCalendar([destinationCalendar])
|
||||
.build();
|
||||
|
||||
expect(event.destinationCalendar).toEqual([destinationCalendar]);
|
||||
expect(event).not.toBeNull();
|
||||
if (event) {
|
||||
expect(event.destinationCalendar).toEqual([destinationCalendar]);
|
||||
}
|
||||
});
|
||||
|
||||
it("should create an event with identifiers", () => {
|
||||
@@ -268,8 +294,11 @@ describe("CalendarEventBuilder", () => {
|
||||
})
|
||||
.build();
|
||||
|
||||
expect(event.iCalUID).toBe("ical-123");
|
||||
expect(event.iCalSequence).toBe(2);
|
||||
expect(event).not.toBeNull();
|
||||
if (event) {
|
||||
expect(event.iCalUID).toBe("ical-123");
|
||||
expect(event.iCalSequence).toBe(2);
|
||||
}
|
||||
});
|
||||
|
||||
it("should create an event with confirmation settings", () => {
|
||||
@@ -290,8 +319,11 @@ describe("CalendarEventBuilder", () => {
|
||||
})
|
||||
.build();
|
||||
|
||||
expect(event.requiresConfirmation).toBe(true);
|
||||
expect(event.oneTimePassword).toBeUndefined();
|
||||
expect(event).not.toBeNull();
|
||||
if (event) {
|
||||
expect(event.requiresConfirmation).toBe(true);
|
||||
expect(event.oneTimePassword).toBeUndefined();
|
||||
}
|
||||
});
|
||||
|
||||
it("should set oneTimePassword to null when isConfirmedByDefault is true", () => {
|
||||
@@ -312,8 +344,11 @@ describe("CalendarEventBuilder", () => {
|
||||
})
|
||||
.build();
|
||||
|
||||
expect(event.requiresConfirmation).toBe(true);
|
||||
expect(event.oneTimePassword).toBeNull();
|
||||
expect(event).not.toBeNull();
|
||||
if (event) {
|
||||
expect(event.requiresConfirmation).toBe(true);
|
||||
expect(event.oneTimePassword).toBeNull();
|
||||
}
|
||||
});
|
||||
|
||||
it("should create an event with platform variables", () => {
|
||||
@@ -336,10 +371,13 @@ describe("CalendarEventBuilder", () => {
|
||||
})
|
||||
.build();
|
||||
|
||||
expect(event.platformClientId).toBe("client-123");
|
||||
expect(event.platformRescheduleUrl).toBe("https://platform.com/reschedule");
|
||||
expect(event.platformCancelUrl).toBe("https://platform.com/cancel");
|
||||
expect(event.platformBookingUrl).toBe("https://platform.com/booking");
|
||||
expect(event).not.toBeNull();
|
||||
if (event) {
|
||||
expect(event.platformClientId).toBe("client-123");
|
||||
expect(event.platformRescheduleUrl).toBe("https://platform.com/reschedule");
|
||||
expect(event.platformCancelUrl).toBe("https://platform.com/cancel");
|
||||
expect(event.platformBookingUrl).toBe("https://platform.com/booking");
|
||||
}
|
||||
});
|
||||
|
||||
it("should create an event with apps status", () => {
|
||||
@@ -376,7 +414,10 @@ describe("CalendarEventBuilder", () => {
|
||||
.withAppsStatus(appsStatus)
|
||||
.build();
|
||||
|
||||
expect(event.appsStatus).toEqual(appsStatus);
|
||||
expect(event).not.toBeNull();
|
||||
if (event) {
|
||||
expect(event.appsStatus).toEqual(appsStatus);
|
||||
}
|
||||
});
|
||||
|
||||
it("should create an event with video call data", () => {
|
||||
@@ -401,7 +442,10 @@ describe("CalendarEventBuilder", () => {
|
||||
.withVideoCallData(videoCallData)
|
||||
.build();
|
||||
|
||||
expect(event.videoCallData).toEqual(videoCallData);
|
||||
expect(event).not.toBeNull();
|
||||
if (event) {
|
||||
expect(event.videoCallData).toEqual(videoCallData);
|
||||
}
|
||||
});
|
||||
|
||||
it("should create an event with team information", () => {
|
||||
@@ -435,7 +479,10 @@ describe("CalendarEventBuilder", () => {
|
||||
.withTeam(team)
|
||||
.build();
|
||||
|
||||
expect(event.team).toEqual(team);
|
||||
expect(event).not.toBeNull();
|
||||
if (event) {
|
||||
expect(event.team).toEqual(team);
|
||||
}
|
||||
});
|
||||
|
||||
it("should create an event with recurring event information", () => {
|
||||
@@ -459,7 +506,10 @@ describe("CalendarEventBuilder", () => {
|
||||
.withRecurring(recurringEvent)
|
||||
.build();
|
||||
|
||||
expect(event.recurringEvent).toEqual(recurringEvent);
|
||||
expect(event).not.toBeNull();
|
||||
if (event) {
|
||||
expect(event.recurringEvent).toEqual(recurringEvent);
|
||||
}
|
||||
});
|
||||
|
||||
it("should create an event with attendee seat ID", () => {
|
||||
@@ -477,7 +527,10 @@ describe("CalendarEventBuilder", () => {
|
||||
.withAttendeeSeatId("seat-123")
|
||||
.build();
|
||||
|
||||
expect(event.attendeeSeatId).toBe("seat-123");
|
||||
expect(event).not.toBeNull();
|
||||
if (event) {
|
||||
expect(event.attendeeSeatId).toBe("seat-123");
|
||||
}
|
||||
});
|
||||
|
||||
it("should create an event with UID", () => {
|
||||
@@ -495,7 +548,10 @@ describe("CalendarEventBuilder", () => {
|
||||
.withUid("booking-uid-123")
|
||||
.build();
|
||||
|
||||
expect(event.uid).toBe("booking-uid-123");
|
||||
expect(event).not.toBeNull();
|
||||
if (event) {
|
||||
expect(event.uid).toBe("booking-uid-123");
|
||||
}
|
||||
});
|
||||
|
||||
it("should create an event with one-time password", () => {
|
||||
@@ -513,7 +569,10 @@ describe("CalendarEventBuilder", () => {
|
||||
.withOneTimePassword("otp123")
|
||||
.build();
|
||||
|
||||
expect(event.oneTimePassword).toBe("otp123");
|
||||
expect(event).not.toBeNull();
|
||||
if (event) {
|
||||
expect(event.oneTimePassword).toBe("otp123");
|
||||
}
|
||||
});
|
||||
|
||||
it("should create an event with recurring event ID", () => {
|
||||
@@ -531,9 +590,12 @@ describe("CalendarEventBuilder", () => {
|
||||
.withRecurringEventId("recurring-123")
|
||||
.build();
|
||||
|
||||
expect(event.existingRecurringEvent).toEqual({
|
||||
recurringEventId: "recurring-123",
|
||||
});
|
||||
expect(event).not.toBeNull();
|
||||
if (event) {
|
||||
expect(event.existingRecurringEvent).toEqual({
|
||||
recurringEventId: "recurring-123",
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it("should create a complete calendar event with all properties", () => {
|
||||
@@ -597,6 +659,8 @@ describe("CalendarEventBuilder", () => {
|
||||
userId: 1,
|
||||
eventTypeId: 123,
|
||||
credentialId: 1,
|
||||
createdAt: null,
|
||||
updatedAt: null,
|
||||
delegationCredentialId: null,
|
||||
domainWideDelegationCredentialId: null,
|
||||
},
|
||||
@@ -644,26 +708,29 @@ describe("CalendarEventBuilder", () => {
|
||||
.build();
|
||||
|
||||
// Test that all properties are set correctly
|
||||
expect(event.title).toBe("Complete Test Event");
|
||||
expect(event.type).toBe("complete-test");
|
||||
expect(event.organizer.name).toBe("John Doe");
|
||||
expect(event.attendees).toHaveLength(1);
|
||||
expect(event.location).toBe("Conference Room A");
|
||||
expect(event.iCalUID).toBe("ical-123");
|
||||
expect(event.requiresConfirmation).toBe(true);
|
||||
expect(event.platformClientId).toBe("client-123");
|
||||
expect(event.appsStatus).toHaveLength(1);
|
||||
expect(event.videoCallData?.url).toBe("https://meet.example.com/123");
|
||||
expect(event.team?.name).toBe("Engineering Team");
|
||||
expect(event.recurringEvent?.count).toBe(5);
|
||||
expect(event.attendeeSeatId).toBe("seat-123");
|
||||
expect(event.uid).toBe("booking-uid-123");
|
||||
expect(event.oneTimePassword).toBe("otp123");
|
||||
expect(event).not.toBeNull();
|
||||
if (event) {
|
||||
expect(event.title).toBe("Complete Test Event");
|
||||
expect(event.type).toBe("complete-test");
|
||||
expect(event.organizer.name).toBe("John Doe");
|
||||
expect(event.attendees).toHaveLength(1);
|
||||
expect(event.location).toBe("Conference Room A");
|
||||
expect(event.iCalUID).toBe("ical-123");
|
||||
expect(event.requiresConfirmation).toBe(true);
|
||||
expect(event.platformClientId).toBe("client-123");
|
||||
expect(event.appsStatus).toHaveLength(1);
|
||||
expect(event.videoCallData?.url).toBe("https://meet.example.com/123");
|
||||
expect(event.team?.name).toBe("Engineering Team");
|
||||
expect(event.recurringEvent?.count).toBe(5);
|
||||
expect(event.attendeeSeatId).toBe("seat-123");
|
||||
expect(event.uid).toBe("booking-uid-123");
|
||||
expect(event.oneTimePassword).toBe("otp123");
|
||||
}
|
||||
});
|
||||
|
||||
it("should throw an error when building without required fields", () => {
|
||||
it("should return null when building without required fields", () => {
|
||||
const builder = new CalendarEventBuilder();
|
||||
expect(() => builder.build()).toThrow("Missing required fields for calendar event");
|
||||
expect(builder.build()).toBeNull();
|
||||
});
|
||||
|
||||
it("should create an event from an existing event", () => {
|
||||
@@ -684,8 +751,11 @@ describe("CalendarEventBuilder", () => {
|
||||
})
|
||||
.build();
|
||||
|
||||
expect(event.title).toBe("Updated Event");
|
||||
expect(event.type).toBe("existing-type");
|
||||
expect(event).not.toBeNull();
|
||||
if (event) {
|
||||
expect(event.title).toBe("Updated Event");
|
||||
expect(event.type).toBe("existing-type");
|
||||
}
|
||||
});
|
||||
|
||||
it("should propagate disableCancelling and disableRescheduling", () => {
|
||||
@@ -706,7 +776,10 @@ describe("CalendarEventBuilder", () => {
|
||||
})
|
||||
.build();
|
||||
|
||||
expect(event.disableCancelling).toBe(true);
|
||||
expect(event.disableRescheduling).toBe(true);
|
||||
expect(event).not.toBeNull();
|
||||
if (event) {
|
||||
expect(event.disableCancelling).toBe(true);
|
||||
expect(event.disableRescheduling).toBe(true);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -266,7 +266,7 @@ export class CalendarEventBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
build(): CalendarEvent {
|
||||
build(): CalendarEvent | null {
|
||||
// Validate required fields
|
||||
if (
|
||||
!this.event.startTime ||
|
||||
@@ -275,7 +275,7 @@ export class CalendarEventBuilder {
|
||||
!this.event.bookerUrl ||
|
||||
!this.event.title
|
||||
) {
|
||||
throw new Error("Missing required fields for calendar event");
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.event as CalendarEvent;
|
||||
|
||||
@@ -7,6 +7,7 @@ import { contructEmailFromPhoneNumber } from "@calcom/lib/contructEmailFromPhone
|
||||
import { getBookingWithResponses } from "@calcom/lib/getBooking";
|
||||
import { eventTypeBookingFields } from "@calcom/prisma/zod-utils";
|
||||
import type { CalendarEvent } from "@calcom/types/Calendar";
|
||||
import { HttpError } from "@calcom/lib/http-error";
|
||||
|
||||
export const getCalEventResponses = ({
|
||||
bookingFields,
|
||||
@@ -42,7 +43,10 @@ export const getCalEventResponses = ({
|
||||
// To set placeholder email for the booking
|
||||
if (!!!backwardCompatibleResponses.email) {
|
||||
if (typeof backwardCompatibleResponses["attendeePhoneNumber"] !== "string")
|
||||
throw new Error("Both Phone and Email are missing");
|
||||
throw new HttpError({
|
||||
statusCode: 400,
|
||||
message: "Both Phone and Email are missing",
|
||||
});
|
||||
|
||||
backwardCompatibleResponses.email = contructEmailFromPhoneNumber(
|
||||
backwardCompatibleResponses["attendeePhoneNumber"]
|
||||
|
||||
@@ -320,17 +320,35 @@ export const buildEventForTeamEventType = async ({
|
||||
|
||||
const teamMembers = await Promise.all(teamMemberPromises);
|
||||
|
||||
evt = CalendarEventBuilder.fromEvent(evt)
|
||||
.withDestinationCalendar([...(evt.destinationCalendar ?? []), ...teamDestinationCalendars])
|
||||
const updatedEvt = CalendarEventBuilder.fromEvent(evt)
|
||||
?.withDestinationCalendar([...(evt.destinationCalendar ?? []), ...teamDestinationCalendars])
|
||||
.build();
|
||||
|
||||
return CalendarEventBuilder.fromEvent(evt)
|
||||
.withTeam({
|
||||
if (!updatedEvt) {
|
||||
throw new HttpError({
|
||||
statusCode: 400,
|
||||
message: "Failed to build event with destination calendar due to missing required fields",
|
||||
});
|
||||
}
|
||||
|
||||
evt = updatedEvt;
|
||||
|
||||
const teamEvt = CalendarEventBuilder.fromEvent(evt)
|
||||
?.withTeam({
|
||||
members: teamMembers,
|
||||
name: team?.name || "Nameless",
|
||||
id: team?.id ?? 0,
|
||||
})
|
||||
.build();
|
||||
|
||||
if (!teamEvt) {
|
||||
throw new HttpError({
|
||||
statusCode: 400,
|
||||
message: "Failed to build team event due to missing required fields",
|
||||
});
|
||||
}
|
||||
|
||||
return teamEvt;
|
||||
};
|
||||
|
||||
function buildTroubleshooterData({
|
||||
@@ -1168,7 +1186,7 @@ async function handler(
|
||||
|
||||
const eventName = getEventName(eventNameObject);
|
||||
|
||||
let evt: CalendarEvent = new CalendarEventBuilder()
|
||||
const builtEvt = new CalendarEventBuilder()
|
||||
.withBasicDetails({
|
||||
bookerUrl,
|
||||
title: eventName,
|
||||
@@ -1226,20 +1244,44 @@ async function handler(
|
||||
})
|
||||
.build();
|
||||
|
||||
if (!builtEvt) {
|
||||
throw new HttpError({
|
||||
statusCode: 400,
|
||||
message: "Failed to build calendar event due to missing required fields",
|
||||
});
|
||||
}
|
||||
|
||||
let evt: CalendarEvent = builtEvt;
|
||||
|
||||
if (input.bookingData.thirdPartyRecurringEventId) {
|
||||
evt = CalendarEventBuilder.fromEvent(evt)
|
||||
.withRecurringEventId(input.bookingData.thirdPartyRecurringEventId)
|
||||
const updatedEvt = CalendarEventBuilder.fromEvent(evt)
|
||||
?.withRecurringEventId(input.bookingData.thirdPartyRecurringEventId)
|
||||
.build();
|
||||
|
||||
if (!updatedEvt) {
|
||||
throw new HttpError({
|
||||
statusCode: 400,
|
||||
message: "Failed to build event with recurring event ID due to missing required fields",
|
||||
});
|
||||
}
|
||||
|
||||
evt = updatedEvt;
|
||||
}
|
||||
|
||||
if (isTeamEventType) {
|
||||
evt = await buildEventForTeamEventType({
|
||||
const teamEvt = await buildEventForTeamEventType({
|
||||
existingEvent: evt,
|
||||
schedulingType: eventType.schedulingType,
|
||||
users,
|
||||
team: eventType.team,
|
||||
organizerUser,
|
||||
});
|
||||
|
||||
if (!teamEvt) {
|
||||
throw new HttpError({ statusCode: 400, message: "Failed to build team event" });
|
||||
}
|
||||
|
||||
evt = teamEvt;
|
||||
}
|
||||
|
||||
// data needed for triggering webhooks
|
||||
@@ -1357,13 +1399,22 @@ async function handler(
|
||||
// Rescheduling logic for the original seated event was handled in handleSeats
|
||||
// We want to use new booking logic for the new time slot
|
||||
originalRescheduledBooking = null;
|
||||
evt = CalendarEventBuilder.fromEvent(evt)
|
||||
.withIdentifiers({
|
||||
const updatedEvt = CalendarEventBuilder.fromEvent(evt)
|
||||
?.withIdentifiers({
|
||||
iCalUID: getICalUID({
|
||||
attendeeId: bookingSeat?.attendeeId,
|
||||
}),
|
||||
})
|
||||
.build();
|
||||
|
||||
if (!updatedEvt) {
|
||||
throw new HttpError({
|
||||
statusCode: 400,
|
||||
message: "Failed to build event with new identifiers due to missing required fields",
|
||||
});
|
||||
}
|
||||
|
||||
evt = updatedEvt;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1484,14 +1535,32 @@ async function handler(
|
||||
}
|
||||
}
|
||||
|
||||
evt = CalendarEventBuilder.fromEvent(evt)
|
||||
.withUid(booking.uid ?? null)
|
||||
const updatedEvtWithUid = CalendarEventBuilder.fromEvent(evt)
|
||||
?.withUid(booking.uid ?? null)
|
||||
.build();
|
||||
|
||||
evt = CalendarEventBuilder.fromEvent(evt)
|
||||
.withOneTimePassword(booking.oneTimePassword ?? null)
|
||||
if (!updatedEvtWithUid) {
|
||||
throw new HttpError({
|
||||
statusCode: 400,
|
||||
message: "Failed to build event with UID due to missing required fields",
|
||||
});
|
||||
}
|
||||
|
||||
evt = updatedEvtWithUid;
|
||||
|
||||
const updatedEvtWithPassword = CalendarEventBuilder.fromEvent(evt)
|
||||
?.withOneTimePassword(booking.oneTimePassword ?? null)
|
||||
.build();
|
||||
|
||||
if (!updatedEvtWithPassword) {
|
||||
throw new HttpError({
|
||||
statusCode: 400,
|
||||
message: "Failed to build event with one-time password due to missing required fields",
|
||||
});
|
||||
}
|
||||
|
||||
evt = updatedEvtWithPassword;
|
||||
|
||||
if (booking && booking.id && eventType.seatsPerTimeSlot) {
|
||||
const currentAttendee = booking.attendees.find(
|
||||
(attendee) =>
|
||||
|
||||
Reference in New Issue
Block a user