fix(#2469): saving user language in database

keep-around/13d6202b3f662a038de7245dbbe045cb995026b7
Rakov Roman 4 years ago
parent 26b6d317dc
commit 13d6202b3f
  1. 4
      src/config/clients/types.tsx
  2. 90
      src/config/languages.tsx
  3. 1
      src/config/procedures.tsx
  4. 11
      src/features/AuthServiceApp/components/LanguageSelect/hooks.tsx
  5. 31
      src/features/AuthServiceApp/components/LanguageSelect/index.tsx
  6. 20
      src/features/AuthServiceApp/components/LanguageSelect/styled.tsx
  7. 3
      src/features/AuthServiceApp/config/clients/types.tsx
  8. 3
      src/features/AuthServiceApp/requests/register.tsx
  9. 4
      src/features/AuthStore/helpers.tsx
  10. 15
      src/features/AuthStore/hooks/useAuth.tsx
  11. 17
      src/features/LexicsStore/hooks/index.tsx
  12. 42
      src/features/LexicsStore/hooks/useLang.tsx
  13. 4
      src/features/LexicsStore/index.tsx
  14. 5
      src/features/StripeElements/index.tsx
  15. 49
      src/features/UserAccount/components/PagePersonalInfo/hooks/index.tsx
  16. 14
      src/features/UserAccount/components/PersonalInfoForm/config.tsx
  17. 35
      src/features/UserAccount/components/PersonalInfoForm/hooks/useUserInfo.tsx
  18. 2
      src/features/UserAccount/components/PersonalInfoForm/index.tsx
  19. 26
      src/helpers/getSortedLangs/index.tsx
  20. 21
      src/helpers/isSupportedLang/__tests__/index.tsx
  21. 10
      src/helpers/isSupportedLang/index.tsx
  22. 7
      src/helpers/languageUrlParam/index.tsx
  23. 35
      src/requests/getLanguages.tsx
  24. 6
      src/requests/getUserInfo.tsx
  25. 3
      src/requests/saveUserInfo.tsx

@ -1,7 +1,5 @@
import { css } from 'styled-components/macro' import { css } from 'styled-components/macro'
import type { Languages } from 'config/languages'
type ProcedureName = string type ProcedureName = string
type RequestParameters = any type RequestParameters = any
type StyledCss = ReturnType<typeof css> type StyledCss = ReturnType<typeof css>
@ -23,7 +21,7 @@ export type ClientConfig = {
clientId: ClientIds, clientId: ClientIds,
metaDataUrlParams?: string, metaDataUrlParams?: string,
}, },
defaultLanguage?: Languages, defaultLanguage: string,
description: string, description: string,
disabledPreferences?: boolean, disabledPreferences?: boolean,
name: ClientNames, name: ClientNames,

@ -1,90 +0,0 @@
import map from 'lodash/map'
import { getSortedLangs } from 'helpers/getSortedLangs'
export const langs = [
{
className: 'ru',
locale: 'ru',
title: 'Русский',
},
{
className: 'gb',
locale: 'en',
title: 'English',
},
{
className: 'cz',
locale: 'cs',
title: 'Čeština',
},
{
className: 'pl',
locale: 'pl',
title: 'Polska',
},
{
className: 'ua',
locale: 'uk',
title: 'Українська',
},
{
className: 'fr',
locale: 'fr',
title: 'Français',
},
{
className: 'de',
locale: 'de',
title: 'Deutsch',
},
{
className: 'nl',
locale: 'nl',
title: 'Dutch',
},
{
className: 'es',
locale: 'es',
title: 'Español',
},
{
className: 'pt',
locale: 'pt',
title: 'Português',
},
{
className: 'it',
locale: 'it',
title: 'Italiano',
},
{
className: 'zh',
locale: 'zh',
title: '中文',
},
{
className: 'bg',
locale: 'bg',
title: 'Български',
},
{
className: 'lv',
locale: 'lv',
title: 'latviešu',
},
] as const
export const getLangsOrder = () => {
const commonLangsLocaleList = map(langs, (lang) => lang.locale).sort()
const clientLanglocaleIndex = commonLangsLocaleList.findIndex(
(locale) => locale === 'en',
)
commonLangsLocaleList.splice(clientLanglocaleIndex, 1).unshift('en')
return commonLangsLocaleList
}
// @ts-expect-error
export const langsList = getSortedLangs(langs)
export type Languages = typeof langsList[number]['locale']

@ -1,6 +1,7 @@
export const PROCEDURES = { export const PROCEDURES = {
bind_ott_subscription: 'bind_ott_subscription', bind_ott_subscription: 'bind_ott_subscription',
get_cities: 'get_cities', get_cities: 'get_cities',
get_languages: 'get_languages',
get_match_info: 'get_match_info', get_match_info: 'get_match_info',
get_match_subscriptions: 'get_match_subscriptions', get_match_subscriptions: 'get_match_subscriptions',
get_matches: 'get_matches', get_matches: 'get_matches',

@ -2,25 +2,28 @@ import { useMemo } from 'react'
import find from 'lodash/find' import find from 'lodash/find'
import { langsList, Languages } from 'config/languages'
import { useToggle } from 'hooks/useToggle' import { useToggle } from 'hooks/useToggle'
import { useLexicsStore } from 'features/LexicsStore' import { useLexicsStore } from 'features/LexicsStore'
export const useLanguageSelect = () => { export const useLanguageSelect = () => {
const { changeLang, lang } = useLexicsStore() const {
changeLang,
lang,
languageList,
} = useLexicsStore()
const { const {
close, close,
isOpen, isOpen,
open, open,
} = useToggle() } = useToggle()
const handleLangChange = (locale: Languages) => () => { const handleLangChange = (locale: string) => () => {
changeLang(locale) changeLang(locale)
close() close()
} }
const selectedLang = useMemo(() => find(langsList, { locale: lang }), [lang]) const selectedLang = useMemo(() => find(languageList, { iso_639_1: lang }), [lang, languageList])
return { return {
close, close,

@ -1,8 +1,8 @@
import map from 'lodash/map' import map from 'lodash/map'
import { langsList } from 'config/languages'
import { OutsideClick } from 'features/OutsideClick' import { OutsideClick } from 'features/OutsideClick'
import { T9n } from 'features/T9n'
import { useLexicsStore } from 'features/LexicsStore'
import { useLanguageSelect } from './hooks' import { useLanguageSelect } from './hooks'
import { import {
@ -24,6 +24,7 @@ export const LanguageSelect = () => {
open, open,
selectedLang, selectedLang,
} = useLanguageSelect() } = useLanguageSelect()
const { languageList } = useLexicsStore()
return ( return (
<Wrapper> <Wrapper>
@ -34,8 +35,10 @@ export const LanguageSelect = () => {
aria-expanded={isOpen} aria-expanded={isOpen}
onClick={open} onClick={open}
> >
<FlagIcon flag={selectedLang.className} /> <FlagIcon lang_iso={selectedLang.iso_639_1} />
<ButtonTitle>{selectedLang.title}</ButtonTitle> <ButtonTitle>
<T9n t={selectedLang.lexic} />
</ButtonTitle>
</Button> </Button>
)} )}
{isOpen && ( {isOpen && (
@ -44,19 +47,21 @@ export const LanguageSelect = () => {
<LangsList id='langsList'> <LangsList id='langsList'>
{ {
map( map(
langsList, languageList,
({ ({
className, id,
locale, iso_639_1,
title, lexic,
}) => ( }) => (
<LangsItem <LangsItem
key={locale} key={id}
selected={selectedLang?.locale === locale} selected={selectedLang?.iso_639_1 === iso_639_1}
onClick={handleLangChange(locale)} onClick={handleLangChange(iso_639_1)}
> >
<FlagIcon flag={className} /> <FlagIcon lang_iso={iso_639_1} />
<LangName>{title}</LangName> <LangName>
<T9n t={lexic} />
</LangName>
</LangsItem> </LangsItem>
), ),
) )

@ -1,6 +1,5 @@
import styled, { css } from 'styled-components/macro' import styled, { css } from 'styled-components/macro'
import { langsList } from 'config/languages'
import { customScrollbar } from 'features/Common/customScrollbar' import { customScrollbar } from 'features/Common/customScrollbar'
export const Wrapper = styled.div` export const Wrapper = styled.div`
@ -108,36 +107,37 @@ export const LangName = styled.span`
padding-left: 10px; padding-left: 10px;
` `
type LanguageFlags = typeof langsList[number]['className']
type Position = { type Position = {
col: number, col: number,
row: number, row: number,
} }
const flagPositions: Record<LanguageFlags, Position> = { const flagPositions: Record<string, Position> = {
bg: { col: 10, row: 1 }, bg: { col: 10, row: 1 },
cz: { col: 1, row: 3 }, cs: { col: 1, row: 3 },
de: { col: 5, row: 4 }, de: { col: 5, row: 4 },
en: { col: 4, row: 12 },
es: { col: 12, row: 10 }, es: { col: 12, row: 10 },
fr: { col: 1, row: 4 }, fr: { col: 1, row: 4 },
gb: { col: 4, row: 12 }, hu: { col: 0, row: 5 },
it: { col: 8, row: 5 }, it: { col: 8, row: 5 },
ja: { col: 6, row: 2 },
lv: { col: 6, row: 6 }, lv: { col: 6, row: 6 },
nl: { col: 5, row: 8 }, nl: { col: 5, row: 8 },
pl: { col: 4, row: 9 }, pl: { col: 4, row: 9 },
pt: { col: 5, row: 9 }, pt: { col: 5, row: 9 },
ru: { col: 8, row: 9 }, ru: { col: 8, row: 9 },
ua: { col: 2, row: 12 }, uk: { col: 2, row: 12 },
zh: { col: 6, row: 2 }, zh: { col: 6, row: 2 },
} }
const getFlagPosition = (flag: LanguageFlags) => { const getFlagPosition = (lang_iso: string) => {
const { col, row } = flagPositions[flag] const { col, row } = flagPositions[lang_iso] || { col: 99, row: 99 }
return `${col * -24}px ${row * -16}px` return `${col * -24}px ${row * -16}px`
} }
type FlagIconProps = { type FlagIconProps = {
flag: LanguageFlags, lang_iso: string,
} }
export const FlagIcon = styled.span<FlagIconProps>` export const FlagIcon = styled.span<FlagIconProps>`
@ -147,5 +147,5 @@ export const FlagIcon = styled.span<FlagIconProps>`
background-image: url('/images/flags-sprite.png'); background-image: url('/images/flags-sprite.png');
background-repeat: no-repeat; background-repeat: no-repeat;
background-size: 360px; background-size: 360px;
background-position: ${({ flag }) => getFlagPosition(flag)}; background-position: ${({ lang_iso }) => getFlagPosition(lang_iso)};
` `

@ -1,7 +1,6 @@
import type { ReactNode, FC } from 'react' import type { ReactNode, FC } from 'react'
import { css } from 'styled-components/macro' import { css } from 'styled-components/macro'
import type { Languages } from 'config/languages'
import { ClientIds, ClientNames } from 'config/clients/types' import { ClientIds, ClientNames } from 'config/clients/types'
type StyledCss = ReturnType<typeof css> type StyledCss = ReturnType<typeof css>
@ -11,7 +10,7 @@ export type ClientConfig = {
clientId: ClientIds, clientId: ClientIds,
}, },
background: FC<{ children: ReactNode }>, background: FC<{ children: ReactNode }>,
defaultLanguage?: Languages, defaultLanguage: string,
description: string, description: string,
name: ClientNames, name: ClientNames,
privacyLink: string, privacyLink: string,

@ -1,5 +1,4 @@
import type { ClientIds } from 'config/clients/types' import type { ClientIds } from 'config/clients/types'
import type { Languages } from 'config/languages'
import { getApiUrl } from 'features/AuthServiceApp/config/routes' import { getApiUrl } from 'features/AuthServiceApp/config/routes'
@ -26,7 +25,7 @@ type SuccessResponse = {
export type UrlParams = { export type UrlParams = {
client_id: ClientIds, client_id: ClientIds,
lang?: Languages, lang?: string,
nonce?: string, nonce?: string,
redirect_uri: string, redirect_uri: string,
response_mode: string, response_mode: string,

@ -6,11 +6,9 @@ import { AUTH_SERVICE } from 'config/routes'
import { ClientIds, ClientNames } from 'config/clients/types' import { ClientIds, ClientNames } from 'config/clients/types'
import { ENV, stageENV } from 'config/env' import { ENV, stageENV } from 'config/env'
import type { Languages } from 'config/languages'
interface Settings extends UserManagerSettings { interface Settings extends UserManagerSettings {
client_id: ClientIds, client_id: ClientIds,
lang?: Languages, lang?: string,
nonce?: string, nonce?: string,
redirect_uri: string, redirect_uri: string,
response_mode: string, response_mode: string,

@ -27,10 +27,12 @@ import {
queryParamStorage, queryParamStorage,
} from 'features/QueryParamsStorage' } from 'features/QueryParamsStorage'
import { getUserInfo } from 'requests'
import { getClientSettings } from '../helpers' import { getClientSettings } from '../helpers'
export const useAuth = () => { export const useAuth = () => {
const { lang } = useLexicsStore() const { changeLang, lang } = useLexicsStore()
const history = useHistory() const history = useHistory()
const { const {
close: markUserLoaded, close: markUserLoaded,
@ -163,6 +165,17 @@ export const useAuth = () => {
return () => userManager.events.removeUserLoaded(storeUser) return () => userManager.events.removeUserLoaded(storeUser)
}, [userManager, storeUser]) }, [userManager, storeUser])
const fetchUserInfo = useCallback(async () => {
const userInfoFetched = await getUserInfo()
userInfoFetched.language.iso && changeLang(userInfoFetched.language.iso)
}, [changeLang])
useEffect(() => {
if (user) {
fetchUserInfo()
}
}, [fetchUserInfo, user])
const auth = useMemo(() => ({ const auth = useMemo(() => ({
loadingUser, loadingUser,
login, login,

@ -4,8 +4,6 @@ import isEmpty from 'lodash/isEmpty'
import { getLexics } from 'requests' import { getLexics } from 'requests'
import type { Languages } from 'config/languages'
import { import {
getLexicIds, getLexicIds,
mapTranslationsToLocalKeys, mapTranslationsToLocalKeys,
@ -16,8 +14,13 @@ import { useLang } from './useLang'
import { useLexicsConfig } from './useLexicsConfig' import { useLexicsConfig } from './useLexicsConfig'
import { useTranslations } from './useTranslations' import { useTranslations } from './useTranslations'
export const useLexics = (initialLanguage?: Languages) => { export const useLexics = (initialLanguage?: string) => {
const { changeLang, lang } = useLang(initialLanguage) const {
changeLang,
lang,
languageLexics,
languageList,
} = useLang(initialLanguage)
const { addLexicsConfig, lexicsConfig } = useLexicsConfig() const { addLexicsConfig, lexicsConfig } = useLexicsConfig()
const { addTranslations, translate } = useTranslations() const { addTranslations, translate } = useTranslations()
@ -36,10 +39,15 @@ export const useLexics = (initialLanguage?: Languages) => {
], ],
) )
useEffect(() => {
addLexicsConfig(languageLexics)
}, [addLexicsConfig, languageLexics])
useEffect(() => { useEffect(() => {
fetchLexics() fetchLexics()
}, [ }, [
lang, lang,
languageList,
lexicsConfig, lexicsConfig,
fetchLexics, fetchLexics,
]) ])
@ -48,6 +56,7 @@ export const useLexics = (initialLanguage?: Languages) => {
addLexicsConfig, addLexicsConfig,
changeLang, changeLang,
lang, lang,
languageList,
suffix: getSuffix(lang), suffix: getSuffix(lang),
translate, translate,
} as const } as const

@ -1,30 +1,56 @@
import { useCallback } from 'react' import {
useCallback,
useEffect,
useState,
} from 'react'
import filter from 'lodash/filter'
import isNull from 'lodash/isNull'
import map from 'lodash/map'
import { useLocalStore } from 'hooks' import { useLocalStore } from 'hooks'
import type { Languages } from 'config/languages'
import { client } from 'config/clients' import { client } from 'config/clients'
import { isSupportedLang } from 'helpers/isSupportedLang' import { getLanguages, ReferenceLanguages } from 'requests/getLanguages'
import { getSortedLangs } from 'helpers/getSortedLangs'
const LANG_KEY = 'lang' const LANG_KEY = 'lang'
const DEFAULT_LANG = client.defaultLanguage || 'en' const DEFAULT_LANG = client.defaultLanguage || 'en'
export const useLang = (initialLanguage?: Languages) => { export const useLang = (initialLanguage?: string) => {
const [lang, setLang] = useLocalStore<Languages>({ const [lang, setLang] = useLocalStore<string>({
defaultValue: DEFAULT_LANG, defaultValue: DEFAULT_LANG,
initialValue: initialLanguage, initialValue: initialLanguage,
key: LANG_KEY, key: LANG_KEY,
validator: isSupportedLang,
}) })
const [languageList, setLanguageList] = useState<ReferenceLanguages>([])
const [languageLexics, setLanguageLexics] = useState<Array<number>>([])
const fetchLanguages = useCallback(async () => {
const languages = await getLanguages()
const langsWithLexic = filter(languages, (language) => !isNull(language.lexic))
const sortedLangs = getSortedLangs(langsWithLexic)
setLanguageList(sortedLangs)
setLanguageLexics(map(langsWithLexic, ({ lexic }) => lexic))
}, [])
useEffect(() => {
fetchLanguages()
}, [fetchLanguages])
const changeLang = useCallback( const changeLang = useCallback(
(newLang: Languages) => { (newLang: string) => {
if (newLang === lang) return if (newLang === lang) return
setLang(newLang) setLang(newLang)
}, },
[lang, setLang], [lang, setLang],
) )
return { changeLang, lang } return {
changeLang,
lang,
languageLexics,
languageList,
}
} }

@ -5,15 +5,13 @@ import {
useEffect, useEffect,
} from 'react' } from 'react'
import type { Languages } from 'config/languages'
import type { LexicsConfig, LexicsId } from './types' import type { LexicsConfig, LexicsId } from './types'
import { useLexics } from './hooks' import { useLexics } from './hooks'
type Context = ReturnType<typeof useLexics> type Context = ReturnType<typeof useLexics>
type Props = { type Props = {
children: ReactNode, children: ReactNode,
initialLanguage?: Languages, initialLanguage?: string,
} }
const LexicsContext = createContext({} as Context) const LexicsContext = createContext({} as Context)

@ -1,7 +1,7 @@
import type { ReactNode } from 'react' import type { ReactNode } from 'react'
import { Elements } from '@stripe/react-stripe-js' import { Elements } from '@stripe/react-stripe-js'
import { loadStripe } from '@stripe/stripe-js' import { loadStripe, StripeElementLocale } from '@stripe/stripe-js'
import { STRIPE_PUBLIC_KEY } from 'config/env' import { STRIPE_PUBLIC_KEY } from 'config/env'
@ -20,8 +20,7 @@ export const StripeElements = ({ children }: Props) => {
<Elements <Elements
key={lang} key={lang}
stripe={stripe} stripe={stripe}
// @ts-expect-error options={{ locale: lang as StripeElementLocale }}
options={{ locale: lang }}
> >
{children} {children}
</Elements> </Elements>

@ -1,5 +1,4 @@
import { import {
useMemo,
useState, useState,
useEffect, useEffect,
useCallback, useCallback,
@ -12,7 +11,6 @@ import isNumber from 'lodash/isNumber'
import isString from 'lodash/isString' import isString from 'lodash/isString'
import isObject from 'lodash/isObject' import isObject from 'lodash/isObject'
import type { Languages } from 'config/languages'
import { formIds } from 'config/form' import { formIds } from 'config/form'
import type { UserInfo, SaveUserInfo } from 'requests' import type { UserInfo, SaveUserInfo } from 'requests'
@ -25,11 +23,7 @@ import {
import type { FormState } from 'features/FormStore/hooks/useFormState' import type { FormState } from 'features/FormStore/hooks/useFormState'
import { useLexicsStore } from 'features/LexicsStore' import { useLexicsStore } from 'features/LexicsStore'
export type SaveWithLang = SaveUserInfo & { const transformToFormState = async (userInfo: UserInfo, lang: string) => {
language?: string | null,
}
const transformToFormState = async (userInfo: UserInfo) => {
const cities = userInfo.country?.id const cities = userInfo.country?.id
? await getCountryCities('', userInfo.country.id) ? await getCountryCities('', userInfo.country.id)
: [] : []
@ -49,6 +43,8 @@ const transformToFormState = async (userInfo: UserInfo) => {
const formValue = { value: String(value.id) } const formValue = { value: String(value.id) }
acc[formIds.initialCountryId] = formValue acc[formIds.initialCountryId] = formValue
acc[formIds.countryId] = formValue acc[formIds.countryId] = formValue
} else if (key === formIds.language && isObject(value)) {
acc[formIds.language] = { value: userInfo.language?.iso ?? lang }
} else if (isNumber(value) || isString(value)) { } else if (isNumber(value) || isString(value)) {
acc[key] = { value: String(value) } acc[key] = { value: String(value) }
} else if (isNull(value)) { } else if (isNull(value)) {
@ -61,40 +57,43 @@ const transformToFormState = async (userInfo: UserInfo) => {
} }
export const useUserInfo = () => { export const useUserInfo = () => {
const { changeLang, lang } = useLexicsStore() const {
const [userInfo, setUserInfo] = useState<FormState>() changeLang,
lang,
languageList,
} = useLexicsStore()
const [userInfo, setUserInfo] = useState<FormState | null>(null)
const [loader, setLoader] = useState<boolean>(false) const [loader, setLoader] = useState<boolean>(false)
const fetchUserInfo = useCallback(() => { const fetchUserInfo = useCallback(async () => {
getUserInfo() const userInfoFetched = await getUserInfo()
.then(transformToFormState) const userInfoFormState = await transformToFormState(userInfoFetched, lang)
.then(setUserInfo) setUserInfo(userInfoFormState)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []) }, [])
const onSubmit = useCallback((data: SaveWithLang) => { const onSubmit = useCallback((data: SaveUserInfo) => {
setLoader(true) setLoader(true)
saveUserInfo(data).then(() => { saveUserInfo(data).then(() => {
fetchUserInfo() fetchUserInfo()
if (data.language) {
changeLang(data.language as Languages) const lang_iso = find(languageList,
(language) => language.id === data.language_id)?.iso_639_1
if (lang_iso) {
changeLang(lang_iso)
} }
}).finally(() => setLoader(false)) }).finally(() => setLoader(false))
}, [fetchUserInfo, changeLang]) // eslint-disable-next-line react-hooks/exhaustive-deps
}, [fetchUserInfo])
useEffect(() => { useEffect(() => {
fetchUserInfo() fetchUserInfo()
}, [fetchUserInfo]) }, [fetchUserInfo])
const user = useMemo(() => (userInfo
? {
...userInfo,
[formIds.language]: { value: lang },
}
: null), [userInfo, lang])
return { return {
loader, loader,
onSubmit, onSubmit,
userInfo: user, userInfo,
} }
} }

@ -1,14 +0,0 @@
import map from 'lodash/map'
import type { Languages } from 'config/languages'
import { langsList } from 'config/languages'
export type Lang = {
id: Languages,
name: string,
}
export const langOptions = map(langsList, (lang) => ({
id: lang.locale,
name: lang.title,
}))

@ -2,23 +2,30 @@ import { useCallback, useMemo } from 'react'
import trim from 'lodash/trim' import trim from 'lodash/trim'
import find from 'lodash/find' import find from 'lodash/find'
import map from 'lodash/map'
import type { Languages } from 'config/languages'
import { formIds } from 'config/form' import { formIds } from 'config/form'
import { useForm } from 'features/FormStore' import { useForm } from 'features/FormStore'
import { useLexicsStore } from 'features/LexicsStore'
import { SaveUserInfo } from 'requests'
import { useUserInfoForm } from './useUserInfoForm' import { useUserInfoForm } from './useUserInfoForm'
import { useValidateForm } from './useValidateForm' import { useValidateForm } from './useValidateForm'
import { Lang, langOptions } from '../config'
import type { SaveWithLang } from '../../PagePersonalInfo/hooks' export type Lang = {
id: string,
name: string,
}
export type Props = { export type Props = {
loader?: boolean, loader?: boolean,
onSubmit: (data: SaveWithLang) => void, onSubmit: (data: SaveUserInfo) => void,
} }
export const useUserInfo = ({ loader, onSubmit }: Props) => { export const useUserInfo = ({ loader, onSubmit }: Props) => {
const { languageList, translate } = useLexicsStore()
const { const {
hasChanges, hasChanges,
readFormError, readFormError,
@ -42,7 +49,10 @@ export const useUserInfo = ({ loader, onSubmit }: Props) => {
if (validateForm()) { if (validateForm()) {
const firstname = readTrimmedValue(formIds.firstname) const firstname = readTrimmedValue(formIds.firstname)
const lastname = readTrimmedValue(formIds.lastname) const lastname = readTrimmedValue(formIds.lastname)
const language = readTrimmedValue(formIds.language) const language_id = find(
languageList,
(language) => language.iso_639_1 === readTrimmedValue(formIds.language),
)?.id ?? null
const phone = readTrimmedValue(formIds.phone) const phone = readTrimmedValue(formIds.phone)
const postalCode = readNumberValue(formIds.postalCode) const postalCode = readNumberValue(formIds.postalCode)
const region = readTrimmedValue(formIds.region) const region = readTrimmedValue(formIds.region)
@ -58,7 +68,7 @@ export const useUserInfo = ({ loader, onSubmit }: Props) => {
cityId, cityId,
countryId, countryId,
firstname, firstname,
language, language_id,
lastname, lastname,
phone, phone,
postalCode, postalCode,
@ -68,15 +78,21 @@ export const useUserInfo = ({ loader, onSubmit }: Props) => {
}, [ }, [
onSubmit, onSubmit,
readTrimmedValue, readTrimmedValue,
languageList,
readNumberValue, readNumberValue,
validateForm, validateForm,
]) ])
const lang = readFormValue(formIds.language) as Languages const lang = readFormValue(formIds.language)
const langOptions = useMemo(() => map(languageList, (language) => ({
id: language.iso_639_1,
name: translate(language.lexic).trim(),
})), [languageList, translate])
const selectedlangOption = useMemo( const selectedlangOption = useMemo(
() => find(langOptions, { id: lang })?.name || '', () => find(langOptions, { id: lang })?.name ?? lang,
[lang], [lang, langOptions],
) )
const onLangSelect = (selectedLang: Lang | null) => { const onLangSelect = (selectedLang: Lang | null) => {
@ -89,6 +105,7 @@ export const useUserInfo = ({ loader, onSubmit }: Props) => {
handleSubmit, handleSubmit,
hasChanges, hasChanges,
lang: selectedlangOption, lang: selectedlangOption,
langOptions,
loader, loader,
onLangSelect, onLangSelect,
onPhoneBlur, onPhoneBlur,

@ -11,7 +11,6 @@ import { ArrowLoader } from 'features/ArrowLoader'
import type { Props } from './hooks/useUserInfo' import type { Props } from './hooks/useUserInfo'
import { useUserInfo } from './hooks/useUserInfo' import { useUserInfo } from './hooks/useUserInfo'
import { langOptions } from './config'
import { SolidButton } from '../../styled' import { SolidButton } from '../../styled'
import { import {
Form, Form,
@ -35,6 +34,7 @@ export const PersonalInfoForm = (props: Props) => {
handleSubmit, handleSubmit,
hasChanges, hasChanges,
lang, lang,
langOptions,
loader, loader,
onLangSelect, onLangSelect,
onPhoneBlur, onPhoneBlur,

@ -1,19 +1,11 @@
import { getLangsOrder } from 'config/languages' import sortBy from 'lodash/sortBy'
import { ReferenceLanguages } from 'requests/getLanguages'
type TLang = { export const getSortedLangs = (langs: ReferenceLanguages): ReferenceLanguages => {
className: string, const languagesSorted = sortBy(langs, ['name_en'])
locale: string, const engLocaleIndex = languagesSorted.findIndex((language) => language.iso_639_1 === 'en')
title: string, const engLanguage = languagesSorted[engLocaleIndex]
} languagesSorted.splice(engLocaleIndex, 1)
languagesSorted.unshift(engLanguage)
const getOrder = (locale: string) => { return languagesSorted
const langsOrder = getLangsOrder()
return langsOrder.findIndex((item) => item === locale)
}
export const getSortedLangs = (langs: Array<TLang>): Array<TLang> => {
langs.sort((lang1, lang2) => (
getOrder(lang1.locale) - getOrder(lang2.locale)
))
return langs
} }

@ -1,21 +0,0 @@
import { isSupportedLang } from '..'
it('returns true for supported languages', () => {
expect(isSupportedLang('ru')).toBe(true)
expect(isSupportedLang('en')).toBe(true)
expect(isSupportedLang('cs')).toBe(true)
expect(isSupportedLang('lv')).toBe(true)
expect(isSupportedLang('uk')).toBe(true)
expect(isSupportedLang('fr')).toBe(true)
expect(isSupportedLang('de')).toBe(true)
expect(isSupportedLang('es')).toBe(true)
expect(isSupportedLang('pt')).toBe(true)
expect(isSupportedLang('it')).toBe(true)
expect(isSupportedLang('pl')).toBe(true)
})
it('returns false for not supported languages', () => {
expect(isSupportedLang('ja')).toBe(false)
expect(isSupportedLang('ro')).toBe(false)
expect(isSupportedLang('tr')).toBe(false)
})

@ -1,10 +0,0 @@
import map from 'lodash/map'
import includes from 'lodash/includes'
import type { Languages } from 'config/languages'
import { langsList } from 'config/languages'
export const isSupportedLang = (lang: string): lang is Languages => {
const supportedLangs = map(langsList, ({ locale }) => locale)
return includes(supportedLangs, lang)
}

@ -1,16 +1,13 @@
import type { Languages } from 'config/languages'
import { history } from 'config/history' import { history } from 'config/history'
import { isSupportedLang } from 'helpers/isSupportedLang'
const KEY = 'lang' const KEY = 'lang'
export const getLanguageUrlParam = () => { export const getLanguageUrlParam = () => {
const lang = new URLSearchParams(history.location.search).get(KEY) const lang = new URLSearchParams(history.location.search).get(KEY)
return lang && isSupportedLang(lang) ? lang : undefined return lang || undefined
} }
export const addLanguageUrlParam = (lang: Languages, url: string) => { export const addLanguageUrlParam = (lang: string, url: string) => {
const urlObject = new URL(url) const urlObject = new URL(url)
urlObject.searchParams.set(KEY, lang) urlObject.searchParams.set(KEY, lang)
return urlObject.toString() return urlObject.toString()

@ -0,0 +1,35 @@
import {
DATA_URL,
PROCEDURES,
} from 'config'
import { callApi } from 'helpers'
const proc = PROCEDURES.get_languages
export type ReferenceLanguage = {
id: number,
iso_639_1: string,
lexic: number,
name_en: string,
name_ru: string,
short_name: string,
ts: number,
}
export type ReferenceLanguages = Array<ReferenceLanguage>
export const getLanguages = async (): Promise<ReferenceLanguages> => {
const config = {
body: {
params: {},
proc,
},
}
const response = await callApi({
config,
url: DATA_URL,
})
return response
}

@ -17,6 +17,12 @@ export type UserInfo = {
name_rus: string, name_rus: string,
}, },
firstname: string | null, firstname: string | null,
language: {
id: number | null,
iso: string | null,
name_en: string | null,
name_ru: string | null,
},
lastname: string | null, lastname: string | null,
password: string | null, password: string | null,
phone: string | null, phone: string | null,

@ -13,6 +13,7 @@ export type SaveUserInfo = {
cityId: number | null, cityId: number | null,
countryId: number | null, countryId: number | null,
firstname: string | null, firstname: string | null,
language_id: number | null,
lastname: string | null, lastname: string | null,
phone: string | null, phone: string | null,
postalCode: number | null, postalCode: number | null,
@ -36,6 +37,7 @@ export const saveUserInfo = async ({
cityId, cityId,
countryId, countryId,
firstname, firstname,
language_id,
lastname, lastname,
phone, phone,
postalCode, postalCode,
@ -50,6 +52,7 @@ export const saveUserInfo = async ({
_p_city_id: cityId, _p_city_id: cityId,
_p_country_id: countryId, _p_country_id: countryId,
_p_firstname: firstname, _p_firstname: firstname,
_p_language_id: language_id,
_p_lastname: lastname, _p_lastname: lastname,
_p_phone: phone, _p_phone: phone,
_p_postal_code: postalCode, _p_postal_code: postalCode,

Loading…
Cancel
Save