* Ok 1 * Finished * Fix PR * Fix PR * Fix desktop * Fix * Fix absolute listen click outside * console.log * Fix according to code review --------- Co-authored-by: Charles Bochet <charles@twenty.com>
118 lines
3.5 KiB
TypeScript
118 lines
3.5 KiB
TypeScript
import { useTheme } from '@emotion/react';
|
|
import styled from '@emotion/styled';
|
|
import { useRecoilState } from 'recoil';
|
|
|
|
import { currentUserState } from '@/auth/states/currentUserState';
|
|
import { Button } from '@/ui/button/components/Button';
|
|
import { IconTrash } from '@/ui/icon';
|
|
import { SubMenuTopBarContainer } from '@/ui/layout/components/SubMenuTopBarContainer';
|
|
import { MainSectionTitle } from '@/ui/title/components/MainSectionTitle';
|
|
import { SubSectionTitle } from '@/ui/title/components/SubSectionTitle';
|
|
import { WorkspaceInviteLink } from '@/workspace/components/WorkspaceInviteLink';
|
|
import { WorkspaceMemberCard } from '@/workspace/components/WorkspaceMemberCard';
|
|
import {
|
|
useGetWorkspaceMembersQuery,
|
|
useRemoveWorkspaceMemberMutation,
|
|
} from '~/generated/graphql';
|
|
|
|
const StyledContainer = styled.div`
|
|
display: flex;
|
|
flex-direction: column;
|
|
padding: ${({ theme }) => theme.spacing(8)};
|
|
width: 350px;
|
|
> * + * {
|
|
margin-top: ${({ theme }) => theme.spacing(8)};
|
|
}
|
|
`;
|
|
|
|
const ButtonContainer = styled.div`
|
|
align-items: center;
|
|
display: flex;
|
|
flex-direction: row;
|
|
margin-left: ${({ theme }) => theme.spacing(3)};
|
|
`;
|
|
|
|
export function SettingsWorkspaceMembers() {
|
|
const [currentUser] = useRecoilState(currentUserState);
|
|
const workspace = currentUser?.workspaceMember?.workspace;
|
|
const theme = useTheme();
|
|
|
|
const { data } = useGetWorkspaceMembersQuery();
|
|
|
|
const [removeWorkspaceMember] = useRemoveWorkspaceMemberMutation();
|
|
|
|
const handleRemoveWorkspaceMember = async (userId: string) => {
|
|
await removeWorkspaceMember({
|
|
variables: {
|
|
where: {
|
|
userId,
|
|
},
|
|
},
|
|
optimisticResponse: {
|
|
__typename: 'Mutation',
|
|
deleteWorkspaceMember: {
|
|
__typename: 'WorkspaceMember',
|
|
id: userId,
|
|
},
|
|
},
|
|
update: (cache, { data: responseData }) => {
|
|
if (!responseData) {
|
|
return;
|
|
}
|
|
|
|
const normalizedId = cache.identify({
|
|
id: responseData.deleteWorkspaceMember.id,
|
|
__typename: 'WorkspaceMember',
|
|
});
|
|
|
|
// Evict object from cache
|
|
cache.evict({ id: normalizedId });
|
|
|
|
// Clean up relation to this object
|
|
cache.gc();
|
|
},
|
|
});
|
|
};
|
|
|
|
return (
|
|
<SubMenuTopBarContainer>
|
|
<StyledContainer>
|
|
<MainSectionTitle>Members</MainSectionTitle>
|
|
{workspace?.inviteHash && (
|
|
<>
|
|
<SubSectionTitle
|
|
title="Invite"
|
|
description="Send an invitation to use Twenty"
|
|
/>
|
|
<WorkspaceInviteLink
|
|
inviteLink={`${window.location.origin}/invite/${workspace?.inviteHash}`}
|
|
/>
|
|
</>
|
|
)}
|
|
<SubSectionTitle
|
|
title="Members"
|
|
description="Manage the members of your space here"
|
|
/>
|
|
{data?.workspaceMembers?.map((member) => (
|
|
<WorkspaceMemberCard
|
|
key={member.user.id}
|
|
workspaceMember={{ user: member.user }}
|
|
accessory={
|
|
currentUser?.id !== member.user.id && (
|
|
<ButtonContainer>
|
|
<Button
|
|
onClick={() => handleRemoveWorkspaceMember(member.user.id)}
|
|
variant="tertiary"
|
|
size="small"
|
|
icon={<IconTrash size={theme.icon.size.md} />}
|
|
/>
|
|
</ButtonContainer>
|
|
)
|
|
}
|
|
/>
|
|
))}
|
|
</StyledContainer>
|
|
</SubMenuTopBarContainer>
|
|
);
|
|
}
|