Compare commits

...

2 Commits

Author SHA1 Message Date
Andrei Dekterev f1efd86f0f Revert "Revert "fix(ott-2710): minor fixes"" 3 years ago
Andrei Dekterev 9f7ea0fb6c Revert "Revert "feat(#ott-2710): add matches filters"" 3 years ago
  1. 3
      public/images/closeBlack.svg
  2. 3
      public/images/closeWhite.svg
  3. 2
      src/components/SelectFilter/index.tsx
  4. 11
      src/components/SelectFilter/styled.tsx
  5. 12
      src/config/lexics/indexLexics.tsx
  6. 5
      src/features/HeaderFilters/components/DateFilter/hooks/index.tsx
  7. 97
      src/features/HeaderFilters/store/hooks/index.tsx
  8. 288
      src/features/HeaderFilters/store/hooks/useMatchFilters.tsx
  9. 45
      src/features/HeaderMobile/index.tsx
  10. 6
      src/features/HomePage/Atoms/HomePageAtoms.tsx
  11. 41
      src/features/HomePage/components/ClearFiltersPopup/index.tsx
  12. 120
      src/features/HomePage/components/ClearFiltersPopup/styled.tsx
  13. 74
      src/features/HomePage/components/Dropdown/helpers.tsx
  14. 127
      src/features/HomePage/components/Dropdown/index.tsx
  15. 234
      src/features/HomePage/components/Dropdown/styled.tsx
  16. 23
      src/features/HomePage/components/Dropdown/types.tsx
  17. 8
      src/features/HomePage/components/Header/index.tsx
  18. 108
      src/features/HomePage/components/HeaderFilters/index.tsx
  19. 17
      src/features/HomePage/components/HeaderFilters/styled.tsx
  20. 14
      src/features/HomePage/components/MatchesFilters/helpers.tsx
  21. 130
      src/features/HomePage/components/MatchesFilters/index.tsx
  22. 171
      src/features/HomePage/components/MatchesFilters/styled.tsx
  23. 91
      src/features/HomePage/components/MobileMatchesFilters/index.tsx
  24. 80
      src/features/HomePage/components/MobileMatchesFilters/styled.tsx
  25. 27
      src/features/HomePage/hooks.tsx
  26. 4
      src/features/HomePage/index.tsx
  27. 4
      src/features/Matches/helpers/prepareMatches.tsx
  28. 2
      src/features/OutsideClick/index.tsx
  29. 12
      src/features/ProfileHeader/styled.tsx
  30. 4
      src/features/TournamentList/components/CollapseTournament/index.tsx
  31. 3
      src/features/UserFavorites/styled.tsx
  32. 31
      src/requests/getMatches/getHomeMatches.tsx
  33. 14
      src/requests/getMatches/types.tsx

@ -0,0 +1,3 @@
<svg width="10" height="11" viewBox="0 0 10 11" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M2.14144 1.19127C1.87731 0.92713 1.44906 0.92713 1.18492 1.19127C0.920782 1.4554 0.920782 1.88366 1.18492 2.14779L4.53696 5.49984L1.18492 8.85188C0.920782 9.11602 0.920782 9.54427 1.18492 9.8084C1.44906 10.0725 1.87731 10.0725 2.14144 9.8084L5.49349 6.45636L8.84553 9.8084C9.10967 10.0725 9.53792 10.0725 9.80206 9.8084C10.0662 9.54427 10.0662 9.11602 9.80206 8.85188L6.45001 5.49984L9.80206 2.14779C10.0662 1.88366 10.0662 1.4554 9.80206 1.19127C9.53792 0.92713 9.10967 0.92713 8.84553 1.19127L5.49349 4.54331L2.14144 1.19127Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 696 B

@ -0,0 +1,3 @@
<svg width="10" height="10" viewBox="0 0 10 10" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M1.16171 0.691267C0.897571 0.42713 0.46932 0.42713 0.205183 0.691267C-0.0589542 0.955404 -0.0589542 1.38366 0.205183 1.64779L3.55723 4.99984L0.205183 8.35188C-0.0589542 8.61602 -0.0589542 9.04427 0.205183 9.3084C0.46932 9.57254 0.897571 9.57254 1.16171 9.3084L4.51375 5.95636L7.8658 9.3084C8.12993 9.57254 8.55818 9.57254 8.82232 9.3084C9.08646 9.04427 9.08646 8.61602 8.82232 8.35188L5.47028 4.99984L8.82232 1.64779C9.08646 1.38366 9.08646 0.955404 8.82232 0.691267C8.55818 0.42713 8.12993 0.42713 7.8658 0.691267L4.51375 4.04331L1.16171 0.691267Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 717 B

@ -11,7 +11,7 @@ import {
type SportsFilterProps = {
onModalOpen?: () => void,
open: boolean,
selectItem: TournamentType | undefined,
selectItem: TournamentType | null,
withArrow?: boolean,
}

@ -4,20 +4,13 @@ import { isMobileDevice } from 'config/userAgent'
import { Icon } from 'features/Icon'
export const ScSelectFilter = styled.div`
display: flex;
color: white;
font-size: 14px;
width: 30%;
text-transform: uppercase;
font-weight: 700;
align-items: center;
cursor: pointer;
font-size: 18px;
line-height: 22px;
white-space: nowrap;
&:hover {
text-decoration: underline;
}
${isMobileDevice
? css`
letter-spacing: 0.15rem;

@ -110,6 +110,17 @@ const newDevicePopup = {
ok: 724,
}
const matchesFilter = {
arena: 19803,
clear_filters: 4302,
clear_popup_message: 19812,
division: 19806,
gender: 19801,
main_team: 19804,
round: 19805,
youth_age: 19802,
}
export const indexLexics = {
add_to_favorites: 14967,
add_to_favorites_error: 12943,
@ -175,6 +186,7 @@ export const indexLexics = {
watch_from_last_pause: 13022,
watch_now: 13020,
...matchesFilter,
...filterPopup,
...confirmPopup,
...highlightsPageLexic,

@ -24,7 +24,7 @@ export const useDateFilter = () => {
setSelectedDate,
setSelectedFilters,
setSelectedLeague,
setSelectTournament,
setSelectedTournament,
} = useHeaderFiltersStore()
const { lang } = useLexicsStore()
@ -52,10 +52,11 @@ export const useDateFilter = () => {
&& parseFilters.selectedLeague[0] !== 'all_competitions') {
setIsShowTournament(false)
setSelectedLeague(parseFilters.selectedLeague)
setSelectTournament(parseFilters.selectTournament)
setSelectedTournament(parseFilters.selectedTournament)
} else {
setIsShowTournament(true)
setSelectedFilters([])
setSelectedTournament(null)
setSelectedLeague(['all_competitions'])
}
// eslint-disable-next-line react-hooks/exhaustive-deps

@ -13,6 +13,7 @@ import { useQueryParamStore } from 'hooks'
import { filterKeys } from '../config'
import { isValidDate } from '../helpers/isValidDate'
import { useMatchFilters } from './useMatchFilters'
export const useFilters = () => {
const { search } = useLocation()
@ -22,15 +23,41 @@ export const useFilters = () => {
key: filterKeys.DATE,
validator: isValidDate,
})
const [selectedSport, setSelectedSport] = useState(['all_sports'])
const [selectedLeague, setSelectedLeague] = useState<Array<string | number>>(['all_competitions'])
const [selectedFilters, setSelectedFilters] = useState<Array<string>>([])
const [isShowTournament, setIsShowTournament] = useState(true)
const [selectTournament, setSelectTournament] = useState<TournamentType>()
const [selectedTournament, setSelectedTournament] = useState<TournamentType | null>(null)
const [sportIds, setSportIds] = useState<any>()
const isTodaySelected = isToday(selectedDate)
const {
activeFilters,
changeInput,
clearAllFilters,
clearFilters,
clickCancel,
clickClearAll,
closeDropdownList,
confirmClear,
currentFilters,
filtersListName,
filtersSize,
getDropdownList,
handleSetFilters,
inputValue,
isEmptyFilters,
isFiltersShown,
matchesList,
openPopup,
queryParams,
setTournamentMatches,
toggleDropdownList,
} = useMatchFilters({
selectedDate,
selectedTournament,
})
const resetFilters = useCallback(() => {
setIsShowTournament(true)
setSelectedFilters([])
@ -43,9 +70,9 @@ export const useFilters = () => {
useEffect(() => {
localStorage.setItem('filters', JSON.stringify({
selectTournament,
selectedDate: selectedDate.getDate(),
selectedLeague,
selectedTournament,
}))
// eslint-disable-next-line
}, [selectedLeague])
@ -60,41 +87,97 @@ export const useFilters = () => {
search,
])
const handleClickBack = useCallback(() => {
setTournamentMatches([])
clearAllFilters()
setIsShowTournament(true)
setSelectedTournament(null)
setSelectedLeague(['all_competitions'])
}, [
clearAllFilters,
setTournamentMatches,
setIsShowTournament,
setSelectedTournament,
setSelectedLeague,
])
const store = useMemo(() => ({
activeFilters,
changeInput,
clearAllFilters,
clearFilters,
clickCancel,
clickClearAll,
closeDropdownList,
confirmClear,
currentFilters,
filtersListName,
filtersSize,
getDropdownList,
handleClickBack,
handleSetFilters,
inputValue,
isEmptyFilters,
isFiltersShown,
isShowTournament,
isTodaySelected,
matchesList,
openPopup,
queryParams,
resetFilters,
selectTournament,
selectedDate,
selectedFilters,
selectedLeague,
selectedSport,
selectedTournament,
setIsShowTournament,
setSelectTournament,
setSelectedDate,
setSelectedFilters,
setSelectedLeague,
setSelectedSport,
setSelectedTournament,
setSportIds,
sportIds,
toggleDropdownList,
updateDate,
}), [
activeFilters,
changeInput,
clearAllFilters,
clearFilters,
clickCancel,
clickClearAll,
closeDropdownList,
confirmClear,
currentFilters,
filtersListName,
filtersSize,
getDropdownList,
handleClickBack,
handleSetFilters,
inputValue,
isEmptyFilters,
isFiltersShown,
isShowTournament,
isTodaySelected,
matchesList,
openPopup,
queryParams,
resetFilters,
selectedDate,
selectedFilters,
selectedLeague,
selectedSport,
selectTournament,
setSelectTournament,
selectedTournament,
setIsShowTournament,
setSelectedDate,
setSelectedFilters,
setSelectedLeague,
setSelectedSport,
setSelectedTournament,
setSportIds,
sportIds,
toggleDropdownList,
updateDate,
])

@ -0,0 +1,288 @@
import {
useCallback,
useEffect,
useMemo,
useState,
MouseEvent,
ChangeEvent,
} from 'react'
import every from 'lodash/every'
import some from 'lodash/some'
import isNil from 'lodash/isNil'
import includes from 'lodash/includes'
import filter from 'lodash/filter'
import isEmpty from 'lodash/isEmpty'
import reduce from 'lodash/reduce'
import size from 'lodash/size'
import { format } from 'date-fns'
import {
getAge,
getArena,
getDivision,
getGender,
getMainTeam,
getRound,
getSport,
} from 'features/HomePage/components/Dropdown/helpers'
import {
getHomeMatches,
Match,
TQueryParams,
} from 'requests'
import type { TournamentType } from 'requests/getMatches/types'
const MATCHES_LIMIT = 1000
const OFFSET = 0
const getTimezoneOffset = (date: Date) => {
const offset = date.getTimezoneOffset()
if (offset === 0) return offset
return -(offset)
}
const getDate = (date: Date) => format(date, 'yyyy-MM-dd')
export type TActiveFilters = {
[key: string]: Array<number>,
}
export type TDefaultType = {
id: number,
name_eng: string,
name_rus: string,
}
type TUseMatchFilters = {
selectedDate: Date,
selectedTournament: TournamentType | null,
}
const DEFAULT_FILTERS = {}
export const useMatchFilters = ({
selectedDate,
selectedTournament,
}: TUseMatchFilters) => {
const [matchesList, setMatchesList] = useState<Array<Match>>([])
const [tournamentMatches, setTournamentMatches] = useState<Array<Match>>([])
const [filtersListName, setFiltersListName] = useState<string>('')
const [activeFilters, setActiveFilters] = useState<TActiveFilters>(DEFAULT_FILTERS)
const [inputValue, setInputValue] = useState<string>('')
const [openPopup, setOpenPopup] = useState(false)
const toggleDropdownList = (title: string) => () => {
if (title === filtersListName) {
setFiltersListName('')
setInputValue('')
} else {
setFiltersListName(title)
}
}
const closeDropdownList = () => {
setFiltersListName('')
setInputValue('')
}
const clearAllFilters = () => {
setInputValue('')
setActiveFilters(DEFAULT_FILTERS)
}
const fetchMatches = useCallback(
(limit: number, offset: number) => getHomeMatches({
date: getDate(selectedDate),
limit,
offset,
timezoneOffset: getTimezoneOffset(selectedDate),
}),
[selectedDate],
)
useEffect(() => {
clearAllFilters()
setMatchesList([])
setTournamentMatches([])
fetchMatches(MATCHES_LIMIT, OFFSET).then(({ broadcast }) => {
setMatchesList(broadcast)
})
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [selectedDate])
useEffect(() => {
if (selectedTournament) {
setTournamentMatches(
filter(matchesList,
(match) => match.tournament.id === selectedTournament.id),
)
}
}, [
matchesList,
selectedTournament,
])
const matchesForFilters = useMemo(() => (
selectedTournament ? tournamentMatches : matchesList),
[
matchesList,
selectedTournament,
tournamentMatches,
])
const getDropdownList = useCallback((filterName: string, queryString: string) => {
switch (filterName) {
case 'gender':
return getGender(matchesForFilters)
case 'youth_age':
return getAge(matchesForFilters)
case 'division':
return getDivision(matchesForFilters)
case 'main_team':
return getMainTeam(matchesForFilters)
case 'arena':
return getArena(matchesForFilters, queryString)
case 'round':
return getRound(matchesForFilters)
case 'sport':
return getSport(matchesForFilters)
default:
return []
}
}, [matchesForFilters])
const currentFilters = useMemo(() => {
const arr = []
const hasArena = some(matchesForFilters, (item) => !isNil(item.arena?.id))
const hasRound = some(matchesForFilters, (item) => !isNil(item.round?.id))
const hasSport = some(matchesForFilters, (item) => !isNil(item.sport))
const hasMainTeam = some(matchesForFilters,
(item) => !isNil(item.team1?.main_team) || !isNil(item.team2?.main_team))
const hasGender = some(matchesForFilters,
(item) => !isNil(item.team1?.gender) || !isNil(item.team2?.gender))
const hasDivision = some(matchesForFilters,
(item) => !isNil(item.team1?.division?.id) || !isNil(item.team2?.division?.id))
const hasYouthAge = some(matchesForFilters,
(item) => !isNil(item.team1?.youth_age) || !isNil(item.team2?.youth_age))
if (hasSport) arr.push('sport')
if (hasArena) arr.push('arena')
if (hasRound) arr.push('round')
if (hasMainTeam) arr.push('main_team')
if (hasYouthAge) arr.push('youth_age')
if (hasGender) arr.push('gender')
if (hasDivision) arr.push('division')
return filter(arr, (filterName) => (
getDropdownList(filterName, '').length > 1
))
}, [getDropdownList, matchesForFilters])
const handleSetFilters = (filterName: string, value: number) => {
const activeFilter = activeFilters[filterName as keyof typeof activeFilters]
const isFilterPresent = !isNil(activeFilter)
if (isFilterPresent) {
const isValuePresent = includes(activeFilter, value)
const currentValue = isValuePresent
? filter(activeFilter, (item) => item !== value)
: [...activeFilter, value]
return setActiveFilters({
...activeFilters,
[filterName]: currentValue,
})
}
return setActiveFilters({
...activeFilters,
[filterName]: [value],
})
}
const clearFilters = (filterName: string) => (e: MouseEvent | ChangeEvent<HTMLInputElement>) => {
e.stopPropagation()
e.preventDefault()
if (filterName === 'arena') {
setInputValue('')
}
setActiveFilters({
...activeFilters,
[filterName]: [],
})
}
const isEmptyFilters = every(activeFilters, (filterItem) => isEmpty(filterItem))
const queryParams: TQueryParams = useMemo(() => {
const params = {
arena: activeFilters.arena,
division: activeFilters.division,
gender: activeFilters.gender,
main_team: activeFilters.main_team,
round: activeFilters.round,
sport: activeFilters.sport,
youth_age: activeFilters.youth_age,
}
return params
}, [activeFilters])
const changeInput = (e: ChangeEvent<HTMLInputElement>) => {
const { value } = e.target
setInputValue(value)
}
const clickClearAll = () => {
setOpenPopup(true)
}
const confirmClear = (e: MouseEvent) => {
setOpenPopup(false)
clearAllFilters()
}
const clickCancel = () => {
setOpenPopup(false)
}
const filtersSize = reduce(activeFilters,
(
result,
value,
) => result + size(value), 0)
const isFiltersShown = useMemo(() => (
size(matchesList) < 12 || selectedTournament),
[matchesList, selectedTournament])
return {
activeFilters,
changeInput,
clearAllFilters,
clearFilters,
clickCancel,
clickClearAll,
closeDropdownList,
confirmClear,
currentFilters,
filtersListName,
filtersSize,
getDropdownList,
handleSetFilters,
inputValue,
isEmptyFilters,
isFiltersShown,
matchesList,
openPopup,
queryParams,
setTournamentMatches,
toggleDropdownList,
}
}

@ -1,14 +1,11 @@
import { useRecoilValue } from 'recoil'
import { isIOS } from 'config/userAgent'
import { isLffClient } from 'config/clients'
import { isInSportsClient } from 'config/clients'
import { HeaderMenu } from 'features/HeaderMenu'
import { DateFilter } from 'features/HeaderFilters'
import { ScoreSwitch } from 'features/MatchSwitches'
import { SportsFilter } from 'features/SportsFilter'
import { isSportFilterShownAtom } from 'features/HomePage/Atoms/HomePageAtoms'
import { SmartBanner } from 'components/SmartBanner'
import { MobileMatchesFilters } from 'features/HomePage/components/MobileMatchesFilters'
import {
HeaderStyled,
@ -21,26 +18,22 @@ type HeaderBannerProps = {
setIsOpenDownload: (open: boolean) => void,
}
export const HeaderMobile = ({ isOpenDownload, setIsOpenDownload }: HeaderBannerProps) => {
const isSportFilterShown = useRecoilValue(isSportFilterShownAtom)
return (
<>
{
isOpenDownload
export const HeaderMobile = ({ isOpenDownload, setIsOpenDownload }: HeaderBannerProps) => (
<>
{
isOpenDownload
&& !isIOS
&& <SmartBanner setIsOpenDownload={setIsOpenDownload} />
}
<HeaderStyled>
<HeaderMenu />
<DateFilter />
<ScSportsWrapper>
{!isLffClient && isSportFilterShown ? <SportsFilter /> : null}
<ScoreSwitchWrapper>
<ScoreSwitch />
</ScoreSwitchWrapper>
</ScSportsWrapper>
</HeaderStyled>
</>
)
}
}
<HeaderStyled>
<HeaderMenu />
<DateFilter />
<ScSportsWrapper>
{isInSportsClient && <MobileMatchesFilters />}
<ScoreSwitchWrapper>
<ScoreSwitch />
</ScoreSwitchWrapper>
</ScSportsWrapper>
</HeaderStyled>
</>
)

@ -1,6 +0,0 @@
import { atom } from 'recoil'
export const isSportFilterShownAtom = atom({
default: true,
key: 'isSportFilterShownAtom',
})

@ -0,0 +1,41 @@
import { useHeaderFiltersStore } from 'features/HeaderFilters'
import { T9n } from 'features/T9n'
import {
ButtonsContainer,
CancelButton,
ConfirmButton,
Modal,
PopupContainer,
PopupText,
PopupTitle,
} from './styled'
export const ClearFiltersPopup = () => {
const {
clickCancel,
confirmClear,
openPopup,
} = useHeaderFiltersStore()
return (
<Modal isOpen={openPopup} withCloseButton={false}>
<PopupContainer>
<PopupTitle>
<T9n t='clear_filters' />
</PopupTitle>
<PopupText>
<T9n t='clear_popup_message' />
</PopupText>
<ButtonsContainer>
<ConfirmButton onClick={confirmClear}>
<T9n t='clear' />
</ConfirmButton>
<CancelButton onClick={clickCancel}>
<T9n t='still_cancel' />
</CancelButton>
</ButtonsContainer>
</PopupContainer>
</Modal>
)
}

@ -0,0 +1,120 @@
import styled, { css } from 'styled-components/macro'
import { ModalWindow } from 'features/Modal/styled'
import { OutsideClickWrapper } from 'features/OutsideClick'
import {
Modal as BaseModal,
} from 'features/AuthServiceApp/components/RegisterPopup/styled'
import { isMobileDevice } from 'config/userAgent'
export const Modal = styled(BaseModal)`
${OutsideClickWrapper} {
${isMobileDevice
? css`height: 100%;`
: ''}
}
${ModalWindow} {
${isMobileDevice
? css`
min-height: 201px;
max-width: 351px;
padding: 26px 15px 33px 15px;
top: 19vh;
`
: css`
min-height: 220px;
max-width: 611px;
padding: 37px 0 39px 0;
`}
}
`
export const PopupContainer = styled.div`
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-style: normal;
color: #FFFFFF;
${isMobileDevice
? ''
: css`min-width: 611px;`}
`
export const PopupTitle = styled.div`
font-weight: 700;
font-size: 24px;
line-height: 24px;
margin-bottom: 45px;
${isMobileDevice
? css`
font-size: 20px;
line-height: 24px;
margin-bottom: 25px;`
: css`
font-size: 24px;
line-height: 24px;
margin-bottom: 45px;`}
`
export const PopupText = styled.div`
font-weight: 400;
${isMobileDevice
? css`
font-size: 16px;
line-height: 22px;
margin-bottom: 33px;`
: css`
font-size: 20px;
line-height: 28px;
margin-bottom: 55px;`}
`
export const ButtonsContainer = styled.div`
display: flex;
flex-direction: row;
align-items: center;
${isMobileDevice
? css`gap: 15px;`
: css`gap: 20px;`}
`
const Button = styled.button`
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
border-radius: 5px;
color: #FFFF;
font-weight: 600;
${isMobileDevice
? css`
font-size: 16px;
line-height: 16px;
width: 149px;
height: 38px;`
: css`
font-size: 20px;
line-height: 50px;
cursor: pointer;
width: 134px;
height: 50px;`}
`
export const ConfirmButton = styled(Button)`
background: #294FC4;
border: 1px solid #294FC4;
filter: drop-shadow(0px 1px 1px rgba(0, 0, 0, 0.3));
`
export const CancelButton = styled(Button)`
border: 1px solid #FFFFFF;
background: none;
filter: drop-shadow(0px 1px 1px rgba(0, 0, 0, 0.3));
`

@ -0,0 +1,74 @@
import map from 'lodash/map'
import some from 'lodash/some'
import filter from 'lodash/filter'
import uniq from 'lodash/uniq'
import uniqBy from 'lodash/uniqBy'
import flatten from 'lodash/flatten'
import compact from 'lodash/compact'
import includes from 'lodash/includes'
import toLower from 'lodash/toLower'
import { Match } from 'requests'
const checkString = (text: string, searchString: string) => includes(
toLower(text), toLower(searchString),
)
export const getAge = (filterList: Array<Match>) => compact(
uniq(
flatten(
map(
filterList, (item) => [item.team1.youth_age, item.team2.youth_age],
),
),
),
)
export const getDivision = (filterList: Array<Match>) => filter(
flatten(
map(
filterList, (item) => [item.team1.division, item.team2.division],
),
), (item) => item?.id,
)
export const getMainTeam = (filterList: Array<Match>) => filter(
flatten(
map(
filterList, (item) => [item.team1.main_team, item.team2.main_team],
),
), (item) => item?.id,
)
export const getArena = (filterList: Array<Match>, inputValue: string) => filter(
map(
filterList, (item) => item.arena,
), (item) => item?.id
&& (checkString(item.name_eng, inputValue)
|| checkString(item.name_rus, inputValue)),
)
export const getSport = (filterList: Array<Match>) => uniqBy(
filter(
map(
filterList, (item) => item.sport_info,
), (item) => item?.id,
), 'id',
)
export const getRound = (filterList: Array<Match>) => uniqBy(
filter(
map(
filterList, (item) => item.round,
), (item) => item?.id,
), 'id',
)
export const getGender = (filterList: Array<Match>) => {
const list = []
if (some(filterList, (item) => item.team1.gender === 1 || item.team2.gender === 1)) list.push({ id: 1, lexic: 'gender_male_long' })
if (some(filterList, (item) => item.team1.gender === 2 || item.team2.gender === 2)) list.push({ id: 2, lexic: 'gender_female_long' })
return list
}

@ -0,0 +1,127 @@
import { ChangeEvent, MouseEvent } from 'react'
import map from 'lodash/map'
import isEmpty from 'lodash/isEmpty'
import includes from 'lodash/includes'
import isNumber from 'lodash/isNumber'
import { T9n } from 'features/T9n'
import { Name } from 'features/Name'
import { useLexicsStore } from 'features/LexicsStore'
import { useHeaderFiltersStore } from 'features/HeaderFilters'
import { isMobileDevice } from 'config/userAgent'
import {
TDropDownProps,
TFilterItem,
TItem,
} from './types'
import {
DropDownContainer,
FiltersList,
FilterItem,
Checkbox,
CommonButtonsBlock,
ClearButtonContainer,
SearchWithAllContainer,
SearchContainer,
SearchInput,
BackButton,
} from './styled'
import { Title } from '../MatchesFilters/styled'
const Label = ({ item }: TFilterItem) => (
isNumber(item) ? <>U{item}</> : <Name nameObj={item} />
)
export const DropDown = ({
activeFilters,
changeInput,
clearFilters,
closeDropdownList,
filterTitle,
inputValue,
setFilters,
}: TDropDownProps) => {
const { translate } = useLexicsStore()
const { getDropdownList } = useHeaderFiltersStore()
const dropdownList = getDropdownList(filterTitle, inputValue) as Array<TItem | number>
const currentActiveFilter = activeFilters[filterTitle as keyof typeof activeFilters]
return (
<DropDownContainer>
<FiltersList>
<CommonButtonsBlock isArena={filterTitle === 'arena'}>
<SearchWithAllContainer>
{isMobileDevice && closeDropdownList
&& (
<BackButton onClick={closeDropdownList} className='back_button'>
{isMobileDevice && (<Title t={filterTitle} />)}
</BackButton>
)}
{filterTitle === 'arena' && (
<SearchContainer>
<SearchInput
onChange={changeInput}
onClick={(e) => e.stopPropagation()}
placeholder={translate('search')}
value={inputValue}
/>
</SearchContainer>
)}
<Checkbox
onChange={clearFilters(filterTitle)}
checked={isEmpty(currentActiveFilter)}
labelLexic='all'
/>
</SearchWithAllContainer>
{!isEmpty(currentActiveFilter) && (
<ClearButtonContainer
onClick={clearFilters(filterTitle)}
>
<T9n
className='clear_button'
t='clear'
/>
</ClearButtonContainer>
)}
</CommonButtonsBlock>
{map(dropdownList, (filterItem) => {
const filterValue = isNumber(filterItem) ? filterItem : filterItem.id
const handleClick = (e: ChangeEvent | MouseEvent) => {
e.preventDefault()
e.stopPropagation()
setFilters(filterTitle, filterValue)
}
return (
<FilterItem
key={filterValue}
onClick={handleClick}
>
{includes(['gender', 'sport'], filterTitle)
? (
<Checkbox
checked={includes(currentActiveFilter, filterValue)}
onChange={handleClick}
labelLexic={!isNumber(filterItem) ? filterItem.lexic : ''}
/>
)
: (
<Checkbox
checked={includes(currentActiveFilter, filterValue)}
onChange={handleClick}
label={(<Label item={filterItem} />)}
/>
)}
</FilterItem>
)
})}
</FiltersList>
</DropDownContainer>
)
}

@ -0,0 +1,234 @@
import styled, { css } from 'styled-components/macro'
import { customScrollbar } from 'features/Common'
import { Checkbox as BaseCheckbox } from 'features/Common/Checkbox'
import { Label } from 'features/Common/Checkbox/styled'
import { CheckboxSvg } from 'features/Common/Checkbox/Icon'
import { isMobileDevice } from 'config/userAgent'
import { NameStyled } from 'features/Name'
export const DropDownContainer = styled.div`
${isMobileDevice
? css` border-top: 1px solid #505050;`
: css`
position: absolute;
top: 57px;
right: -24px;
background: #333333;
border-radius: 3.5px;
z-index: 10;`}
`
export const FiltersList = styled.ul`
overflow-y: auto;
display: flex;
flex-direction: column;
max-height: 500px;
${isMobileDevice
? css`
@media (orientation: landscape){
max-height: 300px;
}
`
: ''}
${customScrollbar}
`
export const FilterItem = styled.li`
${isMobileDevice
? css`
max-width: 280px;
white-space: nowrap;
padding: 10px 0 10px 13px;
`
: css`
min-width: 286px;
white-space: nowrap;
padding: 15px 26px;`}
:hover {
background: rgba(255, 255, 255, 0.2);
}
`
export const Checkbox = styled(BaseCheckbox)`
display: block;
text-transform: uppercase;
${Label} {
text-transform: uppercase;
font-weight: 700;
${isMobileDevice
? css`
font-size: 10px;
line-height: 11px;`
: css`
font-size: 18px;
line-height: 16px;`}
${NameStyled} {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
${({ checked }) => (checked
? ''
: css`color: rgba(255, 255, 255, 0.6);`)}
}
${CheckboxSvg} {
margin-right: 8px;
flex: 0 0 auto;
${isMobileDevice
? css`
width: 14px;
height: 14px;
`
: css`
width: 20px;
height: 20px;`}
}
`
type TCommonButtonsBlock = {
isArena?: boolean,
}
export const CommonButtonsBlock = styled.div<TCommonButtonsBlock>`
display: flex;
justify-content: space-between;
${({ isArena }) => (isArena
? css`
align-items: flex-start;
padding: ${isMobileDevice ? '8px 25px 10px 13px' : '24px 26px 15px 26px'};
`
: css`
align-items: center;
padding:${isMobileDevice ? '8px 25px 10px 13px' : '15px 26px'};`)}
`
export const ClearButtonContainer = styled.div`
${isMobileDevice
? css`
position: absolute;
top: 14px;
right: 36px;`
: ''}
.clear_button {
${isMobileDevice
? css`
font-size: 10px;
line-height: 12px;`
: css`
font-size: 18px;
line-height: 22px;`}
font-style: normal;
font-weight: 400;
letter-spacing: 0.05em;
text-transform: uppercase;
color: rgba(255, 255, 255, 0.5);
cursor: pointer;
}
`
export const SearchContainer = styled.div`
padding-right: ${isMobileDevice ? '0px' : '20px'};
position: relative;
:before {
content: '';
background: url(/images/search.svg) no-repeat;
position: absolute;
${isMobileDevice
? css`
left: 8px;
top: 7px;
width: 11px;
height: 11px;
`
: css`
left: 13px;
top: 10px;
width: 16px;
height: 16px;`}
z-index: 2;
}
`
export const SearchInput = styled.input`
border: none;
background: transparent;
outline: none;
width: 100%;
background: #292929;
border-radius: 10px;
margin-bottom: 15px;
color: #FFFF;
${isMobileDevice
? css`
height: 24px;
min-width: 242px;
padding-left: 23px;`
: css`
min-width: 513px;
padding-left: 36px;
height: 36px;`}
${isMobileDevice
? css`
font-size: 10px;
line-height: 15px;`
: css`
font-size: 18px;
line-height: 22px;`}
::placeholder {
text-transform: uppercase;
letter-spacing: 0.05em;
}
`
export const SearchWithAllContainer = styled.div`
flex: 1 1 auto;
`
export const BackButton = styled.div`
font-style: normal;
font-weight: 700;
font-size: 10px;
line-height: 12px;
align-items: center;
letter-spacing: 0.05em;
text-transform: uppercase;
color: #FFFFFF;
cursor: pointer;
position: absolute;
top: 12px;
left: 13px;
padding-left: 24px;
:before {
content: '';
display: block;
background: url(/images/arrowUpWhite.svg) center no-repeat;
background-size: 12px 12xp;
transform: rotate(-90deg);
right: 0;
width: 12px;
height: 12px;
position: absolute;
top: 0;
left: 0;
}
`

@ -0,0 +1,23 @@
import { MouseEvent, ChangeEvent } from 'react'
import { TActiveFilters } from 'features/HeaderFilters/store/hooks/useMatchFilters'
export type TDropDownProps = {
activeFilters: TActiveFilters,
changeInput: (e: ChangeEvent<HTMLInputElement>) => void,
clearFilters: (filterName: string) => (e: MouseEvent | ChangeEvent<HTMLInputElement>) => void,
closeDropdownList?: () => void,
filterTitle: string,
inputValue: string,
setFilters: (filterName: string, value: number) => void,
}
export type TItem = {
id: number,
lexic?: string,
name_eng: string,
name_rus: string,
}
export type TFilterItem = {
item: TItem | number,
}

@ -15,14 +15,18 @@ import {
Position,
} from 'features/ProfileHeader/styled'
export const Header = () => {
type THeader = {
disabled: boolean,
}
export const Header = ({ disabled }: THeader) => {
const {
resetFilters,
updateDate,
} = useHeaderFiltersStore()
return (
<HeaderStyled>
<HeaderStyled disabled={disabled}>
<Position
top={client.styles.logoTop}
left={client.styles.logoLeft}

@ -1,11 +1,6 @@
import { Fragment } from 'react'
import { useRecoilValue } from 'recoil'
import styled from 'styled-components/macro'
import { isLffClient } from 'config/clients'
import { ProfileTypes } from 'config/profileTypes'
import { ProfileLink } from 'features/ProfileLink'
import { SportsFilter } from 'features/SportsFilter'
import { isInSportsClient } from 'config/clients'
import { SelectFilter } from 'components/SelectFilter'
import { useHeaderFiltersStore } from 'features/HeaderFilters'
import { T9n } from 'features/T9n'
@ -13,83 +8,60 @@ import { T9n } from 'features/T9n'
import {
ScArrow,
ScHeaderFilters,
ScFilterItemsWrap,
ScFilterItem,
SelectFilterWrapper,
} from './styled'
import { ClearFiltersPopup } from '../ClearFiltersPopup'
import { MatchesFilters } from '../MatchesFilters'
import { isSportFilterShownAtom } from '../../Atoms/HomePageAtoms'
const ClearButton = styled.span`
cursor: pointer;
position: absolute;
left: 36px;
top: 30px;
font-style: normal;
font-weight: 400;
font-size: 18px;
letter-spacing: 0.05em;
text-transform: uppercase;
color: rgba(255, 255, 255, 0.5);
`
export const HeaderFilters = () => {
const {
clickClearAll,
handleClickBack,
isEmptyFilters,
isFiltersShown,
isShowTournament,
selectedFilters,
selectTournament,
setIsShowTournament,
setSelectedFilters,
setSelectedLeague,
selectedTournament,
} = useHeaderFiltersStore()
const isSportFilterShown = useRecoilValue(isSportFilterShownAtom)
const isActiveFilter = (filterItem: string) => selectedFilters.indexOf(filterItem) >= 0
const checkFilter = (item: string) => {
isActiveFilter(item)
? setSelectedFilters((prev) => prev.filter((check) => item !== check))
: setSelectedFilters([...selectedFilters, item])
}
const handleClickBack = () => {
setIsShowTournament(true)
setSelectedFilters([])
setSelectedLeague(['all_competitions'])
}
return (
<ScHeaderFilters>
{(!isShowTournament && selectTournament) && (
<Fragment>
{!isShowTournament && (
<SelectFilterWrapper onClick={handleClickBack}>
<ScArrow
refIcon='Arrow'
color='#ffffff'
direction={90}
onClick={() => handleClickBack()}
/>
<ProfileLink
id={selectTournament.id}
sportType={selectTournament.sportType}
profileType={ProfileTypes.TOURNAMENTS}
>
<SelectFilter
open={false}
selectItem={selectTournament}
withArrow={false}
/>
</ProfileLink>
</Fragment>
<SelectFilter
open={false}
selectItem={selectedTournament}
withArrow={false}
/>
</SelectFilterWrapper>
)}
{!isLffClient && isShowTournament && isSportFilterShown && <SportsFilter />}
{isShowTournament && (
<ScFilterItemsWrap>
<ScFilterItem
className={isActiveFilter('live') ? 'activeLive' : ''}
onClick={() => checkFilter('live')}
>
<T9n t='live' />
</ScFilterItem>
<ScFilterItem
className={isActiveFilter('upcoming') ? 'activeButton' : ''}
onClick={() => checkFilter('upcoming')}
>
<T9n t='upcoming' />
</ScFilterItem>
<ScFilterItem
className={isActiveFilter('completed') ? 'activeButton' : ''}
onClick={() => checkFilter('completed')}
>
<T9n t='completed' />
</ScFilterItem>
</ScFilterItemsWrap>
{!isEmptyFilters && (
<ClearButton onClick={clickClearAll}>
<T9n t='clear' />
</ClearButton>
)}
{isInSportsClient && isFiltersShown && (
<>
<MatchesFilters />
<ClearFiltersPopup />
</>
)}
</ScHeaderFilters>
)

@ -5,8 +5,8 @@ import { Icon } from 'features/Icon'
export const ScHeaderFilters = styled.div`
display: flex;
flex-direction: row;
margin-bottom: 23px;
align-items: center;
margin-bottom: 38px;
position: relative;
.activeLive {
color: #ffffff;
@ -19,6 +19,12 @@ export const ScHeaderFilters = styled.div`
}
`
export const SelectFilterWrapper = styled.div`
display: flex;
align-items: center;
cursor: pointer;
`
export const ScFilterItemsWrap = styled.div`
display: flex;
flex-direction: row;
@ -45,7 +51,12 @@ export const ScFilterItem = styled.div<Props>`
export const ScArrow = styled(Icon)`
margin-right: 15px;
cursor: pointer;
height: 20px;
svg {
width: 20px;
height: 12px;
}
:hover {
/* background-color: rgba(255, 255, 255, 0.5);; */

@ -0,0 +1,14 @@
import join from 'lodash/join'
import take from 'lodash/take'
import size from 'lodash/size'
import { TDefaultType } from 'features/HeaderFilters/store/hooks/useMatchFilters'
import { isMobileDevice } from 'config/userAgent'
const TEXT_LENGTH = isMobileDevice ? 6 : 7
export const truncateString = (text: string) => (
size(text) <= TEXT_LENGTH ? text : `${join(take(text, TEXT_LENGTH), '')}...`)
export const checkSize = (filtersList: Array<TDefaultType> | Array<Number> | undefined) => (
(filtersList && size(filtersList) > 2)
)

@ -0,0 +1,130 @@
import map from 'lodash/map'
import isNil from 'lodash/isNil'
import size from 'lodash/size'
import find from 'lodash/find'
import includes from 'lodash/includes'
import { useName } from 'features/Name'
import { T9n } from 'features/T9n'
import { useHeaderFiltersStore } from 'features/HeaderFilters'
import { isMobileDevice } from 'config/userAgent'
import {
FilterContainer,
FiltersCount,
MatchFiltersContainer,
ActiveFilters,
ActiveFilter,
CloseButton,
} from './styled'
import { DropDown } from '../Dropdown'
import { TItem } from '../Dropdown/types'
import { checkSize, truncateString } from './helpers'
import { Title } from '../MatchesFilters/styled'
type TProps = {
dropdownList: Array<TItem | number>,
filterTitle: string,
item: number,
}
const ActiveFilterText = ({
dropdownList,
filterTitle,
item,
}: TProps) => {
const currentItem = find(dropdownList, { id: item }) as TItem
const name = useName(currentItem)
if (includes(['gender', 'sport'], filterTitle)) return <T9n t={currentItem.lexic!} />
return (
<>
{truncateString(name)}
</>
)
}
type TFiltersProps = {
isMobile?: boolean,
}
export const MatchesFilters = ({ isMobile }: TFiltersProps) => {
const {
activeFilters,
changeInput,
clearFilters,
currentFilters,
filtersListName,
filtersSize,
getDropdownList,
handleSetFilters,
inputValue,
matchesList,
toggleDropdownList,
} = useHeaderFiltersStore()
return (
<MatchFiltersContainer>
{map(currentFilters, (filterTitle) => {
const currentActiveFilters = activeFilters[filterTitle as keyof typeof activeFilters]
const isShrinkFilters = filtersSize >= 7 || size(currentActiveFilters) >= 7
|| isMobile
const shrinkedActiveFilters = isShrinkFilters && currentActiveFilters
&& size(currentActiveFilters) > 2
? [currentActiveFilters[0], currentActiveFilters[1]]
: currentActiveFilters
const dropdownList = getDropdownList(filterTitle, '') as Array<TItem | number>
return (
<FilterContainer
active={filtersListName === filterTitle}
key={filterTitle}
onClick={toggleDropdownList(filterTitle)}
>
<Title t={filterTitle} />
<ActiveFilters>
{map(shrinkedActiveFilters, (item) => (
<ActiveFilter key={item}>
{filterTitle === 'youth_age'
? `U${item}`
: (
<ActiveFilterText
dropdownList={dropdownList}
filterTitle={filterTitle}
item={item}
/>
)}
<CloseButton onClick={(e) => {
e.stopPropagation()
handleSetFilters(filterTitle, item)
}}
/>
</ActiveFilter>
))}
{checkSize(currentActiveFilters) && isShrinkFilters && (
<FiltersCount>
+{size(currentActiveFilters) - 2}
</FiltersCount>
)}
</ActiveFilters>
{filtersListName === filterTitle && !isNil(matchesList) && !isMobileDevice && (
<DropDown
activeFilters={activeFilters}
changeInput={changeInput}
clearFilters={clearFilters}
filterTitle={filterTitle}
inputValue={inputValue}
setFilters={handleSetFilters}
/>
)}
</FilterContainer>
)
})}
</MatchFiltersContainer>
)
}

@ -0,0 +1,171 @@
import styled, { css } from 'styled-components/macro'
import { isMobileDevice } from 'config/userAgent'
import { T9n } from 'features/T9n'
export const MatchFiltersContainer = styled.div`
display: flex;
flex-wrap: no-wrap;
justify-content: flex-end;
width: 100%;
${isMobileDevice
? css`
flex-direction: column;
padding-right: 16px;
border-top: 1px solid #505050;
padding-top: 19px;
gap: 22px;
` : css`
gap: 30px;
flex-direction: row;
padding-right: 10px;`}
`
type TFilterContainer = {
active?: boolean,
}
export const FilterContainer = styled.div<TFilterContainer>`
font-style: normal;
font-weight: 700;
letter-spacing: 0.05em;
text-transform: uppercase;
position: relative;
display: flex;
${isMobileDevice
? css`
color:#8b8b8b;
font-size: 10px;
line-height: 14px;
padding-left: 19px;
flex-direction: row;
align-items: center;
`
: css`
font-size: 18px;
line-height: 34px;
height: 34px;
color: #FFFFFF;
padding-left: 32px;
flex-direction: column;`}
${({ active }) => active && !isMobileDevice && css`
:after {
content: '';
display: block;
position: fixed;
background: #000000;
opacity: 0.7;
top: 0px;
left: 0px;
width: 100%;
height: 100%;
z-index: 9;
cursor: auto;
}`}
:before {
display: block;
position: absolute;
top: 0;
content: '';
height: 100%;
cursor: pointer;
${({ active }) => (active
? css`
z-index: 12;
`
: css`
transform: rotate(180deg);
`)}
${isMobileDevice
? css`
background: url(/images/arrowUpWhite.svg) center no-repeat;
transform: rotate(90deg);
right: 0;
width: 10px;
`
: css`
background: url(/images/arrowUpWhite.svg) center no-repeat;
background-size: 20px 12px;
left: 0;
width: 20px;
`}
}
span {
${({ active }) => (active && css`
z-index: 12;
position: relative;
`)}
}
`
export const ActiveFilters = styled.div`
display: flex;
flex-direction: row;
${isMobileDevice
? css`
gap: 5px;`
: css`
gap: 10px;`}
`
export const CloseButton = styled.div`
background: url(/images/closeWhite.svg) no-repeat;
${isMobileDevice
? css`
width: 7px;
height: 7px;
background-size: 7px;`
: css`
height: 9px;
width: 9px;
background-size: 10px;`}
`
export const ActiveFilter = styled.span`
font-style: normal;
font-weight: 600;
display: flex;
align-items: center;
letter-spacing: 0.05em;
text-transform: uppercase;
color: #FFFFFF;
border: 1px solid #FFFFFF;
border-radius: 16px;
gap: 5px;
cursor: pointer;
${isMobileDevice
? css`
padding: 0 5px;
font-size: 10px;
line-height: 12px;`
: css`
padding: 0 10px;
font-size: 14px;
height: 17px;
:hover {
background: #ffff;
color: #000000;
${CloseButton} {
background: url(/images/closeBlack.svg) no-repeat;
}
}`}
`
export const FiltersCount = styled(ActiveFilter)``
export const Title = styled(T9n)`
cursor: pointer;
${isMobileDevice ? css`margin-right: 6px;` : ''}
`

@ -0,0 +1,91 @@
import { useState } from 'react'
import isEmpty from 'lodash/isEmpty'
import isNil from 'lodash/isNil'
import { useHeaderFiltersStore } from 'features/HeaderFilters'
import { T9n } from 'features/T9n'
import { MatchesFilters } from '../MatchesFilters'
import {
ClearButton,
CloseButton,
FilterContainer,
FiltersCount,
Modal,
} from './styled'
import { DropDown } from '../Dropdown'
import { ClearFiltersPopup } from '../ClearFiltersPopup'
export const MobileMatchesFilters = () => {
const [isOpen, setOpen] = useState(false)
const {
activeFilters,
changeInput,
clearFilters,
clickClearAll,
closeDropdownList,
currentFilters,
filtersListName,
filtersSize,
handleSetFilters,
inputValue,
isEmptyFilters,
matchesList,
} = useHeaderFiltersStore()
const openFilters = () => setOpen(true)
const clearAllFilters = () => {
setOpen(false)
clickClearAll()
}
const closeFilters = () => {
setOpen(false)
closeDropdownList()
}
return (
<>
{!isEmpty(currentFilters) && (
<>
<FilterContainer active={filtersSize !== 0} onClick={openFilters}>
<T9n t='filter' />
{filtersSize !== 0 && <FiltersCount>{` ${filtersSize}`}</FiltersCount>}
</FilterContainer>
<Modal isOpen={isOpen} withCloseButton={false}>
{!filtersListName
? (
<>
<MatchesFilters isMobile />
{!isEmptyFilters && (
<ClearButton onClick={clearAllFilters}>
<T9n t='clear' />
</ClearButton>
)}
<CloseButton onClick={closeFilters} />
</>
)
: (
<>
{!isNil(matchesList) && (
<DropDown
activeFilters={activeFilters}
changeInput={changeInput}
clearFilters={clearFilters}
closeDropdownList={closeDropdownList}
filterTitle={filtersListName}
inputValue={inputValue}
setFilters={handleSetFilters}
/>
)}
<CloseButton onClick={closeFilters} />
</>
)}
</Modal>
<ClearFiltersPopup />
</>
)}
</>
)
}

@ -0,0 +1,80 @@
import styled, { css } from 'styled-components/macro'
import { OutsideClickWrapper } from 'features/OutsideClick'
import { ModalWindow } from 'features/Modal/styled'
import {
Modal as BaseModal,
} from 'features/AuthServiceApp/components/RegisterPopup/styled'
export const Modal = styled(BaseModal)`
${OutsideClickWrapper} {
height: 100%;
}
${ModalWindow} {
min-height: auto;
max-width: 293px;
padding: 35px 0 9px 0;
top: 4vh;
}
`
export const CloseButton = styled.div`
position: absolute;
width: 13px;
height: 13px;
background:url(/images/closeWhite.svg) no-repeat;
background-size: 13px;
top: 13px;
right: 13px;
`
type TFilterProps = {
active?: boolean,
}
export const FilterContainer = styled.div<TFilterProps>`
font-style: normal;
font-weight: 700;
font-size: 10px;
line-height: 14px;
letter-spacing: 0.05em;
text-transform: uppercase;
color: #FFFFFF;
padding-left: 22px;
position: relative;
:before{
content: '';
display: block;
position: absolute;
left: 0;
top: 0;
width:14px;
height: 14px;
background-size: 14px 14px;
${({ active }) => (active
? css`
background: url(/images/filter-white.svg) no-repeat;`
: css`
background: url(/images/filter-gray.svg) no-repeat;`)}
}
`
export const ClearButton = styled.div`
font-style: normal;
position: absolute;
top: 14px;
right: 36px;
font-size: 10px;
line-height: 12px;
font-weight: 400;
letter-spacing: 0.05em;
text-transform: uppercase;
color: rgba(255,255,255,0.5);
`
export const FiltersCount = styled.span`
font-weight: 400;
`

@ -6,19 +6,12 @@ import {
import { format } from 'date-fns'
import { useSetRecoilState } from 'recoil'
import { client } from 'config/clients'
import { ClientNames } from 'config/clients/types'
import { useAuthStore } from 'features/AuthStore'
import { useHeaderFiltersStore } from 'features/HeaderFilters'
import { getHomeMatches } from 'requests/getMatches'
import { getAgreements, setAgreements } from 'requests/getAgreements'
import { isSportFilterShownAtom } from './Atoms/HomePageAtoms'
/**
* возвращает смещение в минутах относительно UTC
*
@ -35,10 +28,9 @@ const getDate = (date: Date) => format(date, 'yyyy-MM-dd')
export const useHomePage = () => {
const { user } = useAuthStore()
const { selectedDate } = useHeaderFiltersStore()
const { queryParams, selectedDate } = useHeaderFiltersStore()
const [isOpenDownload, setIsOpenDownload] = useState(false)
const [isShowConfirmPopup, setIsShowConfirmPopup] = useState(false)
const setIsSportFilterShown = useSetRecoilState(isSportFilterShownAtom)
const handleCloseConfirmPopup = useCallback(async () => {
await setAgreements(user?.profile?.email || '')
@ -57,27 +49,22 @@ export const useHomePage = () => {
useEffect(() => {
const dateLastOpenSmartBanner = localStorage.getItem('dateLastOpenSmartBanner')
if (!dateLastOpenSmartBanner
|| Date.parse(JSON.parse(dateLastOpenSmartBanner)) < Date.parse(new Date().toISOString())
|| Date.parse(JSON.parse(dateLastOpenSmartBanner)) < Date.parse(new Date().toISOString())
) {
setIsOpenDownload(true)
}
}, [])
const fetchMatches = useCallback(
(limit: number, offset: number) => getHomeMatches({
const fetchMatches = useCallback((limit: number, offset: number) => getHomeMatches(
{
date: getDate(selectedDate),
limit,
offset,
queryParams,
timezoneOffset: getTimezoneOffset(selectedDate),
}),
[selectedDate],
)
useEffect(() => {
if (client.name === ClientNames.Facr) {
setIsSportFilterShown(false)
}
}, [setIsSportFilterShown])
},
), [selectedDate, queryParams])
return {
fetchMatches,

@ -7,6 +7,7 @@ import { ConfirmPopup } from 'features/AuthServiceApp/components/ConfirmPopup'
import { Matches } from 'features/Matches'
import {
HeaderFiltersStore,
useHeaderFiltersStore,
} from 'features/HeaderFilters'
import {
@ -30,6 +31,7 @@ const Home = () => {
isShowConfirmPopup,
setIsOpenDownload,
} = useHomePage()
const { filtersListName } = useHeaderFiltersStore()
return (
<PageWrapper>
@ -39,7 +41,7 @@ const Home = () => {
setIsOpenDownload={setIsOpenDownload}
/>
) : (
<Header />
<Header disabled={Boolean(filtersListName)} />
)}
<Main>
<UserFavorites />

@ -10,6 +10,7 @@ import { getMatchAccess } from './getMatchClickAction'
const prepareMatch = (match: Match) => {
const {
arena,
calc,
country,
country_id,
@ -21,6 +22,7 @@ const prepareMatch = (match: Match) => {
live,
preview,
previewURL,
round,
sport,
sport_info,
storage,
@ -32,6 +34,7 @@ const prepareMatch = (match: Match) => {
const date = parseDate(matchDate)
return {
access: getMatchAccess(match),
arena,
calc,
countryId: country_id,
countryInfo: country,
@ -44,6 +47,7 @@ const prepareMatch = (match: Match) => {
live,
preview,
previewURL,
round,
sportInfo: sport_info,
sportType: sport,
storage,

@ -11,7 +11,7 @@ type Props = {
onClick: (event?: MouseEvent) => void,
}
const OutsideClickWrapper = styled.div``
export const OutsideClickWrapper = styled.div``
export const OutsideClick = ({
children,

@ -44,6 +44,7 @@ export const defaultHeaderStyles = (
type HeaderProps = {
color?: string,
disabled?: boolean,
headerImage?: string | null,
height?: number,
isMatchPage?: boolean,
@ -63,6 +64,12 @@ export const HeaderStyled = styled.header<HeaderProps>`
` : ''
)}
${({ disabled }) => (
disabled ? css`
pointer-events: none;
` : ''
)}
${({ isMatchPage }) => css`
${isMobileDevice
? css`
@ -71,7 +78,6 @@ export const HeaderStyled = styled.header<HeaderProps>`
`
: ''}
`}
`
type Props = {
@ -105,7 +111,7 @@ export const HeaderLogo = styled(Logo)`
transform: translateX(-50%);
position: absolute;
${client.styles.matchPageMobileHeaderLogo}
${client.styles.matchPageMobileHeaderLogo}
` : ''}
` : css`
${isMobileDevice ? css`
@ -119,8 +125,6 @@ export const HeaderLogo = styled(Logo)`
}
` : ''}
`)}
`
type PositionProps = {

@ -35,7 +35,7 @@ export const CollapseTournament = ({
const {
setIsShowTournament,
setSelectedLeague,
setSelectTournament,
setSelectedTournament,
} = useHeaderFiltersStore()
const {
countryId,
@ -47,7 +47,7 @@ export const CollapseTournament = ({
const handleClick = () => {
setIsShowTournament(false)
setSelectedLeague([tournament.id])
setSelectTournament(tournament)
setSelectedTournament(tournament)
}
const { countryInfo, sportInfo } = tournamentMatches[0]

@ -18,7 +18,8 @@ export const UserSportFavWrapper = styled.aside`
left: 0;
top: 0;
bottom: 0;
z-index: 10;
width: 4%;
z-index: 8;
${isMobileDevice
? css`

@ -1,4 +1,5 @@
import { PROCEDURES, API_ROOT } from 'config'
import isEmpty from 'lodash/isEmpty'
import { client } from 'config/clients'
@ -8,10 +9,21 @@ import { getMatchesPreviews } from './getPreviews'
const proc = PROCEDURES.get_matches
export type TQueryParams = {
arena?: Array<number>,
division?: Array<number>,
gender?: Array<number>,
main_team?: Array<number>,
round?: Array<number>,
sport?: Array<number>,
youth_age?: Array<number>,
}
type Args = {
date: string,
limit: number,
offset: number,
queryParams?: TQueryParams,
timezoneOffset: number,
}
@ -19,16 +31,23 @@ export const getHomeMatches = async ({
date,
limit,
offset,
queryParams,
timezoneOffset,
}: Args): Promise<MatchesBySection> => {
const url = `${API_ROOT}/v1/data/get-matches`
const url = `${API_ROOT}/v1/data/matches/query`
const config = {
body: {
_p_date: `${date} 00:00:00`,
_p_gmt: timezoneOffset,
_p_limit: limit,
_p_offset: offset,
arena: !isEmpty(queryParams?.arena) ? queryParams?.arena : undefined,
date: `${date} 00:00:00`,
division: !isEmpty(queryParams?.division) ? queryParams?.division : undefined,
gender: !isEmpty(queryParams?.gender) ? queryParams?.gender : undefined,
gmt: String(timezoneOffset),
limit: String(limit),
main_team: !isEmpty(queryParams?.main_team) ? queryParams?.main_team : undefined,
offset: String(offset),
round: !isEmpty(queryParams?.round) ? queryParams?.round : undefined,
sport: !isEmpty(queryParams?.sport) ? queryParams?.sport : undefined,
youth_age: !isEmpty(queryParams?.youth_age) ? queryParams?.youth_age : undefined,
...client.requests?.[proc],
},
}

@ -8,11 +8,21 @@ export type TournamentType = {
sportType: SportTypes,
}
export type TDefaultType = {
id: number,
name_eng: string,
name_rus: string,
}
type Team = {
division?: TDefaultType, // Дивизион
gender?: number, // ИД пола
id: number,
main_team?: TDefaultType, // Родительский клуб команды
name_eng: string,
name_rus: string,
score?: number | null,
youth_age?: number | null, // Возраст команды
}
export type SportInfo = {
@ -22,6 +32,8 @@ export type SportInfo = {
export type Match = {
access: boolean,
/** Стадион */
arena: TDefaultType | null,
/** тип трансляции */
c_type_broadcast: number,
calc: boolean,
@ -39,6 +51,8 @@ export type Match = {
live: boolean,
preview?: string,
previewURL?: string,
/** Раунд */
round?: TDefaultType,
sport: SportTypes,
sport_info: SportInfo,
/** наличие завершенного hls стрима */

Loading…
Cancel
Save