From 9ed162411117b9d37ea12ece84abcf6451a21d6f Mon Sep 17 00:00:00 2001 From: Benny Joo Date: Mon, 9 Sep 2024 20:19:44 -0400 Subject: [PATCH] chore: App router migration - `settings/platform/**/*`, `settings/organizations/new` and `settings/organizations/[id]/*` (#16334) * remove WizardLayoutAppDir * refactor organizations/new and add platform/new * refactor organizations/[id]/* * add APP_ROUTER_SETTINGS_ORG_ENABLED * fix type error * fix organizations/new page * remove code not needed and fix type errors * Fix Metadata utils * remove unnecessary code * remove unneeded code * wip * do not remove buildWrappedOnboardTeamMembersPage * fix type error * do not introduce changes to yarn.lock * fix wrong route name * fix onboard members * fix platform pages * fix settings/platform main view * add requiresLicense to WithLayout * refactor * add requiresLicense to platform/new * Add LicenseRequired back to platform/new * add env variable * fix onboard-members --------- Co-authored-by: Keith Williams --- .env.example | 2 + apps/web/abTest/middlewareFactory.ts | 2 + .../[id]/onboard-admins/page.tsx | 18 --- .../organizations/[id]/about/page.tsx | 8 +- .../organizations/[id]/add-teams/page.tsx | 8 +- .../[id]/onboard-members/page.tsx | 15 ++ .../organizations/new/page.tsx | 5 +- .../app/future/settings/platform/new/page.tsx | 21 +++ .../oauth-clients/[clientId]/edit/page.tsx | 15 ++ .../[clientId]/edit/webhooks/page.tsx | 15 ++ .../platform/oauth-clients/create/page.tsx | 19 +++ .../web/app/future/settings/platform/page.tsx | 16 +++ .../organizations/[id]/about-view.tsx | 14 ++ .../organizations/[id]/add-teams-view.tsx | 14 ++ .../[id]/onboard-members-view.tsx | 28 ++++ .../organizations/new/create-new-view.tsx | 14 ++ .../settings/platform/new/create-new-view.tsx | 14 ++ .../[clientId]/edit/edit-view.tsx | 133 +++++++++++++++++ .../[clientId]/edit/edit-webhooks-view.tsx | 122 ++++++++++++++++ .../oauth-clients/create-new-view.tsx | 91 ++++++++++++ .../settings/platform/platform-view.tsx | 107 ++++++++++++++ .../settings/organizations/[id]/about.tsx | 24 ++-- .../settings/organizations/[id]/add-teams.tsx | 24 ++-- .../organizations/[id]/onboard-members.tsx | 55 ++----- .../settings/organizations/new/index.tsx | 23 +-- apps/web/pages/settings/platform/index.tsx | 110 +------------- .../web/pages/settings/platform/new/index.tsx | 24 ++-- .../oauth-clients/[clientId]/edit/index.tsx | 136 +----------------- .../[clientId]/edit/webhooks.tsx | 125 +--------------- .../platform/oauth-clients/create.tsx | 94 +----------- apps/web/scripts/vercel-app-router-deploy.sh | 2 + .../components/AboutOrganizationForm.tsx | 2 + .../components/AddNewTeamsForm.tsx | 2 + .../components/CreateANewOrganizationForm.tsx | 2 + .../components/CreateANewPlatformForm.tsx | 2 + turbo.json | 2 + 36 files changed, 738 insertions(+), 570 deletions(-) delete mode 100644 apps/web/app/future/settings/(settings)/organizations/[id]/onboard-admins/page.tsx rename apps/web/app/future/settings/{(settings) => }/organizations/[id]/about/page.tsx (61%) rename apps/web/app/future/settings/{(settings) => }/organizations/[id]/add-teams/page.tsx (59%) create mode 100644 apps/web/app/future/settings/organizations/[id]/onboard-members/page.tsx rename apps/web/app/future/settings/{(settings) => }/organizations/new/page.tsx (72%) create mode 100644 apps/web/app/future/settings/platform/new/page.tsx create mode 100644 apps/web/app/future/settings/platform/oauth-clients/[clientId]/edit/page.tsx create mode 100644 apps/web/app/future/settings/platform/oauth-clients/[clientId]/edit/webhooks/page.tsx create mode 100644 apps/web/app/future/settings/platform/oauth-clients/create/page.tsx create mode 100644 apps/web/app/future/settings/platform/page.tsx create mode 100644 apps/web/modules/settings/organizations/[id]/about-view.tsx create mode 100644 apps/web/modules/settings/organizations/[id]/add-teams-view.tsx create mode 100644 apps/web/modules/settings/organizations/[id]/onboard-members-view.tsx create mode 100644 apps/web/modules/settings/organizations/new/create-new-view.tsx create mode 100644 apps/web/modules/settings/platform/new/create-new-view.tsx create mode 100644 apps/web/modules/settings/platform/oauth-clients/[clientId]/edit/edit-view.tsx create mode 100644 apps/web/modules/settings/platform/oauth-clients/[clientId]/edit/edit-webhooks-view.tsx create mode 100644 apps/web/modules/settings/platform/oauth-clients/create-new-view.tsx create mode 100644 apps/web/modules/settings/platform/platform-view.tsx diff --git a/.env.example b/.env.example index 876a670317..0ff47a8580 100644 --- a/.env.example +++ b/.env.example @@ -334,6 +334,8 @@ AB_TEST_BUCKET_PROBABILITY=50 # whether we redirect to the future/event-types from event-types or not APP_ROUTER_EVENT_TYPES_ENABLED=0 APP_ROUTER_SETTINGS_ADMIN_ENABLED=0 +APP_ROUTER_SETTINGS_PLATFORM_ENABLED=0 +APP_ROUTER_SETTINGS_ORG_ENABLED=0 APP_ROUTER_APPS_INSTALLED_CATEGORY_ENABLED=0 APP_ROUTER_APPS_SLUG_ENABLED=0 APP_ROUTER_APPS_SLUG_SETUP_ENABLED=0 diff --git a/apps/web/abTest/middlewareFactory.ts b/apps/web/abTest/middlewareFactory.ts index 8fdf1720f3..50e5e3d2aa 100644 --- a/apps/web/abTest/middlewareFactory.ts +++ b/apps/web/abTest/middlewareFactory.ts @@ -8,6 +8,8 @@ import { FUTURE_ROUTES_ENABLED_COOKIE_NAME, FUTURE_ROUTES_OVERRIDE_COOKIE_NAME } const ROUTES: [URLPattern, boolean][] = [ ["/event-types", process.env.APP_ROUTER_EVENT_TYPES_ENABLED === "1"] as const, ["/settings/admin/:path*", process.env.APP_ROUTER_SETTINGS_ADMIN_ENABLED === "1"] as const, + ["/settings/platform/:path*", process.env.APP_ROUTER_SETTINGS_PLATFORM_ENABLED === "1"] as const, + ["/settings/organizations/:path*", process.env.APP_ROUTER_SETTINGS_ORG_ENABLED === "1"] as const, ["/apps/installed/:category", process.env.APP_ROUTER_APPS_INSTALLED_CATEGORY_ENABLED === "1"] as const, ["/apps/:slug", process.env.APP_ROUTER_APPS_SLUG_ENABLED === "1"] as const, ["/apps/:slug/setup", process.env.APP_ROUTER_APPS_SLUG_SETUP_ENABLED === "1"] as const, diff --git a/apps/web/app/future/settings/(settings)/organizations/[id]/onboard-admins/page.tsx b/apps/web/app/future/settings/(settings)/organizations/[id]/onboard-admins/page.tsx deleted file mode 100644 index 1db37f76f5..0000000000 --- a/apps/web/app/future/settings/(settings)/organizations/[id]/onboard-admins/page.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import LegacyPage, { - buildWrappedOnboardTeamMembersPage, -} from "@pages/settings/organizations/[id]/onboard-members"; -import type { PageProps } from "app/_types"; -import { _generateMetadata } from "app/_utils"; -import { WithLayout } from "app/layoutHOC"; - -export const generateMetadata = async () => - await _generateMetadata( - (t) => t("invite_organization_admins"), - (t) => t("invite_organization_admins_description") - ); - -const Page = ({ params }: PageProps) => { - return buildWrappedOnboardTeamMembersPage(params.id, ); -}; - -export default WithLayout({ Page }); diff --git a/apps/web/app/future/settings/(settings)/organizations/[id]/about/page.tsx b/apps/web/app/future/settings/organizations/[id]/about/page.tsx similarity index 61% rename from apps/web/app/future/settings/(settings)/organizations/[id]/about/page.tsx rename to apps/web/app/future/settings/organizations/[id]/about/page.tsx index 4e3e45e4cf..42fca898e4 100644 --- a/apps/web/app/future/settings/(settings)/organizations/[id]/about/page.tsx +++ b/apps/web/app/future/settings/organizations/[id]/about/page.tsx @@ -1,11 +1,15 @@ -import LegacyPage, { LayoutWrapper } from "@pages/settings/organizations/[id]/about"; import { _generateMetadata } from "app/_utils"; import { WithLayout } from "app/layoutHOC"; +import LegacyPage, { LayoutWrapper } from "~/settings/organizations/[id]/about-view"; + export const generateMetadata = async () => await _generateMetadata( (t) => t("about_your_organization"), (t) => t("about_your_organization_description") ); -export default WithLayout({ Page: LegacyPage, getLayout: LayoutWrapper }); +export default WithLayout({ + Page: LegacyPage, + getLayout: LayoutWrapper, +}); diff --git a/apps/web/app/future/settings/(settings)/organizations/[id]/add-teams/page.tsx b/apps/web/app/future/settings/organizations/[id]/add-teams/page.tsx similarity index 59% rename from apps/web/app/future/settings/(settings)/organizations/[id]/add-teams/page.tsx rename to apps/web/app/future/settings/organizations/[id]/add-teams/page.tsx index b9c1805632..0fd0d5d11b 100644 --- a/apps/web/app/future/settings/(settings)/organizations/[id]/add-teams/page.tsx +++ b/apps/web/app/future/settings/organizations/[id]/add-teams/page.tsx @@ -1,11 +1,15 @@ -import LegacyPage, { LayoutWrapper } from "@pages/settings/organizations/[id]/add-teams"; import { _generateMetadata } from "app/_utils"; import { WithLayout } from "app/layoutHOC"; +import LegacyPage, { LayoutWrapper } from "~/settings/organizations/[id]/add-teams-view"; + export const generateMetadata = async () => await _generateMetadata( (t) => t("create_your_teams"), (t) => t("create_your_teams_description") ); -export default WithLayout({ Page: LegacyPage, getLayout: LayoutWrapper }); +export default WithLayout({ + Page: LegacyPage, + getLayout: LayoutWrapper, +}); diff --git a/apps/web/app/future/settings/organizations/[id]/onboard-members/page.tsx b/apps/web/app/future/settings/organizations/[id]/onboard-members/page.tsx new file mode 100644 index 0000000000..113cd399be --- /dev/null +++ b/apps/web/app/future/settings/organizations/[id]/onboard-members/page.tsx @@ -0,0 +1,15 @@ +import { _generateMetadata } from "app/_utils"; +import { WithLayout } from "app/layoutHOC"; + +import LegacyPage, { LayoutWrapper } from "~/settings/organizations/[id]/onboard-members-view"; + +export const generateMetadata = async () => + await _generateMetadata( + (t) => t("invite_organization_admins"), + (t) => t("invite_organization_admins_description") + ); + +export default WithLayout({ + Page: LegacyPage, + getLayout: LayoutWrapper, +}); diff --git a/apps/web/app/future/settings/(settings)/organizations/new/page.tsx b/apps/web/app/future/settings/organizations/new/page.tsx similarity index 72% rename from apps/web/app/future/settings/(settings)/organizations/new/page.tsx rename to apps/web/app/future/settings/organizations/new/page.tsx index 0b77da0508..3c11ec9d19 100644 --- a/apps/web/app/future/settings/(settings)/organizations/new/page.tsx +++ b/apps/web/app/future/settings/organizations/new/page.tsx @@ -1,10 +1,12 @@ -import LegacyPage, { getServerSideProps, LayoutWrapper } from "@pages/settings/organizations/new/index"; import { withAppDirSsr } from "app/WithAppDirSsr"; import { _generateMetadata } from "app/_utils"; import { WithLayout } from "app/layoutHOC"; +import { getServerSideProps } from "@lib/settings/organizations/new/getServerSideProps"; import { type inferSSRProps } from "@lib/types/inferSSRProps"; +import LegacyPage, { LayoutWrapper } from "~/settings/organizations/new/create-new-view"; + export const generateMetadata = async () => await _generateMetadata( (t) => t("set_up_your_organization"), @@ -12,6 +14,7 @@ export const generateMetadata = async () => ); export default WithLayout({ + requiresLicense: true, getLayout: LayoutWrapper, Page: LegacyPage, getData: withAppDirSsr>(getServerSideProps), diff --git a/apps/web/app/future/settings/platform/new/page.tsx b/apps/web/app/future/settings/platform/new/page.tsx new file mode 100644 index 0000000000..033ef74380 --- /dev/null +++ b/apps/web/app/future/settings/platform/new/page.tsx @@ -0,0 +1,21 @@ +import { withAppDirSsr } from "app/WithAppDirSsr"; +import { _generateMetadata } from "app/_utils"; +import { WithLayout } from "app/layoutHOC"; + +import { getServerSideProps } from "@lib/settings/organizations/new/getServerSideProps"; +import { type inferSSRProps } from "@lib/types/inferSSRProps"; + +import LegacyPage, { LayoutWrapper } from "~/settings/platform/new/create-new-view"; + +export const generateMetadata = async () => + await _generateMetadata( + (t) => t("set_up_your_platform_organization"), + (t) => t("platform_organization_description") + ); + +export default WithLayout({ + getLayout: LayoutWrapper, + Page: LegacyPage, + getData: withAppDirSsr>(getServerSideProps), + requiresLicense: true, +}); diff --git a/apps/web/app/future/settings/platform/oauth-clients/[clientId]/edit/page.tsx b/apps/web/app/future/settings/platform/oauth-clients/[clientId]/edit/page.tsx new file mode 100644 index 0000000000..754e9a20fc --- /dev/null +++ b/apps/web/app/future/settings/platform/oauth-clients/[clientId]/edit/page.tsx @@ -0,0 +1,15 @@ +import { _generateMetadata } from "app/_utils"; +import { WithLayout } from "app/layoutHOC"; + +import EditView from "~/settings/platform/oauth-clients/[clientId]/edit/edit-view"; + +export const generateMetadata = async () => + await _generateMetadata( + () => "OAuth client updation form", + () => "" + ); + +export default WithLayout({ + getLayout: null, + Page: EditView, +}); diff --git a/apps/web/app/future/settings/platform/oauth-clients/[clientId]/edit/webhooks/page.tsx b/apps/web/app/future/settings/platform/oauth-clients/[clientId]/edit/webhooks/page.tsx new file mode 100644 index 0000000000..7eef008b4e --- /dev/null +++ b/apps/web/app/future/settings/platform/oauth-clients/[clientId]/edit/webhooks/page.tsx @@ -0,0 +1,15 @@ +import { _generateMetadata } from "app/_utils"; +import { WithLayout } from "app/layoutHOC"; + +import EditWebhooksView from "~/settings/platform/oauth-clients/[clientId]/edit/edit-webhooks-view"; + +export const generateMetadata = async () => + await _generateMetadata( + () => "OAuth client updation form", + () => "" + ); + +export default WithLayout({ + getLayout: null, + Page: EditWebhooksView, +}); diff --git a/apps/web/app/future/settings/platform/oauth-clients/create/page.tsx b/apps/web/app/future/settings/platform/oauth-clients/create/page.tsx new file mode 100644 index 0000000000..5303d7dc4a --- /dev/null +++ b/apps/web/app/future/settings/platform/oauth-clients/create/page.tsx @@ -0,0 +1,19 @@ +import type { PageProps } from "app/_types"; +import { _generateMetadata } from "app/_utils"; +import { WithLayout } from "app/layoutHOC"; + +import CreateNewView from "~/settings/platform/oauth-clients/create-new-view"; + +export const generateMetadata = async ({ params, searchParams }: PageProps) => { + const p = { ...params, ...searchParams }; + const clientId = p?.clientId ?? ""; + return await _generateMetadata( + () => `OAuth client ${!!clientId ? "updation" : "creation"} form`, + () => "" + ); +}; + +export default WithLayout({ + getLayout: null, + Page: CreateNewView, +}); diff --git a/apps/web/app/future/settings/platform/page.tsx b/apps/web/app/future/settings/platform/page.tsx new file mode 100644 index 0000000000..e6105fcc58 --- /dev/null +++ b/apps/web/app/future/settings/platform/page.tsx @@ -0,0 +1,16 @@ +import { _generateMetadata } from "app/_utils"; +import { WithLayout } from "app/layoutHOC"; + +import PlatformView from "~/settings/platform/platform-view"; + +export const generateMetadata = async () => { + return await _generateMetadata( + () => "Platform", + () => "Manage everything related to platform." + ); +}; + +export default WithLayout({ + getLayout: null, + Page: PlatformView, +}); diff --git a/apps/web/modules/settings/organizations/[id]/about-view.tsx b/apps/web/modules/settings/organizations/[id]/about-view.tsx new file mode 100644 index 0000000000..485e582721 --- /dev/null +++ b/apps/web/modules/settings/organizations/[id]/about-view.tsx @@ -0,0 +1,14 @@ +"use client"; + +import { AboutOrganizationForm } from "@calcom/features/ee/organizations/components"; +import { WizardLayout } from "@calcom/ui"; + +export const LayoutWrapper = (page: React.ReactElement) => { + return ( + + {page} + + ); +}; + +export default AboutOrganizationForm; diff --git a/apps/web/modules/settings/organizations/[id]/add-teams-view.tsx b/apps/web/modules/settings/organizations/[id]/add-teams-view.tsx new file mode 100644 index 0000000000..21a11c76e0 --- /dev/null +++ b/apps/web/modules/settings/organizations/[id]/add-teams-view.tsx @@ -0,0 +1,14 @@ +"use client"; + +import { AddNewTeamsForm } from "@calcom/features/ee/organizations/components"; +import { WizardLayout } from "@calcom/ui"; + +export const LayoutWrapper = (page: React.ReactElement) => { + return ( + + {page} + + ); +}; + +export default AddNewTeamsForm; diff --git a/apps/web/modules/settings/organizations/[id]/onboard-members-view.tsx b/apps/web/modules/settings/organizations/[id]/onboard-members-view.tsx new file mode 100644 index 0000000000..6218462585 --- /dev/null +++ b/apps/web/modules/settings/organizations/[id]/onboard-members-view.tsx @@ -0,0 +1,28 @@ +"use client"; + +import { useRouter } from "next/navigation"; + +import AddNewTeamMembers from "@calcom/features/ee/teams/components/AddNewTeamMembers"; +import { useCompatSearchParams } from "@calcom/lib/hooks/useCompatSearchParams"; +import { WizardLayout } from "@calcom/ui"; + +export const LayoutWrapper = (page: React.ReactElement) => { + // eslint-disable-next-line react-hooks/rules-of-hooks + const router = useRouter(); + // eslint-disable-next-line react-hooks/rules-of-hooks + const query = useCompatSearchParams(); + + return ( + { + router.push(`/settings/organizations/${query.get("id")}/add-teams`); + }}> + {page} + + ); +}; + +const OrgAddNewTeamMembers = () => ; +export default OrgAddNewTeamMembers; diff --git a/apps/web/modules/settings/organizations/new/create-new-view.tsx b/apps/web/modules/settings/organizations/new/create-new-view.tsx new file mode 100644 index 0000000000..79f1d3936e --- /dev/null +++ b/apps/web/modules/settings/organizations/new/create-new-view.tsx @@ -0,0 +1,14 @@ +"use client"; + +import { CreateANewOrganizationForm } from "@calcom/features/ee/organizations/components"; +import { WizardLayout } from "@calcom/ui"; + +export const LayoutWrapper = (page: React.ReactElement) => { + return ( + + {page} + + ); +}; + +export default CreateANewOrganizationForm; diff --git a/apps/web/modules/settings/platform/new/create-new-view.tsx b/apps/web/modules/settings/platform/new/create-new-view.tsx new file mode 100644 index 0000000000..fc155ff204 --- /dev/null +++ b/apps/web/modules/settings/platform/new/create-new-view.tsx @@ -0,0 +1,14 @@ +"use client"; + +import { CreateANewPlatformForm } from "@calcom/features/ee/platform/components/index"; +import { WizardLayout } from "@calcom/ui"; + +export const LayoutWrapper = (page: React.ReactElement) => { + return ( + + {page} + + ); +}; + +export default CreateANewPlatformForm; diff --git a/apps/web/modules/settings/platform/oauth-clients/[clientId]/edit/edit-view.tsx b/apps/web/modules/settings/platform/oauth-clients/[clientId]/edit/edit-view.tsx new file mode 100644 index 0000000000..8285c97370 --- /dev/null +++ b/apps/web/modules/settings/platform/oauth-clients/[clientId]/edit/edit-view.tsx @@ -0,0 +1,133 @@ +"use client"; + +import { useParams } from "next/navigation"; +import { useRouter } from "next/navigation"; + +import Shell from "@calcom/features/shell/Shell"; +import { ErrorCode } from "@calcom/lib/errorCodes"; +import { PERMISSIONS_GROUPED_MAP } from "@calcom/platform-constants"; +import { showToast } from "@calcom/ui"; + +import { useOAuthClient } from "@lib/hooks/settings/platform/oauth-clients/useOAuthClients"; +import { useUpdateOAuthClient } from "@lib/hooks/settings/platform/oauth-clients/usePersistOAuthClient"; + +import NoPlatformPlan from "@components/settings/platform/dashboard/NoPlatformPlan"; +import { useGetUserAttributes } from "@components/settings/platform/hooks/useGetUserAttributes"; +import type { FormValues } from "@components/settings/platform/oauth-clients/oauth-client-form"; +import { OAuthClientForm as EditOAuthClientForm } from "@components/settings/platform/oauth-clients/oauth-client-form"; + +import { + hasAppsReadPermission, + hasAppsWritePermission, + hasBookingReadPermission, + hasBookingWritePermission, + hasEventTypeReadPermission, + hasEventTypeWritePermission, + hasProfileReadPermission, + hasProfileWritePermission, + hasScheduleReadPermission, + hasScheduleWritePermission, +} from "../../../../../../../../packages/platform/utils/permissions"; + +export default function EditOAuthClient() { + const router = useRouter(); + const params = useParams<{ clientId: string }>(); + const clientId = params?.clientId || ""; + + const { isUserLoading, isPlatformUser, isPaidUser } = useGetUserAttributes(); + + const { data, isFetched, isFetching, isError, refetch } = useOAuthClient(clientId); + const { mutateAsync: update, isPending: isUpdating } = useUpdateOAuthClient({ + onSuccess: () => { + showToast("OAuth client updated successfully", "success"); + refetch(); + router.push("/settings/platform/"); + }, + onError: () => { + showToast(ErrorCode.UpdatingOauthClientError, "error"); + }, + clientId, + }); + + const onSubmit = (data: FormValues) => { + let userPermissions = 0; + const userRedirectUris = data.redirectUris.map((uri) => uri.uri).filter((uri) => !!uri); + + Object.keys(PERMISSIONS_GROUPED_MAP).forEach((key) => { + const entity = key as keyof typeof PERMISSIONS_GROUPED_MAP; + const entityKey = PERMISSIONS_GROUPED_MAP[entity].key; + const read = PERMISSIONS_GROUPED_MAP[entity].read; + const write = PERMISSIONS_GROUPED_MAP[entity].write; + if (data[`${entityKey}Read`]) userPermissions |= read; + if (data[`${entityKey}Write`]) userPermissions |= write; + }); + + update({ + name: data.name, + // logo: data.logo, + redirectUris: userRedirectUris, + bookingRedirectUri: data.bookingRedirectUri, + bookingCancelRedirectUri: data.bookingCancelRedirectUri, + bookingRescheduleRedirectUri: data.bookingRescheduleRedirectUri, + areEmailsEnabled: data.areEmailsEnabled, + }); + }; + + if (isUserLoading) return
Loading...
; + + if (isPlatformUser && isPaidUser) { + return ( +
+ +
+
+
+

+ OAuth client updation form +

+

+ This is the form to edit an existing OAuth client +

+
+
+ {(!Boolean(clientId) || (isFetched && !data)) &&

OAuth Client not found.

} + {isFetched && !!data && ( + ({ uri })) ?? [{ uri: "" }], + bookingRedirectUri: data?.bookingRedirectUri ?? "", + bookingCancelRedirectUri: data?.bookingCancelRedirectUri ?? "", + bookingRescheduleRedirectUri: data?.bookingRescheduleRedirectUri ?? "", + appsRead: hasAppsReadPermission(data?.permissions), + appsWrite: hasAppsWritePermission(data?.permissions), + bookingRead: hasBookingReadPermission(data?.permissions), + bookingWrite: hasBookingWritePermission(data?.permissions), + eventTypeRead: hasEventTypeReadPermission(data?.permissions), + eventTypeWrite: hasEventTypeWritePermission(data?.permissions), + profileRead: hasProfileReadPermission(data?.permissions), + profileWrite: hasProfileWritePermission(data?.permissions), + scheduleRead: hasScheduleReadPermission(data?.permissions), + scheduleWrite: hasScheduleWritePermission(data?.permissions), + }} + onSubmit={onSubmit} + isPending={isUpdating} + /> + )} + {isFetching &&

Loading...

} + {isError &&

Something went wrong.

} +
+
+
+ ); + } + + return ( +
+ }> + + +
+ ); +} diff --git a/apps/web/modules/settings/platform/oauth-clients/[clientId]/edit/edit-webhooks-view.tsx b/apps/web/modules/settings/platform/oauth-clients/[clientId]/edit/edit-webhooks-view.tsx new file mode 100644 index 0000000000..0d4ae3714a --- /dev/null +++ b/apps/web/modules/settings/platform/oauth-clients/[clientId]/edit/edit-webhooks-view.tsx @@ -0,0 +1,122 @@ +"use client"; + +import { useParams } from "next/navigation"; +import { useRouter } from "next/navigation"; + +import Shell from "@calcom/features/shell/Shell"; +import { WebhookForm } from "@calcom/features/webhooks/components"; +import { WebhookTriggerEvents } from "@calcom/prisma/enums"; +import { showToast } from "@calcom/ui"; + +import { + useOAuthClientWebhooks, + useCreateOAuthClientWebhook, + useUpdateOAuthClientWebhook, +} from "@lib/hooks/settings/platform/oauth-clients/useOAuthClientWebhooks"; + +import NoPlatformPlan from "@components/settings/platform/dashboard/NoPlatformPlan"; +import { useGetUserAttributes } from "@components/settings/platform/hooks/useGetUserAttributes"; + +export default function EditOAuthClientWebhooks() { + const router = useRouter(); + const params = useParams<{ clientId: string }>(); + const clientId = params?.clientId || ""; + + const { isUserLoading, isPlatformUser, isPaidUser } = useGetUserAttributes(); + + const { + data: webhooks, + status: webhooksStatus, + isFetched: isWebhooksFetched, + refetch: refetchWebhooks, + } = useOAuthClientWebhooks(clientId); + const webhookId = webhooks?.[0]?.id ?? ""; + const webhook = webhooks?.[0]; + const { mutateAsync: createWebhook } = useCreateOAuthClientWebhook(clientId); + const { mutateAsync: updateWebhook } = useUpdateOAuthClientWebhook(clientId); + + if (isUserLoading) return
Loading...
; + + if (isPlatformUser && isPaidUser) { + return ( +
+ +
+
+
+

+ Webhook update form +

+

Add a webhook to your OAuthClient.

+
+
+ + {webhooksStatus !== "success" &&

Error while trying to access webhooks.

} + + {isWebhooksFetched && webhooksStatus === "success" && ( + { + try { + const body = { + active: data.active, + payloadTemplate: data.payloadTemplate ?? undefined, + subscriberUrl: data.subscriberUrl, + triggers: data.eventTriggers, + secret: data.secret ?? undefined, + }; + if (webhook) { + await updateWebhook({ + webhookId, + body, + }); + showToast("Webhook updated successfully.", "success"); + } else { + await createWebhook(body); + showToast("Webhook created successfully.", "success"); + } + await refetchWebhooks(); + router.push("/settings/platform/"); + } catch (err) { + showToast(`Failed to ${webhookId ? "update" : "create"} webhook.`, "error"); + } + }} + onCancel={() => { + router.push("/settings/platform/"); + }} + noRoutingFormTriggers={true} + webhook={ + webhook + ? { ...webhook, eventTriggers: webhook.triggers, secret: webhook.secret ?? null } + : undefined + } + /> + )} +
+
+
+ ); + } + + return ( +
+ }> + + +
+ ); +} diff --git a/apps/web/modules/settings/platform/oauth-clients/create-new-view.tsx b/apps/web/modules/settings/platform/oauth-clients/create-new-view.tsx new file mode 100644 index 0000000000..7cedf181d5 --- /dev/null +++ b/apps/web/modules/settings/platform/oauth-clients/create-new-view.tsx @@ -0,0 +1,91 @@ +"use client"; + +import { useRouter } from "next/navigation"; + +import Shell from "@calcom/features/shell/Shell"; +import { ErrorCode } from "@calcom/lib/errorCodes"; +import { useCompatSearchParams } from "@calcom/lib/hooks/useCompatSearchParams"; +import { PERMISSIONS_GROUPED_MAP } from "@calcom/platform-constants/permissions"; +import { showToast } from "@calcom/ui"; + +import { useCreateOAuthClient } from "@lib/hooks/settings/platform/oauth-clients/usePersistOAuthClient"; + +import NoPlatformPlan from "@components/settings/platform/dashboard/NoPlatformPlan"; +import { useGetUserAttributes } from "@components/settings/platform/hooks/useGetUserAttributes"; +import type { FormValues } from "@components/settings/platform/oauth-clients/oauth-client-form"; +import { OAuthClientForm } from "@components/settings/platform/oauth-clients/oauth-client-form"; + +export default function CreateOAuthClient() { + const searchParams = useCompatSearchParams(); + const router = useRouter(); + const clientId = searchParams?.get("clientId") || ""; + + const { isUserLoading, isPlatformUser, isPaidUser } = useGetUserAttributes(); + + const { mutateAsync: save, isPending: isSaving } = useCreateOAuthClient({ + onSuccess: () => { + showToast("OAuth client created successfully", "success"); + router.push("/settings/platform/"); + }, + onError: () => { + showToast(ErrorCode.CreatingOauthClientError, "error"); + }, + }); + + const onSubmit = (data: FormValues) => { + let userPermissions = 0; + const userRedirectUris = data.redirectUris.map((uri) => uri.uri).filter((uri) => !!uri); + + Object.keys(PERMISSIONS_GROUPED_MAP).forEach((key) => { + const entity = key as keyof typeof PERMISSIONS_GROUPED_MAP; + const entityKey = PERMISSIONS_GROUPED_MAP[entity].key; + const read = PERMISSIONS_GROUPED_MAP[entity].read; + const write = PERMISSIONS_GROUPED_MAP[entity].write; + if (data[`${entityKey}Read`]) userPermissions |= read; + if (data[`${entityKey}Write`]) userPermissions |= write; + }); + + save({ + name: data.name, + permissions: userPermissions, + // logo: data.logo, + redirectUris: userRedirectUris, + bookingRedirectUri: data.bookingRedirectUri, + bookingCancelRedirectUri: data.bookingCancelRedirectUri, + bookingRescheduleRedirectUri: data.bookingRescheduleRedirectUri, + areEmailsEnabled: data.areEmailsEnabled, + }); + }; + + if (isUserLoading) return
Loading...
; + + if (isPlatformUser && isPaidUser) { + return ( +
+ +
+
+
+

+ OAuth client creation form +

+

+ This is the form to create a new OAuth client +

+
+
+ +
+
+
+ ); + } + + return ( +
+ }> + + +
+ ); +} diff --git a/apps/web/modules/settings/platform/platform-view.tsx b/apps/web/modules/settings/platform/platform-view.tsx new file mode 100644 index 0000000000..304d791232 --- /dev/null +++ b/apps/web/modules/settings/platform/platform-view.tsx @@ -0,0 +1,107 @@ +"use client"; + +import { QueryClientProvider, QueryClient } from "@tanstack/react-query"; +import { useState, useEffect } from "react"; + +import Shell from "@calcom/features/shell/Shell"; +import { showToast } from "@calcom/ui"; + +import { + useOAuthClients, + useGetOAuthClientManagedUsers, +} from "@lib/hooks/settings/platform/oauth-clients/useOAuthClients"; +import { useDeleteOAuthClient } from "@lib/hooks/settings/platform/oauth-clients/usePersistOAuthClient"; + +import { HelpCards } from "@components/settings/platform/dashboard/HelpCards"; +import NoPlatformPlan from "@components/settings/platform/dashboard/NoPlatformPlan"; +import { ManagedUserList } from "@components/settings/platform/dashboard/managed-user-list"; +import { OAuthClientsList } from "@components/settings/platform/dashboard/oauth-clients-list"; +import { useGetUserAttributes } from "@components/settings/platform/hooks/useGetUserAttributes"; +import { PlatformPricing } from "@components/settings/platform/pricing/platform-pricing"; + +const queryClient = new QueryClient(); + +export default function Platform() { + const [initialClientId, setInitialClientId] = useState(""); + const [initialClientName, setInitialClientName] = useState(""); + + const { data, isLoading: isOAuthClientLoading, refetch: refetchClients } = useOAuthClients(); + const { + isLoading: isManagedUserLoading, + data: managedUserData, + refetch: refetchManagedUsers, + } = useGetOAuthClientManagedUsers(initialClientId); + + const { isUserLoading, isUserBillingDataLoading, isPlatformUser, isPaidUser, userBillingData, userOrgId } = + useGetUserAttributes(); + + const { mutateAsync, isPending: isDeleting } = useDeleteOAuthClient({ + onSuccess: () => { + showToast("OAuth client deleted successfully", "success"); + refetchClients(); + refetchManagedUsers(); + }, + }); + + const handleDelete = async (id: string) => { + await mutateAsync({ id: id }); + }; + + useEffect(() => { + setInitialClientId(data[0]?.id); + setInitialClientName(data[0]?.name); + }, [data]); + + if (isUserLoading || isOAuthClientLoading) return
Loading...
; + + if (isUserBillingDataLoading && !userBillingData) { + return
Loading...
; + } + + if (isPlatformUser && !isPaidUser) return ; + + if (isPlatformUser) { + return ( + +
+ + + + { + setInitialClientId(id); + setInitialClientName(name); + refetchManagedUsers(); + }} + /> + +
+
+ ); + } + + return ( +
+ }> + + +
+ ); +} diff --git a/apps/web/pages/settings/organizations/[id]/about.tsx b/apps/web/pages/settings/organizations/[id]/about.tsx index 5f324067c8..725ae41b08 100644 --- a/apps/web/pages/settings/organizations/[id]/about.tsx +++ b/apps/web/pages/settings/organizations/[id]/about.tsx @@ -1,14 +1,12 @@ -"use client"; - -import { AboutOrganizationForm } from "@calcom/features/ee/organizations/components"; +import { getServerSideProps } from "@calcom/features/ee/organizations/pages/organization"; import { useLocale } from "@calcom/lib/hooks/useLocale"; -import { Meta, WizardLayout } from "@calcom/ui"; +import { Meta } from "@calcom/ui"; import PageWrapper from "@components/PageWrapper"; -export { getServerSideProps } from "@calcom/features/ee/organizations/pages/organization"; +import AboutOrganizationForm, { LayoutWrapper } from "~/settings/organizations/[id]/about-view"; -const AboutOrganizationPage = () => { +const Page = () => { const { t } = useLocale(); return ( <> @@ -17,15 +15,9 @@ const AboutOrganizationPage = () => { ); }; -export const LayoutWrapper = (page: React.ReactElement) => { - return ( - - {page} - - ); -}; -AboutOrganizationPage.getLayout = LayoutWrapper; -AboutOrganizationPage.PageWrapper = PageWrapper; +Page.getLayout = LayoutWrapper; +Page.PageWrapper = PageWrapper; -export default AboutOrganizationPage; +export default Page; +export { getServerSideProps }; diff --git a/apps/web/pages/settings/organizations/[id]/add-teams.tsx b/apps/web/pages/settings/organizations/[id]/add-teams.tsx index c70840c3fb..b2d442267d 100644 --- a/apps/web/pages/settings/organizations/[id]/add-teams.tsx +++ b/apps/web/pages/settings/organizations/[id]/add-teams.tsx @@ -1,14 +1,12 @@ -"use client"; - -import { AddNewTeamsForm } from "@calcom/features/ee/organizations/components"; +import { getServerSideProps } from "@calcom/features/ee/organizations/pages/organization"; import { useLocale } from "@calcom/lib/hooks/useLocale"; -import { Meta, WizardLayout } from "@calcom/ui"; +import { Meta } from "@calcom/ui"; import PageWrapper from "@components/PageWrapper"; -export { getServerSideProps } from "@calcom/features/ee/organizations/pages/organization"; +import AddNewTeamsForm, { LayoutWrapper } from "~/settings/organizations/[id]/add-teams-view"; -const AddNewTeamsPage = () => { +const Page = () => { const { t } = useLocale(); return ( <> @@ -18,15 +16,9 @@ const AddNewTeamsPage = () => { ); }; -export const LayoutWrapper = (page: React.ReactElement) => { - return ( - - {page} - - ); -}; +Page.getLayout = LayoutWrapper; +Page.PageWrapper = PageWrapper; -AddNewTeamsPage.getLayout = LayoutWrapper; -AddNewTeamsPage.PageWrapper = PageWrapper; +export default Page; -export default AddNewTeamsPage; +export { getServerSideProps }; diff --git a/apps/web/pages/settings/organizations/[id]/onboard-members.tsx b/apps/web/pages/settings/organizations/[id]/onboard-members.tsx index dfe0c8f0c2..77832fe839 100644 --- a/apps/web/pages/settings/organizations/[id]/onboard-members.tsx +++ b/apps/web/pages/settings/organizations/[id]/onboard-members.tsx @@ -1,17 +1,12 @@ -"use client"; - -import { redirect, useRouter } from "next/navigation"; - -import AddNewTeamMembers from "@calcom/features/ee/teams/components/AddNewTeamMembers"; -import { useCompatSearchParams } from "@calcom/lib/hooks/useCompatSearchParams"; +import { getServerSideProps } from "@calcom/features/ee/organizations/pages/organization"; import { useLocale } from "@calcom/lib/hooks/useLocale"; -import { Meta, WizardLayout } from "@calcom/ui"; +import { Meta } from "@calcom/ui"; import PageWrapper from "@components/PageWrapper"; -export { getServerSideProps } from "@calcom/features/ee/organizations/pages/organization"; +import OrgAddNewTeamMembers, { LayoutWrapper } from "~/settings/organizations/[id]/onboard-members-view"; -const OnboardTeamMembersPage = () => { +const Page = () => { const { t } = useLocale(); return ( @@ -20,45 +15,13 @@ const OnboardTeamMembersPage = () => { title={t("invite_organization_admins")} description={t("invite_organization_admins_description")} /> - + ); }; -OnboardTeamMembersPage.getLayout = (page: React.ReactElement) => { - // eslint-disable-next-line react-hooks/rules-of-hooks - const router = useRouter(); - // eslint-disable-next-line react-hooks/rules-of-hooks - const query = useCompatSearchParams(); +Page.getLayout = LayoutWrapper; +Page.PageWrapper = PageWrapper; - return ( - { - router.push(`/settings/organizations/${query.get("id")}/add-teams`); - }}> - {page} - - ); -}; - -export const buildWrappedOnboardTeamMembersPage = ( - id: string | string[] | undefined, - page: React.ReactElement -) => { - return ( - { - redirect(`/settings/organizations/${id}/add-teams`); - }}> - {page} - - ); -}; - -OnboardTeamMembersPage.PageWrapper = PageWrapper; - -export default OnboardTeamMembersPage; +export default Page; +export { getServerSideProps }; diff --git a/apps/web/pages/settings/organizations/new/index.tsx b/apps/web/pages/settings/organizations/new/index.tsx index 2ff5cc9d77..a2f41ca5a0 100644 --- a/apps/web/pages/settings/organizations/new/index.tsx +++ b/apps/web/pages/settings/organizations/new/index.tsx @@ -1,16 +1,14 @@ -"use client"; - import LicenseRequired from "@calcom/features/ee/common/components/LicenseRequired"; -import { CreateANewOrganizationForm } from "@calcom/features/ee/organizations/components"; import { useLocale } from "@calcom/lib/hooks/useLocale"; -import { WizardLayout, Meta } from "@calcom/ui"; +import { Meta } from "@calcom/ui"; import { getServerSideProps } from "@lib/settings/organizations/new/getServerSideProps"; -import type { inferSSRProps } from "@lib/types/inferSSRProps"; import PageWrapper from "@components/PageWrapper"; -const CreateNewOrganizationPage = ({ querySlug }: inferSSRProps) => { +import CreateANewOrganizationForm, { LayoutWrapper } from "~/settings/organizations/new/create-new-view"; + +const Page = () => { const { t } = useLocale(); return ( @@ -19,17 +17,10 @@ const CreateNewOrganizationPage = ({ querySlug }: inferSSRProps ); }; -export const LayoutWrapper = (page: React.ReactElement) => { - return ( - - {page} - - ); -}; -CreateNewOrganizationPage.getLayout = LayoutWrapper; -CreateNewOrganizationPage.PageWrapper = PageWrapper; +Page.getLayout = LayoutWrapper; +Page.PageWrapper = PageWrapper; -export default CreateNewOrganizationPage; +export default Page; export { getServerSideProps }; diff --git a/apps/web/pages/settings/platform/index.tsx b/apps/web/pages/settings/platform/index.tsx index 3e87323f39..3d02917526 100644 --- a/apps/web/pages/settings/platform/index.tsx +++ b/apps/web/pages/settings/platform/index.tsx @@ -1,108 +1,12 @@ -import { QueryClientProvider, QueryClient } from "@tanstack/react-query"; -import { useState, useEffect } from "react"; - -import Shell from "@calcom/features/shell/Shell"; -import { showToast } from "@calcom/ui"; - -import { - useOAuthClients, - useGetOAuthClientManagedUsers, -} from "@lib/hooks/settings/platform/oauth-clients/useOAuthClients"; -import { useDeleteOAuthClient } from "@lib/hooks/settings/platform/oauth-clients/usePersistOAuthClient"; - import PageWrapper from "@components/PageWrapper"; -import { HelpCards } from "@components/settings/platform/dashboard/HelpCards"; -import NoPlatformPlan from "@components/settings/platform/dashboard/NoPlatformPlan"; -import { ManagedUserList } from "@components/settings/platform/dashboard/managed-user-list"; -import { OAuthClientsList } from "@components/settings/platform/dashboard/oauth-clients-list"; -import { useGetUserAttributes } from "@components/settings/platform/hooks/useGetUserAttributes"; -import { PlatformPricing } from "@components/settings/platform/pricing/platform-pricing"; -const queryClient = new QueryClient(); +import PlatformView from "~/settings/platform/platform-view"; -export default function Platform() { - const [initialClientId, setInitialClientId] = useState(""); - const [initialClientName, setInitialClientName] = useState(""); +const Page = new Proxy<{ + (): JSX.Element; + PageWrapper?: typeof PageWrapper; +}>(PlatformView, {}); - const { data, isLoading: isOAuthClientLoading, refetch: refetchClients } = useOAuthClients(); - const { - isLoading: isManagedUserLoading, - data: managedUserData, - refetch: refetchManagedUsers, - } = useGetOAuthClientManagedUsers(initialClientId); +Page.PageWrapper = PageWrapper; - const { isUserLoading, isUserBillingDataLoading, isPlatformUser, isPaidUser, userBillingData, userOrgId } = - useGetUserAttributes(); - - const { mutateAsync, isPending: isDeleting } = useDeleteOAuthClient({ - onSuccess: () => { - showToast("OAuth client deleted successfully", "success"); - refetchClients(); - refetchManagedUsers(); - }, - }); - - const handleDelete = async (id: string) => { - await mutateAsync({ id: id }); - }; - - useEffect(() => { - setInitialClientId(data[0]?.id); - setInitialClientName(data[0]?.name); - }, [data]); - - if (isUserLoading || isOAuthClientLoading) return
Loading...
; - - if (isUserBillingDataLoading && !userBillingData) { - return
Loading...
; - } - - if (isPlatformUser && !isPaidUser) return ; - - if (isPlatformUser) { - return ( - -
- - - - { - setInitialClientId(id); - setInitialClientName(name); - refetchManagedUsers(); - }} - /> - -
-
- ); - } - - return ( -
- }> - - -
- ); -} - -Platform.PageWrapper = PageWrapper; +export default Page; diff --git a/apps/web/pages/settings/platform/new/index.tsx b/apps/web/pages/settings/platform/new/index.tsx index 40070a6db8..459f4f7009 100644 --- a/apps/web/pages/settings/platform/new/index.tsx +++ b/apps/web/pages/settings/platform/new/index.tsx @@ -1,15 +1,14 @@ -"use client"; - import LicenseRequired from "@calcom/features/ee/common/components/LicenseRequired"; -import { CreateANewPlatformForm } from "@calcom/features/ee/platform/components/index"; import { useLocale } from "@calcom/lib/hooks/useLocale"; -import { WizardLayout, Meta } from "@calcom/ui"; +import { Meta } from "@calcom/ui"; import { getServerSideProps } from "@lib/settings/organizations/new/getServerSideProps"; import PageWrapper from "@components/PageWrapper"; -const CreateNewOrganizationPage = () => { +import CreateNewOrganizationPage, { LayoutWrapper } from "~/settings/platform/new/create-new-view"; + +const Page = () => { const { t } = useLocale(); return ( @@ -17,21 +16,14 @@ const CreateNewOrganizationPage = () => { title={t("set_up_your_platform_organization")} description={t("platform_organization_description")} /> - + ); }; -export const LayoutWrapper = (page: React.ReactElement) => { - return ( - - {page} - - ); -}; -CreateNewOrganizationPage.getLayout = LayoutWrapper; -CreateNewOrganizationPage.PageWrapper = PageWrapper; +Page.getLayout = LayoutWrapper; +Page.PageWrapper = PageWrapper; -export default CreateNewOrganizationPage; +export default Page; export { getServerSideProps }; diff --git a/apps/web/pages/settings/platform/oauth-clients/[clientId]/edit/index.tsx b/apps/web/pages/settings/platform/oauth-clients/[clientId]/edit/index.tsx index d2ea3caab3..5588eacbc3 100644 --- a/apps/web/pages/settings/platform/oauth-clients/[clientId]/edit/index.tsx +++ b/apps/web/pages/settings/platform/oauth-clients/[clientId]/edit/index.tsx @@ -1,134 +1,12 @@ -import { useParams } from "next/navigation"; -import { useRouter } from "next/navigation"; - -import Shell from "@calcom/features/shell/Shell"; -import { ErrorCode } from "@calcom/lib/errorCodes"; -import { PERMISSIONS_GROUPED_MAP } from "@calcom/platform-constants"; -import { showToast } from "@calcom/ui"; - -import { useOAuthClient } from "@lib/hooks/settings/platform/oauth-clients/useOAuthClients"; -import { useUpdateOAuthClient } from "@lib/hooks/settings/platform/oauth-clients/usePersistOAuthClient"; - import PageWrapper from "@components/PageWrapper"; -import NoPlatformPlan from "@components/settings/platform/dashboard/NoPlatformPlan"; -import { useGetUserAttributes } from "@components/settings/platform/hooks/useGetUserAttributes"; -import type { FormValues } from "@components/settings/platform/oauth-clients/oauth-client-form"; -import { OAuthClientForm as EditOAuthClientForm } from "@components/settings/platform/oauth-clients/oauth-client-form"; -import { - hasAppsReadPermission, - hasAppsWritePermission, - hasBookingReadPermission, - hasBookingWritePermission, - hasEventTypeReadPermission, - hasEventTypeWritePermission, - hasProfileReadPermission, - hasProfileWritePermission, - hasScheduleReadPermission, - hasScheduleWritePermission, -} from "../../../../../../../../packages/platform/utils/permissions"; +import EditView from "~/settings/platform/oauth-clients/[clientId]/edit/edit-view"; -export default function EditOAuthClient() { - const router = useRouter(); - const params = useParams<{ clientId: string }>(); - const clientId = params?.clientId || ""; +const Page = new Proxy<{ + (): JSX.Element; + PageWrapper?: typeof PageWrapper; +}>(EditView, {}); - const { isUserLoading, isPlatformUser, isPaidUser } = useGetUserAttributes(); +Page.PageWrapper = PageWrapper; - const { data, isFetched, isFetching, isError, refetch } = useOAuthClient(clientId); - const { mutateAsync: update, isPending: isUpdating } = useUpdateOAuthClient({ - onSuccess: () => { - showToast("OAuth client updated successfully", "success"); - refetch(); - router.push("/settings/platform/"); - }, - onError: () => { - showToast(ErrorCode.UpdatingOauthClientError, "error"); - }, - clientId, - }); - - const onSubmit = (data: FormValues) => { - let userPermissions = 0; - const userRedirectUris = data.redirectUris.map((uri) => uri.uri).filter((uri) => !!uri); - - Object.keys(PERMISSIONS_GROUPED_MAP).forEach((key) => { - const entity = key as keyof typeof PERMISSIONS_GROUPED_MAP; - const entityKey = PERMISSIONS_GROUPED_MAP[entity].key; - const read = PERMISSIONS_GROUPED_MAP[entity].read; - const write = PERMISSIONS_GROUPED_MAP[entity].write; - if (data[`${entityKey}Read`]) userPermissions |= read; - if (data[`${entityKey}Write`]) userPermissions |= write; - }); - - update({ - name: data.name, - // logo: data.logo, - redirectUris: userRedirectUris, - bookingRedirectUri: data.bookingRedirectUri, - bookingCancelRedirectUri: data.bookingCancelRedirectUri, - bookingRescheduleRedirectUri: data.bookingRescheduleRedirectUri, - areEmailsEnabled: data.areEmailsEnabled, - }); - }; - - if (isUserLoading) return
Loading...
; - - if (isPlatformUser && isPaidUser) { - return ( -
- -
-
-
-

- OAuth client updation form -

-

- This is the form to edit an existing OAuth client -

-
-
- {(!Boolean(clientId) || (isFetched && !data)) &&

OAuth Client not found.

} - {isFetched && !!data && ( - ({ uri })) ?? [{ uri: "" }], - bookingRedirectUri: data?.bookingRedirectUri ?? "", - bookingCancelRedirectUri: data?.bookingCancelRedirectUri ?? "", - bookingRescheduleRedirectUri: data?.bookingRescheduleRedirectUri ?? "", - appsRead: hasAppsReadPermission(data?.permissions), - appsWrite: hasAppsWritePermission(data?.permissions), - bookingRead: hasBookingReadPermission(data?.permissions), - bookingWrite: hasBookingWritePermission(data?.permissions), - eventTypeRead: hasEventTypeReadPermission(data?.permissions), - eventTypeWrite: hasEventTypeWritePermission(data?.permissions), - profileRead: hasProfileReadPermission(data?.permissions), - profileWrite: hasProfileWritePermission(data?.permissions), - scheduleRead: hasScheduleReadPermission(data?.permissions), - scheduleWrite: hasScheduleWritePermission(data?.permissions), - }} - onSubmit={onSubmit} - isPending={isUpdating} - /> - )} - {isFetching &&

Loading...

} - {isError &&

Something went wrong.

} -
-
-
- ); - } - - return ( -
- }> - - -
- ); -} - -EditOAuthClient.PageWrapper = PageWrapper; +export default Page; diff --git a/apps/web/pages/settings/platform/oauth-clients/[clientId]/edit/webhooks.tsx b/apps/web/pages/settings/platform/oauth-clients/[clientId]/edit/webhooks.tsx index 07ee6363e1..818de3ef2c 100644 --- a/apps/web/pages/settings/platform/oauth-clients/[clientId]/edit/webhooks.tsx +++ b/apps/web/pages/settings/platform/oauth-clients/[clientId]/edit/webhooks.tsx @@ -1,123 +1,12 @@ -import { useParams } from "next/navigation"; -import { useRouter } from "next/navigation"; - -import Shell from "@calcom/features/shell/Shell"; -import { WebhookForm } from "@calcom/features/webhooks/components"; -import { WebhookTriggerEvents } from "@calcom/prisma/enums"; -import { showToast } from "@calcom/ui"; - -import { - useOAuthClientWebhooks, - useCreateOAuthClientWebhook, - useUpdateOAuthClientWebhook, -} from "@lib/hooks/settings/platform/oauth-clients/useOAuthClientWebhooks"; - import PageWrapper from "@components/PageWrapper"; -import NoPlatformPlan from "@components/settings/platform/dashboard/NoPlatformPlan"; -import { useGetUserAttributes } from "@components/settings/platform/hooks/useGetUserAttributes"; -export default function EditOAuthClientWebhooks() { - const router = useRouter(); - const params = useParams<{ clientId: string }>(); - const clientId = params?.clientId || ""; +import EditWebhooksView from "~/settings/platform/oauth-clients/[clientId]/edit/edit-webhooks-view"; - const { isUserLoading, isPlatformUser, isPaidUser } = useGetUserAttributes(); +const Page = new Proxy<{ + (): JSX.Element; + PageWrapper?: typeof PageWrapper; +}>(EditWebhooksView, {}); - const { - data: webhooks, - status: webhooksStatus, - isFetched: isWebhooksFetched, - refetch: refetchWebhooks, - } = useOAuthClientWebhooks(clientId); - const webhookId = webhooks?.[0]?.id ?? ""; - const webhook = webhooks?.[0]; - const { mutateAsync: createWebhook } = useCreateOAuthClientWebhook(clientId); - const { mutateAsync: updateWebhook } = useUpdateOAuthClientWebhook(clientId); +Page.PageWrapper = PageWrapper; - if (isUserLoading) return
Loading...
; - - if (isPlatformUser && isPaidUser) { - return ( -
- -
-
-
-

- Webhook update form -

-

Add a webhook to your OAuthClient.

-
-
- - {webhooksStatus !== "success" &&

Error while trying to access webhooks.

} - - {isWebhooksFetched && webhooksStatus === "success" && ( - { - try { - const body = { - active: data.active, - payloadTemplate: data.payloadTemplate ?? undefined, - subscriberUrl: data.subscriberUrl, - triggers: data.eventTriggers, - secret: data.secret ?? undefined, - }; - if (webhook) { - await updateWebhook({ - webhookId, - body, - }); - showToast("Webhook updated successfully.", "success"); - } else { - await createWebhook(body); - showToast("Webhook created successfully.", "success"); - } - await refetchWebhooks(); - router.push("/settings/platform/"); - } catch (err) { - showToast(`Failed to ${webhookId ? "update" : "create"} webhook.`, "error"); - } - }} - onCancel={() => { - router.push("/settings/platform/"); - }} - noRoutingFormTriggers={true} - webhook={ - webhook - ? { ...webhook, eventTriggers: webhook.triggers, secret: webhook.secret ?? null } - : undefined - } - /> - )} -
-
-
- ); - } - - return ( -
- }> - - -
- ); -} - -EditOAuthClientWebhooks.PageWrapper = PageWrapper; +export default Page; diff --git a/apps/web/pages/settings/platform/oauth-clients/create.tsx b/apps/web/pages/settings/platform/oauth-clients/create.tsx index 3720498a6a..593eef06ff 100644 --- a/apps/web/pages/settings/platform/oauth-clients/create.tsx +++ b/apps/web/pages/settings/platform/oauth-clients/create.tsx @@ -1,92 +1,12 @@ -import { useRouter } from "next/navigation"; - -import Shell from "@calcom/features/shell/Shell"; -import { ErrorCode } from "@calcom/lib/errorCodes"; -import { useCompatSearchParams } from "@calcom/lib/hooks/useCompatSearchParams"; -import { PERMISSIONS_GROUPED_MAP } from "@calcom/platform-constants/permissions"; -import { showToast } from "@calcom/ui"; - -import { useCreateOAuthClient } from "@lib/hooks/settings/platform/oauth-clients/usePersistOAuthClient"; - import PageWrapper from "@components/PageWrapper"; -import NoPlatformPlan from "@components/settings/platform/dashboard/NoPlatformPlan"; -import { useGetUserAttributes } from "@components/settings/platform/hooks/useGetUserAttributes"; -import type { FormValues } from "@components/settings/platform/oauth-clients/oauth-client-form"; -import { OAuthClientForm } from "@components/settings/platform/oauth-clients/oauth-client-form"; -export default function CreateOAuthClient() { - const searchParams = useCompatSearchParams(); - const router = useRouter(); - const clientId = searchParams?.get("clientId") || ""; +import CreateOAuthClientView from "~/settings/platform/oauth-clients/create-new-view"; - const { isUserLoading, isPlatformUser, isPaidUser } = useGetUserAttributes(); +const Page = new Proxy<{ + (): JSX.Element; + PageWrapper?: typeof PageWrapper; +}>(CreateOAuthClientView, {}); - const { mutateAsync: save, isPending: isSaving } = useCreateOAuthClient({ - onSuccess: () => { - showToast("OAuth client created successfully", "success"); - router.push("/settings/platform/"); - }, - onError: () => { - showToast(ErrorCode.CreatingOauthClientError, "error"); - }, - }); +Page.PageWrapper = PageWrapper; - const onSubmit = (data: FormValues) => { - let userPermissions = 0; - const userRedirectUris = data.redirectUris.map((uri) => uri.uri).filter((uri) => !!uri); - - Object.keys(PERMISSIONS_GROUPED_MAP).forEach((key) => { - const entity = key as keyof typeof PERMISSIONS_GROUPED_MAP; - const entityKey = PERMISSIONS_GROUPED_MAP[entity].key; - const read = PERMISSIONS_GROUPED_MAP[entity].read; - const write = PERMISSIONS_GROUPED_MAP[entity].write; - if (data[`${entityKey}Read`]) userPermissions |= read; - if (data[`${entityKey}Write`]) userPermissions |= write; - }); - - save({ - name: data.name, - permissions: userPermissions, - // logo: data.logo, - redirectUris: userRedirectUris, - bookingRedirectUri: data.bookingRedirectUri, - bookingCancelRedirectUri: data.bookingCancelRedirectUri, - bookingRescheduleRedirectUri: data.bookingRescheduleRedirectUri, - areEmailsEnabled: data.areEmailsEnabled, - }); - }; - - if (isUserLoading) return
Loading...
; - - if (isPlatformUser && isPaidUser) { - return ( -
- -
-
-
-

- OAuth client creation form -

-

- This is the form to create a new OAuth client -

-
-
- -
-
-
- ); - } - - return ( -
- }> - - -
- ); -} - -CreateOAuthClient.PageWrapper = PageWrapper; +export default Page; diff --git a/apps/web/scripts/vercel-app-router-deploy.sh b/apps/web/scripts/vercel-app-router-deploy.sh index 8153fb8823..f8d4ceb863 100755 --- a/apps/web/scripts/vercel-app-router-deploy.sh +++ b/apps/web/scripts/vercel-app-router-deploy.sh @@ -9,6 +9,8 @@ checkRoute () { checkRoute "$APP_ROUTER_EVENT_TYPES_ENABLED" app/future/event-types checkRoute "$APP_ROUTER_AVAILABILITY_ENABLED" app/future/availability checkRoute "$APP_ROUTER_SETTINGS_ADMIN_ENABLED" app/future/settings/admin +checkRoute "$APP_ROUTER_SETTINGS_PLATFORM_ENABLED" app/future/settings/platform +checkRoute "$APP_ROUTER_SETTINGS_ORG_ENABLED" app/future/settings/organizations checkRoute "$APP_ROUTER_APPS_INSTALLED_CATEGORY_ENABLED" app/future/apps/installed checkRoute "$APP_ROUTER_APPS_SLUG_ENABLED" app/future/apps/\[slug\] checkRoute "$APP_ROUTER_APPS_SLUG_SETUP_ENABLED" app/future/apps/\[slug\]/setup diff --git a/packages/features/ee/organizations/components/AboutOrganizationForm.tsx b/packages/features/ee/organizations/components/AboutOrganizationForm.tsx index 8559813508..a62b65eb58 100644 --- a/packages/features/ee/organizations/components/AboutOrganizationForm.tsx +++ b/packages/features/ee/organizations/components/AboutOrganizationForm.tsx @@ -1,3 +1,5 @@ +"use client"; + import { useRouter } from "next/navigation"; import { useState } from "react"; import { Controller, useForm } from "react-hook-form"; diff --git a/packages/features/ee/organizations/components/AddNewTeamsForm.tsx b/packages/features/ee/organizations/components/AddNewTeamsForm.tsx index d049b59d3b..c33a595288 100644 --- a/packages/features/ee/organizations/components/AddNewTeamsForm.tsx +++ b/packages/features/ee/organizations/components/AddNewTeamsForm.tsx @@ -1,3 +1,5 @@ +"use client"; + import { useSession } from "next-auth/react"; import { useRouter } from "next/navigation"; import { useState } from "react"; diff --git a/packages/features/ee/organizations/components/CreateANewOrganizationForm.tsx b/packages/features/ee/organizations/components/CreateANewOrganizationForm.tsx index 5e590f4e2b..d03faceb8d 100644 --- a/packages/features/ee/organizations/components/CreateANewOrganizationForm.tsx +++ b/packages/features/ee/organizations/components/CreateANewOrganizationForm.tsx @@ -1,3 +1,5 @@ +"use client"; + import type { SessionContextValue } from "next-auth/react"; import { signIn, useSession } from "next-auth/react"; import { useRouter } from "next/navigation"; diff --git a/packages/features/ee/platform/components/CreateANewPlatformForm.tsx b/packages/features/ee/platform/components/CreateANewPlatformForm.tsx index f4cc3f4b97..9567878eaa 100644 --- a/packages/features/ee/platform/components/CreateANewPlatformForm.tsx +++ b/packages/features/ee/platform/components/CreateANewPlatformForm.tsx @@ -1,3 +1,5 @@ +"use client"; + import type { SessionContextValue } from "next-auth/react"; import { useSession, signIn } from "next-auth/react"; import { useRouter } from "next/navigation"; diff --git a/turbo.json b/turbo.json index 42223ff478..d50b4d2d98 100644 --- a/turbo.json +++ b/turbo.json @@ -236,6 +236,8 @@ "APP_ROUTER_EVENT_TYPES_ENABLED", "APP_ROUTER_GETTING_STARTED_STEP_ENABLED", "APP_ROUTER_SETTINGS_ADMIN_ENABLED", + "APP_ROUTER_SETTINGS_PLATFORM_ENABLED", + "APP_ROUTER_SETTINGS_ORG_ENABLED", "APP_ROUTER_SETTINGS_TEAMS_ENABLED", "APP_ROUTER_WORKFLOWS_ENABLED", "APP_ROUTER_VIDEO_ENABLED",