diff --git a/.eslintrc b/.eslintrc index 6aeabb19..099cf2e1 100644 --- a/.eslintrc +++ b/.eslintrc @@ -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" } } diff --git a/src/features/HeaderFilters/components/SportTypeFilter/hooks.tsx b/src/features/HeaderFilters/components/SportTypeFilter/hooks.tsx index 9fc75402..5b43980b 100644 --- a/src/features/HeaderFilters/components/SportTypeFilter/hooks.tsx +++ b/src/features/HeaderFilters/components/SportTypeFilter/hooks.tsx @@ -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) => { + e.stopPropagation() + setSelectedSportTypeId(null) + } + const selectedSportType = find(sportList, (sport) => sport.id === selectedSportTypeId) return { close, isOpen, + onResetSelectedSport, onSelect, open, selectedSportType, diff --git a/src/features/HeaderFilters/components/SportTypeFilter/index.tsx b/src/features/HeaderFilters/components/SportTypeFilter/index.tsx index 9c527d73..08c35e36 100644 --- a/src/features/HeaderFilters/components/SportTypeFilter/index.tsx +++ b/src/features/HeaderFilters/components/SportTypeFilter/index.tsx @@ -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 = () => { + {selectedSportType && } diff --git a/src/features/HeaderFilters/components/TournamentFilter/styled.tsx b/src/features/HeaderFilters/components/TournamentFilter/styled.tsx index a7796954..4a8aea9c 100644 --- a/src/features/HeaderFilters/components/TournamentFilter/styled.tsx +++ b/src/features/HeaderFilters/components/TournamentFilter/styled.tsx @@ -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; diff --git a/src/features/LexicsStore/helpers/index.tsx b/src/features/LexicsStore/helpers/index.tsx index 449408b4..bad471da 100644 --- a/src/features/LexicsStore/helpers/index.tsx +++ b/src/features/LexicsStore/helpers/index.tsx @@ -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' ) diff --git a/src/features/LexicsStore/helpers/isSupportedLang/__tests__/index.tsx b/src/features/LexicsStore/helpers/isSupportedLang/__tests__/index.tsx new file mode 100644 index 00000000..9ccb22df --- /dev/null +++ b/src/features/LexicsStore/helpers/isSupportedLang/__tests__/index.tsx @@ -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) +}) diff --git a/src/features/LexicsStore/helpers/isSupportedLang/index.tsx b/src/features/LexicsStore/helpers/isSupportedLang/index.tsx new file mode 100644 index 00000000..062d35a8 --- /dev/null +++ b/src/features/LexicsStore/helpers/isSupportedLang/index.tsx @@ -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) +} diff --git a/src/features/LexicsStore/hooks/useLang.tsx b/src/features/LexicsStore/hooks/useLang.tsx index e9099ec6..97990e4e 100644 --- a/src/features/LexicsStore/hooks/useLang.tsx +++ b/src/features/LexicsStore/hooks/useLang.tsx @@ -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 } diff --git a/src/hooks/useStorage/helpers.tsx b/src/hooks/useStorage/helpers.tsx index 0ca2e99b..fd0e2c6d 100644 --- a/src/hooks/useStorage/helpers.tsx +++ b/src/hooks/useStorage/helpers.tsx @@ -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 } diff --git a/src/hooks/useStorage/index.tsx b/src/hooks/useStorage/index.tsx index e28262c5..b5b0d617 100644 --- a/src/hooks/useStorage/index.tsx +++ b/src/hooks/useStorage/index.tsx @@ -11,13 +11,17 @@ import { readStorageInitialValue, } from './helpers' +const defaultValidator = () => true + type Args = { defaultValue: T, key: string, /** * функция для валидации полученного значения из стора - * если значение не валидно то используется defaultValue + * если значение не валидно то используется defaultValue. + * Если не передан валидатор то полученное значение из стореджа + * считается валидным. */ validator?: (value: T) => boolean, } @@ -32,10 +36,10 @@ const createHook = (storage: Storage) => ( ({ defaultValue, key, - validator, + validator = defaultValidator, }: Args) => { const storeValue = readStorageInitialValue(storage, key) - const isValid = validator && validator(storeValue) + const isValid = validator(storeValue) const initialState = isValid ? storeValue : defaultValue const [state, setState] = useState(initialState)