diff --git a/apps/api/v2/src/ee/bookings/controllers/bookings.controller.ts b/apps/api/v2/src/ee/bookings/controllers/bookings.controller.ts index 2d29aef416..2733b76926 100644 --- a/apps/api/v2/src/ee/bookings/controllers/bookings.controller.ts +++ b/apps/api/v2/src/ee/bookings/controllers/bookings.controller.ts @@ -57,6 +57,7 @@ type OAuthRequestParams = { platformRescheduleUrl: string; platformCancelUrl: string; platformBookingUrl: string; + platformBookingLocation?: string; }; const DEFAULT_PLATFORM_PARAMS = { @@ -65,6 +66,7 @@ const DEFAULT_PLATFORM_PARAMS = { platformRescheduleUrl: "", platformBookingUrl: "", areEmailsEnabled: true, + platformBookingLocation: undefined, }; @Controller({ @@ -141,12 +143,15 @@ export class BookingsController { @Post("/") async createBooking( @Req() req: BookingRequest, - @Body() _: CreateBookingInput, + @Body() body: CreateBookingInput, @Headers(X_CAL_CLIENT_ID) clientId?: string ): Promise> { const oAuthClientId = clientId?.toString(); + const locationUrl = body.locationUrl; try { - const booking = await handleNewBooking(await this.createNextApiBookingRequest(req, oAuthClientId)); + const booking = await handleNewBooking( + await this.createNextApiBookingRequest(req, oAuthClientId, locationUrl) + ); return { status: SUCCESS_STATUS, data: booking, @@ -258,13 +263,14 @@ export class BookingsController { async createNextApiBookingRequest( req: BookingRequest, - oAuthClientId?: string + oAuthClientId?: string, + platformBookingLocation?: string ): Promise { const userId = (await this.getOwnerId(req)) ?? -1; const oAuthParams = oAuthClientId ? await this.getOAuthClientsParams(req, oAuthClientId) : DEFAULT_PLATFORM_PARAMS; - Object.assign(req, { userId, ...oAuthParams }); + Object.assign(req, { userId, ...oAuthParams, platformBookingLocation }); req.body = { ...req.body, areEmailsEnabled: oAuthParams.areEmailsEnabled }; return req as unknown as NextApiRequest & { userId?: number } & OAuthRequestParams; } diff --git a/apps/api/v2/src/ee/bookings/inputs/create-booking.input.ts b/apps/api/v2/src/ee/bookings/inputs/create-booking.input.ts index b36d6c3ebe..c9dc1da1b6 100644 --- a/apps/api/v2/src/ee/bookings/inputs/create-booking.input.ts +++ b/apps/api/v2/src/ee/bookings/inputs/create-booking.input.ts @@ -98,4 +98,8 @@ export class CreateBookingInput { @Type(() => Response) responses!: Response; + + @IsString() + @IsOptional() + locationUrl?: string; } diff --git a/apps/api/v2/swagger/documentation.json b/apps/api/v2/swagger/documentation.json index ede8013ed2..b822b36de2 100644 --- a/apps/api/v2/swagger/documentation.json +++ b/apps/api/v2/swagger/documentation.json @@ -4225,6 +4225,9 @@ }, "responses": { "$ref": "#/components/schemas/Response" + }, + "locationUrl": { + "type": "string" } }, "required": [ @@ -4270,4 +4273,4 @@ } } } -} +} \ No newline at end of file diff --git a/packages/features/bookings/lib/handleNewBooking.ts b/packages/features/bookings/lib/handleNewBooking.ts index 40bb99b284..21d7c929a5 100644 --- a/packages/features/bookings/lib/handleNewBooking.ts +++ b/packages/features/bookings/lib/handleNewBooking.ts @@ -909,10 +909,18 @@ async function handler( platformRescheduleUrl?: string; platformCancelUrl?: string; platformBookingUrl?: string; + platformBookingLocation?: string; }, bookingDataSchemaGetter: BookingDataSchemaGetter = getBookingDataSchema ) { - const { userId, platformClientId, platformCancelUrl, platformBookingUrl, platformRescheduleUrl } = req; + const { + userId, + platformClientId, + platformCancelUrl, + platformBookingUrl, + platformRescheduleUrl, + platformBookingLocation, + } = req; // handle dynamic user let eventType = @@ -1501,7 +1509,7 @@ async function handler( responses: reqBody.calEventResponses || null, userFieldsResponses: reqBody.calEventUserFieldsResponses || null, attendees: attendeesList, - location: bookingLocation, // Will be processed by the EventManager later. + location: platformBookingLocation ?? bookingLocation, // Will be processed by the EventManager later. conferenceCredentialId, destinationCalendar, hideCalendarNotes: eventType.hideCalendarNotes, diff --git a/packages/platform/atoms/booker/BookerPlatformWrapper.tsx b/packages/platform/atoms/booker/BookerPlatformWrapper.tsx index 625a69d301..36c6c9e9fc 100644 --- a/packages/platform/atoms/booker/BookerPlatformWrapper.tsx +++ b/packages/platform/atoms/booker/BookerPlatformWrapper.tsx @@ -51,6 +51,7 @@ type BookerPlatformWrapperAtomProps = Omit & { onReserveSlotError?: (data: ApiErrorResponse) => void; onDeleteSlotSuccess?: (data: ApiSuccessResponseWithoutData) => void; onDeleteSlotError?: (data: ApiErrorResponse) => void; + locationUrl?: string; }; export const BookerPlatformWrapper = (props: BookerPlatformWrapperAtomProps) => { @@ -227,6 +228,7 @@ export const BookerPlatformWrapper = (props: BookerPlatformWrapperAtomProps) => handleBooking: createBooking, handleInstantBooking: createInstantBooking, handleRecBooking: createRecBooking, + locationUrl: props.locationUrl, }); return ( diff --git a/packages/platform/atoms/hooks/useCreateBooking.ts b/packages/platform/atoms/hooks/useCreateBooking.ts index afca4f5406..0d51178416 100644 --- a/packages/platform/atoms/hooks/useCreateBooking.ts +++ b/packages/platform/atoms/hooks/useCreateBooking.ts @@ -7,6 +7,8 @@ import type { BookingCreateBody } from "@calcom/prisma/zod-utils"; import http from "../lib/http"; +export type UseCreateBookingInput = BookingCreateBody & { locationUrl?: string }; + interface IUseCreateBooking { onSuccess?: (res: ApiSuccessResponse) => void; onError?: (err: ApiErrorResponse | Error) => void; @@ -21,7 +23,7 @@ export const useCreateBooking = ( }, } ) => { - const createBooking = useMutation, Error, BookingCreateBody>({ + const createBooking = useMutation, Error, UseCreateBookingInput>({ mutationFn: (data) => { return http.post>("/bookings", data).then((res) => { if (res.data.status === SUCCESS_STATUS) { diff --git a/packages/platform/atoms/hooks/useHandleBookEvent.ts b/packages/platform/atoms/hooks/useHandleBookEvent.ts index 52299ddd16..3158972977 100644 --- a/packages/platform/atoms/hooks/useHandleBookEvent.ts +++ b/packages/platform/atoms/hooks/useHandleBookEvent.ts @@ -9,14 +9,17 @@ import { import { useLocale } from "@calcom/lib/hooks/useLocale"; import type { BookingCreateBody } from "@calcom/prisma/zod-utils"; +import type { UseCreateBookingInput } from "./useCreateBooking"; + type UseHandleBookingProps = { bookingForm: UseBookingFormReturnType["bookingForm"]; event: useEventReturnType; metadata: Record; hashedLink?: string | null; - handleBooking: (input: BookingCreateBody) => void; + handleBooking: (input: UseCreateBookingInput) => void; handleInstantBooking: (input: BookingCreateBody) => void; handleRecBooking: (input: BookingCreateBody[]) => void; + locationUrl?: string; }; export const useHandleBookEvent = ({ @@ -27,6 +30,7 @@ export const useHandleBookEvent = ({ handleBooking, handleInstantBooking, handleRecBooking, + locationUrl, }: UseHandleBookingProps) => { const setFormValues = useBookerStore((state) => state.setFormValues); const timeslot = useBookerStore((state) => state.selectedTimeslot); @@ -80,7 +84,7 @@ export const useHandleBookEvent = ({ } else if (event.data?.recurringEvent?.freq && recurringEventCount && !rescheduleUid) { handleRecBooking(mapRecurringBookingToMutationInput(bookingInput, recurringEventCount)); } else { - handleBooking(mapBookingToMutationInput(bookingInput)); + handleBooking({ ...mapBookingToMutationInput(bookingInput), locationUrl }); } // Clears form values stored in store, so old values won't stick around. setFormValues({}); diff --git a/packages/platform/examples/base/src/pages/[bookingUid].tsx b/packages/platform/examples/base/src/pages/[bookingUid].tsx index 09b87a55d6..72383fbecc 100644 --- a/packages/platform/examples/base/src/pages/[bookingUid].tsx +++ b/packages/platform/examples/base/src/pages/[bookingUid].tsx @@ -87,10 +87,10 @@ export default function Bookings(props: { calUsername: string; calEmail: string

- {booking.user.name}{" "} + {booking.user?.name}{" "} Host

-

{booking.user.email}

+

{booking.user?.email}

@@ -101,6 +101,16 @@ export default function Bookings(props: { calUsername: string; calEmail: string
+ {!!booking.location && booking.location.startsWith("http") && ( +
+
+

Where

+
+
+

{booking.location}

+
+
+ )} {booking.responses.notes && (
@@ -133,7 +143,7 @@ export default function Bookings(props: { calUsername: string; calEmail: string className="underline" onClick={() => { cancelBooking({ - id: parseInt(booking.id), + id: booking.id, uid: booking.uid, cancellationReason: "User request", allRemainingBookings: true, diff --git a/packages/platform/examples/base/src/pages/booking.tsx b/packages/platform/examples/base/src/pages/booking.tsx index aa6028dfc6..b6086dd4a3 100644 --- a/packages/platform/examples/base/src/pages/booking.tsx +++ b/packages/platform/examples/base/src/pages/booking.tsx @@ -26,7 +26,7 @@ export default function Bookings(props: { calUsername: string; calEmail: string {!isLoadingEvents && !eventTypeSlug && Boolean(eventTypes?.length) && !rescheduleUid && (
- {eventTypes?.map((event: { id: number; slug: string; title: string }) => { + {eventTypes?.map((event: { id: number; slug: string; title: string; length: number }) => { const formatEventSlug = event.slug .split("-") .map((item) => `${item[0].toLocaleUpperCase()}${item.slice(1)}`)