import { keepPreviousData } from "@tanstack/react-query"; import { useSession } from "next-auth/react"; import { useRouter } from "next/navigation"; import { useEffect, useState, useMemo } from "react"; import { useOrgBranding } from "@calcom/features/ee/organizations/context/provider"; import InviteLinkSettingsModal from "@calcom/features/ee/teams/components/InviteLinkSettingsModal"; import { MemberInvitationModalWithoutMembers } from "@calcom/features/ee/teams/components/MemberInvitationModal"; import { classNames } from "@calcom/lib"; import { APP_NAME } from "@calcom/lib/constants"; import { useCompatSearchParams } from "@calcom/lib/hooks/useCompatSearchParams"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import { telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry"; import { MembershipRole } from "@calcom/prisma/enums"; import type { RouterOutputs } from "@calcom/trpc/react"; import { trpc } from "@calcom/trpc/react"; import { Badge, Button, showToast, SkeletonButton, SkeletonContainer, SkeletonText, UserAvatar, } from "@calcom/ui"; type TeamMember = RouterOutputs["viewer"]["teams"]["listMembers"]["members"][number]; const AddNewTeamMembers = ({ isOrg = false }: { isOrg?: boolean }) => { const searchParams = useCompatSearchParams(); const session = useSession(); const telemetry = useTelemetry(); const teamId = searchParams?.get("id") ? Number(searchParams.get("id")) : -1; const teamQuery = trpc.viewer.teams.get.useQuery( { teamId, isOrg }, { enabled: session.status === "authenticated" } ); useEffect(() => { const event = searchParams?.get("event"); if (event === "team_created") { telemetry.event(telemetryEventTypes.team_created); } }, []); if (session.status === "loading" || !teamQuery.data) return ; return ; }; export const AddNewTeamMembersForm = ({ teamId, isOrg }: { teamId: number; isOrg?: boolean }) => { const searchParams = useCompatSearchParams(); const { t } = useLocale(); const router = useRouter(); const orgBranding = useOrgBranding(); const showDialog = searchParams?.get("inviteModal") === "true"; const [memberInviteModal, setMemberInviteModal] = useState(showDialog); const [inviteLinkSettingsModal, setInviteLinkSettingsModal] = useState(false); const { data: team, isPending } = trpc.viewer.teams.get.useQuery({ teamId, isOrg }, { enabled: !!teamId }); const { data: orgMembersNotInThisTeam } = trpc.viewer.organizations.getMembers.useQuery( { teamIdToExclude: teamId, distinctUser: true, }, { enabled: orgBranding !== null, } ); const { data, fetchNextPage, isFetchingNextPage, hasNextPage } = trpc.viewer.teams.listMembers.useInfiniteQuery( { limit: 10, teamId, }, { enabled: !!teamId, getNextPageParam: (lastPage) => lastPage.nextCursor, placeholderData: keepPreviousData, refetchOnWindowFocus: true, refetchOnMount: true, staleTime: 0, } ); const flatData = useMemo(() => data?.pages?.flatMap((page) => page.members) ?? [], [data]) as TeamMember[]; const totalFetched = flatData.length; const publishTeamMutation = trpc.viewer.teams.publish.useMutation({ onSuccess(data) { router.push(data.url); }, onError: (error) => { showToast(error.message, "error"); }, }); return ( <>
    {flatData.map((member, index) => ( ))}
{totalFetched && (
)}
{isPending ? ( ) : ( <> setMemberInviteModal(false)} onSettingsOpen={() => { setMemberInviteModal(false); setInviteLinkSettingsModal(true); }} /> {team?.inviteToken && ( { setInviteLinkSettingsModal(false); setMemberInviteModal(true); }} /> )} )}
); }; export default AddNewTeamMembers; const AddNewTeamMemberSkeleton = () => { return (

); }; const PendingMemberItem = (props: { member: TeamMember; index: number; teamId: number; isOrg?: boolean }) => { const { member, index, teamId } = props; const { t } = useLocale(); const utils = trpc.useUtils(); const session = useSession(); const orgRole = session?.data?.user.org?.role; const bookerUrl = member.bookerUrl; const removeMemberMutation = trpc.viewer.teams.removeMember.useMutation({ async onSuccess() { await utils.viewer.teams.get.invalidate(); await utils.viewer.teams.listMembers.invalidate(); await utils.viewer.eventTypes.invalidate(); showToast(t("member_removed"), "success"); }, async onError(err) { showToast(err.message, "error"); }, }); const isOrgAdminOrOwner = orgRole === MembershipRole.OWNER || orgRole === MembershipRole.ADMIN; return (
  • {member.name || member.email || t("team_member")}

    {/* Assume that the first member of the team is the creator */} {member.id === session.data?.user.id && {t("you")}} {!member.accepted && {t("pending")}} {member.role === MembershipRole.MEMBER && {t("member")}} {member.role === MembershipRole.ADMIN && {t("admin")}} {member.role === MembershipRole.OWNER && {t("owner")}}
    {member.username ? (

    {`${bookerUrl}/${member.username}`}

    ) : (

    {t("not_on_cal", { appName: APP_NAME })}

    )}
    {(member.role !== "OWNER" || isOrgAdminOrOwner) && member.id !== session.data?.user.id && (
  • ); };