From affac606b4e88b6b779e900c47c41f2e958688a2 Mon Sep 17 00:00:00 2001 From: Armen <35077035+Armen9393@users.noreply.github.com> Date: Thu, 15 Oct 2020 12:59:03 +0300 Subject: [PATCH] Ott 463 user account fields (#177) * Ott 463 user account fields 1 (#175) * fix(ott-463): made some changes in combobox * fix(ott-463): fixed input and search icon * fix(ott-463): made some minor changes * Ott 463 user account fields 2 (#176) * fix(ott-463): added fields * fix(ott-463): bug fix * fix(ott-463): moved hooks from register to common hooks folder * fix(ott-463): deleted mutation --- .../config.tsx => config/form.tsx} | 8 +- .../Combobox/components/Arrow/index.tsx | 2 +- src/features/Combobox/hooks/index.tsx | 64 +++---- .../Combobox/hooks/useKeyboardScroll.tsx | 4 +- src/features/Combobox/index.tsx | 4 + src/features/Combobox/styled.tsx | 3 +- src/features/Combobox/types.tsx | 1 + src/features/Common/Input/index.tsx | 4 + src/features/Common/Input/styled.tsx | 8 + src/features/Login/hooks.tsx | 6 +- src/features/Login/index.tsx | 2 +- .../hooks/useSubmitHandler.tsx | 14 +- .../components/RegistrationStep/index.tsx | 6 +- src/features/Search/styled.tsx | 1 + src/features/UserAccount/hooks.tsx | 73 ++++---- src/features/UserAccount/index.tsx | 165 ++++++++---------- src/features/UserAccount/styled.tsx | 8 +- src/features/UserAccount/useValidateForm.tsx | 11 +- .../formatPhoneCode/__tests__/index.tsx | 0 .../helpers/formatPhoneCode/index.tsx | 0 .../helpers/isValidEmail/__tests__/index.tsx | 0 .../helpers/isValidEmail/index.tsx | 0 .../isValidPassword/__tests__/index.tsx | 0 .../helpers/isValidPassword/index.tsx | 0 .../helpers/isValidPhone/__tests__/index.tsx | 0 .../helpers/isValidPhone/index.tsx | 0 .../RegistrationStep => }/hooks/useCities.tsx | 21 +-- .../RegistrationStep => }/hooks/useForm.tsx | 76 +++++--- .../hooks/useValidateForm.tsx | 8 +- src/requests/saveUserInfo.tsx | 6 +- 30 files changed, 266 insertions(+), 229 deletions(-) rename src/{features/Register/components/RegistrationStep/config.tsx => config/form.tsx} (82%) rename src/{features/Register => }/helpers/formatPhoneCode/__tests__/index.tsx (100%) rename src/{features/Register => }/helpers/formatPhoneCode/index.tsx (100%) rename src/{features/Register => }/helpers/isValidEmail/__tests__/index.tsx (100%) rename src/{features/Register => }/helpers/isValidEmail/index.tsx (100%) rename src/{features/Register => }/helpers/isValidPassword/__tests__/index.tsx (100%) rename src/{features/Register => }/helpers/isValidPassword/index.tsx (100%) rename src/{features/Register => }/helpers/isValidPhone/__tests__/index.tsx (100%) rename src/{features/Register => }/helpers/isValidPhone/index.tsx (100%) rename src/{features/Register/components/RegistrationStep => }/hooks/useCities.tsx (74%) rename src/{features/Register/components/RegistrationStep => }/hooks/useForm.tsx (52%) rename src/{features/Register/components/RegistrationStep => }/hooks/useValidateForm.tsx (88%) diff --git a/src/features/Register/components/RegistrationStep/config.tsx b/src/config/form.tsx similarity index 82% rename from src/features/Register/components/RegistrationStep/config.tsx rename to src/config/form.tsx index e2dc51d1..ad6b1ec4 100644 --- a/src/features/Register/components/RegistrationStep/config.tsx +++ b/src/config/form.tsx @@ -1,15 +1,17 @@ export const formIds = { - address1: 'address1', - address2: 'address2', + address1: 'address_line1', + address2: 'address_line2', city: 'city', + cityId: 'cityId', country: 'country', + countryId: 'countryId', email: 'email', firstname: 'firstname', formError: 'formError', lastname: 'lastname', password: 'password', phone: 'phone', - postalCode: 'postalCode', + postalCode: 'postal_code', region: 'region', } diff --git a/src/features/Combobox/components/Arrow/index.tsx b/src/features/Combobox/components/Arrow/index.tsx index ef407a9f..16ad7f5e 100644 --- a/src/features/Combobox/components/Arrow/index.tsx +++ b/src/features/Combobox/components/Arrow/index.tsx @@ -9,7 +9,7 @@ type Props = { const Wrapper = styled.div<{ isExpanded: boolean }>` position: absolute; - right: 16px; + right: 22px; top: 50%; transform: translateY(-50%); width: 20px; diff --git a/src/features/Combobox/hooks/index.tsx b/src/features/Combobox/hooks/index.tsx index 95e8280c..353db0c3 100644 --- a/src/features/Combobox/hooks/index.tsx +++ b/src/features/Combobox/hooks/index.tsx @@ -1,4 +1,4 @@ -import type { ChangeEvent } from 'react' +import type { ChangeEvent, KeyboardEvent } from 'react' import { useState, useCallback, @@ -10,8 +10,9 @@ import toLower from 'lodash/toLower' import find from 'lodash/find' import trim from 'lodash/trim' import size from 'lodash/size' +import isEmpty from 'lodash/isEmpty' -import { useToggle, useEventListener } from 'hooks' +import { useToggle } from 'hooks' import type { Props, Option } from '../types' import { matchSort } from '../helpers' @@ -40,7 +41,10 @@ export const useCombobox = (props: Props) => { const inputFieldRef = useRef(null) const [index, setIndex] = useState(0) - const { onKeyDown, popoverRef } = useKeyboardScroll() + const { + onKeyDownScroll, + popoverRef, + } = useKeyboardScroll() const { onQueryChange, @@ -83,25 +87,19 @@ export const useCombobox = (props: Props) => { const onOutsideClick = (event: MouseEvent) => { if (event.target !== inputFieldRef.current as HTMLInputElement) { close() + if (results[0]?.name.includes(query) && query) { + onOptionSelect(results[0].name) + } else { + onOptionSelect(query) + } } } - const optionSelectListener = useCallback((event: KeyboardEvent) => { - if (event.key === 'ArrowUp') { - setIndex(index - 1) - } else if (event.key === 'ArrowDown') { - setIndex(index + 1) - } else if (event.key === 'Enter') { - onSelect?.(results[index]) - close() - inputFieldRef.current?.blur() + const onInputBlur = () => { + if (isEmpty(results)) { + onOptionSelect('') } - }, [ - close, - index, - results, - onSelect, - ]) + } useEffect(() => { const lastElementIndex = size(results) - 1 @@ -113,28 +111,34 @@ export const useCombobox = (props: Props) => { results, ]) - useEventListener({ - callback: optionSelectListener, - event: 'keydown', - }) - - const escPressListener = useCallback((event: KeyboardEvent) => { + const onKeyDown = useCallback((event: KeyboardEvent) => { + onKeyDownScroll(event) if (event.key === 'Escape') { close() inputFieldRef.current?.blur() + } else if (event.key === 'ArrowUp') { + setIndex(index - 1) + } else if (event.key === 'ArrowDown') { + setIndex(index + 1) + } else if (event.key === 'Enter') { + onSelect?.(results[index]) + close() + inputFieldRef.current?.blur() } - }, [close]) - - useEventListener({ - callback: escPressListener, - event: 'keydown', - }) + }, [ + close, + index, + results, + onSelect, + onKeyDownScroll, + ]) return { close, index, inputFieldRef, isOpen, + onInputBlur, onKeyDown, onOptionSelect, onOutsideClick, diff --git a/src/features/Combobox/hooks/useKeyboardScroll.tsx b/src/features/Combobox/hooks/useKeyboardScroll.tsx index 0aee4f47..9011cb33 100644 --- a/src/features/Combobox/hooks/useKeyboardScroll.tsx +++ b/src/features/Combobox/hooks/useKeyboardScroll.tsx @@ -3,7 +3,7 @@ import { useRef } from 'react' export const useKeyboardScroll = () => { const popoverRef = useRef(null) - const onKeyDown = (event: KeyboardEvent) => { + const onKeyDownScroll = (event: KeyboardEvent) => { const container = popoverRef.current if (event.isDefaultPrevented() || !container) return @@ -24,5 +24,5 @@ export const useKeyboardScroll = () => { }) } - return { onKeyDown, popoverRef } + return { onKeyDownScroll, popoverRef } } diff --git a/src/features/Combobox/index.tsx b/src/features/Combobox/index.tsx index 78f4d214..71dde4ce 100644 --- a/src/features/Combobox/index.tsx +++ b/src/features/Combobox/index.tsx @@ -30,6 +30,7 @@ export const Combobox = (props: Props) => { label, labelLexic, labelWidth, + maxLength, title, withArrow, } = props @@ -38,6 +39,7 @@ export const Combobox = (props: Props) => { index, inputFieldRef, isOpen, + onInputBlur, onKeyDown, onOptionSelect, onOutsideClick, @@ -59,6 +61,8 @@ export const Combobox = (props: Props) => { {labelLexic ? : label} = Pick, ( label?: string, labelLexic?: string, labelWidth?: number, + maxLength?: number, onChange?: (event: ChangeEvent) => void, onSelect?: (option: T | null) => void, options: Array, diff --git a/src/features/Common/Input/index.tsx b/src/features/Common/Input/index.tsx index b19cc415..face7227 100644 --- a/src/features/Common/Input/index.tsx +++ b/src/features/Common/Input/index.tsx @@ -11,12 +11,14 @@ import { Label, LabelTitle, Error, + Icon, Column, } from './styled' type Props = { autoComplete?: string, defaultValue?: string, + editIcon?: boolean, inputWidth?: number, label?: string, labelLexic?: string, @@ -35,6 +37,7 @@ type Props = { export const Input = ({ autoComplete = '', defaultValue, + editIcon = false, error, inputWidth, label, @@ -81,6 +84,7 @@ export const Input = ({ placeholder={translate(labelLexic || '')} /> + {editIcon && } diff --git a/src/features/Common/Input/styled.tsx b/src/features/Common/Input/styled.tsx index 3548e467..94eb5451 100644 --- a/src/features/Common/Input/styled.tsx +++ b/src/features/Common/Input/styled.tsx @@ -174,3 +174,11 @@ export const Error = styled(T9n)` margin-top: 0; } ` + +export const Icon = styled.div<{ image: string }>` + width: 15px; + height: 25px; + background-image: url(/images/${({ image }) => `${image}.svg`}); + background-size: 100%; + background-repeat: no-repeat; +` diff --git a/src/features/Login/hooks.tsx b/src/features/Login/hooks.tsx index 8b796cbf..064532b7 100644 --- a/src/features/Login/hooks.tsx +++ b/src/features/Login/hooks.tsx @@ -3,10 +3,12 @@ import type { FormEvent, FocusEvent } from 'react' import trim from 'lodash/trim' import isEmpty from 'lodash/isEmpty' +import { formIds } from 'config/form' + +import { isValidEmail } from 'helpers/isValidEmail' + 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' export const useLoginForm = () => { const { diff --git a/src/features/Login/index.tsx b/src/features/Login/index.tsx index c3fe0bc9..3b561115 100644 --- a/src/features/Login/index.tsx +++ b/src/features/Login/index.tsx @@ -1,12 +1,12 @@ import React from 'react' import { PAGES } from 'config' +import { formIds } from 'config/form' 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 { FormStore } from 'features/FormStore' import { useLoginForm } from './hooks' diff --git a/src/features/Register/components/RegistrationStep/hooks/useSubmitHandler.tsx b/src/features/Register/components/RegistrationStep/hooks/useSubmitHandler.tsx index e0fa53ac..74d5aedb 100644 --- a/src/features/Register/components/RegistrationStep/hooks/useSubmitHandler.tsx +++ b/src/features/Register/components/RegistrationStep/hooks/useSubmitHandler.tsx @@ -4,12 +4,13 @@ import trim from 'lodash/trim' import type { City } from 'requests' +import { formIds } from 'config/form' + import { useAuthStore } from 'features/AuthStore' import { useForm } from 'features/FormStore' import type { SelectedCountry } from 'hooks/useCountries' -import { formIds } from '../config' -import { useValidateForm } from './useValidateForm' +import { useValidateForm } from 'hooks/useValidateForm' type Args = { selectedCity: City | null, @@ -26,11 +27,6 @@ export const useSubmitHandler = ({ const readTrimmedValue = (fieldName: string) => trim(readFormValue(fieldName)) - const getCityParams = () => { - if (selectedCity) return { cityId: selectedCity.id } - return { city: readTrimmedValue(formIds.city) } - } - const handleSubmit = async (event: FormEvent) => { event.preventDefault() @@ -44,11 +40,13 @@ export const useSubmitHandler = ({ const region = readTrimmedValue(formIds.region) const address1 = readTrimmedValue(formIds.address1) const address2 = readTrimmedValue(formIds.address2) + const city = readTrimmedValue(formIds.city) register({ address1, address2, - ...getCityParams(), + city, + cityId: selectedCity?.id, countryId: selectedCountry.id, email, firstname, diff --git a/src/features/Register/components/RegistrationStep/index.tsx b/src/features/Register/components/RegistrationStep/index.tsx index 813daa1b..4f63a166 100644 --- a/src/features/Register/components/RegistrationStep/index.tsx +++ b/src/features/Register/components/RegistrationStep/index.tsx @@ -1,5 +1,7 @@ import React from 'react' +import { formIds } from 'config/form' + import { T9n } from 'features/T9n' import { Combobox } from 'features/Combobox' import { Input, ButtonSolid } from 'features/Common' @@ -11,8 +13,7 @@ import { } from 'features/Login/styled' import { FormStore } from 'features/FormStore' -import { formIds } from './config' -import { useRegistrationForm } from './hooks/useForm' +import { useRegistrationForm } from 'hooks/useForm' const labelWidth = 116 @@ -123,7 +124,6 @@ const Registration = () => { onChange={updateFormValue(formIds.phone)} onBlur={onPhoneBlur} /> - diff --git a/src/features/Search/styled.tsx b/src/features/Search/styled.tsx index a3949bf2..44ac376d 100644 --- a/src/features/Search/styled.tsx +++ b/src/features/Search/styled.tsx @@ -107,6 +107,7 @@ export const Form = styled.form<{isMatch: boolean}>` ::before { content: ''; display: block; + position: absolute; width: 25px; height: 25px; background-image: url(/images/search.svg); diff --git a/src/features/UserAccount/hooks.tsx b/src/features/UserAccount/hooks.tsx index 606fa807..c0d86e4b 100644 --- a/src/features/UserAccount/hooks.tsx +++ b/src/features/UserAccount/hooks.tsx @@ -6,40 +6,38 @@ import { import forEach from 'lodash/forEach' import trim from 'lodash/trim' -import isString from 'lodash/isString' -import type { SelectedCountry } from 'hooks/useCountries' -import { useCountries } from 'hooks/useCountries' +import { formIds } from 'config/form' +import type { UserInfo } from 'requests/saveUserInfo' import { getUserInfo } from 'requests/getUserInfo' import { saveUserInfo } from 'requests/saveUserInfo' -import type { UserInfo } from 'requests/saveUserInfo' -import { useForm } from 'features/FormStore' -import { useLexicsStore } from 'features/LexicsStore' +import type { SelectedCountry } from 'hooks/useCountries' +import { useRegistrationForm } from 'hooks/useForm' import { useValidateForm } from './useValidateForm' -import { formIds } from './config' - -type Name = 'name_rus' | 'name_eng' - export const useUserInfo = () => { - const { - readFormError, - readFormValue, - updateFormError, - updateFormValue, - } = useForm() - - const { suffix } = useLexicsStore() const validateForm = useValidateForm() const saveButton = useRef(null) const { + cities, countries, - setSelectedCountry, - } = useCountries() + getCities, + onCitySelect, + onCountrySelect, + onPhoneBlur, + onRegionOrCityChange, + readFormError, + readFormValue, + resetCities, + resetSelectedCity, + selectedCity, + updateFormError, + updateFormValue, + } = useRegistrationForm() const readTrimmedValue = useCallback( (fieldName: string) => trim(readFormValue(fieldName)), @@ -54,17 +52,16 @@ export const useUserInfo = () => { const password = readTrimmedValue(formIds.password) const postalCode = Number(readTrimmedValue(formIds.postalCode)) const region = readTrimmedValue(formIds.region) - const address_line1 = readTrimmedValue(formIds.address_line1) - const address_line2 = readTrimmedValue(formIds.address_line2) + const address_line1 = readTrimmedValue(formIds.address1) + const address_line2 = readTrimmedValue(formIds.address2) const city = readTrimmedValue(formIds.city) - const city_id = Number(readTrimmedValue(formIds.city_id)) const countryId = Number(readTrimmedValue(formIds.countryId)) saveUserInfo({ address_line1, address_line2, city, - city_id, + cityId: selectedCity?.id || null, countryId, firstname, lastname, @@ -77,40 +74,36 @@ export const useUserInfo = () => { }, [ readTrimmedValue, validateForm, - ]) - - const onCountrySelect = useCallback((country: SelectedCountry) => { - setSelectedCountry(country) - const countryName = country ? country[`name_${suffix}` as Name] : '' - updateFormValue(formIds.country)(countryName) - // TO DO пока не решили сбрасываем ли город и адрес - // updateFormValue(formIds.region)('') - updateFormValue(formIds.countryId)(`${country?.id}`) - }, [ - setSelectedCountry, - updateFormValue, - suffix, + selectedCity, ]) useEffect(() => { getUserInfo().then((res: UserInfo) => { forEach(res, (value: string | number | SelectedCountry, key: string) => { if (value && typeof value === 'object') { - onCountrySelect(value) - } else if (isString(value)) { - updateFormValue(key)(value) + onCountrySelect(value, false) + } else if (value) { + updateFormValue(key)(String(value)) } }) }) }, [updateFormValue, onCountrySelect]) return { + cities, countries, + getCities, handleSubmit, + onCitySelect, onCountrySelect, + onPhoneBlur, + onRegionOrCityChange, readFormError, readFormValue, + resetCities, + resetSelectedCity, saveButton, + selectedCity, updateFormError, updateFormValue, } diff --git a/src/features/UserAccount/index.tsx b/src/features/UserAccount/index.tsx index 1451f120..d5024991 100644 --- a/src/features/UserAccount/index.tsx +++ b/src/features/UserAccount/index.tsx @@ -1,6 +1,7 @@ import React from 'react' import { userAccountLexics } from 'config/lexics/userAccount' +import { formIds } from 'config/form' import { Background } from 'features/Background' import { Combobox } from 'features/Combobox' @@ -9,11 +10,11 @@ import { Form } from 'features/Login/styled' import { T9n } from 'features/T9n' import { Error } from 'features/Common/Input/styled' import { useLexicsStore, useLexicsConfig } from 'features/LexicsStore' + import { CardNumber } from './CardNumber' import { UserAccountButton } from './UserAccountButton' import { PageTitle } from './PageTitle' import { UserAccountSubscription } from './UserAccountSubscription' -import { formIds } from './config' import { TextNoBorder } from './TextNoBorder' import { useUserInfo } from './hooks' @@ -27,7 +28,7 @@ import { ButtonWrapper, } from './styled' -const labelWidth = 78 +const labelWidth = 110 export const UserAccount = () => { useLexicsConfig(userAccountLexics) @@ -35,9 +36,13 @@ export const UserAccount = () => { const { translate } = useLexicsStore() const { + cities, countries, handleSubmit, + onCitySelect, onCountrySelect, + onPhoneBlur, + onRegionOrCityChange, readFormError, readFormValue, saveButton, @@ -61,6 +66,8 @@ export const UserAccount = () => { labelWidth={labelWidth} onChange={updateFormValue(formIds.firstname)} error={readFormError(formIds.firstname)} + editIcon + maxLength={500} /> { labelWidth={labelWidth} onChange={updateFormValue(formIds.lastname)} error={readFormError(formIds.lastname)} + editIcon + maxLength={500} /> + - - - - - - - - - -
- - - - - - - - -
- -
- - - - - - - - - - -
- - - - - - - - -
- - - - - - - - + + + + + +
diff --git a/src/features/UserAccount/styled.tsx b/src/features/UserAccount/styled.tsx index 1a9942fe..ddf7e799 100644 --- a/src/features/UserAccount/styled.tsx +++ b/src/features/UserAccount/styled.tsx @@ -8,9 +8,11 @@ export const OutlinedButton = styled.button` width: 288px; margin-top: 20px; align-self: flex-start; - color: #005EDD; - border-color: #005EDD; - + color: white; + font-weight: bold; + border-color: #0033CC; + background-color: #0033CC; + &:hover { cursor: pointer; } diff --git a/src/features/UserAccount/useValidateForm.tsx b/src/features/UserAccount/useValidateForm.tsx index 300d6a88..de87914f 100644 --- a/src/features/UserAccount/useValidateForm.tsx +++ b/src/features/UserAccount/useValidateForm.tsx @@ -2,13 +2,14 @@ import trim from 'lodash/trim' import reduce from 'lodash/reduce' import { useForm } from 'features/FormStore' -import { isValidPhone } from 'features/Register/helpers/isValidPhone' +import { isValidPhone } from 'helpers/isValidPhone' +import { isValidPassword } from 'helpers/isValidPassword' import { formIds, requiredFields, simpleValidationFields, -} from './config' +} from 'config/form' export const useValidateForm = () => { const { @@ -37,6 +38,7 @@ export const useValidateForm = () => { const validateForm = () => { let hasError = false const phone = readTrimmedValue(formIds.phone) + const password = readTrimmedValue(formIds.password) if (allFieldsEmpty(requiredFields)) { updateFormError(formIds.formError, 'error_fill_out_required_fields') @@ -46,6 +48,11 @@ export const useValidateForm = () => { hasError = setErrorOnEmptyFields(simpleValidationFields, 'error_fill_out_this_field') + if (!isValidPassword(password)) { + updateFormError(formIds.password, 'error_simple_password') + hasError = true + } + if (!isValidPhone(phone)) { updateFormError(formIds.phone, 'error_invalid_phone_format') hasError = true diff --git a/src/features/Register/helpers/formatPhoneCode/__tests__/index.tsx b/src/helpers/formatPhoneCode/__tests__/index.tsx similarity index 100% rename from src/features/Register/helpers/formatPhoneCode/__tests__/index.tsx rename to src/helpers/formatPhoneCode/__tests__/index.tsx diff --git a/src/features/Register/helpers/formatPhoneCode/index.tsx b/src/helpers/formatPhoneCode/index.tsx similarity index 100% rename from src/features/Register/helpers/formatPhoneCode/index.tsx rename to src/helpers/formatPhoneCode/index.tsx diff --git a/src/features/Register/helpers/isValidEmail/__tests__/index.tsx b/src/helpers/isValidEmail/__tests__/index.tsx similarity index 100% rename from src/features/Register/helpers/isValidEmail/__tests__/index.tsx rename to src/helpers/isValidEmail/__tests__/index.tsx diff --git a/src/features/Register/helpers/isValidEmail/index.tsx b/src/helpers/isValidEmail/index.tsx similarity index 100% rename from src/features/Register/helpers/isValidEmail/index.tsx rename to src/helpers/isValidEmail/index.tsx diff --git a/src/features/Register/helpers/isValidPassword/__tests__/index.tsx b/src/helpers/isValidPassword/__tests__/index.tsx similarity index 100% rename from src/features/Register/helpers/isValidPassword/__tests__/index.tsx rename to src/helpers/isValidPassword/__tests__/index.tsx diff --git a/src/features/Register/helpers/isValidPassword/index.tsx b/src/helpers/isValidPassword/index.tsx similarity index 100% rename from src/features/Register/helpers/isValidPassword/index.tsx rename to src/helpers/isValidPassword/index.tsx diff --git a/src/features/Register/helpers/isValidPhone/__tests__/index.tsx b/src/helpers/isValidPhone/__tests__/index.tsx similarity index 100% rename from src/features/Register/helpers/isValidPhone/__tests__/index.tsx rename to src/helpers/isValidPhone/__tests__/index.tsx diff --git a/src/features/Register/helpers/isValidPhone/index.tsx b/src/helpers/isValidPhone/index.tsx similarity index 100% rename from src/features/Register/helpers/isValidPhone/index.tsx rename to src/helpers/isValidPhone/index.tsx diff --git a/src/features/Register/components/RegistrationStep/hooks/useCities.tsx b/src/hooks/useCities.tsx similarity index 74% rename from src/features/Register/components/RegistrationStep/hooks/useCities.tsx rename to src/hooks/useCities.tsx index 89e1ddd5..9247c441 100644 --- a/src/features/Register/components/RegistrationStep/hooks/useCities.tsx +++ b/src/hooks/useCities.tsx @@ -7,23 +7,24 @@ import debounce from 'lodash/debounce' import type { Cities, City } from 'requests' import { getCountryCities } from 'requests' -import { useForm } from 'features/FormStore' -import { formIds } from '../config' +import { formIds } from 'config/form' + +import { useForm } from 'features/FormStore' const useCitiesList = () => { const [cities, setCities] = useState([]) - const getCities = (city: string, selectedCountryId: number) => { + const getCities = useCallback((city: string, selectedCountryId: number) => { getCountryCities(city, selectedCountryId).then(setCities) - } + }, []) const getCitiesDebounced = useCallback( - debounce(getCities, 300), + debounce(getCities, 500), [], ) - const resetCities = () => setCities([]) + const resetCities = useCallback(() => setCities([]), []) return { cities, @@ -44,19 +45,19 @@ export const useCities = () => { resetCities, } = useCitiesList() - const onCitySelect = (newCity: City | null) => { + const onCitySelect = useCallback((newCity: City | null) => { if (newCity) { setCityQuery(newCity.name) setSelectedCity(newCity) } else { setSelectedCity(null) } - } + }, [setCityQuery]) - const resetSelectedCity = () => { + const resetSelectedCity = useCallback(() => { setCityQuery('') setSelectedCity(null) - } + }, [setCityQuery]) return { cities, diff --git a/src/features/Register/components/RegistrationStep/hooks/useForm.tsx b/src/hooks/useForm.tsx similarity index 52% rename from src/features/Register/components/RegistrationStep/hooks/useForm.tsx rename to src/hooks/useForm.tsx index 788ff9a0..33caa5e2 100644 --- a/src/features/Register/components/RegistrationStep/hooks/useForm.tsx +++ b/src/hooks/useForm.tsx @@ -1,18 +1,26 @@ import type { ChangeEvent, FocusEvent } from 'react' -import { useEffect } from 'react' +import { + useEffect, + useCallback, +} from 'react' import trim from 'lodash/trim' -import { useForm } from 'features/FormStore' -import { isValidEmail } from 'features/Register/helpers/isValidEmail' -import { isValidPhone } from 'features/Register/helpers/isValidPhone' -import { formatPhoneCode } from 'features/Register/helpers/formatPhoneCode' +import { isValidEmail } from 'helpers/isValidEmail' +import { isValidPhone } from 'helpers/isValidPhone' +import { formatPhoneCode } from 'helpers/formatPhoneCode' import type { SelectedCountry } from 'hooks/useCountries' import { useCountries } from 'hooks/useCountries' -import { formIds } from '../config' -import { useCities } from './useCities' -import { useSubmitHandler } from './useSubmitHandler' +import { useCities } from 'hooks/useCities' + +import { formIds } from 'config/form' + +import { useForm } from 'features/FormStore' +import { useSubmitHandler } from 'features/Register/components/RegistrationStep/hooks/useSubmitHandler' +import { useLexicsStore } from 'features/LexicsStore' + +type Name = 'name_rus' | 'name_eng' export const useRegistrationForm = () => { const { @@ -41,33 +49,50 @@ export const useRegistrationForm = () => { selectedCity, selectedCountry, }) + const { suffix } = useLexicsStore() - const onEmailBlur = ({ target }: FocusEvent) => { + const onEmailBlur = useCallback(({ target }: FocusEvent) => { const email = trim(target.value) if (email && !isValidEmail(email)) { updateFormError(formIds.email, 'error_invalid_email_format') } - } + }, [updateFormError]) - const onPhoneBlur = ({ target }: ChangeEvent) => { + const onPhoneBlur = useCallback(({ target }: ChangeEvent) => { const phone = target.value if (phone && !isValidPhone(phone)) { updateFormError(formIds.phone, 'error_invalid_phone_format') } - } + }, [updateFormError]) - const onCountrySelect = (country: SelectedCountry) => { + const onCountrySelect = useCallback(( + country: SelectedCountry, + updatePhoneCode: boolean = true, + ) => { setSelectedCountry(country) - updateFormValue(formIds.country)(country?.name || '') + const countryName = country ? country[`name_${suffix}` as Name] : '' + updateFormValue(formIds.country)(countryName) + + updateFormValue(formIds.cityId)('') + updateFormValue(formIds.countryId)(`${country?.id}`) resetCities() resetSelectedCity() - const code = country?.phone_code - ? formatPhoneCode(country.phone_code) - : '' - updateFormValue(formIds.phone)(code) - } - const onRegionOrCityChange = (fieldName: string) => ( + if (updatePhoneCode) { + const code = country?.phone_code + ? formatPhoneCode(country.phone_code) + : '' + updateFormValue(formIds.phone)(code) + } + }, [ + resetCities, + resetSelectedCity, + setSelectedCountry, + updateFormValue, + suffix, + ]) + + const onRegionOrCityChange = useCallback((fieldName: string) => ( ({ target }: ChangeEvent) => { if (selectedCountry) { updateFormValue(fieldName)(target.value) @@ -75,7 +100,11 @@ export const useRegistrationForm = () => { updateFormError(formIds.country, 'error_select_country_first') } } - ) + ), [ + selectedCountry, + updateFormError, + updateFormValue, + ]) const trimmedCity = trim(readFormValue(formIds.city)) useEffect(() => { @@ -91,6 +120,7 @@ export const useRegistrationForm = () => { return { cities, countries, + getCities, handleSubmit, onCitySelect, onCountrySelect, @@ -99,6 +129,10 @@ export const useRegistrationForm = () => { onRegionOrCityChange, readFormError, readFormValue, + resetCities, + resetSelectedCity, + selectedCity, + updateFormError, updateFormValue, } } diff --git a/src/features/Register/components/RegistrationStep/hooks/useValidateForm.tsx b/src/hooks/useValidateForm.tsx similarity index 88% rename from src/features/Register/components/RegistrationStep/hooks/useValidateForm.tsx rename to src/hooks/useValidateForm.tsx index e3fff184..923315f9 100644 --- a/src/features/Register/components/RegistrationStep/hooks/useValidateForm.tsx +++ b/src/hooks/useValidateForm.tsx @@ -2,15 +2,15 @@ import trim from 'lodash/trim' import reduce from 'lodash/reduce' import { useForm } from 'features/FormStore' -import { isValidEmail } from 'features/Register/helpers/isValidEmail' -import { isValidPassword } from 'features/Register/helpers/isValidPassword' -import { isValidPhone } from 'features/Register/helpers/isValidPhone' +import { isValidEmail } from 'helpers/isValidEmail' +import { isValidPassword } from 'helpers/isValidPassword' +import { isValidPhone } from 'helpers/isValidPhone' import { formIds, requiredFields, simpleValidationFields, -} from '../config' +} from 'config/form' export const useValidateForm = () => { const { diff --git a/src/requests/saveUserInfo.tsx b/src/requests/saveUserInfo.tsx index 4153d9a9..73e2d2ba 100644 --- a/src/requests/saveUserInfo.tsx +++ b/src/requests/saveUserInfo.tsx @@ -10,7 +10,7 @@ export type UserInfo = { address_line1: string, address_line2: string, city: string, - city_id: number, + cityId: number | null, countryId: number, firstname: string, lastname: string, @@ -34,7 +34,7 @@ export const saveUserInfo = async ({ address_line1, address_line2, city, - city_id, + cityId, countryId, firstname, lastname, @@ -49,7 +49,7 @@ export const saveUserInfo = async ({ _p_address_line1: address_line1, _p_address_line2: address_line2, _p_city: city, - _p_city_id: city_id, + _p_city_id: cityId, _p_country_id: countryId, _p_firstname: firstname, _p_lastname: lastname,