Add loader on workspace creation (#12806)

Not my most brillant design but it should work!
                  


https://github.com/user-attachments/assets/b89ae6d8-84ca-43c4-a010-d0686d522183
This commit is contained in:
Charles Bochet
2025-06-23 23:23:13 +02:00
committed by GitHub
parent 4eb859256c
commit d8f4e7e233

View File

@ -1,6 +1,6 @@
import styled from '@emotion/styled';
import { zodResolver } from '@hookform/resolvers/zod';
import { useCallback } from 'react';
import { useCallback, useState } from 'react';
import { Controller, SubmitHandler, useForm } from 'react-hook-form';
import { Key } from 'ts-key-enum';
import { z } from 'zod';
@ -16,6 +16,7 @@ import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { TextInputV2 } from '@/ui/input/components/TextInputV2';
import { Modal } from '@/ui/layout/modal/components/Modal';
import { Trans, useLingui } from '@lingui/react/macro';
import { motion } from 'framer-motion';
import { isDefined } from 'twenty-shared/utils';
import { H2Title } from 'twenty-ui/display';
import { Loader } from 'twenty-ui/feedback';
@ -35,6 +36,21 @@ const StyledButtonContainer = styled.div`
width: 200px;
`;
enum PendingCreationLoaderStep {
None = 'none',
Step1 = 'step-1',
Step2 = 'step-2',
Step3 = 'step-3',
}
const StyledPendingCreationLoader = styled(motion.div)`
height: 388px;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
`;
export const CreateWorkspace = () => {
const { t } = useLingui();
const { enqueueSnackBar } = useSnackBar();
@ -43,6 +59,9 @@ export const CreateWorkspace = () => {
const { loadCurrentUser } = useAuth();
const [activateWorkspace] = useActivateWorkspaceMutation();
const [pendingCreationLoaderStep, setPendingCreationLoaderStep] = useState(
PendingCreationLoaderStep.None,
);
const validationSchema = z
.object({
@ -68,6 +87,16 @@ export const CreateWorkspace = () => {
const onSubmit: SubmitHandler<Form> = useCallback(
async (data) => {
try {
setTimeout(() => {
setPendingCreationLoaderStep(PendingCreationLoaderStep.Step1);
}, 500);
setTimeout(() => {
setPendingCreationLoaderStep(PendingCreationLoaderStep.Step2);
}, 2000);
setTimeout(() => {
setPendingCreationLoaderStep(PendingCreationLoaderStep.Step3);
}, 5000);
const result = await activateWorkspace({
variables: {
input: {
@ -84,6 +113,7 @@ export const CreateWorkspace = () => {
await loadCurrentUser();
setNextOnboardingStatus();
} catch (error: any) {
setPendingCreationLoaderStep(PendingCreationLoaderStep.None);
enqueueSnackBar(error?.message, {
variant: SnackBarVariant.Error,
});
@ -108,55 +138,84 @@ export const CreateWorkspace = () => {
return (
<Modal.Content isVerticalCentered isHorizontalCentered>
<Title noMarginTop>
<Trans>Create your workspace</Trans>
</Title>
<SubTitle>
<Trans>
A shared environment where you will be able to manage your customer
relations with your team.
</Trans>
</SubTitle>
<StyledContentContainer>
<StyledSectionContainer>
<H2Title title={t`Workspace logo`} />
<WorkspaceLogoUploader />
</StyledSectionContainer>
<StyledSectionContainer>
<H2Title
title={t`Workspace name`}
description={t`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
/>
{pendingCreationLoaderStep !== PendingCreationLoaderStep.None && (
<>
<StyledPendingCreationLoader>
{pendingCreationLoaderStep === PendingCreationLoaderStep.Step1 && (
<Title animate>
<Loader color="gray" />
<Trans>Setting up your database</Trans>
</Title>
)}
/>
</StyledSectionContainer>
</StyledContentContainer>
<StyledButtonContainer>
<MainButton
title={t`Continue`}
onClick={handleSubmit(onSubmit)}
disabled={!isValid || isSubmitting}
Icon={() => isSubmitting && <Loader />}
fullWidth
/>
</StyledButtonContainer>
{pendingCreationLoaderStep === PendingCreationLoaderStep.Step2 && (
<Title animate>
<Loader color="gray" />
<Trans>Creating your schema</Trans>
</Title>
)}
{pendingCreationLoaderStep === PendingCreationLoaderStep.Step3 && (
<Title animate>
<Loader color="gray" />
<Trans>Prefilling your workspace data</Trans>
</Title>
)}
</StyledPendingCreationLoader>
</>
)}
{pendingCreationLoaderStep === PendingCreationLoaderStep.None && (
<>
<Title noMarginTop>
<Trans>Create your workspace</Trans>
</Title>
<SubTitle>
<Trans>
A shared environment where you will be able to manage your
customer relations with your team.
</Trans>
</SubTitle>
<StyledContentContainer>
<StyledSectionContainer>
<H2Title title={t`Workspace logo`} />
<WorkspaceLogoUploader />
</StyledSectionContainer>
<StyledSectionContainer>
<H2Title
title={t`Workspace name`}
description={t`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={t`Continue`}
onClick={handleSubmit(onSubmit)}
disabled={!isValid || isSubmitting}
Icon={() => isSubmitting && <Loader />}
fullWidth
/>
</StyledButtonContainer>
</>
)}
</Modal.Content>
);
};