Ott 318 sport type filter clear btn (#107)

* chore(#318): fixed eslint rules order

* feat(#318): added sport type filter clear button

* fix(#318): fixed useLocalStore hook bug when validator was not specified

* refactor(#318): replaced lang useState to useLocalStore hook

Co-authored-by: mirlan.maksitaliev <mirlan.maksitaliev@instatsport.com>
keep-around/af30b88d367751c9e05a735e4a0467a96238ef47
Mirlan 5 years ago committed by GitHub
parent d7d9266409
commit 9da11400d9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      .eslintrc
  2. 7
      src/features/HeaderFilters/components/SportTypeFilter/hooks.tsx
  3. 3
      src/features/HeaderFilters/components/SportTypeFilter/index.tsx
  4. 7
      src/features/HeaderFilters/components/TournamentFilter/styled.tsx
  5. 15
      src/features/LexicsStore/helpers/index.tsx
  6. 13
      src/features/LexicsStore/helpers/isSupportedLang/__tests__/index.tsx
  7. 9
      src/features/LexicsStore/helpers/isSupportedLang/index.tsx
  8. 18
      src/features/LexicsStore/hooks/useLang.tsx
  9. 6
      src/hooks/useStorage/helpers.tsx
  10. 10
      src/hooks/useStorage/index.tsx

@ -26,6 +26,7 @@
"requireLast": false
}
}],
"@typescript-eslint/semi": ["error", "never"],
"import/extensions": [
"warn",
"never",
@ -87,7 +88,6 @@
"no-unused-vars": "off",
"react/jsx-one-expression-per-line": "off",
"react/jsx-fragments": "off",
"semi": "off",
"@typescript-eslint/semi": ["error", "never"]
"semi": "off"
}
}

@ -1,3 +1,4 @@
import type { MouseEvent } from 'react'
import { useState, useEffect } from 'react'
import find from 'lodash/find'
@ -31,10 +32,16 @@ export const useSportTypeFilter = () => {
close()
}
const onResetSelectedSport = (e: MouseEvent<HTMLButtonElement>) => {
e.stopPropagation()
setSelectedSportTypeId(null)
}
const selectedSportType = find(sportList, (sport) => sport.id === selectedSportTypeId)
return {
close,
isOpen,
onResetSelectedSport,
onSelect,
open,
selectedSportType,

@ -14,6 +14,7 @@ import {
import {
DropdownButton,
ButtonTitle,
ClearButton,
Arrows,
} from '../TournamentFilter/styled'
@ -21,6 +22,7 @@ export const SportTypeFilter = () => {
const {
close,
isOpen,
onResetSelectedSport,
onSelect,
open,
selectedSportType,
@ -38,6 +40,7 @@ export const SportTypeFilter = () => {
<ButtonTitle>
<T9n t={selectedSportType?.lexic || 'sport'} />
</ButtonTitle>
{selectedSportType && <ClearButton onClick={onResetSelectedSport} />}
<Arrows active={isOpen} />
</DropdownButton>

@ -113,11 +113,10 @@ export const Wrapper = styled.div`
}
`
export const ClearButton = styled.button`
outline: none;
border: none;
export const ClearButton = styled.span`
display: inline-block;
cursor: pointer;
width: 10px;
min-width: 10px;
height: 10px;
margin-left: 10px;
background-color: transparent;

@ -8,21 +8,6 @@ import type { Translations } from 'requests'
import type { LexicsId, LexicsConfig } from '../types'
const LANG_KEY = 'lang'
const defaultLang = 'en'
export const writeLang = (lang: string) => {
localStorage.setItem(LANG_KEY, lang)
}
export const readLang = () => {
const lang = localStorage.getItem(LANG_KEY)
if (lang) return lang
writeLang(defaultLang)
return defaultLang
}
export const getSuffix = (lang: string) => (
lang === 'ru' ? 'rus' : 'eng'
)

@ -0,0 +1,13 @@
import { isSupportedLang } from '..'
it('returns true for supported languages', () => {
expect(isSupportedLang('ru')).toBe(true)
expect(isSupportedLang('en')).toBe(true)
})
it('returns false for not supported languages', () => {
expect(isSupportedLang('es')).toBe(false)
expect(isSupportedLang('ja')).toBe(false)
expect(isSupportedLang('fr')).toBe(false)
expect(isSupportedLang('de')).toBe(false)
})

@ -0,0 +1,9 @@
import map from 'lodash/map'
import includes from 'lodash/includes'
import { langsList } from 'features/LanguageSelect/config'
export const isSupportedLang = (lang: string) => {
const supportedLangs = map(langsList, 'locale')
return includes(supportedLangs, lang)
}

@ -1,17 +1,25 @@
import { useState, useCallback } from 'react'
import { useCallback } from 'react'
import { readLang, writeLang } from 'features/LexicsStore/helpers'
import { useLocalStore } from 'hooks'
import { isSupportedLang } from '../helpers/isSupportedLang'
const LANG_KEY = 'lang'
const DEFAULT_LANG = 'en'
export const useLang = () => {
const [lang, setLang] = useState(readLang)
const [lang, setLang] = useLocalStore({
defaultValue: DEFAULT_LANG,
key: LANG_KEY,
validator: isSupportedLang,
})
const changeLang = useCallback(
(newLang: string) => {
if (newLang === lang) return
writeLang(newLang)
setLang(newLang)
},
[lang],
[lang, setLang],
)
return { changeLang, lang }

@ -39,7 +39,11 @@ export const dateReplacer = (key: string, value: string) => {
export const readStorageInitialValue = (storage: Storage, key: string) => {
const rawValue = storage.getItem(key)
if (rawValue) {
return JSON.parse(rawValue, dateReviver)
try {
return JSON.parse(rawValue, dateReviver)
} catch (error) {
return null
}
}
return null
}

@ -11,13 +11,17 @@ import {
readStorageInitialValue,
} from './helpers'
const defaultValidator = () => true
type Args<T> = {
defaultValue: T,
key: string,
/**
* функция для валидации полученного значения из стора
* если значение не валидно то используется defaultValue
* если значение не валидно то используется defaultValue.
* Если не передан валидатор то полученное значение из стореджа
* считается валидным.
*/
validator?: (value: T) => boolean,
}
@ -32,10 +36,10 @@ const createHook = (storage: Storage) => (
<T extends any>({
defaultValue,
key,
validator,
validator = defaultValidator,
}: Args<T>) => {
const storeValue = readStorageInitialValue(storage, key)
const isValid = validator && validator(storeValue)
const isValid = validator(storeValue)
const initialState = isValid ? storeValue : defaultValue
const [state, setState] = useState<T>(initialState)

Loading…
Cancel
Save