From c834b927b6b91f3963abfe5b0b26c7d0f489042e Mon Sep 17 00:00:00 2001 From: Somay Chauhan Date: Mon, 30 Sep 2024 14:45:11 +0530 Subject: [PATCH] refactor: event advanced web wrapper (#16711) * chore: EventTypeWebWrapper base pr * fixup! chore: EventTypeWebWrapper base pr * fixup! Merge branch 'main' into morgan/cal-4183-eventtypeatom-web-wrapper-base * wip * fix: error * Event type atom wrapper handles app dir * fixup! Merge branch 'main' into morgan/cal-4183-eventtypeatom-web-wrapper-base * fixup! fixup! Merge branch 'main' into morgan/cal-4183-eventtypeatom-web-wrapper-base * remove console log * review comments * fixup! review comments * refactor: event advanced web wrapper * rename `connectedCalendars` -> `calendarsQueryData` * Update BookerLayoutSelector.tsx * moved useMeQuery up the parent tree --------- Co-authored-by: Morgan Vernay Co-authored-by: Morgan <33722304+ThyMinimalDev@users.noreply.github.com> --- .../CreateEventsOnCalendarSelect.tsx | 2 + .../settings/my-account/appearance-view.tsx | 1 + .../calendars/DestinationCalendarSelector.tsx | 30 +++++++------- .../tabs/advanced/EventAdvancedTab.tsx | 41 +++++++++++++++---- .../settings/BookerLayoutSelector.tsx | 13 +++++- .../wrappers/EventAdvancedWebWrapper.tsx | 27 ++++++++++++ .../wrappers/EventTypeWebWrapper.tsx | 15 ++++--- 7 files changed, 98 insertions(+), 31 deletions(-) create mode 100644 packages/platform/atoms/event-types/wrappers/EventAdvancedWebWrapper.tsx diff --git a/apps/web/components/getting-started/components/CreateEventsOnCalendarSelect.tsx b/apps/web/components/getting-started/components/CreateEventsOnCalendarSelect.tsx index ee91119370..4a7d79b5b5 100644 --- a/apps/web/components/getting-started/components/CreateEventsOnCalendarSelect.tsx +++ b/apps/web/components/getting-started/components/CreateEventsOnCalendarSelect.tsx @@ -11,6 +11,7 @@ const CreateEventsOnCalendarSelect = (props: ICreateEventsOnCalendarSelectProps) const { calendar } = props; const { t } = useLocale(); const mutation = trpc.viewer.setDestinationCalendar.useMutation(); + const connectedCalendarsQuery = trpc.viewer.connectedCalendars.useQuery(); return ( <> @@ -26,6 +27,7 @@ const CreateEventsOnCalendarSelect = (props: ICreateEventsOnCalendarSelectProps) mutation.mutate(calendar); }} hidePlaceholder + calendarsQueryData={connectedCalendarsQuery.data} /> diff --git a/apps/web/modules/settings/my-account/appearance-view.tsx b/apps/web/modules/settings/my-account/appearance-view.tsx index fc904d000b..d118129ac7 100644 --- a/apps/web/modules/settings/my-account/appearance-view.tsx +++ b/apps/web/modules/settings/my-account/appearance-view.tsx @@ -304,6 +304,7 @@ const AppearanceView = ({ description={t("bookerlayout_user_settings_description")} isDisabled={isBookerLayoutFormSubmitting || !isBookerLayoutFormDirty} isLoading={mutation.isPending} + user={user} /> diff --git a/packages/features/calendars/DestinationCalendarSelector.tsx b/packages/features/calendars/DestinationCalendarSelector.tsx index 78ad5bd8e0..082aa4e74f 100644 --- a/packages/features/calendars/DestinationCalendarSelector.tsx +++ b/packages/features/calendars/DestinationCalendarSelector.tsx @@ -4,19 +4,18 @@ import type { OptionProps, SingleValueProps } from "react-select"; import { components } from "react-select"; import { useLocale } from "@calcom/lib/hooks/useLocale"; -import type { DestinationCalendar } from "@calcom/prisma/client"; -import { trpc } from "@calcom/trpc/react"; +import type { RouterOutputs } from "@calcom/trpc/react"; import { Badge, Icon, Select } from "@calcom/ui"; interface Props { onChange: (value: { externalId: string; integration: string }) => void; isPending?: boolean; hidePlaceholder?: boolean; - /** The external Id of the connected calendar */ - destinationCalendar?: DestinationCalendar | null; + /** The external Id of the connected calendar */ // destinationCalendar?: DestinationCalendar | null; value: string | undefined; maxWidth?: number; hideAdvancedText?: boolean; + calendarsQueryData?: RouterOutputs["viewer"]["connectedCalendars"]; } interface Option { @@ -53,9 +52,12 @@ const DestinationCalendarSelector = ({ hidePlaceholder, hideAdvancedText, maxWidth, + calendarsQueryData, }: Props): JSX.Element | null => { const { t } = useLocale(); - const query = trpc.viewer.connectedCalendars.useQuery(); + const connectedCalendarsList = calendarsQueryData?.connectedCalendars; + const destinationCalendar = calendarsQueryData?.destinationCalendar; + const [selectedOption, setSelectedOption] = useState<{ value: string; label: string; @@ -80,13 +82,13 @@ const DestinationCalendarSelector = ({ }; useEffect(() => { - const selected = query.data?.connectedCalendars - .map((connected) => connected.calendars ?? []) + const selected = connectedCalendarsList + ?.map((connected) => connected.calendars ?? []) .flat() .find((cal) => cal.externalId === value); if (selected) { - const selectedIntegration = query.data?.connectedCalendars.find((integration) => + const selectedIntegration = connectedCalendarsList?.find((integration) => integration.calendars?.some((calendar) => calendar.externalId === selected.externalId) ); @@ -98,13 +100,13 @@ const DestinationCalendarSelector = ({ })`, }); } - }, [query.data?.connectedCalendars]); + }, [connectedCalendarsList]); - if (!query.data?.connectedCalendars.length) { + if (!connectedCalendarsList?.length) { return null; } const options = - query.data.connectedCalendars.map((selectedCalendar) => ({ + connectedCalendarsList?.map((selectedCalendar) => ({ key: selectedCalendar.credentialId, label: `${selectedCalendar.integration.title?.replace(/calendar/i, "")} (${ selectedCalendar.primary?.integration === "office365_calendar" @@ -122,8 +124,6 @@ const DestinationCalendarSelector = ({ })), })) ?? []; - const queryDestinationCalendar = query.data.destinationCalendar; - return (
Default{" "} - {queryDestinationCalendar.name && - `${queryDestinationCalendar.name} (${queryDestinationCalendar?.integrationTitle} - ${queryDestinationCalendar.primaryEmail})`} + {destinationCalendar?.name && + `${destinationCalendar.name} (${destinationCalendar?.integrationTitle} - ${destinationCalendar.primaryEmail})`} ) } diff --git a/packages/features/eventtypes/components/tabs/advanced/EventAdvancedTab.tsx b/packages/features/eventtypes/components/tabs/advanced/EventAdvancedTab.tsx index dfb92e8d21..743e03943c 100644 --- a/packages/features/eventtypes/components/tabs/advanced/EventAdvancedTab.tsx +++ b/packages/features/eventtypes/components/tabs/advanced/EventAdvancedTab.tsx @@ -3,6 +3,7 @@ import { useEffect, useState } from "react"; import { Controller, useFormContext } from "react-hook-form"; import type { z } from "zod"; +import type { EventAdvancedWebWrapperProps } from "@calcom/atoms/event-types/wrappers/EventAdvancedWebWrapper"; import type { EventNameObjectType } from "@calcom/core/event"; import { getEventName } from "@calcom/core/event"; import getLocationsOptionsForSelect from "@calcom/features/bookings/lib/getLocationOptionsForSelect"; @@ -12,21 +13,26 @@ import { allowDisablingAttendeeConfirmationEmails, allowDisablingHostConfirmationEmails, } from "@calcom/features/ee/workflows/lib/allowDisablingStandardEmails"; -import type { FormValues, EventTypeSetupProps } from "@calcom/features/eventtypes/lib/types"; +import type { FormValues } from "@calcom/features/eventtypes/lib/types"; import { FormBuilder } from "@calcom/features/form-builder/FormBuilder"; import type { fieldSchema } from "@calcom/features/form-builder/schema"; import type { EditableSchema } from "@calcom/features/form-builder/schema"; import { BookerLayoutSelector } from "@calcom/features/settings/BookerLayoutSelector"; import { classNames } from "@calcom/lib"; import cx from "@calcom/lib/classNames"; -import { DEFAULT_LIGHT_BRAND_COLOR, DEFAULT_DARK_BRAND_COLOR } from "@calcom/lib/constants"; -import { APP_NAME, IS_VISUAL_REGRESSION_TESTING, WEBSITE_URL } from "@calcom/lib/constants"; +import { + DEFAULT_LIGHT_BRAND_COLOR, + DEFAULT_DARK_BRAND_COLOR, + APP_NAME, + IS_VISUAL_REGRESSION_TESTING, + WEBSITE_URL, +} from "@calcom/lib/constants"; import { generateHashedLink } from "@calcom/lib/generateHashedLink"; import { checkWCAGContrastColor } from "@calcom/lib/getBrandColours"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import type { Prisma } from "@calcom/prisma/client"; import { SchedulingType } from "@calcom/prisma/enums"; -import { trpc } from "@calcom/trpc/react"; +import type { RouterOutputs } from "@calcom/trpc/react"; import { Alert, Button, @@ -50,9 +56,19 @@ type BookingField = z.infer; const CustomEventTypeModal = dynamic(() => import("./CustomEventTypeModal")); -export const EventAdvancedTab = ({ eventType, team }: Pick) => { - const connectedCalendarsQuery = trpc.viewer.connectedCalendars.useQuery(); - const { data: user } = trpc.viewer.me.useQuery(); +export type EventAdvancedTabProps = EventAdvancedWebWrapperProps & { + calendarsQueryData?: RouterOutputs["viewer"]["connectedCalendars"]; + user?: RouterOutputs["viewer"]["me"]; + isUserLoading?: boolean; +}; + +export const EventAdvancedTab = ({ + eventType, + team, + calendarsQueryData, + user, + isUserLoading, +}: EventAdvancedTabProps) => { const formMethods = useFormContext(); const { t } = useLocale(); const [showEventNameTip, setShowEventNameTip] = useState(false); @@ -154,7 +170,7 @@ export const EventAdvancedTab = ({ eventType, team }: Pick )} /> @@ -261,7 +278,13 @@ export const EventAdvancedTab = ({ eventType, team }: Pick
- +
{ const { control, getValues } = useFormContext(); const { t } = useLocale(); @@ -77,6 +81,8 @@ export const BookerLayoutSelector = ({ onChange={onChange} isDark={isDark} isOuterBorder={isOuterBorder} + user={user} + isUserLoading={isUserLoading} /> {!isOuterBorder && ( @@ -98,6 +104,8 @@ type BookerLayoutFieldsProps = { showUserSettings: boolean; isDark?: boolean; isOuterBorder?: boolean; + user?: RouterOutputs["viewer"]["me"]; + isUserLoading?: boolean; }; type BookerLayoutState = { [key in BookerLayouts]: boolean }; @@ -108,9 +116,10 @@ const BookerLayoutFields = ({ showUserSettings, isDark, isOuterBorder, + user, + isUserLoading, }: BookerLayoutFieldsProps) => { const { t } = useLocale(); - const { isPending: isUserLoading, data: user } = useMeQuery(); const [isOverridingSettings, setIsOverridingSettings] = useState(false); const disableFields = showUserSettings && !isOverridingSettings; diff --git a/packages/platform/atoms/event-types/wrappers/EventAdvancedWebWrapper.tsx b/packages/platform/atoms/event-types/wrappers/EventAdvancedWebWrapper.tsx new file mode 100644 index 0000000000..0fa9f2da68 --- /dev/null +++ b/packages/platform/atoms/event-types/wrappers/EventAdvancedWebWrapper.tsx @@ -0,0 +1,27 @@ +import { EventAdvancedTab } from "@calcom/features/eventtypes/components/tabs/advanced/EventAdvancedTab"; +import type { EventTypeSetupProps } from "@calcom/features/eventtypes/lib/types"; +import type { RouterOutputs } from "@calcom/trpc/react"; +import { trpc } from "@calcom/trpc/react"; + +export type EventAdvancedWebWrapperProps = Pick & { + loggedInUser?: RouterOutputs["viewer"]["me"]; + isLoggedInUserPending?: boolean; +}; + +const EventAdvancedWebWrapper = ({ + loggedInUser, + isLoggedInUserPending, + ...props +}: EventAdvancedWebWrapperProps) => { + const connectedCalendarsQuery = trpc.viewer.connectedCalendars.useQuery(); + return ( + + ); +}; + +export default EventAdvancedWebWrapper; diff --git a/packages/platform/atoms/event-types/wrappers/EventTypeWebWrapper.tsx b/packages/platform/atoms/event-types/wrappers/EventTypeWebWrapper.tsx index a393df68b9..0c7a57345d 100644 --- a/packages/platform/atoms/event-types/wrappers/EventTypeWebWrapper.tsx +++ b/packages/platform/atoms/event-types/wrappers/EventTypeWebWrapper.tsx @@ -54,9 +54,7 @@ const EventLimitsTab = dynamic(() => const EventAdvancedTab = dynamic(() => // import web wrapper when it's ready - import("@calcom/features/eventtypes/components/tabs/advanced/EventAdvancedTab").then( - (mod) => mod.EventAdvancedTab - ) + import("./EventAdvancedWebWrapper").then((mod) => mod) ); const EventInstantTab = dynamic(() => @@ -143,7 +141,7 @@ const EventTypeWeb = ({ const { t } = useLocale(); const utils = trpc.useUtils(); - const { data: loggedInUser } = useMeQuery(); + const { data: loggedInUser, isPending: isLoggedInUserPending } = useMeQuery(); const isTeamEventTypeDeleted = useRef(false); const leaveWithoutAssigningHosts = useRef(false); const telemetry = useTelemetry(); @@ -229,7 +227,14 @@ const EventTypeWeb = ({ ), team: , limits: , - advanced: , + advanced: ( + + ), instant: , recurring: , apps: ,