From 7108971ff64adb9a760f4586104ed70137868c27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=92scar=20Casajuana?= Date: Wed, 6 Nov 2024 18:46:39 +0100 Subject: [PATCH 1/2] Resend verify code if out of date and trying to login --- src/components/Auth/SignIn.tsx | 63 ++++++++++++++++++++++++++---- src/components/Auth/api.ts | 2 +- src/components/Auth/authQueries.ts | 2 +- 3 files changed, 57 insertions(+), 10 deletions(-) diff --git a/src/components/Auth/SignIn.tsx b/src/components/Auth/SignIn.tsx index e4920d51e..3311e9568 100644 --- a/src/components/Auth/SignIn.tsx +++ b/src/components/Auth/SignIn.tsx @@ -1,9 +1,10 @@ -import { Button, Flex, Text } from '@chakra-ui/react' +import { Button, Flex, Text, useToast } from '@chakra-ui/react' +import { useMutation } from '@tanstack/react-query' import { useEffect, useState } from 'react' import { FormProvider, useForm } from 'react-hook-form' import { useTranslation } from 'react-i18next' import { NavLink, useNavigate, useOutletContext } from 'react-router-dom' -import { UnverifiedApiError } from '~components/Auth/api' +import { api, ApiEndpoints, UnverifiedApiError } from '~components/Auth/api' import { ILoginParams } from '~components/Auth/authQueries' import { useAuth } from '~components/Auth/useAuth' import { VerifyAccountNeeded } from '~components/Auth/Verify' @@ -19,8 +20,29 @@ type FormData = { keepLogedIn: boolean } & ILoginParams +const useVerificationCodeStatus = () => + useMutation({ + mutationFn: async (email: string) => { + const response = await api<{ email: string; expiration: string; valid: boolean }>( + `${ApiEndpoints.VerifyCode}?email=${encodeURIComponent(email)}` + ) + return response + }, + }) + +const useResendVerificationCode = () => + useMutation({ + mutationFn: async (email: string) => { + await api(ApiEndpoints.VerifyCode, { + method: 'POST', + body: { email }, + }) + }, + }) + const SignIn = () => { const { t } = useTranslation() + const toast = useToast() const navigate = useNavigate() const { setTitle, setSubTitle } = useOutletContext() const methods = useForm() @@ -33,19 +55,44 @@ const SignIn = () => { }, []) const { - login: { mutateAsync: login, isError, error, isPending }, + login: { mutateAsync: login, isError, error }, } = useAuth() const [verifyNeeded, setVerifyNeeded] = useState(false) + const { mutateAsync: checkVerificationCodeStatus } = useVerificationCodeStatus() + const resendVerificationCode = useResendVerificationCode() const onSubmit = async (data: FormData) => { await login(data) .then(() => navigate(Routes.dashboard.base)) - .catch((e) => { - if (e instanceof UnverifiedApiError) { - setVerifyNeeded(true) - return + .catch(async (e) => { + if (e instanceof UnverifiedApiError && email) { + try { + const verificationData = await checkVerificationCodeStatus(email) + if (verificationData.valid) { + setVerifyNeeded(true) + return + } + // Code expired, resend verification code + await resendVerificationCode.mutateAsync(email) + setVerifyNeeded(true) + toast({ + title: t('verification_code_resent', { defaultValue: 'Verification code resent!' }), + status: 'success', + duration: 5000, + isClosable: true, + }) + } catch (error) { + toast({ + title: t('error.title', { defaultValue: 'Error' }), + description: (error as Error).message, + status: 'error', + duration: 5000, + isClosable: true, + }) + } + } else { + throw e } - throw e }) } diff --git a/src/components/Auth/api.ts b/src/components/Auth/api.ts index 5a525ab94..8b71dffbe 100644 --- a/src/components/Auth/api.ts +++ b/src/components/Auth/api.ts @@ -10,7 +10,7 @@ export enum ApiEndpoints { Organization = 'organizations/{address}', OrganizationMembers = 'organizations/{address}/members', Verify = 'users/verify', - VerifyResend = 'users/verify/code', + VerifyCode = 'users/verify/code', } interface IApiError { diff --git a/src/components/Auth/authQueries.ts b/src/components/Auth/authQueries.ts index c988415ee..94914c9c8 100644 --- a/src/components/Auth/authQueries.ts +++ b/src/components/Auth/authQueries.ts @@ -55,7 +55,7 @@ export const useResendVerificationMail = ( ) => { return useMutation({ mutationFn: (params: IResendVerificationParams) => - api(ApiEndpoints.VerifyResend, { body: params, method: 'POST' }), + api(ApiEndpoints.VerifyCode, { body: params, method: 'POST' }), ...options, }) } From adbef832aef6f5577c8368a6cf21aed13fdc5e2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=92scar=20Casajuana?= Date: Tue, 12 Nov 2024 12:57:44 +0100 Subject: [PATCH 2/2] Consistency code change --- src/components/Auth/SignIn.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/Auth/SignIn.tsx b/src/components/Auth/SignIn.tsx index 3311e9568..fc14750e2 100644 --- a/src/components/Auth/SignIn.tsx +++ b/src/components/Auth/SignIn.tsx @@ -59,7 +59,7 @@ const SignIn = () => { } = useAuth() const [verifyNeeded, setVerifyNeeded] = useState(false) const { mutateAsync: checkVerificationCodeStatus } = useVerificationCodeStatus() - const resendVerificationCode = useResendVerificationCode() + const { mutateAsync: resendVerificationCode } = useResendVerificationCode() const onSubmit = async (data: FormData) => { await login(data) @@ -73,7 +73,7 @@ const SignIn = () => { return } // Code expired, resend verification code - await resendVerificationCode.mutateAsync(email) + await resendVerificationCode(email) setVerifyNeeded(true) toast({ title: t('verification_code_resent', { defaultValue: 'Verification code resent!' }),