feat(#680): add statsview page

pull/265/head
andreidekterev 3 years ago committed by Gitea
parent 17e8794399
commit e1d82fc86e
  1. 2
      src/config/lexics/indexLexics.tsx
  2. 3
      src/config/lexics/statsviewLexics.tsx
  3. 1
      src/config/pages.tsx
  4. 4
      src/features/App/AuthenticatedApp.tsx
  5. 6
      src/features/MatchPage/store/hooks/useTeamsStats.tsx
  6. 7
      src/features/MatchSidePlaylists/components/TeamsStatsTable/Cell.tsx
  7. 32
      src/features/MatchSidePlaylists/components/TeamsStatsTable/hooks.tsx
  8. 71
      src/features/MatchSidePlaylists/components/TeamsStatsTable/index.tsx
  9. 90
      src/pages/StatsView/components/StatsTable.tsx
  10. 16
      src/pages/StatsView/helpers/getStatsItem.tsx
  11. 22
      src/pages/StatsView/helpers/getStatsLexic.tsx
  12. 2
      src/pages/StatsView/helpers/index.tsx
  13. 78
      src/pages/StatsView/hooks.tsx
  14. 35
      src/pages/StatsView/index.tsx
  15. 25
      src/pages/StatsView/styled.tsx
  16. 6
      src/requests/getTeamsStats.tsx

@ -5,6 +5,7 @@ import { mailingsLexics } from './mailings'
import { sportsLexic } from './sportsLexic'
import { landingLexics } from './landingLexics'
import { matchDownload } from './matchDownload'
import { statsviewLexics } from './statsviewLexics'
const matchPopupLexics = {
actions: 1020,
@ -225,4 +226,5 @@ export const indexLexics = {
...sportsPopup,
...landingLexics,
...matchDownload,
...statsviewLexics,
}

@ -0,0 +1,3 @@
export const statsviewLexics = {
powered_by: 20210,
}

@ -7,6 +7,7 @@ export const PAGES = {
mailings: '/useraccount/mailings',
match: '/matches',
player: '/players',
statsview: '/statsview',
team: '/teams',
thanksForSubscribe: '/thanks-for-subscription',
tournament: '/tournaments',

@ -41,6 +41,7 @@ const HighlightsPage = lazy(() => import('pages/HighlightsPage'))
const ThanksPage = lazy(() => import('pages/ThanksPage'))
const Mailings = lazy(() => import('pages/Mailings'))
const FailedPaymeePage = lazy(() => import('pages/FailedPaymeePage'))
const StatsView = lazy(() => import('pages/StatsView'))
export const AuthenticatedApp = () => {
useSportList()
@ -77,6 +78,9 @@ export const AuthenticatedApp = () => {
<Route exact path={PAGES.home}>
<HomePage />
</Route>
<Route path={`/:sportName${PAGES.statsview}/:pageId`}>
<StatsView />
</Route>
<Route path={`/:sportName${PAGES.tournament}/:pageId`}>
<TournamentPage />
</Route>

@ -23,7 +23,7 @@ import { getTeamsStats, TeamStatItem } from 'requests'
import { usePageParams } from 'hooks'
import { getLocalStorageItem } from 'helpers/getLocalStorage'
import { getLocalStorageItem, isMatchPage } from 'helpers'
import { StatsType, Tabs as StatsTab } from 'features/MatchSidePlaylists/components/TabStats/config'
import { getHalfTime } from 'features/MatchPage/helpers/getHalfTime'
@ -44,7 +44,7 @@ type UseTeamsStatsArgs = {
statsType: StatsType,
}
type TeamsStats = {
export type TeamsStats = {
[teamId: number]: Array<TeamStatItem>,
}
@ -73,7 +73,7 @@ export const useTeamsStats = ({
)
const getFirstClickableParam = useCallback((stats: TeamsStats) => {
if (isEmpty(stats)) return null
if (isEmpty(stats) || !isMatchPage()) return null
const statItem = (matchProfile?.team1.id && find(
stats[matchProfile.team1.id],

@ -31,6 +31,7 @@ import { useMatchPageStore } from 'features/MatchPage/store'
import { useLexicsStore } from 'features/LexicsStore'
import { Spotlight, Steps } from 'features/MatchTour'
import { isMatchPage } from 'helpers'
import { StatsType } from '../TabStats/config'
import { CircleAnimationBar } from '../CircleAnimationBar'
@ -97,7 +98,7 @@ export const Cell = ({
)
const onParamClick = async (param: Param, paramName: string) => {
if (!isClickable(param)) return
if (!isMatchPage() && !isClickable(param)) return
disablePlayingEpisodes()
@ -171,7 +172,7 @@ export const Cell = ({
)
: (
<ParamValue
clickable={isClickable(teamStatItem.param1)}
clickable={isMatchPage() && isClickable(teamStatItem.param1)}
onClick={() => onParamClick(teamStatItem.param1, translate(teamStatItem.lexic))}
data-param-id={teamStatItem.param1.id}
hasValue={Boolean(teamStatItem.param1.val)}
@ -212,7 +213,7 @@ export const Cell = ({
<Fragment>
<Divider>/</Divider>
<ParamValue
clickable={isClickable(teamStatItem.param2)}
clickable={isMatchPage() && isClickable(teamStatItem.param2)}
onClick={() => onParamClick(
teamStatItem.param2!,
translate(teamStatItem.lexic),

@ -1,12 +1,8 @@
import { useEffect, useMemo } from 'react'
import find from 'lodash/find'
import reduce from 'lodash/reduce'
import type { TeamStatItem } from 'requests'
import { useMatchPageStore } from 'features/MatchPage/store'
import { useLexicsConfig } from 'features/LexicsStore'
import { getStatsLexics } from 'pages/StatsView/helpers'
export const useTeamsStatsTable = () => {
const {
@ -17,31 +13,12 @@ export const useTeamsStatsTable = () => {
teamsStats,
} = useMatchPageStore()
const lexicsIds = useMemo(
() => (
profile
? reduce<TeamStatItem, Array<number>>(
teamsStats[profile.team1.id],
(acc, curr) => {
!acc.includes(curr.lexic) && acc.push(curr.lexic)
!acc.includes(curr.param1.lexic) && acc.push(curr.param1.lexic)
curr.param2 && !acc.includes(curr.param2.lexic) && acc.push(curr.param2.lexic)
return acc
},
[],
)
: []),
const statsLexicIds = useMemo(
() => getStatsLexics({ matchProfile: profile, stats: teamsStats }),
[profile, teamsStats],
)
useLexicsConfig(lexicsIds)
const getStatItemById = (paramId: number) => {
if (!profile) return null
return find(teamsStats[profile?.team2.id], ({ param1 }) => param1.id === paramId) || null
}
useLexicsConfig(statsLexicIds)
useEffect(() => {
setCircleAnimation((state) => ({
@ -52,6 +29,5 @@ export const useTeamsStatsTable = () => {
return {
firstClickableParam: getFirstClickableParam(teamsStats),
getStatItemById,
}
}

@ -1,23 +1,12 @@
import { useTour } from '@reactour/tour'
import map from 'lodash/map'
import { useMatchPageStore } from 'features/MatchPage/store'
import { Loader } from 'features/Loader'
import { defaultTheme } from 'features/Theme/config'
import { StatsTable } from 'pages/StatsView/components/StatsTable'
import { useTeamsStatsTable } from './hooks'
import { Cell } from './Cell'
import {
Container,
TableWrapper,
Table,
Header,
Row,
CellContainer,
TeamShortName,
StatItemTitle,
} from './styled'
export const TeamsStatsTable = () => {
const {
@ -28,7 +17,6 @@ export const TeamsStatsTable = () => {
const {
firstClickableParam,
getStatItemById,
} = useTeamsStatsTable()
const { isOpen } = useTour()
@ -42,54 +30,11 @@ export const TeamsStatsTable = () => {
}
return (
<Container>
<TableWrapper isOpenTour={Boolean(isOpen)}>
<Table role='marquee' aria-live='off'>
<Header>
<Row>
<CellContainer as='th'>
<TeamShortName
nameObj={profile.team1}
prefix='abbrev_'
/>
</CellContainer>
<CellContainer as='th' />
<CellContainer as='th'>
<TeamShortName
nameObj={profile.team2}
prefix='abbrev_'
/>
</CellContainer>
</Row>
</Header>
<tbody>
{map(teamsStats[profile.team1.id], (team1StatItem) => {
const team2StatItem = getStatItemById(team1StatItem.param1.id)
return (
<Row key={team1StatItem.param1.id}>
<Cell
teamStatItem={team1StatItem}
teamId={profile.team1.id}
firstClickableParam={firstClickableParam}
/>
<CellContainer>
<StatItemTitle t={team1StatItem.lexic} />
</CellContainer>
<Cell
teamStatItem={team2StatItem}
teamId={profile.team2.id}
firstClickableParam={firstClickableParam}
/>
</Row>
)
})}
</tbody>
</Table>
</TableWrapper>
</Container>
<StatsTable
firstClickableParam={firstClickableParam}
isOpen={Boolean(isOpen)}
profile={profile}
teamsStats={teamsStats}
/>
)
}

@ -0,0 +1,90 @@
import map from 'lodash/map'
import { MatchInfo, Param } from 'requests'
import {
CellContainer,
Container,
Header,
Row,
StatItemTitle,
Table,
TableWrapper,
TeamShortName,
} from 'features/MatchSidePlaylists/components/TeamsStatsTable/styled'
import { Cell } from 'features/MatchSidePlaylists/components/TeamsStatsTable/Cell'
import { TeamsStats } from 'features/MatchPage/store/hooks/useTeamsStats'
import { getStatItemById } from '../helpers'
type StatsTableProps = {
firstClickableParam?: Param | null,
isOpen?: boolean,
profile: MatchInfo,
teamsStats: TeamsStats,
}
export const StatsTable = ({
firstClickableParam = null,
isOpen = false,
profile,
teamsStats,
}: StatsTableProps) => {
if (!profile) return null
return (
<Container>
<TableWrapper isOpenTour={Boolean(isOpen)}>
<Table role='marquee' aria-live='off'>
<Header>
<Row>
<CellContainer as='th'>
<TeamShortName
nameObj={profile.team1}
prefix='abbrev_'
/>
</CellContainer>
<CellContainer as='th' />
<CellContainer as='th'>
<TeamShortName
nameObj={profile.team2}
prefix='abbrev_'
/>
</CellContainer>
</Row>
</Header>
<tbody>
{map(teamsStats[profile.team1.id], (team1StatItem) => {
const team2StatItem = getStatItemById({
matchProfile: profile,
paramId: team1StatItem.param1.id,
stats: teamsStats,
})
return (
<Row key={team1StatItem.param1.id}>
<Cell
teamStatItem={team1StatItem}
teamId={profile.team1.id}
firstClickableParam={firstClickableParam}
/>
<CellContainer>
<StatItemTitle t={team1StatItem.lexic} />
</CellContainer>
<Cell
teamStatItem={team2StatItem}
teamId={profile.team2.id}
firstClickableParam={firstClickableParam}
/>
</Row>
)
})}
</tbody>
</Table>
</TableWrapper>
</Container>
)
}

@ -0,0 +1,16 @@
import { TeamStatItem } from 'requests'
import { StatsLexicType } from './getStatsLexic'
type StatsItemType = StatsLexicType & {
paramId: number,
}
export const getStatItemById = ({
matchProfile,
paramId,
stats,
}: StatsItemType) => {
if (!matchProfile) return null
return stats[matchProfile?.team2.id]
.find(({ param1 }: TeamStatItem) => param1.id === paramId) || null
}

@ -0,0 +1,22 @@
import reduce from 'lodash/reduce'
import { MatchInfo, TeamStatItem } from 'requests'
import { TeamsStats } from 'features/MatchPage/store/hooks/useTeamsStats'
export type StatsLexicType = {
matchProfile: MatchInfo,
stats: TeamsStats,
}
export const getStatsLexics = ({ matchProfile, stats }: StatsLexicType) => (
matchProfile
? reduce<TeamStatItem, Array<number>>(
stats[matchProfile.team1.id],
(acc, curr) => {
!acc.includes(curr.lexic) && acc.push(curr.lexic)
!acc.includes(curr.param1.lexic) && acc.push(curr.param1.lexic)
curr.param2 && !acc.includes(curr.param2.lexic) && acc.push(curr.param2.lexic)
return acc
},
[],
)
: [])

@ -0,0 +1,2 @@
export * from './getStatsLexic'
export * from './getStatsItem'

@ -0,0 +1,78 @@
import {
useEffect,
useMemo,
useState,
} from 'react'
import {
getMatchInfo,
getTeamsStats,
MatchInfo,
} from 'requests'
import { useInterval, usePageParams } from 'hooks'
import { TeamsStats } from 'features/MatchPage/store/hooks/useTeamsStats'
import { useLexicsConfig } from 'features/LexicsStore'
import { getStatsLexics } from 'pages/StatsView/helpers'
const INTERVAL_FETCH_STATS = 30 * 1000
export const useStatsView = () => {
const [matchProfile, setMatchProfile] = useState<MatchInfo>(null)
const [stats, setStats] = useState<TeamsStats>({})
const {
profileId,
sportName,
sportType,
} = usePageParams()
const fetchMatchInfo = async () => {
if (!sportName || !profileId) return
const profile = await getMatchInfo(sportType, profileId)
setMatchProfile(profile)
}
const fetchStats = async () => {
if (!sportName || !profileId) return
const statistic = await getTeamsStats({
matchId: profileId,
sportName,
})
setStats(statistic)
}
const statsLexicIds = useMemo(
() => getStatsLexics({ matchProfile, stats }),
[matchProfile, stats],
)
useLexicsConfig(statsLexicIds)
const { start, stop } = useInterval({
callback: fetchStats,
intervalDuration: INTERVAL_FETCH_STATS,
startImmediate: true,
})
useEffect(() => {
if (!sportName || !profileId) return undefined
start()
fetchMatchInfo()
return () => stop()
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [
profileId,
sportName,
])
return {
matchProfile,
teamsStats: stats,
}
}

@ -0,0 +1,35 @@
import { Logo } from 'features/Logo'
import { T9n } from 'features/T9n'
import { useStatsView } from './hooks'
import { StatsTable } from './components/StatsTable'
import { Powered, Container } from './styled'
const StatsView = () => {
const { matchProfile, teamsStats } = useStatsView()
return (
<Container>
<header className='header__logo'>
<Logo />
</header>
<main>
{matchProfile?.team1 && matchProfile?.team2 && (
<StatsTable
profile={matchProfile}
teamsStats={teamsStats}
/>
)}
</main>
<footer className='footer__powered'>
<a target='_blank' href='https://india.insports.tv' rel='noreferrer'>
<Powered>
<T9n t='powered_by' />
</Powered>
</a>
</footer>
</Container>
)
}
export default StatsView

@ -0,0 +1,25 @@
import styled from 'styled-components/macro'
export const Powered = styled.span`
display: block;
text-decoration: none;
font-size: 12px;
line-height: 20px;
text-align: center;
letter-spacing: -0.32px;
color: #76ADFF;
`
export const Container = styled.div`
display: flex;
flex-direction: column;
gap: 15px;
padding: 25px 5px 15px 5px;
.header__logo{
display: flex;
justify-content: center;
}
`

@ -25,13 +25,13 @@ export type TeamStatItem = {
}
type Response = {
data?: {
[teamId: string]: Array<TeamStatItem>,
},
data?: TeamsType,
error?: string,
message?: string,
}
export type TeamsType = Record<string, Array<TeamStatItem>>
type GetTeamsStatsArgs = {
matchId: number,
period?: number,

Loading…
Cancel
Save