Ott 892 match profile imprs (#327)
* refactor(892): split match players into 2 components (#324) * Ott 892 part 2 (#325) * fix(892): micro fix * fix(892): hls player ui impr. * fix(892): finished match player ui impr. (#326) * fix(892): rewind btw episodes (#334) * refactor(892): removed resuming from MultiSourcePlayer (#335)keep-around/af30b88d367751c9e05a735e4a0467a96238ef47
parent
e3a683f37d
commit
20e58e7c5a
|
After Width: | Height: | Size: 418 B |
|
After Width: | Height: | Size: 436 B |
@ -0,0 +1,91 @@ |
|||||||
|
import { useEffect } from 'react' |
||||||
|
|
||||||
|
import isEqual from 'lodash/isEqual' |
||||||
|
|
||||||
|
import type { MatchInfo } from 'requests' |
||||||
|
|
||||||
|
import { |
||||||
|
useSportNameParam, |
||||||
|
usePageId, |
||||||
|
useToggle, |
||||||
|
} from 'hooks' |
||||||
|
|
||||||
|
import type { Settings } from 'features/MatchPopup' |
||||||
|
import { useMatchPopupStore } from 'features/MatchPopup' |
||||||
|
import { usePlayerProgressReporter } from 'features/MatchPage/hooks/usePlayerProgressReporter' |
||||||
|
|
||||||
|
import { useEpisodes } from './useEpisodes' |
||||||
|
import { useChapters } from './useChapters' |
||||||
|
|
||||||
|
export type Props = { |
||||||
|
profile: MatchInfo, |
||||||
|
} |
||||||
|
|
||||||
|
export const useFinishedMatch = ({ profile }: Props) => { |
||||||
|
const { |
||||||
|
actions, |
||||||
|
fetchMatchPlaylists, |
||||||
|
handlePlaylistClick, |
||||||
|
matchPlaylists, |
||||||
|
selectedPlaylist, |
||||||
|
setMatch, |
||||||
|
setSettings, |
||||||
|
settings, |
||||||
|
} = useMatchPopupStore() |
||||||
|
const { sportType } = useSportNameParam() |
||||||
|
const matchId = usePageId() |
||||||
|
const { |
||||||
|
close: closeSettingsPopup, |
||||||
|
isOpen: isSettingsPopupOpen, |
||||||
|
open: openSettingsPopup, |
||||||
|
} = useToggle() |
||||||
|
|
||||||
|
const { episodes } = useEpisodes() |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
if (profile) { |
||||||
|
const match = { |
||||||
|
calc: false, |
||||||
|
id: matchId, |
||||||
|
live: false, |
||||||
|
sportType, |
||||||
|
team1: profile.team1, |
||||||
|
team2: profile.team2, |
||||||
|
} |
||||||
|
setMatch(match) |
||||||
|
fetchMatchPlaylists(match) |
||||||
|
} |
||||||
|
}, [ |
||||||
|
matchId, |
||||||
|
profile, |
||||||
|
setMatch, |
||||||
|
sportType, |
||||||
|
fetchMatchPlaylists, |
||||||
|
]) |
||||||
|
|
||||||
|
const setEpisodesSettings = (newSettings: Settings) => { |
||||||
|
const settingsChanged = !isEqual(newSettings, settings) |
||||||
|
if (settingsChanged) { |
||||||
|
setSettings(newSettings) |
||||||
|
} |
||||||
|
closeSettingsPopup() |
||||||
|
} |
||||||
|
|
||||||
|
return { |
||||||
|
actions, |
||||||
|
closeSettingsPopup, |
||||||
|
isSettingsPopupOpen, |
||||||
|
onPlaylistSelect: handlePlaylistClick, |
||||||
|
openSettingsPopup, |
||||||
|
playlists: matchPlaylists, |
||||||
|
profile, |
||||||
|
selectedPlaylist, |
||||||
|
setEpisodesSettings, |
||||||
|
settings, |
||||||
|
...useChapters({ |
||||||
|
episodes, |
||||||
|
selectedPlaylist, |
||||||
|
}), |
||||||
|
...usePlayerProgressReporter(), |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,72 @@ |
|||||||
|
import { Fragment } from 'react' |
||||||
|
|
||||||
|
import isEmpty from 'lodash/isEmpty' |
||||||
|
|
||||||
|
import { MatchSidePlaylists } from 'features/MatchSidePlaylists' |
||||||
|
import { MultiSourcePlayer } from 'features/MultiSourcePlayer' |
||||||
|
|
||||||
|
import { MatchProfileCard } from '../MatchProfileCard' |
||||||
|
import { SettingsPopup } from '../SettingsPopup' |
||||||
|
|
||||||
|
import type { Props } from './hooks' |
||||||
|
import { useFinishedMatch } from './hooks' |
||||||
|
import { Container } from '../../styled' |
||||||
|
import { Modal } from './styled' |
||||||
|
|
||||||
|
export const FinishedMatch = (props: Props) => { |
||||||
|
const { profile } = props |
||||||
|
const { |
||||||
|
actions, |
||||||
|
chapters, |
||||||
|
closeSettingsPopup, |
||||||
|
isSettingsPopupOpen, |
||||||
|
onPlayerProgressChange, |
||||||
|
onPlayingChange, |
||||||
|
onPlaylistSelect, |
||||||
|
openSettingsPopup, |
||||||
|
playlists, |
||||||
|
selectedPlaylist, |
||||||
|
setEpisodesSettings, |
||||||
|
settings, |
||||||
|
} = useFinishedMatch(props) |
||||||
|
|
||||||
|
return ( |
||||||
|
<Fragment> |
||||||
|
<Modal |
||||||
|
close={closeSettingsPopup} |
||||||
|
isOpen={isSettingsPopupOpen} |
||||||
|
withCloseButton={false} |
||||||
|
> |
||||||
|
<SettingsPopup |
||||||
|
actions={actions} |
||||||
|
onWatchEpisodesClick={setEpisodesSettings} |
||||||
|
settings={settings} |
||||||
|
closePopup={closeSettingsPopup} |
||||||
|
profile={profile} |
||||||
|
selectedPlaylist={selectedPlaylist} |
||||||
|
/> |
||||||
|
</Modal> |
||||||
|
|
||||||
|
<Container> |
||||||
|
<MatchProfileCard profile={profile} /> |
||||||
|
{!isEmpty(chapters) && ( |
||||||
|
<MultiSourcePlayer |
||||||
|
chapters={chapters} |
||||||
|
onPlayingChange={onPlayingChange} |
||||||
|
onProgressChange={onPlayerProgressChange} |
||||||
|
/> |
||||||
|
)} |
||||||
|
</Container> |
||||||
|
|
||||||
|
{playlists && ( |
||||||
|
<MatchSidePlaylists |
||||||
|
playlists={playlists} |
||||||
|
selectedPlaylist={selectedPlaylist} |
||||||
|
onSelect={onPlaylistSelect} |
||||||
|
profile={profile} |
||||||
|
openPopup={openSettingsPopup} |
||||||
|
/> |
||||||
|
)} |
||||||
|
</Fragment> |
||||||
|
) |
||||||
|
} |
||||||
@ -0,0 +1,27 @@ |
|||||||
|
import styled from 'styled-components/macro' |
||||||
|
|
||||||
|
import { devices } from 'config/devices' |
||||||
|
|
||||||
|
import { Modal as BaseModal } from 'features/Modal' |
||||||
|
import { ModalWindow } from 'features/Modal/styled' |
||||||
|
|
||||||
|
export const Modal = styled(BaseModal)` |
||||||
|
background-color: rgba(0, 0, 0, 0.7); |
||||||
|
|
||||||
|
${ModalWindow} { |
||||||
|
width: 1222px; |
||||||
|
padding: 20px 0; |
||||||
|
background-color: #3F3F3F; |
||||||
|
border-radius: 5px; |
||||||
|
|
||||||
|
@media ${devices.tablet} { |
||||||
|
width: 100vw; |
||||||
|
} |
||||||
|
|
||||||
|
@media ${devices.mobile} { |
||||||
|
height: 100vh; |
||||||
|
padding: 0; |
||||||
|
background-color: transparent; |
||||||
|
} |
||||||
|
} |
||||||
|
` |
||||||
@ -0,0 +1,30 @@ |
|||||||
|
import { useEffect, useState } from 'react' |
||||||
|
|
||||||
|
import type { LiveVideos } from 'requests' |
||||||
|
import { getLiveVideos } from 'requests' |
||||||
|
|
||||||
|
import { |
||||||
|
useSportNameParam, |
||||||
|
usePageId, |
||||||
|
} from 'hooks' |
||||||
|
|
||||||
|
import { usePlayerProgressReporter } from 'features/MatchPage/hooks/usePlayerProgressReporter' |
||||||
|
import { useLastPlayPosition } from 'features/MatchPage/hooks/useLastPlayPosition' |
||||||
|
|
||||||
|
export const useLiveMatch = () => { |
||||||
|
const { sportType } = useSportNameParam() |
||||||
|
const matchId = usePageId() |
||||||
|
|
||||||
|
const [liveVideos, setLiveVideos] = useState<LiveVideos>([]) |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
getLiveVideos(sportType, matchId).then(setLiveVideos) |
||||||
|
}, |
||||||
|
[sportType, matchId]) |
||||||
|
|
||||||
|
return { |
||||||
|
matchUrl: liveVideos[0] || '', |
||||||
|
...usePlayerProgressReporter(), |
||||||
|
...useLastPlayPosition(), |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,32 @@ |
|||||||
|
import type { MatchInfo } from 'requests' |
||||||
|
|
||||||
|
import { StreamPlayer } from 'features/StreamPlayer' |
||||||
|
|
||||||
|
import { useLiveMatch } from './hooks' |
||||||
|
import { MatchProfileCard } from '../MatchProfileCard' |
||||||
|
import { Container } from '../../styled' |
||||||
|
|
||||||
|
type Props = { |
||||||
|
profile: MatchInfo, |
||||||
|
} |
||||||
|
|
||||||
|
export const LiveMatch = ({ profile }: Props) => { |
||||||
|
const { |
||||||
|
lastPlayPosition, |
||||||
|
matchUrl, |
||||||
|
onPlayerProgressChange, |
||||||
|
onPlayingChange, |
||||||
|
} = useLiveMatch() |
||||||
|
|
||||||
|
return ( |
||||||
|
<Container marginRight={320}> |
||||||
|
<MatchProfileCard profile={profile} /> |
||||||
|
<StreamPlayer |
||||||
|
url={matchUrl} |
||||||
|
onPlayingChange={onPlayingChange} |
||||||
|
onProgressChange={onPlayerProgressChange} |
||||||
|
resumeFrom={lastPlayPosition.second} |
||||||
|
/> |
||||||
|
</Container> |
||||||
|
) |
||||||
|
} |
||||||
@ -1,115 +0,0 @@ |
|||||||
import { useEffect, useState } from 'react' |
|
||||||
|
|
||||||
import isEqual from 'lodash/isEqual' |
|
||||||
|
|
||||||
import type { LiveVideos } from 'requests' |
|
||||||
import { getLiveVideos } from 'requests' |
|
||||||
import { |
|
||||||
useSportNameParam, |
|
||||||
usePageId, |
|
||||||
useToggle, |
|
||||||
} from 'hooks' |
|
||||||
import { Settings, useMatchPopupStore } from 'features/MatchPopup' |
|
||||||
|
|
||||||
import { useLastPlayPosition } from './useLastPlayPosition' |
|
||||||
import { useEpisodes } from './useEpisodes' |
|
||||||
import { useChapters } from './useChapters' |
|
||||||
import { useMatchProfile } from './useMatchProfile' |
|
||||||
|
|
||||||
export const useMatchPage = () => { |
|
||||||
const { |
|
||||||
actions, |
|
||||||
closePopup, |
|
||||||
fetchMatchPlaylists, |
|
||||||
handlePlaylistClick, |
|
||||||
matchPlaylists, |
|
||||||
selectedPlaylist, |
|
||||||
setMatch, |
|
||||||
setSettings, |
|
||||||
settings, |
|
||||||
} = useMatchPopupStore() |
|
||||||
const [isFinishedMatch, setFinishedMatch] = useState(Boolean(selectedPlaylist)) |
|
||||||
const [liveVideos, setLiveVideos] = useState<LiveVideos>([]) |
|
||||||
const profile = useMatchProfile() |
|
||||||
const { sportType } = useSportNameParam() |
|
||||||
const matchId = usePageId() |
|
||||||
|
|
||||||
const { |
|
||||||
close, |
|
||||||
isOpen, |
|
||||||
open, |
|
||||||
} = useToggle() |
|
||||||
|
|
||||||
const { episodes } = useEpisodes() |
|
||||||
|
|
||||||
useEffect(() => { |
|
||||||
if (!isFinishedMatch) { |
|
||||||
getLiveVideos(sportType, matchId) |
|
||||||
.then(setLiveVideos) |
|
||||||
.catch(() => setFinishedMatch(true)) |
|
||||||
} |
|
||||||
}, |
|
||||||
[ |
|
||||||
isFinishedMatch, |
|
||||||
sportType, |
|
||||||
matchId, |
|
||||||
]) |
|
||||||
|
|
||||||
useEffect(() => { |
|
||||||
if (profile && isFinishedMatch) { |
|
||||||
const match = { |
|
||||||
calc: false, |
|
||||||
id: matchId, |
|
||||||
live: false, |
|
||||||
sportType, |
|
||||||
team1: profile.team1, |
|
||||||
team2: profile.team2, |
|
||||||
} |
|
||||||
setMatch(match) |
|
||||||
fetchMatchPlaylists(match) |
|
||||||
} |
|
||||||
}, [ |
|
||||||
matchId, |
|
||||||
profile, |
|
||||||
setMatch, |
|
||||||
sportType, |
|
||||||
isFinishedMatch, |
|
||||||
fetchMatchPlaylists, |
|
||||||
]) |
|
||||||
|
|
||||||
const setEpisodesSettings = (values: Settings) => { |
|
||||||
const isSettingsChanged = !isEqual(values, settings) |
|
||||||
if (isSettingsChanged) { |
|
||||||
setSettings({ |
|
||||||
episodeDuration: values.episodeDuration, |
|
||||||
selectedActions: values.selectedActions, |
|
||||||
selectedFormat: values.selectedFormat, |
|
||||||
}) |
|
||||||
} |
|
||||||
close() |
|
||||||
} |
|
||||||
|
|
||||||
useEffect(() => { |
|
||||||
closePopup() |
|
||||||
}, [closePopup]) |
|
||||||
|
|
||||||
return { |
|
||||||
actions, |
|
||||||
closeSettingsPopup: close, |
|
||||||
isOpen, |
|
||||||
onPlaylistSelect: handlePlaylistClick, |
|
||||||
openSettingsPopup: open, |
|
||||||
playlists: matchPlaylists, |
|
||||||
profile, |
|
||||||
selectedPlaylist, |
|
||||||
setEpisodesSettings, |
|
||||||
settings, |
|
||||||
url: liveVideos[0] || '', |
|
||||||
...useChapters({ |
|
||||||
episodes, |
|
||||||
isFinishedMatch, |
|
||||||
selectedPlaylist, |
|
||||||
}), |
|
||||||
...useLastPlayPosition(), |
|
||||||
} |
|
||||||
} |
|
||||||
@ -0,0 +1,3 @@ |
|||||||
|
export const REWIND_SECONDS = 5 |
||||||
|
|
||||||
|
export const HOUR_IN_MILLISECONDS = 60 * 60 * 1000 |
||||||
@ -0,0 +1,32 @@ |
|||||||
|
import styled from 'styled-components/macro' |
||||||
|
|
||||||
|
import { ButtonBase } from 'features/StreamPlayer/styled' |
||||||
|
|
||||||
|
export const ChaptersText = styled.span` |
||||||
|
margin: 0 14px; |
||||||
|
font-weight: 500; |
||||||
|
font-size: 16px; |
||||||
|
color: #fff; |
||||||
|
text-align: center; |
||||||
|
` |
||||||
|
|
||||||
|
type PrevProps = { |
||||||
|
disabled?: boolean, |
||||||
|
} |
||||||
|
|
||||||
|
export const Prev = styled(ButtonBase)<PrevProps>` |
||||||
|
width: 29px; |
||||||
|
height: 28px; |
||||||
|
background-image: url(/images/player-prev.svg); |
||||||
|
|
||||||
|
${({ disabled }) => ( |
||||||
|
disabled |
||||||
|
? 'opacity: 0.5;' |
||||||
|
: '' |
||||||
|
)} |
||||||
|
` |
||||||
|
|
||||||
|
export const Next = styled(Prev)` |
||||||
|
margin-right: 24px; |
||||||
|
transform: rotate(180deg); |
||||||
|
` |
||||||
Loading…
Reference in new issue