import {useEffect, useState} from 'react'; import {AnimatePresence, m} from 'framer-motion'; import {useWorkspaceWithMembers} from './requests/workspace-with-members'; import {ProgressCircle} from '../ui/progress/progress-circle'; import {Workspace} from './types/workspace'; import {GroupIcon} from '../icons/material/Group'; import {WorkspaceMember} from './types/workspace-member'; import {useAuth} from '../auth/use-auth'; import { ChipField, ChipValue, } from '../ui/forms/input-field/chip-field/chip-field'; import {useValueLists} from '../http/value-lists'; import {Button} from '../ui/buttons/button'; import {ArrowDropDownIcon} from '../icons/material/ArrowDropDown'; import {useInviteMembers} from './requests/invite-members'; import {WorkspaceInvite} from './types/workspace-invite'; import {ConfirmationDialog} from '../ui/overlays/dialog/confirmation-dialog'; import {useResendInvite} from './requests/resend-invite'; import {isEmail} from '../utils/string/is-email'; import {ButtonSize} from '../ui/buttons/button-size'; import {useChangeRole} from './requests/change-role'; import {IconButton} from '../ui/buttons/icon-button'; import {useRemoveMember} from './requests/remove-member'; import {CloseIcon} from '../icons/material/Close'; import {ExitToAppIcon} from '../icons/material/ExitToApp'; import {toast} from '../ui/toast/toast'; import {DialogTrigger} from '../ui/overlays/dialog/dialog-trigger'; import {Menu, MenuItem, MenuTrigger} from '../ui/navigation/menu/menu-trigger'; import {useDialogContext} from '../ui/overlays/dialog/dialog-context'; import {Dialog} from '../ui/overlays/dialog/dialog'; import {DialogHeader} from '../ui/overlays/dialog/dialog-header'; import {DialogBody} from '../ui/overlays/dialog/dialog-body'; import {Trans} from '../i18n/trans'; import {useTrans} from '../i18n/use-trans'; import {message} from '../i18n/message'; import {LeaveWorkspaceConfirmation} from './leave-workspace-confirmation'; interface WorkspaceMembersDialogProps { workspace: Workspace; } export function WorkspaceMembersDialog({ workspace, }: WorkspaceMembersDialogProps) { const {data, isLoading} = useWorkspaceWithMembers(workspace.id); return ( {isLoading ? (
) : ( )}
); } interface ManagerProps { workspace: Workspace; } function Manager({workspace}: ManagerProps) { const {user} = useAuth(); const can = usePermissions(workspace); const members: (WorkspaceMember | WorkspaceInvite)[] = [ ...(workspace.members || []), ...(workspace.invites || []), ]; const shouldHideOtherMembers = !can.update && !can.delete; return (
{can.invite && }
{members.map(member => { if (shouldHideOtherMembers && member.id !== user?.id) { return null; } return ( ); })} {shouldHideOtherMembers && (
)}
); } interface MemberListItemProps { member: WorkspaceMember | WorkspaceInvite; workspace: Workspace; } function MemberListItem({workspace, member}: MemberListItemProps) { return (
{member.display_name}
{member.email}
); } function usePermissions(workspace: Workspace) { const {user: authUser} = useAuth(); const response = {update: false, invite: false, delete: false}; const permissions = ['update', 'invite', 'delete'] as const; const authMember = workspace.members?.find(mb => mb.id === authUser?.id); if (authMember) { permissions.forEach(permission => { response[permission] = authMember.is_owner || !!authMember.permissions?.find( p => p.name === `workspace_members.${permission}`, ); }); } return response; } interface MemberActionsProps { workspace: Workspace; member: WorkspaceMember | WorkspaceInvite; } function MemberActions({workspace, member}: MemberActionsProps) { const [selectedRole, setSelectedRole] = useState(member.role_id); const changeRole = useChangeRole(); const {user} = useAuth(); const can = usePermissions(workspace); const isOwner = member.model_type === 'member' && member.is_owner; const isCurrentUser = member.model_type === 'member' && user?.id === member.id; const roleSelector = !can.update || isOwner || isCurrentUser ? (
) : ( { setSelectedRole(roleId); changeRole.mutate({ roleId, workspaceId: workspace.id, member, }); }} /> ); return ( <> {roleSelector} {!isOwner && (isCurrentUser || can.delete) && ( )} ); } interface InviteChipFieldProps { workspace: Workspace; } function InviteChipField({workspace}: InviteChipFieldProps) { const {trans} = useTrans(); const [chips, setChips] = useState([]); const allEmailsValid = chips.every(chip => !chip.invalid); const displayWith = (chip: ChipValue) => chip.description || chip.name; const [selectedRole, setSelectedRole] = useState(); const inviteMembers = useInviteMembers(); const {data} = useValueLists(['workspaceRoles']); useEffect(() => { if (!selectedRole && data?.workspaceRoles?.length) { setSelectedRole(data.workspaceRoles[0].id); } }, [data, selectedRole]); return (
{ const invalid = !isEmail(chip.description); return { ...chip, invalid, errorMessage: invalid ? trans({message: 'Not a valid email'}) : undefined, }; }} placeholder={trans({message: 'Enter email addresses'})} label={} />
{chips.length && selectedRole ? ( ) : null}
); } interface RemoveMemberButtonProps { member: WorkspaceMember | WorkspaceInvite; workspace: Workspace; type: 'leave' | 'remove'; } function RemoveMemberButton({ member, workspace, type, }: RemoveMemberButtonProps) { const removeMember = useRemoveMember(); const {close} = useDialogContext(); return ( { if (isConfirmed) { removeMember.mutate({ workspaceId: workspace.id, memberId: member.id, memberType: member.model_type, }); if (type === 'leave') { close(); toast(message('Left workspace')); } } }} > {type === 'leave' ? : } {type === 'leave' ? ( ) : ( )} ); } interface RemoveMemberConfirmationProps { member: WorkspaceMember | WorkspaceInvite; } function RemoveMemberConfirmation({member}: RemoveMemberConfirmationProps) { return ( } body={
} confirm={} /> ); } interface RoleMenuTriggerProps { onChange: (value: number) => void; value?: number; size?: ButtonSize; className?: string; isDisabled?: boolean; } function RoleMenuTrigger({ value, onChange, size = 'xs', className, isDisabled, }: RoleMenuTriggerProps) { const {data} = useValueLists(['workspaceRoles']); const role = data?.workspaceRoles?.find(r => r.id === value); if (!value || !role || !data?.workspaceRoles) return null; return ( { onChange(newValue as number); }} > {data.workspaceRoles.map(r => ( ))} ); } interface MemberDisplayNameAppendProps { member: WorkspaceMember | WorkspaceInvite; workspace: Workspace; } function MemberDisplayNameAppend({ member, workspace, }: MemberDisplayNameAppendProps) { const {user} = useAuth(); const can = usePermissions(workspace); if (user?.id === member.id) { return (
()
); } if (member.model_type === 'invite') { return (
·
{can.invite ? ( <>
·
) : null}
); } return null; } function ResendInviteDialogTrigger({ member, workspace, }: MemberDisplayNameAppendProps) { const resendInvite = useResendInvite(); return ( { if (isConfirmed) { resendInvite.mutate({ workspaceId: workspace.id, inviteId: member.id as string, }); } }} > } body={ } confirm={} /> ); }