diff --git a/src/config/lexics/public.tsx b/src/config/lexics/public.tsx index 71cabadf..f0b3a41e 100644 --- a/src/config/lexics/public.tsx +++ b/src/config/lexics/public.tsx @@ -1,8 +1,11 @@ export const publicLexics = { + error_account_blocked: 12909, error_empty_email: 2498, + error_empty_password: 2499, error_fill_out_required_fields: 12911, error_fill_out_this_field: 12933, error_invalid_email_format: 12908, + error_invalid_email_or_password: 2502, error_select_country_first: 12910, error_simple_password: 12940, form_address1: 12914, diff --git a/src/features/AuthStore/hooks/useLogin.tsx b/src/features/AuthStore/hooks/useLogin.tsx index 28ca33b8..68ec11c3 100644 --- a/src/features/AuthStore/hooks/useLogin.tsx +++ b/src/features/AuthStore/hooks/useLogin.tsx @@ -19,12 +19,7 @@ export const useLogin = ({ setToken }: Args) => { history.replace(PAGES.home) } - const onError = (message: string) => { - // eslint-disable-next-line no-alert - window.alert(message) - } - return async ({ email, password }: LoginArgs) => ( - login({ email, password }).then(onSuccess, onError) + login({ email, password }).then(onSuccess) ) } diff --git a/src/features/Combobox/index.tsx b/src/features/Combobox/index.tsx index cf5892a1..b77c6ef6 100644 --- a/src/features/Combobox/index.tsx +++ b/src/features/Combobox/index.tsx @@ -88,7 +88,7 @@ export const Combobox = (props: Props) => { )} - {error && } + ) } diff --git a/src/features/Common/Input/index.tsx b/src/features/Common/Input/index.tsx index 43671e73..426b36be 100644 --- a/src/features/Common/Input/index.tsx +++ b/src/features/Common/Input/index.tsx @@ -81,6 +81,6 @@ export const Input = ({ title={title} /> - {error && } + ) diff --git a/src/features/Common/Input/styled.tsx b/src/features/Common/Input/styled.tsx index cdbd4b36..2f76daea 100644 --- a/src/features/Common/Input/styled.tsx +++ b/src/features/Common/Input/styled.tsx @@ -2,6 +2,8 @@ import styled, { css } from 'styled-components/macro' import isNil from 'lodash/isNil' +import { T9n } from 'features/T9n' + export type WrapperProps = { error?: string | null, paddingX?: number, @@ -88,7 +90,7 @@ export const Column = styled.div` flex-direction: column; ` -export const Error = styled.span` +export const Error = styled(T9n)` min-height: 16px; margin-top: 5px; font-style: normal; diff --git a/src/features/Login/hooks.tsx b/src/features/Login/hooks.tsx index d98139c9..1e91dc8a 100644 --- a/src/features/Login/hooks.tsx +++ b/src/features/Login/hooks.tsx @@ -1,26 +1,68 @@ -import type { FormEvent } from 'react' +import type { FormEvent, FocusEvent } from 'react' import trim from 'lodash/trim' +import isEmpty from 'lodash/isEmpty' import { useAuthStore } from 'features/AuthStore' +import { useForm } from 'features/FormStore' import { formIds } from 'features/Register/components/RegistrationStep/config' +import { isValidEmail } from 'features/Register/helpers/isValidEmail' -const readFormValue = (event: FormEvent) => ( - (fieldName: string) => trim(event.currentTarget[fieldName]?.value) -) - -export const useForm = () => { +export const useLoginForm = () => { + const { + readFormError, + readFormValue, + updateFormError, + updateFormValue, + } = useForm() const { login } = useAuthStore() + const onEmailBlur = ({ target }: FocusEvent) => { + if (!isValidEmail(target.value)) { + updateFormError(formIds.email, 'error_invalid_email_format') + } + } + + const readTrimmedValue = (fieldName: string) => trim(readFormValue(fieldName)) + + const validateForm = () => { + let hasError = false + const email = readTrimmedValue(formIds.email) + const password = readTrimmedValue(formIds.password) + if (isEmpty(email)) { + updateFormError(formIds.email, 'error_empty_email') + hasError = true + } else if (!isValidEmail(email)) { + updateFormError(formIds.email, 'error_invalid_email_format') + hasError = true + } + if (isEmpty(password)) { + updateFormError(formIds.password, 'error_empty_password') + hasError = true + } + return !hasError + } + + const onError = (message: string) => { + updateFormError(formIds.formError, message) + } + const handleSubmit = async (event: FormEvent) => { event.preventDefault() - const readFieldValue = readFormValue(event) - const email = readFieldValue(formIds.email) - const password = readFieldValue(formIds.password) + if (validateForm()) { + const email = readTrimmedValue(formIds.email) + const password = readTrimmedValue(formIds.password) - login({ email, password }) + login({ email, password }).catch(onError) + } } - return { handleSubmit } + return { + handleSubmit, + onEmailBlur, + readFormError, + readFormValue, + updateFormValue, + } } diff --git a/src/features/Login/index.tsx b/src/features/Login/index.tsx index e3f6bd34..8c1a4d39 100644 --- a/src/features/Login/index.tsx +++ b/src/features/Login/index.tsx @@ -5,10 +5,11 @@ import { PAGES } from 'config' import { T9n } from 'features/T9n' import { Logo } from 'features/Logo' import { Input, ButtonSolid } from 'features/Common' +import { Error } from 'features/Common/Input/styled' import { formIds } from 'features/Register/components/RegistrationStep/config' -import { useLexicsStore } from 'features/LexicsStore' +import { FormStore } from 'features/FormStore' -import { useForm } from './hooks' +import { useLoginForm } from './hooks' import { BlockTitle, CenterBlock, @@ -19,10 +20,16 @@ import { const labelWidth = 75 -export const Login = () => { - const { handleSubmit } = useForm() - const { translate } = useLexicsStore() - const defaultMessage = translate('please_fill_out_this_field') +const LoginForm = () => { + const { + handleSubmit, + onEmailBlur, + readFormError, + readFormValue, + updateFormValue, + } = useLoginForm() + + const requestError = readFormError(formIds.formError) return ( @@ -32,21 +39,26 @@ export const Login = () => { + {requestError && } + @@ -61,3 +73,9 @@ export const Login = () => { ) } + +export const Login = () => ( + + + +) diff --git a/src/features/Register/components/RegistrationStep/hooks/useValidateForm.tsx b/src/features/Register/components/RegistrationStep/hooks/useValidateForm.tsx index 26bd84b0..776a2cdd 100644 --- a/src/features/Register/components/RegistrationStep/hooks/useValidateForm.tsx +++ b/src/features/Register/components/RegistrationStep/hooks/useValidateForm.tsx @@ -27,16 +27,16 @@ export const useValidateForm = () => { (acc, fieldName) => { if (isFieldEmpty(fieldName)) { updateFormError(fieldName, message) - return acc + 1 + return true } return acc }, - 0, + false, ) ) const validateForm = () => { - let errorsCount = 0 + let hasError = false const email = readTrimmedValue(formIds.email) const password = readTrimmedValue(formIds.password) if (allFieldsEmpty(requiredFields)) { @@ -46,16 +46,16 @@ export const useValidateForm = () => { } if (isFieldEmpty(formIds.email)) { updateFormError(formIds.email, 'error_empty_email') - errorsCount++ + hasError = true } else if (!isValidEmail(email)) { updateFormError(formIds.email, 'error_invalid_email_format') } if (!isValidPassword(password)) { updateFormError(formIds.password, 'error_simple_password') - errorsCount++ + hasError = true } - errorsCount += setErrorOnEmptyFields(simpleValidationFields, 'error_fill_out_this_field') - return errorsCount === 0 + hasError = setErrorOnEmptyFields(simpleValidationFields, 'error_fill_out_this_field') + return !hasError } return validateForm diff --git a/src/features/Register/components/RegistrationStep/index.tsx b/src/features/Register/components/RegistrationStep/index.tsx index 949caae2..1606ac60 100644 --- a/src/features/Register/components/RegistrationStep/index.tsx +++ b/src/features/Register/components/RegistrationStep/index.tsx @@ -139,7 +139,7 @@ const Registration = () => { - + ) diff --git a/src/requests/login.tsx b/src/requests/login.tsx index f0d95c46..66cc98f7 100644 --- a/src/requests/login.tsx +++ b/src/requests/login.tsx @@ -15,12 +15,16 @@ const statusCodes = { INVALID_CREDENTIALS: 3, SUCCESS: 1, USER_REMOVED_OR_BLOCKED: 4, -} as const +} -type StatusCodes = typeof statusCodes[keyof typeof statusCodes] +const errorMessages = { + [statusCodes.EMAIL_NOT_FOUND]: 'error_invalid_email_or_password', + [statusCodes.INVALID_CREDENTIALS]: 'error_invalid_email_or_password', + [statusCodes.USER_REMOVED_OR_BLOCKED]: 'error_account_blocked', +} type Response = { - _p_status: StatusCodes, + _p_status: number, } type Args = { @@ -55,7 +59,7 @@ export const login = async ({ if (token && _p_status === statusCodes.SUCCESS) { return Promise.resolve(token) } - return Promise.reject(_p_status) + return Promise.reject(errorMessages[_p_status]) } catch (error) { return Promise.reject() }