From a66e6471060a5b2e8245f6a6ed14d473bfefba94 Mon Sep 17 00:00:00 2001 From: Mirlan Date: Thu, 16 Jul 2020 20:20:25 +0600 Subject: [PATCH] Ott 227 add phone code (#45) --- src/config/lexics/public.tsx | 1 + .../components/RegistrationStep/config.tsx | 1 - .../RegistrationStep/hooks/useCountries.tsx | 11 +++++------ .../RegistrationStep/hooks/useForm.tsx | 18 ++++++++++++++++-- .../hooks/useSubmitHandler.tsx | 4 ++-- .../RegistrationStep/hooks/useValidateForm.tsx | 6 ++++++ .../components/RegistrationStep/index.tsx | 2 ++ .../formatPhoneCode/__tests__/index.tsx | 12 ++++++++++++ .../Register/helpers/formatPhoneCode/index.tsx | 7 +++++++ .../helpers/isValidPhone/__tests__/index.tsx | 16 ++++++++++++++++ .../Register/helpers/isValidPhone/index.tsx | 5 +++++ src/requests/getCountries.tsx | 1 + 12 files changed, 73 insertions(+), 11 deletions(-) create mode 100644 src/features/Register/helpers/formatPhoneCode/__tests__/index.tsx create mode 100644 src/features/Register/helpers/formatPhoneCode/index.tsx create mode 100644 src/features/Register/helpers/isValidPhone/__tests__/index.tsx create mode 100644 src/features/Register/helpers/isValidPhone/index.tsx diff --git a/src/config/lexics/public.tsx b/src/config/lexics/public.tsx index 303ad817..c0ebbf1f 100644 --- a/src/config/lexics/public.tsx +++ b/src/config/lexics/public.tsx @@ -6,6 +6,7 @@ export const publicLexics = { error_fill_out_this_field: 12933, error_invalid_email_format: 12908, error_invalid_email_or_password: 2502, + error_invalid_phone_format: 12946, error_select_country_first: 12910, error_simple_password: 12940, form_address1: 12914, diff --git a/src/features/Register/components/RegistrationStep/config.tsx b/src/features/Register/components/RegistrationStep/config.tsx index 15b683c1..e2dc51d1 100644 --- a/src/features/Register/components/RegistrationStep/config.tsx +++ b/src/features/Register/components/RegistrationStep/config.tsx @@ -32,7 +32,6 @@ export const simpleValidationFields = [ formIds.country, formIds.firstname, formIds.lastname, - formIds.phone, formIds.postalCode, formIds.region, ] diff --git a/src/features/Register/components/RegistrationStep/hooks/useCountries.tsx b/src/features/Register/components/RegistrationStep/hooks/useCountries.tsx index 856372d6..03789175 100644 --- a/src/features/Register/components/RegistrationStep/hooks/useCountries.tsx +++ b/src/features/Register/components/RegistrationStep/hooks/useCountries.tsx @@ -7,14 +7,13 @@ import { import orderBy from 'lodash/orderBy' import map from 'lodash/map' -import type { Countries } from 'requests' +import type { Countries, Country } from 'requests' import { getCountries } from 'requests' import { useLexicsStore } from 'features/LexicsStore' -export type Country = { - id: number, +export type SelectedCountry = (Country & { name: string, -} +}) | null type Names = 'name_eng' | 'name_rus' @@ -31,14 +30,14 @@ const useCountriesList = () => { export const useCountries = () => { const countries = useCountriesList() const { suffix } = useLexicsStore() - const [selectedCountry, setSelectedCountry] = useState(null) + const [selectedCountry, setSelectedCountry] = useState(null) const nameField = `name_${suffix}` as Names const transformedCountries = useMemo( () => orderBy( map(countries, (country) => ({ - id: country.id, + ...country, name: country[nameField], })), 'name', diff --git a/src/features/Register/components/RegistrationStep/hooks/useForm.tsx b/src/features/Register/components/RegistrationStep/hooks/useForm.tsx index 62e865db..aace46a4 100644 --- a/src/features/Register/components/RegistrationStep/hooks/useForm.tsx +++ b/src/features/Register/components/RegistrationStep/hooks/useForm.tsx @@ -5,9 +5,11 @@ 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 { formIds } from '../config' -import type { Country } from './useCountries' +import type { SelectedCountry } from './useCountries' import { useCountries } from './useCountries' import { useCities } from './useCities' import { useSubmitHandler } from './useSubmitHandler' @@ -45,11 +47,22 @@ export const useRegistrationForm = () => { } } - const onCountrySelect = (country: Country | null) => { + const onPhoneBlur = ({ target }: ChangeEvent) => { + const phone = target.value + if (phone && !isValidPhone(phone)) { + updateFormError(formIds.phone, 'error_invalid_phone_format') + } + } + + const onCountrySelect = (country: SelectedCountry) => { setSelectedCountry(country) updateFormValue(formIds.country)(country?.name || '') resetCities() resetSelectedCity() + const code = country?.phone_code + ? formatPhoneCode(country.phone_code) + : '' + updateFormValue(formIds.phone)(code) } const onRegionOrCityChange = (fieldName: string) => ( @@ -80,6 +93,7 @@ export const useRegistrationForm = () => { onCitySelect, onCountrySelect, onEmailBlur, + onPhoneBlur, onRegionOrCityChange, readFormError, readFormValue, diff --git a/src/features/Register/components/RegistrationStep/hooks/useSubmitHandler.tsx b/src/features/Register/components/RegistrationStep/hooks/useSubmitHandler.tsx index b4d12659..b37e1727 100644 --- a/src/features/Register/components/RegistrationStep/hooks/useSubmitHandler.tsx +++ b/src/features/Register/components/RegistrationStep/hooks/useSubmitHandler.tsx @@ -8,12 +8,12 @@ import { useAuthStore } from 'features/AuthStore' import { useForm } from 'features/FormStore' import { formIds } from '../config' -import type { Country } from './useCountries' +import type { SelectedCountry } from './useCountries' import { useValidateForm } from './useValidateForm' type Args = { selectedCity: City | null, - selectedCountry: Country | null, + selectedCountry: SelectedCountry, } export const useSubmitHandler = ({ diff --git a/src/features/Register/components/RegistrationStep/hooks/useValidateForm.tsx b/src/features/Register/components/RegistrationStep/hooks/useValidateForm.tsx index 776a2cdd..47ff9628 100644 --- a/src/features/Register/components/RegistrationStep/hooks/useValidateForm.tsx +++ b/src/features/Register/components/RegistrationStep/hooks/useValidateForm.tsx @@ -4,6 +4,7 @@ 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 { formIds, @@ -39,6 +40,7 @@ export const useValidateForm = () => { let hasError = false const email = readTrimmedValue(formIds.email) const password = readTrimmedValue(formIds.password) + const phone = readTrimmedValue(formIds.phone) if (allFieldsEmpty(requiredFields)) { updateFormError(formIds.formError, 'error_fill_out_required_fields') setErrorOnEmptyFields(requiredFields, '') @@ -54,6 +56,10 @@ export const useValidateForm = () => { updateFormError(formIds.password, 'error_simple_password') hasError = true } + if (isValidPhone(phone)) { + updateFormError(formIds.phone, 'error_invalid_phone_format') + hasError = true + } hasError = setErrorOnEmptyFields(simpleValidationFields, 'error_fill_out_this_field') return !hasError } diff --git a/src/features/Register/components/RegistrationStep/index.tsx b/src/features/Register/components/RegistrationStep/index.tsx index 36ddbe97..3add5f2d 100644 --- a/src/features/Register/components/RegistrationStep/index.tsx +++ b/src/features/Register/components/RegistrationStep/index.tsx @@ -24,6 +24,7 @@ const Registration = () => { onCitySelect, onCountrySelect, onEmailBlur, + onPhoneBlur, onRegionOrCityChange, readFormError, readFormValue, @@ -133,6 +134,7 @@ const Registration = () => { labelLexic='form_phone' labelWidth={labelWidth} onChange={updateFormValue(formIds.phone)} + onBlur={onPhoneBlur} /> diff --git a/src/features/Register/helpers/formatPhoneCode/__tests__/index.tsx b/src/features/Register/helpers/formatPhoneCode/__tests__/index.tsx new file mode 100644 index 00000000..b1ad0089 --- /dev/null +++ b/src/features/Register/helpers/formatPhoneCode/__tests__/index.tsx @@ -0,0 +1,12 @@ +import { formatPhoneCode } from '..' + +it('returns empty code', () => { + expect(formatPhoneCode('')).toBe('') + expect(formatPhoneCode('+')).toBe('') + expect(formatPhoneCode('abcd')).toBe('') +}) + +it('returns formatted code', () => { + expect(formatPhoneCode('+1')).toBe('+(1)') + expect(formatPhoneCode('+12345')).toBe('+(12345)') +}) diff --git a/src/features/Register/helpers/formatPhoneCode/index.tsx b/src/features/Register/helpers/formatPhoneCode/index.tsx new file mode 100644 index 00000000..44b632fb --- /dev/null +++ b/src/features/Register/helpers/formatPhoneCode/index.tsx @@ -0,0 +1,7 @@ +const numberGroup = /(\d+)/ + +export const formatPhoneCode = (phoneCode: string) => { + const group = phoneCode.match(numberGroup) + const code = group?.[0] + return code ? `+(${code})` : '' +} diff --git a/src/features/Register/helpers/isValidPhone/__tests__/index.tsx b/src/features/Register/helpers/isValidPhone/__tests__/index.tsx new file mode 100644 index 00000000..2cdd4877 --- /dev/null +++ b/src/features/Register/helpers/isValidPhone/__tests__/index.tsx @@ -0,0 +1,16 @@ +import { isValidPhone } from '..' + +it('returns false for invalid phones', () => { + expect(isValidPhone('')).toBeFalsy() + expect(isValidPhone('a')).toBeFalsy() + expect(isValidPhone('!@#!$%')).toBeFalsy() + expect(isValidPhone('+(1)123a')).toBeFalsy() + expect(isValidPhone('+(1)-234-5678$')).toBeFalsy() +}) + +it('returns true for valid phones', () => { + expect(isValidPhone('+(1)')).toBeTruthy() + expect(isValidPhone('+(1)12345')).toBeTruthy() + expect(isValidPhone('+(1) 234 5678')).toBeTruthy() + expect(isValidPhone('+(1)-234-5678')).toBeTruthy() +}) diff --git a/src/features/Register/helpers/isValidPhone/index.tsx b/src/features/Register/helpers/isValidPhone/index.tsx new file mode 100644 index 00000000..0da90f61 --- /dev/null +++ b/src/features/Register/helpers/isValidPhone/index.tsx @@ -0,0 +1,5 @@ +const phoneRegex = /^[0-9+\- ()]{1,500}$/ + +export const isValidPhone = (phone: string) => ( + phoneRegex.test(phone.toLowerCase()) +) diff --git a/src/requests/getCountries.tsx b/src/requests/getCountries.tsx index e0b4a191..a0790b6b 100644 --- a/src/requests/getCountries.tsx +++ b/src/requests/getCountries.tsx @@ -9,6 +9,7 @@ export type Country = { iso_3166_1_alpha_3: string, name_eng: string, name_rus: string, + phone_code: string | null, } export type Countries = Array