From ad347cb59f8d8aa9906a94e155544f495667262b Mon Sep 17 00:00:00 2001 From: Morgan <33722304+ThyMinimalDev@users.noreply.github.com> Date: Mon, 30 Sep 2024 13:44:11 +0300 Subject: [PATCH] feat: Event Type Atom base pr (#16831) * feat: Event Type Atom base pr * fixup! Merge branch 'main' into chore-event-type-atom-platform-wrapper-base-pr * Update EventTypeWebWrapper.tsx --------- Co-authored-by: Somay Chauhan --- apps/api/v2/package.json | 2 +- .../event-types.repository.ts | 18 -- .../services/event-types.service.ts | 21 -- apps/api/v2/src/modules/atoms/atoms.module.ts | 23 ++ .../atoms/controllers/atoms.controller.ts | 67 +++++ .../services/event-types-atom.service.ts | 80 ++++++ apps/api/v2/src/modules/endpoints.module.ts | 2 + apps/web/package.json | 2 +- .../eventtypes/components/EventType.tsx | 70 ++--- .../eventtypes/components/EventTypeLayout.tsx | 264 ++++-------------- .../eventtypes/components/Locations.tsx | 5 +- .../components/dialogs/DeleteDialog.tsx | 33 +-- .../components/tabs/setup/EventSetupTab.tsx | 13 +- .../form/components/LocationSelect.tsx | 58 +++- .../event-types/hooks/useAtomEventTypeById.ts | 27 ++ .../hooks/useAtomUpdateEventType.ts | 42 +++ .../hooks/usePlatformTabsNavigations.tsx | 168 +++++++++++ .../event-types/hooks/useTabsNavigations.tsx | 220 +++++++++++++++ .../wrappers/EventSetupTabPlatformWrapper.tsx | 10 + .../wrappers/EventSetupTabWebWrapper.tsx | 8 +- .../wrappers/EventTypePlatformWrapper.tsx | 167 +++++++++++ .../wrappers/EventTypeWebWrapper.tsx | 94 ++++++- packages/platform/atoms/index.ts | 1 + packages/platform/atoms/monorepo.ts | 1 + packages/platform/atoms/vite.config.ts | 3 + .../base/src/components/Navbar/index.tsx | 3 + .../examples/base/src/pages/event-types.tsx | 94 +++++++ packages/platform/libraries/index.ts | 2 +- .../navigation/tabs/VerticalTabItem.tsx | 7 + 29 files changed, 1148 insertions(+), 357 deletions(-) create mode 100644 apps/api/v2/src/modules/atoms/atoms.module.ts create mode 100644 apps/api/v2/src/modules/atoms/controllers/atoms.controller.ts create mode 100644 apps/api/v2/src/modules/atoms/services/event-types-atom.service.ts create mode 100644 packages/platform/atoms/event-types/hooks/useAtomEventTypeById.ts create mode 100644 packages/platform/atoms/event-types/hooks/useAtomUpdateEventType.ts create mode 100644 packages/platform/atoms/event-types/hooks/usePlatformTabsNavigations.tsx create mode 100644 packages/platform/atoms/event-types/hooks/useTabsNavigations.tsx create mode 100644 packages/platform/atoms/event-types/wrappers/EventSetupTabPlatformWrapper.tsx create mode 100644 packages/platform/atoms/event-types/wrappers/EventTypePlatformWrapper.tsx create mode 100644 packages/platform/examples/base/src/pages/event-types.tsx diff --git a/apps/api/v2/package.json b/apps/api/v2/package.json index 6fba137189..abf6885712 100644 --- a/apps/api/v2/package.json +++ b/apps/api/v2/package.json @@ -28,7 +28,7 @@ "dependencies": { "@calcom/platform-constants": "*", "@calcom/platform-enums": "*", - "@calcom/platform-libraries": "npm:@calcom/platform-libraries@0.0.43", + "@calcom/platform-libraries": "npm:@calcom/platform-libraries@0.0.44", "@calcom/platform-libraries-0.0.2": "npm:@calcom/platform-libraries@0.0.2", "@calcom/platform-types": "*", "@calcom/platform-utils": "*", diff --git a/apps/api/v2/src/ee/event-types/event-types_2024_06_14/event-types.repository.ts b/apps/api/v2/src/ee/event-types/event-types_2024_06_14/event-types.repository.ts index f789049ff4..a4df49c30a 100644 --- a/apps/api/v2/src/ee/event-types/event-types_2024_06_14/event-types.repository.ts +++ b/apps/api/v2/src/ee/event-types/event-types_2024_06_14/event-types.repository.ts @@ -1,12 +1,9 @@ import { PrismaReadService } from "@/modules/prisma/prisma-read.service"; import { PrismaWriteService } from "@/modules/prisma/prisma-write.service"; import { UsersService } from "@/modules/users/services/users.service"; -import { UserWithProfile } from "@/modules/users/users.repository"; import { Injectable } from "@nestjs/common"; -import { getEventTypeById } from "@calcom/platform-libraries"; import { InputEventTransformed_2024_06_14 } from "@calcom/platform-types"; -import type { PrismaClient } from "@calcom/prisma"; @Injectable() export class EventTypesRepository_2024_06_14 { @@ -69,21 +66,6 @@ export class EventTypesRepository_2024_06_14 { }); } - async getUserEventTypeForAtom( - user: UserWithProfile, - isUserOrganizationAdmin: boolean, - eventTypeId: number - ) { - return await getEventTypeById({ - currentOrganizationId: this.usersService.getUserMainOrgId(user), - eventTypeId, - userId: user.id, - prisma: this.dbRead.prisma as unknown as PrismaClient, - isUserOrganizationAdmin, - isTrpcCall: true, - }); - } - async getEventTypeById(eventTypeId: number) { return this.dbRead.prisma.eventType.findUnique({ where: { id: eventTypeId }, diff --git a/apps/api/v2/src/ee/event-types/event-types_2024_06_14/services/event-types.service.ts b/apps/api/v2/src/ee/event-types/event-types_2024_06_14/services/event-types.service.ts index 7ffb3cf8b5..eabbd49c6f 100644 --- a/apps/api/v2/src/ee/event-types/event-types_2024_06_14/services/event-types.service.ts +++ b/apps/api/v2/src/ee/event-types/event-types_2024_06_14/services/event-types.service.ts @@ -142,27 +142,6 @@ export class EventTypesService_2024_06_14 { }); } - async getUserEventTypeForAtom(user: UserWithProfile, eventTypeId: number) { - const organizationId = this.usersService.getUserMainOrgId(user); - - const isUserOrganizationAdmin = organizationId - ? await this.membershipsRepository.isUserOrganizationAdmin(user.id, organizationId) - : false; - - const eventType = await this.eventTypesRepository.getUserEventTypeForAtom( - user, - isUserOrganizationAdmin, - eventTypeId - ); - - if (!eventType) { - return null; - } - - this.checkUserOwnsEventType(user.id, eventType.eventType); - return eventType; - } - async getEventTypesPublicByUsername(username: string): Promise { const user = await this.usersRepository.findByUsername(username); if (!user) { diff --git a/apps/api/v2/src/modules/atoms/atoms.module.ts b/apps/api/v2/src/modules/atoms/atoms.module.ts new file mode 100644 index 0000000000..ef8c41baa8 --- /dev/null +++ b/apps/api/v2/src/modules/atoms/atoms.module.ts @@ -0,0 +1,23 @@ +import { EventTypesModule_2024_06_14 } from "@/ee/event-types/event-types_2024_06_14/event-types.module"; +import { SchedulesRepository_2024_06_11 } from "@/ee/schedules/schedules_2024_06_11/schedules.repository"; +import { AtomsController } from "@/modules/atoms/controllers/atoms.controller"; +import { EventTypesAtomService } from "@/modules/atoms/services/event-types-atom.service"; +import { MembershipsRepository } from "@/modules/memberships/memberships.repository"; +import { PrismaModule } from "@/modules/prisma/prisma.module"; +import { UsersService } from "@/modules/users/services/users.service"; +import { UsersRepository } from "@/modules/users/users.repository"; +import { Module } from "@nestjs/common"; + +@Module({ + imports: [PrismaModule, EventTypesModule_2024_06_14], + providers: [ + EventTypesAtomService, + MembershipsRepository, + UsersRepository, + UsersService, + SchedulesRepository_2024_06_11, + ], + exports: [EventTypesAtomService], + controllers: [AtomsController], +}) +export class AtomsModule {} diff --git a/apps/api/v2/src/modules/atoms/controllers/atoms.controller.ts b/apps/api/v2/src/modules/atoms/controllers/atoms.controller.ts new file mode 100644 index 0000000000..55f49fc2ee --- /dev/null +++ b/apps/api/v2/src/modules/atoms/controllers/atoms.controller.ts @@ -0,0 +1,67 @@ +import { API_VERSIONS_VALUES } from "@/lib/api-versions"; +import { EventTypesAtomService } from "@/modules/atoms/services/event-types-atom.service"; +import { GetUser } from "@/modules/auth/decorators/get-user/get-user.decorator"; +import { ApiAuthGuard } from "@/modules/auth/guards/api-auth/api-auth.guard"; +import { UserWithProfile } from "@/modules/users/users.repository"; +import { + Controller, + Get, + Param, + ParseIntPipe, + UseGuards, + Version, + VERSION_NEUTRAL, + Patch, + Body, +} from "@nestjs/common"; +import { ApiTags as DocsTags, ApiExcludeController as DocsExcludeController } from "@nestjs/swagger"; + +import { SUCCESS_STATUS } from "@calcom/platform-constants"; +import type { UpdateEventTypeReturn } from "@calcom/platform-libraries"; +import { ApiResponse } from "@calcom/platform-types"; + +/* + +Endpoints used only by platform atoms, reusing code from other modules, data is already formatted and ready to be used by frontend atoms +these endpoints should not be recommended for use by third party and are excluded from docs + +*/ + +@Controller({ + path: "/v2/atoms", + version: API_VERSIONS_VALUES, +}) +@DocsTags("Atoms - endpoints for atoms") +@DocsExcludeController(true) +export class AtomsController { + constructor(private readonly eventTypesService: EventTypesAtomService) {} + + @Get("event-types/:eventTypeId") + @Version(VERSION_NEUTRAL) + @UseGuards(ApiAuthGuard) + async getAtomEventType( + @GetUser() user: UserWithProfile, + @Param("eventTypeId", ParseIntPipe) eventTypeId: number + ): Promise> { + const eventType = await this.eventTypesService.getUserEventType(user, eventTypeId); + return { + status: SUCCESS_STATUS, + data: eventType, + }; + } + + @Patch("event-types/:eventTypeId") + @Version(VERSION_NEUTRAL) + @UseGuards(ApiAuthGuard) + async updateAtomEventType( + @GetUser() user: UserWithProfile, + @Param("eventTypeId", ParseIntPipe) eventTypeId: number, + @Body() body: UpdateEventTypeReturn + ): Promise> { + const eventType = await this.eventTypesService.updateEventType(eventTypeId, body, user); + return { + status: SUCCESS_STATUS, + data: eventType, + }; + } +} diff --git a/apps/api/v2/src/modules/atoms/services/event-types-atom.service.ts b/apps/api/v2/src/modules/atoms/services/event-types-atom.service.ts new file mode 100644 index 0000000000..1abd9657d3 --- /dev/null +++ b/apps/api/v2/src/modules/atoms/services/event-types-atom.service.ts @@ -0,0 +1,80 @@ +import { EventTypesService_2024_06_14 } from "@/ee/event-types/event-types_2024_06_14/services/event-types.service"; +import { MembershipsRepository } from "@/modules/memberships/memberships.repository"; +import { PrismaReadService } from "@/modules/prisma/prisma-read.service"; +import { PrismaWriteService } from "@/modules/prisma/prisma-write.service"; +import { UsersService } from "@/modules/users/services/users.service"; +import { UserWithProfile } from "@/modules/users/users.repository"; +import { Injectable, NotFoundException } from "@nestjs/common"; + +import { + updateEventType, + TUpdateEventTypeInputSchema, + systemBeforeFieldEmail, + getEventTypeById, +} from "@calcom/platform-libraries"; +import { PrismaClient } from "@calcom/prisma/client"; + +@Injectable() +export class EventTypesAtomService { + constructor( + private readonly membershipsRepository: MembershipsRepository, + private readonly usersService: UsersService, + private readonly dbWrite: PrismaWriteService, + private readonly dbRead: PrismaReadService, + private readonly eventTypeService: EventTypesService_2024_06_14 + ) {} + + async getUserEventType(user: UserWithProfile, eventTypeId: number) { + this.eventTypeService.checkUserOwnsEventType(user.id, { id: eventTypeId, userId: user.id }); + const organizationId = this.usersService.getUserMainOrgId(user); + + const isUserOrganizationAdmin = organizationId + ? await this.membershipsRepository.isUserOrganizationAdmin(user.id, organizationId) + : false; + + const eventType = await getEventTypeById({ + currentOrganizationId: this.usersService.getUserMainOrgId(user), + eventTypeId, + userId: user.id, + prisma: this.dbRead.prisma as unknown as PrismaClient, + isUserOrganizationAdmin, + isTrpcCall: true, + }); + + if (!eventType) { + throw new NotFoundException(`Event type with id ${eventTypeId} not found`); + } + + this.eventTypeService.checkUserOwnsEventType(user.id, eventType.eventType); + return eventType; + } + + async updateEventType(eventTypeId: number, body: TUpdateEventTypeInputSchema, user: UserWithProfile) { + this.eventTypeService.checkCanUpdateEventType(user.id, eventTypeId, body.scheduleId); + const eventTypeUser = await this.eventTypeService.getUserToUpdateEvent(user); + const bookingFields = [...(body.bookingFields || [])]; + + if ( + !bookingFields.find((field) => field.type === "email") && + !bookingFields.find((field) => field.type === "phone") + ) { + bookingFields.push(systemBeforeFieldEmail); + } + + const eventType = await updateEventType({ + input: { id: eventTypeId, ...body, bookingFields }, + ctx: { + user: eventTypeUser, + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + prisma: this.dbWrite.prisma, + }, + }); + + if (!eventType) { + throw new NotFoundException(`Event type with id ${eventTypeId} not found`); + } + + return eventType.eventType; + } +} diff --git a/apps/api/v2/src/modules/endpoints.module.ts b/apps/api/v2/src/modules/endpoints.module.ts index 5fe14276e1..eb6ed4876a 100644 --- a/apps/api/v2/src/modules/endpoints.module.ts +++ b/apps/api/v2/src/modules/endpoints.module.ts @@ -1,4 +1,5 @@ import { PlatformEndpointsModule } from "@/ee/platform-endpoints-module"; +import { AtomsModule } from "@/modules/atoms/atoms.module"; import { BillingModule } from "@/modules/billing/billing.module"; import { DestinationCalendarsModule } from "@/modules/destination-calendars/destination-calendars.module"; import { OAuthClientModule } from "@/modules/oauth-clients/oauth-client.module"; @@ -18,6 +19,7 @@ import { WebhooksModule } from "./webhooks/webhooks.module"; UsersModule, WebhooksModule, DestinationCalendarsModule, + AtomsModule, ], }) export class EndpointsModule implements NestModule { diff --git a/apps/web/package.json b/apps/web/package.json index 04abc4f070..2d76eff2b6 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -136,7 +136,7 @@ "stripe": "^9.16.0", "superjson": "1.9.1", "tailwindcss-radix": "^2.6.0", - "turndown": "^7.1.1", + "turndown": "^7.1.3", "uuid": "^8.3.2", "zod": "^3.22.4" }, diff --git a/packages/features/eventtypes/components/EventType.tsx b/packages/features/eventtypes/components/EventType.tsx index 67ca181912..51ab4f54f4 100644 --- a/packages/features/eventtypes/components/EventType.tsx +++ b/packages/features/eventtypes/components/EventType.tsx @@ -3,8 +3,6 @@ /* eslint-disable @typescript-eslint/no-empty-function */ import { useAutoAnimate } from "@formkit/auto-animate/react"; import type { UseFormReturn } from "react-hook-form"; -// eslint-disable-next-line @calcom/eslint/deprecated-imports-next-router -import { z } from "zod"; import type { Workflow } from "@calcom/features/ee/workflows/lib/types"; import type { ChildrenEventType } from "@calcom/features/eventtypes/components/ChildrenEventTypeSelect"; @@ -14,9 +12,9 @@ import type { FormValues, EventTypeApps, } from "@calcom/features/eventtypes/lib/types"; -import { useTypedQuery } from "@calcom/lib/hooks/useTypedQuery"; import type { customInputSchema } from "@calcom/prisma/zod-utils"; import type { RouterOutputs } from "@calcom/trpc/react"; +import type { VerticalTabItemProps } from "@calcom/ui"; import { Form } from "@calcom/ui"; import { EventTypeSingleLayout } from "./EventTypeLayout"; @@ -31,24 +29,19 @@ export type Host = { export type CustomInputParsed = typeof customInputSchema._output; -const querySchema = z.object({ - tabName: z - .enum([ - "setup", - "availability", - "apps", - "limits", - "instant", - "recurring", - "team", - "advanced", - "workflows", - "webhooks", - "ai", - ]) - .optional() - .default("setup"), -}); +const tabs = [ + "setup", + "availability", + "team", + "limits", + "advanced", + "instant", + "recurring", + "apps", + "workflows", + "webhooks", + "ai", +] as const; export type EventTypeSetup = RouterOutputs["viewer"]["eventTypes"]["get"]["eventType"]; export type EventTypeAssignedUsers = RouterOutputs["viewer"]["eventTypes"]["get"]["eventType"]["children"]; @@ -58,47 +51,29 @@ export const EventType = ( props: EventTypeSetupProps & { allActiveWorkflows?: Workflow[]; tabMap: TabMap; - onDelete: () => void; + onDelete: (id: number) => void; + isDeleting?: boolean; onConflict: (eventTypes: ChildrenEventType[]) => void; children?: React.ReactNode; handleSubmit: (values: FormValues) => void; formMethods: UseFormReturn; eventTypeApps?: EventTypeApps; isUpdating: boolean; + isPlatform?: boolean; + tabName: (typeof tabs)[number]; + tabsNavigation: VerticalTabItemProps[]; } ) => { - const { - data: { tabName }, - } = useTypedQuery(querySchema); - - const { formMethods, eventTypeApps } = props; + const { formMethods, isPlatform, tabName } = props; const { eventType, team, currentUserMembership, tabMap, isUpdating } = props; const [animationParentRef] = useAutoAnimate(); - const appsMetadata = formMethods.getValues("metadata")?.apps; - const availability = formMethods.watch("availability"); - let numberOfActiveApps = 0; - - if (appsMetadata) { - numberOfActiveApps = Object.entries(appsMetadata).filter( - ([appId, appData]) => - eventTypeApps?.items.find((app) => app.slug === appId)?.isInstalled && appData.enabled - ).length; - } - - // Optional prerender all tabs after 300 ms on mount - return ( <> webhook.active).length} team={team} - availability={availability} isUpdateMutationLoading={isUpdating} formMethods={formMethods} // disableBorder={tabName === "apps" || tabName === "workflows" || tabName === "webhooks"} @@ -106,7 +81,10 @@ export const EventType = ( currentUserMembership={currentUserMembership} bookerUrl={eventType.bookerUrl} isUserOrganizationAdmin={props.isUserOrganizationAdmin} - onDelete={props.onDelete}> + onDelete={props.onDelete} + isDeleting={props.isDeleting} + isPlatform={isPlatform} + tabsNavigation={props.tabsNavigation}>
{tabMap[tabName]}
diff --git a/packages/features/eventtypes/components/EventTypeLayout.tsx b/packages/features/eventtypes/components/EventTypeLayout.tsx index 77d1a6a5b4..5c8e0ccaca 100644 --- a/packages/features/eventtypes/components/EventTypeLayout.tsx +++ b/packages/features/eventtypes/components/EventTypeLayout.tsx @@ -1,14 +1,13 @@ -import type { TFunction } from "next-i18next"; import { useMemo, useState, Suspense } from "react"; import type { UseFormReturn } from "react-hook-form"; +import { Shell as PlatformShell } from "@calcom/atoms/monorepo"; import useLockedFieldsManager from "@calcom/features/ee/managed-event-types/hooks/useLockedFieldsManager"; import { EventTypeEmbedButton, EventTypeEmbedDialog } from "@calcom/features/embed/EventTypeEmbed"; -import type { FormValues, AvailabilityOption } from "@calcom/features/eventtypes/lib/types"; +import type { FormValues } from "@calcom/features/eventtypes/lib/types"; import type { EventTypeSetupProps } from "@calcom/features/eventtypes/lib/types"; -import Shell from "@calcom/features/shell/Shell"; +import WebShell from "@calcom/features/shell/Shell"; import { classNames } from "@calcom/lib"; -import getPaymentAppData from "@calcom/lib/getPaymentAppData"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import { SchedulingType } from "@calcom/prisma/enums"; import type { VerticalTabItemProps } from "@calcom/ui"; @@ -40,91 +39,30 @@ type Props = { currentUserMembership: EventTypeSetupProps["currentUserMembership"]; team: EventTypeSetupProps["team"]; disableBorder?: boolean; - enabledAppsNumber: number; - installedAppsNumber: number; - enabledWorkflowsNumber: number; formMethods: UseFormReturn; isUpdateMutationLoading?: boolean; - availability?: AvailabilityOption; isUserOrganizationAdmin: boolean; bookerUrl: string; - activeWebhooksNumber: number; - onDelete: () => void; + onDelete: (id: number) => void; + isDeleting?: boolean; + isPlatform?: boolean; + tabsNavigation: VerticalTabItemProps[]; }; -type getNavigationProps = { - t: TFunction; - length: number; - id: number; - multipleDuration?: EventTypeSetupProps["eventType"]["metadata"]["multipleDuration"]; - enabledAppsNumber: number; - enabledWorkflowsNumber: number; - installedAppsNumber: number; - availability: AvailabilityOption | undefined; -}; - -function getNavigation({ - length, - id, - multipleDuration, - t, - enabledAppsNumber, - installedAppsNumber, - enabledWorkflowsNumber, -}: getNavigationProps) { - const duration = multipleDuration?.map((duration) => ` ${duration}`) || length; - - return [ - { - name: "event_setup_tab_title", - href: `/event-types/${id}?tabName=setup`, - icon: "link", - info: `${duration} ${t("minute_timeUnit")}`, // TODO: Get this from props - }, - { - name: "event_limit_tab_title", - href: `/event-types/${id}?tabName=limits`, - icon: "clock", - info: `event_limit_tab_description`, - }, - { - name: "event_advanced_tab_title", - href: `/event-types/${id}?tabName=advanced`, - icon: "sliders-vertical", - info: `event_advanced_tab_description`, - }, - { - name: "apps", - href: `/event-types/${id}?tabName=apps`, - icon: "grid-3x3", - //TODO: Handle proper translation with count handling - info: `${installedAppsNumber} apps, ${enabledAppsNumber} ${t("active")}`, - }, - { - name: "workflows", - href: `/event-types/${id}?tabName=workflows`, - icon: "zap", - info: `${enabledWorkflowsNumber} ${t("active")}`, - }, - ] satisfies VerticalTabItemProps[]; -} - function EventTypeSingleLayout({ children, eventType, currentUserMembership, team, disableBorder, - enabledAppsNumber, - installedAppsNumber, - enabledWorkflowsNumber, isUpdateMutationLoading, formMethods, - availability, isUserOrganizationAdmin, bookerUrl, - activeWebhooksNumber, onDelete, + isDeleting, + isPlatform, + tabsNavigation, }: Props) { const { t } = useLocale(); const eventTypesLockedByOrg = eventType.team?.parent?.organizationSettings?.lockEventTypeCreationForUsers; @@ -142,110 +80,7 @@ function EventTypeSingleLayout({ translate: t, formMethods, }); - - const length = formMethods.watch("length"); - const multipleDuration = formMethods.watch("metadata")?.multipleDuration; - - const watchSchedulingType = formMethods.watch("schedulingType"); - const watchChildrenCount = formMethods.watch("children").length; - - const paymentAppData = getPaymentAppData(eventType); - const requirePayment = paymentAppData.price > 0; - - // Define tab navigation here - const EventTypeTabs = useMemo(() => { - const navigation: VerticalTabItemProps[] = getNavigation({ - t, - length, - multipleDuration, - id: formMethods.getValues("id"), - enabledAppsNumber, - installedAppsNumber, - enabledWorkflowsNumber, - availability, - }); - - if (!requirePayment) { - navigation.splice(3, 0, { - name: "recurring", - href: `/event-types/${formMethods.getValues("id")}?tabName=recurring`, - icon: "repeat", - info: `recurring_event_tab_description`, - }); - } - navigation.splice(1, 0, { - name: "availability", - href: `/event-types/${formMethods.getValues("id")}?tabName=availability`, - icon: "calendar", - info: - isManagedEventType || isChildrenManagedEventType - ? formMethods.getValues("schedule") === null - ? "members_default_schedule" - : isChildrenManagedEventType - ? `${ - formMethods.getValues("scheduleName") - ? `${formMethods.getValues("scheduleName")} - ${t("managed")}` - : `default_schedule_name` - }` - : formMethods.getValues("scheduleName") ?? `default_schedule_name` - : formMethods.getValues("scheduleName") ?? `default_schedule_name`, - }); - // If there is a team put this navigation item within the tabs - if (team) { - navigation.splice(2, 0, { - name: "assignment", - href: `/event-types/${formMethods.getValues("id")}?tabName=team`, - icon: "users", - info: `${t(watchSchedulingType?.toLowerCase() ?? "")}${ - isManagedEventType ? ` - ${t("number_member", { count: watchChildrenCount || 0 })}` : "" - }`, - }); - } - const showWebhooks = !(isManagedEventType || isChildrenManagedEventType); - if (showWebhooks) { - if (team) { - navigation.push({ - name: "instant_tab_title", - href: `/event-types/${eventType.id}?tabName=instant`, - icon: "phone-call", - info: `instant_event_tab_description`, - }); - } - navigation.push({ - name: "webhooks", - href: `/event-types/${formMethods.getValues("id")}?tabName=webhooks`, - icon: "webhook", - info: `${activeWebhooksNumber} ${t("active")}`, - }); - } - const hidden = true; // hidden while in alpha trial. you can access it with tabName=ai - if (team && hidden) { - navigation.push({ - name: "Cal.ai", - href: `/event-types/${eventType.id}?tabName=ai`, - icon: "sparkles", - info: "cal_ai_event_tab_description", // todo `cal_ai_event_tab_description`, - }); - } - return navigation; - }, [ - t, - enabledAppsNumber, - installedAppsNumber, - enabledWorkflowsNumber, - availability, - isManagedEventType, - isChildrenManagedEventType, - team, - length, - requirePayment, - multipleDuration, - formMethods.getValues("id"), - watchSchedulingType, - watchChildrenCount, - activeWebhooksNumber, - ]); - + const EventTypeTabs = tabsNavigation; const permalink = `${bookerUrl}/${ team ? `${!team.parentId ? "team/" : ""}${team.slug}` : formMethods.getValues("users")[0].username }/${eventType.slug}`; @@ -254,7 +89,11 @@ function EventTypeSingleLayout({ team ? `team/${team.slug}` : formMethods.getValues("users")[0].username }/${formMethods.getValues("slug")}`; const isManagedEvent = formMethods.getValues("schedulingType") === SchedulingType.MANAGED ? "_managed" : ""; - // const title = formMethods.watch("title"); + + const [Shell] = useMemo(() => { + return isPlatform ? [PlatformShell] : [WebShell]; + }, [isPlatform]); + return ( {/* We have to warp this in tooltip as it has a href which disabels the tooltip on buttons */} - + {!isPlatform && ( + +