feat(in-142): match stats tab

pull/11/head
Ruslan Khayrullin 3 years ago
parent ee3b93c622
commit 49403a6746
  1. 7
      src/features/MatchPage/components/FinishedMatch/index.tsx
  2. 8
      src/features/MatchPage/components/LiveMatch/hooks/index.tsx
  3. 8
      src/features/MatchPage/store/hooks/index.tsx
  4. 12
      src/features/MatchPage/store/hooks/useMatchData.tsx
  5. 55
      src/features/MatchPage/store/hooks/useTeamsStats.tsx
  6. 29
      src/features/MatchSidePlaylists/components/MatchPlaylists/index.tsx
  7. 0
      src/features/MatchSidePlaylists/components/Matches/components/VideoDate/index.tsx
  8. 0
      src/features/MatchSidePlaylists/components/Matches/components/VideoDate/styled.tsx
  9. 12
      src/features/MatchSidePlaylists/components/Matches/index.tsx
  10. 9
      src/features/MatchSidePlaylists/components/Matches/styled.tsx
  11. 2
      src/features/MatchSidePlaylists/components/PlayersPlaylists/styled.tsx
  12. 3
      src/features/MatchSidePlaylists/components/TabStats/hooks.tsx
  13. 4
      src/features/MatchSidePlaylists/components/TabStats/index.tsx
  14. 37
      src/features/MatchSidePlaylists/components/TabWatch/index.tsx
  15. 276
      src/features/MatchSidePlaylists/components/TeamsStats/index.tsx
  16. 30
      src/features/MatchSidePlaylists/components/TeamsStatsTable/hooks.tsx
  17. 93
      src/features/MatchSidePlaylists/components/TeamsStatsTable/index.tsx
  18. 17
      src/features/MatchSidePlaylists/components/TeamsStatsTable/styled.tsx
  19. 14
      src/features/MatchSidePlaylists/hooks.tsx
  20. 3
      src/features/MatchSidePlaylists/index.tsx
  21. 6
      src/features/MatchSidePlaylists/styled.tsx
  22. 3
      src/features/MultiSourcePlayer/hooks/index.tsx
  23. 4
      src/requests/getTeamsStats.tsx

@ -17,7 +17,11 @@ import { useMatchPageStore } from '../../store'
export const FinishedMatch = () => { export const FinishedMatch = () => {
const [circleAnimation, setCircleAnimation] = useState<TCircleAnimation>(initialCircleAnimation) const [circleAnimation, setCircleAnimation] = useState<TCircleAnimation>(initialCircleAnimation)
const { isOpenPopup, profile } = useMatchPageStore() const {
isOpenPopup,
profile,
setPlayingProgress,
} = useMatchPageStore()
const { const {
chapters, chapters,
closeSettingsPopup, closeSettingsPopup,
@ -51,6 +55,7 @@ export const FinishedMatch = () => {
isOpenPopup={isOpenPopup} isOpenPopup={isOpenPopup}
chapters={chapters} chapters={chapters}
onPlayingChange={onPlayingChange} onPlayingChange={onPlayingChange}
onPlayerProgressChange={setPlayingProgress}
profile={profile} profile={profile}
/> />
<MatchDescription /> <MatchDescription />

@ -21,6 +21,7 @@ export const useLiveMatch = () => {
profile, profile,
selectedPlaylist, selectedPlaylist,
setFullMatchPlaylistDuration, setFullMatchPlaylistDuration,
setPlayingProgress,
} = useMatchPageStore() } = useMatchPageStore()
const { profileId: matchId, sportType } = usePageParams() const { profileId: matchId, sportType } = usePageParams()
const resume = useResumeUrlParam() const resume = useResumeUrlParam()
@ -45,7 +46,7 @@ export const useLiveMatch = () => {
} = usePlaylistLogger() } = usePlaylistLogger()
const { const {
onPlayerProgressChange, onPlayerProgressChange: playerProgressChange,
onPlayingChange: notifyProgressLogger, onPlayingChange: notifyProgressLogger,
} = usePlayerProgressReporter() } = usePlayerProgressReporter()
@ -66,6 +67,11 @@ export const useLiveMatch = () => {
handlePlaylistClick(playlist, e) handlePlaylistClick(playlist, e)
} }
const onPlayerProgressChange = (seconds: number, period = 0) => {
playerProgressChange(seconds, period)
setPlayingProgress(seconds * 1000)
}
return { return {
chapters, chapters,
isPlayFilterEpisodes, isPlayFilterEpisodes,

@ -68,8 +68,12 @@ export const useMatchPage = () => {
fetchTeamsStats, fetchTeamsStats,
handlePlaylistClick, handlePlaylistClick,
matchPlaylists, matchPlaylists,
playingProgress,
selectedPlaylist, selectedPlaylist,
setFullMatchPlaylistDuration, setFullMatchPlaylistDuration,
setPlayingProgress,
setStatsType,
statsType,
teamsStats, teamsStats,
} = useMatchData(matchProfile) } = useMatchData(matchProfile)
@ -173,6 +177,7 @@ export const useMatchPage = () => {
plaingOrder, plaingOrder,
playEpisodes, playEpisodes,
playNextEpisode, playNextEpisode,
playingProgress,
profile, profile,
profileCardShown, profileCardShown,
resetEvents, resetEvents,
@ -182,10 +187,13 @@ export const useMatchPage = () => {
setFullMatchPlaylistDuration, setFullMatchPlaylistDuration,
setIsPlayinFiltersEpisodes, setIsPlayinFiltersEpisodes,
setPlaingOrder, setPlaingOrder,
setPlayingProgress,
setReversed, setReversed,
setStatsType,
setUnreversed, setUnreversed,
setWatchAllEpisodesTimer, setWatchAllEpisodesTimer,
showProfileCard, showProfileCard,
statsType,
teamsStats, teamsStats,
toggleActiveEvents, toggleActiveEvents,
toggleActivePlayers, toggleActivePlayers,

@ -25,6 +25,7 @@ export const useMatchData = (profile: MatchInfo) => {
const { profileId: matchId, sportType } = usePageParams() const { profileId: matchId, sportType } = usePageParams()
const { chapters } = useMatchPopupStore() const { chapters } = useMatchPopupStore()
const [matchDuration, setMatchDuration] = useState(0) const [matchDuration, setMatchDuration] = useState(0)
const [playingProgress, setPlayingProgress] = useState(0)
const { const {
fetchMatchPlaylists, fetchMatchPlaylists,
handlePlaylistClick, handlePlaylistClick,
@ -34,7 +35,12 @@ export const useMatchData = (profile: MatchInfo) => {
setSelectedPlaylist, setSelectedPlaylist,
} = useMatchPlaylists(profile) } = useMatchPlaylists(profile)
const { events, fetchMatchEvents } = useEvents() const { events, fetchMatchEvents } = useEvents()
const { fetchTeamsStats, teamsStats } = useTeamsStats(profile) const {
fetchTeamsStats,
setStatsType,
statsType,
teamsStats,
} = useTeamsStats(profile, playingProgress)
const fetchPlaylistsDebounced = useMemo( const fetchPlaylistsDebounced = useMemo(
() => debounce(fetchMatchPlaylists, MATCH_PLAYLISTS_DELAY), () => debounce(fetchMatchPlaylists, MATCH_PLAYLISTS_DELAY),
@ -97,8 +103,12 @@ export const useMatchData = (profile: MatchInfo) => {
fetchTeamsStats, fetchTeamsStats,
handlePlaylistClick, handlePlaylistClick,
matchPlaylists, matchPlaylists,
playingProgress,
selectedPlaylist, selectedPlaylist,
setFullMatchPlaylistDuration, setFullMatchPlaylistDuration,
setPlayingProgress,
setStatsType,
statsType,
teamsStats, teamsStats,
} }
} }

@ -2,42 +2,33 @@ import {
useEffect, useEffect,
useState, useState,
useMemo, useMemo,
useCallback,
} from 'react' } from 'react'
import flatMap from 'lodash/flatMap' import throttle from 'lodash/throttle'
import reduce from 'lodash/reduce'
import includes from 'lodash/includes'
import type { MatchInfo } from 'requests' import type { MatchInfo } from 'requests'
import { getTeamsStats, TeamStatItem } from 'requests' import { getTeamsStats, TeamStatItem } from 'requests'
import { usePageParams } from 'hooks/usePageParams' import { usePageParams } from 'hooks/usePageParams'
import { useLexicsConfig } from 'features/LexicsStore' import { StatsType } from 'features/MatchSidePlaylists/components/TabStats/config'
export const useTeamsStats = (matchProfile: MatchInfo) => { const REQUEST_DELAY = 3000
const STATS_POLL_INTERVAL = 30000
export const useTeamsStats = (matchProfile: MatchInfo, playingProgress: number) => {
const [statsType, setStatsType] = useState<StatsType>(StatsType.FINAL_STATS)
const [teamsStats, setTeamsStats] = useState<{ const [teamsStats, setTeamsStats] = useState<{
[teamId: string]: Array<TeamStatItem>, [teamId: string]: Array<TeamStatItem>,
}>({}) }>({})
const { profileId: matchId, sportName } = usePageParams() const { profileId: matchId, sportName } = usePageParams()
const lexics = useMemo(() => reduce<TeamStatItem, Array<number>>( const progressSec = Math.floor(playingProgress / 1000)
flatMap(teamsStats),
(acc, curr) => {
if (curr.param1?.lexic && !includes(acc, curr.param1.lexic)) {
acc.push(curr.param1.lexic)
}
return acc
},
[],
), [teamsStats])
useLexicsConfig(lexics) const isCurrentStats = statsType === StatsType.CURRENT_STATS
const fetchTeamsStats = useCallback((second?: number) => { const fetchTeamsStats = useMemo(() => throttle((second?: number) => {
if (!sportName) return if (!sportName) return
getTeamsStats({ getTeamsStats({
@ -45,14 +36,36 @@ export const useTeamsStats = (matchProfile: MatchInfo) => {
second, second,
sportName, sportName,
}).then(setTeamsStats) }).then(setTeamsStats)
}, [matchId, sportName]) }, REQUEST_DELAY), [matchId, sportName])
useEffect(() => { useEffect(() => {
let timer: ReturnType<typeof setInterval>
if (!isCurrentStats) {
fetchTeamsStats() fetchTeamsStats()
}, [fetchTeamsStats]) }
if (matchProfile?.live) {
timer = setInterval(() => {
if (isCurrentStats) return
fetchTeamsStats()
}, STATS_POLL_INTERVAL)
}
return () => clearInterval(timer)
}, [fetchTeamsStats, matchProfile?.live, isCurrentStats])
useEffect(() => {
if (isCurrentStats) {
fetchTeamsStats(progressSec)
}
}, [fetchTeamsStats, progressSec, isCurrentStats])
return { return {
fetchTeamsStats, fetchTeamsStats,
setStatsType,
statsType,
teamsStats, teamsStats,
} }
} }

@ -1,8 +1,8 @@
import { useMemo } from 'react' import type { ForwardedRef } from 'react'
import { forwardRef } from 'react'
import styled, { css } from 'styled-components/macro' import styled, { css } from 'styled-components/macro'
import filter from 'lodash/filter'
import isEmpty from 'lodash/isEmpty' import isEmpty from 'lodash/isEmpty'
import map from 'lodash/map' import map from 'lodash/map'
@ -15,6 +15,8 @@ import { T9n } from 'features/T9n'
import { PlayButton } from '../PlayButton' import { PlayButton } from '../PlayButton'
export const LIST_ITEM_INDENT = 12
type Props = { type Props = {
live?: boolean, live?: boolean,
onSelect?: (selectedMathPlaylist: PlaylistOption) => void, onSelect?: (selectedMathPlaylist: PlaylistOption) => void,
@ -25,7 +27,7 @@ type Props = {
const List = styled.ul`` const List = styled.ul``
const Item = styled.li` const Item = styled.li`
margin-bottom: 12px; margin-bottom: ${LIST_ITEM_INDENT}px;
width: 100%; width: 100%;
height: 36px; height: 36px;
${isMobileDevice ${isMobileDevice
@ -36,24 +38,17 @@ const Item = styled.li`
: ''}; : ''};
` `
export const MatchPlaylists = ({ export const MatchPlaylists = forwardRef(
({
live, live,
onSelect, onSelect,
playlists, playlists,
selectedMathPlaylist, selectedMathPlaylist,
}: Props) => { }: Props,
const filteredPlayListByDuration = useMemo(() => ( ref: ForwardedRef<HTMLUListElement>) => (
filter(playlists, (playlist) => ( <List ref={ref}>
live
? Boolean(playlist.duration) || (playlist.id === 'full_game')
: Boolean(playlist.duration)
))
), [playlists, live])
return (
<List>
{ {
map(filteredPlayListByDuration, (playlist) => ( map(playlists, (playlist) => (
<Item key={playlist.id}> <Item key={playlist.id}>
<PlayButton <PlayButton
duration={playlist.duration} duration={playlist.duration}
@ -68,5 +63,5 @@ export const MatchPlaylists = ({
)) ))
} }
</List> </List>
),
) )
}

@ -23,13 +23,15 @@ import { VideoDate } from './components/VideoDate'
import { MatchesWrapper } from './styled' import { MatchesWrapper } from './styled'
type Props = { type Props = {
additionalScrollHeight: number,
profile: MatchInfo, profile: MatchInfo,
tournamentData: TournamentData, tournamentData: TournamentData,
} }
const formatDate = (date: Date) => format(date, 'yyyy-MM-dd') const formatDate = (date: Date) => format(date, 'yyyy-MM-dd')
export const TabVideo = ({ export const Matches = ({
additionalScrollHeight,
profile, profile,
tournamentData, tournamentData,
}: Props) => { }: Props) => {
@ -75,7 +77,7 @@ export const TabVideo = ({
const hasScroll = scrollHeight > clientHeight const hasScroll = scrollHeight > clientHeight
setOverflow(hasScroll) setOverflow(hasScroll)
}, [ref, selectedDate]) }, [ref.current?.clientHeight, selectedDate])
if (tournamentData.matches.length <= 1) return null if (tournamentData.matches.length <= 1) return null
@ -88,7 +90,11 @@ export const TabVideo = ({
profileDate={profileDate} profileDate={profileDate}
onDateClick={setSelectedDate} onDateClick={setSelectedDate}
/> />
<MatchesWrapper ref={ref} hasScroll={overflow}> <MatchesWrapper
ref={ref}
hasScroll={overflow}
additionalScrollHeight={additionalScrollHeight}
>
{ {
map(sortBy(matches, ({ live }) => !live), (match) => ( map(sortBy(matches, ({ live }) => !live), (match) => (
<MatchCard <MatchCard

@ -2,9 +2,14 @@ import styled, { css } from 'styled-components/macro'
import { customScrollbar } from 'features/Common' import { customScrollbar } from 'features/Common'
import { isMobileDevice } from '../../../../config/userAgent' import { isMobileDevice } from '../../../../config/userAgent'
export const MatchesWrapper = styled.div<{hasScroll?: boolean}>` type MatchesWrapperProps = {
additionalScrollHeight: number,
hasScroll?: boolean,
}
export const MatchesWrapper = styled.div<MatchesWrapperProps>`
overflow-y: auto; overflow-y: auto;
max-height: calc(100vh - 170px); max-height: calc(100vh - 165px - ${({ additionalScrollHeight }) => additionalScrollHeight}px);
padding-right: ${({ hasScroll }) => (hasScroll ? '10px' : '')}; padding-right: ${({ hasScroll }) => (hasScroll ? '10px' : '')};
> * { > * {

@ -28,6 +28,7 @@ export const PlayerAvatar = styled(ProfileLogo)`
` `
export const Tabs = styled.div` export const Tabs = styled.div`
margin-top: -10px;
margin-bottom: 23px; margin-bottom: 23px;
` `
@ -38,6 +39,7 @@ type TabProps = {
export const Tab = styled.button<TabProps>` export const Tab = styled.button<TabProps>`
position: relative; position: relative;
border: none; border: none;
height: 34px;
padding: 0; padding: 0;
background-color: transparent; background-color: transparent;
font-size: 12px; font-size: 12px;

@ -5,10 +5,9 @@ import { useMatchPageStore } from 'features/MatchPage/store'
import { StatsType, Tabs } from './config' import { StatsType, Tabs } from './config'
export const useTabStats = () => { export const useTabStats = () => {
const [statsType, setStatsType] = useState<StatsType>(StatsType.FINAL_STATS)
const [selectedTab, setSelectedTab] = useState<Tabs>(Tabs.TEAMS) const [selectedTab, setSelectedTab] = useState<Tabs>(Tabs.TEAMS)
const { fetchTeamsStats, teamsStats } = useMatchPageStore() const { setStatsType, statsType } = useMatchPageStore()
const isFinalStatsType = statsType === StatsType.FINAL_STATS const isFinalStatsType = statsType === StatsType.FINAL_STATS

@ -4,7 +4,7 @@ import { T9n } from 'features/T9n'
import { Tabs } from './config' import { Tabs } from './config'
import { useTabStats } from './hooks' import { useTabStats } from './hooks'
import { PlayersTable } from '../PlayersTable' import { PlayersTable } from '../PlayersTable'
import { TeamsStats } from '../TeamsStats' import { TeamsStatsTable } from '../TeamsStatsTable'
import { import {
Container, Container,
@ -17,7 +17,7 @@ import {
} from './styled' } from './styled'
const tabPanes = { const tabPanes = {
[Tabs.TEAMS]: TeamsStats, [Tabs.TEAMS]: TeamsStatsTable,
[Tabs.TEAM1]: PlayersTable, [Tabs.TEAM1]: PlayersTable,
[Tabs.TEAM2]: PlayersTable, [Tabs.TEAM2]: PlayersTable,
} }

@ -1,6 +1,11 @@
import { Fragment } from 'react' import {
Fragment,
useMemo,
useRef,
} from 'react'
import size from 'lodash/size' import size from 'lodash/size'
import filter from 'lodash/filter'
import type { import type {
PlaylistOption, PlaylistOption,
@ -10,12 +15,13 @@ import type {
import type { MatchInfo } from 'requests' import type { MatchInfo } from 'requests'
import { DropdownSection } from '../DropdownSection' import { DropdownSection } from '../DropdownSection'
import { MatchPlaylists } from '../MatchPlaylists' import { MatchPlaylists, LIST_ITEM_INDENT } from '../MatchPlaylists'
import { SideInterviews } from '../SideInterviews' import { SideInterviews } from '../SideInterviews'
import { TabVideo } from '../../components/TabVideo' import { Matches } from '../Matches'
type Props = { type Props = {
onSelect: (option: PlaylistOption) => void, onSelect: (option: PlaylistOption) => void,
playListFilter: number,
playlists: Playlists, playlists: Playlists,
profile: MatchInfo, profile: MatchInfo,
selectedPlaylist?: PlaylistOption, selectedPlaylist?: PlaylistOption,
@ -24,18 +30,35 @@ type Props = {
export const TabWatch = ({ export const TabWatch = ({
onSelect, onSelect,
playListFilter,
playlists, playlists,
profile, profile,
selectedPlaylist, selectedPlaylist,
tournamentData, tournamentData,
}: Props) => ( }: Props) => {
const matchPlaylistsRef = useRef<HTMLUListElement>(null)
const additionalScrollHeight = (matchPlaylistsRef.current?.clientHeight || 0) + LIST_ITEM_INDENT
const filteredPlayListByDuration = useMemo(() => (
filter(playlists.match, (playlist) => (
profile?.live
? Boolean(playlist.duration) || (playlist.id === 'full_game')
: Boolean(playlist.duration)
))
), [playlists.match, profile?.live])
return (
<Fragment> <Fragment>
{playListFilter > 1 && (
<MatchPlaylists <MatchPlaylists
playlists={playlists.match} ref={matchPlaylistsRef}
playlists={filteredPlayListByDuration}
selectedMathPlaylist={selectedPlaylist} selectedMathPlaylist={selectedPlaylist}
onSelect={onSelect} onSelect={onSelect}
live={profile?.live} live={profile?.live}
/> />
)}
<DropdownSection <DropdownSection
itemsCount={size(playlists.interview)} itemsCount={size(playlists.interview)}
title={playlists.lexics?.interview} title={playlists.lexics?.interview}
@ -46,9 +69,11 @@ export const TabWatch = ({
onSelect={onSelect} onSelect={onSelect}
/> />
</DropdownSection> </DropdownSection>
<TabVideo <Matches
profile={profile} profile={profile}
tournamentData={tournamentData} tournamentData={tournamentData}
additionalScrollHeight={additionalScrollHeight}
/> />
</Fragment> </Fragment>
) )
}

@ -1,276 +0,0 @@
import {
Container,
Row,
TeamShortName,
ParamValueContainer,
ParamValue,
ParamTitle,
} from './styled'
export const TeamsStats = () => (
<Container>
<Row>
<TeamShortName>DIN</TeamShortName>
<TeamShortName>SPA</TeamShortName>
</Row>
<Row>
<ParamValueContainer>
<ParamValue clickable>90</ParamValue>
</ParamValueContainer>
<ParamTitle>Points</ParamTitle>
<ParamValue clickable>123</ParamValue>
</Row>
<Row>
<ParamValueContainer>
<ParamValue>90</ParamValue>
</ParamValueContainer>
<ParamTitle>Points</ParamTitle>
<ParamValue>123</ParamValue>
</Row>
<Row>
<ParamValueContainer>
<ParamValue>90</ParamValue>
</ParamValueContainer>
<ParamTitle>Points</ParamTitle>
<ParamValue>123</ParamValue>
</Row>
<Row>
<ParamValueContainer>
<ParamValue>90</ParamValue>
</ParamValueContainer>
<ParamTitle>Points</ParamTitle>
<ParamValue>123</ParamValue>
</Row>
<Row>
<ParamValueContainer>
<ParamValue>90</ParamValue>
</ParamValueContainer>
<ParamTitle>Points</ParamTitle>
<ParamValue>123</ParamValue>
</Row>
<Row>
<ParamValueContainer>
<ParamValue>90</ParamValue>
</ParamValueContainer>
<ParamTitle>Points</ParamTitle>
<ParamValue>123</ParamValue>
</Row>
<Row>
<ParamValueContainer>
<ParamValue>90</ParamValue>
</ParamValueContainer>
<ParamTitle>Points</ParamTitle>
<ParamValue>123</ParamValue>
</Row>
<Row>
<ParamValueContainer>
<ParamValue>90</ParamValue>
</ParamValueContainer>
<ParamTitle>Points</ParamTitle>
<ParamValue>123</ParamValue>
</Row>
<Row>
<ParamValueContainer>
<ParamValue>90</ParamValue>
</ParamValueContainer>
<ParamTitle>Points</ParamTitle>
<ParamValue>123</ParamValue>
</Row>
<Row>
<ParamValueContainer>
<ParamValue>90</ParamValue>
</ParamValueContainer>
<ParamTitle>Points</ParamTitle>
<ParamValue>123</ParamValue>
</Row>
<Row>
<ParamValueContainer>
<ParamValue>90</ParamValue>
</ParamValueContainer>
<ParamTitle>Points</ParamTitle>
<ParamValue>123</ParamValue>
</Row>
<Row>
<ParamValueContainer>
<ParamValue>90</ParamValue>
</ParamValueContainer>
<ParamTitle>Points</ParamTitle>
<ParamValue>123</ParamValue>
</Row>
<Row>
<ParamValueContainer>
<ParamValue>90</ParamValue>
</ParamValueContainer>
<ParamTitle>Points</ParamTitle>
<ParamValue>123</ParamValue>
</Row>
<Row>
<ParamValueContainer>
<ParamValue>90</ParamValue>
</ParamValueContainer>
<ParamTitle>Points</ParamTitle>
<ParamValue>123</ParamValue>
</Row>
<Row>
<ParamValueContainer>
<ParamValue>90</ParamValue>
</ParamValueContainer>
<ParamTitle>Points</ParamTitle>
<ParamValue>123</ParamValue>
</Row>
<Row>
<ParamValueContainer>
<ParamValue>90</ParamValue>
</ParamValueContainer>
<ParamTitle>Points</ParamTitle>
<ParamValue>123</ParamValue>
</Row>
<Row>
<ParamValueContainer>
<ParamValue>90</ParamValue>
</ParamValueContainer>
<ParamTitle>Points</ParamTitle>
<ParamValue>123</ParamValue>
</Row>
<Row>
<ParamValueContainer>
<ParamValue>90</ParamValue>
</ParamValueContainer>
<ParamTitle>Points</ParamTitle>
<ParamValue>123</ParamValue>
</Row>
<Row>
<ParamValueContainer>
<ParamValue>90</ParamValue>
</ParamValueContainer>
<ParamTitle>Points</ParamTitle>
<ParamValue>123</ParamValue>
</Row>
<Row>
<ParamValueContainer>
<ParamValue>90</ParamValue>
</ParamValueContainer>
<ParamTitle>Points</ParamTitle>
<ParamValue>123</ParamValue>
</Row>
<Row>
<ParamValueContainer>
<ParamValue>90</ParamValue>
</ParamValueContainer>
<ParamTitle>Points</ParamTitle>
<ParamValue>123</ParamValue>
</Row>
<Row>
<ParamValueContainer>
<ParamValue>90</ParamValue>
</ParamValueContainer>
<ParamTitle>Points</ParamTitle>
<ParamValue>123</ParamValue>
</Row>
<Row>
<ParamValueContainer>
<ParamValue>90</ParamValue>
</ParamValueContainer>
<ParamTitle>Points</ParamTitle>
<ParamValue>123</ParamValue>
</Row>
<Row>
<ParamValueContainer>
<ParamValue>90</ParamValue>
</ParamValueContainer>
<ParamTitle>Points</ParamTitle>
<ParamValue>123</ParamValue>
</Row>
<Row>
<ParamValueContainer>
<ParamValue>90</ParamValue>
</ParamValueContainer>
<ParamTitle>Points</ParamTitle>
<ParamValue>123</ParamValue>
</Row>
<Row>
<ParamValueContainer>
<ParamValue>90</ParamValue>
</ParamValueContainer>
<ParamTitle>Points</ParamTitle>
<ParamValue>123</ParamValue>
</Row>
<Row>
<ParamValueContainer>
<ParamValue>90</ParamValue>
</ParamValueContainer>
<ParamTitle>Points</ParamTitle>
<ParamValue>123</ParamValue>
</Row>
<Row>
<ParamValueContainer>
<ParamValue>90</ParamValue>
</ParamValueContainer>
<ParamTitle>Points</ParamTitle>
<ParamValue>123</ParamValue>
</Row>
<Row>
<ParamValueContainer>
<ParamValue>90</ParamValue>
</ParamValueContainer>
<ParamTitle>Points</ParamTitle>
<ParamValue>123</ParamValue>
</Row>
<Row>
<ParamValueContainer>
<ParamValue>90</ParamValue>
</ParamValueContainer>
<ParamTitle>Points</ParamTitle>
<ParamValue>123</ParamValue>
</Row>
<Row>
<ParamValueContainer>
<ParamValue>90</ParamValue>
</ParamValueContainer>
<ParamTitle>Points</ParamTitle>
<ParamValue>123</ParamValue>
</Row>
<Row>
<ParamValueContainer>
<ParamValue>90</ParamValue>
</ParamValueContainer>
<ParamTitle>Points</ParamTitle>
<ParamValue>123</ParamValue>
</Row>
<Row>
<ParamValueContainer>
<ParamValue>90</ParamValue>
</ParamValueContainer>
<ParamTitle>Points</ParamTitle>
<ParamValue>123</ParamValue>
</Row>
<Row>
<ParamValueContainer>
<ParamValue>90</ParamValue>
</ParamValueContainer>
<ParamTitle>Points</ParamTitle>
<ParamValue>123</ParamValue>
</Row>
<Row>
<ParamValueContainer>
<ParamValue>90</ParamValue>
</ParamValueContainer>
<ParamTitle>Points</ParamTitle>
<ParamValue>123</ParamValue>
</Row>
<Row>
<ParamValueContainer>
<ParamValue>90</ParamValue>
</ParamValueContainer>
<ParamTitle>Points</ParamTitle>
<ParamValue>123</ParamValue>
</Row>
<Row>
<ParamValueContainer>
<ParamValue>90</ParamValue>
</ParamValueContainer>
<ParamTitle>Points</ParamTitle>
<ParamValue>123</ParamValue>
</Row>
</Container>
)

@ -0,0 +1,30 @@
import isNumber from 'lodash/isNumber'
import find from 'lodash/find'
import type { Param } from 'requests'
import { useMatchPageStore } from 'features/MatchPage/store'
export const useTeamsStatsTable = () => {
const { profile, teamsStats } = useMatchPageStore()
const getDisplayedValue = (val: any) => (
isNumber(val) ? val : '-'
)
const getStatItemById = (paramId: number) => {
if (!profile) return null
return find(teamsStats[profile?.team2.id], ({ param1 }) => param1.id === paramId) || null
}
const isClickable = (param: Param) => (
isNumber(param.val) && param.clickable
)
return {
getDisplayedValue,
getStatItemById,
isClickable,
}
}

@ -0,0 +1,93 @@
import { Fragment } from 'react'
import map from 'lodash/map'
import { useMatchPageStore } from 'features/MatchPage/store'
import { useLexicsStore } from 'features/LexicsStore'
import { useTeamsStatsTable } from './hooks'
import {
Container,
Row,
TeamShortName,
ParamValueContainer,
ParamValue,
StatItemTitle,
Divider,
} from './styled'
export const TeamsStatsTable = () => {
const { profile, teamsStats } = useMatchPageStore()
const {
getDisplayedValue,
getStatItemById,
isClickable,
} = useTeamsStatsTable()
const { lang } = useLexicsStore()
if (!profile) return null
return (
<Container>
<Row>
<TeamShortName
nameObj={profile.team1}
prefix='abbrev_'
/>
<TeamShortName
nameObj={profile.team2}
prefix='abbrev_'
/>
</Row>
{map(teamsStats[profile.team1.id], (team1StatItem) => {
const team2StatItem = getStatItemById(team1StatItem.param1.id)
const statItemTitle = team1StatItem[`name_${lang === 'ru' ? 'ru' : 'en'}`]
return (
<Row key={team1StatItem.param1.id}>
<ParamValueContainer>
<ParamValue
clickable={isClickable(team1StatItem.param1)}
>
{getDisplayedValue(team1StatItem.param1.val)}
</ParamValue>
{team1StatItem.param2 && (
<Fragment>
<Divider>/</Divider>
<ParamValue
clickable={isClickable(team1StatItem.param2)}
>
{getDisplayedValue(team1StatItem.param2.val)}
</ParamValue>
</Fragment>
)}
</ParamValueContainer>
<StatItemTitle>{statItemTitle}</StatItemTitle>
{team2StatItem && (
<ParamValueContainer>
<ParamValue
clickable={isClickable(team2StatItem.param1)}
>
{getDisplayedValue(team2StatItem.param1.val)}
</ParamValue>
{team2StatItem.param2 && (
<Fragment>
<Divider>/</Divider>
<ParamValue
clickable={isClickable(team2StatItem.param2)}
>
{getDisplayedValue(team2StatItem.param2.val)}
</ParamValue>
</Fragment>
)}
</ParamValueContainer>
)}
</Row>
)
})}
</Container>
)
}

@ -1,11 +1,13 @@
import styled, { css } from 'styled-components/macro' import styled, { css } from 'styled-components/macro'
import { Name } from 'features/Name'
export const Container = styled.div` export const Container = styled.div`
width: 100%; width: 100%;
font-size: 11px; font-size: 11px;
` `
export const TeamShortName = styled.span` export const TeamShortName = styled(Name)`
color: ${({ theme }) => theme.colors.white}; color: ${({ theme }) => theme.colors.white};
letter-spacing: -0.078px; letter-spacing: -0.078px;
text-transform: uppercase; text-transform: uppercase;
@ -33,7 +35,10 @@ type TParamValue = {
clickable?: boolean, clickable?: boolean,
} }
export const ParamValue = styled.span<TParamValue>` export const ParamValue = styled.span.attrs(({ clickable }: TParamValue) => ({
...clickable && { tabIndex: 0 },
}))<TParamValue>`
font-weight: 600;
color: ${({ clickable, theme }) => (clickable ? '#5EB2FF' : theme.colors.white)}; color: ${({ clickable, theme }) => (clickable ? '#5EB2FF' : theme.colors.white)};
${({ clickable }) => (clickable ${({ clickable }) => (clickable
@ -43,10 +48,16 @@ export const ParamValue = styled.span<TParamValue>`
: '')} : '')}
` `
export const ParamTitle = styled.span` export const StatItemTitle = styled.span`
color: ${({ theme }) => theme.colors.white}; color: ${({ theme }) => theme.colors.white};
letter-spacing: -0.078px; letter-spacing: -0.078px;
text-transform: uppercase; text-transform: uppercase;
font-weight: 600; font-weight: 600;
opacity: 0.5; opacity: 0.5;
` `
export const Divider = styled.span`
color: ${({ theme }) => theme.colors.white};
opacity: 0.5;
font-weight: 600;
`

@ -18,10 +18,11 @@ export const useMatchSidePlaylists = () => {
events, events,
matchPlaylists: playlists, matchPlaylists: playlists,
teamsStats, teamsStats,
tournamentData,
} = useMatchPageStore() } = useMatchPageStore()
const [selectedTab, setSelectedTab] = useState<Tabs>(Tabs.WATCH) const [selectedTab, setSelectedTab] = useState<Tabs>(Tabs.WATCH)
const isWatchTabVisible = useMemo(() => {
const playListFilter = reduce( const playListFilter = useMemo(() => reduce(
playlists.match, playlists.match,
(acc, item) => { (acc, item) => {
let result = acc let result = acc
@ -29,9 +30,11 @@ export const useMatchSidePlaylists = () => {
return result return result
}, },
0, 0,
) ), [playlists.match])
return playListFilter > 1
}, [playlists]) const isWatchTabVisible = useMemo(() => (
playListFilter > 1 || tournamentData.matchDates.length > 1
), [playListFilter, tournamentData.matchDates.length])
const isEventTabVisible = useMemo(() => ( const isEventTabVisible = useMemo(() => (
events.length > 0 events.length > 0
@ -85,6 +88,7 @@ export const useMatchSidePlaylists = () => {
isStatsTabVisible, isStatsTabVisible,
isWatchTabVisible, isWatchTabVisible,
onTabClick: setSelectedTab, onTabClick: setSelectedTab,
playListFilter,
selectedTab, selectedTab,
} }
} }

@ -63,6 +63,7 @@ export const MatchSidePlaylists = ({
isStatsTabVisible, isStatsTabVisible,
isWatchTabVisible, isWatchTabVisible,
onTabClick, onTabClick,
playListFilter,
selectedTab, selectedTab,
} = useMatchSidePlaylists() } = useMatchSidePlaylists()
@ -148,6 +149,7 @@ export const MatchSidePlaylists = ({
<Container <Container
hasScroll={hasTabPaneScroll} hasScroll={hasTabPaneScroll}
ref={tabPaneContainerRef} ref={tabPaneContainerRef}
forWatchTab={selectedTab === Tabs.WATCH}
> >
<TabPane <TabPane
setCircleAnimation={setCircleAnimation} setCircleAnimation={setCircleAnimation}
@ -157,6 +159,7 @@ export const MatchSidePlaylists = ({
playlists={playlists} playlists={playlists}
profile={profile} profile={profile}
selectedPlaylist={selectedPlaylist} selectedPlaylist={selectedPlaylist}
playListFilter={playListFilter}
/> />
</Container> </Container>
</Wrapper> </Wrapper>

@ -98,7 +98,7 @@ export const TabTitle = styled(T9n)`
` `
type TContainer = { type TContainer = {
forVideoTab?: boolean, forWatchTab?: boolean,
hasScroll: boolean, hasScroll: boolean,
} }
@ -106,8 +106,8 @@ export const Container = styled.div<TContainer>`
width: 320px; width: 320px;
margin-top: 23px; margin-top: 23px;
max-height: calc(100vh - 130px); max-height: calc(100vh - 130px);
overflow-y: ${({ forVideoTab }) => (forVideoTab ? 'hidden' : 'auto')}; overflow-y: ${({ forWatchTab }) => (forWatchTab ? 'hidden' : 'auto')};
padding-right: ${({ forVideoTab }) => (forVideoTab ? '0' : '')}; padding-right: ${({ forWatchTab }) => (forWatchTab ? '0' : '')};
padding-left: 14px; padding-left: 14px;
padding-right: ${({ hasScroll }) => (hasScroll ? '10px' : '')}; padding-right: ${({ hasScroll }) => (hasScroll ? '10px' : '')};

@ -56,6 +56,7 @@ export type Props = {
chapters: Chapters, chapters: Chapters,
isOpenPopup?: boolean, isOpenPopup?: boolean,
onError?: () => void, onError?: () => void,
onPlayerProgressChange?: (ms: number) => void,
onPlayingChange: (playing: boolean) => void, onPlayingChange: (playing: boolean) => void,
profile: MatchInfo, profile: MatchInfo,
setCircleAnimation: TSetCircleAnimation, setCircleAnimation: TSetCircleAnimation,
@ -64,6 +65,7 @@ export type Props = {
export const useMultiSourcePlayer = ({ export const useMultiSourcePlayer = ({
chapters, chapters,
onError, onError,
onPlayerProgressChange,
onPlayingChange, onPlayingChange,
setCircleAnimation, setCircleAnimation,
}: Props) => { }: Props) => {
@ -201,6 +203,7 @@ export const useMultiSourcePlayer = ({
timeForStatistics.current = (value + chapter.startMs) / 1000 timeForStatistics.current = (value + chapter.startMs) / 1000
setPlayerState({ playedProgress: value }) setPlayerState({ playedProgress: value })
onPlayerProgressChange?.(playedMs + chapter.startMs)
} }
const onEnded = () => { const onEnded = () => {

@ -2,7 +2,7 @@ import isUndefined from 'lodash/isUndefined'
import { callApi } from 'helpers' import { callApi } from 'helpers'
type Param = { export type Param = {
clickable: boolean, clickable: boolean,
data_type: string, data_type: string,
id: number, id: number,
@ -10,7 +10,7 @@ type Param = {
markers: Array<number>, markers: Array<number>,
name_en: string, name_en: string,
name_ru: string, name_ru: string,
val: number, val: number | null,
} }
export type TeamStatItem = { export type TeamStatItem = {

Loading…
Cancel
Save