From e1d82fc86e750da13533154ba847dadfd2659718 Mon Sep 17 00:00:00 2001 From: andreidekterev Date: Mon, 19 Jun 2023 17:10:39 +0700 Subject: [PATCH] feat(#680): add statsview page --- src/config/lexics/indexLexics.tsx | 2 + src/config/lexics/statsviewLexics.tsx | 3 + src/config/pages.tsx | 1 + src/features/App/AuthenticatedApp.tsx | 4 + .../MatchPage/store/hooks/useTeamsStats.tsx | 6 +- .../components/TeamsStatsTable/Cell.tsx | 7 +- .../components/TeamsStatsTable/hooks.tsx | 32 +------ .../components/TeamsStatsTable/index.tsx | 71 ++------------- src/pages/StatsView/components/StatsTable.tsx | 90 +++++++++++++++++++ src/pages/StatsView/helpers/getStatsItem.tsx | 16 ++++ src/pages/StatsView/helpers/getStatsLexic.tsx | 22 +++++ src/pages/StatsView/helpers/index.tsx | 2 + src/pages/StatsView/hooks.tsx | 78 ++++++++++++++++ src/pages/StatsView/index.tsx | 35 ++++++++ src/pages/StatsView/styled.tsx | 25 ++++++ src/requests/getTeamsStats.tsx | 6 +- 16 files changed, 300 insertions(+), 100 deletions(-) create mode 100644 src/config/lexics/statsviewLexics.tsx create mode 100644 src/pages/StatsView/components/StatsTable.tsx create mode 100644 src/pages/StatsView/helpers/getStatsItem.tsx create mode 100644 src/pages/StatsView/helpers/getStatsLexic.tsx create mode 100644 src/pages/StatsView/helpers/index.tsx create mode 100644 src/pages/StatsView/hooks.tsx create mode 100644 src/pages/StatsView/index.tsx create mode 100644 src/pages/StatsView/styled.tsx diff --git a/src/config/lexics/indexLexics.tsx b/src/config/lexics/indexLexics.tsx index a4c9227f..49684a38 100644 --- a/src/config/lexics/indexLexics.tsx +++ b/src/config/lexics/indexLexics.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, } diff --git a/src/config/lexics/statsviewLexics.tsx b/src/config/lexics/statsviewLexics.tsx new file mode 100644 index 00000000..554fdf23 --- /dev/null +++ b/src/config/lexics/statsviewLexics.tsx @@ -0,0 +1,3 @@ +export const statsviewLexics = { + powered_by: 20210, +} diff --git a/src/config/pages.tsx b/src/config/pages.tsx index a3ca9614..54e162a5 100644 --- a/src/config/pages.tsx +++ b/src/config/pages.tsx @@ -7,6 +7,7 @@ export const PAGES = { mailings: '/useraccount/mailings', match: '/matches', player: '/players', + statsview: '/statsview', team: '/teams', thanksForSubscribe: '/thanks-for-subscription', tournament: '/tournaments', diff --git a/src/features/App/AuthenticatedApp.tsx b/src/features/App/AuthenticatedApp.tsx index cddfc571..55fc6fb2 100644 --- a/src/features/App/AuthenticatedApp.tsx +++ b/src/features/App/AuthenticatedApp.tsx @@ -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 = () => { + + + diff --git a/src/features/MatchPage/store/hooks/useTeamsStats.tsx b/src/features/MatchPage/store/hooks/useTeamsStats.tsx index 2e92672d..c59d4d4e 100644 --- a/src/features/MatchPage/store/hooks/useTeamsStats.tsx +++ b/src/features/MatchPage/store/hooks/useTeamsStats.tsx @@ -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, } @@ -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], diff --git a/src/features/MatchSidePlaylists/components/TeamsStatsTable/Cell.tsx b/src/features/MatchSidePlaylists/components/TeamsStatsTable/Cell.tsx index 112456ac..a407749c 100644 --- a/src/features/MatchSidePlaylists/components/TeamsStatsTable/Cell.tsx +++ b/src/features/MatchSidePlaylists/components/TeamsStatsTable/Cell.tsx @@ -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 = ({ ) : ( onParamClick(teamStatItem.param1, translate(teamStatItem.lexic))} data-param-id={teamStatItem.param1.id} hasValue={Boolean(teamStatItem.param1.val)} @@ -212,7 +213,7 @@ export const Cell = ({ / onParamClick( teamStatItem.param2!, translate(teamStatItem.lexic), diff --git a/src/features/MatchSidePlaylists/components/TeamsStatsTable/hooks.tsx b/src/features/MatchSidePlaylists/components/TeamsStatsTable/hooks.tsx index ff5bd97e..b0a72d85 100644 --- a/src/features/MatchSidePlaylists/components/TeamsStatsTable/hooks.tsx +++ b/src/features/MatchSidePlaylists/components/TeamsStatsTable/hooks.tsx @@ -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>( - 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, } } diff --git a/src/features/MatchSidePlaylists/components/TeamsStatsTable/index.tsx b/src/features/MatchSidePlaylists/components/TeamsStatsTable/index.tsx index dc5f59f6..63de02d5 100644 --- a/src/features/MatchSidePlaylists/components/TeamsStatsTable/index.tsx +++ b/src/features/MatchSidePlaylists/components/TeamsStatsTable/index.tsx @@ -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 ( - - - -
- - - - - - - - - -
- - - {map(teamsStats[profile.team1.id], (team1StatItem) => { - const team2StatItem = getStatItemById(team1StatItem.param1.id) - - return ( - - - - - - - - - - ) - })} - -
-
-
+ ) } diff --git a/src/pages/StatsView/components/StatsTable.tsx b/src/pages/StatsView/components/StatsTable.tsx new file mode 100644 index 00000000..2fb33c21 --- /dev/null +++ b/src/pages/StatsView/components/StatsTable.tsx @@ -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 ( + + + +
+ + + + + + + + + +
+ + + {map(teamsStats[profile.team1.id], (team1StatItem) => { + const team2StatItem = getStatItemById({ + matchProfile: profile, + paramId: team1StatItem.param1.id, + stats: teamsStats, + }) + + return ( + + + + + + + + + + ) + })} + +
+
+
+ ) +} diff --git a/src/pages/StatsView/helpers/getStatsItem.tsx b/src/pages/StatsView/helpers/getStatsItem.tsx new file mode 100644 index 00000000..f03e283b --- /dev/null +++ b/src/pages/StatsView/helpers/getStatsItem.tsx @@ -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 +} diff --git a/src/pages/StatsView/helpers/getStatsLexic.tsx b/src/pages/StatsView/helpers/getStatsLexic.tsx new file mode 100644 index 00000000..d2f96e46 --- /dev/null +++ b/src/pages/StatsView/helpers/getStatsLexic.tsx @@ -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>( + 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 + }, + [], + ) + : []) diff --git a/src/pages/StatsView/helpers/index.tsx b/src/pages/StatsView/helpers/index.tsx new file mode 100644 index 00000000..97f38ade --- /dev/null +++ b/src/pages/StatsView/helpers/index.tsx @@ -0,0 +1,2 @@ +export * from './getStatsLexic' +export * from './getStatsItem' diff --git a/src/pages/StatsView/hooks.tsx b/src/pages/StatsView/hooks.tsx new file mode 100644 index 00000000..75b387d3 --- /dev/null +++ b/src/pages/StatsView/hooks.tsx @@ -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(null) + const [stats, setStats] = useState({}) + 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, + } +} diff --git a/src/pages/StatsView/index.tsx b/src/pages/StatsView/index.tsx new file mode 100644 index 00000000..e9a6c8dc --- /dev/null +++ b/src/pages/StatsView/index.tsx @@ -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 ( + +
+ +
+
+ {matchProfile?.team1 && matchProfile?.team2 && ( + + )} +
+ +
+ ) +} + +export default StatsView diff --git a/src/pages/StatsView/styled.tsx b/src/pages/StatsView/styled.tsx new file mode 100644 index 00000000..b3d2eef9 --- /dev/null +++ b/src/pages/StatsView/styled.tsx @@ -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; + } +` diff --git a/src/requests/getTeamsStats.tsx b/src/requests/getTeamsStats.tsx index ec8fd690..ef9269de 100644 --- a/src/requests/getTeamsStats.tsx +++ b/src/requests/getTeamsStats.tsx @@ -25,13 +25,13 @@ export type TeamStatItem = { } type Response = { - data?: { - [teamId: string]: Array, - }, + data?: TeamsType, error?: string, message?: string, } +export type TeamsType = Record> + type GetTeamsStatsArgs = { matchId: number, period?: number,