feat(#2901): add usa state to add card form

keep-around/2fd168b18eeebc91eac94ae86d817c12edfe1576
Andrei Dekterev 3 years ago
parent 861b9025e1
commit a31504be0b
  1. 73882
      package-lock.json
  2. 3
      package.json
  3. 1
      src/config/lexics/payment.tsx
  4. 44
      src/features/AddCardForm/components/Form/hooks/index.tsx
  5. 23
      src/features/AddCardForm/components/Form/hooks/useCountries.tsx
  6. 40
      src/features/AddCardForm/components/Form/index.tsx
  7. 4
      src/features/AddCardForm/styled.tsx
  8. 22
      src/requests/getUsaStates.tsx

73882
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -34,7 +34,7 @@
"react-dom": "^17.0.2", "react-dom": "^17.0.2",
"react-router": "^5.2.0", "react-router": "^5.2.0",
"react-router-dom": "^5.2.0", "react-router-dom": "^5.2.0",
"react-scripts": "^4.0.3", "react-scripts": "^5.0.1",
"react-window": "^1.8.6", "react-window": "^1.8.6",
"react-youtube": "^7.14.0", "react-youtube": "^7.14.0",
"recoil": "^0.7.4", "recoil": "^0.7.4",
@ -71,6 +71,7 @@
"commitizen": "^4.2.4", "commitizen": "^4.2.4",
"eslint": "^7.14.0", "eslint": "^7.14.0",
"eslint-config-airbnb": "18.2.1", "eslint-config-airbnb": "18.2.1",
"eslint-config-react-app": "^7.0.1",
"eslint-plugin-import": "^2.22.1", "eslint-plugin-import": "^2.22.1",
"eslint-plugin-jsx-a11y": "^6.4.1", "eslint-plugin-jsx-a11y": "^6.4.1",
"eslint-plugin-postro4no": "^0.0.7", "eslint-plugin-postro4no": "^0.0.7",

@ -26,6 +26,7 @@ export const paymentLexics = {
payment_method: 2010, payment_method: 2010,
pb_instat: 18274, pb_instat: 18274,
save_sub: 18190, save_sub: 18190,
state: 12932,
still_cancel: 2646, still_cancel: 2646,
sub_not_renewed: 15060, sub_not_renewed: 15060,
subscription_plan: 18182, subscription_plan: 18182,

@ -32,7 +32,12 @@ import { dataForPayHighlights } from 'pages/HighlightsPage/storeHighlightsAtoms'
import { onePayment } from 'requests/onePayment' import { onePayment } from 'requests/onePayment'
import { SelectedCountry, useCountries } from './useCountries' import {
SelectedCountry,
SelectedState,
useCountries,
} from './useCountries'
import { import {
isValidAddress, isValidAddress,
isValidName, isValidName,
@ -47,6 +52,7 @@ export enum ElementTypes {
CardExpiry = 'cardExpiry', CardExpiry = 'cardExpiry',
CardHolder = 'cardHolder', CardHolder = 'cardHolder',
CardNumber = 'cardNumber', CardNumber = 'cardNumber',
CardState = 'cardState',
} }
export type Props = { export type Props = {
@ -72,6 +78,7 @@ const initialState = {
cardExpiry: inputState, cardExpiry: inputState,
cardHolder: inputState, cardHolder: inputState,
cardNumber: inputState, cardNumber: inputState,
cardState: inputState,
} }
export const useFormSubmit = ({ export const useFormSubmit = ({
@ -93,6 +100,7 @@ export const useFormSubmit = ({
const [name, setName] = useState('') const [name, setName] = useState('')
const [city, setCity] = useState('') const [city, setCity] = useState('')
const [address, setAddress] = useState('') const [address, setAddress] = useState('')
const [usaStateValue, setUsaStateValue] = useState('')
const [inputStates, setInputStates] = useObjectState(initialState) const [inputStates, setInputStates] = useObjectState(initialState)
const [errorMessage, setErrorMessage] = useState('') const [errorMessage, setErrorMessage] = useState('')
const [loader, setLoader] = useState(false) const [loader, setLoader] = useState(false)
@ -107,7 +115,10 @@ export const useFormSubmit = ({
const { const {
countries, countries,
selectedCountry, selectedCountry,
selectedState,
setSelectedCountry, setSelectedCountry,
setSelectedState,
usaStates,
} = useCountries() } = useCountries()
const resetErrors = useCallback(() => { const resetErrors = useCallback(() => {
@ -154,8 +165,25 @@ export const useFormSubmit = ({
if (country?.id === selectedCountry?.id) return if (country?.id === selectedCountry?.id) return
setSelectedCountry(country) setSelectedCountry(country)
if (selectedCountry?.id !== 194) {
setSelectedState(null)
}
setElementTypeState(ElementTypes.CardCountry, country?.name_eng || '') setElementTypeState(ElementTypes.CardCountry, country?.name_eng || '')
}, [resetErrors, selectedCountry?.id, setElementTypeState, setSelectedCountry]) }, [
resetErrors,
selectedCountry?.id,
setElementTypeState,
setSelectedCountry,
setSelectedState,
])
const onStateSelect = useCallback((state: SelectedState) => {
resetErrors()
if (state?.id === selectedState?.id) return
setSelectedState(state)
setUsaStateValue('')
setElementTypeState(ElementTypes.CardState, state?.name_eng || '')
}, [resetErrors, selectedState?.id, setElementTypeState, setSelectedState])
const onCityChange = (e: ChangeEvent<HTMLInputElement>) => { const onCityChange = (e: ChangeEvent<HTMLInputElement>) => {
const { value } = e.target const { value } = e.target
@ -167,6 +195,12 @@ export const useFormSubmit = ({
resetErrors() resetErrors()
setElementTypeState(ElementTypes.CardCity, value) setElementTypeState(ElementTypes.CardCity, value)
} }
const onStateChange = (e: ChangeEvent<HTMLInputElement>) => {
const { value } = e.target
setUsaStateValue(value)
}
const onAddressChange = (e: ChangeEvent<HTMLInputElement>) => { const onAddressChange = (e: ChangeEvent<HTMLInputElement>) => {
const { value } = e.target const { value } = e.target
if (!isValidAddress(value)) { if (!isValidAddress(value)) {
@ -244,6 +278,7 @@ export const useFormSubmit = ({
address_city: city, address_city: city,
address_country: selectedCountry?.name || '', address_country: selectedCountry?.name || '',
address_line1: address, address_line1: address,
address_state: selectedState?.name_eng,
name, name,
}, },
) )
@ -303,6 +338,11 @@ export const useFormSubmit = ({
onInputsChange, onInputsChange,
onInputsFocus, onInputsFocus,
onNameChange, onNameChange,
onStateChange,
onStateSelect,
selectedCountry, selectedCountry,
selectedState,
usaStateValue,
usaStates,
} }
} }

@ -1,7 +1,7 @@
import { import {
useEffect, useEffect,
useState,
useMemo, useMemo,
useState,
} from 'react' } from 'react'
import orderBy from 'lodash/orderBy' import orderBy from 'lodash/orderBy'
@ -9,11 +9,16 @@ import map from 'lodash/map'
import type { Countries, Country } from 'requests' import type { Countries, Country } from 'requests'
import { getCountries } from 'requests' import { getCountries } from 'requests'
import { getUsaStates, UsaStateType } from 'requests/getUsaStates'
export type SelectedCountry = (Country & { export type SelectedCountry = (Country & {
name: string, name: string,
}) | null }) | null
export type SelectedState = (UsaStateType & {
name: string,
}) | null
const useCountriesList = () => { const useCountriesList = () => {
const [countries, setCountries] = useState<Countries>([]) const [countries, setCountries] = useState<Countries>([])
@ -27,6 +32,9 @@ const useCountriesList = () => {
export const useCountries = () => { export const useCountries = () => {
const countries = useCountriesList() const countries = useCountriesList()
const [selectedCountry, setSelectedCountry] = useState<SelectedCountry>(null) const [selectedCountry, setSelectedCountry] = useState<SelectedCountry>(null)
const [usaStates, setUsaStates] = useState<Array<UsaStateType>>([])
const [selectedState, setSelectedState] = useState<SelectedState>(null)
const transformedCountries = useMemo( const transformedCountries = useMemo(
() => orderBy( () => orderBy(
map(countries, (country) => ({ map(countries, (country) => ({
@ -38,9 +46,22 @@ export const useCountries = () => {
[countries], [countries],
) )
useEffect(() => {
if (selectedCountry?.id === 194) {
(async () => {
const states = await getUsaStates()
setUsaStates(states)
})()
}
}, [selectedCountry])
return { return {
countries: transformedCountries, countries: transformedCountries,
selectedCountry, selectedCountry,
selectedState,
setSelectedCountry, setSelectedCountry,
setSelectedState,
setUsaStates,
usaStates: usaStates.map((state: UsaStateType) => ({ ...state, name: state.name_eng })),
} }
} }

@ -62,6 +62,17 @@ export const AddCardFormInner = (props: Props) => {
const isUserAccountPage = useRouteMatch(PAGES.useraccount)?.path === PAGES.useraccount const isUserAccountPage = useRouteMatch(PAGES.useraccount)?.path === PAGES.useraccount
const calcWidth = () => {
switch (true) {
case isUsaCountry:
return '100%'
case isMobileDevice:
return '48%'
default:
return '275px'
}
}
const { const {
address, address,
city, city,
@ -78,9 +89,16 @@ export const AddCardFormInner = (props: Props) => {
onInputsChange, onInputsChange,
onInputsFocus, onInputsFocus,
onNameChange, onNameChange,
onStateChange,
onStateSelect,
selectedCountry, selectedCountry,
selectedState,
usaStates,
usaStateValue,
} = useFormSubmit(props) } = useFormSubmit(props)
const isUsaCountry = selectedCountry?.id === 194
return ( return (
<Form onSubmit={handleSubmit}> <Form onSubmit={handleSubmit}>
<SectionTitle> <SectionTitle>
@ -160,10 +178,28 @@ export const AddCardFormInner = (props: Props) => {
noSearch noSearch
/> />
</CountryWrapper> </CountryWrapper>
{isUsaCountry && (
<CountryWrapper>
<CustomCombobox
value={usaStateValue || selectedState?.name || ''}
labelLexic={selectedState?.name ? '' : 'state'}
onSelect={onStateSelect}
onBlur={onInputsBlur(ElementTypes.CardState)}
options={usaStates.filter(
(state) => (state.name_eng.toLowerCase().includes(usaStateValue.toLowerCase())),
)}
withError={false}
selected={Boolean(selectedState?.name)}
onChange={onStateChange}
/>
</CountryWrapper>
)}
<ElementContainer <ElementContainer
label={isLabelVisible(ElementTypes.CardCity) ? 'city' : ''} label={isLabelVisible(ElementTypes.CardCity) ? 'city' : ''}
width={isMobileDevice ? '48%' : '275px'} width={calcWidth()}
backgroundColor={inputsBackground} backgroundColor={inputsBackground}
className={isUsaCountry ? 'CardForm__cityInput' : ''}
> >
<Input <Input
type='text' type='text'
@ -178,7 +214,7 @@ export const AddCardFormInner = (props: Props) => {
label={isLabelVisible(ElementTypes.CardAddress) ? 'address' : ''} label={isLabelVisible(ElementTypes.CardAddress) ? 'address' : ''}
width='100%' width='100%'
backgroundColor={inputsBackground} backgroundColor={inputsBackground}
className='AddCardForm_Address' className={isUsaCountry ? 'CardForm__cityInput AddCardForm_Address' : 'AddCardForm_Address'}
> >
<Input <Input
type='text' type='text'

@ -20,6 +20,10 @@ export const Column = styled.div`
justify-content: space-between; justify-content: space-between;
flex-wrap: wrap; flex-wrap: wrap;
margin-bottom: 8px; margin-bottom: 8px;
.CardForm__cityInput {
margin: 10px 0;
}
` `
export const ButtonsBlock = styled.div<ButtonsBlockTypes>` export const ButtonsBlock = styled.div<ButtonsBlockTypes>`

@ -0,0 +1,22 @@
import {
API_ROOT,
} from 'config'
import { callApi } from 'helpers'
export type UsaStateType = {
id: number,
iso_2: string,
name_eng: string,
name_rus: string,
}
export const getUsaStates = (): Promise<Array<UsaStateType>> => {
const config = {
method: 'GET',
}
return callApi({
config,
url: `${API_ROOT}/v1/data/usa-states`,
})
}
Loading…
Cancel
Save