feat(auth): enhance error handling for sign-up and existing user checks (#14953)
Refactored error handling in `useSignUpInNewWorkspace` and `useSignInUp` hooks to provide user-friendly messages. Added validation for existing users during sign-up, updating server-side logic to throw specific exceptions (`USER_ALREADY_EXIST`). Fix https://twenty-v7.sentry.io/issues/6686753138/events/latest/?environment=prod&project=4507072499810304&query=is%3Aunresolved%20issue.priority%3A%5Bhigh%2C%20medium%5D%20QueryFailedError&referrer=latest-event&sort=date --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
This commit is contained in:
+1
-1
@@ -173,7 +173,7 @@ export const SignInUpGlobalScopeForm = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
continueWithCredentials();
|
||||
await continueWithCredentials();
|
||||
};
|
||||
|
||||
const onEmailChange = (email: string) => {
|
||||
|
||||
@@ -19,9 +19,11 @@ import { AppPath } from 'twenty-shared/types';
|
||||
import { buildAppPathWithQueryParams } from '~/utils/buildAppPathWithQueryParams';
|
||||
import { isMatchingLocation } from '~/utils/isMatchingLocation';
|
||||
import { useAuth } from '../../hooks/useAuth';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
|
||||
export const useSignInUp = (form: UseFormReturn<Form>) => {
|
||||
const { enqueueErrorSnackBar } = useSnackBar();
|
||||
const { t } = useLingui();
|
||||
|
||||
const [signInUpStep, setSignInUpStep] = useRecoilState(signInUpStepState);
|
||||
const [signInUpMode, setSignInUpMode] = useRecoilState(signInUpModeState);
|
||||
@@ -55,28 +57,33 @@ export const useSignInUp = (form: UseFormReturn<Form>) => {
|
||||
setSignInUpStep(SignInUpStep.Email);
|
||||
}, [setSignInUpStep]);
|
||||
|
||||
const errorMsgUserAlreadyExist = t`An error occurred while checking user existence`;
|
||||
const continueWithCredentials = useCallback(async () => {
|
||||
const token = await readCaptchaToken();
|
||||
if (!form.getValues('email')) {
|
||||
return;
|
||||
}
|
||||
checkUserExistsQuery({
|
||||
variables: {
|
||||
email: form.getValues('email').toLowerCase().trim(),
|
||||
captchaToken: token,
|
||||
},
|
||||
onError: (error) => {
|
||||
enqueueErrorSnackBar({ apolloError: error });
|
||||
},
|
||||
onCompleted: (data) => {
|
||||
setSignInUpMode(
|
||||
data?.checkUserExists.exists
|
||||
? SignInUpMode.SignIn
|
||||
: SignInUpMode.SignUp,
|
||||
);
|
||||
setSignInUpStep(SignInUpStep.Password);
|
||||
},
|
||||
});
|
||||
try {
|
||||
const { data } = await checkUserExistsQuery({
|
||||
variables: {
|
||||
email: form.getValues('email').toLowerCase().trim(),
|
||||
captchaToken: token,
|
||||
},
|
||||
});
|
||||
|
||||
setSignInUpMode(
|
||||
data?.checkUserExists.exists
|
||||
? SignInUpMode.SignIn
|
||||
: SignInUpMode.SignUp,
|
||||
);
|
||||
setSignInUpStep(SignInUpStep.Password);
|
||||
} catch (error) {
|
||||
enqueueErrorSnackBar({
|
||||
...(error instanceof ApolloError
|
||||
? { apolloError: error }
|
||||
: { message: errorMsgUserAlreadyExist }),
|
||||
});
|
||||
}
|
||||
}, [
|
||||
readCaptchaToken,
|
||||
form,
|
||||
@@ -84,6 +91,7 @@ export const useSignInUp = (form: UseFormReturn<Form>) => {
|
||||
enqueueErrorSnackBar,
|
||||
setSignInUpStep,
|
||||
setSignInUpMode,
|
||||
errorMsgUserAlreadyExist,
|
||||
]);
|
||||
|
||||
const submitCredentials: SubmitHandler<Form> = useCallback(
|
||||
|
||||
+22
-16
@@ -1,32 +1,38 @@
|
||||
import { useRedirectToWorkspaceDomain } from '@/domain-manager/hooks/useRedirectToWorkspaceDomain';
|
||||
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
||||
import { type ApolloError } from '@apollo/client';
|
||||
import { ApolloError } from '@apollo/client';
|
||||
import { AppPath } from 'twenty-shared/types';
|
||||
import { useSignUpInNewWorkspaceMutation } from '~/generated-metadata/graphql';
|
||||
import { getWorkspaceUrl } from '~/utils/getWorkspaceUrl';
|
||||
import { assertIsDefinedOrThrow } from 'twenty-shared/utils';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
|
||||
export const useSignUpInNewWorkspace = () => {
|
||||
const { redirectToWorkspaceDomain } = useRedirectToWorkspaceDomain();
|
||||
const { enqueueErrorSnackBar } = useSnackBar();
|
||||
const { t } = useLingui();
|
||||
|
||||
const [signUpInNewWorkspaceMutation] = useSignUpInNewWorkspaceMutation();
|
||||
|
||||
const createWorkspace = async ({ newTab } = { newTab: true }) => {
|
||||
await signUpInNewWorkspaceMutation({
|
||||
onCompleted: async (data) => {
|
||||
return await redirectToWorkspaceDomain(
|
||||
getWorkspaceUrl(data.signUpInNewWorkspace.workspace.workspaceUrls),
|
||||
AppPath.Verify,
|
||||
{
|
||||
loginToken: data.signUpInNewWorkspace.loginToken.token,
|
||||
},
|
||||
newTab ? '_blank' : '_self',
|
||||
);
|
||||
},
|
||||
onError: (error: ApolloError) => {
|
||||
enqueueErrorSnackBar({ apolloError: error });
|
||||
},
|
||||
});
|
||||
try {
|
||||
const { data } = await signUpInNewWorkspaceMutation();
|
||||
assertIsDefinedOrThrow(data?.signUpInNewWorkspace);
|
||||
return await redirectToWorkspaceDomain(
|
||||
getWorkspaceUrl(data.signUpInNewWorkspace.workspace.workspaceUrls),
|
||||
AppPath.Verify,
|
||||
{
|
||||
loginToken: data.signUpInNewWorkspace.loginToken.token,
|
||||
},
|
||||
newTab ? '_blank' : '_self',
|
||||
);
|
||||
} catch (error) {
|
||||
enqueueErrorSnackBar({
|
||||
...(error instanceof ApolloError
|
||||
? { apolloError: error }
|
||||
: { message: t`Workspace creation failed` }),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user