Files
calendar/apps/web/modules/ee/teams/components/TeamsListing.tsx
T

112 lines
3.8 KiB
TypeScript

"use client";
import { WEBAPP_URL } from "@calcom/lib/constants";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import type { RouterOutputs } from "@calcom/trpc/react";
import { Button } from "@calcom/ui/components/button";
import { EmptyScreen } from "@calcom/ui/components/empty-screen";
import { Label } from "@calcom/ui/components/form";
import { InfoIcon } from "@coss/ui/icons";
import { showToast } from "@calcom/ui/components/toast";
import { useHasTeamPlan } from "@calcom/web/modules/billing/hooks/useHasPaidPlan";
import { FullscreenUpgradeBannerForTeamsPage } from "@calcom/web/modules/billing/upgrade-banners/FullscreenUpgradeBannerForTeamsPage";
import { useRouter, useSearchParams } from "next/navigation";
import { useEffect, useMemo } from "react";
import SkeletonLoaderTeamList from "~/ee/teams/components/SkeletonloaderTeamList";
import TeamList from "./TeamList";
type TeamsListingProps = {
invitationAccepted: boolean;
orgId: number | null;
permissions: {
canCreateTeam: boolean;
};
teams: RouterOutputs["viewer"]["teams"]["list"];
teamNameFromInvite: string | null;
errorMsgFromInvite: string | null;
};
export function TeamsListing({
invitationAccepted,
orgId,
permissions,
teams: data,
teamNameFromInvite,
errorMsgFromInvite,
}: TeamsListingProps) {
const searchParams = useSearchParams();
const token = searchParams?.get("token");
const { t } = useLocale();
const router = useRouter();
const teams = useMemo(() => data?.filter((m) => m.accepted && !m.isOrganization) || [], [data]);
const teamInvites = useMemo(() => data?.filter((m) => !m.accepted && !m.isOrganization) || [], [data]);
const organizationInvites = (data?.filter((m) => !m.accepted && m.isOrganization) || []).filter(
(orgInvite) => {
const isThereASubTeamOfTheOrganizationInInvites = teamInvites.find(
(teamInvite) => teamInvite.parentId === orgInvite.id
);
// Accepting a subteam invite automatically accepts the invite for the parent organization. So, need to show such an organization's invite
return !isThereASubTeamOfTheOrganizationInInvites;
}
);
const isCreateTeamButtonDisabled = !!(orgId && !permissions.canCreateTeam);
const { isPending: isPendingTeamPlan } = useHasTeamPlan();
useEffect(() => {
if (!token) {
return;
}
if (errorMsgFromInvite) {
showToast(errorMsgFromInvite, "error");
return;
}
if (invitationAccepted) {
showToast(t("successfully_joined"), "success");
return;
}
if (teamNameFromInvite) {
showToast(t("team_invite_received", { teamName: teamNameFromInvite }), "success");
return;
}
}, [errorMsgFromInvite, invitationAccepted, t, teamNameFromInvite, token]);
return (
<>
{organizationInvites.length > 0 && (
<div className="mb-6 rounded-md bg-subtle p-5">
<Label className="pb-2 font-semibold text-emphasis">{t("pending_organization_invites")}</Label>
<TeamList orgId={orgId} teams={organizationInvites} pending />
</div>
)}
{teamInvites.length > 0 && (
<div className="mb-6 rounded-md bg-subtle p-5">
<Label className="pb-2 font-semibold text-emphasis">{t("pending_invites")}</Label>
<TeamList orgId={orgId} teams={teamInvites} pending />
</div>
)}
{teams.length > 0 && <TeamList orgId={orgId} teams={teams} />}
{teams.length === 0 && isPendingTeamPlan && <SkeletonLoaderTeamList />}
{teams.length === 0 && !isPendingTeamPlan && <FullscreenUpgradeBannerForTeamsPage />}
{/* Only show tip when not showing the upgrade banner */}
{teams.length > 0 && (
<p className="mt-4 mb-8 flex w-full items-center gap-1 text-sm text-subtle md:justify-center md:text-center">
<InfoIcon className="hidden sm:block" /> {t("tip_username_plus")}
</p>
)}
</>
);
}