5509 remove flash on intermediate verify step when sign in with sso (#5526)

- remove flash on /verify
- remove flash on signInUp
- remove useless redirections and hooks
- Remove DefaultHomePage component
- Move redirections to /objects/companies in PageChangeEffect
- add useShowAuthModal hooks and tests
- add usePageChangeEffectNaviteLocation hooks and tests
- fix refresh token expired produces blank screen
This commit is contained in:
martmull
2024-05-25 10:36:59 +02:00
committed by GitHub
parent f455ad4001
commit 9080981990
26 changed files with 976 additions and 418 deletions

View File

@ -1,9 +0,0 @@
import { Navigate } from 'react-router-dom';
import { useDefaultHomePagePath } from '~/hooks/useDefaultHomePagePath';
export const DefaultHomePage = () => {
const { defaultHomePagePath } = useDefaultHomePagePath();
return <Navigate to={defaultHomePagePath} />;
};

View File

@ -5,7 +5,7 @@ import { useRecoilValue } from 'recoil';
import { SubTitle } from '@/auth/components/SubTitle';
import { Title } from '@/auth/components/Title';
import { useSignOutAndRedirect } from '@/auth/hooks/useSignOutAndRedirect';
import { useAuth } from '@/auth/hooks/useAuth';
import { SubscriptionBenefit } from '@/billing/components/SubscriptionBenefit';
import { SubscriptionCard } from '@/billing/components/SubscriptionCard';
import { billingState } from '@/client-config/states/billingState';
@ -95,7 +95,7 @@ export const ChooseYourPlan = () => {
};
};
const handleLogout = useSignOutAndRedirect();
const { signOut } = useAuth();
const computeInfo = (
price: ProductPriceEntity,
@ -175,7 +175,7 @@ export const ChooseYourPlan = () => {
disabled={isSubmitting}
/>
<StyledLinkGroup>
<ActionLink onClick={handleLogout}>Log out</ActionLink>
<ActionLink onClick={signOut}>Log out</ActionLink>
<span />
<ActionLink href={CAL_LINK} target="_blank" rel="noreferrer">
Book a Call

View File

@ -1,5 +1,4 @@
import { useEffect, useMemo } from 'react';
import { useNavigate } from 'react-router-dom';
import { useMemo } from 'react';
import styled from '@emotion/styled';
import { useRecoilValue } from 'recoil';
@ -10,10 +9,7 @@ import { SignInUpForm } from '@/auth/sign-in-up/components/SignInUpForm';
import { useSignInUpForm } from '@/auth/sign-in-up/hooks/useSignInUpForm';
import { useWorkspaceFromInviteHash } from '@/auth/sign-in-up/hooks/useWorkspaceFromInviteHash';
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
import { AppPath } from '@/types/AppPath';
import { Loader } from '@/ui/feedback/loader/components/Loader';
import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { MainButton } from '@/ui/input/button/components/MainButton';
import { useWorkspaceSwitching } from '@/ui/navigation/navigation-drawer/hooks/useWorkspaceSwitching';
import { AnimatedEaseIn } from '@/ui/utilities/animation/components/AnimatedEaseIn';
@ -26,13 +22,8 @@ const StyledContentContainer = styled.div`
`;
export const Invite = () => {
const { enqueueSnackBar } = useSnackBar();
const navigate = useNavigate();
const {
workspace: workspaceFromInviteHash,
loading: workspaceFromInviteHashLoading,
workspaceInviteHash,
} = useWorkspaceFromInviteHash();
const { workspace: workspaceFromInviteHash, workspaceInviteHash } =
useWorkspaceFromInviteHash();
const { form } = useSignInUpForm();
const currentWorkspace = useRecoilValue(currentWorkspaceState);
const [addUserToWorkspace] = useAddUserToWorkspaceMutation();
@ -56,68 +47,41 @@ export const Invite = () => {
await switchWorkspace(workspaceFromInviteHash.id);
};
useEffect(() => {
if (
!isDefined(workspaceFromInviteHash) &&
!workspaceFromInviteHashLoading
) {
enqueueSnackBar('workspace does not exist', {
variant: SnackBarVariant.Error,
});
if (isDefined(currentWorkspace)) {
navigate(AppPath.Index);
} else {
navigate(AppPath.SignInUp);
}
}
if (
if (
!isDefined(workspaceFromInviteHash) ||
(isDefined(workspaceFromInviteHash) &&
isDefined(currentWorkspace) &&
currentWorkspace.id === workspaceFromInviteHash?.id
) {
enqueueSnackBar(
`You already belong to ${workspaceFromInviteHash?.displayName} workspace`,
{
variant: SnackBarVariant.Info,
},
);
navigate(AppPath.Index);
}
}, [
navigate,
enqueueSnackBar,
currentWorkspace,
workspaceFromInviteHash,
workspaceFromInviteHashLoading,
]);
workspaceFromInviteHash.id === currentWorkspace.id)
) {
return <></>;
}
return (
!workspaceFromInviteHashLoading && (
<>
<AnimatedEaseIn>
<Logo workspaceLogo={workspaceFromInviteHash?.logo} />
</AnimatedEaseIn>
<Title animate>{title}</Title>
{isDefined(currentWorkspace) && workspaceFromInviteHash ? (
<>
<StyledContentContainer>
<MainButton
variant="secondary"
title="Continue"
type="submit"
onClick={handleUserJoinWorkspace}
Icon={() => form.formState.isSubmitting && <Loader />}
fullWidth
/>
</StyledContentContainer>
<FooterNote>
By using Twenty, you agree to the Terms of Service and Privacy
Policy.
</FooterNote>
</>
) : (
<SignInUpForm />
)}
</>
)
<>
<AnimatedEaseIn>
<Logo workspaceLogo={workspaceFromInviteHash?.logo} />
</AnimatedEaseIn>
<Title animate>{title}</Title>
{isDefined(currentWorkspace) ? (
<>
<StyledContentContainer>
<MainButton
variant="secondary"
title="Continue"
type="submit"
onClick={handleUserJoinWorkspace}
Icon={() => form.formState.isSubmitting && <Loader />}
fullWidth
/>
</StyledContentContainer>
<FooterNote>
By using Twenty, you agree to the Terms of Service and Privacy
Policy.
</FooterNote>
</>
) : (
<SignInUpForm />
)}
</>
);
};

View File

@ -7,19 +7,20 @@ import styled from '@emotion/styled';
import { zodResolver } from '@hookform/resolvers/zod';
import { isNonEmptyString } from '@sniptt/guards';
import { motion } from 'framer-motion';
import { useSetRecoilState } from 'recoil';
import { z } from 'zod';
import { Logo } from '@/auth/components/Logo';
import { Title } from '@/auth/components/Title';
import { useAuth } from '@/auth/hooks/useAuth';
import { useIsLogged } from '@/auth/hooks/useIsLogged';
import { useNavigateAfterSignInUp } from '@/auth/sign-in-up/hooks/useNavigateAfterSignInUp';
import { PASSWORD_REGEX } from '@/auth/utils/passwordRegex';
import { AppPath } from '@/types/AppPath';
import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar';
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 { isDefaultLayoutAuthModalVisibleState } from '@/ui/layout/states/isDefaultLayoutAuthModalVisibleState';
import { AnimatedEaseIn } from '@/ui/utilities/animation/components/AnimatedEaseIn';
import {
useUpdatePasswordViaResetTokenMutation,
@ -73,6 +74,7 @@ export const PasswordReset = () => {
const navigate = useNavigate();
const [email, setEmail] = useState('');
const [isTokenValid, setIsTokenValid] = useState(false);
const theme = useTheme();
@ -80,6 +82,9 @@ export const PasswordReset = () => {
const isLoggedIn = useIsLogged();
const setIsDefaultLayoutAuthModalVisibleState = useSetRecoilState(
isDefaultLayoutAuthModalVisibleState,
);
const { control, handleSubmit } = useForm<Form>({
mode: 'onChange',
defaultValues: {
@ -89,7 +94,7 @@ export const PasswordReset = () => {
resolver: zodResolver(validationSchema),
});
const { loading: isValidatingToken } = useValidatePasswordResetTokenQuery({
useValidatePasswordResetTokenQuery({
variables: {
token: passwordResetToken ?? '',
},
@ -98,13 +103,11 @@ export const PasswordReset = () => {
enqueueSnackBar(error?.message ?? 'Token Invalid', {
variant: SnackBarVariant.Error,
});
if (!isLoggedIn) {
navigate(AppPath.SignInUp);
} else {
navigate(AppPath.Index);
}
navigate(AppPath.Index);
},
onCompleted: (data) => {
setIsTokenValid(true);
setIsDefaultLayoutAuthModalVisibleState(true);
if (isNonEmptyString(data?.validatePasswordResetToken?.email)) {
setEmail(data.validatePasswordResetToken.email);
}
@ -116,8 +119,6 @@ export const PasswordReset = () => {
const { signInWithCredentials } = useAuth();
const { navigateAfterSignInUp } = useNavigateAfterSignInUp();
const onSubmit = async (formData: Form) => {
try {
const { data } = await updatePasswordViaToken({
@ -142,12 +143,7 @@ export const PasswordReset = () => {
return;
}
const {
workspace: currentWorkspace,
workspaceMember: currentWorkspaceMember,
} = await signInWithCredentials(email || '', formData.newPassword);
navigateAfterSignInUp(currentWorkspace, currentWorkspaceMember);
await signInWithCredentials(email || '', formData.newPassword);
} catch (err) {
logError(err);
enqueueSnackBar(
@ -160,89 +156,90 @@ export const PasswordReset = () => {
};
return (
<StyledMainContainer>
<AnimatedEaseIn>
<Logo />
</AnimatedEaseIn>
<Title animate>Reset Password</Title>
<StyledContentContainer>
{isValidatingToken && (
<SkeletonTheme
baseColor={theme.background.quaternary}
highlightColor={theme.background.secondary}
>
<Skeleton
height={32}
count={2}
style={{
marginBottom: theme.spacing(2),
}}
/>
</SkeletonTheme>
)}
{email && (
<StyledForm onSubmit={handleSubmit(onSubmit)}>
<StyledFullWidthMotionDiv
initial={{ opacity: 0, height: 0 }}
animate={{ opacity: 1, height: 'auto' }}
transition={{
type: 'spring',
stiffness: 800,
damping: 35,
}}
isTokenValid && (
<StyledMainContainer>
<AnimatedEaseIn>
<Logo />
</AnimatedEaseIn>
<Title animate>Reset Password</Title>
<StyledContentContainer>
{!email ? (
<SkeletonTheme
baseColor={theme.background.quaternary}
highlightColor={theme.background.secondary}
>
<StyledInputContainer>
<TextInputV2
autoFocus
value={email}
placeholder="Email"
fullWidth
disabled
/>
</StyledInputContainer>
</StyledFullWidthMotionDiv>
<StyledFullWidthMotionDiv
initial={{ opacity: 0, height: 0 }}
animate={{ opacity: 1, height: 'auto' }}
transition={{
type: 'spring',
stiffness: 800,
damping: 35,
}}
>
<Controller
name="newPassword"
control={control}
render={({
field: { onChange, onBlur, value },
fieldState: { error },
}) => (
<StyledInputContainer>
<TextInputV2
autoFocus
value={value}
type="password"
placeholder="New Password"
onBlur={onBlur}
onChange={onChange}
error={error?.message}
fullWidth
/>
</StyledInputContainer>
)}
<Skeleton
height={32}
count={2}
style={{
marginBottom: theme.spacing(2),
}}
/>
</StyledFullWidthMotionDiv>
</SkeletonTheme>
) : (
<StyledForm onSubmit={handleSubmit(onSubmit)}>
<StyledFullWidthMotionDiv
initial={{ opacity: 0, height: 0 }}
animate={{ opacity: 1, height: 'auto' }}
transition={{
type: 'spring',
stiffness: 800,
damping: 35,
}}
>
<StyledInputContainer>
<TextInputV2
autoFocus
value={email}
placeholder="Email"
fullWidth
disabled
/>
</StyledInputContainer>
</StyledFullWidthMotionDiv>
<StyledFullWidthMotionDiv
initial={{ opacity: 0, height: 0 }}
animate={{ opacity: 1, height: 'auto' }}
transition={{
type: 'spring',
stiffness: 800,
damping: 35,
}}
>
<Controller
name="newPassword"
control={control}
render={({
field: { onChange, onBlur, value },
fieldState: { error },
}) => (
<StyledInputContainer>
<TextInputV2
autoFocus
value={value}
type="password"
placeholder="New Password"
onBlur={onBlur}
onChange={onChange}
error={error?.message}
fullWidth
/>
</StyledInputContainer>
)}
/>
</StyledFullWidthMotionDiv>
<MainButton
variant="secondary"
title="Change Password"
type="submit"
fullWidth
disabled={isUpdatingPassword}
/>
</StyledForm>
)}
</StyledContentContainer>
</StyledMainContainer>
<MainButton
variant="secondary"
title="Change Password"
type="submit"
fullWidth
disabled={isUpdatingPassword}
/>
</StyledForm>
)}
</StyledContentContainer>
</StyledMainContainer>
)
);
};