[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:
@ -9,49 +9,5 @@ export const USER_QUERY_FRAGMENT = gql`
|
||||
lastName
|
||||
canImpersonate
|
||||
supportUserHash
|
||||
avatarUrl
|
||||
workspaceMember {
|
||||
id
|
||||
allowImpersonation
|
||||
workspace {
|
||||
id
|
||||
domainName
|
||||
displayName
|
||||
logo
|
||||
inviteHash
|
||||
}
|
||||
assignedActivities {
|
||||
id
|
||||
title
|
||||
}
|
||||
authoredActivities {
|
||||
id
|
||||
title
|
||||
}
|
||||
authoredAttachments {
|
||||
id
|
||||
name
|
||||
type
|
||||
}
|
||||
settings {
|
||||
id
|
||||
colorScheme
|
||||
locale
|
||||
}
|
||||
companies {
|
||||
id
|
||||
name
|
||||
domainName
|
||||
}
|
||||
comments {
|
||||
id
|
||||
body
|
||||
}
|
||||
}
|
||||
settings {
|
||||
id
|
||||
colorScheme
|
||||
locale
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
@ -4,12 +4,19 @@ import {
|
||||
snapshot_UNSTABLE,
|
||||
useGotoRecoilSnapshot,
|
||||
useRecoilState,
|
||||
useSetRecoilState,
|
||||
} from 'recoil';
|
||||
|
||||
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||
import { isVerifyPendingState } from '@/auth/states/isVerifyPendingState';
|
||||
import { CREATE_ONE_WORKSPACE_MEMBER_V2 } from '@/object-record/graphql/mutation/createOneWorkspaceMember';
|
||||
import { FIND_ONE_WORKSPACE_MEMBER_V2 } from '@/object-record/graphql/queries/findOneWorkspaceMember';
|
||||
import { REACT_APP_SERVER_AUTH_URL } from '~/config';
|
||||
import {
|
||||
useChallengeMutation,
|
||||
useCheckUserExistsLazyQuery,
|
||||
useGetCurrentWorkspaceLazyQuery,
|
||||
useSignUpMutation,
|
||||
useVerifyMutation,
|
||||
} from '~/generated/graphql';
|
||||
@ -19,13 +26,20 @@ import { tokenPairState } from '../states/tokenPairState';
|
||||
|
||||
export const useAuth = () => {
|
||||
const [, setTokenPair] = useRecoilState(tokenPairState);
|
||||
const [, setCurrentUser] = useRecoilState(currentUserState);
|
||||
const setCurrentUser = useSetRecoilState(currentUserState);
|
||||
const setCurrentWorkspaceMember = useSetRecoilState(
|
||||
currentWorkspaceMemberState,
|
||||
);
|
||||
const setCurrentWorkspace = useSetRecoilState(currentWorkspaceState);
|
||||
const setIsVerifyPendingState = useSetRecoilState(isVerifyPendingState);
|
||||
|
||||
const [challenge] = useChallengeMutation();
|
||||
const [signUp] = useSignUpMutation();
|
||||
const [verify] = useVerifyMutation();
|
||||
const [checkUserExistsQuery, { data: checkUserExistsData }] =
|
||||
useCheckUserExistsLazyQuery();
|
||||
const [getCurrentWorkspaceQuery, { data: getCurrentWorkspaceData }] =
|
||||
useGetCurrentWorkspaceLazyQuery();
|
||||
|
||||
const client = useApolloClient();
|
||||
|
||||
@ -67,36 +81,56 @@ export const useAuth = () => {
|
||||
throw new Error('No verify result');
|
||||
}
|
||||
|
||||
if (!verifyResult.data?.verify.user.workspaceMember) {
|
||||
throw new Error('No workspace member');
|
||||
}
|
||||
|
||||
if (!verifyResult.data?.verify.user.workspaceMember.settings) {
|
||||
throw new Error('No settings');
|
||||
}
|
||||
|
||||
setCurrentUser({
|
||||
...verifyResult.data?.verify.user,
|
||||
workspaceMember: {
|
||||
...verifyResult.data?.verify.user.workspaceMember,
|
||||
settings: verifyResult.data?.verify.user.workspaceMember.settings,
|
||||
setTokenPair(verifyResult.data?.verify.tokens);
|
||||
const workspaceMember = await client.query({
|
||||
query: FIND_ONE_WORKSPACE_MEMBER_V2,
|
||||
variables: {
|
||||
filter: {
|
||||
userId: { eq: verifyResult.data?.verify.user.id },
|
||||
},
|
||||
},
|
||||
});
|
||||
setTokenPair(verifyResult.data?.verify.tokens);
|
||||
const currentWorkspace = await getCurrentWorkspaceQuery();
|
||||
|
||||
return verifyResult.data?.verify;
|
||||
setCurrentUser(verifyResult.data?.verify.user);
|
||||
setCurrentWorkspaceMember(workspaceMember.data?.findMany);
|
||||
setCurrentWorkspace(currentWorkspace.data?.currentWorkspace ?? null);
|
||||
return {
|
||||
user: verifyResult.data?.verify.user,
|
||||
workspaceMember: workspaceMember.data?.findMany,
|
||||
workspace: currentWorkspace.data?.currentWorkspace,
|
||||
tokens: verifyResult.data?.verify.tokens,
|
||||
};
|
||||
},
|
||||
[setTokenPair, verify, setCurrentUser],
|
||||
[
|
||||
verify,
|
||||
setTokenPair,
|
||||
client,
|
||||
getCurrentWorkspaceQuery,
|
||||
setCurrentUser,
|
||||
setCurrentWorkspaceMember,
|
||||
setCurrentWorkspace,
|
||||
],
|
||||
);
|
||||
|
||||
const handleCrendentialsSignIn = useCallback(
|
||||
async (email: string, password: string) => {
|
||||
const { loginToken } = await handleChallenge(email, password);
|
||||
setIsVerifyPendingState(true);
|
||||
|
||||
const { user } = await handleVerify(loginToken.token);
|
||||
return user;
|
||||
const { user, workspaceMember, workspace } = await handleVerify(
|
||||
loginToken.token,
|
||||
);
|
||||
|
||||
setIsVerifyPendingState(false);
|
||||
|
||||
return {
|
||||
user,
|
||||
workspaceMember,
|
||||
workspace,
|
||||
};
|
||||
},
|
||||
[handleChallenge, handleVerify],
|
||||
[handleChallenge, handleVerify, setIsVerifyPendingState],
|
||||
);
|
||||
|
||||
const handleSignOut = useCallback(() => {
|
||||
@ -110,6 +144,8 @@ export const useAuth = () => {
|
||||
|
||||
const handleCredentialsSignUp = useCallback(
|
||||
async (email: string, password: string, workspaceInviteHash?: string) => {
|
||||
setIsVerifyPendingState(true);
|
||||
|
||||
const signUpResult = await signUp({
|
||||
variables: {
|
||||
email,
|
||||
@ -126,13 +162,30 @@ export const useAuth = () => {
|
||||
throw new Error('No login token');
|
||||
}
|
||||
|
||||
const { user } = await handleVerify(
|
||||
const { user, workspace } = await handleVerify(
|
||||
signUpResult.data?.signUp.loginToken.token,
|
||||
);
|
||||
|
||||
return user;
|
||||
const workspaceMember = await client.mutate({
|
||||
mutation: CREATE_ONE_WORKSPACE_MEMBER_V2,
|
||||
variables: {
|
||||
input: {
|
||||
firstName: user.firstName ?? '',
|
||||
lastName: user.lastName ?? '',
|
||||
colorScheme: 'Light',
|
||||
userId: user.id,
|
||||
allowImpersonation: true,
|
||||
locale: 'en',
|
||||
},
|
||||
},
|
||||
});
|
||||
setCurrentWorkspaceMember(workspaceMember.data?.createWorkspaceMemberV2);
|
||||
|
||||
setIsVerifyPendingState(false);
|
||||
|
||||
return { user, workspaceMember, workspace };
|
||||
},
|
||||
[signUp, handleVerify],
|
||||
[setIsVerifyPendingState, signUp, handleVerify, client],
|
||||
);
|
||||
|
||||
const handleGoogleLogin = useCallback((workspaceInviteHash?: string) => {
|
||||
|
||||
@ -1,9 +1,12 @@
|
||||
import { useRecoilState } from 'recoil';
|
||||
import { useRecoilState, useRecoilValue } from 'recoil';
|
||||
|
||||
import { isVerifyPendingState } from '@/auth/states/isVerifyPendingState';
|
||||
|
||||
import { tokenPairState } from '../states/tokenPairState';
|
||||
|
||||
export const useIsLogged = (): boolean => {
|
||||
const [tokenPair] = useRecoilState(tokenPairState);
|
||||
const isVerifyPending = useRecoilValue(isVerifyPendingState);
|
||||
|
||||
return !!tokenPair;
|
||||
return !!tokenPair && !isVerifyPending;
|
||||
};
|
||||
|
||||
@ -1,15 +1,26 @@
|
||||
import { useRecoilState } from 'recoil';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||
|
||||
import { useIsLogged } from '../hooks/useIsLogged';
|
||||
import { currentUserState } from '../states/currentUserState';
|
||||
import {
|
||||
getOnboardingStatus,
|
||||
OnboardingStatus,
|
||||
} from '../utils/getOnboardingStatus';
|
||||
|
||||
export const useOnboardingStatus = (): OnboardingStatus | undefined => {
|
||||
const [currentUser] = useRecoilState(currentUserState);
|
||||
const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState);
|
||||
const currentWorkspace = useRecoilValue(currentWorkspaceState);
|
||||
const isLoggedIn = useIsLogged();
|
||||
|
||||
return getOnboardingStatus(isLoggedIn, currentUser);
|
||||
console.log(
|
||||
getOnboardingStatus(isLoggedIn, currentWorkspaceMember, currentWorkspace),
|
||||
);
|
||||
|
||||
return getOnboardingStatus(
|
||||
isLoggedIn,
|
||||
currentWorkspaceMember,
|
||||
currentWorkspace,
|
||||
);
|
||||
};
|
||||
|
||||
@ -62,7 +62,7 @@ export const useSignInUp = () => {
|
||||
});
|
||||
const [showErrors, setShowErrors] = useState(false);
|
||||
|
||||
const { data: workspace } = useGetWorkspaceFromInviteHashQuery({
|
||||
const { data: workspaceFromInviteHash } = useGetWorkspaceFromInviteHashQuery({
|
||||
variables: { inviteHash: workspaceInviteHash || '' },
|
||||
});
|
||||
|
||||
@ -119,20 +119,23 @@ export const useSignInUp = () => {
|
||||
if (!data.email || !data.password) {
|
||||
throw new Error('Email and password are required');
|
||||
}
|
||||
let user;
|
||||
let currentWorkspace;
|
||||
|
||||
if (signInUpMode === SignInUpMode.SignIn) {
|
||||
user = await signInWithCredentials(
|
||||
const { workspace } = await signInWithCredentials(
|
||||
data.email.toLowerCase(),
|
||||
data.password,
|
||||
);
|
||||
currentWorkspace = workspace;
|
||||
} else {
|
||||
user = await signUpWithCredentials(
|
||||
const { workspace } = await signUpWithCredentials(
|
||||
data.email.toLowerCase(),
|
||||
data.password,
|
||||
workspaceInviteHash,
|
||||
);
|
||||
currentWorkspace = workspace;
|
||||
}
|
||||
if (user?.workspaceMember?.workspace?.displayName) {
|
||||
if (currentWorkspace?.displayName) {
|
||||
navigate('/');
|
||||
} else {
|
||||
navigate('/create/workspace');
|
||||
@ -144,12 +147,12 @@ export const useSignInUp = () => {
|
||||
}
|
||||
},
|
||||
[
|
||||
navigate,
|
||||
signInUpMode,
|
||||
signInWithCredentials,
|
||||
signUpWithCredentials,
|
||||
workspaceInviteHash,
|
||||
navigate,
|
||||
enqueueSnackBar,
|
||||
signInUpMode,
|
||||
],
|
||||
);
|
||||
|
||||
@ -188,6 +191,6 @@ export const useSignInUp = () => {
|
||||
goBackToEmailStep,
|
||||
submitCredentials,
|
||||
form,
|
||||
workspace: workspace?.findWorkspaceFromInviteHash,
|
||||
workspace: workspaceFromInviteHash?.findWorkspaceFromInviteHash,
|
||||
};
|
||||
};
|
||||
|
||||
@ -1,32 +1,11 @@
|
||||
import { atom } from 'recoil';
|
||||
|
||||
import {
|
||||
User,
|
||||
UserSettings,
|
||||
Workspace,
|
||||
WorkspaceMember,
|
||||
} from '~/generated/graphql';
|
||||
import { User } from '~/generated/graphql';
|
||||
|
||||
export type CurrentUser = Pick<
|
||||
User,
|
||||
| 'id'
|
||||
| 'email'
|
||||
| 'displayName'
|
||||
| 'firstName'
|
||||
| 'lastName'
|
||||
| 'avatarUrl'
|
||||
| 'canImpersonate'
|
||||
| 'supportUserHash'
|
||||
> & {
|
||||
workspaceMember: Pick<WorkspaceMember, 'id' | 'allowImpersonation'> & {
|
||||
workspace: Pick<
|
||||
Workspace,
|
||||
'id' | 'displayName' | 'domainName' | 'inviteHash' | 'logo'
|
||||
>;
|
||||
settings: Pick<UserSettings, 'id' | 'colorScheme' | 'locale'>;
|
||||
};
|
||||
settings: Pick<UserSettings, 'id' | 'colorScheme' | 'locale'>;
|
||||
};
|
||||
'id' | 'email' | 'supportUserHash' | 'canImpersonate'
|
||||
>;
|
||||
|
||||
export const currentUserState = atom<CurrentUser | null>({
|
||||
key: 'currentUserState',
|
||||
|
||||
18
front/src/modules/auth/states/currentWorkspaceMemberState.ts
Normal file
18
front/src/modules/auth/states/currentWorkspaceMemberState.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { atom } from 'recoil';
|
||||
|
||||
import { ColorScheme } from '~/generated-metadata/graphql';
|
||||
|
||||
export type CurrentWorkspaceMember = {
|
||||
id: string;
|
||||
locale: string;
|
||||
colorScheme: ColorScheme;
|
||||
allowImpersonation: boolean;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
avatarUrl: string;
|
||||
};
|
||||
|
||||
export const currentWorkspaceMemberState = atom<CurrentWorkspaceMember | null>({
|
||||
key: 'currentWorkspaceMemberState',
|
||||
default: null,
|
||||
});
|
||||
13
front/src/modules/auth/states/currentWorkspaceState.ts
Normal file
13
front/src/modules/auth/states/currentWorkspaceState.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { atom } from 'recoil';
|
||||
|
||||
import { Workspace } from '~/generated-metadata/graphql';
|
||||
|
||||
export type CurrentWorkspace = Pick<
|
||||
Workspace,
|
||||
'id' | 'inviteHash' | 'logo' | 'displayName'
|
||||
>;
|
||||
|
||||
export const currentWorkspaceState = atom<CurrentWorkspace | null>({
|
||||
key: 'currentWorkspaceState',
|
||||
default: null,
|
||||
});
|
||||
6
front/src/modules/auth/states/isVerifyPendingState.ts
Normal file
6
front/src/modules/auth/states/isVerifyPendingState.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import { atom } from 'recoil';
|
||||
|
||||
export const isVerifyPendingState = atom<boolean>({
|
||||
key: 'isVerifyPendingState',
|
||||
default: false,
|
||||
});
|
||||
@ -1,4 +1,5 @@
|
||||
import { CurrentUser } from '../states/currentUserState';
|
||||
import { CurrentWorkspaceMember } from '@/auth/states/currentWorkspaceMemberState';
|
||||
import { CurrentWorkspace } from '@/auth/states/currentWorkspaceState';
|
||||
|
||||
export enum OnboardingStatus {
|
||||
OngoingUserCreation = 'ongoing_user_creation',
|
||||
@ -9,21 +10,22 @@ export enum OnboardingStatus {
|
||||
|
||||
export const getOnboardingStatus = (
|
||||
isLoggedIn: boolean,
|
||||
currentUser: CurrentUser | null,
|
||||
currentWorkspaceMember: CurrentWorkspaceMember | null,
|
||||
currentWorkspace: CurrentWorkspace | null,
|
||||
) => {
|
||||
if (!isLoggedIn) {
|
||||
return OnboardingStatus.OngoingUserCreation;
|
||||
}
|
||||
|
||||
// if the user has not been fetched yet, we can't know the onboarding status
|
||||
if (!currentUser) {
|
||||
if (!currentWorkspaceMember) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (!currentUser.workspaceMember?.workspace.displayName) {
|
||||
if (!currentWorkspace?.displayName) {
|
||||
return OnboardingStatus.OngoingWorkspaceCreation;
|
||||
}
|
||||
if (!currentUser.firstName || !currentUser.lastName) {
|
||||
if (!currentWorkspaceMember.firstName || !currentWorkspaceMember.lastName) {
|
||||
return OnboardingStatus.OngoingProfileCreation;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user