import { ArrowRight, Check, Minus, User, X } from 'lucide-react' import Image from 'next/legacy/image' import { useState } from 'react' import { useParams } from 'common' import Table from 'components/to-be-cleaned/Table' import PartnerIcon from 'components/ui/PartnerIcon' import { useOrganizationRolesV2Query } from 'data/organization-members/organization-roles-query' import { OrganizationMember } from 'data/organizations/organization-members-query' import { useProjectsQuery } from 'data/projects/projects-query' import { useHasAccessToProjectLevelPermissions } from 'data/subscriptions/org-subscription-query' import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization' import { useProfile } from 'lib/profile' import { Badge, HoverCardContent_Shadcn_, HoverCardTrigger_Shadcn_, HoverCard_Shadcn_, ScrollArea, cn, } from 'ui' import ShimmeringLoader from 'ui-patterns/ShimmeringLoader' import { getUserDisplayName, isInviteExpired } from '../Organization.utils' import { MemberActions } from './MemberActions' import Link from 'next/link' interface MemberRowProps { member: OrganizationMember } const MEMBER_ORIGIN_TO_MANAGED_BY = { vercel: 'vercel-marketplace', } as const export const MemberRow = ({ member }: MemberRowProps) => { const { profile } = useProfile() const selectedOrganization = useSelectedOrganization() const [hasInvalidImg, setHasInvalidImg] = useState(false) const { data: projects } = useProjectsQuery() const { data: roles, isLoading: isLoadingRoles } = useOrganizationRolesV2Query({ slug: selectedOrganization?.slug, }) const orgProjects = projects?.filter((p) => p.organization_id === selectedOrganization?.id) const hasProjectScopedRoles = (roles?.project_scoped_roles ?? []).length > 0 const memberIsUser = member.gotrue_id == profile?.gotrue_id const isInvitedUser = Boolean(member.invited_id) const isEmailUser = member.username === member.primary_email const isFlyUser = Boolean(member.primary_email?.endsWith('customer.fly.io')) // [Joshen] From project role POV, mask any roles for other projects const isObfuscated = member.role_ids.filter((id) => { const role = [ ...(roles?.org_scoped_roles ?? []), ...(roles?.project_scoped_roles ?? []), ].find((role) => role.id === id) const isOrgScope = role?.project_ids === null if (isOrgScope) return false const appliedProjects = (role?.project_ids ?? []) .map((id) => { return projects?.find((p) => p.id === id)?.name ?? '' }) .filter((x) => x.length > 0) return appliedProjects.length === 0 }).length > 0 return (
{isInvitedUser || isEmailUser || isFlyUser || hasInvalidImg ? (
) : ( {member.username} { setHasInvalidImg(true) }} /> )}
{isInvitedUser === undefined ? (

{member.primary_email}

) : (

{getUserDisplayName(member)}

)} {member.primary_email === profile?.primary_email && You}
{(member.metadata as any)?.origin && ( )}
{isInvitedUser && member.invited_at && ( {isInviteExpired(member.invited_at) ? 'Expired' : 'Invited'} )}
{member.mfa_enabled ? ( ) : ( )}
{isLoadingRoles ? ( ) : isObfuscated ? ( ) : ( member.role_ids.map((id) => { const orgScopedRole = (roles?.org_scoped_roles ?? []).find((role) => role.id === id) const projectScopedRole = (roles?.project_scoped_roles ?? []).find( (role) => role.id === id ) const role = orgScopedRole || projectScopedRole const roleName = (role?.name ?? '').split('_')[0] const projectsApplied = role?.project_ids === null ? orgProjects?.map((p) => p.name) ?? [] : (role?.project_ids ?? []) .map((id) => { return orgProjects?.find((p) => p.id === id)?.name ?? '' }) .filter((x) => x.length > 0) return (

{roleName}

{hasProjectScopedRoles && ( <> • {projectsApplied.length === 1 ? ( {projectsApplied[0]} ) : ( {role?.project_ids === null ? 'Organization' : `${projectsApplied.length} project${projectsApplied.length > 1 ? 's' : ''}`}

{roleName} role applies to {projectsApplied.length} project {projectsApplied.length > 1 ? 's' : ''}

5 ? 'h-[130px]' : '')} > {projectsApplied.map((name) => { const ref = orgProjects?.find((p) => p.name === name)?.ref return ( {name} Go to project ) })}
)} )}
) }) )}
{!memberIsUser && }
) }