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 <morgan@cal.com> Co-authored-by: Morgan <33722304+ThyMinimalDev@users.noreply.github.com>
This commit is contained in:
co-authored by
Morgan Vernay
Morgan
parent
34ba27407b
commit
c834b927b6
@@ -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}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -304,6 +304,7 @@ const AppearanceView = ({
|
||||
description={t("bookerlayout_user_settings_description")}
|
||||
isDisabled={isBookerLayoutFormSubmitting || !isBookerLayoutFormDirty}
|
||||
isLoading={mutation.isPending}
|
||||
user={user}
|
||||
/>
|
||||
</Form>
|
||||
|
||||
|
||||
@@ -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 (
|
||||
<div
|
||||
className="relative table w-full table-fixed"
|
||||
@@ -136,8 +136,8 @@ const DestinationCalendarSelector = ({
|
||||
) : (
|
||||
<span className="text-default min-w-0 overflow-hidden truncate whitespace-nowrap">
|
||||
<Badge variant="blue">Default</Badge>{" "}
|
||||
{queryDestinationCalendar.name &&
|
||||
`${queryDestinationCalendar.name} (${queryDestinationCalendar?.integrationTitle} - ${queryDestinationCalendar.primaryEmail})`}
|
||||
{destinationCalendar?.name &&
|
||||
`${destinationCalendar.name} (${destinationCalendar?.integrationTitle} - ${destinationCalendar.primaryEmail})`}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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<typeof fieldSchema>;
|
||||
|
||||
const CustomEventTypeModal = dynamic(() => import("./CustomEventTypeModal"));
|
||||
|
||||
export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupProps, "eventType" | "team">) => {
|
||||
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<FormValues>();
|
||||
const { t } = useLocale();
|
||||
const [showEventNameTip, setShowEventNameTip] = useState(false);
|
||||
@@ -154,7 +170,7 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupProps,
|
||||
);
|
||||
|
||||
const displayDestinationCalendarSelector =
|
||||
!!connectedCalendarsQuery.data?.connectedCalendars.length && (!team || isChildrenManagedEventType);
|
||||
!!calendarsQueryData?.connectedCalendars?.length && (!team || isChildrenManagedEventType);
|
||||
|
||||
const verifiedSecondaryEmails = [
|
||||
{
|
||||
@@ -186,6 +202,7 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupProps,
|
||||
onChange={onChange}
|
||||
hidePlaceholder
|
||||
hideAdvancedText
|
||||
calendarsQueryData={calendarsQueryData}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
@@ -261,7 +278,13 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupProps,
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<BookerLayoutSelector fallbackToUserSettings isDark={selectedThemeIsDark} isOuterBorder={true} />
|
||||
<BookerLayoutSelector
|
||||
fallbackToUserSettings
|
||||
isDark={selectedThemeIsDark}
|
||||
isOuterBorder={true}
|
||||
user={user}
|
||||
isUserLoading={isUserLoading}
|
||||
/>
|
||||
<div className="border-subtle space-y-6 rounded-lg border p-6">
|
||||
<FormBuilder
|
||||
title={t("booking_questions_title")}
|
||||
|
||||
@@ -8,7 +8,7 @@ import { classNames } from "@calcom/lib";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { BookerLayouts, defaultBookerLayoutSettings } from "@calcom/prisma/zod-utils";
|
||||
import { bookerLayoutOptions, type BookerLayoutSettings } from "@calcom/prisma/zod-utils";
|
||||
import useMeQuery from "@calcom/trpc/react/hooks/useMeQuery";
|
||||
import type { RouterOutputs } from "@calcom/trpc/react";
|
||||
import { Label, CheckboxField, Button } from "@calcom/ui";
|
||||
|
||||
import SectionBottomActions from "./SectionBottomActions";
|
||||
@@ -34,6 +34,8 @@ type BookerLayoutSelectorProps = {
|
||||
isLoading?: boolean;
|
||||
isDisabled?: boolean;
|
||||
isOuterBorder?: boolean;
|
||||
user?: RouterOutputs["viewer"]["me"];
|
||||
isUserLoading?: boolean;
|
||||
};
|
||||
|
||||
const defaultFieldName = "metadata.bookerLayouts";
|
||||
@@ -47,6 +49,8 @@ export const BookerLayoutSelector = ({
|
||||
isDisabled = false,
|
||||
isOuterBorder = false,
|
||||
isLoading = false,
|
||||
user,
|
||||
isUserLoading,
|
||||
}: BookerLayoutSelectorProps) => {
|
||||
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 && (
|
||||
<SectionBottomActions align="end">
|
||||
@@ -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;
|
||||
|
||||
@@ -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<EventTypeSetupProps, "eventType" | "team"> & {
|
||||
loggedInUser?: RouterOutputs["viewer"]["me"];
|
||||
isLoggedInUserPending?: boolean;
|
||||
};
|
||||
|
||||
const EventAdvancedWebWrapper = ({
|
||||
loggedInUser,
|
||||
isLoggedInUserPending,
|
||||
...props
|
||||
}: EventAdvancedWebWrapperProps) => {
|
||||
const connectedCalendarsQuery = trpc.viewer.connectedCalendars.useQuery();
|
||||
return (
|
||||
<EventAdvancedTab
|
||||
{...props}
|
||||
calendarsQueryData={connectedCalendarsQuery.data}
|
||||
user={loggedInUser}
|
||||
isUserLoading={isLoggedInUserPending}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default EventAdvancedWebWrapper;
|
||||
@@ -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: <EventTeamAssignmentTab teamMembers={teamMembers} team={team} eventType={eventType} />,
|
||||
limits: <EventLimitsTab eventType={eventType} />,
|
||||
advanced: <EventAdvancedTab eventType={eventType} team={team} />,
|
||||
advanced: (
|
||||
<EventAdvancedTab
|
||||
eventType={eventType}
|
||||
team={team}
|
||||
loggedInUser={loggedInUser}
|
||||
isLoggedInUserPending={isLoggedInUserPending}
|
||||
/>
|
||||
),
|
||||
instant: <EventInstantTab eventType={eventType} isTeamEvent={!!team} />,
|
||||
recurring: <EventRecurringTab eventType={eventType} />,
|
||||
apps: <EventAppsTab eventType={{ ...eventType, URL: permalink }} />,
|
||||
|
||||
Reference in New Issue
Block a user