diff --git a/packages/features/bookings/Booker/Booker.tsx b/packages/features/bookings/Booker/Booker.tsx index 1155156f5f..008143c65f 100644 --- a/packages/features/bookings/Booker/Booker.tsx +++ b/packages/features/bookings/Booker/Booker.tsx @@ -291,7 +291,9 @@ const BookerComponent = ({ (layout === BookerLayouts.COLUMN_VIEW || layout === BookerLayouts.WEEK_VIEW) && "bg-default dark:bg-muted sticky top-0 z-10" )}> - {!isPlatform ? ( + {isPlatform && layout === BookerLayouts.MONTH_VIEW ? ( + <> + ) : (
- ) : ( - <> )} )} diff --git a/packages/features/bookings/Booker/components/Header.tsx b/packages/features/bookings/Booker/components/Header.tsx index 1c13399ed8..bf03708908 100644 --- a/packages/features/bookings/Booker/components/Header.tsx +++ b/packages/features/bookings/Booker/components/Header.tsx @@ -1,6 +1,7 @@ import { useCallback, useMemo } from "react"; import { shallow } from "zustand/shallow"; +import { useIsPlatform } from "@calcom/atoms/monorepo"; import dayjs from "@calcom/dayjs"; import { useIsEmbed } from "@calcom/embed-core/embed-iframe"; import { WEBAPP_URL } from "@calcom/lib/constants"; @@ -170,6 +171,7 @@ const LayoutToggle = ({ enabledLayouts?: BookerLayouts[]; }) => { const isEmbed = useIsEmbed(); + const isPlatform = useIsPlatform(); const { t } = useLocale(); @@ -199,6 +201,10 @@ const LayoutToggle = ({ return null; } + // just like embed the layout toggle doesn't look rightly placed in platform + // the layout can be toggled via props in the booker atom + if (isPlatform) return null; + return ; }; diff --git a/packages/features/bookings/Booker/components/OverlayCalendar/OverlayCalendar.tsx b/packages/features/bookings/Booker/components/OverlayCalendar/OverlayCalendar.tsx index ac7ab7b632..fa460e6f23 100644 --- a/packages/features/bookings/Booker/components/OverlayCalendar/OverlayCalendar.tsx +++ b/packages/features/bookings/Booker/components/OverlayCalendar/OverlayCalendar.tsx @@ -1,3 +1,5 @@ +import { useIsPlatform } from "@calcom/atoms/monorepo"; + import type { UseCalendarsReturnType } from "../hooks/useCalendars"; import { useOverlayCalendar } from "../hooks/useOverlayCalendar"; import { OverlayCalendarContinueModal } from "./OverlayCalendarContinueModal"; @@ -29,6 +31,7 @@ export const OverlayCalendar = ({ handleClickContinue, hasSession, }: OverlayCalendarProps) => { + const isPlatform = useIsPlatform(); const { handleCloseContinueModal, handleCloseSettingsModal, @@ -37,6 +40,12 @@ export const OverlayCalendar = ({ handleToggleConnectedCalendar, checkIsCalendarToggled, } = useOverlayCalendar({ connectedCalendars, overlayBusyDates, onToggleCalendar }); + + // on platform we don't handle connecting to third party calendar via booker yet + if (isPlatform && connectedCalendars?.length === 0) { + return <>; + } + return ( <> - + {!isPlatform && ( + + )} @@ -93,8 +95,12 @@ export function OverlayCalendarSettingsModal({ "h-10 w-10", item.integration.logo.includes("-dark") && "dark:invert" )} - src={item.integration.logo} - alt={item.integration.title} + src={ + isPlatform + ? `https://app.cal.com${item.integration.logo}` + : item.integration.logo + } + alt={`${item.integration.title} logo`} /> ) } diff --git a/packages/features/bookings/Booker/components/hooks/useCalendars.ts b/packages/features/bookings/Booker/components/hooks/useCalendars.ts index 371a84bea9..ea11e498fc 100644 --- a/packages/features/bookings/Booker/components/hooks/useCalendars.ts +++ b/packages/features/bookings/Booker/components/hooks/useCalendars.ts @@ -14,6 +14,11 @@ export type UseCalendarsReturnType = ReturnType; type UseCalendarsProps = { hasSession: boolean; }; +export type ToggledConnectedCalendars = Set<{ + credentialId: number; + externalId: string; +}>; + export const useCalendars = ({ hasSession }: UseCalendarsProps) => { const searchParams = useSearchParams(); const selectedDate = useBookerStore((state) => state.selectedDate); @@ -64,7 +69,7 @@ export const useCalendars = ({ hasSession }: UseCalendarsProps) => { isOverlayCalendarEnabled: switchEnabled, connectedCalendars: data?.connectedCalendars || [], loadingConnectedCalendar: isPending, - onToggleCalendar: () => { + onToggleCalendar: (data: ToggledConnectedCalendars) => { utils.viewer.availability.calendarOverlay.reset(); }, }; diff --git a/packages/features/bookings/Booker/components/hooks/useLocalSet.tsx b/packages/features/bookings/Booker/components/hooks/useLocalSet.tsx index 2c19aa1599..67a8609c8c 100644 --- a/packages/features/bookings/Booker/components/hooks/useLocalSet.tsx +++ b/packages/features/bookings/Booker/components/hooks/useLocalSet.tsx @@ -32,9 +32,10 @@ export function useLocalSet(key: string, initialValue: }); }; - const toggleValue = (value: T) => { + const toggleValue = (value: T): Set => { + let newSet = new Set(); setSet((prevSet) => { - const updatedSet = new Set(prevSet); + const updatedSet = new Set(prevSet); let itemFound = false; updatedSet.forEach((item) => { @@ -48,8 +49,12 @@ export function useLocalSet(key: string, initialValue: updatedSet.add(value); } + newSet = updatedSet; + return updatedSet; }); + + return newSet; }; const hasItem = (value: T) => { diff --git a/packages/features/bookings/Booker/components/hooks/useOverlayCalendar.ts b/packages/features/bookings/Booker/components/hooks/useOverlayCalendar.ts index 20043691d6..92e482fe9d 100644 --- a/packages/features/bookings/Booker/components/hooks/useOverlayCalendar.ts +++ b/packages/features/bookings/Booker/components/hooks/useOverlayCalendar.ts @@ -66,12 +66,12 @@ export const useOverlayCalendar = ({ }, [hasItem, set, initalised]); const handleToggleConnectedCalendar = (externalCalendarId: string, credentialId: number) => { - toggleValue({ + const calendarsToLoad = toggleValue({ credentialId: credentialId, externalId: externalCalendarId, }); setOverlayBusyDates([]); - onToggleCalendar(); + onToggleCalendar(calendarsToLoad); }; return { diff --git a/packages/platform/atoms/booker/BookerPlatformWrapper.tsx b/packages/platform/atoms/booker/BookerPlatformWrapper.tsx index 361b504c92..6b543b208a 100644 --- a/packages/platform/atoms/booker/BookerPlatformWrapper.tsx +++ b/packages/platform/atoms/booker/BookerPlatformWrapper.tsx @@ -1,11 +1,10 @@ import { useQueryClient } from "@tanstack/react-query"; -import { useMemo, useEffect } from "react"; +import { useMemo, useEffect, useCallback, useState } from "react"; import { shallow } from "zustand/shallow"; import dayjs from "@calcom/dayjs"; import type { BookerProps } from "@calcom/features/bookings/Booker"; import { Booker as BookerComponent } from "@calcom/features/bookings/Booker"; -import { useOverlayCalendarStore } from "@calcom/features/bookings/Booker/components/OverlayCalendar/store"; import { useBookerLayout } from "@calcom/features/bookings/Booker/components/hooks/useBookerLayout"; import { useBookingForm } from "@calcom/features/bookings/Booker/components/hooks/useBookingForm"; import { useLocalSet } from "@calcom/features/bookings/Booker/components/hooks/useLocalSet"; @@ -75,8 +74,11 @@ export type BookerPlatformWrapperAtomProps = Omit< onDeleteSlotSuccess?: (data: ApiSuccessResponseWithoutData) => void; onDeleteSlotError?: (data: ApiErrorResponse) => void; locationUrl?: string; + view?: VIEW_TYPE; }; +type VIEW_TYPE = keyof typeof BookerLayouts; + type BookerPlatformWrapperAtomPropsForIndividual = BookerPlatformWrapperAtomProps & { username: string | string[]; isTeamEvent?: false; @@ -91,6 +93,9 @@ type BookerPlatformWrapperAtomPropsForTeam = BookerPlatformWrapperAtomProps & { export const BookerPlatformWrapper = ( props: BookerPlatformWrapperAtomPropsForIndividual | BookerPlatformWrapperAtomPropsForTeam ) => { + const { view = "MONTH_VIEW" } = props; + const layout = BookerLayouts[view]; + const { clientId } = useAtomsContext(); const teamId: number | undefined = props.isTeamEvent ? props.teamId : undefined; const [bookerState, setBookerState] = useBookerStore((state) => [state.state, state.setState], shallow); @@ -101,6 +106,11 @@ export const BookerPlatformWrapper = ( const bookingData = useBookerStore((state) => state.bookingData); const setSelectedTimeslot = useBookerStore((state) => state.setSelectedTimeslot); const setSelectedMonth = useBookerStore((state) => state.setMonth); + + const [isOverlayCalendarEnabled, setIsOverlayCalendarEnabled] = useState( + Boolean(localStorage?.getItem?.("overlayCalendarSwitchDefault")) + ); + useGetBookingForReschedule({ uid: props.rescheduleUid ?? props.bookingUid ?? "", onSuccess: (data) => { @@ -175,7 +185,7 @@ export const BookerPlatformWrapper = ( eventId: event.data?.id, rescheduleUid: props.rescheduleUid ?? null, bookingUid: props.bookingUid ?? null, - layout: bookerLayout.defaultLayout, + layout: layout, org: props.entity?.orgSlug, username, bookingData, @@ -302,12 +312,9 @@ export const BookerPlatformWrapper = ( }); const slots = useSlots(event); - const [calendarSettingsOverlay] = useOverlayCalendarStore( - (state) => [state.calendarSettingsOverlayModal, state.setCalendarSettingsOverlayModal], - shallow - ); + const { data: connectedCalendars, isPending: fetchingConnectedCalendars } = useConnectedCalendars({ - enabled: !!calendarSettingsOverlay, + enabled: hasSession, }); const calendars = connectedCalendars as ConnectedDestinationCalendars; @@ -315,20 +322,21 @@ export const BookerPlatformWrapper = ( credentialId: number; externalId: string; }>("toggledConnectedCalendars", []); + const [latestCalendarsToLoad, setLatestCalendarsToLoad] = useState( + Array.from(set).map((item) => ({ + credentialId: item.credentialId, + externalId: item.externalId, + })) + ); const { data: overlayBusyDates } = useCalendarsBusyTimes({ loggedInUsersTz: session?.data?.timeZone || "Europe/London", dateFrom: selectedDate, dateTo: selectedDate, - calendarsToLoad: Array.from(set).map((item) => ({ - credentialId: item.credentialId, - externalId: item.externalId, - })), + calendarsToLoad: latestCalendarsToLoad, onError: () => { clearSet(); }, - enabled: Boolean( - hasSession && set.size > 0 && localStorage?.getItem("overlayCalendarSwitchDefault") === "true" - ), + enabled: Boolean(hasSession && isOverlayCalendarEnabled && latestCalendarsToLoad?.length > 0), }); const handleBookEvent = useHandleBookEvent({ @@ -342,6 +350,18 @@ export const BookerPlatformWrapper = ( locationUrl: props.locationUrl, }); + const onOverlaySwitchStateChange = useCallback( + (state: boolean) => { + setIsOverlayCalendarEnabled(state); + if (state) { + localStorage.setItem("overlayCalendarSwitchDefault", "true"); + } else { + localStorage.removeItem("overlayCalendarSwitchDefault"); + } + }, + [setIsOverlayCalendarEnabled] + ); + useEffect(() => { // reset booker whenever it's unmounted return () => { @@ -361,6 +381,11 @@ export const BookerPlatformWrapper = ( }); setBookingData(null); } + if (isOverlayCalendarEnabled) { + localStorage.setItem("overlayCalendarSwitchDefault", "true"); + } else { + localStorage.removeItem("overlayCalendarSwitchDefault"); + } }; // eslint-disable-next-line react-hooks/exhaustive-deps }, []); @@ -397,9 +422,7 @@ export const BookerPlatformWrapper = ( onClickOverlayContinue={function (): void { throw new Error("Function not implemented."); }} - onOverlaySwitchStateChange={function (): void { - throw new Error("Function not implemented."); - }} + onOverlaySwitchStateChange={onOverlaySwitchStateChange} extraOptions={extraOptions ?? {}} bookings={{ handleBookEvent: () => { @@ -423,10 +446,12 @@ export const BookerPlatformWrapper = ( slots={slots} calendars={{ overlayBusyDates: overlayBusyDates?.data, - isOverlayCalendarEnabled: false, + isOverlayCalendarEnabled: isOverlayCalendarEnabled, connectedCalendars: calendars?.connectedCalendars || [], loadingConnectedCalendar: fetchingConnectedCalendars, - onToggleCalendar: () => { + onToggleCalendar: (data) => { + const calendarsToLoad = Array.from(data ?? []); + setLatestCalendarsToLoad(calendarsToLoad); return; }, }} diff --git a/packages/platform/atoms/hooks/useCalendarsBusyTimes.ts b/packages/platform/atoms/hooks/useCalendarsBusyTimes.ts index 69fe8e31c5..6226d8dcae 100644 --- a/packages/platform/atoms/hooks/useCalendarsBusyTimes.ts +++ b/packages/platform/atoms/hooks/useCalendarsBusyTimes.ts @@ -14,7 +14,7 @@ export const useCalendarsBusyTimes = ({ onError, enabled, ...rest }: UseCalendar const availableSlots = useQuery({ queryKey: [ QUERY_KEY, - rest?.calendarsToLoad?.toString() ?? "", + rest?.calendarsToLoad?.length ?? 0, rest.dateFrom ?? "", rest.dateTo ?? "", rest.loggedInUsersTz, diff --git a/packages/platform/examples/base/src/pages/booking.tsx b/packages/platform/examples/base/src/pages/booking.tsx index 84c290bc22..bc81700335 100644 --- a/packages/platform/examples/base/src/pages/booking.tsx +++ b/packages/platform/examples/base/src/pages/booking.tsx @@ -89,8 +89,8 @@ export default function Bookings(props: { calUsername: string; calEmail: string {!bookingTitle && eventTypeSlug && !rescheduleUid && ( <> -

{eventTypeSlug}

{ setBookingTitle(data.data.title ?? "");