Ott 143 tournaments dropdown (#62)
parent
7c2495daab
commit
1d5b0d5e5b
@ -0,0 +1,35 @@ |
||||
import map from 'lodash/map' |
||||
|
||||
import type { Tournaments } from 'requests' |
||||
|
||||
import { LOGOS_FALLBACKS } from 'config' |
||||
import { getLogo, SPORT_TYPES } from 'helpers' |
||||
|
||||
type Name = 'name_rus' | 'name_eng' |
||||
type ShortName = 'short_name_rus' | 'short_name_eng' |
||||
|
||||
export const normalizeTournaments = (tournaments: Tournaments, suffix: string) => ( |
||||
map(tournaments, (tournament) => { |
||||
const { c_sport, id } = tournament |
||||
const sportType = SPORT_TYPES[c_sport] |
||||
const name = tournament[`name_${suffix}` as Name] |
||||
const shortName = tournament[`short_name_${suffix}` as ShortName] || name |
||||
const country = tournament.country?.[`name_${suffix}` as Name] |
||||
|
||||
const logo = getLogo({ |
||||
id, |
||||
sportType, |
||||
type: 'tournaments', |
||||
}) |
||||
|
||||
return { |
||||
country, |
||||
fallbackImage: LOGOS_FALLBACKS[sportType].tournaments, |
||||
id, |
||||
logo, |
||||
name, |
||||
shortName, |
||||
sportType, |
||||
} |
||||
}) |
||||
) |
||||
@ -0,0 +1,58 @@ |
||||
import { useEffect, useState } from 'react' |
||||
|
||||
import find from 'lodash/find' |
||||
|
||||
import type { Tournaments } from 'requests' |
||||
import { getSportTournaments } from 'requests' |
||||
|
||||
import { useToggle } from 'hooks' |
||||
|
||||
import { useHeaderFiltersStore } from 'features/HeaderFilters' |
||||
import { useLexicsStore } from 'features/LexicsStore' |
||||
|
||||
import { normalizeTournaments } from './helpers' |
||||
|
||||
const useTournamentsList = () => { |
||||
const { selectedSportType } = useHeaderFiltersStore() |
||||
const [list, setList] = useState<Tournaments>([]) |
||||
|
||||
useEffect(() => { |
||||
setList([]) |
||||
getSportTournaments(selectedSportType).then(setList) |
||||
}, [selectedSportType]) |
||||
|
||||
return list |
||||
} |
||||
|
||||
export const useTournamentFilter = () => { |
||||
const { suffix } = useLexicsStore() |
||||
const { |
||||
selectedTournamentId, |
||||
setSelectedTournamentId, |
||||
} = useHeaderFiltersStore() |
||||
const { |
||||
close, |
||||
isOpen, |
||||
open, |
||||
} = useToggle() |
||||
const tournamentList = useTournamentsList() |
||||
const tournaments = normalizeTournaments(tournamentList, suffix) |
||||
const selectedTournament = find( |
||||
tournaments, |
||||
(tournament) => tournament.id === selectedTournamentId, |
||||
) |
||||
|
||||
const onTournamentSelect = (tournamentId: number) => { |
||||
setSelectedTournamentId(tournamentId) |
||||
close() |
||||
} |
||||
|
||||
return { |
||||
close, |
||||
isOpen, |
||||
onTournamentSelect, |
||||
open, |
||||
selectedTournament, |
||||
tournaments, |
||||
} |
||||
} |
||||
@ -1,5 +1,51 @@ |
||||
import React from 'react' |
||||
|
||||
import { Wrapper } from './styled' |
||||
import { T9n } from 'features/T9n' |
||||
import { OutsideClick } from 'features/OutsideClick' |
||||
|
||||
export const TournamentFilter = () => <Wrapper /> |
||||
import { TournamentList } from '../TournamentList' |
||||
import { useTournamentFilter } from './hooks' |
||||
import { |
||||
Wrapper, |
||||
ListWrapper, |
||||
DropdownButton, |
||||
ButtonTitle, |
||||
Arrows, |
||||
} from './styled' |
||||
|
||||
export const TournamentFilter = () => { |
||||
const { |
||||
close, |
||||
isOpen, |
||||
onTournamentSelect, |
||||
open, |
||||
selectedTournament, |
||||
tournaments, |
||||
} = useTournamentFilter() |
||||
return ( |
||||
<Wrapper> |
||||
<DropdownButton onClick={open} active={isOpen}> |
||||
<ButtonTitle> |
||||
{ |
||||
selectedTournament |
||||
? selectedTournament.shortName |
||||
: <T9n t='tournament' /> |
||||
} |
||||
</ButtonTitle> |
||||
<Arrows active={isOpen} /> |
||||
</DropdownButton> |
||||
{ |
||||
isOpen && ( |
||||
<OutsideClick onClick={close}> |
||||
<ListWrapper> |
||||
<TournamentList |
||||
tournaments={tournaments} |
||||
onSelect={onTournamentSelect} |
||||
/> |
||||
</ListWrapper> |
||||
</OutsideClick> |
||||
) |
||||
} |
||||
</Wrapper> |
||||
) |
||||
} |
||||
|
||||
@ -1,3 +1,84 @@ |
||||
import styled from 'styled-components/macro' |
||||
|
||||
export const Wrapper = styled.div`` |
||||
import { сustomScrollbar } from 'features/Common' |
||||
|
||||
export const Wrapper = styled.div` |
||||
height: 100%; |
||||
width: 50%; |
||||
position: relative; |
||||
` |
||||
|
||||
export const ListWrapper = styled.div` |
||||
position: absolute; |
||||
left: -100%; |
||||
top: calc(100% + 8px); |
||||
width: 448px; |
||||
height: 456px; |
||||
overflow-y: scroll; |
||||
|
||||
${сustomScrollbar} |
||||
` |
||||
|
||||
type Props = { |
||||
active?: boolean, |
||||
} |
||||
|
||||
export const DropdownButton = styled.button<Props>` |
||||
position: relative; |
||||
height: 100%; |
||||
width: 100%; |
||||
outline: none; |
||||
border: none; |
||||
display: flex; |
||||
align-items: center; |
||||
background-color: #3F3F3F; |
||||
font-weight: 600; |
||||
font-size: 18px; |
||||
cursor: pointer; |
||||
border-left: 1px solid #222222; |
||||
border-top-right-radius: 2px; |
||||
border-bottom-right-radius: 2px; |
||||
background-size: 12px 12px; |
||||
background-repeat: no-repeat; |
||||
background-position: 113px; |
||||
|
||||
${({ active }) => ( |
||||
active |
||||
? ` |
||||
background-color: #666666; |
||||
color: #fff; |
||||
` |
||||
: ` |
||||
color: #999999; |
||||
|
||||
:hover { |
||||
background-color: #484848; |
||||
} |
||||
` |
||||
)} |
||||
` |
||||
|
||||
export const ButtonTitle = styled.span` |
||||
display: inline-block; |
||||
width: 80%; |
||||
white-space: nowrap; |
||||
overflow: hidden; |
||||
text-overflow: ellipsis; |
||||
line-height: normal; |
||||
` |
||||
|
||||
export const Arrows = styled.span<Props>` |
||||
position: absolute; |
||||
right: 19px; |
||||
display: inline-block; |
||||
width: 12px; |
||||
height: 12px; |
||||
background-repeat: no-repeat; |
||||
background-position: center; |
||||
|
||||
${({ active }) => ( |
||||
active |
||||
? 'background-image: url(/images/arrowUp.svg);' |
||||
: 'background-image: url(/images/arrowDown.svg);' |
||||
)} |
||||
` |
||||
|
||||
@ -0,0 +1,71 @@ |
||||
import React from 'react' |
||||
|
||||
import map from 'lodash/map' |
||||
|
||||
import { SPORT_COLORS } from 'config' |
||||
import type { SportType } from 'features/Search/config' |
||||
|
||||
import { useItemsList } from 'features/ItemsList/hooks' |
||||
import { |
||||
Logo, |
||||
LogoWrapper, |
||||
ItemInfo, |
||||
Name, |
||||
SportName, |
||||
TeamOrCountry, |
||||
Wrapper, |
||||
} from 'features/ItemsList/styled' |
||||
|
||||
import { ListItem } from './styled' |
||||
|
||||
type Tournament = { |
||||
country?: string, |
||||
fallbackImage: string, |
||||
id: number, |
||||
logo: string, |
||||
name: string, |
||||
sportType: SportType, |
||||
} |
||||
|
||||
type TournamentListProps = { |
||||
onSelect: (id: number) => void, |
||||
tournaments: Array<Tournament>, |
||||
} |
||||
|
||||
export const TournamentList = ({ onSelect, tournaments }: TournamentListProps) => { |
||||
const { |
||||
onError, |
||||
ref, |
||||
} = useItemsList() |
||||
|
||||
return ( |
||||
<Wrapper ref={ref}> |
||||
{map(tournaments, ({ |
||||
country, |
||||
fallbackImage, |
||||
id, |
||||
logo, |
||||
name, |
||||
sportType, |
||||
}) => ( |
||||
<ListItem key={id} onClick={() => onSelect(id)}> |
||||
<LogoWrapper> |
||||
<Logo |
||||
data-src={logo} |
||||
onError={onError(fallbackImage)} |
||||
alt={name} |
||||
/> |
||||
</LogoWrapper> |
||||
<ItemInfo> |
||||
<Name>{name}</Name> |
||||
<SportName |
||||
color={SPORT_COLORS[sportType]} |
||||
t={sportType} |
||||
/> |
||||
<TeamOrCountry>{country}</TeamOrCountry> |
||||
</ItemInfo> |
||||
</ListItem> |
||||
))} |
||||
</Wrapper> |
||||
) |
||||
} |
||||
@ -0,0 +1,22 @@ |
||||
import styled from 'styled-components/macro' |
||||
|
||||
import { Item } from 'features/ItemsList/styled' |
||||
|
||||
export const ListItem = styled(Item)` |
||||
display: flex; |
||||
align-items: center; |
||||
width: 100%; |
||||
height: 56px; |
||||
background-color: #666; |
||||
cursor: pointer; |
||||
|
||||
:focus-within, |
||||
:hover { |
||||
background-color: #999; |
||||
outline: none; |
||||
} |
||||
|
||||
:focus { |
||||
background-color: #999; |
||||
} |
||||
` |
||||
@ -1,14 +0,0 @@ |
||||
type TournamentOption = {} |
||||
|
||||
type Tournaments = { |
||||
options: Array<TournamentOption>, |
||||
selected: TournamentOption | null, |
||||
} |
||||
|
||||
const initialState: Tournaments = { |
||||
options: [], |
||||
selected: null, |
||||
} |
||||
|
||||
// доделаем на таске по турнирам
|
||||
export const useTournaments = () => initialState |
||||
@ -0,0 +1,41 @@ |
||||
import { DATA_URL, PROCEDURES } from 'config' |
||||
import { callApi, getResponseData } from 'helpers' |
||||
import { SportTypes } from 'features/HeaderFilters' |
||||
|
||||
const proc = PROCEDURES.get_tournament_list |
||||
|
||||
type Country = { |
||||
id: number, |
||||
name_eng: string, |
||||
name_rus: string, |
||||
} |
||||
|
||||
export type Tournament = { |
||||
c_gender: number | null, |
||||
c_sport: SportTypes, |
||||
c_tournament_type: number, |
||||
country: Country, |
||||
id: number, |
||||
name_eng: string, |
||||
name_rus: string, |
||||
short_name_eng: string | null, |
||||
short_name_rus: string | null, |
||||
} |
||||
|
||||
export type Tournaments = Array<Tournament> |
||||
|
||||
export const getSportTournaments = (sportId: number): Promise<Tournaments> => { |
||||
const config = { |
||||
body: { |
||||
params: { |
||||
_p_sport: sportId, |
||||
}, |
||||
proc, |
||||
}, |
||||
} |
||||
|
||||
return callApi({ |
||||
config, |
||||
url: DATA_URL, |
||||
}).then(getResponseData(proc)) |
||||
} |
||||
Loading…
Reference in new issue