Ott 1701 part 1 (#552)

keep-around/fdb88b04b32b9392e76795099e2ec47c9856b38b
Mirlan 4 years ago committed by Andrei Dekterev
parent c565ff1b55
commit 95d0194c5b
  1. 2
      src/features/MatchPage/components/FinishedMatch/hooks/useEpisodes.tsx
  2. 52
      src/features/MatchPage/components/LiveMatch/index.tsx
  3. 7
      src/features/MatchPage/components/SubscriptionGuard/index.tsx
  4. 5
      src/features/MatchPage/helpers/buildPlaylists.tsx
  5. 68
      src/features/MatchPage/index.tsx
  6. 83
      src/features/MatchPage/store/hooks/index.tsx
  7. 28
      src/features/MatchPage/store/hooks/useEvents.tsx
  8. 25
      src/features/MatchPage/store/hooks/useEventsLexics.tsx
  9. 72
      src/features/MatchPage/store/hooks/useMatchData.tsx
  10. 81
      src/features/MatchPage/store/hooks/useMatchPlaylists.tsx
  11. 21
      src/features/MatchPage/store/hooks/usePlaylistLexics.tsx
  12. 49
      src/features/MatchPage/store/hooks/useSelectedPlaylist.tsx
  13. 15
      src/features/MatchPage/store/index.tsx
  14. 6
      src/features/MatchPage/types.tsx
  15. 2
      src/features/MatchSidePlaylists/components/EventsList/index.tsx

@ -41,7 +41,7 @@ export const useEpisodes = () => {
}).then(setEpisodes)
} else if (playlistOption.type === PlaylistTypes.MATCH
|| playlistOption.type === PlaylistTypes.EVENT) {
setEpisodes(playlistOption.data)
setEpisodes(playlistOption.episodes)
}
}, [matchId, sportType])

@ -1,38 +1,42 @@
import { Fragment } from 'react'
import type { Events } from 'requests/getMatchEvents'
import type { MatchInfo } from 'requests/getMatchInfo'
import isEmpty from 'lodash/isEmpty'
import { useMatchPageStore } from 'features/MatchPage/store'
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 { MatchProfileCardMobile } from '../MatchProfileCardMobile'
type Props = {
events: Events,
profile: MatchInfo,
// events: Events,
// profile: MatchInfo,
tournamentData: TournamentData,
}
export const LiveMatch = ({
events,
profile,
// events,
// profile,
tournamentData,
}: Props) => {
const {
events,
matchPlaylists,
profile,
selectedPlaylist,
} = useMatchPageStore()
const {
chapters,
onDurationChange,
onPlayerProgressChange,
onPlayingChange,
onPlaylistSelect,
resume,
selectedPlaylist,
streamUrl,
} = useLiveMatch(profile)
@ -41,14 +45,26 @@ export const LiveMatch = ({
return (
<Fragment>
<Container>
<Player
onPlayingChange={onPlayingChange}
onProgressChange={onPlayerProgressChange}
profile={profile}
resumeFrom={resume}
url={streamUrl}
/>
{isMobileDevice ? <MatchProfileCardMobile profile={profile} /> : null}
{profile?.youtube_link ? (
<Player
onPlayingChange={onPlayingChange}
onProgressChange={onPlayerProgressChange}
profile={profile}
resumeFrom={resume}
url={streamUrl}
/>
) : (
!isEmpty(chapters) && (
<StreamPlayer
onDurationChange={onDurationChange}
onPlayingChange={onPlayingChange}
onProgressChange={onPlayerProgressChange}
isLive={profile?.live}
resumeFrom={resume}
chapters={chapters}
/>
)
)}
</Container>
<MatchSidePlaylists

@ -1,20 +1,19 @@
import type { ReactNode } from 'react'
import { Fragment, useEffect } from 'react'
import type { MatchInfo } from 'requests/getMatchInfo'
import { usePageParams } from 'hooks/usePageParams'
import { useBuyMatchPopupStore } from 'features/BuyMatchPopup'
import { useMatchPageStore } from 'features/MatchPage/store'
import { prepareMatchProfile } from '../../helpers/prepareMatchProfile'
type Props = {
children: ReactNode,
matchProfile: MatchInfo,
}
export const SubscriptionGuard = ({ children, matchProfile }: Props) => {
export const SubscriptionGuard = ({ children }: Props) => {
const { profile: matchProfile } = useMatchPageStore()
const { open: openBuyMatchPopup } = useBuyMatchPopupStore()
const { profileId: matchId, sportType } = usePageParams()

@ -1,7 +1,7 @@
import map from 'lodash/map'
import sortBy from 'lodash/sortBy'
import type { MatchPlaylists, Players } from 'requests'
import type { MatchPlaylists, Players } from 'requests/getMatchPlaylists'
import type {
Playlists,
@ -27,8 +27,8 @@ const getMatchPlaylists = (matchPlaylists: MatchPlaylists | null): MatchPlaylist
const playlist = matchPlaylists[key]
const lexic = matchPlaylists.lexics[key]
return {
data: sortBy(playlist?.data, ['h', 's']),
duration: playlist?.dur,
episodes: sortBy(playlist?.data, ['h', 's']),
id: key,
lexic,
type: PlaylistTypes.MATCH,
@ -39,6 +39,7 @@ const getMatchPlaylists = (matchPlaylists: MatchPlaylists | null): MatchPlaylist
const getPlayerPlaylists = (players?: Players): PlayerPlaylistOptions => (
map(players, (player) => ({
...player,
episodes: [],
type: PlaylistTypes.PLAYER,
}))
)

@ -11,20 +11,19 @@ import {
import { FavoritesActions } from 'requests'
import { ProfileTypes } from 'config'
import { isMobileDevice } from 'config/userAgent'
import { usePageLogger } from 'hooks/usePageLogger'
import { usePageParams } from 'hooks/usePageParams'
import { MatchPageStore } from './store'
import { SubscriptionGuard } from './components/SubscriptionGuard'
import { MatchProfileCard } from './components/MatchProfileCard'
import { FinishedMatch } from './components/FinishedMatch'
import { LiveMatch } from './components/LiveMatch'
import { FinishedMatch } from './components/FinishedMatch'
import { useMatchProfile } from './hooks/useMatchProfile'
import { Wrapper } from './styled'
import { MatchPageStore } from './store'
const MatchPage = () => {
const MatchPageComponent = () => {
usePageLogger()
const history = useHistory()
const { addRemoveFavorite, userFavorites } = useUserFavoritesStore()
@ -72,35 +71,40 @@ const MatchPage = () => {
}
return (
<MatchPageStore>
<PageWrapper>
<ProfileHeader color='#2B2A28' height={4.5}>
{isMobileDevice ? null : <MatchProfileCard profile={profile} />}
</ProfileHeader>
<Main>
<UserFavorites />
<SubscriptionGuard matchProfile={profile}>
<Wrapper>
{playFromOTT && (
<LiveMatch
events={events}
profile={profile}
tournamentData={tournamentData}
/>
)}
{playFromScout && (
<FinishedMatch
events={events}
profile={profile}
tournamentData={tournamentData}
/>
)}
</Wrapper>
</SubscriptionGuard>
</Main>
</PageWrapper>
</MatchPageStore>
<PageWrapper>
<ProfileHeader color='#2B2A28' height={4.5}>
<MatchProfileCard profile={profile} />
</ProfileHeader>
<Main>
<UserFavorites />
<SubscriptionGuard>
<Wrapper>
{playFromOTT && (
<LiveMatch
events={events}
profile={profile}
tournamentData={tournamentData}
/>
)}
{playFromScout && (
<FinishedMatch
events={events}
profile={profile}
tournamentData={tournamentData}
/>
)}
<LiveMatch />
</Wrapper>
</SubscriptionGuard>
</Main>
</PageWrapper>
)
}
const MatchPage = () => (
<MatchPageStore>
<MatchPageComponent />
</MatchPageStore>
)
export default MatchPage

@ -0,0 +1,83 @@
import {
useEffect,
useState,
useMemo,
} from 'react'
import type { MatchInfo } from 'requests/getMatchInfo'
import { getMatchInfo } from 'requests/getMatchInfo'
import { usePageParams } from 'hooks/usePageParams'
import { parseDate } from 'helpers/parseDate'
import { useMatchData } from './useMatchData'
import type { Playlists } from '../../types'
const addScoresFromPlaylists = (
profile: MatchInfo,
playlists: Playlists,
): MatchInfo => (
profile
? {
...profile,
team1: {
...profile?.team1,
score: playlists.score1,
},
team2: {
...profile?.team2,
score: playlists.score2,
},
}
: null
)
export const useMatchPage = () => {
const [matchProfile, setMatchProfile] = useState<MatchInfo>(null)
const { profileId: matchId, sportType } = usePageParams()
useEffect(() => {
getMatchInfo(sportType, matchId).then(setMatchProfile)
}, [sportType, matchId])
useEffect(() => {
let getIntervalMatch: ReturnType<typeof setInterval>
if (matchProfile?.live && !matchProfile.youtube_link) {
getIntervalMatch = setInterval(
() => getMatchInfo(sportType, matchId).then(setMatchProfile), 1000 * 60 * 3,
)
}
return () => clearInterval(getIntervalMatch)
}, [matchProfile, sportType, matchId])
const {
events,
handlePlaylistClick,
matchPlaylists,
selectedPlaylist,
setFullMatchPlaylistDuration,
} = useMatchData(matchProfile?.live)
const profile = useMemo(
() => addScoresFromPlaylists(matchProfile, matchPlaylists),
[matchProfile, matchPlaylists],
)
const isStarted = useMemo(() => (
profile?.date
? parseDate(profile.date) < new Date()
: true
), [profile?.date])
return {
events,
handlePlaylistClick,
isStarted,
matchPlaylists,
profile,
selectedPlaylist,
setFullMatchPlaylistDuration,
}
}

@ -0,0 +1,28 @@
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<Events>([])
const { fetchLexics } = useEventsLexics()
const { profileId: matchId, sportType } = usePageParams()
const fetchMatchEvents = useCallback(() => {
getMatchEvents({
matchId,
sportType,
}).then(fetchLexics)
.then(setEvents)
}, [
fetchLexics,
matchId,
sportType,
])
return { events, fetchMatchEvents }
}

@ -0,0 +1,25 @@
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 }
}

@ -0,0 +1,72 @@
import { useEffect, useMemo } from 'react'
import debounce from 'lodash/debounce'
import { usePageParams } from 'hooks/usePageParams'
import { useInterval } from 'hooks/useInterval'
import { useMatchPlaylists } from './useMatchPlaylists'
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,
handlePlaylistClick,
matchPlaylists,
selectedPlaylist,
setFullMatchPlaylistDuration,
} = useMatchPlaylists()
const { events, fetchMatchEvents } = useEvents()
const fetchPlaylistsDebounced = useMemo(
() => debounce(fetchMatchPlaylists, MATCH_PLAYLISTS_DELAY),
[fetchMatchPlaylists],
)
useEffect(() => {
fetchMatchPlaylists({
id: matchId,
sportType,
})
fetchMatchEvents()
}, [
matchId,
sportType,
fetchMatchPlaylists,
fetchMatchEvents,
])
const intervalCallback = () => {
fetchPlaylistsDebounced({
id: matchId,
sportType,
})
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,
handlePlaylistClick,
matchPlaylists,
selectedPlaylist,
setFullMatchPlaylistDuration,
}
}

@ -0,0 +1,81 @@
import {
useState,
useCallback,
} from 'react'
import isEmpty from 'lodash/isEmpty'
import type { SportTypes } from 'config/sportTypes'
import { getMatchPlaylists } from 'requests/getMatchPlaylists'
import type { Playlists } from 'features/MatchPage/types'
import { buildPlaylists } from 'features/MatchPage/helpers/buildPlaylists'
import { usePlaylistLexics } from './usePlaylistLexics'
import { useSelectedPlaylist } from './useSelectedPlaylist'
type ArgsFetchMatchPlaylists = {
id: number,
sportType: SportTypes,
}
const initialPlaylists = buildPlaylists(null)
export const useMatchPlaylists = () => {
const [matchPlaylists, setMatchPlaylists] = useState<Playlists>(initialPlaylists)
const { fetchLexics } = usePlaylistLexics()
const {
handlePlaylistClick,
selectedPlaylist,
setSelectedPlaylist,
} = useSelectedPlaylist()
const setInitialSeletedPlaylist = useCallback((playlists: Playlists) => {
setSelectedPlaylist((playlist) => {
if (!playlist && !isEmpty(playlists.match)) {
return playlists.match[0]
}
return playlist
})
return playlists
}, [setSelectedPlaylist])
const fetchMatchPlaylists = useCallback(({
id,
sportType,
}: ArgsFetchMatchPlaylists) => {
getMatchPlaylists({
matchId: id,
selectedActions: [],
sportType,
}).then(fetchLexics)
.then(buildPlaylists)
.then(setInitialSeletedPlaylist)
.then(setMatchPlaylists)
}, [fetchLexics, setInitialSeletedPlaylist])
const setFullMatchPlaylistDuration = (duration: number) => {
const playlists = [...matchPlaylists.match]
if (!playlists[0]) return
playlists[0].duration = duration
setMatchPlaylists({
...matchPlaylists,
match: playlists,
})
if (selectedPlaylist) {
setSelectedPlaylist({ ...selectedPlaylist })
}
}
return {
fetchMatchPlaylists,
handlePlaylistClick,
matchPlaylists,
selectedPlaylist,
setFullMatchPlaylistDuration,
}
}

@ -0,0 +1,21 @@
import { useCallback } from 'react'
import isEmpty from 'lodash/isEmpty'
import values from 'lodash/values'
import type { MatchPlaylists } from 'requests'
import { useLexicsStore } from 'features/LexicsStore'
export const usePlaylistLexics = () => {
const { addLexicsConfig } = useLexicsStore()
const fetchLexics = useCallback((playlist: MatchPlaylists | null) => {
const lexics = values(playlist?.lexics)
if (!isEmpty(lexics)) {
addLexicsConfig(lexics)
}
return playlist
}, [addLexicsConfig])
return { fetchLexics }
}

@ -0,0 +1,49 @@
import type { MouseEvent } from 'react'
import { useState, useCallback } from 'react'
import { getPlayerPlaylists } from 'requests/getPlayerPlaylists'
import { usePageParams } from 'hooks/usePageParams'
import {
PlayerPlaylistOption,
PlaylistOption,
PlaylistTypes,
} from 'features/MatchPage/types'
import { defaultSettings } from 'features/MatchPopup/types'
export const useSelectedPlaylist = () => {
const { profileId: matchId, sportType } = usePageParams()
const [selectedPlaylist, setSelectedPlaylist] = useState<PlaylistOption>()
const fetchPlayerEpisodes = useCallback((playlistOption: PlayerPlaylistOption) => (
getPlayerPlaylists({
matchId,
playerId: playlistOption.id,
settings: defaultSettings,
sportType,
})
), [matchId, sportType])
const handlePlaylistClick = useCallback((playlist: PlaylistOption, e?: MouseEvent) => {
e?.stopPropagation()
if (playlist === selectedPlaylist) return
if (playlist.type === PlaylistTypes.PLAYER) {
fetchPlayerEpisodes(playlist).then((episodes) => {
setSelectedPlaylist({
...playlist,
episodes,
})
})
} else {
setSelectedPlaylist(playlist)
}
}, [fetchPlayerEpisodes, selectedPlaylist])
return {
handlePlaylistClick,
selectedPlaylist,
setSelectedPlaylist,
}
}

@ -1,7 +1,10 @@
import type { ReactNode } from 'react'
import { createContext, useContext } from 'react'
import {
createContext,
useContext,
} from 'react'
import { useMatchPage } from '../hooks'
import { useMatchPage } from './hooks'
type Context = ReturnType<typeof useMatchPage>
type Props = { children: ReactNode }
@ -9,12 +12,8 @@ type Props = { children: ReactNode }
const MatchPageContext = createContext({} as Context)
export const MatchPageStore = ({ children }: Props) => {
const value = useMatchPage()
return (
<MatchPageContext.Provider value={value}>
{children}
</MatchPageContext.Provider>
)
const lexics = useMatchPage()
return <MatchPageContext.Provider value={lexics}>{children}</MatchPageContext.Provider>
}
export const useMatchPageStore = () => useContext(MatchPageContext)

@ -12,8 +12,8 @@ export enum PlaylistTypes {
}
export type MatchPlaylistOption = {
data: Episodes,
duration?: number,
episodes: Episodes,
id: MatchPlaylistIds,
lexic: number | string,
type: PlaylistTypes.MATCH,
@ -21,6 +21,7 @@ export type MatchPlaylistOption = {
export type PlayerPlaylistOption = {
dur: number,
episodes: Episodes,
gk?: boolean,
id: number,
name_eng: string,
@ -31,6 +32,7 @@ export type PlayerPlaylistOption = {
}
export type InterviewPlaylistOption = {
episodes: Episodes,
id: number,
name_eng: string,
name_rus: string,
@ -38,7 +40,7 @@ export type InterviewPlaylistOption = {
}
export type EventPlaylistOption = {
data: Episodes,
episodes: Episodes,
id: number,
type: PlaylistTypes.EVENT,
}

@ -45,7 +45,7 @@ export const EventsList = ({
const repeatedEpisodes = event.rep || []
const eventPlaylist = {
data: [{
episodes: [{
e: event.e,
h: event.h,
s: event.s,

Loading…
Cancel
Save