[WIP] Whole FE migrated (#2517)
* Wip * WIP * Removed concole log * Add relations to workspace init (#2511) * Add relations to workspace init * remove logs * update prefill * add missing isSystem * comment relation fields * Migrate v2 core models to graphql schema (#2509) * migrate v2 core models to graphql schema * Migrate to new workspace member schema * Continue work * migrated-main * Finished accountOwner nested field integration on companies * Introduce bug * Fix --------- Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com> Co-authored-by: Weiko <corentin@twenty.com>
This commit is contained in:
@ -11,6 +11,7 @@ import { z } from 'zod';
|
||||
import { SubTitle } from '@/auth/components/SubTitle';
|
||||
import { Title } from '@/auth/components/Title';
|
||||
import { currentUserState } from '@/auth/states/currentUserState';
|
||||
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
||||
import { ProfilePictureUploader } from '@/settings/profile/components/ProfilePictureUploader';
|
||||
import { PageHotkeyScope } from '@/types/PageHotkeyScope';
|
||||
import { H2Title } from '@/ui/display/typography/components/H2Title';
|
||||
@ -57,6 +58,7 @@ export const CreateProfile = () => {
|
||||
const { enqueueSnackBar } = useSnackBar();
|
||||
|
||||
const [currentUser] = useRecoilState(currentUserState);
|
||||
const [currentWorkspaceMember] = useRecoilState(currentWorkspaceMemberState);
|
||||
|
||||
const [updateUser] = useUpdateUserMutation();
|
||||
|
||||
@ -69,8 +71,8 @@ export const CreateProfile = () => {
|
||||
} = useForm<Form>({
|
||||
mode: 'onChange',
|
||||
defaultValues: {
|
||||
firstName: currentUser?.firstName ?? '',
|
||||
lastName: currentUser?.lastName ?? '',
|
||||
firstName: currentWorkspaceMember?.firstName ?? '',
|
||||
lastName: currentWorkspaceMember?.lastName ?? '',
|
||||
},
|
||||
resolver: zodResolver(validationSchema),
|
||||
});
|
||||
|
||||
@ -1,15 +1,18 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useNavigate, useSearchParams } from 'react-router-dom';
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { useAuth } from '@/auth/hooks/useAuth';
|
||||
import { useIsLogged } from '@/auth/hooks/useIsLogged';
|
||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||
|
||||
import { AppPath } from '../../modules/types/AppPath';
|
||||
|
||||
export const VerifyEffect = () => {
|
||||
const [searchParams] = useSearchParams();
|
||||
const loginToken = searchParams.get('loginToken');
|
||||
const currentWorkspace = useRecoilValue(currentWorkspaceState);
|
||||
|
||||
const isLogged = useIsLogged();
|
||||
const navigate = useNavigate();
|
||||
@ -21,13 +24,9 @@ export const VerifyEffect = () => {
|
||||
if (!loginToken) {
|
||||
navigate(AppPath.SignIn);
|
||||
} else {
|
||||
const verifyResponse = await verify(loginToken);
|
||||
await verify(loginToken);
|
||||
|
||||
if (
|
||||
isNonEmptyString(
|
||||
verifyResponse.user.workspaceMember?.workspace.displayName,
|
||||
)
|
||||
) {
|
||||
if (isNonEmptyString(currentWorkspace?.displayName)) {
|
||||
navigate(AppPath.Index);
|
||||
} else {
|
||||
navigate(AppPath.CreateWorkspace);
|
||||
|
||||
@ -38,21 +38,9 @@ export const ImpersonateEffect = () => {
|
||||
throw new Error('No impersonate result');
|
||||
}
|
||||
|
||||
if (!impersonateResult.data?.impersonate.user.workspaceMember) {
|
||||
throw new Error('No workspace member');
|
||||
}
|
||||
|
||||
if (!impersonateResult.data?.impersonate.user.workspaceMember.settings) {
|
||||
throw new Error('No workspace member settings');
|
||||
}
|
||||
|
||||
setCurrentUser({
|
||||
...impersonateResult.data.impersonate.user,
|
||||
workspaceMember: {
|
||||
...impersonateResult.data.impersonate.user.workspaceMember,
|
||||
settings:
|
||||
impersonateResult.data.impersonate.user.workspaceMember.settings,
|
||||
},
|
||||
// Todo also set WorkspaceMember
|
||||
});
|
||||
setTokenPair(impersonateResult.data?.impersonate.tokens);
|
||||
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
import { useState } from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
import { useRecoilState } from 'recoil';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { currentUserState } from '@/auth/states/currentUserState';
|
||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||
import { useDeleteOneObjectRecord } from '@/object-record/hooks/useDeleteOneObjectRecord';
|
||||
import { useFindManyObjectRecords } from '@/object-record/hooks/useFindManyObjectRecords';
|
||||
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
||||
import { IconSettings, IconTrash } from '@/ui/display/icon';
|
||||
import { H1Title } from '@/ui/display/typography/components/H1Title';
|
||||
@ -13,10 +15,7 @@ import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer'
|
||||
import { Section } from '@/ui/layout/section/components/Section';
|
||||
import { WorkspaceInviteLink } from '@/workspace/components/WorkspaceInviteLink';
|
||||
import { WorkspaceMemberCard } from '@/workspace/components/WorkspaceMemberCard';
|
||||
import {
|
||||
useGetWorkspaceMembersQuery,
|
||||
useRemoveWorkspaceMemberMutation,
|
||||
} from '~/generated/graphql';
|
||||
import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember';
|
||||
|
||||
const StyledH1Title = styled(H1Title)`
|
||||
margin-bottom: 0;
|
||||
@ -31,51 +30,22 @@ const StyledButtonContainer = styled.div`
|
||||
|
||||
export const SettingsWorkspaceMembers = () => {
|
||||
const [isConfirmationModalOpen, setIsConfirmationModalOpen] = useState(false);
|
||||
const [userToDelete, setUserToDelete] = useState<string | undefined>();
|
||||
const [workspaceMemberToDelete, setWorkspaceMemberToDelete] = useState<
|
||||
string | undefined
|
||||
>();
|
||||
|
||||
const [currentUser] = useRecoilState(currentUserState);
|
||||
const workspace = currentUser?.workspaceMember?.workspace;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
cache.evict({
|
||||
id: cache.identify({
|
||||
id: responseData.deleteWorkspaceMember.id,
|
||||
__typename: 'WorkspaceMember',
|
||||
}),
|
||||
});
|
||||
|
||||
cache.evict({
|
||||
id: cache.identify({
|
||||
id: userId,
|
||||
__typename: 'User',
|
||||
}),
|
||||
});
|
||||
|
||||
cache.gc();
|
||||
},
|
||||
const { objects: workspaceMembers } =
|
||||
useFindManyObjectRecords<WorkspaceMember>({
|
||||
objectNamePlural: 'workspaceMembersV2',
|
||||
});
|
||||
const { deleteOneObject: deleteOneWorkspaceMember } =
|
||||
useDeleteOneObjectRecord({
|
||||
objectNamePlural: 'workspaceMembersV2',
|
||||
});
|
||||
const currentWorkspace = useRecoilValue(currentWorkspaceState);
|
||||
|
||||
const handleRemoveWorkspaceMember = async (workspaceMemberId: string) => {
|
||||
await deleteOneWorkspaceMember?.(workspaceMemberId);
|
||||
setIsConfirmationModalOpen(false);
|
||||
};
|
||||
|
||||
@ -83,14 +53,14 @@ export const SettingsWorkspaceMembers = () => {
|
||||
<SubMenuTopBarContainer Icon={IconSettings} title="Settings">
|
||||
<SettingsPageContainer width={350}>
|
||||
<StyledH1Title title="Members" />
|
||||
{workspace?.inviteHash && (
|
||||
{currentWorkspace?.inviteHash && (
|
||||
<Section>
|
||||
<H2Title
|
||||
title="Invite"
|
||||
description="Send an invitation to use Twenty"
|
||||
/>
|
||||
<WorkspaceInviteLink
|
||||
inviteLink={`${window.location.origin}/invite/${workspace?.inviteHash}`}
|
||||
inviteLink={`${window.location.origin}/invite/${currentWorkspace?.inviteHash}`}
|
||||
/>
|
||||
</Section>
|
||||
)}
|
||||
@ -99,17 +69,17 @@ export const SettingsWorkspaceMembers = () => {
|
||||
title="Members"
|
||||
description="Manage the members of your space here"
|
||||
/>
|
||||
{data?.workspaceMembers?.map((member) => (
|
||||
{workspaceMembers?.map((member) => (
|
||||
<WorkspaceMemberCard
|
||||
key={member.user.id}
|
||||
workspaceMember={{ user: member.user }}
|
||||
key={member.id}
|
||||
workspaceMember={member as WorkspaceMember}
|
||||
accessory={
|
||||
currentUser?.id !== member.user.id && (
|
||||
currentWorkspace?.id !== member.id && (
|
||||
<StyledButtonContainer>
|
||||
<IconButton
|
||||
onClick={() => {
|
||||
setIsConfirmationModalOpen(true);
|
||||
setUserToDelete(member.user.id);
|
||||
setWorkspaceMemberToDelete(member.id);
|
||||
}}
|
||||
variant="tertiary"
|
||||
size="medium"
|
||||
@ -133,7 +103,8 @@ export const SettingsWorkspaceMembers = () => {
|
||||
</>
|
||||
}
|
||||
onConfirmClick={() =>
|
||||
userToDelete && handleRemoveWorkspaceMember(userToDelete)
|
||||
workspaceMemberToDelete &&
|
||||
handleRemoveWorkspaceMember(workspaceMemberToDelete)
|
||||
}
|
||||
deleteButtonText="Delete account"
|
||||
/>
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useRecoilState } from 'recoil';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { currentUserState } from '@/auth/states/currentUserState';
|
||||
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
||||
import { useFilter } from '@/ui/object/object-filter-dropdown/hooks/useFilter';
|
||||
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
|
||||
|
||||
import { tasksFilterDefinitions } from './tasks-filter-definitions';
|
||||
|
||||
export const TasksEffect = () => {
|
||||
const [currentUser] = useRecoilState(currentUserState);
|
||||
const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState);
|
||||
const { setSelectedFilter, setAvailableFilterDefinitions } = useFilter();
|
||||
|
||||
useEffect(() => {
|
||||
@ -16,16 +16,19 @@ export const TasksEffect = () => {
|
||||
}, [setAvailableFilterDefinitions]);
|
||||
|
||||
useEffect(() => {
|
||||
if (currentUser) {
|
||||
if (currentWorkspaceMember) {
|
||||
setSelectedFilter({
|
||||
fieldMetadataId: 'assigneeId',
|
||||
value: currentUser.id,
|
||||
value: currentWorkspaceMember.id,
|
||||
operand: ViewFilterOperand.Is,
|
||||
displayValue: currentUser.displayName,
|
||||
displayAvatarUrl: currentUser.avatarUrl ?? undefined,
|
||||
displayValue:
|
||||
currentWorkspaceMember.firstName +
|
||||
' ' +
|
||||
currentWorkspaceMember.lastName,
|
||||
displayAvatarUrl: currentWorkspaceMember.avatarUrl ?? undefined,
|
||||
definition: tasksFilterDefinitions[0],
|
||||
});
|
||||
}
|
||||
}, [currentUser, setSelectedFilter]);
|
||||
}, [currentWorkspaceMember, setSelectedFilter]);
|
||||
return <></>;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user