3628 timebox separate user creation from workspace creation (#3737)
* Remove workspace schema creation from signUp * Set user workspaceMember nullable * Remove workspace creation * Handle null workspace in tokens * Update onboarding status * Generate types * Move createWorkspace to workspace resolver * Create workspace after signup * Update createWorkspace return type * Update createWorkspace return type * Create core.workspace at signup * WIP * Fix create workspace * Fix create workspace * Clean code * Remove useless recoil set * Simplify create workspace request * Set currentWorkspace at login * Fix tests * Create a recoil value for is workspaceSchema created * Rename createWorkspace to createWorkspaceSchema * Code review returns * Use AppPath when possible * Try without state * Fix * Fixes * Rename createWorkspaceSchema to activateWorkspace * Remove defaultAvatarUrl from user * Add defaultAvatarUrl to core user This reverts commit 1701c30eb18804558293cc42043aedf96ea888df. * Add defaultAvatarUrl to core user This reverts commit 1701c30eb18804558293cc42043aedf96ea888df. * Fix ci * Fix tests * Fix storybook * Fix test * Remove useless query * Fix test * Fix test * Fix mock data * Fix test * Clean Mock Requests * Fix tentative * Revert "Clean Mock Requests" This reverts commit 8aa20a34363ffddfdee24f18fc80b27ea0ad5e1d. * Fix * Revert "Fix" This reverts commit 2df7e9b6569b8bfb53f6a45391db725e28d16a18. * Revert "Revert "Clean Mock Requests"" This reverts commit 3aefef8e9600d161434a047e845563d1b8e0692e. * Revert "Fix tentative" This reverts commit 13e7748d6f3b3858d30fb08adbc8ad347c5556ee. * Update filename --------- Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
@ -1,6 +1,5 @@
|
||||
import { useCallback } from 'react';
|
||||
import { Controller, SubmitHandler, useForm } from 'react-hook-form';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import styled from '@emotion/styled';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { useRecoilState } from 'recoil';
|
||||
@ -54,7 +53,6 @@ const validationSchema = z
|
||||
type Form = z.infer<typeof validationSchema>;
|
||||
|
||||
export const CreateProfile = () => {
|
||||
const navigate = useNavigate();
|
||||
const onboardingStatus = useOnboardingStatus();
|
||||
|
||||
const { enqueueSnackBar } = useSnackBar();
|
||||
@ -114,8 +112,6 @@ export const CreateProfile = () => {
|
||||
colorScheme: 'System',
|
||||
}) as any,
|
||||
);
|
||||
|
||||
navigate('/');
|
||||
} catch (error: any) {
|
||||
enqueueSnackBar(error?.message, {
|
||||
variant: 'error',
|
||||
@ -125,7 +121,6 @@ export const CreateProfile = () => {
|
||||
[
|
||||
currentWorkspaceMember?.id,
|
||||
enqueueSnackBar,
|
||||
navigate,
|
||||
setCurrentWorkspaceMember,
|
||||
updateOneRecord,
|
||||
],
|
||||
|
||||
@ -3,22 +3,24 @@ import { Controller, SubmitHandler, useForm } from 'react-hook-form';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import styled from '@emotion/styled';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { useSetRecoilState } from 'recoil';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { SubTitle } from '@/auth/components/SubTitle';
|
||||
import { Title } from '@/auth/components/Title';
|
||||
import { useOnboardingStatus } from '@/auth/hooks/useOnboardingStatus';
|
||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||
import { OnboardingStatus } from '@/auth/utils/getOnboardingStatus';
|
||||
import { FIND_MANY_OBJECT_METADATA_ITEMS } from '@/object-metadata/graphql/queries';
|
||||
import { useApolloMetadataClient } from '@/object-metadata/hooks/useApolloMetadataClient';
|
||||
import { WorkspaceLogoUploader } from '@/settings/workspace/components/WorkspaceLogoUploader';
|
||||
import { AppPath } from '@/types/AppPath';
|
||||
import { PageHotkeyScope } from '@/types/PageHotkeyScope';
|
||||
import { H2Title } from '@/ui/display/typography/components/H2Title';
|
||||
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
||||
import { MainButton } from '@/ui/input/button/components/MainButton';
|
||||
import { TextInput } from '@/ui/input/components/TextInput';
|
||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||
import { useUpdateWorkspaceMutation } from '~/generated/graphql';
|
||||
import { GET_CURRENT_USER } from '@/users/graphql/queries/getCurrentUser';
|
||||
import { useActivateWorkspaceMutation } from '~/generated/graphql';
|
||||
|
||||
const StyledContentContainer = styled.div`
|
||||
width: 100%;
|
||||
@ -46,9 +48,9 @@ export const CreateWorkspace = () => {
|
||||
|
||||
const { enqueueSnackBar } = useSnackBar();
|
||||
const onboardingStatus = useOnboardingStatus();
|
||||
const setCurrentWorkspace = useSetRecoilState(currentWorkspaceState);
|
||||
|
||||
const [updateWorkspace] = useUpdateWorkspaceMutation();
|
||||
const [activateWorkspace] = useActivateWorkspaceMutation();
|
||||
const apolloMetadataClient = useApolloMetadataClient();
|
||||
|
||||
// Form
|
||||
const {
|
||||
@ -67,28 +69,25 @@ export const CreateWorkspace = () => {
|
||||
const onSubmit: SubmitHandler<Form> = useCallback(
|
||||
async (data) => {
|
||||
try {
|
||||
const result = await updateWorkspace({
|
||||
const result = await activateWorkspace({
|
||||
variables: {
|
||||
input: {
|
||||
displayName: data.name,
|
||||
},
|
||||
},
|
||||
});
|
||||
setCurrentWorkspace({
|
||||
id: result.data?.updateWorkspace?.id ?? '',
|
||||
displayName: data.name,
|
||||
subscriptionStatus:
|
||||
result.data?.updateWorkspace?.subscriptionStatus ?? 'incomplete',
|
||||
allowImpersonation:
|
||||
result.data?.updateWorkspace?.allowImpersonation ?? false,
|
||||
refetchQueries: [GET_CURRENT_USER],
|
||||
});
|
||||
|
||||
if (result.errors || !result.data?.updateWorkspace) {
|
||||
await apolloMetadataClient?.refetchQueries({
|
||||
include: [FIND_MANY_OBJECT_METADATA_ITEMS],
|
||||
});
|
||||
|
||||
if (result.errors) {
|
||||
throw result.errors ?? new Error('Unknown error');
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
navigate('/create/profile');
|
||||
navigate(AppPath.CreateProfile);
|
||||
}, 20);
|
||||
} catch (error: any) {
|
||||
enqueueSnackBar(error?.message, {
|
||||
@ -96,7 +95,7 @@ export const CreateWorkspace = () => {
|
||||
});
|
||||
}
|
||||
},
|
||||
[enqueueSnackBar, navigate, setCurrentWorkspace, updateWorkspace],
|
||||
[enqueueSnackBar, navigate, apolloMetadataClient, activateWorkspace],
|
||||
);
|
||||
|
||||
const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
|
||||
@ -115,7 +114,7 @@ export const CreateWorkspace = () => {
|
||||
[onSubmit],
|
||||
);
|
||||
|
||||
if (onboardingStatus !== OnboardingStatus.OngoingWorkspaceCreation) {
|
||||
if (onboardingStatus !== OnboardingStatus.OngoingWorkspaceActivation) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@ -6,8 +6,7 @@ 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';
|
||||
import { AppPath } from '@/types/AppPath';
|
||||
|
||||
export const VerifyEffect = () => {
|
||||
const [searchParams] = useSearchParams();
|
||||
|
||||
@ -4,7 +4,7 @@ import { within } from '@storybook/test';
|
||||
import { graphql, HttpResponse } from 'msw';
|
||||
|
||||
import { AppPath } from '@/types/AppPath';
|
||||
import { GET_CURRENT_USER_AND_VIEWS } from '@/users/graphql/queries/getCurrentUserAndViews';
|
||||
import { GET_CURRENT_USER } from '@/users/graphql/queries/getCurrentUser';
|
||||
import {
|
||||
PageDecorator,
|
||||
PageDecoratorArgs,
|
||||
@ -22,16 +22,13 @@ const meta: Meta<PageDecoratorArgs> = {
|
||||
parameters: {
|
||||
msw: {
|
||||
handlers: [
|
||||
graphql.query(
|
||||
getOperationName(GET_CURRENT_USER_AND_VIEWS) ?? '',
|
||||
() => {
|
||||
return HttpResponse.json({
|
||||
data: {
|
||||
currentUser: mockedOnboardingUsersData[0],
|
||||
},
|
||||
});
|
||||
},
|
||||
),
|
||||
graphql.query(getOperationName(GET_CURRENT_USER) ?? '', () => {
|
||||
return HttpResponse.json({
|
||||
data: {
|
||||
currentUser: mockedOnboardingUsersData[0],
|
||||
},
|
||||
});
|
||||
}),
|
||||
graphqlMocks.handlers,
|
||||
],
|
||||
},
|
||||
|
||||
@ -1,14 +1,18 @@
|
||||
import { getOperationName } from '@apollo/client/utilities';
|
||||
import { Meta, StoryObj } from '@storybook/react';
|
||||
import { within } from '@storybook/test';
|
||||
import { graphql, HttpResponse } from 'msw';
|
||||
import { useSetRecoilState } from 'recoil';
|
||||
|
||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||
import { AppPath } from '@/types/AppPath';
|
||||
import { GET_CURRENT_USER } from '@/users/graphql/queries/getCurrentUser';
|
||||
import {
|
||||
PageDecorator,
|
||||
PageDecoratorArgs,
|
||||
} from '~/testing/decorators/PageDecorator';
|
||||
import { graphqlMocks } from '~/testing/graphqlMocks';
|
||||
import { mockedOnboardingUsersData } from '~/testing/mock-data/users';
|
||||
|
||||
import { CreateWorkspace } from '../CreateWorkspace';
|
||||
|
||||
@ -25,7 +29,18 @@ const meta: Meta<PageDecoratorArgs> = {
|
||||
],
|
||||
args: { routePath: AppPath.CreateWorkspace },
|
||||
parameters: {
|
||||
msw: graphqlMocks,
|
||||
msw: {
|
||||
handlers: [
|
||||
graphql.query(getOperationName(GET_CURRENT_USER) ?? '', () => {
|
||||
return HttpResponse.json({
|
||||
data: {
|
||||
currentUser: mockedOnboardingUsersData[1],
|
||||
},
|
||||
});
|
||||
}),
|
||||
graphqlMocks.handlers,
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@ -4,7 +4,7 @@ import { within } from '@storybook/test';
|
||||
import { graphql, HttpResponse } from 'msw';
|
||||
|
||||
import { AppPath } from '@/types/AppPath';
|
||||
import { GET_CURRENT_USER_AND_VIEWS } from '@/users/graphql/queries/getCurrentUserAndViews';
|
||||
import { GET_CURRENT_USER } from '@/users/graphql/queries/getCurrentUser';
|
||||
import {
|
||||
PageDecorator,
|
||||
PageDecoratorArgs,
|
||||
@ -22,22 +22,19 @@ const meta: Meta<PageDecoratorArgs> = {
|
||||
parameters: {
|
||||
msw: {
|
||||
handlers: [
|
||||
graphql.query(
|
||||
getOperationName(GET_CURRENT_USER_AND_VIEWS) ?? '',
|
||||
() => {
|
||||
return HttpResponse.json({
|
||||
data: {
|
||||
currentUser: {
|
||||
...mockedOnboardingUsersData[0],
|
||||
defaultWorkspace: {
|
||||
...mockedOnboardingUsersData[0].defaultWorkspace,
|
||||
subscriptionStatus: 'incomplete',
|
||||
},
|
||||
graphql.query(getOperationName(GET_CURRENT_USER) ?? '', () => {
|
||||
return HttpResponse.json({
|
||||
data: {
|
||||
currentUser: {
|
||||
...mockedOnboardingUsersData[0],
|
||||
defaultWorkspace: {
|
||||
...mockedOnboardingUsersData[0].defaultWorkspace,
|
||||
subscriptionStatus: 'incomplete',
|
||||
},
|
||||
},
|
||||
});
|
||||
},
|
||||
),
|
||||
},
|
||||
});
|
||||
}),
|
||||
graphqlMocks.handlers,
|
||||
],
|
||||
},
|
||||
|
||||
@ -4,7 +4,7 @@ import { fireEvent, within } from '@storybook/test';
|
||||
import { graphql, HttpResponse } from 'msw';
|
||||
|
||||
import { AppPath } from '@/types/AppPath';
|
||||
import { GET_CURRENT_USER_AND_VIEWS } from '@/users/graphql/queries/getCurrentUserAndViews';
|
||||
import { GET_CURRENT_USER } from '@/users/graphql/queries/getCurrentUser';
|
||||
import {
|
||||
PageDecorator,
|
||||
PageDecoratorArgs,
|
||||
@ -22,16 +22,13 @@ const meta: Meta<PageDecoratorArgs> = {
|
||||
parameters: {
|
||||
msw: {
|
||||
handlers: [
|
||||
graphql.query(
|
||||
getOperationName(GET_CURRENT_USER_AND_VIEWS) ?? '',
|
||||
() => {
|
||||
return HttpResponse.json({
|
||||
data: {
|
||||
currentUser: mockedOnboardingUsersData[0],
|
||||
},
|
||||
});
|
||||
},
|
||||
),
|
||||
graphql.query(getOperationName(GET_CURRENT_USER) ?? '', () => {
|
||||
return HttpResponse.json({
|
||||
data: {
|
||||
currentUser: mockedOnboardingUsersData[0],
|
||||
},
|
||||
});
|
||||
}),
|
||||
graphqlMocks.handlers,
|
||||
],
|
||||
},
|
||||
|
||||
@ -6,10 +6,9 @@ import { useRecoilState, useSetRecoilState } from 'recoil';
|
||||
import { useIsLogged } from '@/auth/hooks/useIsLogged';
|
||||
import { currentUserState } from '@/auth/states/currentUserState';
|
||||
import { tokenPairState } from '@/auth/states/tokenPairState';
|
||||
import { AppPath } from '@/types/AppPath';
|
||||
import { useImpersonateMutation } from '~/generated/graphql';
|
||||
|
||||
import { AppPath } from '../../modules/types/AppPath';
|
||||
|
||||
export const ImpersonateEffect = () => {
|
||||
const navigate = useNavigate();
|
||||
const { userId } = useParams();
|
||||
|
||||
@ -2,6 +2,7 @@ import { useNavigate } from 'react-router-dom';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { SignInBackgroundMockPage } from '@/sign-in-background-mock/components/SignInBackgroundMockPage';
|
||||
import { AppPath } from '@/types/AppPath';
|
||||
import { MainButton } from '@/ui/input/button/components/MainButton';
|
||||
import AnimatedPlaceholder from '@/ui/layout/animated-placeholder/components/AnimatedPlaceholder';
|
||||
import { StyledEmptyTextContainer } from '@/ui/layout/animated-placeholder/components/EmptyPlaceholderStyled';
|
||||
@ -49,7 +50,7 @@ export const NotFound = () => {
|
||||
<MainButton
|
||||
title="Back to content"
|
||||
fullWidth
|
||||
onClick={() => navigate('/')}
|
||||
onClick={() => navigate(AppPath.Index)}
|
||||
/>
|
||||
</StyledButtonContainer>
|
||||
</StyledErrorContainer>
|
||||
|
||||
@ -1,10 +1,6 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import styled from '@emotion/styled';
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
|
||||
import { useOnboardingStatus } from '@/auth/hooks/useOnboardingStatus';
|
||||
import { OnboardingStatus } from '@/auth/utils/getOnboardingStatus';
|
||||
import { useObjectMetadataItemForSettings } from '@/object-metadata/hooks/useObjectMetadataItemForSettings';
|
||||
import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObjectNameSingularFromPlural';
|
||||
import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord';
|
||||
@ -32,10 +28,6 @@ export const RecordIndexPage = () => {
|
||||
objectNamePlural,
|
||||
});
|
||||
|
||||
const onboardingStatus = useOnboardingStatus();
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
||||
const { findObjectMetadataItemByNamePlural } =
|
||||
useObjectMetadataItemForSettings();
|
||||
|
||||
@ -44,15 +36,6 @@ export const RecordIndexPage = () => {
|
||||
findObjectMetadataItemByNamePlural(objectNamePlural)?.icon,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
!isNonEmptyString(objectNamePlural) &&
|
||||
onboardingStatus === OnboardingStatus.Completed
|
||||
) {
|
||||
navigate('/');
|
||||
}
|
||||
}, [objectNamePlural, navigate, onboardingStatus]);
|
||||
|
||||
const { createOneRecord: createOneObject } = useCreateOneRecord({
|
||||
objectNameSingular,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user