diff --git a/apps/web/app/(use-page-wrapper)/(main-nav)/availability/actions.ts b/apps/web/app/(use-page-wrapper)/(main-nav)/availability/actions.ts
new file mode 100644
index 0000000000..9d240ed673
--- /dev/null
+++ b/apps/web/app/(use-page-wrapper)/(main-nav)/availability/actions.ts
@@ -0,0 +1,7 @@
+"use server";
+
+import { revalidatePath } from "next/cache";
+
+export async function revalidateAvailabilityList() {
+ revalidatePath("/availability");
+}
diff --git a/apps/web/app/(use-page-wrapper)/(main-nav)/availability/loading.tsx b/apps/web/app/(use-page-wrapper)/(main-nav)/availability/loading.tsx
new file mode 100644
index 0000000000..59e435930e
--- /dev/null
+++ b/apps/web/app/(use-page-wrapper)/(main-nav)/availability/loading.tsx
@@ -0,0 +1,5 @@
+import AvailabilityLoader from "app/(use-page-wrapper)/(main-nav)/availability/skeleton";
+
+export default function Loading() {
+ return ;
+}
diff --git a/apps/web/app/(use-page-wrapper)/(main-nav)/availability/page.tsx b/apps/web/app/(use-page-wrapper)/(main-nav)/availability/page.tsx
index d77ad8719a..a7bea5611f 100644
--- a/apps/web/app/(use-page-wrapper)/(main-nav)/availability/page.tsx
+++ b/apps/web/app/(use-page-wrapper)/(main-nav)/availability/page.tsx
@@ -1,11 +1,14 @@
+import { createRouterCaller } from "app/_trpc/context";
+import type { PageProps } from "app/_types";
import { _generateMetadata, getTranslate } from "app/_utils";
-// import { cookies, headers } from "next/headers";
import { notFound } from "next/navigation";
-// import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
-// import { buildLegacyRequest } from "@lib/buildLegacyCtx";
-// import { OrganizationRepository } from "@calcom/lib/server/repository/organization";
-import AvailabilityPage, { AvailabilityCTA } from "~/availability/availability-view";
+import { AvailabilitySliderTable } from "@calcom/features/timezone-buddy/components/AvailabilitySliderTable";
+import { OrganizationRepository } from "@calcom/lib/server/repository/organization";
+import { availabilityRouter } from "@calcom/trpc/server/routers/viewer/availability/_router";
+import { meRouter } from "@calcom/trpc/server/routers/viewer/me/_router";
+
+import { AvailabilityList, AvailabilityCTA } from "~/availability/availability-view";
import { ShellMainAppDir } from "../ShellMainAppDir";
@@ -19,29 +22,44 @@ export const generateMetadata = async () => {
);
};
-const Page = async () => {
- // const session = await getServerSession({ req: buildLegacyRequest(await headers(), await cookies()) });
- // const userId = session?.user?.id;
- // const orgId = session?.user?.org?.id;
- // if (!userId || !orgId) {
- // notFound();
- // }
-
+const Page = async ({ searchParams: _searchParams }: PageProps) => {
+ const searchParams = await _searchParams;
+ const t = await getTranslate();
try {
- // const currentOrg = await OrganizationRepository.findCurrentOrg({
- // orgId,
- // userId,
- // });
- const t = await getTranslate();
+ const [meCaller, availabilityCaller] = await Promise.all([
+ createRouterCaller(meRouter),
+ createRouterCaller(availabilityRouter),
+ ]);
+
+ const [me, availabilities] = await Promise.all([meCaller.get(), availabilityCaller.list()]);
+ const organizationId = me.organization?.id ?? me.profiles[0]?.organizationId;
+ const isOrgPrivate = organizationId
+ ? await OrganizationRepository.checkIfPrivate({
+ orgId: organizationId,
+ })
+ : false;
+ const canViewTeamAvailability = me.organization?.isOrgAdmin || !isOrgPrivate;
+
return (
}>
-
+ CTA={
+
+ }>
+ {searchParams?.type === "team" && canViewTeamAvailability ? (
+
+ ) : (
+
+ )}
);
- } catch {
+ } catch (error) {
notFound();
}
};
diff --git a/apps/web/app/(use-page-wrapper)/(main-nav)/availability/skeleton.tsx b/apps/web/app/(use-page-wrapper)/(main-nav)/availability/skeleton.tsx
new file mode 100644
index 0000000000..d6ad66b184
--- /dev/null
+++ b/apps/web/app/(use-page-wrapper)/(main-nav)/availability/skeleton.tsx
@@ -0,0 +1,25 @@
+"use client";
+
+import { ShellMainAppDir } from "app/(use-page-wrapper)/(main-nav)/ShellMainAppDir";
+
+import SkeletonLoader from "@calcom/features/availability/components/SkeletonLoader";
+import { useLocale } from "@calcom/lib/hooks/useLocale";
+
+import { AvailabilityCTA } from "~/availability/availability-view";
+
+export default function AvailabilityLoader() {
+ const { t } = useLocale();
+ const toggleGroupOptions = [
+ { value: "mine", label: t("my_availability") },
+ { value: "team", label: t("team_availability") },
+ ];
+
+ return (
+ }>
+
+
+ );
+}
diff --git a/apps/web/modules/availability/[schedule]/schedule-view.tsx b/apps/web/modules/availability/[schedule]/schedule-view.tsx
index fcb71b8b40..71822472d6 100644
--- a/apps/web/modules/availability/[schedule]/schedule-view.tsx
+++ b/apps/web/modules/availability/[schedule]/schedule-view.tsx
@@ -1,5 +1,6 @@
"use client";
+import { revalidateAvailabilityList } from "app/(use-page-wrapper)/(main-nav)/availability/actions";
import { revalidateSchedulePage } from "app/(use-page-wrapper)/availability/[schedule]/actions";
import { useRouter, useSearchParams } from "next/navigation";
import { useState } from "react";
@@ -47,6 +48,7 @@ export const AvailabilitySettingsWebWrapper = ({
{
onSuccess: () => {
utils.viewer.availability.list.invalidate();
+ revalidateAvailabilityList();
callback();
showToast(t("success"), "success");
},
@@ -73,6 +75,7 @@ export const AvailabilitySettingsWebWrapper = ({
utils.viewer.availability.schedule.get.invalidate({ scheduleId: data.schedule.id });
revalidateSchedulePage(scheduleId);
utils.viewer.availability.list.invalidate();
+ revalidateAvailabilityList();
showToast(
t("availability_updated_successfully", {
scheduleName: data.schedule.name,
@@ -97,6 +100,7 @@ export const AvailabilitySettingsWebWrapper = ({
},
onSuccess: () => {
showToast(t("schedule_deleted_successfully"), "success");
+ revalidateAvailabilityList();
router.push("/availability");
},
});
diff --git a/apps/web/modules/availability/availability-view.tsx b/apps/web/modules/availability/availability-view.tsx
index 852fdc7636..b496856e00 100644
--- a/apps/web/modules/availability/availability-view.tsx
+++ b/apps/web/modules/availability/availability-view.tsx
@@ -1,33 +1,31 @@
"use client";
import { useAutoAnimate } from "@formkit/auto-animate/react";
+import { revalidateAvailabilityList } from "app/(use-page-wrapper)/(main-nav)/availability/actions";
import Link from "next/link";
import { useRouter, usePathname } from "next/navigation";
import { useCallback, useState } from "react";
-import { checkAdminOrOwner } from "@calcom/features/auth/lib/checkAdminOrOwner";
-import SkeletonLoader from "@calcom/features/availability/components/SkeletonLoader";
import { BulkEditDefaultForEventsModal } from "@calcom/features/eventtypes/components/BulkEditDefaultForEventsModal";
import type { BulkUpdatParams } from "@calcom/features/eventtypes/components/BulkEditDefaultForEventsModal";
import { NewScheduleButton, ScheduleListItem } from "@calcom/features/schedules";
-import { AvailabilitySliderTable } from "@calcom/features/timezone-buddy/components/AvailabilitySliderTable";
import { useCompatSearchParams } from "@calcom/lib/hooks/useCompatSearchParams";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { HttpError } from "@calcom/lib/http-error";
-import type { OrganizationRepository } from "@calcom/lib/server/repository/organization";
+import type { RouterOutputs } from "@calcom/trpc/react";
import { trpc } from "@calcom/trpc/react";
-import useMeQuery from "@calcom/trpc/react/hooks/useMeQuery";
import { EmptyScreen } from "@calcom/ui/components/empty-screen";
import { ToggleGroup } from "@calcom/ui/components/form";
import { showToast } from "@calcom/ui/components/toast";
-export function AvailabilityList() {
+type AvailabilityListProps = {
+ me: RouterOutputs["viewer"]["me"]["get"];
+ availabilities: RouterOutputs["viewer"]["availability"]["list"];
+};
+export function AvailabilityList({ availabilities, me }: AvailabilityListProps) {
const { t } = useLocale();
const [bulkUpdateModal, setBulkUpdateModal] = useState(false);
const utils = trpc.useUtils();
- const { data: availabilityData } = trpc.viewer.availability.list.useQuery();
- const meQuery = trpc.viewer.me.get.useQuery();
-
const router = useRouter();
const deleteMutation = trpc.viewer.availability.schedule.delete.useMutation({
@@ -55,6 +53,7 @@ export function AvailabilityList() {
utils.viewer.availability.list.invalidate();
},
onSuccess: () => {
+ revalidateAvailabilityList();
showToast(t("schedule_deleted_successfully"), "success");
},
});
@@ -62,6 +61,7 @@ export function AvailabilityList() {
const updateMutation = trpc.viewer.availability.schedule.update.useMutation({
onSuccess: async ({ schedule }) => {
await utils.viewer.availability.list.invalidate();
+ revalidateAvailabilityList();
showToast(
t("availability_updated_successfully", {
scheduleName: schedule.name,
@@ -92,6 +92,7 @@ export function AvailabilityList() {
{
onSuccess: () => {
utils.viewer.availability.list.invalidate();
+ revalidateAvailabilityList();
showToast(t("success"), "success");
callback();
},
@@ -120,13 +121,9 @@ export function AvailabilityList() {
const [animationParentRef] = useAutoAnimate();
- if (!availabilityData) {
- return ;
- }
-
return (
<>
- {availabilityData.schedules.length === 0 ? (
+ {availabilities.schedules.length === 0 ? (
- {availabilityData.schedules.map((schedule) => (
+ {availabilities.schedules.map((schedule) => (
> | null;
+type AvailabilityCTAProps = {
+ toggleGroupOptions: {
+ value: string;
+ label: string;
+ }[];
};
-
-export const AvailabilityCTA = () => {
- const { t } = useLocale();
+export const AvailabilityCTA = ({ toggleGroupOptions }: AvailabilityCTAProps) => {
const searchParams = useCompatSearchParams();
const router = useRouter();
const pathname = usePathname();
@@ -203,18 +201,6 @@ export const AvailabilityCTA = () => {
[searchParams]
);
- const { data } = trpc.viewer.organizations.listCurrent.useQuery();
- const isOrgAdminOrOwner = (data && checkAdminOrOwner(data.user.role)) ?? false;
- const isOrgAndPrivate = data?.isOrganization && data.isPrivate;
-
- const canViewTeamAvailability = isOrgAdminOrOwner || !isOrgAndPrivate;
-
- const toggleGroupOptions = [{ value: "mine", label: t("my_availability") }];
-
- if (canViewTeamAvailability) {
- toggleGroupOptions.push({ value: "team", label: t("team_availability") });
- }
-
return (
{
);
};
-
-export default function AvailabilityPage({ currentOrg }: PageProps) {
- const { t } = useLocale();
- const searchParams = useCompatSearchParams();
- const me = useMeQuery();
-
- const { data: _data } = trpc.viewer.organizations.listCurrent.useQuery(undefined, { enabled: !currentOrg });
- const data = currentOrg ?? _data;
-
- const isOrg = Boolean(data);
- const isOrgAdminOrOwner = (data && checkAdminOrOwner(data.user.role)) ?? false;
- const isOrgAndPrivate = data?.isOrganization && data.isPrivate;
-
- const canViewTeamAvailability = isOrgAdminOrOwner || !isOrgAndPrivate;
-
- const toggleGroupOptions = [{ value: "mine", label: t("my_availability") }];
-
- if (canViewTeamAvailability) {
- toggleGroupOptions.push({ value: "team", label: t("team_availability") });
- }
-
- return searchParams?.get("type") === "team" && canViewTeamAvailability ? (
-
- ) : (
-
- );
-}
diff --git a/packages/features/availability/components/SkeletonLoader.tsx b/packages/features/availability/components/SkeletonLoader.tsx
index 263ecc6b93..45c87e2a1f 100644
--- a/packages/features/availability/components/SkeletonLoader.tsx
+++ b/packages/features/availability/components/SkeletonLoader.tsx
@@ -1,6 +1,8 @@
-import { SkeletonText } from "@calcom/ui/components/skeleton";
-import { Button } from "@calcom/ui/components/button";
+"use client";
+
import classNames from "@calcom/ui/classNames";
+import { Button } from "@calcom/ui/components/button";
+import { SkeletonText } from "@calcom/ui/components/skeleton";
function SkeletonLoader() {
return (
diff --git a/packages/features/schedules/components/ScheduleListItem.tsx b/packages/features/schedules/components/ScheduleListItem.tsx
index 9b5bad0b0e..11e499fca3 100644
--- a/packages/features/schedules/components/ScheduleListItem.tsx
+++ b/packages/features/schedules/components/ScheduleListItem.tsx
@@ -1,3 +1,5 @@
+"use client";
+
import Link from "next/link";
import { Fragment } from "react";
@@ -5,6 +7,8 @@ import { availabilityAsString } from "@calcom/lib/availability";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { sortAvailabilityStrings } from "@calcom/lib/weekstart";
import type { RouterOutputs } from "@calcom/trpc/react";
+import { Badge } from "@calcom/ui/components/badge";
+import { Button } from "@calcom/ui/components/button";
import {
Dropdown,
DropdownItem,
@@ -12,8 +16,6 @@ import {
DropdownMenuItem,
DropdownMenuTrigger,
} from "@calcom/ui/components/dropdown";
-import { Badge } from "@calcom/ui/components/badge";
-import { Button } from "@calcom/ui/components/button";
import { Icon } from "@calcom/ui/components/icon";
import { showToast } from "@calcom/ui/components/toast";
diff --git a/packages/lib/server/repository/organization.ts b/packages/lib/server/repository/organization.ts
index 07fe565891..db97e700a3 100644
--- a/packages/lib/server/repository/organization.ts
+++ b/packages/lib/server/repository/organization.ts
@@ -456,4 +456,18 @@ export class OrganizationRepository {
},
});
}
+
+ static async checkIfPrivate({ orgId }: { orgId: number }) {
+ const team = await prisma.team.findUnique({
+ where: {
+ id: orgId,
+ isOrganization: true,
+ },
+ select: {
+ isPrivate: true,
+ },
+ });
+
+ return team?.isPrivate ?? false;
+ }
}