diff --git a/public/images/closeBlack.svg b/public/images/closeBlack.svg
new file mode 100644
index 00000000..8cb31a4f
--- /dev/null
+++ b/public/images/closeBlack.svg
@@ -0,0 +1,3 @@
+
diff --git a/public/images/closeWhite.svg b/public/images/closeWhite.svg
new file mode 100644
index 00000000..8bcc2ce2
--- /dev/null
+++ b/public/images/closeWhite.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/components/SelectFilter/styled.tsx b/src/components/SelectFilter/styled.tsx
index 543b770f..b0a2dd34 100644
--- a/src/components/SelectFilter/styled.tsx
+++ b/src/components/SelectFilter/styled.tsx
@@ -7,7 +7,7 @@ export const ScSelectFilter = styled.div`
display: flex;
color: white;
font-size: 14px;
- width: 30%;
+ width: auto;
text-transform: uppercase;
font-weight: 700;
align-items: center;
diff --git a/src/config/lexics/indexLexics.tsx b/src/config/lexics/indexLexics.tsx
index 8bb9b918..939c0678 100644
--- a/src/config/lexics/indexLexics.tsx
+++ b/src/config/lexics/indexLexics.tsx
@@ -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,
diff --git a/src/features/HeaderFilters/store/hooks/index.tsx b/src/features/HeaderFilters/store/hooks/index.tsx
index 8530987c..27f7b4c9 100644
--- a/src/features/HeaderFilters/store/hooks/index.tsx
+++ b/src/features/HeaderFilters/store/hooks/index.tsx
@@ -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,7 +23,27 @@ export const useFilters = () => {
key: filterKeys.DATE,
validator: isValidDate,
})
-
+ const {
+ activeFilters,
+ changeInput,
+ clearAllFilters,
+ clearFilters,
+ clickCancel,
+ clickClearAll,
+ closeDropdownList,
+ confirmClear,
+ currentFilters,
+ filtersList,
+ filtersSize,
+ handleSetFilters,
+ inputValue,
+ isEmptyFilters,
+ isOpenList,
+ openDropdownList,
+ openPopup,
+ queryParams,
+ setFilters,
+ } = useMatchFilters(selectedDate)
const [selectedSport, setSelectedSport] = useState(['all_sports'])
const [selectedLeague, setSelectedLeague] = useState>(['all_competitions'])
const [selectedFilters, setSelectedFilters] = useState>([])
@@ -61,14 +82,33 @@ export const useFilters = () => {
])
const store = useMemo(() => ({
+ activeFilters,
+ changeInput,
+ clearAllFilters,
+ clearFilters,
+ clickCancel,
+ clickClearAll,
+ closeDropdownList,
+ confirmClear,
+ currentFilters,
+ filtersList,
+ filtersSize,
+ handleSetFilters,
+ inputValue,
+ isEmptyFilters,
+ isOpenList,
isShowTournament,
isTodaySelected,
+ openDropdownList,
+ openPopup,
+ queryParams,
resetFilters,
selectTournament,
selectedDate,
selectedFilters,
selectedLeague,
selectedSport,
+ setFilters,
setIsShowTournament,
setSelectTournament,
setSelectedDate,
@@ -79,16 +119,35 @@ export const useFilters = () => {
sportIds,
updateDate,
}), [
+ activeFilters,
+ clickCancel,
+ clickClearAll,
+ confirmClear,
+ changeInput,
+ clearAllFilters,
+ clearFilters,
+ closeDropdownList,
+ currentFilters,
+ filtersList,
+ filtersSize,
+ handleSetFilters,
+ inputValue,
+ isEmptyFilters,
+ isOpenList,
isShowTournament,
isTodaySelected,
+ openPopup,
+ openDropdownList,
+ queryParams,
resetFilters,
+ selectTournament,
selectedDate,
selectedFilters,
selectedLeague,
selectedSport,
- selectTournament,
- setSelectTournament,
+ setFilters,
setIsShowTournament,
+ setSelectTournament,
setSelectedDate,
setSelectedFilters,
setSelectedLeague,
diff --git a/src/features/HeaderFilters/store/hooks/useMatchFilters.tsx b/src/features/HeaderFilters/store/hooks/useMatchFilters.tsx
new file mode 100644
index 00000000..3455c590
--- /dev/null
+++ b/src/features/HeaderFilters/store/hooks/useMatchFilters.tsx
@@ -0,0 +1,185 @@
+import {
+ useCallback,
+ useEffect,
+ useMemo,
+ useState,
+ MouseEvent,
+ ChangeEvent,
+} from 'react'
+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 map from 'lodash/map'
+import reduce from 'lodash/reduce'
+import size from 'lodash/size'
+
+import { format } from 'date-fns'
+
+import {
+ getHomeMatches,
+ Match,
+ TQueryParams,
+} from 'requests'
+
+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 = {
+ arena?: Array,
+ division?: Array,
+ gender?: Array,
+ main_team?: Array,
+ round?: Array,
+ youth_age?: Array,
+}
+export type TDefaultType = {
+ id: number,
+ name_eng: string,
+ name_rus: string,
+}
+
+export const useMatchFilters = (selectedDate: Date) => {
+ const [filtersList, setFiltersList] = useState>()
+ const [isOpenList, setOpenList] = useState('')
+ const [activeFilters, setActiveFilters] = useState({})
+ const [inputValue, setInputValue] = useState('')
+ const [openPopup, setOpenPopup] = useState(false)
+
+ const setFilters = (filters: Array) => {
+ setFiltersList(filters)
+ }
+
+ const openDropdownList = (title: string) => () => {
+ setOpenList(title === isOpenList ? '' : title)
+ }
+
+ const closeDropdownList = () => {
+ setOpenList('')
+ }
+ const fetchMatches = useCallback(
+ (limit: number, offset: number) => getHomeMatches({
+ date: getDate(selectedDate),
+ limit,
+ offset,
+ timezoneOffset: getTimezoneOffset(selectedDate),
+ }),
+ [selectedDate],
+ )
+
+ useEffect(() => {
+ fetchMatches(1000, 0).then((resp) => setFiltersList(resp.broadcast))
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [selectedDate])
+
+ const currentFilters = useMemo(() => {
+ const arr = []
+ if (some(filtersList, (item) => !isNil(item.arena?.id))) arr.push('arena')
+ if (some(filtersList, (item) => !isNil(item.round?.id))) arr.push('round')
+ if (some(filtersList, (item) => !isNil(item.team1?.main_team) || !isNil(item.team2?.main_team))) arr.push('main_team')
+ if (some(filtersList, (item) => !isNil(item.team1?.youth_age) || !isNil(item.team2?.youth_age))) arr.push('youth_age')
+ if (some(filtersList, (item) => !isNil(item.team1?.gender) || !isNil(item.team2?.gender))) arr.push('gender')
+ if (some(filtersList, (item) => !isNil(item.team1?.division?.id) || !isNil(item.team2?.division?.id))) arr.push('division')
+ return arr
+ }, [filtersList])
+
+ const handleSetFilters = (filterName: string, value: any) => {
+ const isFilterPresent = !isNil(activeFilters[filterName as keyof typeof activeFilters])
+ if (isFilterPresent) {
+ const isValuePresent = includes(
+ activeFilters[filterName as keyof typeof activeFilters], value,
+ )
+ const currentValue = isValuePresent
+ ? filter(activeFilters[filterName as keyof typeof activeFilters], (item) => item !== value)
+ : [...activeFilters[filterName as keyof typeof activeFilters]!, value]
+
+ return setActiveFilters({
+ ...activeFilters,
+ [filterName]: currentValue,
+ })
+ }
+ return setActiveFilters({
+ ...activeFilters,
+ [filterName]: [value],
+ })
+ }
+
+ const clearFilters = (filterName: string) => (e: MouseEvent | ChangeEvent) => {
+ e.stopPropagation()
+ e.preventDefault()
+ return setActiveFilters({
+ ...activeFilters,
+ [filterName]: [],
+ })
+ }
+
+ const clearAllFilters = (e: MouseEvent) => {
+ e.stopPropagation()
+ setActiveFilters({})
+ }
+
+ const isEmptyFilters = some(activeFilters, (filterItem) => isEmpty(filterItem))
+ || isEmpty(activeFilters)
+
+ const queryParams: TQueryParams = useMemo(() => {
+ const params = {
+ arena: map(activeFilters.arena, (item) => item.id),
+ division: map(activeFilters.division, (item) => item.id),
+ gender: map(activeFilters.gender, (item) => item.id),
+ main_team: map(activeFilters.main_team, (item) => item.id),
+ round: map(activeFilters.round, (item) => item.id),
+ youth_age: activeFilters.youth_age,
+ }
+
+ return (params)
+ }, [activeFilters])
+
+ const changeInput = (e: ChangeEvent) => {
+ const { value } = e.target
+ setInputValue(value)
+ }
+
+ const clickClearAll = () => {
+ setOpenPopup(true)
+ }
+
+ const confirmClear = (e: MouseEvent) => {
+ setOpenPopup(false)
+ clearAllFilters(e)
+ }
+
+ const clickCancel = () => {
+ setOpenPopup(false)
+ }
+
+ const filtersSize = reduce(activeFilters,
+ (result,
+ value) => result + size(value), 0)
+
+ return {
+ activeFilters,
+ changeInput,
+ clearAllFilters,
+ clearFilters,
+ clickCancel,
+ clickClearAll,
+ closeDropdownList,
+ confirmClear,
+ currentFilters,
+ filtersList,
+ filtersSize,
+ handleSetFilters,
+ inputValue,
+ isEmptyFilters,
+ isOpenList,
+ openDropdownList,
+ openPopup,
+ queryParams,
+ setFilters,
+ }
+}
diff --git a/src/features/HeaderMobile/index.tsx b/src/features/HeaderMobile/index.tsx
index 86d26f4c..6076bce9 100644
--- a/src/features/HeaderMobile/index.tsx
+++ b/src/features/HeaderMobile/index.tsx
@@ -10,6 +10,7 @@ import { SportsFilter } from 'features/SportsFilter'
import { isSportFilterShownAtom } from 'features/HomePage/Atoms/HomePageAtoms'
import { SmartBanner } from 'components/SmartBanner'
+import { MobileMathesFilters } from 'features/HomePage/components/MobileMatchesFilters'
import {
HeaderStyled,
ScoreSwitchWrapper,
@@ -35,7 +36,12 @@ export const HeaderMobile = ({ isOpenDownload, setIsOpenDownload }: HeaderBanner
- {!isLffClient && isSportFilterShown ? : null}
+ {!isLffClient && isSportFilterShown ? (
+ <>
+
+
+ >
+ ) : null}
diff --git a/src/features/HomePage/components/ClearFiltersPopup/index.tsx b/src/features/HomePage/components/ClearFiltersPopup/index.tsx
new file mode 100644
index 00000000..3a510448
--- /dev/null
+++ b/src/features/HomePage/components/ClearFiltersPopup/index.tsx
@@ -0,0 +1,41 @@
+import { useHeaderFiltersStore } from 'features/HeaderFilters'
+import { T9n } from 'features/T9n'
+import React from 'react'
+import {
+ ButtonsContainer,
+ CancelButton,
+ ConfirmButton,
+ Modal,
+ PopupContainer,
+ PopupText,
+ PopupTitle,
+} from './styled'
+
+export const ClearFiltersPopup = () => {
+ const {
+ clickCancel,
+ confirmClear,
+ openPopup,
+ } = useHeaderFiltersStore()
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
diff --git a/src/features/HomePage/components/ClearFiltersPopup/styled.tsx b/src/features/HomePage/components/ClearFiltersPopup/styled.tsx
new file mode 100644
index 00000000..690d81cb
--- /dev/null
+++ b/src/features/HomePage/components/ClearFiltersPopup/styled.tsx
@@ -0,0 +1,113 @@
+import styled, { css } from 'styled-components/macro'
+
+import { ModalWindow } from 'features/Modal/styled'
+import {
+ Modal as BaseModal,
+} from 'features/AuthServiceApp/components/RegisterPopup/styled'
+import { isMobileDevice } from 'config/userAgent'
+
+export const Modal = styled(BaseModal)`
+ ${ModalWindow} {
+ ${isMobileDevice
+ ? css`
+ min-height: 201px;
+ max-width: 351px;
+ padding: 26px 19px 33px 19px;
+ `
+ : 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``
+ : 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));
+`
diff --git a/src/features/HomePage/components/Dropdown/Dropdown.tsx b/src/features/HomePage/components/Dropdown/Dropdown.tsx
new file mode 100644
index 00000000..5ba084b7
--- /dev/null
+++ b/src/features/HomePage/components/Dropdown/Dropdown.tsx
@@ -0,0 +1,160 @@
+import React, { useMemo } from 'react'
+
+import map from 'lodash/map'
+import isEmpty from 'lodash/isEmpty'
+import includes from 'lodash/includes'
+
+import { T9n } from 'features/T9n'
+import { Name } from 'features/Name'
+
+import { useLexicsStore } from 'features/LexicsStore'
+import { isMobileDevice } from 'config/userAgent'
+import {
+ getAge,
+ getArena,
+ getDivision,
+ getGender,
+ getMainTeam,
+ getRound,
+} from './helpers'
+import {
+ TDropDownProps,
+ TFilterItem,
+ TItem,
+} from './types'
+import {
+ DropDownContainer,
+ FiltersList,
+ FilterItem,
+ Checkbox,
+ CommonButtonsBlock,
+ ClearButtonContainer,
+ SearchWithAllContainer,
+ SearchContainer,
+ SearchInput,
+ BackButton,
+} from './styled'
+
+const Label = ({ item }: TFilterItem) => {
+ const isNumber = typeof item === 'number'
+
+ return (
+ <>
+ {isNumber ? (<>U{item}>) : ()}
+ >
+ )
+}
+
+export const DropDown = ({
+ activeFilters,
+ changeInput,
+ clearFilters,
+ closeDropdownList,
+ filterList,
+ filterTitle,
+ inputValue,
+ setFilters,
+}: TDropDownProps) => {
+ const { translate } = useLexicsStore()
+
+ const dropDownList = useMemo(() => {
+ switch (filterTitle) {
+ case 'gender':
+ return getGender(filterList)
+ case 'youth_age':
+ return getAge(filterList)
+ case 'division':
+ return getDivision(filterList)
+ case 'main_team':
+ return getMainTeam(filterList)
+ case 'arena':
+ return getArena(filterList, inputValue)
+ case 'round':
+ return getRound(filterList)
+ default:
+ return []
+ }
+ }, [filterTitle, filterList, inputValue]) as Array | Array
+
+ const currentActiveFilter = activeFilters[filterTitle as keyof typeof activeFilters]
+
+ return (
+
+
+
+
+ {/* {isMobileDevice && ()} */}
+ {isMobileDevice && closeDropdownList
+ && (
+
+ {filterTitle}
+
+ )}
+ {filterTitle === 'arena' && (
+
+ e.stopPropagation()}
+ placeholder={translate('search')}
+ />
+
+ )}
+
+
+
+
+
+
+
+ {!isEmpty(dropDownList) && map(dropDownList, (filterItem, i) => (
+ <>
+ {
+ e.preventDefault()
+ e.stopPropagation()
+ setFilters(filterTitle, filterItem)
+ }}
+ >
+ {filterTitle === 'gender'
+ ? (
+ {
+ e.preventDefault()
+ e.stopPropagation()
+ setFilters(filterTitle, filterItem)
+ }}
+ labelLexic={filterItem.title}
+ />
+ )
+ : (
+ {
+ e.preventDefault()
+ e.stopPropagation()
+ setFilters(filterTitle, filterItem)
+ }}
+ label={()}
+ />
+ )}
+
+ >
+ ))}
+
+
+ )
+}
diff --git a/src/features/HomePage/components/Dropdown/helpers.tsx b/src/features/HomePage/components/Dropdown/helpers.tsx
new file mode 100644
index 00000000..caffc6fc
--- /dev/null
+++ b/src/features/HomePage/components/Dropdown/helpers.tsx
@@ -0,0 +1,62 @@
+import map from 'lodash/map'
+import some from 'lodash/some'
+import filter from 'lodash/filter'
+import uniq from 'lodash/uniq'
+import flatten from 'lodash/flatten'
+import compact from 'lodash/compact'
+import startsWith from 'lodash/startsWith'
+import toLower from 'lodash/toLower'
+
+import { Match } from 'requests'
+
+const checkStartString = (text: string, searchString: string) => startsWith(
+ toLower(text), toLower(searchString),
+)
+export const getAge = (filterList: Array) => compact(
+ uniq(
+ flatten(
+ map(
+ filterList, (item) => [item.team1.youth_age, item.team2.youth_age],
+ ),
+ ),
+ ),
+)
+
+export const getDivision = (filterList: Array) => filter(
+ flatten(
+ map(
+ filterList, (item) => [item.team1.division, item.team2.division],
+ ),
+ ), (item) => item?.id,
+)
+
+export const getMainTeam = (filterList: Array) => filter(
+ flatten(
+ map(
+ filterList, (item) => [item.team1.main_team, item.team2.main_team],
+ ),
+ ), (item) => item?.id,
+)
+
+export const getArena = (filterList: Array, inputValue: string) => filter(
+ map(
+ filterList, (item) => item.arena,
+ ), (item) => item?.id
+ && (checkStartString(item.name_eng, inputValue)
+ || checkStartString(item.name_rus, inputValue)),
+)
+
+export const getRound = (filterList: Array) => filter(
+ map(
+ filterList, (item) => item.round,
+ ), (item) => item?.id,
+)
+
+export const getGender = (filterList: Array) => {
+ const list = []
+
+ if (some(filterList, (item) => item.team1.gender === 1 || item.team2.gender === 1)) list.push({ id: 1, title: 'gender_male_long' })
+ if (some(filterList, (item) => item.team1.gender === 2 || item.team2.gender === 2)) list.push({ id: 2, title: 'gender_female_long' })
+
+ return list
+}
diff --git a/src/features/HomePage/components/Dropdown/styled.tsx b/src/features/HomePage/components/Dropdown/styled.tsx
new file mode 100644
index 00000000..4cff2a99
--- /dev/null
+++ b/src/features/HomePage/components/Dropdown/styled.tsx
@@ -0,0 +1,215 @@
+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`
+${customScrollbar}
+overflow-y: auto;
+display: flex;
+flex-direction: column;
+max-height: 500px;
+`
+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``
+ : 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`
+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 {
+ font-style: normal;
+ ${isMobileDevice
+ ? css`
+ font-size: 10px;
+ line-height: 12px;`
+ : css`
+ font-size: 18px;
+ line-height: 22px;`}
+ 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;`
+ : css`
+ left: 13px;
+ top: 13px;`}
+ z-index: 2;
+ width: 13px;
+ height: 11px;
+}
+`
+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;`}
+
+::placeholder {
+
+${isMobileDevice
+ ? css`
+ font-size: 10px;
+ line-height: 15px;`
+ : css`
+ font-size: 18px;
+ line-height: 22px;`}
+
+ 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;
+}
+`
diff --git a/src/features/HomePage/components/Dropdown/types.tsx b/src/features/HomePage/components/Dropdown/types.tsx
new file mode 100644
index 00000000..77c26e29
--- /dev/null
+++ b/src/features/HomePage/components/Dropdown/types.tsx
@@ -0,0 +1,24 @@
+import { MouseEvent, ChangeEvent } from 'react'
+import { Match } from 'requests'
+import { TActiveFilters } from 'features/HeaderFilters/store/hooks/useMatchFilters'
+
+export type TDropDownProps = {
+ activeFilters: TActiveFilters,
+ changeInput: (e: ChangeEvent) => void,
+ clearFilters: (filterName: string) => (e: MouseEvent | ChangeEvent) => void,
+ closeDropdownList?: () => void,
+ filterList: Array,
+ filterTitle: string,
+ inputValue: string,
+ setFilters: (filterName: string, value: number) => void,
+}
+
+export type TItem = {
+ id: number,
+ name_eng: string,
+ name_rus: string,
+}
+
+export type TFilterItem = {
+ item: TItem | number,
+}
diff --git a/src/features/HomePage/components/HeaderFilters/index.tsx b/src/features/HomePage/components/HeaderFilters/index.tsx
index c219c5a0..781164e1 100644
--- a/src/features/HomePage/components/HeaderFilters/index.tsx
+++ b/src/features/HomePage/components/HeaderFilters/index.tsx
@@ -1,26 +1,51 @@
-import { Fragment } from 'react'
import { useRecoilValue } from 'recoil'
-import { isLffClient } from 'config/clients'
-import { ProfileTypes } from 'config/profileTypes'
+import { isLffClient, isInSportsClient } from 'config/clients'
-import { ProfileLink } from 'features/ProfileLink'
import { SportsFilter } from 'features/SportsFilter'
import { SelectFilter } from 'components/SelectFilter'
import { useHeaderFiltersStore } from 'features/HeaderFilters'
import { T9n } from 'features/T9n'
+import {
+ Modal as BaseModal,
+} from 'features/AuthServiceApp/components/RegisterPopup/styled'
+import styled from 'styled-components/macro'
+import { ModalWindow } from 'features/Modal/styled'
import {
ScArrow,
ScHeaderFilters,
ScFilterItemsWrap,
ScFilterItem,
} from './styled'
-
import { isSportFilterShownAtom } from '../../Atoms/HomePageAtoms'
+import { ClearFiltersPopup } from '../ClearFiltersPopup'
+import { MatchesFilters } from '../MatchesFilters'
+
+export const Modal = styled(BaseModal)`
+ ${ModalWindow} {
+ min-height: 452px;
+ max-width: 280px;
+ padding: 37px 0 39px 0;
+ }
+`
+const ClearButton = styled.span`
+ cursor: pointer;
+ position: absolute;
+ left: 5px;
+ top: 38px;
+ 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,
+ isEmptyFilters,
isShowTournament,
selectedFilters,
selectTournament,
@@ -43,33 +68,38 @@ export const HeaderFilters = () => {
setSelectedFilters([])
setSelectedLeague(['all_competitions'])
}
-
return (
- {(!isShowTournament && selectTournament) && (
-
+ {!isShowTournament && (
+ <>
handleClickBack()}
/>
-
-
-
-
+
+ >
)}
{!isLffClient && isShowTournament && isSportFilterShown && }
- {isShowTournament && (
+ {!isEmptyFilters && (
+
+
+
+ )}
+ {!isLffClient && (
+ <>
+
+
+
+ >
+ )}
+ {isShowTournament && !isInSportsClient && (
(
+ size(text) <= TEXT_LENGTH ? text : `${join(take(text, TEXT_LENGTH), '')}...`)
+
+export const checkSize = (filtersList: Array | Array | undefined) => (
+ (filtersList && size(filtersList) > 2)
+)
diff --git a/src/features/HomePage/components/MatchesFilters/index.tsx b/src/features/HomePage/components/MatchesFilters/index.tsx
new file mode 100644
index 00000000..15ff7714
--- /dev/null
+++ b/src/features/HomePage/components/MatchesFilters/index.tsx
@@ -0,0 +1,110 @@
+import React from 'react'
+import map from 'lodash/map'
+import isNil from 'lodash/isNil'
+import size from 'lodash/size'
+
+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/Dropdown'
+import { checkSize, truncateString } from './helpers'
+
+type TProps = {
+ filterTitle: string,
+ item: any,
+}
+
+const ActiveFilterText = ({ filterTitle, item }: TProps) => {
+ const name = useName(item)
+ if (filterTitle === 'gender') return ()
+ return (
+ <>
+ {truncateString(name)}
+ >
+ )
+}
+type TFiltersProps = {
+ isMobile?: boolean,
+}
+
+export const MatchesFilters = ({ isMobile }: TFiltersProps) => {
+ const {
+ activeFilters,
+ changeInput,
+ clearFilters,
+ currentFilters,
+ filtersList,
+ filtersSize,
+ handleSetFilters,
+ inputValue,
+ isOpenList,
+ openDropdownList,
+ } = useHeaderFiltersStore()
+
+ return (
+
+ {map(currentFilters, (filterTitle, index) => {
+ 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
+
+ return (
+
+ {/* */}
+ {filterTitle}
+
+ {map(shrinkedActiveFilters, (item, i) => (
+
+ {typeof item === 'number'
+ ? `U${item}`
+ : ()}
+ {
+ e.stopPropagation()
+ handleSetFilters(filterTitle, item)
+ }}
+ />
+
+ ))}
+
+ {checkSize(currentActiveFilters) && isShrinkFilters && (
+
+ +{size(currentActiveFilters) - 2}
+
+ )}
+
+ {isOpenList === filterTitle && !isNil(filtersList) && !isMobileDevice && (
+
+ )}
+
+ )
+ })}
+
+
+ )
+}
diff --git a/src/features/HomePage/components/MatchesFilters/styled.tsx b/src/features/HomePage/components/MatchesFilters/styled.tsx
new file mode 100644
index 00000000..656c771b
--- /dev/null
+++ b/src/features/HomePage/components/MatchesFilters/styled.tsx
@@ -0,0 +1,169 @@
+import { isMobileDevice } from 'config/userAgent'
+import styled, { css } from 'styled-components/macro'
+
+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: 25px;
+ `}
+`
+
+type TFilterContainer = {
+ active?: boolean,
+}
+
+export const FilterContainer = styled.div`
+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;`}
+
+.filter_title {
+ cursor: pointer;
+ ${isMobileDevice && 'margin-right: 6px;'}
+}
+${({ 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)``
diff --git a/src/features/HomePage/components/MobileMatchesFilters/index.tsx b/src/features/HomePage/components/MobileMatchesFilters/index.tsx
new file mode 100644
index 00000000..2547c38d
--- /dev/null
+++ b/src/features/HomePage/components/MobileMatchesFilters/index.tsx
@@ -0,0 +1,87 @@
+import { useHeaderFiltersStore } from 'features/HeaderFilters'
+import { T9n } from 'features/T9n'
+import React, { useState } from 'react'
+import isEmpty from 'lodash/isEmpty'
+import isNil from 'lodash/isNil'
+import { MatchesFilters } from '../MatchesFilters'
+import {
+ ClearButton,
+ CloseButton,
+ FilterContainer,
+ Modal,
+} from './styled'
+import { DropDown } from '../Dropdown/Dropdown'
+import { ClearFiltersPopup } from '../ClearFiltersPopup'
+
+export const MobileMathesFilters = () => {
+ const [isOpen, setOpen] = useState(false)
+ const {
+ activeFilters,
+ changeInput,
+ clearFilters,
+ clickClearAll,
+ closeDropdownList,
+ currentFilters,
+ filtersList,
+ filtersSize,
+ handleSetFilters,
+ inputValue,
+ isOpenList,
+ } = useHeaderFiltersStore()
+
+ const openFilters = () => setOpen(true)
+
+ const clearAllFilters = () => {
+ setOpen(false)
+ clickClearAll()
+ }
+
+ const closeFilters = () => {
+ setOpen(false)
+ closeDropdownList()
+ }
+ return (
+ <>
+ {!isEmpty(currentFilters) && (
+ <>
+
+
+ {filtersSize !== 0 && ` ${filtersSize}`}
+
+
+ {isEmpty(isOpenList)
+ ? (
+ <>
+
+ {filtersSize !== 0 && (
+
+
+
+ )}
+
+ >
+ )
+ : (
+ <>
+ {!isNil(filtersList) && (
+
+ )}
+
+ >
+ )}
+
+
+ >
+ )}
+ >
+ )
+}
diff --git a/src/features/HomePage/components/MobileMatchesFilters/styled.tsx b/src/features/HomePage/components/MobileMatchesFilters/styled.tsx
new file mode 100644
index 00000000..1b40d4f8
--- /dev/null
+++ b/src/features/HomePage/components/MobileMatchesFilters/styled.tsx
@@ -0,0 +1,71 @@
+import styled, { css } from 'styled-components/macro'
+
+import { ModalWindow } from 'features/Modal/styled'
+import {
+ Modal as BaseModal,
+} from 'features/AuthServiceApp/components/RegisterPopup/styled'
+
+export const Modal = styled(BaseModal)`
+ ${ModalWindow} {
+ min-height: auto;
+ max-height: 452px;
+ max-width: 293px;
+ padding: 35px 0 9px 0;
+ }
+`
+
+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`
+font-style: normal;
+font-weight: 700;
+font-size: 10px;
+line-height: 12px;
+letter-spacing: 0.05em;
+text-transform: uppercase;
+color: #FFFFFF;
+padding-left: 22px;
+position: relative;
+margin-left: 20px;
+
+:before{
+ content: '';
+ display: block;
+ position: absolute;
+ left: 0;
+ top: 0;
+ width:14px;
+ height: 14px;
+ ${({ active }) => (active
+ ? css`
+ background: url(/images/filter-white.svg) no-repeat;`
+ : css`
+ background: url(/images/filter-gray.svg) no-repeat;`)}
+ background-size: 14px 14px;
+}
+`
+
+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);
+`
diff --git a/src/features/HomePage/hooks.tsx b/src/features/HomePage/hooks.tsx
index c8b11b82..6f14c4d1 100644
--- a/src/features/HomePage/hooks.tsx
+++ b/src/features/HomePage/hooks.tsx
@@ -35,7 +35,7 @@ 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)
@@ -57,21 +57,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],
- )
+
+ },
+ ), [selectedDate, queryParams])
useEffect(() => {
if (client.name === ClientNames.Facr) {
diff --git a/src/features/UserFavorites/styled.tsx b/src/features/UserFavorites/styled.tsx
index bb588989..85bb5e40 100644
--- a/src/features/UserFavorites/styled.tsx
+++ b/src/features/UserFavorites/styled.tsx
@@ -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`
diff --git a/src/requests/getMatches/getHomeMatches.tsx b/src/requests/getMatches/getHomeMatches.tsx
index f76c9aad..f1519251 100644
--- a/src/requests/getMatches/getHomeMatches.tsx
+++ b/src/requests/getMatches/getHomeMatches.tsx
@@ -1,4 +1,5 @@
import { PROCEDURES, API_ROOT } from 'config'
+import isEmpty from 'lodash/isEmpty'
import { client } from 'config/clients'
@@ -8,10 +9,20 @@ import { getMatchesPreviews } from './getPreviews'
const proc = PROCEDURES.get_matches
+export type TQueryParams = {
+ arena?: Array,
+ division?: Array,
+ gender?: Array,
+ main_team?: Array,
+ round?: Array,
+ youth_age?: Array,
+}
+
type Args = {
date: string,
limit: number,
offset: number,
+ queryParams?: TQueryParams,
timezoneOffset: number,
}
@@ -19,16 +30,22 @@ export const getHomeMatches = async ({
date,
limit,
offset,
+ queryParams,
timezoneOffset,
}: Args): Promise => {
- 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,
+ youth_age: !isEmpty(queryParams?.youth_age) ? queryParams?.youth_age : undefined,
...client.requests?.[proc],
},
}
diff --git a/src/requests/getMatches/types.tsx b/src/requests/getMatches/types.tsx
index 15e8e9ce..af52baae 100644
--- a/src/requests/getMatches/types.tsx
+++ b/src/requests/getMatches/types.tsx
@@ -8,11 +8,20 @@ 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 +31,8 @@ export type SportInfo = {
export type Match = {
access: boolean,
+ /** Стадион */
+ arena: TDefaultType | null,
/** тип трансляции */
c_type_broadcast: number,
calc: boolean,
@@ -39,6 +50,8 @@ export type Match = {
live: boolean,
preview?: string,
previewURL?: string,
+ /** Раунд */
+ round?: TDefaultType,
sport: SportTypes,
sport_info: SportInfo,
/** наличие завершенного hls стрима */