diff --git a/apps/web/app/(use-page-wrapper)/settings/organizations/[id]/members/layout.tsx b/apps/web/app/(use-page-wrapper)/settings/organizations/[id]/members/layout.tsx
new file mode 100644
index 0000000000..7403ef82cd
--- /dev/null
+++ b/apps/web/app/(use-page-wrapper)/settings/organizations/[id]/members/layout.tsx
@@ -0,0 +1,19 @@
+import { getTranslate } from "app/_utils";
+
+import { CTA_CONTAINER_CLASS_NAME } from "@calcom/features/data-table/lib/utils";
+import Shell from "@calcom/features/shell/Shell";
+
+export default async function Layout({ children }: { children: React.ReactNode }) {
+ const t = await getTranslate();
+
+ return (
+ }>
+ {children}
+
+ );
+}
diff --git a/apps/web/app/(use-page-wrapper)/settings/organizations/[id]/members/loading.tsx b/apps/web/app/(use-page-wrapper)/settings/organizations/[id]/members/loading.tsx
new file mode 100644
index 0000000000..489822d2d6
--- /dev/null
+++ b/apps/web/app/(use-page-wrapper)/settings/organizations/[id]/members/loading.tsx
@@ -0,0 +1,5 @@
+import { UserListTableSkeleton } from "@calcom/features/users/components/UserTable/UserListTableSkeleton";
+
+export default function Loading() {
+ return ;
+}
diff --git a/apps/web/app/(use-page-wrapper)/settings/organizations/[id]/members/page.tsx b/apps/web/app/(use-page-wrapper)/settings/organizations/[id]/members/page.tsx
index e22b5193d5..5e15a03a6a 100644
--- a/apps/web/app/(use-page-wrapper)/settings/organizations/[id]/members/page.tsx
+++ b/apps/web/app/(use-page-wrapper)/settings/organizations/[id]/members/page.tsx
@@ -1,6 +1,10 @@
+import { createRouterCaller } from "app/_trpc/context";
import { _generateMetadata } from "app/_utils";
-import MembersPage from "~/members/members-view";
+import { attributesRouter } from "@calcom/trpc/server/routers/viewer/attributes/_router";
+import { viewerOrganizationsRouter } from "@calcom/trpc/server/routers/viewer/organizations/_router";
+
+import { MembersView } from "~/members/members-view";
export const generateMetadata = async ({ params }: { params: Promise<{ id: string }> }) =>
await _generateMetadata(
@@ -11,8 +15,20 @@ export const generateMetadata = async ({ params }: { params: Promise<{ id: strin
`/settings/organizations/${(await params).id}/members`
);
-const ServerPageWrapper = () => {
- return ;
+const ServerPageWrapper = async () => {
+ const [orgCaller, attributesCaller] = await Promise.all([
+ createRouterCaller(viewerOrganizationsRouter),
+ createRouterCaller(attributesRouter),
+ ]);
+ const [org, teams, facetedTeamValues, attributes] = await Promise.all([
+ orgCaller.listCurrent(),
+ orgCaller.getTeams(),
+ orgCaller.getFacetedValues(),
+ attributesCaller.list(),
+ ]);
+ return (
+
+ );
};
export default ServerPageWrapper;
diff --git a/apps/web/app/(use-page-wrapper)/settings/organizations/members/layout.tsx b/apps/web/app/(use-page-wrapper)/settings/organizations/members/layout.tsx
new file mode 100644
index 0000000000..deb88ac86d
--- /dev/null
+++ b/apps/web/app/(use-page-wrapper)/settings/organizations/members/layout.tsx
@@ -0,0 +1,20 @@
+import SettingsLayoutAppDirClient from "app/(use-page-wrapper)/settings/(settings-layout)/SettingsLayoutAppDirClient";
+import { getTranslate } from "app/_utils";
+
+import { CTA_CONTAINER_CLASS_NAME } from "@calcom/features/data-table/lib/utils";
+import SettingsHeader from "@calcom/features/settings/appDir/SettingsHeader";
+
+export default async function Layout({ children }: { children: React.ReactNode }) {
+ const t = await getTranslate();
+
+ return (
+
+
+ {children}
+
+
+ );
+}
diff --git a/apps/web/app/(use-page-wrapper)/settings/organizations/members/loading.tsx b/apps/web/app/(use-page-wrapper)/settings/organizations/members/loading.tsx
new file mode 100644
index 0000000000..489822d2d6
--- /dev/null
+++ b/apps/web/app/(use-page-wrapper)/settings/organizations/members/loading.tsx
@@ -0,0 +1,5 @@
+import { UserListTableSkeleton } from "@calcom/features/users/components/UserTable/UserListTableSkeleton";
+
+export default function Loading() {
+ return ;
+}
diff --git a/apps/web/app/(use-page-wrapper)/settings/organizations/members/page.tsx b/apps/web/app/(use-page-wrapper)/settings/organizations/members/page.tsx
index e097bc493a..6a499d66af 100644
--- a/apps/web/app/(use-page-wrapper)/settings/organizations/members/page.tsx
+++ b/apps/web/app/(use-page-wrapper)/settings/organizations/members/page.tsx
@@ -1,9 +1,10 @@
-import SettingsLayoutAppDir from "app/(use-page-wrapper)/settings/(settings-layout)/layout";
-import { _generateMetadata, getTranslate } from "app/_utils";
+import { createRouterCaller } from "app/_trpc/context";
+import { _generateMetadata } from "app/_utils";
-import { CTA_CONTAINER_CLASS_NAME } from "@calcom/features/data-table/lib/utils";
-import LegacyPage from "@calcom/features/ee/organizations/pages/members";
-import SettingsHeader from "@calcom/features/settings/appDir/SettingsHeader";
+import { attributesRouter } from "@calcom/trpc/server/routers/viewer/attributes/_router";
+import { viewerOrganizationsRouter } from "@calcom/trpc/server/routers/viewer/organizations/_router";
+
+import { MembersView } from "~/members/members-view";
export const generateMetadata = async () =>
await _generateMetadata(
@@ -15,17 +16,20 @@ export const generateMetadata = async () =>
);
const Page = async () => {
- const t = await getTranslate();
+ const [orgCaller, attributesCaller] = await Promise.all([
+ createRouterCaller(viewerOrganizationsRouter),
+ createRouterCaller(attributesRouter),
+ ]);
+ const [org, teams, facetedTeamValues, attributes] = await Promise.all([
+ orgCaller.listCurrent(),
+ orgCaller.getTeams(),
+ orgCaller.getFacetedValues(),
+ attributesCaller.list(),
+ ]);
- const children = (
-
-
-
+ return (
+
);
- return await SettingsLayoutAppDir({ children, containerClassName: "lg:max-w-screen-2xl" });
};
export default Page;
diff --git a/apps/web/app/(use-page-wrapper)/settings/platform/members/layout.tsx b/apps/web/app/(use-page-wrapper)/settings/platform/members/layout.tsx
new file mode 100644
index 0000000000..76a42b69f9
--- /dev/null
+++ b/apps/web/app/(use-page-wrapper)/settings/platform/members/layout.tsx
@@ -0,0 +1,33 @@
+import { getTranslate } from "app/_utils";
+
+import { CTA_CONTAINER_CLASS_NAME } from "@calcom/features/data-table/lib/utils";
+import Shell from "@calcom/features/shell/Shell";
+import { Button } from "@calcom/ui/components/button";
+
+export default async function Layout({ children }: { children: React.ReactNode }) {
+ const t = await getTranslate();
+
+ return (
+
+ Member management
+
+
+ }
+ title={t("platform_members")}
+ subtitle={t("platform_members_description")}
+ withoutMain={false}
+ isPlatformUser={true}
+ actions={}>
+ {children}
+
+ );
+}
diff --git a/apps/web/app/(use-page-wrapper)/settings/platform/members/loading.tsx b/apps/web/app/(use-page-wrapper)/settings/platform/members/loading.tsx
new file mode 100644
index 0000000000..489822d2d6
--- /dev/null
+++ b/apps/web/app/(use-page-wrapper)/settings/platform/members/loading.tsx
@@ -0,0 +1,5 @@
+import { UserListTableSkeleton } from "@calcom/features/users/components/UserTable/UserListTableSkeleton";
+
+export default function Loading() {
+ return ;
+}
diff --git a/apps/web/app/(use-page-wrapper)/settings/platform/members/page.tsx b/apps/web/app/(use-page-wrapper)/settings/platform/members/page.tsx
index 7f59327f20..47d5fcda48 100644
--- a/apps/web/app/(use-page-wrapper)/settings/platform/members/page.tsx
+++ b/apps/web/app/(use-page-wrapper)/settings/platform/members/page.tsx
@@ -1,6 +1,9 @@
+import { createRouterCaller } from "app/_trpc/context";
import { _generateMetadata } from "app/_utils";
import PlatformMembersView from "@calcom/features/ee/platform/pages/settings/members";
+import { attributesRouter } from "@calcom/trpc/server/routers/viewer/attributes/_router";
+import { viewerOrganizationsRouter } from "@calcom/trpc/server/routers/viewer/organizations/_router";
export const generateMetadata = async () =>
await _generateMetadata(
@@ -11,8 +14,26 @@ export const generateMetadata = async () =>
"/settings/platform/members"
);
-const ServerPageWrapper = () => {
- return ;
+const ServerPageWrapper = async () => {
+ const [orgCaller, attributesCaller] = await Promise.all([
+ createRouterCaller(viewerOrganizationsRouter),
+ createRouterCaller(attributesRouter),
+ ]);
+ const [org, teams, facetedTeamValues, attributes] = await Promise.all([
+ orgCaller.listCurrent(),
+ orgCaller.getTeams(),
+ orgCaller.getFacetedValues(),
+ attributesCaller.list(),
+ ]);
+
+ return (
+
+ );
};
export default ServerPageWrapper;
diff --git a/apps/web/modules/members/members-view.tsx b/apps/web/modules/members/members-view.tsx
index 3af6de5c17..123e562419 100644
--- a/apps/web/modules/members/members-view.tsx
+++ b/apps/web/modules/members/members-view.tsx
@@ -1,24 +1,25 @@
"use client";
-import { CTA_CONTAINER_CLASS_NAME } from "@calcom/features/data-table/lib/utils";
-import MembersView from "@calcom/features/ee/organizations/pages/members";
-import Shell from "@calcom/features/shell/Shell";
+import { checkAdminOrOwner } from "@calcom/features/auth/lib/checkAdminOrOwner";
+import LicenseRequired from "@calcom/features/ee/common/components/LicenseRequired";
+import { UserListTable } from "@calcom/features/users/components/UserTable/UserListTable";
+import type { UserListTableProps } from "@calcom/features/users/components/UserTable/UserListTable";
import { useLocale } from "@calcom/lib/hooks/useLocale";
-const MembersPage: React.FC = () => {
+export const MembersView = (props: UserListTableProps) => {
const { t } = useLocale();
+ const isOrgAdminOrOwner = props.org && checkAdminOrOwner(props.org.user.role);
+ const canLoggedInUserSeeMembers =
+ (props.org?.isPrivate && isOrgAdminOrOwner) || isOrgAdminOrOwner || !props.org?.isPrivate;
+
return (
- }>
-
-
+
+ {canLoggedInUserSeeMembers && }
+ {!canLoggedInUserSeeMembers && (
+
+
{t("only_admin_can_see_members_of_org")}
+
+ )}
+
);
};
-
-export default MembersPage;
diff --git a/packages/features/ee/organizations/pages/members.tsx b/packages/features/ee/organizations/pages/members.tsx
deleted file mode 100644
index 7662a6687c..0000000000
--- a/packages/features/ee/organizations/pages/members.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-"use client";
-
-import { checkAdminOrOwner } from "@calcom/features/auth/lib/checkAdminOrOwner";
-import LicenseRequired from "@calcom/features/ee/common/components/LicenseRequired";
-import { UserListTable } from "@calcom/features/users/components/UserTable/UserListTable";
-import { useLocale } from "@calcom/lib/hooks/useLocale";
-import { trpc } from "@calcom/trpc/react";
-
-const MembersView = () => {
- const { t } = useLocale();
- const { data: currentOrg, isPending } = trpc.viewer.organizations.listCurrent.useQuery();
-
- const isOrgAdminOrOwner = currentOrg && checkAdminOrOwner(currentOrg.user.role);
-
- const canLoggedInUserSeeMembers =
- (currentOrg?.isPrivate && isOrgAdminOrOwner) || isOrgAdminOrOwner || !currentOrg?.isPrivate;
-
- return (
-
- {!isPending && canLoggedInUserSeeMembers && }
- {!canLoggedInUserSeeMembers && (
-
-
{t("only_admin_can_see_members_of_org")}
-
- )}
-
- );
-};
-
-export default MembersView;
diff --git a/packages/features/ee/platform/pages/settings/members.tsx b/packages/features/ee/platform/pages/settings/members.tsx
index 930ea36bc6..189b3a3255 100644
--- a/packages/features/ee/platform/pages/settings/members.tsx
+++ b/packages/features/ee/platform/pages/settings/members.tsx
@@ -1,29 +1,24 @@
"use client";
import { checkAdminOrOwner } from "@calcom/features/auth/lib/checkAdminOrOwner";
-import { CTA_CONTAINER_CLASS_NAME } from "@calcom/features/data-table/lib/utils";
-import Shell from "@calcom/features/shell/Shell";
import { UserListTable } from "@calcom/features/users/components/UserTable/UserListTable";
-import { useLocale } from "@calcom/lib/hooks/useLocale";
-import { trpc } from "@calcom/trpc/react";
-import { Button } from "@calcom/ui/components/button";
+import type { UserListTableProps } from "@calcom/features/users/components/UserTable/UserListTable";
+import { UserListTableSkeleton } from "@calcom/features/users/components/UserTable/UserListTableSkeleton";
import NoPlatformPlan from "@calcom/web/components/settings/platform/dashboard/NoPlatformPlan";
import { useGetUserAttributes } from "@calcom/web/components/settings/platform/hooks/useGetUserAttributes";
import { PlatformPricing } from "@calcom/web/components/settings/platform/pricing/platform-pricing/index";
-const PlatformMembersView = () => {
- const { t } = useLocale();
+const PlatformMembersView = (props: UserListTableProps) => {
const { isUserLoading, isUserBillingDataLoading, isPlatformUser, isPaidUser, userBillingData, userOrgId } =
useGetUserAttributes();
- const { data: currentOrg, isPending } = trpc.viewer.organizations.listCurrent.useQuery();
-
+ const currentOrg = props.org;
const isOrgAdminOrOwner = currentOrg && checkAdminOrOwner(currentOrg.user.role);
const canLoggedInUserSeeMembers =
(currentOrg?.isPrivate && isOrgAdminOrOwner) || isOrgAdminOrOwner || !currentOrg?.isPrivate;
if (isUserLoading || (isUserBillingDataLoading && !userBillingData)) {
- return Loading...
;
+ return ;
}
if (isPlatformUser && !isPaidUser)
@@ -38,37 +33,10 @@ const PlatformMembersView = () => {
/>
);
- if (!isPlatformUser)
- return (
-
- >}>
-
-
-
- );
-
- return (
-
- Member management
-
-
- }
- title={t("platform_members")}
- subtitle={t("platform_members_description")}
- withoutMain={false}
- isPlatformUser={true}
- actions={}>
- {!isPending && canLoggedInUserSeeMembers && }
-
+ return !isPlatformUser ? (
+ {canLoggedInUserSeeMembers && }
+ ) : (
+
);
};
diff --git a/packages/features/users/components/UserTable/UserListTable.tsx b/packages/features/users/components/UserTable/UserListTable.tsx
index 9e0a8a73f5..7fe5506f88 100644
--- a/packages/features/users/components/UserTable/UserListTable.tsx
+++ b/packages/features/users/components/UserTable/UserListTable.tsx
@@ -31,6 +31,7 @@ import {
import { getUserAvatarUrl } from "@calcom/lib/getAvatarUrl";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { trpc } from "@calcom/trpc";
+import type { RouterOutputs } from "@calcom/trpc/react";
import classNames from "@calcom/ui/classNames";
import { Avatar } from "@calcom/ui/components/avatar";
import { Badge } from "@calcom/ui/components/badge";
@@ -105,15 +106,22 @@ function reducer(state: UserTableState, action: UserTableAction): UserTableState
}
}
-export function UserListTable() {
+export type UserListTableProps = {
+ org: RouterOutputs["viewer"]["organizations"]["listCurrent"];
+ teams: RouterOutputs["viewer"]["organizations"]["getTeams"];
+ facetedTeamValues: RouterOutputs["viewer"]["organizations"]["getFacetedValues"];
+ attributes: RouterOutputs["viewer"]["attributes"]["list"];
+};
+
+export function UserListTable(props: UserListTableProps) {
return (
-
+
);
}
-function UserListTableContent() {
+function UserListTableContent({ org, attributes, teams, facetedTeamValues }: UserListTableProps) {
const [dynamicLinkVisible, setDynamicLinkVisible] = useQueryState("dynamicLink", parseAsBoolean);
const orgBranding = useOrgBranding();
const domain = orgBranding?.fullDomain ?? WEBAPP_URL;
@@ -121,22 +129,6 @@ function UserListTableContent() {
const { data: session } = useSession();
const { isPlatformUser } = useGetUserAttributes();
- const { data: org } = trpc.viewer.organizations.listCurrent.useQuery(undefined, {
- refetchOnWindowFocus: false,
- });
- const { data: attributes, isSuccess: isSuccessAttributes } = trpc.viewer.attributes.list.useQuery(
- undefined,
- {
- refetchOnWindowFocus: false,
- }
- );
- const { data: teams } = trpc.viewer.organizations.getTeams.useQuery(undefined, {
- refetchOnWindowFocus: false,
- });
- const { data: facetedTeamValues } = trpc.viewer.organizations.getFacetedValues.useQuery(undefined, {
- refetchOnWindowFocus: false,
- });
-
const [state, dispatch] = useReducer(reducer, initialState);
const [isDownloading, setIsDownloading] = useState(false);
const [rowSelection, setRowSelection] = useState({});
@@ -561,11 +553,6 @@ function UserListTableContent() {
}
};
- if (!isPlatformUser && !isSuccessAttributes) {
- // do not render the table until the attributes are fetched
- return null;
- }
-
return (
<>
diff --git a/packages/features/users/components/UserTable/UserListTableSkeleton.tsx b/packages/features/users/components/UserTable/UserListTableSkeleton.tsx
new file mode 100644
index 0000000000..dc3389c5a2
--- /dev/null
+++ b/packages/features/users/components/UserTable/UserListTableSkeleton.tsx
@@ -0,0 +1,47 @@
+"use client";
+
+import { DataTableSkeleton } from "@calcom/features/data-table";
+import { CTA_CONTAINER_CLASS_NAME } from "@calcom/features/data-table/lib/utils";
+import { SkeletonButton, SkeletonContainer, SkeletonText } from "@calcom/ui/components/skeleton";
+
+export function UserListTableSkeleton() {
+ return (
+
+ {/* Toolbar with search, filters, etc. */}
+
+
+
+
+ {/* Search bar */}
+
+
+ {/* Filters */}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* DataTable */}
+
+
+ {/* CTA actions at the bottom */}
+
+
+
+
+
+ );
+}