diff --git a/src/config/lexics/indexLexics.tsx b/src/config/lexics/indexLexics.tsx index 96d6b091..e4031970 100644 --- a/src/config/lexics/indexLexics.tsx +++ b/src/config/lexics/indexLexics.tsx @@ -44,6 +44,7 @@ const buyMatchPopupLexics = { buy_subscription: 13565, change_card: 13564, choose_subscription: 13563, + completed: 14072, description_all_season_matches: 15069, description_all_team_matches: 15070, description_away_team_matches: 15072, @@ -86,6 +87,7 @@ const sportsPopup = { export const indexLexics = { add_to_favorites: 14967, add_to_favorites_error: 12943, + all_competitions: 17926, all_matches_shown: 13386, all_sports: 13824, available_matches_shown: 13385, @@ -100,6 +102,7 @@ export const indexLexics = { futsal: 17670, game_finished: 13026, game_time: 13029, + games: 15773, gender_female: 9648, gender_female_long: 13374, gender_male: 9647, @@ -133,6 +136,7 @@ export const indexLexics = { team: 14973, to_home: 13376, tournament: 14974, + upcoming: 17925, user_account: 12928, volleyball: 9761, watch_from_beginning: 13021, diff --git a/src/features/HeaderFilters/store/hooks/index.tsx b/src/features/HeaderFilters/store/hooks/index.tsx index c2feba70..121f5ee2 100644 --- a/src/features/HeaderFilters/store/hooks/index.tsx +++ b/src/features/HeaderFilters/store/hooks/index.tsx @@ -22,8 +22,15 @@ export const useFilters = () => { serialize: serializeDate, validator: isValidDate, }) - const [selectedSport, setSelectedSport] = useState('all_sports') - const [selectedLeague, setSelectedLeague] = useState('all_leagues') + const [allFilters, setAllFilters] = useState({ + selectedFilters: [], + selectedLeague: [], + selectedSports: [], + }) + const [selectedSport, setSelectedSport] = useState(['all_sports']) + const [selectedLeague, setSelectedLeague] = useState(['all_competitions']) + const [selectedFilters, setSelectedFilters] = useState>([]) + const [isShowTournament, setIsShowTournament] = useState(true) const isTodaySelected = isToday(selectedDate) @@ -42,16 +49,30 @@ export const useFilters = () => { ]) const store = useMemo(() => ({ + allFilters, + isShowTournament, isTodaySelected, + setAllFilters, selectedDate, + selectedFilters, + selectedLeague, selectedSport, + setIsShowTournament, setSelectedDate, + setSelectedFilters, setSelectedSport, }), [ + allFilters, + isShowTournament, isTodaySelected, + setAllFilters, selectedDate, + selectedFilters, + selectedLeague, selectedSport, + setIsShowTournament, setSelectedDate, + setSelectedFilters, setSelectedSport, ]) diff --git a/src/features/HomePage/components/HeaderFilters/index.tsx b/src/features/HomePage/components/HeaderFilters/index.tsx index 956d139d..96be28fe 100644 --- a/src/features/HomePage/components/HeaderFilters/index.tsx +++ b/src/features/HomePage/components/HeaderFilters/index.tsx @@ -1,11 +1,23 @@ import { SportsFilter } from 'features/SportsFilter' import { useHeaderFiltersStore } from 'features/HeaderFilters' +import { T9n } from 'features/T9n' import { SelectFilter } from 'components/SelectFilter' -import { ScHeaderFilters } from './styled' +import { ScHeaderFilters, ScFilterItemsWrap, ScFilterItem } from './styled' export const HeaderFilters = () => { - const { selectedSport, setSelectedSport } = useHeaderFiltersStore() + const { + selectedFilters, + setSelectedFilters, + } = useHeaderFiltersStore() + + const isActiveFilter = (filterItem: string) => selectedFilters.indexOf(filterItem) >= 0 + + const checkFilter = (item: string) => { + isActiveFilter(item) + ? setSelectedFilters((prev) => prev.filter((check) => item !== check)) + : setSelectedFilters([...selectedFilters, item]) + } return ( @@ -13,8 +25,28 @@ export const HeaderFilters = () => { console.log(1)} open={false} - selectItem='all_sports' + selectItem='all_competitions' /> + + checkFilter('live')} + > + + + checkFilter('upcoming')} + > + + + checkFilter('completed')} + > + + + ) } diff --git a/src/features/HomePage/components/HeaderFilters/styled.tsx b/src/features/HomePage/components/HeaderFilters/styled.tsx index eb1526d4..c415f80c 100644 --- a/src/features/HomePage/components/HeaderFilters/styled.tsx +++ b/src/features/HomePage/components/HeaderFilters/styled.tsx @@ -3,4 +3,39 @@ import styled from 'styled-components/macro' export const ScHeaderFilters = styled.div` display: flex; flex-direction: row; + margin-bottom: 23px; + + .activeLive { + color: #ffffff; + background-color: #cc0000; + } + + .activeButton { + color: #000000; + background-color: #ffffff; + } +` + +export const ScFilterItemsWrap = styled.div` + display: flex; + flex-direction: row; + width: 100%; + justify-content: flex-end; +` + +type Props = { + background?: string, + color?: string, +} + +export const ScFilterItem = styled.div` + text-transform: uppercase; + font-weight: 700; + font-size: 14px; + color: rgba(255, 255, 255, 0.5); + margin: 0 10px; + cursor: pointer; + border-radius: 20px; + text-align: center; + padding: 6px 16px; ` diff --git a/src/features/HomePage/index.tsx b/src/features/HomePage/index.tsx index c6c9c2e8..442200e0 100644 --- a/src/features/HomePage/index.tsx +++ b/src/features/HomePage/index.tsx @@ -29,7 +29,7 @@ const Home = () => {
- + {isMobileDevice ? null : }
diff --git a/src/features/Matches/components/MatchesList/index.tsx b/src/features/Matches/components/MatchesList/index.tsx index e5376b7a..61468951 100644 --- a/src/features/Matches/components/MatchesList/index.tsx +++ b/src/features/Matches/components/MatchesList/index.tsx @@ -5,6 +5,7 @@ import isEmpty from 'lodash/isEmpty' import type { Match } from 'features/Matches/hooks' import { MatchesSlider } from 'features/MatchesSlider' import { MatchesGrid } from 'features/MatchesGrid' +import { TournamentList } from 'features/TournamentList' import { T9n } from 'features/T9n' import { Title, Section } from '../../styled' @@ -12,6 +13,7 @@ import { Title, Section } from '../../styled' const matchesComponents = { grid: MatchesGrid, slider: MatchesSlider, + tournaments: TournamentList, } type Props = { diff --git a/src/features/Matches/helpers/prepareMatches.tsx b/src/features/Matches/helpers/prepareMatches.tsx index 5f421fa0..cf3c83fa 100644 --- a/src/features/Matches/helpers/prepareMatches.tsx +++ b/src/features/Matches/helpers/prepareMatches.tsx @@ -15,6 +15,7 @@ const prepareMatch = (match: Match) => { date: matchDate, has_video, id, + is_finished, live, preview, previewURL, @@ -33,6 +34,7 @@ const prepareMatch = (match: Match) => { formattedDate: format(date, 'dd.MM.yy'), hasVideo: has_video, id, + is_finished, live, preview, previewURL, diff --git a/src/features/MatchesGrid/index.tsx b/src/features/MatchesGrid/index.tsx index 75527e8a..e8431de7 100644 --- a/src/features/MatchesGrid/index.tsx +++ b/src/features/MatchesGrid/index.tsx @@ -2,11 +2,11 @@ import { memo } from 'react' import { useRouteMatch } from 'react-router-dom' import { PAGES } from 'config/pages' -import { isMobileDevice } from 'config/userAgent' import { MatchCard } from 'features/MatchCard' import { TournamentList } from 'features/TournamentList' import type { Match } from 'features/Matches' +import { useHeaderFiltersStore } from 'features/HeaderFilters' import { Wrapper } from './styled' @@ -16,14 +16,24 @@ type MatchesGridProps = { export const MatchesGrid = memo(({ matches }: MatchesGridProps) => { const isHomePage = useRouteMatch(PAGES.home)?.isExact + const { selectedFilters, isShowTournament } = useHeaderFiltersStore() + + const filteredMatches = selectedFilters?.length + ? matches.filter((match) => ( + match.live && selectedFilters.indexOf('live') >= 0) + || (selectedFilters.indexOf('upcoming') >= 0 && match.date > new Date()) + || (selectedFilters.indexOf('completed') >= 0 && match.is_finished)) + : matches return ( - {isHomePage && isMobileDevice - ? - : (matches.map((match) => ( + {isHomePage && isShowTournament ? ( + + ) : ( + filteredMatches.map((match) => ( - )))} + )) + )} ) }) diff --git a/src/features/SportsFilter/components/SelectSport/index.tsx b/src/features/SportsFilter/components/SelectSport/index.tsx index ed162520..a574598c 100644 --- a/src/features/SportsFilter/components/SelectSport/index.tsx +++ b/src/features/SportsFilter/components/SelectSport/index.tsx @@ -5,7 +5,7 @@ import { ScSportsFilter, ScArrow } from './styled' type SportsFilterProps = { onModalOpen: () => void, open: boolean, - sport: string, + sport: Array, } export const SelectSport = ({ @@ -14,7 +14,9 @@ export const SelectSport = ({ sport, }: SportsFilterProps) => ( - + +   + {sport.length > 1 ? `+ ${sport.length - 1}` : ''} ) diff --git a/src/features/SportsFilter/components/SelectSportPopup/index.tsx b/src/features/SportsFilter/components/SelectSportPopup/index.tsx index 87a368af..2f02a2d5 100644 --- a/src/features/SportsFilter/components/SelectSportPopup/index.tsx +++ b/src/features/SportsFilter/components/SelectSportPopup/index.tsx @@ -6,6 +6,7 @@ import { ScHeaderTitle, ScHeaderGroup, ScSport, + ScSportName, } from './styled' const sports = [ @@ -21,7 +22,7 @@ type Props = { isOpen: boolean, onModalClose: () => void, onSportClick: (sport: string) => void, - selectedSport: string, + selectedSport: Array, } export const SelectSportPopup = ({ isOpen, @@ -41,10 +42,12 @@ export const SelectSportPopup = ({ onSportClick(sport)} - className={selectedSport === sport ? 'active' : ''} - active={selectedSport === sport} + className={selectedSport.indexOf(sport) >= 0 ? 'active' : ''} + active={selectedSport.indexOf(sport) >= 0} > - + + + ))} diff --git a/src/features/SportsFilter/components/SelectSportPopup/styled.tsx b/src/features/SportsFilter/components/SelectSportPopup/styled.tsx index 63bed564..afc23c84 100644 --- a/src/features/SportsFilter/components/SelectSportPopup/styled.tsx +++ b/src/features/SportsFilter/components/SelectSportPopup/styled.tsx @@ -151,7 +151,10 @@ export const ScModal = styled(BaseModal)` background-color: rgba(0, 0, 0, 0.7); ${ModalWindow} { - min-width: 286px; + position: absolute; + top: 200px; + left: 75px; + min-width: 200px; max-height: 290px; background-color: #333333; border-radius: 0px; @@ -162,6 +165,7 @@ export const ScModal = styled(BaseModal)` ${isMobileDevice ? css` + position: static; min-width: 280px; max-height: 250px; height: auto; @@ -175,8 +179,10 @@ export const ScHeaderTitle = styled.span` font-size: 10px; line-height: 24px; color: #FFFFFF; + padding-left: 30px; ${isMobileDevice ? css` + padding: 0; font-size: 10px; line-height: 20px; @@ -190,12 +196,13 @@ export const ScHeaderTitle = styled.span` export const ScHeaderGroup = styled.div` display: flex; flex-direction: row; - justify-content: center; - padding: 10px; + padding: 10px 0; border-bottom: 1px solid #505050; ${isMobileDevice ? css` + padding: 10px; + justify-content: center; font-size: 10px; line-height: 20px; @@ -208,7 +215,13 @@ export const ScHeaderGroup = styled.div` export const ScBody = styled.div` display: flex; flex-direction: column; - padding: 0 15px 23px 15px; + padding-bottom: 10px; + + ${isMobileDevice + ? css` + padding: 0 15px 23px 15px; + ` + : ''}; ` type SportProps = { @@ -216,11 +229,28 @@ type SportProps = { } export const ScSport = styled.div` display: flex; - justify-content: center; text-transform: uppercase; font-size: 10px; font-weight: 700; + height: 30px; + width: 100%; opacity: ${({ active }) => (active ? 1 : 0.5)}; - margin-top: 18px; + /* margin-left: 30px; */ + align-items: center; cursor: pointer; + + ${isMobileDevice + ? css` + justify-content: center; + ` + : ''}; + + :hover { + background-color: rgba(255, 255, 255, 0.2); + color: #FFFFFF; + } +` + +export const ScSportName = styled.span` + padding-left: 30px; ` diff --git a/src/features/SportsFilter/index.tsx b/src/features/SportsFilter/index.tsx index 16afd710..d97ad31a 100644 --- a/src/features/SportsFilter/index.tsx +++ b/src/features/SportsFilter/index.tsx @@ -6,11 +6,19 @@ import { SelectSport } from './components/SelectSport' import { SelectSportPopup } from './components/SelectSportPopup' export const SportsFilter = () => { - const { selectedSport, setSelectedSport } = useHeaderFiltersStore() + const { selectedSport, setSelectedSport, setIsShowTournament } = useHeaderFiltersStore() const [isOpen, setIsOpen] = useState(false) const onSportClick = (sport: string) => { - setSelectedSport(sport) + if (sport === 'all_sports') { + setSelectedSport([sport]) + } else { + setSelectedSport((prev) => [ + ...prev.filter((item) => item !== 'all_sports'), + sport, + ]) + } + setIsShowTournament(true) setIsOpen(false) } diff --git a/src/features/TournamentList/components/CollapseTournament/index.tsx b/src/features/TournamentList/components/CollapseTournament/index.tsx new file mode 100644 index 00000000..ca9dd1e6 --- /dev/null +++ b/src/features/TournamentList/components/CollapseTournament/index.tsx @@ -0,0 +1,99 @@ +import { ProfileTypes } from 'config' + +import { getSportLexic } from 'helpers' + +import { T9n } from 'features/T9n' +import { useUserFavoritesStore } from 'features/UserFavorites/store' +import { Icon } from 'features/Icon' +import { useHeaderFiltersStore } from 'features/HeaderFilters' + +import { SportIcon } from 'components/SportIcon/SportIcon' + +import { TournamentProps } from '../TournamentMobile/index' + +import { + CardWrapperOuter, + CardWrapper, + CountMatches, + FavoriteSign, + FirstInfo, + Info, + LiveSign, + MatchTimeInfo, + TournamentLogo, + PreviewWrapper, + TournamentName, + CountryFlag, + SecondaryInfo, + HoverFrame, +} from './styled' + +export const CollapseTournament = ({ + tournament, + tournamentMatches, +}: TournamentProps) => { + const { setSelectedSport, setIsShowTournament } = useHeaderFiltersStore() + const { isInFavorites } = useUserFavoritesStore() + const { + countryId, + live, + sportType, + } = tournament + + const tournamentInFavorites = isInFavorites( + ProfileTypes.TOURNAMENTS, + tournament.id, + ) + + const handleClick = () => { + const sportName = getSportLexic(sportType) + setIsShowTournament(false) + setSelectedSport([sportName]) + } + + return ( + handleClick()}> + + + + + + {live && ( + + + + )} + + + + + + + + + + + {tournamentInFavorites && ( + + + + )} + + + {tournamentMatches.length} +   + + + + + + ) +} diff --git a/src/features/TournamentList/components/CollapseTournament/styled.tsx b/src/features/TournamentList/components/CollapseTournament/styled.tsx new file mode 100644 index 00000000..e7318fef --- /dev/null +++ b/src/features/TournamentList/components/CollapseTournament/styled.tsx @@ -0,0 +1,215 @@ +import styled, { css } from 'styled-components/macro' + +import { devices } from 'config/devices' +import { isMobileDevice } from 'config/userAgent' + +import { Name } from 'features/Name' +import { ProfileLogo } from 'features/ProfileLogo' + +export const CardWrapperOuter = styled.li.attrs({ + tabIndex: 0, +})` + padding-top: 100%; + position: relative; + ${isMobileDevice + ? css` + width: 100%; + padding-top: 0; + height: 90px; + margin-bottom: 10px; + + @media screen and (orientation: landscape){ + width: 49%; + :nth-child(odd){ + margin-right: 10px; + } + } + ` + : ''}; +` + +export const CardWrapper = styled.div` + position: absolute; + top: 0; + left: 0; + bottom: 0; + right: 0; + padding-bottom: 0.75rem; + border-radius: 2px; + background: linear-gradient(236.13deg, rgba(53, 96, 225, 0.56) -4.49%, rgba(0, 0, 0, 0) 98.29%), #3F3F3F; + cursor: pointer; + ${isMobileDevice + ? css` + width: 100%; + height: 90px; + padding-bottom: 0; + ` + : ''}; +` + +export const HoverFrame = styled.div` + position: absolute; + min-width: 100%; + min-height: 100%; + border-radius: 2px; + border: 2px solid transparent; + transition: border 0.5s ease-out; + z-index: 2; + + &:hover { + border: 2px solid #fff + } +` + +export const PreviewWrapper = styled.div` + position: relative; + display: flex; + justify-content: center; + width: 100%; + height: 60%; + ${isMobileDevice + ? css` + width: 50%; + height: 100%; + ` + : ''}; +` + +export const MatchTimeInfo = styled.div` + width: 100%; + position: absolute; + top: 0.519rem; + padding: 0 0.519rem; + display: flex; + flex-direction: row; +` + +type MatchDateProps = { + isHomePage?: boolean, +} + +export const MatchDate = styled.div` + width: fit-content; + height: 0.9rem; + border-radius: 2px; + padding: ${({ isHomePage }) => (!isHomePage ? '0 0.27rem' : '')}; + font-weight: bold; + font-size: 0.472rem; + line-height: 0.567rem; + letter-spacing: 0.05em; + text-transform: uppercase; + display: flex; + align-items: center; + justify-content: center; + white-space: nowrap; + color: white; + background-color: #6D6D6D; + + @media ${devices.tablet} { + padding: ${({ isHomePage }) => (!isHomePage ? '0.27rem 0.36rem' : '')}; + } + ${isMobileDevice + ? css` + height: 15px; + font-size: 8px; + ` + : ''}; +` + +export const LiveSign = styled(MatchDate)` + background-color: #CC0000; + margin-left: auto; +` + +export const Time = styled.span` + margin: 0 0.2rem; +` + +export const Info = styled.div` + display: flex; + flex-direction: column; + padding: 0.85rem 0.472rem 0 0.519rem; + color: #fff; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + ${isMobileDevice + ? css` + position: absolute; + top: 0; + left: 50%; + width: 50%; + height: 100%; + padding: 13px 12px 13px 10px; + ` + : ''}; +` + +export const FirstInfo = styled.div` + display: flex; + justify-content: center; + align-items: center; + margin: 5px 0; +` + +export const SecondaryInfo = styled.div` + display: flex; + justify-content: center; + align-items: center; +` + +export const CountryFlag = styled.img` + width: 0.71rem; + height: 0.75rem; + margin-left: 0.567rem; + object-fit: contain; + object-position: bottom; + ${isMobileDevice + ? css` + width: 12px; + height: 8px; + margin-left: 3.5px; + ` + : ''}; +` + +export const CountMatches = styled.span` + display: block; + text-align: center; + font-weight: 400; + font-size: 10px; + line-height: 16px; + color: #FFFFFF; +` + +export const TournamentName = styled(Name)` + font-weight: 600; + font-size: 13px; + line-height: 24px; + color: #ffffff; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +` + +export const TournamentLogo = styled(ProfileLogo)` + padding: 10px; + max-height: 100%; +` + +type FavoriteSignProps = { + color?: string, + marginLeft?: number, +} + +export const FavoriteSign = styled.span` + margin-left: ${({ marginLeft = 9 }) => marginLeft}px; + color: ${({ color }) => color}; + display: flex; + transform: translateY(25%); + justify-content: center; + align-items: center; + width: 8px; + height: 8px; + margin-bottom: 7px; +` diff --git a/src/features/TournamentList/components/Tournament/index.tsx b/src/features/TournamentList/components/TournamentMobile/index.tsx similarity index 98% rename from src/features/TournamentList/components/Tournament/index.tsx rename to src/features/TournamentList/components/TournamentMobile/index.tsx index c0093e31..bdd1ce0a 100644 --- a/src/features/TournamentList/components/Tournament/index.tsx +++ b/src/features/TournamentList/components/TournamentMobile/index.tsx @@ -35,7 +35,7 @@ export type TournamentProps = { tournamentMatches: Array, } -export const Tournament = ({ +export const TournamentMobile = ({ tournament, tournamentMatches, }: TournamentProps) => { diff --git a/src/features/TournamentList/components/Tournament/styled.tsx b/src/features/TournamentList/components/TournamentMobile/styled.tsx similarity index 100% rename from src/features/TournamentList/components/Tournament/styled.tsx rename to src/features/TournamentList/components/TournamentMobile/styled.tsx diff --git a/src/features/TournamentList/hooks.tsx b/src/features/TournamentList/hooks.tsx index 0c4a8854..0345029b 100644 --- a/src/features/TournamentList/hooks.tsx +++ b/src/features/TournamentList/hooks.tsx @@ -7,15 +7,12 @@ import { useHeaderFiltersStore } from 'features/HeaderFilters' export const useTournaments = (matches: Array) => { const { selectedSport } = useHeaderFiltersStore() - const compareSport = (match: Match, sportName: string) => { - if (sportName === 'all_sports') { + const compareSport = (match: Match, sportNames: Array) => { + if (sportNames[0] === 'all_sports') { return true } const sport = getSportLexic(match.sportType) - if (sportName.indexOf('_popup') !== -1) { - return sport === sportName.replace('_popup', '') - } - return sport === sportName + return (sportNames.indexOf(sport) >= 0 || sportNames.indexOf(`${sport}_popup`) >= 0) } const tournamentSort: Array = [] diff --git a/src/features/TournamentList/index.tsx b/src/features/TournamentList/index.tsx index d9181699..9bd29ad7 100644 --- a/src/features/TournamentList/index.tsx +++ b/src/features/TournamentList/index.tsx @@ -1,36 +1,68 @@ +import { useRouteMatch } from 'react-router-dom' + import type { Match } from 'features/Matches' +import { MatchCard } from 'features/MatchCard' import type { TournamentType } from 'requests/getMatches/types' -import { Tournament } from './components/Tournament' +import { PAGES } from 'config/pages' +import { isMobileDevice } from 'config/userAgent' + +import { TournamentMobile } from './components/TournamentMobile' import { useTournaments } from './hooks' +import { CollapseTournament } from './components/CollapseTournament' type TournamentTypeProps = { matches: Array, } export type TournamentListProps = { - [key: number]:{tournament: TournamentType & { - countryId: number, - live: boolean, - sportType: number, - }, - tournamentMatches: Array, - }, + [key: number]: { + tournament: TournamentType & { + countryId: number, + live: boolean, + sportType: number, + } + tournamentMatches: Array, + } } export const TournamentList = ({ matches }: TournamentTypeProps) => { const { tournaments, tournamentSort } = useTournaments(matches) + const isHomePage = useRouteMatch(PAGES.home)?.isExact - return ( - <> - {tournamentSort?.map((id) => ( - - ))} - - ) + switch (true) { + case isMobileDevice && isHomePage: + return ( + <> + {tournamentSort?.map((id) => ( + + ))} + + ) + case isHomePage && matches.length <= 12: + return ( + <> + {tournamentSort?.map((id) => ( + + ))} + + ) + default: + return ( + <> + {matches.map((match) => ( + + ))} + + ) + } } diff --git a/src/requests/getMatches/types.tsx b/src/requests/getMatches/types.tsx index 3aee53cb..a0c8369d 100644 --- a/src/requests/getMatches/types.tsx +++ b/src/requests/getMatches/types.tsx @@ -21,6 +21,8 @@ export type Match = { /** наличие mp4 видео */ has_video: boolean, id: number, + /** матч закончен */ + is_finished?: boolean, /** наличие hls стрима */ live: boolean, preview?: string,