From 7d3185dc1dddf968cf3673bd816b7edfa1c631ec Mon Sep 17 00:00:00 2001 From: Rakov Roman Date: Wed, 17 Aug 2022 13:58:20 +0300 Subject: [PATCH] fix(#2639): bug fixing for match page mobile --- public/images/rewind-left.svg | 28 +++ public/images/rewind-right.svg | 28 +++ .../components/DateFilter/styled.tsx | 12 +- src/features/MatchCard/helpers/index.tsx | 2 +- .../components/FinishedMatch/hooks/index.tsx | 6 +- .../FinishedMatch/hooks/useEpisodes.tsx | 6 +- .../components/FinishedMatch/index.tsx | 30 +-- .../MatchPage/components/LiveMatch/index.tsx | 26 +-- .../components/MatchDescription/index.tsx | 62 ++++--- .../components/MatchDescription/styled.tsx | 62 ++++--- .../components/MatchDate/index.tsx | 34 ---- .../components/MatchDate/styled.tsx | 10 - .../components/TeamsDetails/index.tsx | 73 -------- .../components/TeamsDetails/styled.tsx | 70 ------- .../MatchProfileCardMobile/index.tsx | 28 --- .../MatchProfileCardMobile/styled.tsx | 19 -- src/features/MatchPage/hooks/index.tsx | 15 -- src/features/MatchPage/hooks/useEvents.tsx | 28 --- .../MatchPage/hooks/useEventsLexics.tsx | 25 --- src/features/MatchPage/hooks/useMatchData.tsx | 64 ------- .../MatchPage/hooks/useMatchProfile.tsx | 76 -------- src/features/MatchPage/index.tsx | 20 +- src/features/MatchPage/store/hooks/index.tsx | 5 +- .../store/hooks/useMatchPlaylists.tsx | 9 +- .../{ => store}/hooks/useTournamentData.tsx | 2 +- src/features/MatchPage/styled.tsx | 6 +- .../TabVideo/components/VideoDate/styled.tsx | 10 + .../components/TabVideo/styled.tsx | 14 +- src/features/MatchSidePlaylists/hooks.tsx | 17 +- src/features/MatchSidePlaylists/index.tsx | 59 ++---- src/features/MatchSidePlaylists/styled.tsx | 45 +---- .../components/ProgressBar/index.tsx | 10 +- src/features/MultiSourcePlayer/config.tsx | 4 +- .../MultiSourcePlayer/hooks/index.tsx | 2 +- src/features/MultiSourcePlayer/index.tsx | 31 +++- .../components/SelectSport/styled.tsx | 1 + .../components/SelectSportPopup/styled.tsx | 2 +- .../components/Chapters/styled.tsx | 16 +- .../Components/ControlsMobile/styled.tsx | 3 +- .../components/Controls/index.tsx | 46 ++--- .../components/ProgressBar/index.tsx | 14 +- .../components/ProgressBar/styled.tsx | 29 ++- .../components/RewindMobile/index.tsx | 67 +++++++ .../components/RewindMobile/styled.tsx | 41 ++++ .../components/YoutubePlayer/index.tsx | 4 +- src/features/StreamPlayer/config.tsx | 4 +- src/features/StreamPlayer/hooks/index.tsx | 7 +- .../hooks/useControlsVisibility.tsx | 56 ++++-- src/features/StreamPlayer/index.tsx | 175 +++++++----------- src/features/StreamPlayer/styled.tsx | 27 ++- .../components/TournamentMobile/styled.tsx | 7 +- src/features/TournamentSubtitle/index.tsx | 26 +-- src/features/TournamentSubtitle/styled.tsx | 36 ++-- 53 files changed, 576 insertions(+), 923 deletions(-) create mode 100644 public/images/rewind-left.svg create mode 100644 public/images/rewind-right.svg delete mode 100644 src/features/MatchPage/components/MatchProfileCardMobile/components/MatchDate/index.tsx delete mode 100644 src/features/MatchPage/components/MatchProfileCardMobile/components/MatchDate/styled.tsx delete mode 100644 src/features/MatchPage/components/MatchProfileCardMobile/components/TeamsDetails/index.tsx delete mode 100644 src/features/MatchPage/components/MatchProfileCardMobile/components/TeamsDetails/styled.tsx delete mode 100644 src/features/MatchPage/components/MatchProfileCardMobile/index.tsx delete mode 100644 src/features/MatchPage/components/MatchProfileCardMobile/styled.tsx delete mode 100644 src/features/MatchPage/hooks/index.tsx delete mode 100644 src/features/MatchPage/hooks/useEvents.tsx delete mode 100644 src/features/MatchPage/hooks/useEventsLexics.tsx delete mode 100644 src/features/MatchPage/hooks/useMatchData.tsx delete mode 100644 src/features/MatchPage/hooks/useMatchProfile.tsx rename src/features/MatchPage/{ => store}/hooks/useTournamentData.tsx (97%) create mode 100644 src/features/StreamPlayer/components/RewindMobile/index.tsx create mode 100644 src/features/StreamPlayer/components/RewindMobile/styled.tsx diff --git a/public/images/rewind-left.svg b/public/images/rewind-left.svg new file mode 100644 index 00000000..37f6a190 --- /dev/null +++ b/public/images/rewind-left.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/images/rewind-right.svg b/public/images/rewind-right.svg new file mode 100644 index 00000000..f786c740 --- /dev/null +++ b/public/images/rewind-right.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/features/HeaderFilters/components/DateFilter/styled.tsx b/src/features/HeaderFilters/components/DateFilter/styled.tsx index 7d0f7fef..3857d476 100644 --- a/src/features/HeaderFilters/components/DateFilter/styled.tsx +++ b/src/features/HeaderFilters/components/DateFilter/styled.tsx @@ -84,6 +84,7 @@ export const DateButton = styled(BaseButton) ` position: static; width: 9px; height: 9px; + margin-left: 10px; ` : ''}; @@ -96,17 +97,6 @@ export const DateButton = styled(BaseButton) ` ? 'opacity: 1;' : '' )} - - ${isMobileDevice - ? css` - /* right: 14px; - width: 16px; - height: 16px; */ - @media screen and (orientation: landscape){ - /* right: 20px; */ - } - ` - : ''}; ` export const WeekDaysWrapper = styled.div` diff --git a/src/features/MatchCard/helpers/index.tsx b/src/features/MatchCard/helpers/index.tsx index bca3139d..3d65a5b5 100644 --- a/src/features/MatchCard/helpers/index.tsx +++ b/src/features/MatchCard/helpers/index.tsx @@ -12,6 +12,6 @@ export const getPrepareTimeFormat = ({ time, }: prepareTimeFormat) => ( isNeedFormatTimeChanged - ? format(date, 'h:mm aaa') + ? format(date, 'h:mm a') : time ) diff --git a/src/features/MatchPage/components/FinishedMatch/hooks/index.tsx b/src/features/MatchPage/components/FinishedMatch/hooks/index.tsx index 1ff17d42..5a33de95 100644 --- a/src/features/MatchPage/components/FinishedMatch/hooks/index.tsx +++ b/src/features/MatchPage/components/FinishedMatch/hooks/index.tsx @@ -4,19 +4,19 @@ import { useToggle } from 'hooks/useToggle' import type { Settings } from 'features/MatchPopup' import { useMatchPopupStore } from 'features/MatchPopup' +import { useMatchPageStore } from 'features/MatchPage/store' import { usePlayerLogger } from './usePlayerLogger' import { useEpisodes } from './useEpisodes' import { useChapters } from './useChapters' export const useFinishedMatch = () => { + const { setChapters, setSettings } = useMatchPopupStore() const { handlePlaylistClick, matchPlaylists, selectedPlaylist, - setChapters, - setSettings, - } = useMatchPopupStore() + } = useMatchPageStore() const { close: closeSettingsPopup, isOpen: isSettingsPopupOpen, diff --git a/src/features/MatchPage/components/FinishedMatch/hooks/useEpisodes.tsx b/src/features/MatchPage/components/FinishedMatch/hooks/useEpisodes.tsx index 152638cf..93b7dc40 100644 --- a/src/features/MatchPage/components/FinishedMatch/hooks/useEpisodes.tsx +++ b/src/features/MatchPage/components/FinishedMatch/hooks/useEpisodes.tsx @@ -12,6 +12,8 @@ import { getPlayerPlaylists } from 'requests' import { usePageParams } from 'hooks/usePageParams' import { PlaylistOption, PlaylistTypes } from 'features/MatchPage/types' +import { useMatchPageStore } from 'features/MatchPage/store' + import { defaultSettings, Settings, @@ -19,12 +21,12 @@ import { } from 'features/MatchPopup' export const useEpisodes = () => { + const { settings } = useMatchPopupStore() const { handlePlaylistClick, matchPlaylists: playlists, selectedPlaylist, - settings, - } = useMatchPopupStore() + } = useMatchPageStore() const [episodes, setEpisodes] = useState([]) const { profileId: matchId, sportType } = usePageParams() diff --git a/src/features/MatchPage/components/FinishedMatch/index.tsx b/src/features/MatchPage/components/FinishedMatch/index.tsx index f8190c7f..4d588a3c 100644 --- a/src/features/MatchPage/components/FinishedMatch/index.tsx +++ b/src/features/MatchPage/components/FinishedMatch/index.tsx @@ -2,11 +2,6 @@ import { Fragment } from 'react' import isEmpty from 'lodash/isEmpty' -import { isMobileDevice } from 'config/userAgent' - -import type { Events } from 'requests/getMatchEvents' -import type { MatchInfo } from 'requests/getMatchInfo' - import { MatchSidePlaylists } from 'features/MatchSidePlaylists' import { MultiSourcePlayer } from 'features/MultiSourcePlayer' @@ -15,28 +10,17 @@ import { SettingsPopup } from '../SettingsPopup' import { useFinishedMatch } from './hooks' import { Container } from '../../styled' import { Modal } from './styled' -import { TournamentData } from '../../types' import { MatchDescription } from '../MatchDescription' -import { MatchProfileCardMobile } from '../MatchProfileCardMobile' - -type Props = { - events: Events, - profile: MatchInfo, - tournamentData: TournamentData, -} +import { useMatchPageStore } from '../../store' -export const FinishedMatch = ({ - events, - profile, - tournamentData, -}: Props) => { +export const FinishedMatch = () => { + const { profile } = useMatchPageStore() const { chapters, closeSettingsPopup, isSettingsPopupOpen, onPlayingChange, onPlaylistSelect, - playlists, selectedPlaylist, setEpisodesSettings, } = useFinishedMatch() @@ -64,20 +48,14 @@ export const FinishedMatch = ({ onPlayingChange={onPlayingChange} profile={profile} /> - {isMobileDevice - ? : ( - )} + )} ) diff --git a/src/features/MatchPage/components/LiveMatch/index.tsx b/src/features/MatchPage/components/LiveMatch/index.tsx index 79abf0cb..b6a405f1 100644 --- a/src/features/MatchPage/components/LiveMatch/index.tsx +++ b/src/features/MatchPage/components/LiveMatch/index.tsx @@ -7,25 +7,13 @@ import { StreamPlayer } from 'features/StreamPlayer' import { YoutubePlayer } from 'features/StreamPlayer/components/YoutubePlayer' import { MatchSidePlaylists } from 'features/MatchSidePlaylists' -import { isMobileDevice } from 'config/userAgent' - import { Container } from '../../styled' import { useLiveMatch } from './hooks' -import { TournamentData } from '../../types' import { MatchDescription } from '../MatchDescription' -import { MatchProfileCardMobile } from '../MatchProfileCardMobile' - -type Props = { - tournamentData: TournamentData, -} -export const LiveMatch = ({ - tournamentData, -}: Props) => { +export const LiveMatch = () => { const { - events, - matchPlaylists, profile, selectedPlaylist, } = useMatchPageStore() @@ -47,8 +35,8 @@ export const LiveMatch = ({ @@ -58,24 +46,18 @@ export const LiveMatch = ({ onDurationChange={onDurationChange} onPlayingChange={onPlayingChange} onProgressChange={onPlayerProgressChange} - isLive={profile?.live} + isLive={profile?.live ?? false} resumeFrom={resume} chapters={chapters} profile={profile} /> ) )} - {isMobileDevice - ? : ( - )} + diff --git a/src/features/MatchPage/components/MatchDescription/index.tsx b/src/features/MatchPage/components/MatchDescription/index.tsx index 239d3fbb..3a3a3377 100644 --- a/src/features/MatchPage/components/MatchDescription/index.tsx +++ b/src/features/MatchPage/components/MatchDescription/index.tsx @@ -1,43 +1,54 @@ +import { useCallback } from 'react' + import { format } from 'date-fns' import includes from 'lodash/includes' -import type { MatchInfo } from 'requests/getMatchInfo' +import type { Team } from 'requests/getMatchInfo' -import { Name } from 'features/Name' -import { SportIcon } from 'components/SportIcon/SportIcon' +import { getName, Name } from 'features/Name' import { useAuthStore } from 'features/AuthStore' import { useMatchSwitchesStore } from 'features/MatchSwitches' +import { TournamentSubtitle } from 'features/TournamentSubtitle' +import { useLexicsStore } from 'features/LexicsStore' +import { useMatchPageStore } from 'features/MatchPage/store' import { parseDate } from 'helpers/parseDate' import { ProfileTypes } from 'config' +import { isMobileDevice } from 'config/userAgent' import { usePageParams } from 'hooks/usePageParams' import { - CountryFlag, Description, DescriptionInnerBlock, MatchDate, StyledLink, Score, Title, - Tournament, Views, Time, } from './styled' -type Props = { - profile: MatchInfo, -} - -export const MatchDescription = ({ - profile, -}: Props) => { +export const MatchDescription = () => { const { sportType } = usePageParams() const { user } = useAuthStore() const { isScoreHidden } = useMatchSwitchesStore() + const { suffix } = useLexicsStore() + const { profile, profileCardShown } = useMatchPageStore() + + const getTeamName = useCallback((team: Team) => { + if (isMobileDevice) { + const teamNameLimit = 14 + let name = getName({ nameObj: team, suffix }) + if (name.length > teamNameLimit) { + name = `${name.substring(0, teamNameLimit)}...` + } + return name + } + return + }, [suffix]) if (!profile) return @@ -50,12 +61,12 @@ export const MatchDescription = ({ } = profile const isChangedTimeFormat = includes(['US', 'CA'], user?.profile.country_code) - const localDate = format(parseDate(date), 'MMMM d, y') + const localDate = format(parseDate(date), 'MMM d, y') const changedTimeFormat = format(parseDate(date), - isChangedTimeFormat ? 'h:mm aaa' : 'HH:mm') + isChangedTimeFormat ? 'h:mm a' : 'HH:mm') return ( - + <StyledLink @@ -63,7 +74,7 @@ export const MatchDescription = ({ profileType={ProfileTypes.TEAMS} sportType={sportType} > - <Name nameObj={team1} /> + {getTeamName(team1)} </StyledLink> <Score> { @@ -77,22 +88,13 @@ export const MatchDescription = ({ profileType={ProfileTypes.TEAMS} sportType={sportType} > - <Name nameObj={team2} /> + {getTeamName(team2)} </StyledLink> - - - - - - - + diff --git a/src/features/MatchPage/components/MatchDescription/styled.tsx b/src/features/MatchPage/components/MatchDescription/styled.tsx index 3045b861..c3369aab 100644 --- a/src/features/MatchPage/components/MatchDescription/styled.tsx +++ b/src/features/MatchPage/components/MatchDescription/styled.tsx @@ -3,7 +3,7 @@ import { isMobileDevice } from 'config/userAgent' import { ProfileLink } from 'features/ProfileLink' -export const Description = styled.div` +export const Description = styled.div<{isHidden?: boolean}>` padding: 22px 0 24px; display: flex; justify-content: space-between; @@ -11,24 +11,37 @@ export const Description = styled.div` ${isMobileDevice ? css` - @media (orientation: portrait) { - padding-left: 14px; - } + padding: 0 5px; ` : ''}; + + ${({ isHidden }) => (isHidden && isMobileDevice ? css` + height: 0; + opacity: 0; + margin-bottom: 0; + ` : '')} ` -export const DescriptionInnerBlock = styled.div`` +export const DescriptionInnerBlock = styled.div` + margin-right: 10px; +` export const Score = styled.span` margin: 0 10px; color: inherit; + + ${isMobileDevice + ? css` + margin: 0 5px; + ` + : ''}; ` export const StyledLink = styled(ProfileLink)` display: flex; align-items: center; color: #fff; + white-space: nowrap; &:hover { text-decoration: underline; @@ -37,11 +50,8 @@ export const StyledLink = styled(ProfileLink)` export const Title = styled.div` display: flex; - flex-direction: row; font-weight: 500; font-size: 20px; - line-height: 24px; - margin-bottom: 1px; &:hover > ${StyledLink}:not(:hover) { opacity: 0.7; @@ -51,34 +61,28 @@ export const Title = styled.div` opacity: 0.7; pointer-events: none; } -` - -export const Tournament = styled.span` - display: flex; - flex-direction: row; - align-items: center; - font-size: 14px; - line-height: 16px; - margin-bottom: 1px; - opacity: 0.7; - - &:hover { - opacity: 1; - text-decoration: underline; - } -` -export const CountryFlag = styled.img` - height: 12px; - margin: 0 6px; + ${isMobileDevice + ? css` + font-size: 14px; + margin-bottom: 5px; + ` + : ''}; ` export const Views = styled.div` color: #fff; opacity: 0.7; font-size: 20px; - line-height: 24px; - align-self: flex-start; + + ${isMobileDevice + ? css` + font-size: 10px; + display: flex; + flex-wrap: wrap; + justify-content: flex-end; + ` + : ''}; ` export const MatchDate = styled.span` diff --git a/src/features/MatchPage/components/MatchProfileCardMobile/components/MatchDate/index.tsx b/src/features/MatchPage/components/MatchProfileCardMobile/components/MatchDate/index.tsx deleted file mode 100644 index c8c7964c..00000000 --- a/src/features/MatchPage/components/MatchProfileCardMobile/components/MatchDate/index.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { useMemo } from 'react' - -import { format, parseISO } from 'date-fns' - -import { MatchInfo } from 'requests' - -import { ScDate, ScDateMonth } from './styled' - -type Props = { - profile: MatchInfo, -} - -export const MatchDate = ({ profile }: Props) => { - const { - date, - } = { ...profile! } - - const month = useMemo(() => ( - format(parseISO(date), 'MMM dd,') - ), [date]) - - const hour = useMemo(() => ( - format(parseISO(date), ' HH:mm') - ), [date]) - - return ( - - - {month} - - {hour} - - ) -} diff --git a/src/features/MatchPage/components/MatchProfileCardMobile/components/MatchDate/styled.tsx b/src/features/MatchPage/components/MatchProfileCardMobile/components/MatchDate/styled.tsx deleted file mode 100644 index 694bb0da..00000000 --- a/src/features/MatchPage/components/MatchProfileCardMobile/components/MatchDate/styled.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import styled from 'styled-components' - -export const ScDate = styled.div` - font-size: 10px; - color: rgba(255, 255, 255, 0.7); -` - -export const ScDateMonth = styled.span` - font-weight: 600; -` diff --git a/src/features/MatchPage/components/MatchProfileCardMobile/components/TeamsDetails/index.tsx b/src/features/MatchPage/components/MatchProfileCardMobile/components/TeamsDetails/index.tsx deleted file mode 100644 index c99e3507..00000000 --- a/src/features/MatchPage/components/MatchProfileCardMobile/components/TeamsDetails/index.tsx +++ /dev/null @@ -1,73 +0,0 @@ -import { useCallback } from 'react' - -import { ProfileTypes } from 'config' - -import { getName } from 'features/Name' -import { useMatchSwitchesStore } from 'features/MatchSwitches' -import { useLexicsStore } from 'features/LexicsStore' - -import { usePageParams } from 'hooks/usePageParams' - -import { MatchInfo, Team } from 'requests' - -import { - Score, - ScoreWrapper, - StyledLink, - ScTeam, - Wrapper, -} from './styled' - -type Props = { - profile: MatchInfo, - teamNameLimit?: number, -} - -export const TeamsDetails = ({ profile, teamNameLimit }: Props) => { - const { sportType } = usePageParams() - const { isScoreHidden } = useMatchSwitchesStore() - const { suffix } = useLexicsStore() - - const { - team1, - team2, - } = { ...profile! } - - const getTeamName = useCallback((team: Team) => { - let name = getName({ nameObj: team, suffix }) - if (!!teamNameLimit && name.length > teamNameLimit) name = name.substring(0, teamNameLimit).concat('...') - return name - }, [suffix, teamNameLimit]) - - return ( - - - - {getTeamName(team1)} - - - - - { - isScoreHidden - ? '-' - : `${team1.score} - ${team2.score}` - } - - - - - {getTeamName(team2)} - - - - ) -} diff --git a/src/features/MatchPage/components/MatchProfileCardMobile/components/TeamsDetails/styled.tsx b/src/features/MatchPage/components/MatchProfileCardMobile/components/TeamsDetails/styled.tsx deleted file mode 100644 index 90b95f01..00000000 --- a/src/features/MatchPage/components/MatchProfileCardMobile/components/TeamsDetails/styled.tsx +++ /dev/null @@ -1,70 +0,0 @@ -import styled, { css } from 'styled-components' - -import { isMobileDevice } from 'config/userAgent' - -import { ProfileLink } from 'features/ProfileLink' -import { ProfileLogo } from 'features/ProfileLogo' - -export const Wrapper = styled.div` - display: flex; - font-weight: 600; - margin-bottom: 5px; -` - -export const ScTeam = styled.div` - font-size: 21px; - - ${isMobileDevice - ? css` - font-size: 16px; - ` - : ''}; -` - -export const StyledLink = styled(ProfileLink)` - display: flex; - align-items: center; - color: white; - font-size: 14px; - - &:hover { - text-decoration: underline; - } -` - -export const ScoreWrapper = styled.div` - margin: 0 10px; - display: flex; - flex-direction: column; - align-items: center; -` - -export const Score = styled.span` - font-size: 14px; - white-space: nowrap; -` - -export const MatchStatus = styled.span` - text-align: center; - background-color: #CC0000; - border-radius: 1.3px; - font-weight: 600; - font-size: 13px; - line-height: 16px; - letter-spacing: 0.05em; - text-transform: uppercase; - padding: 2.5px 14px; - margin-top: 6px; -` - -export const Logo = styled(ProfileLogo)` - width: 41px; - height: 41px; - margin: 0 9px; - ${isMobileDevice - ? css` - width: 30px; - height: 30px; - ` - : ''}; -` diff --git a/src/features/MatchPage/components/MatchProfileCardMobile/index.tsx b/src/features/MatchPage/components/MatchProfileCardMobile/index.tsx deleted file mode 100644 index 824f7696..00000000 --- a/src/features/MatchPage/components/MatchProfileCardMobile/index.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { MatchInfo } from 'requests' -import { TournamentSubtitle } from 'features/TournamentSubtitle' - -import { Wrapper, WrapperTop } from './styled' - -import { TeamsDetails } from './components/TeamsDetails' -import { MatchDate } from './components/MatchDate' -import { useMatchPageStore } from '../../store' - -type Props = { - profile: MatchInfo, -} - -export const MatchProfileCardMobile = ({ profile }: Props) => { - const { profileCardShown } = useMatchPageStore() - - if (!profile) return null - - return ( - - - - - - - - ) -} diff --git a/src/features/MatchPage/components/MatchProfileCardMobile/styled.tsx b/src/features/MatchPage/components/MatchProfileCardMobile/styled.tsx deleted file mode 100644 index a6c0e552..00000000 --- a/src/features/MatchPage/components/MatchProfileCardMobile/styled.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import styled, { css } from 'styled-components/macro' - -export const Wrapper = styled.div<{isHidden?: boolean}>` - transition: 0.3s linear; - padding: 0 5px; - color: white; - margin-bottom: 15px; - - ${({ isHidden }) => (isHidden ? css` - height: 0; - opacity: 0; - margin-bottom: 0; - ` : '')} -` - -export const WrapperTop = styled.div` - display: flex; - justify-content: space-between; -` diff --git a/src/features/MatchPage/hooks/index.tsx b/src/features/MatchPage/hooks/index.tsx deleted file mode 100644 index 64d0936b..00000000 --- a/src/features/MatchPage/hooks/index.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { useToggle } from 'hooks' - -export const useMatchPage = () => { - const { - close: hideProfileCard, - isOpen: profileCardShown, - open: showProfileCard, - } = useToggle(true) - - return { - hideProfileCard, - profileCardShown, - showProfileCard, - } -} diff --git a/src/features/MatchPage/hooks/useEvents.tsx b/src/features/MatchPage/hooks/useEvents.tsx deleted file mode 100644 index 14f7095c..00000000 --- a/src/features/MatchPage/hooks/useEvents.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { useCallback, useState } from 'react' - -import type { Events } from 'requests' -import { getMatchEvents } from 'requests' - -import { usePageParams } from 'hooks/usePageParams' - -import { useEventsLexics } from './useEventsLexics' - -export const useEvents = () => { - const [events, setEvents] = useState([]) - const { fetchLexics } = useEventsLexics() - const { profileId: matchId, sportType } = usePageParams() - - const fetchMatchEvents = useCallback(() => { - getMatchEvents({ - matchId, - sportType, - }).then(fetchLexics) - .then(setEvents) - }, [ - fetchLexics, - matchId, - sportType, - ]) - - return { events, fetchMatchEvents } -} diff --git a/src/features/MatchPage/hooks/useEventsLexics.tsx b/src/features/MatchPage/hooks/useEventsLexics.tsx deleted file mode 100644 index cc886d0f..00000000 --- a/src/features/MatchPage/hooks/useEventsLexics.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { useCallback } from 'react' - -import isEmpty from 'lodash/isEmpty' -import map from 'lodash/map' -import uniq from 'lodash/uniq' - -import type { Events } from 'requests' - -import { useLexicsStore } from 'features/LexicsStore' - -export const useEventsLexics = () => { - const { addLexicsConfig } = useLexicsStore() - - const fetchLexics = useCallback((events: Events) => { - const lexics = uniq(map(events, ({ l }) => l)) - - if (!isEmpty(lexics)) { - addLexicsConfig(lexics) - } - - return events - }, [addLexicsConfig]) - - return { fetchLexics } -} diff --git a/src/features/MatchPage/hooks/useMatchData.tsx b/src/features/MatchPage/hooks/useMatchData.tsx deleted file mode 100644 index 3918361a..00000000 --- a/src/features/MatchPage/hooks/useMatchData.tsx +++ /dev/null @@ -1,64 +0,0 @@ -import { useEffect, useMemo } from 'react' - -import debounce from 'lodash/debounce' - -import { usePageParams } from 'hooks/usePageParams' -import { useInterval } from 'hooks/useInterval' - -import { useMatchPopupStore } from 'features/MatchPopup' - -import { useEvents } from './useEvents' - -const MATCH_DATA_POLL_INTERVAL = 60000 -const MATCH_PLAYLISTS_DELAY = 5000 - -export const useMatchData = (live: boolean = false) => { - const { profileId: matchId, sportType } = usePageParams() - const { fetchMatchPlaylists, matchPlaylists } = useMatchPopupStore() - const { events, fetchMatchEvents } = useEvents() - - const fetchPlaylistsDebounced = useMemo( - () => debounce(fetchMatchPlaylists, MATCH_PLAYLISTS_DELAY), - [fetchMatchPlaylists], - ) - - useEffect(() => { - fetchMatchPlaylists({ - id: matchId, - sportType, - withFullMatchDuration: !live, - }) - fetchMatchEvents() - }, [ - live, - matchId, - sportType, - fetchMatchPlaylists, - fetchMatchEvents, - ]) - - const intervalCallback = () => { - fetchPlaylistsDebounced({ - id: matchId, - sportType, - withFullMatchDuration: !live, - }) - fetchMatchEvents() - } - - const { start, stop } = useInterval({ - callback: intervalCallback, - intervalDuration: MATCH_DATA_POLL_INTERVAL, - startImmediate: false, - }) - - useEffect(() => { - if (live) { - start() - } else { - stop() - } - }, [live, start, stop]) - - return { events, matchPlaylists } -} diff --git a/src/features/MatchPage/hooks/useMatchProfile.tsx b/src/features/MatchPage/hooks/useMatchProfile.tsx deleted file mode 100644 index 1f3b3580..00000000 --- a/src/features/MatchPage/hooks/useMatchProfile.tsx +++ /dev/null @@ -1,76 +0,0 @@ -import { - useEffect, - useState, - useMemo, -} from 'react' - -import type { MatchInfo } from 'requests' -import { getMatchInfo } from 'requests' - -import { usePageParams } from 'hooks/usePageParams' - -import { parseDate } from 'helpers/parseDate' - -import type { Playlists } from '../types' -import { useMatchData } from './useMatchData' -import { useTournamentData } from './useTournamentData' - -const addScoresFromPlaylists = ( - profile: MatchInfo, - playlists: Playlists, -): MatchInfo => ( - profile - ? { - ...profile, - team1: { - ...profile?.team1, - score: playlists.score1, - }, - team2: { - ...profile?.team2, - score: playlists.score2, - }, - } - : null -) - -export const useMatchProfile = () => { - const [matchProfile, setMatchProfile] = useState(null) - const { profileId: matchId, sportType } = usePageParams() - - useEffect(() => { - getMatchInfo(sportType, matchId).then(setMatchProfile) - }, [sportType, matchId]) - - useEffect(() => { - let getIntervalMatch: ReturnType - if (matchProfile?.live && !matchProfile.youtube_link) { - getIntervalMatch = setInterval( - () => getMatchInfo(sportType, matchId).then(setMatchProfile), 1000 * 60 * 3, - ) - } - return () => clearInterval(getIntervalMatch) - }, [matchProfile, sportType, matchId]) - - const { events, matchPlaylists } = useMatchData(matchProfile?.live) - - const profile = useMemo( - () => addScoresFromPlaylists(matchProfile, matchPlaylists), - [matchProfile, matchPlaylists], - ) - - const { tournamentData } = useTournamentData(matchProfile?.tournament.id ?? null) - - const isStarted = useMemo(() => ( - profile?.date - ? parseDate(profile.date) < new Date() - : true - ), [profile?.date]) - - return { - events, - isStarted, - profile, - tournamentData, - } -} diff --git a/src/features/MatchPage/index.tsx b/src/features/MatchPage/index.tsx index 58f8bdeb..aa86b625 100644 --- a/src/features/MatchPage/index.tsx +++ b/src/features/MatchPage/index.tsx @@ -15,11 +15,10 @@ import { ProfileTypes } from 'config' import { usePageLogger } from 'hooks/usePageLogger' import { usePageParams } from 'hooks/usePageParams' -import { MatchPageStore } from './store' +import { MatchPageStore, useMatchPageStore } from './store' import { SubscriptionGuard } from './components/SubscriptionGuard' import { LiveMatch } from './components/LiveMatch' -import { useMatchProfile } from './hooks/useMatchProfile' import { Wrapper } from './styled' import { FinishedMatch } from './components/FinishedMatch' @@ -28,12 +27,7 @@ const MatchPageComponent = () => { const history = useHistory() const { addRemoveFavorite, userFavorites } = useUserFavoritesStore() - const { - events, - isStarted, - profile, - tournamentData, - } = useMatchProfile() + const { isStarted, profile } = useMatchPageStore() const { profileType, @@ -77,16 +71,10 @@ const MatchPageComponent = () => { {playFromOTT && ( - + )} {playFromScout && ( - + )} diff --git a/src/features/MatchPage/store/hooks/index.tsx b/src/features/MatchPage/store/hooks/index.tsx index 5e17b1a0..3f09735b 100644 --- a/src/features/MatchPage/store/hooks/index.tsx +++ b/src/features/MatchPage/store/hooks/index.tsx @@ -12,6 +12,7 @@ import { usePageParams } from 'hooks/usePageParams' import { parseDate } from 'helpers/parseDate' +import { useTournamentData } from './useTournamentData' import { useMatchData } from './useMatchData' import type { Playlists } from '../../types' @@ -70,13 +71,14 @@ export const useMatchPage = () => { () => addScoresFromPlaylists(matchProfile, matchPlaylists), [matchProfile, matchPlaylists], ) - const isStarted = useMemo(() => ( profile?.date ? parseDate(profile.date) < new Date() : true ), [profile?.date]) + const { tournamentData } = useTournamentData(matchProfile?.tournament.id ?? null) + return { events, handlePlaylistClick, @@ -88,5 +90,6 @@ export const useMatchPage = () => { selectedPlaylist, setFullMatchPlaylistDuration, showProfileCard, + tournamentData, } } diff --git a/src/features/MatchPage/store/hooks/useMatchPlaylists.tsx b/src/features/MatchPage/store/hooks/useMatchPlaylists.tsx index 5667b8e2..5af4789c 100644 --- a/src/features/MatchPage/store/hooks/useMatchPlaylists.tsx +++ b/src/features/MatchPage/store/hooks/useMatchPlaylists.tsx @@ -3,8 +3,6 @@ import { useCallback, } from 'react' -import isEmpty from 'lodash/isEmpty' - import type { SportTypes } from 'config/sportTypes' import { getMatchPlaylists } from 'requests/getMatchPlaylists' @@ -34,12 +32,7 @@ export const useMatchPlaylists = () => { } = useSelectedPlaylist() const setInitialSeletedPlaylist = useCallback((playlists: Playlists) => { - setSelectedPlaylist((playlist) => { - if (!playlist && !isEmpty(playlists.match)) { - return playlists.match[0] - } - return playlist - }) + setSelectedPlaylist(playlists.match[0]) return playlists }, [setSelectedPlaylist]) diff --git a/src/features/MatchPage/hooks/useTournamentData.tsx b/src/features/MatchPage/store/hooks/useTournamentData.tsx similarity index 97% rename from src/features/MatchPage/hooks/useTournamentData.tsx rename to src/features/MatchPage/store/hooks/useTournamentData.tsx index 2d1c9c0c..d3a55aa5 100644 --- a/src/features/MatchPage/hooks/useTournamentData.tsx +++ b/src/features/MatchPage/store/hooks/useTournamentData.tsx @@ -18,7 +18,7 @@ import { parseDate } from 'helpers/parseDate' import { usePageParams } from 'hooks/usePageParams' -import { TournamentData } from '../types' +import { TournamentData } from '../../types' export const useTournamentData = (tournamentId: number | null) => { const { sportType } = usePageParams() diff --git a/src/features/MatchPage/styled.tsx b/src/features/MatchPage/styled.tsx index 6661053d..3d4cef56 100644 --- a/src/features/MatchPage/styled.tsx +++ b/src/features/MatchPage/styled.tsx @@ -17,12 +17,10 @@ export const Wrapper = styled.div` ${isMobileDevice ? css` + height: calc(100vh - 40px); + @media screen and (orientation: landscape) { - padding-top: 20px; flex-direction: row; - justify-content: space-between; - margin-left: 10px; - width: 100vw; } ` : ''}; diff --git a/src/features/MatchSidePlaylists/components/TabVideo/components/VideoDate/styled.tsx b/src/features/MatchSidePlaylists/components/TabVideo/components/VideoDate/styled.tsx index 9b75ab2b..1a07d61d 100644 --- a/src/features/MatchSidePlaylists/components/TabVideo/components/VideoDate/styled.tsx +++ b/src/features/MatchSidePlaylists/components/TabVideo/components/VideoDate/styled.tsx @@ -1,5 +1,7 @@ import styled, { css } from 'styled-components/macro' +import { isMobileDevice } from 'config/userAgent' + export const Wrapper = styled.div` color: #FFFFFF; display: flex; @@ -10,6 +12,14 @@ export const Wrapper = styled.div` > :not(:last-child) { margin-right: 20px; } + + ${isMobileDevice ? css` + @media screen and (orientation: landscape){ + > :not(:last-child) { + margin-right: 3px; + } + } + ` : ''} ` export const WeekDay = styled.div.attrs(() => ({ diff --git a/src/features/MatchSidePlaylists/components/TabVideo/styled.tsx b/src/features/MatchSidePlaylists/components/TabVideo/styled.tsx index d10607e1..e9b0b502 100644 --- a/src/features/MatchSidePlaylists/components/TabVideo/styled.tsx +++ b/src/features/MatchSidePlaylists/components/TabVideo/styled.tsx @@ -1,14 +1,20 @@ -import styled from 'styled-components/macro' +import styled, { css } from 'styled-components/macro' import { customScrollbar } from 'features/Common' +import { isMobileDevice } from '../../../../config/userAgent' export const MatchesWrapper = styled.div` - overflow-y: scroll; + overflow-y: auto; max-height: calc(100vh - 170px); - + padding-right: 5px; + > * { margin-bottom: 15px; } - ${customScrollbar} + + ${isMobileDevice ? css` + overflow: hidden; + max-height: initial; + ` : ''} ` diff --git a/src/features/MatchSidePlaylists/hooks.tsx b/src/features/MatchSidePlaylists/hooks.tsx index df3dc7c3..158e5d18 100644 --- a/src/features/MatchSidePlaylists/hooks.tsx +++ b/src/features/MatchSidePlaylists/hooks.tsx @@ -6,25 +6,16 @@ import { import reduce from 'lodash/reduce' -import { Playlists, TournamentData } from 'features/MatchPage/types' - -import type { Events } from 'requests' +import { useMatchPageStore } from 'features/MatchPage/store' import { Tabs } from './config' -export type Props = { - events: Events, - playlists: Playlists, - tournamentData: TournamentData, -} - -export const useMatchSidePlaylists = (props: Props) => { +export const useMatchSidePlaylists = () => { const { events, - playlists, + matchPlaylists: playlists, tournamentData, - } = props - + } = useMatchPageStore() const [selectedTab, setSelectedTab] = useState(Tabs.WATCH) const isWatchTabVisible = useMemo(() => { diff --git a/src/features/MatchSidePlaylists/index.tsx b/src/features/MatchSidePlaylists/index.tsx index f16e49bc..0722f795 100644 --- a/src/features/MatchSidePlaylists/index.tsx +++ b/src/features/MatchSidePlaylists/index.tsx @@ -1,19 +1,12 @@ import { useRef } from 'react' -import type { Events, MatchInfo } from 'requests' - -import type { - PlaylistOption, - Playlists, - TournamentData, -} from 'features/MatchPage/types' +import type { PlaylistOption } from 'features/MatchPage/types' import { Tab, TabsGroup } from 'features/Common' import { T9n } from 'features/T9n' +import { useMatchPageStore } from 'features/MatchPage/store' import { useEventListener } from 'hooks' -import { useMatchPageStore } from 'features/MatchPage/store' - import { isIOS } from 'config/userAgent' import { Tabs } from './config' @@ -22,7 +15,6 @@ import { TabWatch } from './components/TabWatch' import { TabVideo } from './components/TabVideo' import { useMatchSidePlaylists } from './hooks' import { - BackToTopBtn, Wrapper, TabsWrapper, Container, @@ -35,39 +27,30 @@ const tabPanes = { } type Props = { - events: Events, onSelect: (option: PlaylistOption) => void, - playlists: Playlists, - profile: MatchInfo, selectedPlaylist?: PlaylistOption, - tournamentData: TournamentData, } export const MatchSidePlaylists = ({ - events, onSelect, - playlists, - profile, selectedPlaylist, - tournamentData, }: Props) => { + const { + events, + hideProfileCard, + matchPlaylists: playlists, + profile, + showProfileCard, + tournamentData, + } = useMatchPageStore() + const { isEventTabVisible, isVideoTabVisible, isWatchTabVisible, onTabClick, selectedTab, - } = useMatchSidePlaylists({ - events, - playlists, - tournamentData, - }) - - const { - hideProfileCard, - profileCardShown, - showProfileCard, - } = useMatchPageStore() + } = useMatchSidePlaylists() const TabPane = tabPanes[selectedTab] @@ -76,9 +59,7 @@ export const MatchSidePlaylists = ({ useEventListener({ callback: () => { const screenLandscape = isIOS ? window.orientation : window.screen.orientation.type - const yOffset = isIOS - ? containerRef.current?.offsetTop - : containerRef.current?.scrollTop + const yOffset = containerRef.current?.scrollTop const isScreenLandscape = isIOS ? (screenLandscape === 90 || screenLandscape === -90) : (screenLandscape === 'landscape-primary' || screenLandscape === 'landscape-secondary') @@ -86,12 +67,12 @@ export const MatchSidePlaylists = ({ if (yOffset && yOffset > 10 && !isScreenLandscape) hideProfileCard() if (yOffset && yOffset < 10) showProfileCard() }, - event: isIOS ? 'touchmove' : 'scroll', + event: 'scroll', target: containerRef, }) return ( - + {isWatchTabVisible ? ( @@ -119,15 +100,9 @@ export const MatchSidePlaylists = ({ ) : null} - - + ` margin-top: 14px; padding: 0 10px 0 14px; max-height: calc(100vh - 170px); - overflow-y: ${({ forVideoTab }) => (forVideoTab ? 'none' : 'scroll')}; + overflow-y: ${({ forVideoTab }) => (forVideoTab ? 'hidden' : 'auto')}; ${customScrollbar} @media ${devices.tablet} { - max-height: calc(100vh - 40px); margin-top: 15px; } ${isMobileDevice ? css` padding: 0 5px; - overflow-y: auto; - + overflow-y: hidden; + max-height: initial; + @media (max-width: 750px){ width: 100%; } @@ -138,27 +135,3 @@ export const BlockTitle = styled.span` color: rgba(255, 255, 255, 0.5); text-transform: uppercase; ` -export const BackToTopBtn = styled.div` - position: absolute; - left: 50%; - bottom: -100%; - background: rgba(0, 0, 0, 0.5); - border-radius: 0px 0 20px 20px; - width: 37px; - height: 34px; - z-index: 1; - cursor: pointer; - transform: translate(-50%, 6%); - - :after { - content: ''; - width: 10px; - height: 10px; - position: absolute; - border-left: 2px solid rgb(255, 255, 255); - border-top: 2px solid rgb(255, 255, 255); - top: 50%; - left: 50%; - transform: translate(-50%, -50%) rotate(45deg); - } -` diff --git a/src/features/MultiSourcePlayer/components/ProgressBar/index.tsx b/src/features/MultiSourcePlayer/components/ProgressBar/index.tsx index 2882700b..17be301b 100644 --- a/src/features/MultiSourcePlayer/components/ProgressBar/index.tsx +++ b/src/features/MultiSourcePlayer/components/ProgressBar/index.tsx @@ -1,6 +1,6 @@ import { useSlider } from 'features/StreamPlayer/hooks/useSlider' import { TimeTooltip } from 'features/StreamPlayer/components/TimeTooltip' -import { Scrubber } from 'features/StreamPlayer/components/ProgressBar/styled' +import { Scrubber, ScrubberContainer } from 'features/StreamPlayer/components/ProgressBar/styled' import { Chapters } from 'features/StreamPlayer/components/Chapters' import type { Props } from './hooks' @@ -35,9 +35,11 @@ export const ProgressBar = (props: ProgressBarProps) => { {isScrubberVisible === false ? null : ( - - - + + + + + )} ) diff --git a/src/features/MultiSourcePlayer/config.tsx b/src/features/MultiSourcePlayer/config.tsx index 4602985b..02537a31 100644 --- a/src/features/MultiSourcePlayer/config.tsx +++ b/src/features/MultiSourcePlayer/config.tsx @@ -1,3 +1,5 @@ -export const REWIND_SECONDS = 5 +import { isMobileDevice } from 'config/userAgent' + +export const REWIND_SECONDS = isMobileDevice ? 10 : 5 export const HOUR_IN_MILLISECONDS = 60 * 60 * 1000 diff --git a/src/features/MultiSourcePlayer/hooks/index.tsx b/src/features/MultiSourcePlayer/hooks/index.tsx index fb9cfa2d..244b8df5 100644 --- a/src/features/MultiSourcePlayer/hooks/index.tsx +++ b/src/features/MultiSourcePlayer/hooks/index.tsx @@ -274,7 +274,7 @@ export const useMultiSourcePlayer = ({ video2Ref, videoQualities, wrapperRef, - ...useControlsVisibility(isFullscreen), + ...useControlsVisibility(isFullscreen, playing), ...useVolume(), } } diff --git a/src/features/MultiSourcePlayer/index.tsx b/src/features/MultiSourcePlayer/index.tsx index e0e03a81..b41cf85f 100644 --- a/src/features/MultiSourcePlayer/index.tsx +++ b/src/features/MultiSourcePlayer/index.tsx @@ -12,6 +12,7 @@ import { 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 { isMobileDevice } from 'config/userAgent' @@ -27,13 +28,15 @@ export const MultiSourcePlayer = (props: Props) => { activePlayer, activeSrc, allPlayedProgress, + centerControlsVisible, chapters, - controlsVisible, duration, + hideCenterControls, isFirstChapterPlaying, isFullscreen, isLastChapterPlaying, loadedProgress, + mainControlsVisible, muted, nextSrc, numberOfChapters, @@ -63,6 +66,7 @@ export const MultiSourcePlayer = (props: Props) => { rewindForward, seek, selectedQuality, + showCenterControls, togglePlaying, video1Ref, video2Ref, @@ -76,7 +80,7 @@ export const MultiSourcePlayer = (props: Props) => { { onReady={onReady} /> - {isMobileDevice && isFullscreen && controlsVisible && profile && ( + {isMobileDevice && isFullscreen && mainControlsVisible && profile && ( {` ${profile.team1.score}-${profile.team2.score} `} @@ -132,22 +136,29 @@ export const MultiSourcePlayer = (props: Props) => { )} {ready && ( - - {REWIND_SECONDS} + + {isMobileDevice + ? + : {REWIND_SECONDS}} { + togglePlaying() + hideCenterControls() + }} /> - {REWIND_SECONDS} + {isMobileDevice + ? + : {REWIND_SECONDS}} )} { volume={volume} volumeInPercent={volumeInPercent} /> - + ) } diff --git a/src/features/SportsFilter/components/SelectSport/styled.tsx b/src/features/SportsFilter/components/SelectSport/styled.tsx index 9cb43fba..6dcb599e 100644 --- a/src/features/SportsFilter/components/SelectSport/styled.tsx +++ b/src/features/SportsFilter/components/SelectSport/styled.tsx @@ -22,6 +22,7 @@ export const ScSportsFilter = styled.div` width: 30%; letter-spacing: 0.15rem; font-size: 10px; + white-space: nowrap; ` : ''}; ` diff --git a/src/features/SportsFilter/components/SelectSportPopup/styled.tsx b/src/features/SportsFilter/components/SelectSportPopup/styled.tsx index bccc6693..b086d542 100644 --- a/src/features/SportsFilter/components/SelectSportPopup/styled.tsx +++ b/src/features/SportsFilter/components/SelectSportPopup/styled.tsx @@ -179,7 +179,7 @@ export const ScModal = styled(BaseModal)` height: auto; ${ModalCloseButton} { - padding: 16px 14px 15px 15px; + padding: 0; } ` : ''}; diff --git a/src/features/StreamPlayer/components/Chapters/styled.tsx b/src/features/StreamPlayer/components/Chapters/styled.tsx index 7a20409c..729b8132 100644 --- a/src/features/StreamPlayer/components/Chapters/styled.tsx +++ b/src/features/StreamPlayer/components/Chapters/styled.tsx @@ -1,4 +1,6 @@ -import styled from 'styled-components/macro' +import styled, { css } from 'styled-components/macro' + +import { isMobileDevice } from 'config/userAgent' export const ChapterList = styled.div` width: 100%; @@ -23,6 +25,12 @@ export const LoadedProgress = styled.div` background-color: rgba(255, 255, 255, 0.6); height: 100%; max-width: 100%; + + ${isMobileDevice + ? css` + background-color: rgba(255, 255, 255, 0.3); + ` + : ''} ` export const PlayedProgress = styled.div` @@ -31,4 +39,10 @@ export const PlayedProgress = styled.div` background-color: #CC0000; height: 100%; max-width: 100%; + + ${isMobileDevice + ? css` + background-color: rgba(255, 255, 255, 1); + ` + : ''} ` diff --git a/src/features/StreamPlayer/components/Controls/Components/ControlsMobile/styled.tsx b/src/features/StreamPlayer/components/Controls/Components/ControlsMobile/styled.tsx index 2b98d9b1..d61b5757 100644 --- a/src/features/StreamPlayer/components/Controls/Components/ControlsMobile/styled.tsx +++ b/src/features/StreamPlayer/components/Controls/Components/ControlsMobile/styled.tsx @@ -15,10 +15,9 @@ export const Controls = styled.div` flex-direction: column; align-items: center; filter: drop-shadow(0px 4px 4px rgba(0, 0, 0, 0.25)); - bottom: 0; + bottom: ${({ isFullscreen }) => (isFullscreen ? '20px' : 0)}; @media (orientation: landscape){ - bottom: ${({ isFullscreen }) => (isFullscreen ? '20px' : 0)}; width: 100%; left: 50%; transform: translateX(-50%); diff --git a/src/features/StreamPlayer/components/Controls/index.tsx b/src/features/StreamPlayer/components/Controls/index.tsx index 9542d828..1f14e9b5 100644 --- a/src/features/StreamPlayer/components/Controls/index.tsx +++ b/src/features/StreamPlayer/components/Controls/index.tsx @@ -7,17 +7,17 @@ import { isMobileDevice } from 'config/userAgent' import { secondsToHms } from 'helpers/secondsToHms' import { ProgressBar as ProgressBarMultiSource } from 'features/MultiSourcePlayer/components/ProgressBar' -import { Chapters } from 'features/MultiSourcePlayer/types' +import { Chapters as MultiSourceChapters } from 'features/MultiSourcePlayer/types' +import { Chapters as LiveChapters } from 'features/StreamPlayer/types' import { ControlsMobile } from './Components/ControlsMobile' import { ControlsWeb } from './Components/ControlsWeb' -// import { ProgressBar } from '../ProgressBar' +import { ProgressBar } from '../ProgressBar' export type ControlsProps = { - activeChapterIndex?: number, - allPlayedProgress?: number, + activeChapterIndex: number, + allPlayedProgress: number, backToLive?: () => void, - chapters?: Chapters, controlsVisible: boolean, duration: number, isFirstChapterPlaying?: boolean, @@ -25,12 +25,13 @@ export type ControlsProps = { isLastChapterPlaying?: boolean, isLive?: boolean, isStorage?: boolean, + liveChapters?: LiveChapters, loadedProgress: number, + multiSourceChapters?: MultiSourceChapters, muted: boolean, numberOfChapters?: number, onFullscreenClick: () => void, - onProgressChange?: (progress: number, seeking: boolean) => void, - onProgressChangeLive?: (progress: number) => void, + onProgressChange: (progress: number, seeking: boolean) => void, onQualitySelect: (quality: string) => void, onTouchEnd: DebouncedFunc<() => void>, onTouchStart: () => void, @@ -58,14 +59,14 @@ export const Controls = (props: ControlsProps) => { const { activeChapterIndex = 0, allPlayedProgress = 0, - chapters, controlsVisible, duration, isLive, isStorage, + liveChapters, loadedProgress, + multiSourceChapters, onProgressChange, - // onProgressChangeLive, onTouchEnd, onTouchStart, playedProgress, @@ -86,21 +87,24 @@ export const Controls = (props: ControlsProps) => { ]) const progressBarElement = useMemo(() => { if (isLive || isStorage) { - // return ( - // - // ) + return ( + + ) } return ( { }, [ activeChapterIndex, allPlayedProgress, - chapters, + liveChapters, + multiSourceChapters, controlsVisible, duration, isLive, isStorage, loadedProgress, onProgressChange, - // onProgressChangeLive, onTouchEnd, onTouchStart, playedProgress, diff --git a/src/features/StreamPlayer/components/ProgressBar/index.tsx b/src/features/StreamPlayer/components/ProgressBar/index.tsx index 0475d15d..47845144 100644 --- a/src/features/StreamPlayer/components/ProgressBar/index.tsx +++ b/src/features/StreamPlayer/components/ProgressBar/index.tsx @@ -1,6 +1,6 @@ import { useSlider } from 'features/StreamPlayer/hooks/useSlider' import { TimeTooltip } from 'features/StreamPlayer/components/TimeTooltip' -import { Scrubber } from 'features/StreamPlayer/components/ProgressBar/styled' +import { Scrubber, ScrubberContainer } from 'features/StreamPlayer/components/ProgressBar/styled' import { Chapters } from '../Chapters' import type { Props } from './hooks' @@ -8,7 +8,7 @@ import { useProgressBar } from './hooks' import { ProgressBarList } from './styled' export const ProgressBar = (props: Props) => { - const { onPlayedProgressChange } = props + const { isScrubberVisible, onPlayedProgressChange } = props const progressBarRef = useSlider({ onChange: onPlayedProgressChange }) const { calculatedChapters, @@ -18,9 +18,13 @@ export const ProgressBar = (props: Props) => { return ( - - - + {isScrubberVisible === false ? null : ( + + + + + + )} ) } diff --git a/src/features/StreamPlayer/components/ProgressBar/styled.tsx b/src/features/StreamPlayer/components/ProgressBar/styled.tsx index bce8da4c..e3fa149c 100644 --- a/src/features/StreamPlayer/components/ProgressBar/styled.tsx +++ b/src/features/StreamPlayer/components/ProgressBar/styled.tsx @@ -8,6 +8,23 @@ export const ProgressBarList = styled.div` flex-grow: 1; height: 4px; position: relative; + background-color: rgba(255, 255, 255, 0.3); + cursor: pointer; + + ${isMobileDevice + ? css` + height: 1px; + ` + : ''} +` +export const ScrubberContainer = styled.div` + ${isMobileDevice + ? css` + position: relative; + margin: 0 7px; + ` + : ''} + ` export const Scrubber = styled.div` @@ -15,24 +32,24 @@ export const Scrubber = styled.div` outline: none; position: absolute; top: 0; - transform: translate(-50%, -43%); + transform: translate(-50%, -38%); z-index: 3; width: 18px; height: 18px; background-color: #CC0000; border-radius: 50%; cursor: pointer; - + :hover ${Wrapper} { visibility: visible; } ${isMobileDevice ? css` - width: 30px; - height: 30px; - background-clip: padding-box; - border: 10px solid transparent; + width: 14px; + height: 14px; + background-color: #FFFFFF; + transform: translate(-50%, -48%); ` : ''} ` diff --git a/src/features/StreamPlayer/components/RewindMobile/index.tsx b/src/features/StreamPlayer/components/RewindMobile/index.tsx new file mode 100644 index 00000000..e489e16a --- /dev/null +++ b/src/features/StreamPlayer/components/RewindMobile/index.tsx @@ -0,0 +1,67 @@ +import { + useCallback, + useMemo, + useState, +} from 'react' + +import debounce from 'lodash/debounce' + +import { + Background, + RewindIcon, + Time, +} from './styled' + +export type RewindProps = { + isBackward?: boolean, + isForward?: boolean, + rewindCallback: () => void, +} + +const RewindMobile = ({ + isBackward, + isForward, + rewindCallback, +}: RewindProps) => { + const [isActive, setIsActive] = useState(false) + const [time, setTime] = useState(0) + + const resetData = useCallback(() => { + setIsActive(false) + setTime(0) + }, []) + + const resetDataDebounced = useMemo(() => ( + debounce(resetData, 1500) + ), [resetData]) + + const handleDoubleClick = useCallback(() => { + setIsActive(true) + rewindCallback() + setTime(time + 10) + resetDataDebounced() + }, [resetDataDebounced, rewindCallback, time]) + + const TimeContent = useMemo(() => ( + + ), [isBackward, isForward, time]) + + return ( + + {isActive && TimeContent} + + ) +} + +export default RewindMobile diff --git a/src/features/StreamPlayer/components/RewindMobile/styled.tsx b/src/features/StreamPlayer/components/RewindMobile/styled.tsx new file mode 100644 index 00000000..c66681ac --- /dev/null +++ b/src/features/StreamPlayer/components/RewindMobile/styled.tsx @@ -0,0 +1,41 @@ +import styled, { css } from 'styled-components/macro' + +type RewindProps = { + isActive?: boolean, + isBackward?: boolean, + isForward?: boolean, +} + +export const Background = styled.div` + width: 920px; + height: 920px; + border-radius: 50%; + background-color: ${({ isActive }) => (isActive ? 'rgba(0, 0, 0, 0.4)' : 'rgba(0, 0, 0, 0)')}; + position: absolute; + ${({ isBackward }) => isBackward && css`right: 60%;`} + ${({ isForward }) => isForward && css`left: 60%;`} + transition: all 0.3s ease-in-out; +` + +export const Time = styled.div` + position: absolute; + color: #FFFFFF; + top: 50%; + font-size: 20px; + transform: translate(0, -50%); + display: flex; + align-items: center; + user-select: none; + + ${({ isBackward }) => isBackward && css`right: 2%;`} + ${({ isForward }) => isForward && css`left: 2%;`} + + > :first-child { + margin-right: 10px; + } +` + +export const RewindIcon = styled.img` + width: 43px; + height: 28px; +` diff --git a/src/features/StreamPlayer/components/YoutubePlayer/index.tsx b/src/features/StreamPlayer/components/YoutubePlayer/index.tsx index daf63fd2..214ffccb 100644 --- a/src/features/StreamPlayer/components/YoutubePlayer/index.tsx +++ b/src/features/StreamPlayer/components/YoutubePlayer/index.tsx @@ -1,10 +1,12 @@ import YouTube from 'react-youtube' +import { useMatchPageStore } from 'features/MatchPage/store' + import { PlayerWrapper } from '../../styled' import { useVideoPlayer, Props } from '../../hooks' export const YoutubePlayer = (props: Props) => { - const { profile } = props + const { profile } = useMatchPageStore() const { onMouseMove, diff --git a/src/features/StreamPlayer/config.tsx b/src/features/StreamPlayer/config.tsx index 77418095..eb585004 100644 --- a/src/features/StreamPlayer/config.tsx +++ b/src/features/StreamPlayer/config.tsx @@ -2,6 +2,8 @@ import type { HlsConfig } from 'hls.js' import { readToken } from 'helpers/token' +import { isMobileDevice } from 'config/userAgent' + export const streamConfig: Partial = { liveSyncDuration: 30, maxBufferLength: 30, @@ -12,6 +14,6 @@ export const streamConfig: Partial = { }, } -export const REWIND_SECONDS = 5 +export const REWIND_SECONDS = isMobileDevice ? 10 : 5 export const HOUR_IN_MILLISECONDS = 60 * 60 * 1000 diff --git a/src/features/StreamPlayer/hooks/index.tsx b/src/features/StreamPlayer/hooks/index.tsx index 6eb9f291..e65615e3 100644 --- a/src/features/StreamPlayer/hooks/index.tsx +++ b/src/features/StreamPlayer/hooks/index.tsx @@ -20,8 +20,6 @@ import { useLiveMatch } from 'features/MatchPage/components/LiveMatch/hooks' import type { Chapters } from 'features/StreamPlayer/types' -import { MatchInfo } from 'requests/getMatchInfo' - import { REWIND_SECONDS } from '../config' import { useHlsPlayer } from './useHlsPlayer' import { useFullscreen } from './useFullscreen' @@ -50,11 +48,10 @@ const initialState = { export type Props = { chapters: Chapters, - isLive?: boolean, + isLive: boolean, onDurationChange?: (duration: number) => void, onPlayingChange: (playing: boolean) => void, onProgressChange: (seconds: number) => void, - profile?: MatchInfo, resumeFrom?: number, url?: string, } @@ -414,7 +411,7 @@ export const useVideoPlayer = ({ url, videoRef, wrapperRef, - ...useControlsVisibility(isFullscreen), + ...useControlsVisibility(isFullscreen, playing), ...useVolume(), ...useVideoQuality(hls), } diff --git a/src/features/StreamPlayer/hooks/useControlsVisibility.tsx b/src/features/StreamPlayer/hooks/useControlsVisibility.tsx index efead7dd..ca7c8134 100644 --- a/src/features/StreamPlayer/hooks/useControlsVisibility.tsx +++ b/src/features/StreamPlayer/hooks/useControlsVisibility.tsx @@ -1,40 +1,56 @@ -import { - useMemo, - useState, - useCallback, -} from 'react' +import { useCallback, useMemo } from 'react' import debounce from 'lodash/debounce' -export const useControlsVisibility = (isFullscreen: boolean) => { - const [controlsVisible, setControlsVisibility] = useState(true) +import { useToggle } from 'hooks' - const show = useCallback(() => { - setControlsVisibility(true) - }, []) +export const useControlsVisibility = (isFullscreen: boolean, playing: boolean) => { + const { + close: hideCenterControls, + isOpen: centerControlsVisible, + open: showCenterControls, + } = useToggle(playing) - const hide = useCallback(() => { - setControlsVisibility(false) - }, []) + const hideCenterDebounced = useMemo(() => ( + debounce(hideCenterControls, 2000) + ), [hideCenterControls]) + + const showCenter = useCallback(() => { + if (playing) { + showCenterControls() + hideCenterDebounced() + } else { + showCenterControls() + } + }, [hideCenterDebounced, playing, showCenterControls]) + + const { + close: hideMainControls, + isOpen: mainControlsVisible, + open: showMainControls, + } = useToggle(true) const hideDebounced = useMemo( - () => debounce(hide, 3000), - [hide], + () => debounce(hideMainControls, 3000), + [hideMainControls], ) const onMouseMove = () => { - show() + showMainControls() if (isFullscreen) { hideDebounced() } } return { - controlsVisible, - onMouseEnter: show, - onMouseLeave: hide, + centerControlsVisible, + hideCenterControls, + mainControlsVisible, + onMouseEnter: showMainControls, + onMouseLeave: hideMainControls, onMouseMove, onTouchEnd: hideDebounced, - onTouchStart: show, + onTouchStart: showMainControls, + showCenterControls: showCenter, } } diff --git a/src/features/StreamPlayer/index.tsx b/src/features/StreamPlayer/index.tsx index 95ef3e48..2d8318e7 100644 --- a/src/features/StreamPlayer/index.tsx +++ b/src/features/StreamPlayer/index.tsx @@ -1,62 +1,49 @@ -import { Fragment } from 'react' - -import { T9n } from 'features/T9n' import { Loader } from 'features/Loader' import { VideoPlayer } from 'features/VideoPlayer' +import { useMatchPageStore } from 'features/MatchPage/store' +import { Name } from 'features/Name' import { WaterMark } from 'components/WaterMark' -import { secondsToHms } from 'helpers' +import { isMobileDevice } from 'config/userAgent' -import { HOUR_IN_MILLISECONDS, REWIND_SECONDS } from './config' -import { VolumeBar } from './components/VolumeBar' -import { Settings } from './components/Settings' -import { ProgressBar } from './components/ProgressBar' +import { REWIND_SECONDS } from './config' import { PlayerWrapper, - Controls, - ControlsRow, - ControlsGroup, CenterControls, PlayStop, - Fullscreen, LoaderWrapper, Backward, Forward, - PlaybackTime, ControlsGradient, - LiveBtn, - ChaptersText, - Next, - Prev, - // WaterMark, + TeamsDetailsWrapper, } from './styled' import type { Props } from './hooks' import { useVideoPlayer } from './hooks' import { useAuthStore } from '../AuthStore' +import { Controls } from './components/Controls' +import RewindMobile from './components/RewindMobile' /** * HLS плеер, применяется на лайв и завершенных матчах */ export const StreamPlayer = (props: Props) => { - const { isLive, profile } = props + const { profile } = useMatchPageStore() const { user } = useAuthStore() const { activeChapterIndex, - allPlayedProgress, backToLive, buffering, + centerControlsVisible, chapters, - controlsVisible, duration, - isFirstChapterPlaying, + hideCenterControls, isFullscreen, - isLastChapterPlaying, loadedProgress, + mainControlsVisible, muted, - numberOfChapters, onDuration, onError, onFullscreenClick, @@ -79,13 +66,12 @@ export const StreamPlayer = (props: Props) => { onWaiting, playedProgress, playing, - playNextChapter, - playPrevChapter, ready, rewindBackward, rewindForward, seek, selectedQuality, + showCenterControls, togglePlaying, url, videoQualities, @@ -98,7 +84,7 @@ export const StreamPlayer = (props: Props) => { { onError={onError} crossOrigin='use-credentials' /> + + {isMobileDevice && isFullscreen && mainControlsVisible && profile && ( + + + {` ${profile.team1.score}-${profile.team2.score} `} + + + )} + {ready && ( - - - {REWIND_SECONDS} - + + {isMobileDevice + ? + : {REWIND_SECONDS}} { + togglePlaying() + hideCenterControls() + }} /> - - {REWIND_SECONDS} - + {isMobileDevice + ? + : {REWIND_SECONDS}} )} - - - - - - - - { - numberOfChapters > 1 && ( - - playPrevChapter()} - /> - - {activeChapterIndex + 1} / {numberOfChapters} - - playNextChapter()} - /> - - ) - } - - { - isLive - ? ( - - {secondsToHms(allPlayedProgress / 1000)} - - ) - : ( - HOUR_IN_MILLISECONDS ? 150 : 130}> - {secondsToHms(allPlayedProgress / 1000)} - {' / '} - {secondsToHms(duration / 1000)} - - ) - } - {REWIND_SECONDS} - {REWIND_SECONDS} - - - { - isLive && ( - - - - ) - } - - - - - - + + ) } diff --git a/src/features/StreamPlayer/styled.tsx b/src/features/StreamPlayer/styled.tsx index d99334aa..8ee6ff80 100644 --- a/src/features/StreamPlayer/styled.tsx +++ b/src/features/StreamPlayer/styled.tsx @@ -170,11 +170,14 @@ export const PlayStop = styled(ButtonBase)` )}; ${isMobileDevice ? css` - width: 20%; - height: 60%; - margin-right: 0; - padding: 0; - ` + width: ${sizes.sm}px; + height: ${sizes.sm}px; + margin-right: 0; + padding: 0; + position: absolute; + left: 50%; + transform: translate(-50%, 0); + ` : ''}; ` @@ -271,6 +274,7 @@ export const PlaybackTime = styled.span` ` type CenterControlsProps = { + controlsVisible: boolean, playing: boolean, } @@ -287,11 +291,14 @@ export const CenterControls = styled.div` transition: opacity 0.3s ease-in-out; opacity: ${({ playing }) => (playing ? 0 : 1)}; pointer-events: ${({ playing }) => (playing ? 'none' : 'auto')}; - ${isMobileDevice - ? css` - width: 70%; - ` - : ''}; + + ${({ controlsVisible, playing }) => isMobileDevice && css` + width: 100%; + height: 100%; + overflow: hidden; + opacity: ${controlsVisible || !playing ? 1 : 0}; + pointer-events: ${controlsVisible || !playing ? 'auto' : 'none'}; + `} ` export const LiveBtn = styled(ButtonBase)` diff --git a/src/features/TournamentList/components/TournamentMobile/styled.tsx b/src/features/TournamentList/components/TournamentMobile/styled.tsx index 1dfdacaa..e38eda59 100644 --- a/src/features/TournamentList/components/TournamentMobile/styled.tsx +++ b/src/features/TournamentList/components/TournamentMobile/styled.tsx @@ -35,6 +35,7 @@ export const CardWrapper = styled.div<{ padding: 10px; width: 100%; height: 50px; + justify-content: space-between; ` : ''}; ` @@ -61,7 +62,7 @@ export const CountMatches = styled.span<{ color?: string }>` color: ${({ color }) => color}; width: 20px; text-align: end; - margin: 0 9px 0 20px; + margin: 0 9px 0 10px; ` export const ScFirstInfo = styled.div` @@ -69,7 +70,8 @@ export const ScFirstInfo = styled.div` flex-direction: row; align-items: center; justify-content: flex-start; - width: 80%; + margin-right: 10px; + overflow: hidden; ` export const ScSecondInfo = styled.div` @@ -77,7 +79,6 @@ export const ScSecondInfo = styled.div` flex-direction: row; align-items: center; justify-content: flex-end; - width: 100%; ` export const ScMatchesWrapper = styled.ul` diff --git a/src/features/TournamentSubtitle/index.tsx b/src/features/TournamentSubtitle/index.tsx index 408d0b2d..1191ef24 100644 --- a/src/features/TournamentSubtitle/index.tsx +++ b/src/features/TournamentSubtitle/index.tsx @@ -2,7 +2,7 @@ import { Fragment } from 'react' import { SportIcon } from 'components/SportIcon/SportIcon' -import { useName } from 'features/Name' +import { Name } from 'features/Name' import { useUserFavoritesStore } from 'features/UserFavorites/store' import { ProfileTypes, SportTypes } from 'config' @@ -12,12 +12,13 @@ import { usePageParams } from 'hooks/usePageParams' import { TournamentType } from 'requests' +import { isMatchPage } from 'helpers/isMatchPage' + import { CountryFlag, FavoriteSign, - NameSignWrapper, Wrapper, - TournamentName, + StyledLink, } from './styled' type Props = { @@ -33,7 +34,6 @@ export const TournamentSubtitle = ({ }: Props) => { const { isInFavorites } = useUserFavoritesStore() const { sportType: sportTypeFromUrl } = usePageParams() - const tournamentName = useName(tournament) const tournamentInFavorites = isInFavorites(ProfileTypes.TOURNAMENTS, tournament.id) return ( @@ -44,14 +44,16 @@ export const TournamentSubtitle = ({ )} - {tournament && ( - - - {tournamentName} - - {tournamentInFavorites && } - - )} + + + + {tournamentInFavorites && } ) } diff --git a/src/features/TournamentSubtitle/styled.tsx b/src/features/TournamentSubtitle/styled.tsx index 7d35a962..95e2e352 100644 --- a/src/features/TournamentSubtitle/styled.tsx +++ b/src/features/TournamentSubtitle/styled.tsx @@ -2,6 +2,8 @@ import styled, { css } from 'styled-components' import { isMobileDevice } from 'config/userAgent' +import { ProfileLink } from 'features/ProfileLink' + export const Wrapper = styled.div` display: flex; align-items: center; @@ -13,6 +15,7 @@ export const CountryFlag = styled.img` margin-left: 0.567rem; object-fit: contain; object-position: bottom; + ${isMobileDevice ? css` width: 12px; @@ -27,31 +30,32 @@ export const NameSignWrapper = styled.div` max-width: 90%; align-items: center; ` - -const nameStyles = css` - text-overflow: ellipsis; - white-space: nowrap; - overflow: hidden; -` - -type TTournamentName = { +type StyledLinkProps = { + isMatchPage?: boolean, isLeftSide?: boolean, } -export const TournamentName = styled.span` +export const StyledLink = styled(ProfileLink)` color: rgba(255, 255, 255, 0.7); font-size: 0.567rem; line-height: 0.95rem; margin-left: ${({ isLeftSide }) => (isLeftSide ? '0px' : '0.567rem')}; - ${isMobileDevice + + &:hover { + text-decoration: underline; + color: rgba(255, 255, 255, 1); + } + + ${({ isMatchPage }) => (isMatchPage ? css` - font-size: 10px; - line-height: 100%; - max-width: 100%; - ` - : ''}; + font-size: 14px; - ${nameStyles} + ${isMobileDevice + ? css` + font-size: 10px; + ` + : ''}; + ` : null)} ` type FavoriteSignProps = {