refactor(auth): add workspaces selection (#12098)

This commit is contained in:
Antoine Moreaux
2025-06-13 16:17:35 +02:00
committed by GitHub
parent 836e2f792c
commit b1af98f93d
162 changed files with 3542 additions and 1340 deletions

View File

@ -124,7 +124,7 @@ export const PasswordReset = () => {
const [updatePasswordViaToken, { loading: isUpdatingPassword }] =
useUpdatePasswordViaResetTokenMutation();
const { signInWithCredentials } = useAuth();
const { signInWithCredentialsInWorkspace } = useAuth();
const { readCaptchaToken } = useReadCaptchaToken();
const onSubmit = async (formData: Form) => {
@ -153,7 +153,11 @@ export const PasswordReset = () => {
const token = await readCaptchaToken();
await signInWithCredentials(email || '', formData.newPassword, token);
await signInWithCredentialsInWorkspace(
email || '',
formData.newPassword,
token,
);
navigate(AppPath.Index);
} catch (err) {
logError(err);

View File

@ -1,17 +1,20 @@
import { useSignInUp } from '@/auth/sign-in-up/hooks/useSignInUp';
import { useSignInUpForm } from '@/auth/sign-in-up/hooks/useSignInUpForm';
import { SignInUpStep } from '@/auth/states/signInUpStepState';
import {
SignInUpStep,
signInUpStepState,
} from '@/auth/states/signInUpStepState';
import { workspacePublicDataState } from '@/auth/states/workspacePublicDataState';
import { useRecoilValue } from 'recoil';
import { useRecoilValue, useSetRecoilState } from 'recoil';
import { Logo } from '@/auth/components/Logo';
import { Title } from '@/auth/components/Title';
import { EmailVerificationSent } from '@/auth/sign-in-up/components/EmailVerificationSent';
import { FooterNote } from '@/auth/sign-in-up/components/FooterNote';
import { SignInUpGlobalScopeForm } from '@/auth/sign-in-up/components/SignInUpGlobalScopeForm';
import { SignInUpSSOIdentityProviderSelection } from '@/auth/sign-in-up/components/SignInUpSSOIdentityProviderSelection';
import { SignInUpSSOIdentityProviderSelection } from '@/auth/sign-in-up/components/internal/SignInUpSSOIdentityProviderSelection';
import { SignInUpWorkspaceScopeForm } from '@/auth/sign-in-up/components/SignInUpWorkspaceScopeForm';
import { SignInUpWorkspaceScopeFormEffect } from '@/auth/sign-in-up/components/SignInUpWorkspaceScopeFormEffect';
import { SignInUpWorkspaceScopeFormEffect } from '@/auth/sign-in-up/components/internal/SignInUpWorkspaceScopeFormEffect';
import { isMultiWorkspaceEnabledState } from '@/client-config/states/isMultiWorkspaceEnabledState';
import { useGetPublicWorkspaceDataByDomain } from '@/domain-manager/hooks/useGetPublicWorkspaceDataByDomain';
import { useIsCurrentLocationOnAWorkspace } from '@/domain-manager/hooks/useIsCurrentLocationOnAWorkspace';
@ -26,17 +29,20 @@ import { useSearchParams } from 'react-router-dom';
import { isDefined } from 'twenty-shared/utils';
import { AnimatedEaseIn } from 'twenty-ui/utilities';
import { PublicWorkspaceDataOutput } from '~/generated/graphql';
import { SignInUpGlobalScopeFormEffect } from '@/auth/sign-in-up/components/internal/SignInUpGlobalScopeFormEffect';
const StandardContent = ({
workspacePublicData,
signInUpForm,
signInUpStep,
title,
onClickOnLogo,
}: {
workspacePublicData: PublicWorkspaceDataOutput | null;
signInUpForm: JSX.Element | null;
signInUpStep: SignInUpStep;
title: string;
onClickOnLogo: () => void;
}) => {
return (
<Modal.Content isVerticalCentered isHorizontalCentered>
@ -44,6 +50,7 @@ const StandardContent = ({
<Logo
secondaryLogo={workspacePublicData?.logo}
placeholder={workspacePublicData?.displayName}
onClick={onClickOnLogo}
/>
</AnimatedEaseIn>
<Title animate>{title}</Title>
@ -55,6 +62,7 @@ const StandardContent = ({
export const SignInUp = () => {
const { t } = useLingui();
const setSignInUpStep = useSetRecoilState(signInUpStepState);
const { form } = useSignInUpForm();
const { signInUpStep } = useSignInUp(form);
@ -67,10 +75,20 @@ export const SignInUp = () => {
useWorkspaceFromInviteHash();
const [searchParams] = useSearchParams();
const onClickOnLogo = () => {
setSignInUpStep(SignInUpStep.Init);
};
const title = useMemo(() => {
if (isDefined(workspaceInviteHash)) {
return `Join ${workspaceFromInviteHash?.displayName ?? ''} team`;
}
if (signInUpStep === SignInUpStep.WorkspaceSelection) {
return t`Choose a Workspace`;
}
const workspaceName = !isDefined(workspacePublicData?.displayName)
? DEFAULT_WORKSPACE_NAME
: workspacePublicData?.displayName === ''
@ -79,31 +97,32 @@ export const SignInUp = () => {
return t`Welcome to ${workspaceName}`;
}, [
workspaceFromInviteHash?.displayName,
workspaceInviteHash,
signInUpStep,
workspacePublicData?.displayName,
t,
workspaceFromInviteHash?.displayName,
]);
const signInUpForm = useMemo(() => {
if (loading) return null;
if (isDefaultDomain && isMultiWorkspaceEnabled) {
return <SignInUpGlobalScopeForm />;
return (
<>
<SignInUpGlobalScopeFormEffect />
<SignInUpGlobalScopeForm />
</>
);
}
if (
(!isMultiWorkspaceEnabled ||
(isMultiWorkspaceEnabled && isOnAWorkspace)) &&
isOnAWorkspace &&
signInUpStep === SignInUpStep.SSOIdentityProviderSelection
) {
return <SignInUpSSOIdentityProviderSelection />;
}
if (
isDefined(workspacePublicData) &&
(!isMultiWorkspaceEnabled || isOnAWorkspace)
) {
if (isDefined(workspacePublicData) && isOnAWorkspace) {
return (
<>
<SignInUpWorkspaceScopeFormEffect />
@ -112,7 +131,12 @@ export const SignInUp = () => {
);
}
return <SignInUpGlobalScopeForm />;
return (
<>
<SignInUpGlobalScopeFormEffect />
<SignInUpGlobalScopeForm />
</>
);
}, [
isDefaultDomain,
isMultiWorkspaceEnabled,
@ -136,6 +160,7 @@ export const SignInUp = () => {
signInUpForm={signInUpForm}
signInUpStep={signInUpStep}
title={title}
onClickOnLogo={onClickOnLogo}
/>
);
};

View File

@ -1,19 +1,19 @@
import { SaveAndCancelButtons } from '@/settings/components/SaveAndCancelButtons/SaveAndCancelButtons';
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
import { SettingsPath } from '@/types/SettingsPath';
import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { TextInput } from '@/ui/input/components/TextInput';
import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
import { zodResolver } from '@hookform/resolvers/zod';
import { Controller, useForm } from 'react-hook-form';
import { useNavigateSettings } from '~/hooks/useNavigateSettings';
import { getSettingsPath } from '~/utils/navigation/getSettingsPath';
import { Trans, useLingui } from '@lingui/react/macro';
import { z } from 'zod';
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
import { useCreateApprovedAccessDomainMutation } from '~/generated/graphql';
import { Controller, useForm } from 'react-hook-form';
import { H2Title } from 'twenty-ui/display';
import { Section } from 'twenty-ui/layout';
import { TextInput } from '@/ui/input/components/TextInput';
import { z } from 'zod';
import { useCreateApprovedAccessDomainMutation } from '~/generated/graphql';
import { useNavigateSettings } from '~/hooks/useNavigateSettings';
import { getSettingsPath } from '~/utils/navigation/getSettingsPath';
export const SettingsSecurityApprovedAccessDomain = () => {
const navigate = useNavigateSettings();
@ -62,7 +62,7 @@ export const SettingsSecurityApprovedAccessDomain = () => {
},
},
onCompleted: () => {
enqueueSnackBar(t`Domain added successfully.`, {
enqueueSnackBar(t`Please check your email for a verification link.`, {
variant: SnackBarVariant.Success,
});
navigate(SettingsPath.Security);