From 291d44c858ba739c3c6b1ad45498869037371a97 Mon Sep 17 00:00:00 2001 From: alexnofoget Date: Mon, 12 Sep 2022 09:56:09 +0300 Subject: [PATCH] feat(#ott-2698): add filters popup --- public/images/boldArrowGray.svg | 3 + public/images/boldArrowWhite.svg | 3 + public/images/filter-gray.svg | 3 + public/images/filter-white.svg | 3 + public/images/likeDisable.svg | 6 + src/config/lexics/indexLexics.tsx | 11 + .../components/FinishedMatch/index.tsx | 3 +- src/features/MatchPage/store/hooks/index.tsx | 103 +++++++++ .../MatchPage/store/hooks/useFitersPopup.tsx | 101 +++++++++ .../MatchPage/store/hooks/useTabEvents.tsx | 80 +++++++ src/features/MatchPage/styled.tsx | 1 + .../components/EventsList/index.tsx | 11 +- .../components/FiltersPopup/index.tsx | 145 +++++++++++++ .../components/FiltersPopup/styled.tsx | 199 ++++++++++++++++++ .../components/TabEvents/index.tsx | 175 ++++++++------- .../components/TabEvents/styled.tsx | 156 +++++++++++--- src/features/MatchSidePlaylists/hooks.tsx | 5 + src/features/MatchSidePlaylists/index.tsx | 2 - .../MultiSourcePlayer/hooks/index.tsx | 17 +- src/features/MultiSourcePlayer/index.tsx | 4 +- src/features/Name/index.tsx | 2 +- .../components/YoutubePlayer/index.tsx | 4 +- src/features/StreamPlayer/index.tsx | 12 +- 23 files changed, 916 insertions(+), 133 deletions(-) create mode 100644 public/images/boldArrowGray.svg create mode 100644 public/images/boldArrowWhite.svg create mode 100644 public/images/filter-gray.svg create mode 100644 public/images/filter-white.svg create mode 100644 public/images/likeDisable.svg create mode 100644 src/features/MatchPage/store/hooks/useFitersPopup.tsx create mode 100644 src/features/MatchPage/store/hooks/useTabEvents.tsx create mode 100644 src/features/MatchSidePlaylists/components/FiltersPopup/index.tsx create mode 100644 src/features/MatchSidePlaylists/components/FiltersPopup/styled.tsx diff --git a/public/images/boldArrowGray.svg b/public/images/boldArrowGray.svg new file mode 100644 index 00000000..ed54cdcd --- /dev/null +++ b/public/images/boldArrowGray.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/images/boldArrowWhite.svg b/public/images/boldArrowWhite.svg new file mode 100644 index 00000000..20386d85 --- /dev/null +++ b/public/images/boldArrowWhite.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/images/filter-gray.svg b/public/images/filter-gray.svg new file mode 100644 index 00000000..8438dc4f --- /dev/null +++ b/public/images/filter-gray.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/images/filter-white.svg b/public/images/filter-white.svg new file mode 100644 index 00000000..0385b4f8 --- /dev/null +++ b/public/images/filter-white.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/images/likeDisable.svg b/public/images/likeDisable.svg new file mode 100644 index 00000000..7335e996 --- /dev/null +++ b/public/images/likeDisable.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/config/lexics/indexLexics.tsx b/src/config/lexics/indexLexics.tsx index f58b3483..ad395906 100644 --- a/src/config/lexics/indexLexics.tsx +++ b/src/config/lexics/indexLexics.tsx @@ -38,6 +38,16 @@ const matchPopupLexics = { watching_now: 16041, } +const filterPopup = { + all_actions: 547, + apply_filter: 15117, + episodes_selected: 19779, + filter: 8385, + filter_match_events: 15166, + watch_all: 2454, + +} + const confirmPopup = { consent: 15431, i_agree: 15430, @@ -163,6 +173,7 @@ export const indexLexics = { watch_from_last_pause: 13022, watch_now: 13020, + ...filterPopup, ...confirmPopup, ...highlightsPageLexic, ...preferencesPopupLexics, diff --git a/src/features/MatchPage/components/FinishedMatch/index.tsx b/src/features/MatchPage/components/FinishedMatch/index.tsx index 4d588a3c..9d11218a 100644 --- a/src/features/MatchPage/components/FinishedMatch/index.tsx +++ b/src/features/MatchPage/components/FinishedMatch/index.tsx @@ -14,7 +14,7 @@ import { MatchDescription } from '../MatchDescription' import { useMatchPageStore } from '../../store' export const FinishedMatch = () => { - const { profile } = useMatchPageStore() + const { isOpenPopup, profile } = useMatchPageStore() const { chapters, closeSettingsPopup, @@ -44,6 +44,7 @@ export const FinishedMatch = () => { {!isEmpty(chapters) && ( { open: showProfileCard, } = useToggle(true) + const { + activeEvents, + activeFirstTeamPlayers, + activeSecondTeamPlayers, + applyFilters, + close: closePopup, + countOfFilters, + filters, + isEmptyFilters, + isOpen: isOpenPopup, + resetEvents, + resetPlayers, + toggle: togglePopup, + toggleActiveEvents, + toggleActivePlayers, + } = useFiltersPopup() + useEffect(() => { getMatchInfo(sportType, matchId).then(setMatchProfile) }, [sportType, matchId]) @@ -79,17 +103,96 @@ export const useMatchPage = () => { const { tournamentData } = useTournamentData(matchProfile?.tournament.id ?? null) + const filteredEvents = useMemo(() => { + switch (true) { + case (!isEmpty(filters.events) && !isEmpty(filters.players)): + return filter(events, (event) => includes(filters.players, event.p) + && includes(filters.events, event.l)) + case (!isEmpty(filters.players)): + return filter(events, (event) => includes(filters.players, event.p)) + case (!isEmpty(filters.events)): + return filter(events, (event) => includes(filters.events, event.l)) + default: return events + } + }, [events, filters]) + + const [plaingOrder, setPlaingOrder] = useState(0) + const [isPlayFilterEpisodes, setIsPlayinFiltersEpisodes] = useState(false) + + const { + activeStatus, + episodesToPlay, + isLiveMatch, + likeImage, + likeToggle, + reversedGroupEvents, + setReversed, + setUnreversed, + } = useTabEvents({ events: filteredEvents, profile }) + + useEffect(() => { + if (plaingOrder > episodesToPlay.length) setPlaingOrder(0) + }, [plaingOrder, episodesToPlay]) + + const playNextEpisode = (order?: number) => { + const isLastEpisode = plaingOrder === episodesToPlay.length + + const currentOrder = order === 0 ? order : plaingOrder + if (isLastEpisode) { + setIsPlayinFiltersEpisodes(false) + + return + } + handlePlaylistClick(episodesToPlay[currentOrder]) + setPlaingOrder(currentOrder + 1) + } + const playEpisodes = () => { + setIsPlayinFiltersEpisodes(true) + playNextEpisode(0) + } + + const disablePlayingEpisodes = () => { + setIsPlayinFiltersEpisodes(false) + } + return { + activeEvents, + activeFirstTeamPlayers, + activeSecondTeamPlayers, + activeStatus, + applyFilters, + closePopup, + countOfFilters, + disablePlayingEpisodes, events, + filteredEvents, handlePlaylistClick, hideProfileCard, + isEmptyFilters, + isLiveMatch, + isOpenPopup, + isPlayFilterEpisodes, isStarted, + likeImage, + likeToggle, matchPlaylists, + playEpisodes, + playNextEpisode, profile, profileCardShown, + resetEvents, + resetPlayers, + reversedGroupEvents, selectedPlaylist, setFullMatchPlaylistDuration, + setIsPlayinFiltersEpisodes, + setPlaingOrder, + setReversed, + setUnreversed, showProfileCard, + toggleActiveEvents, + toggleActivePlayers, + togglePopup, tournamentData, } } diff --git a/src/features/MatchPage/store/hooks/useFitersPopup.tsx b/src/features/MatchPage/store/hooks/useFitersPopup.tsx new file mode 100644 index 00000000..78fa4e06 --- /dev/null +++ b/src/features/MatchPage/store/hooks/useFitersPopup.tsx @@ -0,0 +1,101 @@ +import { useMemo, useState } from 'react' + +import includes from 'lodash/includes' +import filter from 'lodash/filter' +import isEmpty from 'lodash/isEmpty' +import size from 'lodash/size' + +type TTogglePlayers = { + id: Number, + team: String, +} + +type TFilters = { + events: Array, + players: Array, +} + +export const useFiltersPopup = () => { + const [isOpen, setIsOpen] = useState(false) + const [activeEvents, setActiveEvents] = useState>([]) + const [activeFirstTeamPlayers, setActiveFirstTeamPlayers] = useState>([]) + const [activeSecondTeamPlayers, setActiveSecondTeamPlayers] = useState>([]) + const [activeFilters, setActiveFilters] = useState({ events: [], players: [] }) + + const toggle = () => { + setIsOpen(!isOpen) + } + + const close = () => { + setIsOpen(false) + } + + const toggleActiveEvents = (id: number) => () => { + setActiveEvents(includes(activeEvents, id) + ? [...filter(activeEvents, (item) => item !== id)] + : [...activeEvents, id]) + } + + const toggleActivePlayers = ({ id, team }: TTogglePlayers) => () => { + const teamState = team === 'team1' + ? activeFirstTeamPlayers + : activeSecondTeamPlayers + + const setterTeamState = team === 'team1' + ? setActiveFirstTeamPlayers + : setActiveSecondTeamPlayers + + setterTeamState(includes(teamState, id) + ? [...filter(teamState, (item) => item !== id)] + : [...teamState, id]) + } + + const resetPlayers = (team: string) => () => { + const teamState = team === 'team1' + ? activeFirstTeamPlayers + : activeSecondTeamPlayers + + const setterTeamState = team === 'team1' + ? setActiveFirstTeamPlayers + : setActiveSecondTeamPlayers + + if (isEmpty(teamState)) return + setterTeamState([]) + } + + const resetEvents = () => { + if (isEmpty(activeEvents)) return + setActiveEvents([]) + } + + const applyFilters = () => { + setActiveFilters({ + events: [...activeEvents], + players: [...activeFirstTeamPlayers, ...activeSecondTeamPlayers], + }) + close() + } + + const isEmptyFilters = useMemo(() => ( + isEmpty(activeFilters.events) && isEmpty(activeFilters.players)), [activeFilters]) + + const countOfFilters = useMemo(() => ( + size(activeFilters.events) + size(activeFilters.players)), [activeFilters]) + + return { + activeEvents, + activeFirstTeamPlayers, + activeSecondTeamPlayers, + applyFilters, + close, + countOfFilters, + filters: activeFilters, + isEmptyFilters, + isOpen, + resetEvents, + resetPlayers, + toggle, + toggleActiveEvents, + toggleActivePlayers, + } +} diff --git a/src/features/MatchPage/store/hooks/useTabEvents.tsx b/src/features/MatchPage/store/hooks/useTabEvents.tsx new file mode 100644 index 00000000..64f7cfbf --- /dev/null +++ b/src/features/MatchPage/store/hooks/useTabEvents.tsx @@ -0,0 +1,80 @@ +import { + useCallback, + useMemo, + useState, +} from 'react' + +import map from 'lodash/map' +import groupBy from 'lodash/groupBy' +import reverse from 'lodash/reverse' +import filter from 'lodash/filter' +import values from 'lodash/values' +import flatten from 'lodash/flatten' +import { Events, MatchInfo } from 'requests' +import { useToggle } from 'hooks' +import { EventPlaylistOption } from 'features/MatchPage/types' + +type TPropsTabEvents = { + events?: Events, + profile?: MatchInfo, +} + +export const useTabEvents = ({ + events, + profile, +}: TPropsTabEvents) => { + const [likesOnly, setLikesOnly] = useState(false) + + const { + close: setUnreversed, + isOpen: areEventsReversed, + open: setReversed, + } = useToggle() + + const likeToggle = useCallback(() => setLikesOnly((state) => !state), []) + const likeImage = likesOnly ? '/images/like-active-icon.svg' : '/images/likeDisable.svg' + + const isLiveMatch = profile?.live + const reverseStatus = (areEventsReversed || isLiveMatch) && (areEventsReversed !== isLiveMatch) + const activeStatus = isLiveMatch ? areEventsReversed : !areEventsReversed + + const reversedGroupEvents = useMemo(() => { + const eventsList = likesOnly ? filter(events, 'like') : events + const groupedEvents = values( + groupBy( + reverseStatus + ? reverse([...eventsList!]) + : eventsList, + ({ h }) => h, + ), + ) + return reverseStatus + ? reverse(groupedEvents) + : groupedEvents + }, [ + events, + likesOnly, + reverseStatus, + ]) + + const episodesToPlay = map(flatten(reversedGroupEvents), ((event) => ({ + episodes: [{ + e: event.e, + h: event.h, + s: event.s, + }], + id: event.n, + type: 3, + }))) as Array + + return { + activeStatus, + episodesToPlay, + isLiveMatch, + likeImage, + likeToggle, + reversedGroupEvents, + setReversed, + setUnreversed, + } +} diff --git a/src/features/MatchPage/styled.tsx b/src/features/MatchPage/styled.tsx index 3d4cef56..a0c1816f 100644 --- a/src/features/MatchPage/styled.tsx +++ b/src/features/MatchPage/styled.tsx @@ -32,6 +32,7 @@ export const Container = styled.div` max-height: 896px; display: flex; flex-direction: column; + position: relative; @media ${devices.tablet} { flex-grow: 0; diff --git a/src/features/MatchSidePlaylists/components/EventsList/index.tsx b/src/features/MatchSidePlaylists/components/EventsList/index.tsx index bf4d9e3a..4976aca0 100644 --- a/src/features/MatchSidePlaylists/components/EventsList/index.tsx +++ b/src/features/MatchSidePlaylists/components/EventsList/index.tsx @@ -21,6 +21,7 @@ import { } from '../TabEvents/styled' type Props = { + disablePlayingEpisodes?: () => void, events: Events, onSelect: (option: PlaylistOption) => void, profile: MatchInfo, @@ -28,6 +29,7 @@ type Props = { } export const EventsList = ({ + disablePlayingEpisodes, events, onSelect, profile, @@ -64,13 +66,20 @@ export const EventsList = ({ : profile?.team2 const eventWithoutClick = isLffClient && profile?.live + const eventClick = () => { + !eventWithoutClick && onSelect(eventPlaylist) + if (disablePlayingEpisodes) { + disablePlayingEpisodes() + } + } + return ( !eventWithoutClick && onSelect(eventPlaylist)} + onClick={eventClick} team={team} /> diff --git a/src/features/MatchSidePlaylists/components/FiltersPopup/index.tsx b/src/features/MatchSidePlaylists/components/FiltersPopup/index.tsx new file mode 100644 index 00000000..2e92ec24 --- /dev/null +++ b/src/features/MatchSidePlaylists/components/FiltersPopup/index.tsx @@ -0,0 +1,145 @@ +import uniq from 'lodash/uniq' +import map from 'lodash/map' +import isEmpty from 'lodash/isEmpty' +import includes from 'lodash/includes' +import filter from 'lodash/filter' + +import { T9n } from 'features/T9n' +import { useMatchPageStore } from 'features/MatchPage/store' +import { PlayerPlaylistOption } from 'features/MatchPage/types' +import { CloseButton } from 'features/PopupComponents' +import { Name, useName } from 'features/Name' + +import { + Checkbox, + CloseButtonContainer, + PartBlock, + HeaderText, + ItemBlock, + ItemsContainer, + ItemText, + MainCheckboxContainer, + PopupContainer, + PopupHeader, + Button, + ButtonConatiner, + PlayerNumber, +} from './styled' + +type TLabelProps = { + player: PlayerPlaylistOption, +} + +const Label = ({ player }: TLabelProps) => { + const { num } = player + return ( + + + {num} + + + + ) +} + +export const FiltersPopup = () => { + const { + activeEvents, + activeFirstTeamPlayers, + activeSecondTeamPlayers, + applyFilters, + closePopup, + events, + matchPlaylists, + profile, + resetEvents, + resetPlayers, + toggleActiveEvents, + toggleActivePlayers, + } = useMatchPageStore() + const currentEvents = filter(events, (event) => event.pl !== undefined + && event.t !== undefined) + + const uniqEvents = uniq(map(currentEvents, ({ l }) => l)) + + const team1Name = useName(profile!.team1) + const team2Name = useName(profile!.team2) + + return ( + + + + + + + + + + + + + + + {map(uniqEvents, ((event) => ( + + + + )))} + + + + + + + + {map(matchPlaylists.players.team1, ((player) => ( + + )} + /> + + )))} + + + + + + + + {map(matchPlaylists.players.team2, ((player) => ( + + )} + /> + + )))} + + + + + + + ) +} diff --git a/src/features/MatchSidePlaylists/components/FiltersPopup/styled.tsx b/src/features/MatchSidePlaylists/components/FiltersPopup/styled.tsx new file mode 100644 index 00000000..68af236d --- /dev/null +++ b/src/features/MatchSidePlaylists/components/FiltersPopup/styled.tsx @@ -0,0 +1,199 @@ +import styled, { css } from 'styled-components/macro' + +import { Checkbox as BaseCheckbox } from 'features/Common/Checkbox' +import { Label } from 'features/Common/Checkbox/styled' +import { CheckboxSvg } from 'features/Common/Checkbox/Icon' +import { customScrollbar } from 'features/Common' +import { NameStyled } from 'features/Name' +import { isMobileDevice } from 'config/userAgent' +import { BaseButton } from 'features/PopupComponents' + +export const PopupContainer = styled.div` + background: #333333; + box-shadow: 0px 2px 40px rgba(0, 0, 0, 0.6); + border-radius: 2px; + display: flex; + flex-direction: column; + position: absolute; + overflow-y: auto; + z-index: 1000; + height: 100%; + right: 0; + top: 0; + + ${customScrollbar} + + ${isMobileDevice + ? css` + position: fixed; + height: calc(100vh - 40px); + width: 100%; + padding-bottom: 70px; + top: 40px;` + : css` + width: 651px;`} +` + +export const PopupHeader = styled.div` + flex: 0 0 auto; + ${isMobileDevice + ? css` + height: auto; + padding: 12px 0px 0px 0px; + margin-bottom: 14px;` + : css` + height: 50px; + padding: 17px 22px 0px 22px;`} +` + +export const CloseButtonContainer = styled.div` + position: absolute; + top: 14px; + right: 12px; + + ${BaseButton} { + top: -4px; + right:0 ; + } +` + +export const HeaderText = styled.div` + font-family: 'Montserrat'; + font-style: normal; + font-weight: 700; + text-transform: uppercase; + + color: #FFFFFF; + ${isMobileDevice + ? css` + font-size: 12px; + line-height: 15px; + text-align: center;` + : css` + font-size: 18px; + line-height: 22px; + margin-bottom: 21px;`} +` + +export const PartBlock = styled.div` + flex: 1 0 auto; + border-bottom: 1px solid #505050; + padding: 17px 22px 17px 22px; +` + +export const ItemsContainer = styled.ul` + display: flex; + flex-direction: row; + flex-wrap: wrap; +` + +export const MainCheckboxContainer = styled.div` + margin-bottom: 15px; + display: flex; +` + +export const ItemBlock = styled.div` + flex: 0 0 33.33%; + margin-bottom: 4px; + + ${isMobileDevice + ? css` + flex: 0 0 50%;` + : css` + flex: 0 0 33.33%;`} +` + +export const Checkbox = styled(BaseCheckbox)` + height: 28px; + display: block; + + ${Label} { + height: 100%; + font-style: normal; + font-weight: 400; + + ${isMobileDevice + ? css` + font-size: 12px; + line-height: 18px;` + : css` + font-size: 14px; + line-height: 16px;`} + + ${({ checked }) => (checked + ? css`` + : css` + color: rgba(255, 255, 255, 0.6);` + )} + } + + ${CheckboxSvg} { + margin-right: 8px; + width: 20px; + height: 20px; + } +` + +export const ItemText = styled.div` + display: flex; + height: 100%; + align-items: center; + + ${NameStyled} { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + width: 130px; + } + + ${isMobileDevice + ? css` + width: 110px;` + : css` + width: 130px;`} +` + +export const TeamBlock = styled.div`` + +export const ButtonConatiner = styled.div` + display: flex; + align-items: center; + justify-content: center; + flex: 0 0 66px; + + ${isMobileDevice + ? css` + position: fixed; + bottom: 14px; + left: 50%; + transform: translate(-50%, 0);` + : css``} +` + +export const Button = styled.button` + height: 41px; + background: #294FC4; + box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.3); + border-radius: 5px; + border: none; + cursor: pointer; + font-size: 15px; + line-height: 50px; + font-weight: 600; + display: flex; + align-items: center; + justify-content: center; + color: #ffff; + + ${isMobileDevice + ? css` + width: 301px;` + : css` + width: 167px;`} +` +export const PlayerNumber = styled.span` + margin-right: 8px; + font-size: 11px; + line-height: 16px; + font-weight: 600; +` diff --git a/src/features/MatchSidePlaylists/components/TabEvents/index.tsx b/src/features/MatchSidePlaylists/components/TabEvents/index.tsx index d4a40425..719f1f95 100644 --- a/src/features/MatchSidePlaylists/components/TabEvents/index.tsx +++ b/src/features/MatchSidePlaylists/components/TabEvents/index.tsx @@ -1,21 +1,14 @@ -import { - Fragment, - useCallback, - useMemo, - useState, -} from 'react' +import { Fragment } from 'react' -import groupBy from 'lodash/groupBy' import isEmpty from 'lodash/isEmpty' import map from 'lodash/map' -import reverse from 'lodash/reverse' -import filter from 'lodash/filter' -import values from 'lodash/values' +import flatten from 'lodash/flatten' +import size from 'lodash/size' import { T9n } from 'features/T9n' import type { PlaylistOption } from 'features/MatchPage/types' -import { useToggle } from 'hooks' -import type { Events, MatchInfo } from 'requests' +import { useMatchPageStore } from 'features/MatchPage/store' +import type { MatchInfo } from 'requests' import { EventsList } from '../EventsList' import { @@ -26,109 +19,105 @@ import { Tabs, Tab, LikeToggle, + Filters, + ButtonsBlock, + HoverTooltip, + EpisodesCount, + SelectedEpisodes, + WatchButton, } from './styled' type Props = { - events: Events, onSelect: (option: PlaylistOption) => void, profile: MatchInfo, selectedPlaylist?: PlaylistOption, } export const TabEvents = ({ - events, onSelect, profile, selectedPlaylist, }: Props) => { const { - close: setUnreversed, - isOpen: areEventsReversed, - open: setReversed, - } = useToggle() - - const [likesOnly, setLikesOnly] = useState(false) - const likeToggle = useCallback(() => setLikesOnly((state) => !state), []) - const likeImage = likesOnly ? '/images/like-active-icon.svg' : '/images/like-icon.svg' - - const isLiveMatch = profile?.live - const reverseStatus = (areEventsReversed || isLiveMatch) && (areEventsReversed !== isLiveMatch) - const activeStatus = isLiveMatch ? areEventsReversed : !areEventsReversed - - const reversedGroupEvents = useMemo(() => { - const eventsList = likesOnly ? filter(events, 'like') : events - const groupedEvents = values( - groupBy( - reverseStatus - ? reverse([...eventsList]) - : eventsList, - ({ h }) => h, - ), - ) - return reverseStatus - ? reverse(groupedEvents) - : groupedEvents - }, [ - events, - likesOnly, - reverseStatus, - ]) + activeStatus, + countOfFilters, + disablePlayingEpisodes, + isEmptyFilters, + isLiveMatch, + likeImage, + likeToggle, + playEpisodes, + reversedGroupEvents, + setReversed, + setUnreversed, + togglePopup, + } = useMatchPageStore() if (!profile) return null return ( - {isEmpty(events) - ? ( - - - - ) - : ( - - - - - - - - - - + + + + + + + + + + + + + + + {countOfFilters !== 0 && size(flatten(reversedGroupEvents)) !== 0 && ( + + + {size(flatten(reversedGroupEvents))} + + + + + + )} + {isEmpty(reversedGroupEvents) + ? ( + + + + ) : ( - { - map(reversedGroupEvents, (halfEvents, idx) => { - const firstEvent = halfEvents[0] - const isFirstBlock = idx === 0 + {map(reversedGroupEvents, (halfEvents, idx) => { + const firstEvent = halfEvents[0] + const isFirstBlock = idx === 0 - return ( - - { - !isFirstBlock && ( - - - - ) - } - - - ) - }) - } + return ( + + {!isFirstBlock && ( + + + + )} + + + ) + })} - - )} + )} + ) } diff --git a/src/features/MatchSidePlaylists/components/TabEvents/styled.tsx b/src/features/MatchSidePlaylists/components/TabEvents/styled.tsx index 963d2249..995af978 100644 --- a/src/features/MatchSidePlaylists/components/TabEvents/styled.tsx +++ b/src/features/MatchSidePlaylists/components/TabEvents/styled.tsx @@ -4,7 +4,8 @@ import { isMobileDevice } from 'config/userAgent' import { ProfileLogo } from 'features/ProfileLogo' -import { Tabs as TabsBase, Tab as TabBase } from '../PlayersPlaylists/styled' +import { Tabs as TabsBase } from '../PlayersPlaylists/styled' + import { BlockTitle as BlockTitleBase, Button as ButtonBase, @@ -52,7 +53,7 @@ type AvatarProps = { isPlayer: boolean, } -export const Avatar = styled(ProfileLogo)` +export const Avatar = styled(ProfileLogo) ` position: absolute; width: 35px; height: 43px; @@ -138,40 +139,56 @@ export const EventTime = styled(Title)` export const Tabs = styled(TabsBase)` margin-top: 0px; - margin-bottom: 18px; + font-style: normal; + font-weight: 400; + font-size: 12px; + letter-spacing: -0.32px; + color: #ffff; + flex: 1 1 auto; + + ${isMobileDevice ? 'padding-left: 33px;' : 'padding-left: 20px;'} ` -export const Tab = styled(TabBase)` - text-transform: none; +type TTab = { + active?: boolean, +} - :first-child { - margin-right: 15px; +export const Tab = styled.span` + text-transform: none; + border: none; + cursor: pointer; + width: 13px; + height: 13px; + + :nth-child(2) { + margin-left: 3px; } - ${isMobileDevice + ${({ active }) => (active ? css` - font-size: 14px; - - @media (orientation: portrait) { - width: 120px; - } + background: url(/images/boldArrowWhite.svg) no-repeat; + background-size: 13px 13px; + + :nth-child(3) { + transform: rotate(180deg); + } + ` + : css` + background: url(/images/boldArrowGray.svg) no-repeat; + background-size: 13px 13px; + + :nth-child(2) { + transform: rotate(180deg); + } ` - : ''} + )} + ` export const LikeToggle = styled.img` - position: absolute; - right: 0; - top: 9px; - width: 15px; - height: 15px; + width: 12px; + height: 12px; cursor: pointer; - - ${isMobileDevice - ? css` - right: 20px; - ` - : ''}; ` export const BlockTitle = styled(BlockTitleBase)` @@ -185,7 +202,7 @@ type ButtonProps = { like?: boolean, } -export const Button = styled(ButtonBase)` +export const Button = styled(ButtonBase) ` ${({ like }) => ( like ? css` background: url(/images/event-like-bg.png); @@ -212,3 +229,90 @@ export const Button = styled(ButtonBase)` : '' )} ` + +export const ButtonsBlock = styled.div` + position: relative; + display: flex; + width: 100%; + height: 20px; + margin-bottom: 7px; +` + +export const HoverTooltip = styled.span` + display: flex; + background: #FFFFFF; + border-radius: 6px; + left: 8px; + top: 30px; + transform: translate(-100%, -50%); + font-weight: 600; + font-size: 15px; + text-align: center; + flex-direction: column; + position: absolute; + justify-content: center; + align-items: center; + min-width: 160px; + height: 21px; + text-decoration: none; + color: #000000; + opacity: 0; + transition: all 0.1s ease; + pointer-events: none; + z-index: 1000; +` + +type TFilters = { + active?: boolean, +} + +export const Filters = styled.span` + cursor: pointer; + width: 12px; + height: 12px; + position: relative; + margin-left: 15px; + + ${({ active }) => (active + ? css` + background: url('/images/filter-white.svg') no-repeat; + ` + : css` + background: url('/images/filter-gray.svg')no-repeat; + `)} + + :hover ${HoverTooltip} { + opacity: 1; + z-index: 1; + } +` + +export const SelectedEpisodes = styled.div` + display: flex; + gap: 18px; +` + +export const EpisodesCount = styled.div` + font-weight: 600; + font-size: 12px; + line-height: 20px; + text-align: right; + letter-spacing: -0.32px; + color: rgba(255, 255, 255, 0.5); +` + +export const WatchButton = styled.span` + font-weight: 600; + font-size: 12px; + height: 16px; + padding-left: 12px; + letter-spacing: -0.32px; + color: #ffff; + cursor: pointer; + background: url('/images/player-play.svg') left 2px no-repeat; + background-size: 9px 11px; + + :hover { + box-shadow: 0 1px #ffff; + } +` diff --git a/src/features/MatchSidePlaylists/hooks.tsx b/src/features/MatchSidePlaylists/hooks.tsx index 78cc8e3a..a953144c 100644 --- a/src/features/MatchSidePlaylists/hooks.tsx +++ b/src/features/MatchSidePlaylists/hooks.tsx @@ -12,6 +12,7 @@ import { Tabs } from './config' export const useMatchSidePlaylists = () => { const { + closePopup, events, matchPlaylists: playlists, tournamentData, @@ -52,6 +53,10 @@ export const useMatchSidePlaylists = () => { } }, [isEventTabVisible, isVideoTabVisible, isWatchTabVisible]) + useEffect(() => { + if (selectedTab !== Tabs.EVENTS) closePopup() + }, [selectedTab, closePopup]) + return { isEventTabVisible, isVideoTabVisible, diff --git a/src/features/MatchSidePlaylists/index.tsx b/src/features/MatchSidePlaylists/index.tsx index 4b243884..d73993ce 100644 --- a/src/features/MatchSidePlaylists/index.tsx +++ b/src/features/MatchSidePlaylists/index.tsx @@ -36,7 +36,6 @@ export const MatchSidePlaylists = ({ selectedPlaylist, }: Props) => { const { - events, hideProfileCard, matchPlaylists: playlists, profile, @@ -105,7 +104,6 @@ export const MatchSidePlaylists = ({ void, onPlayingChange: (playing: boolean) => void, profile: MatchInfo, @@ -53,6 +55,11 @@ export const useMultiSourcePlayer = ({ onError, onPlayingChange, }: Props) => { + const { + isPlayFilterEpisodes, + playNextEpisode, + } = useMatchPageStore() + const numberOfChapters = size(chapters) const [ { @@ -180,7 +187,6 @@ export const useMultiSourcePlayer = ({ const onEnded = () => { playNextChapter() } - const onPause = () => { setPlayerState({ playing: false }) } @@ -199,14 +205,21 @@ export const useMultiSourcePlayer = ({ useEffect(() => { const { duration: chapterDuration } = getActiveChapter() - if (playedProgress >= chapterDuration && !seeking) { + if (playedProgress >= chapterDuration && !seeking && isPlayFilterEpisodes) { + setPlayerState({ playedProgress: 0 }) + playNextEpisode() + } + if (playedProgress >= chapterDuration && !seeking && !isPlayFilterEpisodes) { playNextChapter() } }, [ + isPlayFilterEpisodes, + playNextEpisode, getActiveChapter, playedProgress, seeking, playNextChapter, + setPlayerState, ]) useEventListener({ diff --git a/src/features/MultiSourcePlayer/index.tsx b/src/features/MultiSourcePlayer/index.tsx index 4d80db39..0808fc8d 100644 --- a/src/features/MultiSourcePlayer/index.tsx +++ b/src/features/MultiSourcePlayer/index.tsx @@ -13,6 +13,7 @@ import { VideoPlayer } from 'features/VideoPlayer' import { Controls } from 'features/StreamPlayer/components/Controls' import { Name } from 'features/Name' import RewindMobile from 'features/StreamPlayer/components/RewindMobile' +import { FiltersPopup } from 'features/MatchSidePlaylists/components/FiltersPopup' import { isMobileDevice } from 'config/userAgent' @@ -22,7 +23,7 @@ import { Players } from './types' import { REWIND_SECONDS } from './config' export const MultiSourcePlayer = (props: Props) => { - const { profile } = props + const { isOpenPopup, profile } = props const { activeChapterIndex, activePlayer, @@ -94,6 +95,7 @@ export const MultiSourcePlayer = (props: Props) => { ) } + {isOpenPopup && } { - const { profile } = useMatchPageStore() + const { isOpenPopup, profile } = useMatchPageStore() const { onMouseMove, @@ -33,6 +34,7 @@ export const YoutubePlayer = (props: Props) => { onTouchStart={onTouchStart} onTouchEnd={onTouchEnd} > + {isOpenPopup && } { - const { profile } = useMatchPageStore() + const { isOpenPopup, profile } = useMatchPageStore() const { user } = useAuthStore() const { @@ -91,14 +92,15 @@ export const StreamPlayer = (props: Props) => { onTouchStart={onTouchStart} onTouchEnd={onTouchEnd} > + {isOpenPopup && } {(profile?.tournament.id === 1136) - && playing - && ( - - )} + && playing + && ( + + )}