diff --git a/canopeum_frontend/src/locale/en/auth.ts b/canopeum_frontend/src/locale/en/auth.ts index 69ecd46a..9793729e 100644 --- a/canopeum_frontend/src/locale/en/auth.ts +++ b/canopeum_frontend/src/locale/en/auth.ts @@ -17,6 +17,7 @@ export default { 'password-confirmation-error-required': 'Please re-enter your password', 'password-error-must-match': 'Passwords do not match', 'log-in': 'Log In', + 'remember-me': 'Remember me', 'log-out': 'Log Out', 'log-out-confirmation': 'Are you sure you want to log out?', 'sign-up': 'Sign Up', diff --git a/canopeum_frontend/src/locale/fr/auth.ts b/canopeum_frontend/src/locale/fr/auth.ts index 26d87f39..aeeeda7b 100644 --- a/canopeum_frontend/src/locale/fr/auth.ts +++ b/canopeum_frontend/src/locale/fr/auth.ts @@ -22,6 +22,7 @@ export default { 'log-out': 'Se Déconnecter', 'log-out-confirmation': 'Est-vous certain de vouloir vous déconnecter?', 'sign-up': "S'inscrire", + 'remember-me': 'Se souvenir de moi', 'create-account': 'Créer mon compte', 'already-have-an-account': 'Vous avez déjà un compte?', 'back-to-map': 'Retourner à la carte', diff --git a/canopeum_frontend/src/pages/Login.tsx b/canopeum_frontend/src/pages/Login.tsx index 9aae39df..5fbda504 100644 --- a/canopeum_frontend/src/pages/Login.tsx +++ b/canopeum_frontend/src/pages/Login.tsx @@ -1,150 +1,118 @@ +/* eslint-disable react/jsx-props-no-spreading -- Needed for react hook forms */ import { useContext, useState } from 'react' +import { type SubmitHandler, useForm } from 'react-hook-form' import { useTranslation } from 'react-i18next' import { Link } from 'react-router-dom' import AuthPageLayout from '@components/auth/AuthPageLayout' -import Checkbox from '@components/Checkbox' import { AuthenticationContext } from '@components/context/AuthenticationContext' import { appRoutes } from '@constants/routes.constant' +import { formClasses } from '@constants/style' import useApiClient from '@hooks/ApiClientHook' import { LoginUser } from '@services/api' import { storeToken } from '@utils/auth.utils' -import type { InputValidationError } from '@utils/validators' -const Login = () => { - const { authenticate } = useContext(AuthenticationContext) - const { t: translate } = useTranslation() - const { getApiClient } = useApiClient() - - const [email, setEmail] = useState('') - const [password, setPassword] = useState('') - const [rememberMe, setRememberMe] = useState(false) - - const [emailError, setEmailError] = useState() - const [passwordError, setPasswordError] = useState() - - const [loginError, setLoginError] = useState() - - const validateEmail = () => { - if (!email) { - setEmailError('required') - - return false - } - - setEmailError(undefined) - - return true - } - - const validatePassword = () => { - if (!password) { - setPasswordError('required') - - return false - } - - setPasswordError(undefined) - - return true - } - - const validateForm = () => { - // Do not return directly the method calls; - // we need each of them to be called before returning the result - const emailValid = validateEmail() - const passwordValid = validatePassword() - - return emailValid - && passwordValid - } +type LoginFormInputs = { + email: string, + password: string, + rememberMe: boolean, +} - const onLoginClick = async () => { - const isFormValid = validateForm() - if (!isFormValid) return +const Login = () => { + const { + register, + handleSubmit, + formState: { errors, touchedFields }, + } = useForm({ mode: 'onTouched' }) + const onSubmit: SubmitHandler = async formData => { try { const response = await getApiClient().authenticationClient.login( new LoginUser({ - email: email.trim(), - password, + email: formData.email.trim(), + password: formData.password, }), ) - storeToken(response.token, rememberMe) + storeToken(response.token, formData.rememberMe) authenticate(response.user) } catch { setLoginError(translate('auth.log-in-error')) } } + const { authenticate } = useContext(AuthenticationContext) + const { t: translate } = useTranslation() + const { getApiClient } = useApiClient() + + const [loginError, setLoginError] = useState() + return (

{translate('auth.log-in-header-text')}

-
+
validateEmail()} - onChange={event => setEmail(event.target.value)} type='email' + {...register('email', { + required: { value: true, message: translate('auth.email-error-required') }, + })} /> - {emailError === 'required' && ( - - {translate('auth.email-error-required')} - - )} + {errors.email && {errors.email.message}}
validatePassword()} - onChange={event => setPassword(event.target.value)} type='password' + {...register('password', { + required: { value: true, message: translate('auth.password-error-required') }, + })} /> - {passwordError === 'required' && ( - - {translate('auth.password-error-required')} - + {errors.password && ( + {errors.password.message} )}
- setRememberMe(isChecked)} - value='remember-me' - > - Remember Me - + {/* TODO: Make a component, this is extracted from the Checkbox */} + {/* component until everything uses React Hook Forms */} +
+ + +
{loginError && {loginError}}
- @@ -156,7 +124,7 @@ const Login = () => { {translate('auth.sign-up')}
-
+
) }