## Context As discussed with @lucasbordeau and @charlesBochet we are looking at making low level UI components stateless when possible. Therefore TextInput should not handle a hotkey state. Instead hotkeys should be defined in the parent component (as done here in CreateProfile). Introducing here TextInputV2 that is stateless and that can already replace TextInput without any behaviour change everywhere it is used with `disableHotkey` prop. ## How was it tested? Locally + Storybook --------- Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
170 lines
5.0 KiB
TypeScript
170 lines
5.0 KiB
TypeScript
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 { useSetRecoilState } from 'recoil';
|
|
import { Key } from 'ts-key-enum';
|
|
import { z } from 'zod';
|
|
|
|
import { SubTitle } from '@/auth/components/SubTitle';
|
|
import { Title } from '@/auth/components/Title';
|
|
import { useOnboardingStatus } from '@/auth/hooks/useOnboardingStatus';
|
|
import { isCurrentUserLoadedState } from '@/auth/states/isCurrentUserLoadingState';
|
|
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 { H2Title } from '@/ui/display/typography/components/H2Title';
|
|
import { Loader } from '@/ui/feedback/loader/components/Loader.tsx';
|
|
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
|
import { MainButton } from '@/ui/input/button/components/MainButton';
|
|
import { TextInputV2 } from '@/ui/input/components/TextInputV2';
|
|
import { useActivateWorkspaceMutation } from '~/generated/graphql';
|
|
import { isDefined } from '~/utils/isDefined';
|
|
|
|
const StyledContentContainer = styled.div`
|
|
width: 100%;
|
|
`;
|
|
|
|
const StyledSectionContainer = styled.div`
|
|
margin-top: ${({ theme }) => theme.spacing(8)};
|
|
`;
|
|
|
|
const StyledButtonContainer = styled.div`
|
|
margin-top: ${({ theme }) => theme.spacing(8)};
|
|
width: 200px;
|
|
`;
|
|
|
|
const validationSchema = z
|
|
.object({
|
|
name: z.string().min(1, { message: 'Name can not be empty' }),
|
|
})
|
|
.required();
|
|
|
|
type Form = z.infer<typeof validationSchema>;
|
|
|
|
export const CreateWorkspace = () => {
|
|
const navigate = useNavigate();
|
|
|
|
const { enqueueSnackBar } = useSnackBar();
|
|
const onboardingStatus = useOnboardingStatus();
|
|
|
|
const [activateWorkspace] = useActivateWorkspaceMutation();
|
|
const apolloMetadataClient = useApolloMetadataClient();
|
|
const setIsCurrentUserLoaded = useSetRecoilState(isCurrentUserLoadedState);
|
|
|
|
// Form
|
|
const {
|
|
control,
|
|
handleSubmit,
|
|
formState: { isValid, isSubmitting },
|
|
} = useForm<Form>({
|
|
mode: 'onChange',
|
|
defaultValues: {
|
|
name: '',
|
|
},
|
|
resolver: zodResolver(validationSchema),
|
|
});
|
|
|
|
const onSubmit: SubmitHandler<Form> = useCallback(
|
|
async (data) => {
|
|
try {
|
|
const result = await activateWorkspace({
|
|
variables: {
|
|
input: {
|
|
displayName: data.name,
|
|
},
|
|
},
|
|
});
|
|
setIsCurrentUserLoaded(false);
|
|
|
|
await apolloMetadataClient?.refetchQueries({
|
|
include: [FIND_MANY_OBJECT_METADATA_ITEMS],
|
|
});
|
|
|
|
if (isDefined(result.errors)) {
|
|
throw result.errors ?? new Error('Unknown error');
|
|
}
|
|
|
|
setTimeout(() => {
|
|
navigate(AppPath.CreateProfile);
|
|
}, 20);
|
|
} catch (error: any) {
|
|
enqueueSnackBar(error?.message, {
|
|
variant: 'error',
|
|
});
|
|
}
|
|
},
|
|
[
|
|
activateWorkspace,
|
|
setIsCurrentUserLoaded,
|
|
apolloMetadataClient,
|
|
navigate,
|
|
enqueueSnackBar,
|
|
],
|
|
);
|
|
|
|
const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
|
|
if (event.key === Key.Enter) {
|
|
event.preventDefault();
|
|
handleSubmit(onSubmit)();
|
|
}
|
|
};
|
|
|
|
if (onboardingStatus !== OnboardingStatus.OngoingWorkspaceActivation) {
|
|
return null;
|
|
}
|
|
|
|
return (
|
|
<>
|
|
<Title withMarginTop={false}>Create your workspace</Title>
|
|
<SubTitle>
|
|
A shared environment where you will be able to manage your customer
|
|
relations with your team.
|
|
</SubTitle>
|
|
<StyledContentContainer>
|
|
<StyledSectionContainer>
|
|
<H2Title title="Workspace logo" />
|
|
<WorkspaceLogoUploader />
|
|
</StyledSectionContainer>
|
|
<StyledSectionContainer>
|
|
<H2Title
|
|
title="Workspace name"
|
|
description="The name of your organization"
|
|
/>
|
|
<Controller
|
|
name="name"
|
|
control={control}
|
|
render={({
|
|
field: { onChange, onBlur, value },
|
|
fieldState: { error },
|
|
}) => (
|
|
<TextInputV2
|
|
autoFocus
|
|
value={value}
|
|
placeholder="Apple"
|
|
onBlur={onBlur}
|
|
onChange={onChange}
|
|
error={error?.message}
|
|
onKeyDown={handleKeyDown}
|
|
fullWidth
|
|
/>
|
|
)}
|
|
/>
|
|
</StyledSectionContainer>
|
|
</StyledContentContainer>
|
|
<StyledButtonContainer>
|
|
<MainButton
|
|
title="Continue"
|
|
onClick={handleSubmit(onSubmit)}
|
|
disabled={!isValid || isSubmitting}
|
|
Icon={() => isSubmitting && <Loader />}
|
|
fullWidth
|
|
/>
|
|
</StyledButtonContainer>
|
|
</>
|
|
);
|
|
};
|