From e6873a698f04d89a3d7112518fec10778837b921 Mon Sep 17 00:00:00 2001 From: Ruslan Khayrullin Date: Mon, 27 Jul 2020 14:47:40 +0300 Subject: [PATCH] feat(ott-142): sport type filter (#59) --- public/images/arrowUp.svg | 3 + public/images/basketball.svg | 9 +++ public/images/football.svg | 12 ++++ public/images/hockey.svg | 6 ++ src/config/lexics/authenticated.tsx | 5 ++ src/config/lexics/procedures.tsx | 5 ++ src/config/procedures.tsx | 1 + .../Combobox/components/Arrow/index.tsx | 32 ++++++++++ src/features/Combobox/hooks/index.tsx | 8 ++- src/features/Combobox/index.tsx | 17 ++++-- src/features/Combobox/styled.tsx | 20 +----- src/features/Combobox/types.tsx | 12 +++- src/features/Common/customStyles/index.tsx | 11 ++++ src/features/Common/index.tsx | 1 + .../components/SportTypeFilter/hooks.tsx | 45 ++++++++++++++ .../components/SportTypeFilter/index.tsx | 26 +++++++- .../components/SportTypeFilter/styled.tsx | 61 ++++++++++++++++++- .../HeaderFilters/store/hooks/index.tsx | 4 +- src/requests/getSportList.tsx | 24 ++++++++ 19 files changed, 271 insertions(+), 31 deletions(-) create mode 100644 public/images/arrowUp.svg create mode 100644 public/images/basketball.svg create mode 100644 public/images/football.svg create mode 100644 public/images/hockey.svg create mode 100644 src/config/lexics/procedures.tsx create mode 100644 src/features/Combobox/components/Arrow/index.tsx create mode 100644 src/features/Common/customStyles/index.tsx create mode 100644 src/features/HeaderFilters/components/SportTypeFilter/hooks.tsx create mode 100644 src/requests/getSportList.tsx diff --git a/public/images/arrowUp.svg b/public/images/arrowUp.svg new file mode 100644 index 00000000..8cdd1d73 --- /dev/null +++ b/public/images/arrowUp.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/images/basketball.svg b/public/images/basketball.svg new file mode 100644 index 00000000..638ee386 --- /dev/null +++ b/public/images/basketball.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/public/images/football.svg b/public/images/football.svg new file mode 100644 index 00000000..07bc14f9 --- /dev/null +++ b/public/images/football.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/public/images/hockey.svg b/public/images/hockey.svg new file mode 100644 index 00000000..b22763cd --- /dev/null +++ b/public/images/hockey.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/config/lexics/authenticated.tsx b/src/config/lexics/authenticated.tsx index 50ff731e..c9d0a0fc 100644 --- a/src/config/lexics/authenticated.tsx +++ b/src/config/lexics/authenticated.tsx @@ -1,3 +1,5 @@ +import { proceduresLexics } from './procedures' + export const authenticatedLexics = { basketball: 6960, football: 6958, @@ -8,7 +10,10 @@ export const authenticatedLexics = { match_status_live: 12984, match_status_soon: 12986, player: 630, + sport: 12993, team: 658, tournament: 1009, user_account: 12928, + + ...proceduresLexics, } diff --git a/src/config/lexics/procedures.tsx b/src/config/lexics/procedures.tsx new file mode 100644 index 00000000..90314757 --- /dev/null +++ b/src/config/lexics/procedures.tsx @@ -0,0 +1,5 @@ +export const proceduresLexics = { + 3556: 3556, + 6959: 6959, + 12980: 12980, +} diff --git a/src/config/procedures.tsx b/src/config/procedures.tsx index 37b91cb4..5f571f51 100644 --- a/src/config/procedures.tsx +++ b/src/config/procedures.tsx @@ -4,6 +4,7 @@ export const PROCEDURES = { get_cities: 'get_cities', get_matches: 'get_matches', get_players_teams_tournaments: 'get_players_teams_tournaments', + get_sport_list: 'get_sport_list', get_user_favorites: 'get_user_favorites', logout_user: 'logout_user', lst_c_country: 'lst_c_country', diff --git a/src/features/Combobox/components/Arrow/index.tsx b/src/features/Combobox/components/Arrow/index.tsx new file mode 100644 index 00000000..523981a3 --- /dev/null +++ b/src/features/Combobox/components/Arrow/index.tsx @@ -0,0 +1,32 @@ +import React from 'react' + +import styled from 'styled-components/macro' + +import { useComboboxContext } from '@reach/combobox' + +const Wrapper = styled.div<{ isExpanded: boolean }>` + position: absolute; + right: 16px; + top: 50%; + transform: translateY(-50%); + width: 20px; + height: 20px; + background-size: 12px 12px; + background-image: url(/images/${({ isExpanded }) => ( + isExpanded + ? 'arrowUp.svg' + : 'arrowDown.svg' + )}); + background-position: center; + background-repeat: no-repeat; + + :hover { + cursor: pointer; + } +` + +export const Arrow = () => { + const { isExpanded } = useComboboxContext() + + return +} diff --git a/src/features/Combobox/hooks/index.tsx b/src/features/Combobox/hooks/index.tsx index dc3ccd53..84b5cfd8 100644 --- a/src/features/Combobox/hooks/index.tsx +++ b/src/features/Combobox/hooks/index.tsx @@ -29,7 +29,11 @@ const useQuery = ({ onChange, value }: Props) => { } export const useCombobox = (props: Props) => { - const { onSelect, options } = props + const { + filterOptions = true, + onSelect, + options, + } = props const { onQueryChange, @@ -70,7 +74,7 @@ export const useCombobox = (props: Props) => { onInputBlur, onOptionSelect, onQueryChange, - options: results, + options: filterOptions ? results : options, query, } } diff --git a/src/features/Combobox/index.tsx b/src/features/Combobox/index.tsx index b77c6ef6..6ced6ab8 100644 --- a/src/features/Combobox/index.tsx +++ b/src/features/Combobox/index.tsx @@ -19,11 +19,12 @@ import { ComboboxPopoverStyled, ComboboxListStyled, ComboboxOptionStyled, - Arrow, } from './styled' +import { Arrow } from './components/Arrow' export const Combobox = (props: Props) => { const { + customListStyles, disabled, error, id, @@ -32,6 +33,7 @@ export const Combobox = (props: Props) => { labelWidth, openOnFocus, pattern, + placeholder, required, title, withArrow, @@ -74,15 +76,22 @@ export const Combobox = (props: Props) => { onChange={onQueryChange} onBlur={onInputBlur} onKeyDown={onKeyDown} + placeholder={placeholder} /> {!isEmpty(options) && ( - - {map(options, ({ id: optionId, name }) => ( + + {map(options, ({ + children, + id: optionId, + name, + }) => ( + > + {children} + ))} diff --git a/src/features/Combobox/styled.tsx b/src/features/Combobox/styled.tsx index 068f4ab7..2a3614c4 100644 --- a/src/features/Combobox/styled.tsx +++ b/src/features/Combobox/styled.tsx @@ -9,7 +9,7 @@ import { } from '@reach/combobox' import { wrapperStyles, inputStyles } from 'features/Common/Input/styled' -import { сustomScrollbar } from 'features/Common' +import { сustomScrollbar, customStylesMixin } from 'features/Common' export const ComboboxStyled = styled(Combobox)` ${wrapperStyles} @@ -21,23 +21,6 @@ export const ComboboxInputStyled = styled(ComboboxInput)` padding-right: 24px; ` -export const Arrow = styled.div` - position: absolute; - right: 16px; - top: 50%; - transform: translateY(-50%); - width: 20px; - height: 20px; - background-size: 12px 12px; - background-image: url(/images/arrowDown.svg); - background-position: center; - background-repeat: no-repeat; - - :hover { - cursor: pointer; - } -` - export const ComboboxPopoverStyled = styled(ComboboxPopover)` border: none; ` @@ -55,6 +38,7 @@ export const ComboboxListStyled = styled(ComboboxList)` overflow: auto; ${сustomScrollbar} + ${customStylesMixin} ` export const ComboboxOptionStyled = styled(ComboboxOption)` diff --git a/src/features/Combobox/types.tsx b/src/features/Combobox/types.tsx index 9da8f896..92ed4afa 100644 --- a/src/features/Combobox/types.tsx +++ b/src/features/Combobox/types.tsx @@ -1,6 +1,13 @@ -import type { InputHTMLAttributes, ChangeEvent } from 'react' +import type { + InputHTMLAttributes, + ChangeEvent, + ReactNode, +} from 'react' + +import type { TCustomStyles } from 'features/Common' export type Option = { + children?: ReactNode, id: number, name: string, } @@ -12,8 +19,11 @@ export type Props = Pick, ( | 'disabled' | 'pattern' | 'title' + | 'placeholder' )> & { + customListStyles?: TCustomStyles, error?: string | null, + filterOptions?: boolean, label?: string, labelLexic?: string, labelWidth?: number, diff --git a/src/features/Common/customStyles/index.tsx b/src/features/Common/customStyles/index.tsx new file mode 100644 index 00000000..dabacad6 --- /dev/null +++ b/src/features/Common/customStyles/index.tsx @@ -0,0 +1,11 @@ +import { css } from 'styled-components' + +export type TCustomStyles = string | ReturnType + +type TCustomStylesMixin = { + customstyles?: TCustomStyles, +} + +export const customStylesMixin = css` + ${({ customstyles }) => customstyles} +` diff --git a/src/features/Common/index.tsx b/src/features/Common/index.tsx index 623e4fbf..9ed1199f 100644 --- a/src/features/Common/index.tsx +++ b/src/features/Common/index.tsx @@ -4,3 +4,4 @@ export * from './Radio' export * from './Checkbox' export * from './Arrows' export * from './сustomScrollbar' +export * from './customStyles' diff --git a/src/features/HeaderFilters/components/SportTypeFilter/hooks.tsx b/src/features/HeaderFilters/components/SportTypeFilter/hooks.tsx new file mode 100644 index 00000000..e9f804bd --- /dev/null +++ b/src/features/HeaderFilters/components/SportTypeFilter/hooks.tsx @@ -0,0 +1,45 @@ +import React, { useState, useEffect } from 'react' + +import map from 'lodash/map' + +import type { SportList } from 'requests/getSportList' +import type { Option } from 'features/Combobox/types' +import { getSportList } from 'requests/getSportList' +import { useLexicsStore } from 'features/LexicsStore' +import { useHeaderFiltersStore } from 'features/HeaderFilters/store' + +import { CustomOption } from './styled' + +export const useSportTypeFilter = () => { + const [sportList, setSportList] = useState([]) + const { setSelectedSportTypes } = useHeaderFiltersStore() + + const { + translate, + } = useLexicsStore() + + useEffect(() => { + getSportList().then(setSportList) + }, []) + + const options = map(sportList, ({ + id, + lexic, + name, + }) => ({ + children: , + id, + name: translate(String(lexic)), + })) + + const onSelect = (option: Option | null) => { + if (option) { + setSelectedSportTypes(option.id) + } + } + + return { + onSelect, + options, + } +} diff --git a/src/features/HeaderFilters/components/SportTypeFilter/index.tsx b/src/features/HeaderFilters/components/SportTypeFilter/index.tsx index 6feac3bd..a63f2652 100644 --- a/src/features/HeaderFilters/components/SportTypeFilter/index.tsx +++ b/src/features/HeaderFilters/components/SportTypeFilter/index.tsx @@ -1,5 +1,27 @@ import React from 'react' -import { Wrapper } from './styled' +import { Combobox } from 'features/Combobox' -export const SportTypeFilter = () => +import { useLexicsStore } from 'features/LexicsStore' +import { useSportTypeFilter } from './hooks' +import { Wrapper, customListStyles } from './styled' + +export const SportTypeFilter = () => { + const { onSelect, options } = useSportTypeFilter() + const { translate } = useLexicsStore() + + return ( + + + + ) +} diff --git a/src/features/HeaderFilters/components/SportTypeFilter/styled.tsx b/src/features/HeaderFilters/components/SportTypeFilter/styled.tsx index 8646cd0a..d44de38f 100644 --- a/src/features/HeaderFilters/components/SportTypeFilter/styled.tsx +++ b/src/features/HeaderFilters/components/SportTypeFilter/styled.tsx @@ -1,3 +1,60 @@ -import styled from 'styled-components/macro' +import styled, { css } from 'styled-components/macro' -export const Wrapper = styled.div`` +import { + ComboboxStyled, + ComboboxInputStyled, + ComboboxOptionStyled, +} from 'features/Combobox/styled' +import { T9n } from 'features/T9n' + +export const Wrapper = styled.div` + width: 50%; + + ${ComboboxStyled} { + margin-top: 0; + padding-left: 18px; + } + + ${ComboboxInputStyled} { + margin-left: 0; + overflow: hidden; + font-size: 18px; + + &[aria-expanded="true"] { + ::placeholder { + color: #fff; + } + } + + &[aria-expanded="false"] { + ::placeholder { + color: #999; + } + } + } +` + +export const CustomOption = styled(T9n)<{ image: string }>` + display: flex; + align-items: center; + height: 100%; + + ::before { + content: ''; + width: 58px; + height: 100%; + background-image: url(/images/${({ image }) => `${image}.svg`}); + background-position: center; + background-repeat: no-repeat; + } +` + +export const customListStyles = css` + left: -19px; + min-width: 460px; + + ${ComboboxOptionStyled} { + height: 56px; + padding-left: 0; + } +` diff --git a/src/features/HeaderFilters/store/hooks/index.tsx b/src/features/HeaderFilters/store/hooks/index.tsx index fade37cb..ee900041 100644 --- a/src/features/HeaderFilters/store/hooks/index.tsx +++ b/src/features/HeaderFilters/store/hooks/index.tsx @@ -21,8 +21,8 @@ export enum MatchStatuses { export enum SportTypes { Football = 1, - Basketball = 2, - Hockey = 3, + Basketball = 3, + Hockey = 2, } const dateFormat = 'dd/MM/yyyy HH:mm:ss' diff --git a/src/requests/getSportList.tsx b/src/requests/getSportList.tsx new file mode 100644 index 00000000..56d5c30f --- /dev/null +++ b/src/requests/getSportList.tsx @@ -0,0 +1,24 @@ +import { DATA_URL, PROCEDURES } from 'config' +import { callApi, getResponseData } from 'helpers' + +const proc = PROCEDURES.get_sport_list + +export type SportList = Array<{ + id: number, + lexic: number, + name: string, +}> + +export const getSportList = (): Promise => { + const config = { + body: { + params: {}, + proc, + }, + } + + return callApi({ + config, + url: DATA_URL, + }).then(getResponseData(proc)) +}