From c53c2b1d55eced377c2fe8db10e58792944107de Mon Sep 17 00:00:00 2001 From: Ruslan Khayrullin Date: Fri, 16 Dec 2022 18:39:24 +0500 Subject: [PATCH] feat(in-142): players stats --- src/features/MatchPage/store/hooks/index.tsx | 10 +- .../MatchPage/store/hooks/useMatchData.tsx | 24 +- .../MatchPage/store/hooks/usePlayersStats.tsx | 159 ++ .../MatchPage/store/hooks/useStatsTab.tsx | 12 + .../MatchPage/store/hooks/useTeamsStats.tsx | 15 +- .../components/PlayersTable/config.tsx | 7 +- .../components/PlayersTable/hooks.tsx | 61 - .../components/PlayersTable/hooks/index.tsx | 58 + .../PlayersTable/hooks/usePlayers.tsx | 83 + .../PlayersTable/hooks/useTable.tsx | 171 ++ .../components/PlayersTable/index.tsx | 1826 ++--------------- .../components/PlayersTable/styled.tsx | 214 +- .../components/PlayersTable/types.tsx | 8 + .../components/TabStats/hooks.tsx | 41 +- .../components/TabStats/index.tsx | 66 +- .../components/TeamsStatsTable/hooks.tsx | 3 +- src/features/MatchSidePlaylists/hooks.tsx | 29 +- src/helpers/getTeamAbbr/index.tsx | 25 + src/helpers/index.tsx | 1 + src/hooks/index.tsx | 1 + src/requests/getMatchParticipants.tsx | 65 + src/requests/getPlayersStats.tsx | 54 + src/requests/getTeamsStats.tsx | 2 +- src/requests/index.tsx | 2 + 24 files changed, 1072 insertions(+), 1865 deletions(-) create mode 100644 src/features/MatchPage/store/hooks/usePlayersStats.tsx create mode 100644 src/features/MatchPage/store/hooks/useStatsTab.tsx delete mode 100644 src/features/MatchSidePlaylists/components/PlayersTable/hooks.tsx create mode 100644 src/features/MatchSidePlaylists/components/PlayersTable/hooks/index.tsx create mode 100644 src/features/MatchSidePlaylists/components/PlayersTable/hooks/usePlayers.tsx create mode 100644 src/features/MatchSidePlaylists/components/PlayersTable/hooks/useTable.tsx create mode 100644 src/features/MatchSidePlaylists/components/PlayersTable/types.tsx create mode 100644 src/helpers/getTeamAbbr/index.tsx create mode 100644 src/requests/getMatchParticipants.tsx create mode 100644 src/requests/getPlayersStats.tsx diff --git a/src/features/MatchPage/store/hooks/index.tsx b/src/features/MatchPage/store/hooks/index.tsx index d407fa08..d0c0b76a 100644 --- a/src/features/MatchPage/store/hooks/index.tsx +++ b/src/features/MatchPage/store/hooks/index.tsx @@ -65,10 +65,11 @@ export const useMatchPage = () => { const { events, - fetchTeamsStats, handlePlaylistClick, + isEmptyPlayersStats, matchPlaylists, - playingProgress, + playersData, + playersStats, selectedPlaylist, setFullMatchPlaylistDuration, setPlayingProgress, @@ -162,11 +163,11 @@ export const useMatchPage = () => { countOfFilters, disablePlayingEpisodes, events, - fetchTeamsStats, filteredEvents, handlePlaylistClick, hideProfileCard, isEmptyFilters, + isEmptyPlayersStats, isLiveMatch, isOpenFiltersPopup, isPlayFilterEpisodes, @@ -177,7 +178,8 @@ export const useMatchPage = () => { plaingOrder, playEpisodes, playNextEpisode, - playingProgress, + playersData, + playersStats, profile, profileCardShown, resetEvents, diff --git a/src/features/MatchPage/store/hooks/useMatchData.tsx b/src/features/MatchPage/store/hooks/useMatchData.tsx index 3aa9f0fe..39fbf3b5 100644 --- a/src/features/MatchPage/store/hooks/useMatchData.tsx +++ b/src/features/MatchPage/store/hooks/useMatchData.tsx @@ -17,6 +17,8 @@ import { useMatchPopupStore } from 'features/MatchPopup' import { useMatchPlaylists } from './useMatchPlaylists' import { useEvents } from './useEvents' import { useTeamsStats } from './useTeamsStats' +import { useStatsTab } from './useStatsTab' +import { usePlayersStats } from './usePlayersStats' const MATCH_DATA_POLL_INTERVAL = 60000 const MATCH_PLAYLISTS_DELAY = 5000 @@ -35,12 +37,21 @@ export const useMatchData = (profile: MatchInfo) => { setSelectedPlaylist, } = useMatchPlaylists(profile) const { events, fetchMatchEvents } = useEvents() + const { setStatsType, statsType } = useStatsTab() + const { teamsStats } = useTeamsStats({ + matchProfile: profile, + playingProgress, + statsType, + }) const { - fetchTeamsStats, - setStatsType, + isEmptyPlayersStats, + playersData, + playersStats, + } = usePlayersStats({ + matchProfile: profile, + playingProgress, statsType, - teamsStats, - } = useTeamsStats(profile, playingProgress) + }) const fetchPlaylistsDebounced = useMemo( () => debounce(fetchMatchPlaylists, MATCH_PLAYLISTS_DELAY), @@ -100,10 +111,11 @@ export const useMatchData = (profile: MatchInfo) => { return { events, - fetchTeamsStats, handlePlaylistClick, + isEmptyPlayersStats, matchPlaylists, - playingProgress, + playersData, + playersStats, selectedPlaylist, setFullMatchPlaylistDuration, setPlayingProgress, diff --git a/src/features/MatchPage/store/hooks/usePlayersStats.tsx b/src/features/MatchPage/store/hooks/usePlayersStats.tsx new file mode 100644 index 00000000..326d4f51 --- /dev/null +++ b/src/features/MatchPage/store/hooks/usePlayersStats.tsx @@ -0,0 +1,159 @@ +import { + useMemo, + useEffect, + useState, +} from 'react' + +import throttle from 'lodash/throttle' +import isEmpty from 'lodash/isEmpty' +import every from 'lodash/every' +import find from 'lodash/find' + +import type { + MatchInfo, + PlayersStats, + Player, +} from 'requests' +import { getPlayersStats, getMatchParticipants } from 'requests' + +import { useObjectState, usePageParams } from 'hooks' + +import { StatsType } from 'features/MatchSidePlaylists/components/TabStats/config' + +const REQUEST_DELAY = 3000 +const STATS_POLL_INTERVAL = 30000 + +type UsePlayersStatsArgs = { + matchProfile: MatchInfo, + playingProgress: number, + statsType: StatsType, +} + +type PlayersData = { + team1: Array, + team2: Array, +} + +export const usePlayersStats = ({ + matchProfile, + playingProgress, + statsType, +}: UsePlayersStatsArgs) => { + const [playersStats, setPlayersStats] = useObjectState>({}) + const [playersData, setPlayersData] = useState({ team1: [], team2: [] }) + + const { + profileId: matchId, + sportName, + sportType, + } = usePageParams() + + const isCurrentStats = statsType === StatsType.CURRENT_STATS + + const progressSec = Math.floor(playingProgress / 1000) + + const isEmptyPlayersStats = (teamId: number) => ( + isEmpty(playersStats[teamId]) + || every(playersStats[teamId], isEmpty) + || isEmpty(playersData[matchProfile?.team1.id === teamId ? 'team1' : 'team2']) + ) + + const fetchPlayers = useMemo(() => throttle((second?: number) => { + if (!matchProfile?.team1.id || !matchProfile?.team1.id) return + + try { + getMatchParticipants({ + matchId, + second, + sportType, + }).then((data) => { + const team1Players = find(data, { team_id: matchProfile.team1.id })?.players || [] + const team2Players = find(data, { team_id: matchProfile.team2.id })?.players || [] + + setPlayersData({ + team1: team1Players, + team2: team2Players, + }) + }) + + // eslint-disable-next-line no-empty + } catch (e) {} + }, REQUEST_DELAY), [ + matchId, + matchProfile?.team1.id, + matchProfile?.team2.id, + sportType, + ]) + + const fetchPlayersStats = useMemo(() => throttle((second?: number) => { + if (!sportName || !matchProfile?.team1.id || !matchProfile?.team2.id) return + + try { + getPlayersStats({ + matchId, + second, + sportName, + teamId: matchProfile.team1.id, + }).then((data) => setPlayersStats({ [matchProfile.team1.id]: data })) + + getPlayersStats({ + matchId, + second, + sportName, + teamId: matchProfile.team2.id, + }).then((data) => setPlayersStats({ [matchProfile?.team2.id]: data })) + // eslint-disable-next-line no-empty + } catch (e) {} + }, REQUEST_DELAY), [ + matchId, + matchProfile?.team1.id, + matchProfile?.team2.id, + setPlayersStats, + sportName, + ]) + + useEffect(() => { + let interval: NodeJS.Timeout + + fetchPlayers() + + if (!isCurrentStats) { + fetchPlayersStats() + } + + if (matchProfile?.live) { + interval = setInterval(() => { + if (isCurrentStats) return + + fetchPlayersStats() + fetchPlayers() + }, STATS_POLL_INTERVAL) + } + + return () => clearInterval(interval) + }, [ + fetchPlayersStats, + fetchPlayers, + isCurrentStats, + matchProfile?.live, + ]) + + useEffect(() => { + if (isCurrentStats) { + fetchPlayersStats(progressSec) + fetchPlayers(progressSec) + } + }, [ + fetchPlayersStats, + fetchPlayers, + progressSec, + isCurrentStats, + matchProfile?.live, + ]) + + return { + isEmptyPlayersStats, + playersData, + playersStats, + } +} diff --git a/src/features/MatchPage/store/hooks/useStatsTab.tsx b/src/features/MatchPage/store/hooks/useStatsTab.tsx new file mode 100644 index 00000000..9a2a18f1 --- /dev/null +++ b/src/features/MatchPage/store/hooks/useStatsTab.tsx @@ -0,0 +1,12 @@ +import { useState } from 'react' + +import { StatsType } from 'features/MatchSidePlaylists/components/TabStats/config' + +export const useStatsTab = () => { + const [statsType, setStatsType] = useState(StatsType.FINAL_STATS) + + return { + setStatsType, + statsType, + } +} diff --git a/src/features/MatchPage/store/hooks/useTeamsStats.tsx b/src/features/MatchPage/store/hooks/useTeamsStats.tsx index b7a6d000..f9f6ea58 100644 --- a/src/features/MatchPage/store/hooks/useTeamsStats.tsx +++ b/src/features/MatchPage/store/hooks/useTeamsStats.tsx @@ -16,8 +16,17 @@ import { StatsType } from 'features/MatchSidePlaylists/components/TabStats/confi const REQUEST_DELAY = 3000 const STATS_POLL_INTERVAL = 30000 -export const useTeamsStats = (matchProfile: MatchInfo, playingProgress: number) => { - const [statsType, setStatsType] = useState(StatsType.FINAL_STATS) +type UseTeamsStatsArgs = { + matchProfile: MatchInfo, + playingProgress: number, + statsType: StatsType, +} + +export const useTeamsStats = ({ + matchProfile, + playingProgress, + statsType, +}: UseTeamsStatsArgs) => { const [teamsStats, setTeamsStats] = useState<{ [teamId: string]: Array, }>({}) @@ -63,8 +72,6 @@ export const useTeamsStats = (matchProfile: MatchInfo, playingProgress: number) }, [fetchTeamsStats, progressSec, isCurrentStats]) return { - fetchTeamsStats, - setStatsType, statsType, teamsStats, } diff --git a/src/features/MatchSidePlaylists/components/PlayersTable/config.tsx b/src/features/MatchSidePlaylists/components/PlayersTable/config.tsx index 095cfcbe..c0ac6c10 100644 --- a/src/features/MatchSidePlaylists/components/PlayersTable/config.tsx +++ b/src/features/MatchSidePlaylists/components/PlayersTable/config.tsx @@ -1 +1,6 @@ -export const CELL_WIDTH = 47 +export const PARAM_COLUMN_WIDTH = 50 +export const REQUEST_DELAY = 3000 +export const STATS_POLL_INTERVAL = 30000 +export const DISPLAYED_PARAMS_COLUMNS = 4 +export const FIRST_COLUMN_WIDTH_DEFAULT = 100 +export const SCROLLBAR_WIDTH = 8 diff --git a/src/features/MatchSidePlaylists/components/PlayersTable/hooks.tsx b/src/features/MatchSidePlaylists/components/PlayersTable/hooks.tsx deleted file mode 100644 index 811ddda6..00000000 --- a/src/features/MatchSidePlaylists/components/PlayersTable/hooks.tsx +++ /dev/null @@ -1,61 +0,0 @@ -import type { SyntheticEvent } from 'react' -import { - useRef, - useState, - useEffect, -} from 'react' - -import { isMobileDevice } from 'config/userAgent' - -import { CELL_WIDTH } from './config' - -export const usePlayersTable = () => { - const containerRef = useRef(null) - const tableWrapperRef = useRef(null) - - const [showLeftArrow, setShowLeftArrow] = useState(false) - const [showRightArrow, setShowRightArrow] = useState(false) - - const cellWidth = isMobileDevice - ? ((containerRef.current?.clientWidth || 0) - 98) / 4 - : CELL_WIDTH - - const slideLeft = () => tableWrapperRef.current!.scrollBy(-cellWidth, 0) - const slideRight = () => tableWrapperRef.current!.scrollBy(cellWidth, 0) - - const handleScroll = (e: SyntheticEvent) => { - const { - clientWidth, - scrollLeft, - scrollWidth, - } = e.currentTarget - - const scrollRight = scrollWidth - (scrollLeft + clientWidth) - - setShowLeftArrow(scrollLeft > 1) - setShowRightArrow(scrollRight > 1) - } - - useEffect(() => { - const { - clientWidth = 0, - scrollLeft = 0, - scrollWidth = 0, - } = tableWrapperRef.current || {} - - const scrollRight = scrollWidth - (scrollLeft + clientWidth) - - setShowRightArrow(scrollRight > 1) - }, []) - - return { - cellWidth, - containerRef, - handleScroll, - showLeftArrow, - showRightArrow, - slideLeft, - slideRight, - tableWrapperRef, - } -} diff --git a/src/features/MatchSidePlaylists/components/PlayersTable/hooks/index.tsx b/src/features/MatchSidePlaylists/components/PlayersTable/hooks/index.tsx new file mode 100644 index 00000000..537e480a --- /dev/null +++ b/src/features/MatchSidePlaylists/components/PlayersTable/hooks/index.tsx @@ -0,0 +1,58 @@ +import { useState } from 'react' + +import type { SortCondition, PlayersTableProps } from '../types' +import { usePlayers } from './usePlayers' +import { useTable } from './useTable' + +export const usePlayersTable = ({ teamId }: PlayersTableProps) => { + const [sortCondition, setSortCondition] = useState({ dir: 'asc', paramId: null }) + + const { + getFullName, + getPlayerParams, + players, + } = usePlayers({ sortCondition, teamId }) + + const { + containerRef, + firstColumnWidth, + getDisplayedValue, + handleScroll, + handleSortClick, + isExpanded, + paramColumnWidth, + params, + showExpandButton, + showLeftArrow, + showRightArrow, + slideLeft, + slideRight, + tableWrapperRef, + toggleIsExpanded, + } = useTable({ + setSortCondition, + teamId, + }) + + return { + containerRef, + firstColumnWidth, + getDisplayedValue, + getFullName, + getPlayerParams, + handleScroll, + handleSortClick, + isExpanded, + paramColumnWidth, + params, + players, + showExpandButton, + showLeftArrow, + showRightArrow, + slideLeft, + slideRight, + sortCondition, + tableWrapperRef, + toggleIsExpanded, + } +} diff --git a/src/features/MatchSidePlaylists/components/PlayersTable/hooks/usePlayers.tsx b/src/features/MatchSidePlaylists/components/PlayersTable/hooks/usePlayers.tsx new file mode 100644 index 00000000..ff2b8e3a --- /dev/null +++ b/src/features/MatchSidePlaylists/components/PlayersTable/hooks/usePlayers.tsx @@ -0,0 +1,83 @@ +import { useMemo, useCallback } from 'react' + +import orderBy from 'lodash/orderBy' +import isNil from 'lodash/isNil' +import trim from 'lodash/trim' + +import type { Player, PlayerParam } from 'requests' + +import { useToggle } from 'hooks' + +import { useMatchPageStore } from 'features/MatchPage/store' +import { useLexicsStore } from 'features/LexicsStore' + +import type { SortCondition } from '../types' + +type UsePlayersArgs = { + sortCondition: SortCondition, + teamId: number, +} + +export const usePlayers = ({ sortCondition, teamId }: UsePlayersArgs) => { + const { isOpen: isExpanded, toggle: toggleIsExpanded } = useToggle() + const { + playersData, + playersStats, + profile: matchProfile, + } = useMatchPageStore() + const { suffix } = useLexicsStore() + + const getPlayerParams = useCallback( + (playerId: number) => playersStats[teamId][playerId] || {}, + [playersStats, teamId], + ) + + const getDisplayedValue = ({ val }: PlayerParam) => (isNil(val) ? '-' : val) + + const getFullName = useCallback((player: Player) => ( + trim(`${player[`firstname_${suffix}`]} ${player[`lastname_${suffix}`]}`) + ), [suffix]) + + const getParamValue = useCallback((playerId: number, paramId: number) => { + const playerParams = getPlayerParams(playerId) + const { val } = playerParams[paramId] || {} + + return val + }, [getPlayerParams]) + + const sortedPlayers = useMemo(() => { + const players = playersData[matchProfile?.team1.id === teamId ? 'team1' : 'team2'] + + return isNil(sortCondition.paramId) + ? orderBy(players, getFullName) + : orderBy( + players, + [ + (player) => { + const paramValue = getParamValue(player.id, sortCondition.paramId!) + + return isNil(paramValue) ? -1 : paramValue + }, + getFullName, + ], + sortCondition.dir, + ) + }, [ + getFullName, + getParamValue, + playersData, + matchProfile?.team1.id, + sortCondition.dir, + sortCondition.paramId, + teamId, + ]) + + return { + getDisplayedValue, + getFullName, + getPlayerParams, + isExpanded, + players: sortedPlayers, + toggleIsExpanded, + } +} diff --git a/src/features/MatchSidePlaylists/components/PlayersTable/hooks/useTable.tsx b/src/features/MatchSidePlaylists/components/PlayersTable/hooks/useTable.tsx new file mode 100644 index 00000000..5bc2f55c --- /dev/null +++ b/src/features/MatchSidePlaylists/components/PlayersTable/hooks/useTable.tsx @@ -0,0 +1,171 @@ +import type { + SyntheticEvent, + Dispatch, + SetStateAction, +} from 'react' +import { + useRef, + useState, + useEffect, + useMemo, +} from 'react' + +import size from 'lodash/size' +import isNil from 'lodash/isNil' +import reduce from 'lodash/reduce' +import forEach from 'lodash/forEach' +import values from 'lodash/values' +import round from 'lodash/round' +import map from 'lodash/map' + +import { isMobileDevice } from 'config' + +import type { PlayerParam, PlayersStats } from 'requests' + +import { useToggle } from 'hooks' + +import { useMatchPageStore } from 'features/MatchPage/store' +import { useLexicsConfig } from 'features/LexicsStore' + +import type { SortCondition } from '../types' +import { + PARAM_COLUMN_WIDTH, + DISPLAYED_PARAMS_COLUMNS, + FIRST_COLUMN_WIDTH_DEFAULT, + SCROLLBAR_WIDTH, +} from '../config' + +type UseTableArgs = { + setSortCondition: Dispatch>, + teamId: number, +} + +type HeaderParam = Pick + +export const useTable = ({ + setSortCondition, + teamId, +}: UseTableArgs) => { + const containerRef = useRef(null) + const tableWrapperRef = useRef(null) + + const [showLeftArrow, setShowLeftArrow] = useState(false) + const [showRightArrow, setShowRightArrow] = useState(false) + + const { isOpen: isExpanded, toggle: toggleIsExpanded } = useToggle() + const { playersStats } = useMatchPageStore() + + const params = useMemo(() => ( + reduce>( + playersStats[teamId], + (acc, curr) => { + forEach(values(curr), ({ + id, + lexic, + lexica_short, + }) => { + acc[id] = acc[id] || { + id, + lexic, + lexica_short, + } + }) + + return acc + }, + {}, + ) + ), [playersStats, teamId]) + + const lexics = useMemo(() => ( + reduce>( + values(params), + (acc, { lexic, lexica_short }) => { + if (lexic) acc.push(lexic) + if (lexica_short) acc.push(lexica_short) + + return acc + }, + [], + ) + // eslint-disable-next-line react-hooks/exhaustive-deps + ), [map(params, 'id').sort().join('')]) + + useLexicsConfig(lexics) + + const paramsCount = size(params) + + const getParamColumnWidth = () => { + const rest = ( + (containerRef.current?.clientWidth || 0) - FIRST_COLUMN_WIDTH_DEFAULT - SCROLLBAR_WIDTH + ) + const desktopWith = PARAM_COLUMN_WIDTH + const mobileWidth = paramsCount < DISPLAYED_PARAMS_COLUMNS ? 0 : rest / DISPLAYED_PARAMS_COLUMNS + + return isMobileDevice ? mobileWidth : desktopWith + } + + const getFirstColumnWidth = () => { + if (isExpanded) return 0 + + return paramsCount < DISPLAYED_PARAMS_COLUMNS ? 0 : FIRST_COLUMN_WIDTH_DEFAULT + } + + const paramColumnWidth = getParamColumnWidth() + const firstColumnWidth = getFirstColumnWidth() + + const slideLeft = () => tableWrapperRef.current?.scrollBy(-paramColumnWidth, 0) + const slideRight = () => tableWrapperRef.current?.scrollBy(paramColumnWidth, 0) + + const getDisplayedValue = ({ val }: PlayerParam) => (isNil(val) ? '-' : round(val, 2)) + + const handleScroll = (e: SyntheticEvent) => { + const { + clientWidth, + scrollLeft, + scrollWidth, + } = e.currentTarget + + const scrollRight = scrollWidth - (scrollLeft + clientWidth) + + setShowLeftArrow(scrollLeft > 0) + setShowRightArrow(scrollRight > 0) + } + + const handleSortClick = (paramId: number) => () => { + setSortCondition((curr) => ({ + dir: curr.dir === 'asc' || curr.paramId !== paramId ? 'desc' : 'asc', + paramId, + })) + } + + useEffect(() => { + const { + clientWidth = 0, + scrollLeft = 0, + scrollWidth = 0, + } = tableWrapperRef.current || {} + + const scrollRight = scrollWidth - (scrollLeft + clientWidth) + + setShowRightArrow(scrollRight > 0) + }, [isExpanded]) + + return { + containerRef, + firstColumnWidth, + getDisplayedValue, + handleScroll, + handleSortClick, + isExpanded, + paramColumnWidth, + params, + showExpandButton: !isMobileDevice && paramsCount > DISPLAYED_PARAMS_COLUMNS, + showLeftArrow, + showRightArrow, + slideLeft, + slideRight, + tableWrapperRef, + toggleIsExpanded, + } +} diff --git a/src/features/MatchSidePlaylists/components/PlayersTable/index.tsx b/src/features/MatchSidePlaylists/components/PlayersTable/index.tsx index 0be29a9c..9e5ce602 100644 --- a/src/features/MatchSidePlaylists/components/PlayersTable/index.tsx +++ b/src/features/MatchSidePlaylists/components/PlayersTable/index.tsx @@ -1,1728 +1,164 @@ +import { Fragment } from 'react' + +import map from 'lodash/map' +import includes from 'lodash/includes' + +import { PlayerParam } from 'requests' + +import { T9n } from 'features/T9n' + +import type { PlayersTableProps } from './types' import { usePlayersTable } from './hooks' import { Container, TableWrapper, Table, - Thead, - Th, - Tbody, - Tr, - Td, + FirstColumn, + Cell, + Row, PlayerNum, + PlayerNameWrapper, + PlayerName, ParamShortTitle, ArrowButtonRight, ArrowButtonLeft, Arrow, + ExpandButton, + Tooltip, } from './styled' -export const PlayersTable = () => { +export const PlayersTable = (props: PlayersTableProps) => { const { - cellWidth, containerRef, + firstColumnWidth, + getDisplayedValue, + getFullName, + getPlayerParams, handleScroll, + handleSortClick, + isExpanded, + paramColumnWidth, + params, + players, + showExpandButton, showLeftArrow, showRightArrow, slideLeft, slideRight, + sortCondition, tableWrapperRef, - } = usePlayersTable() + toggleIsExpanded, + } = usePlayersTable(props) return ( - + - {showLeftArrow && ( - - - - )} - {showRightArrow && ( - - - + {!isExpanded && ( + + {showLeftArrow && ( + + + + )} + {showRightArrow && ( + + + + )} + )} + + + + {showExpandButton && ( + + + + + )} + + + {map(players, (player) => { + const fullName = getFullName(player) + + return ( + + + + {player.club_shirt_num} + {' '} + + + {fullName} + + + {fullName} + + + + + ) + })} + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + return ( + + {value} + + ) + })} + + ))}
- - Min - - Pt - - Reb - - Ass - - To - - Min - - Pt - - Reb - - Ass - - To - - Min - - Pt - - Reb - - Ass - + + {map(params, ({ + id, + lexic, + lexica_short, + }) => ( + + + + + + + ))} + - To - + {map(players, (player) => ( + + {map(params, ({ id }) => { + const playerParam = getPlayerParams(player.id)[id] as PlayerParam | undefined + const value = playerParam ? getDisplayedValue(playerParam) : '-' + const clickable = Boolean(playerParam?.clickable) && !includes([0, '-'], value) + const sorted = sortCondition.paramId === id - Min - - Pt - - Reb - - Ass - - To -
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
57 Selikhov9712214971221497122149712214
diff --git a/src/features/MatchSidePlaylists/components/PlayersTable/styled.tsx b/src/features/MatchSidePlaylists/components/PlayersTable/styled.tsx index 303332dd..a0d9f33d 100644 --- a/src/features/MatchSidePlaylists/components/PlayersTable/styled.tsx +++ b/src/features/MatchSidePlaylists/components/PlayersTable/styled.tsx @@ -1,138 +1,211 @@ import styled, { css } from 'styled-components/macro' -import { isMobileDevice } from 'config/userAgent' +import { isMobileDevice } from 'config' import { customScrollbar } from 'features/Common' +import { TooltipWrapper } from 'features/Tooltip' import { ArrowButton as ArrowButtonBase, Arrow as ArrowBase, } from 'features/HeaderFilters/components/DateFilter/styled' +import { T9n } from 'features/T9n' -import { CELL_WIDTH } from './config' +type ContainerProps = { + isExpanded?: boolean, +} -export const Container = styled.div` - position: relative; +export const Container = styled.div` + ${({ isExpanded }) => (isExpanded + ? '' + : css` + position: relative; + `)} ` -export const TableWrapper = styled.div` +type TableWrapperProps = { + isExpanded?: boolean, +} + +export const TableWrapper = styled.div` + display: flex; + max-width: 100%; max-height: calc(100vh - 235px); border-radius: 5px; overflow-x: auto; scroll-behavior: smooth; + background-color: #333333; + z-index: 50; ${customScrollbar} + + ${({ isExpanded }) => (isExpanded + ? css` + position: absolute; + right: 14px; + ` + : '')} ` -export const Table = styled.table` - width: 100%; +export const Table = styled.div` + flex-grow: 1; border-radius: 5px; border-collapse: collapse; letter-spacing: -0.078px; - table-layout: fixed; ` -export const Thead = styled.thead` - height: 45px; - border-bottom: 0.5px solid rgba(255, 255, 255, 0.5); -` - -type ThProps = { - sorted?: boolean, - width?: number, -} - -export const Th = styled.th.attrs({ tabIndex: 0 })` - position: sticky; - left: 0; - top: 0; - width: ${({ width }) => width || CELL_WIDTH}px; +export const Tooltip = styled(TooltipWrapper)` + left: auto; + padding: 2px 10px; + border-radius: 6px; + transform: none; font-size: 11px; - color: ${({ theme }) => theme.colors.white}; - text-transform: uppercase; - cursor: pointer; - background-color: #333333; - z-index: 2; + line-height: 1; + color: ${({ theme }) => theme.colors.black}; - :first-child { - width: 90px; - z-index: 3; - cursor: default; + ::before { + display: none; } - - ${({ sorted }) => (sorted - ? '' - : css` - ${ParamShortTitle} { - opacity: 0.5; - } - `)} ` -export const ParamShortTitle = styled.span`` - -export const Tbody = styled.tbody`` +export const ParamShortTitle = styled(T9n)` + text-transform: uppercase; +` -export const Tr = styled.tr` +export const Row = styled.div` + display: flex; + width: 100%; height: 45px; border-bottom: 0.5px solid rgba(255, 255, 255, 0.5); - :last-child { - border-bottom: none; + :first-child { + position: sticky; + left: 0; + top: 0; + z-index: 1; } ` type TdProps = { clickable?: boolean, + columnWidth?: number, + headerCell?: boolean, sorted?: boolean, } -export const Td = styled.td.attrs(({ clickable }: TdProps) => ({ +export const Cell = styled.div.attrs(({ clickable }: TdProps) => ({ ...clickable && { tabIndex: 0 }, }))` + position: relative; + display: flex; + justify-content: center; + align-items: center; + flex-shrink: 0; + width: ${({ columnWidth }) => (columnWidth ? `${columnWidth}px` : 'auto')}; font-size: 11px; - text-align: center; - color: ${({ clickable, theme }) => (clickable ? '#5EB2FF' : theme.colors.white)}; - text-overflow: ellipsis; - overflow: hidden; + color: ${({ + clickable, + headerCell, + theme, + }) => (clickable && !headerCell ? '#5EB2FF' : theme.colors.white)}; white-space: nowrap; background-color: #333333; - :first-child { - position: sticky; - left: 0; - z-index: 1; - padding-left: 13px; - text-align: left; - color: ${({ theme }) => theme.colors.white}; + ${Tooltip} { + top: 35px; + } + + :hover { + ${Tooltip} { + display: block; + } } + ${({ headerCell }) => (headerCell + ? '' + : css` + :first-child { + justify-content: unset; + padding-left: 13px; + color: ${({ theme }) => theme.colors.white}; + } + `)} + ${({ sorted }) => (sorted ? css` font-weight: bold; ` : '')} - ${({ clickable }) => (clickable + ${({ clickable, headerCell }) => (clickable || headerCell ? css` cursor: pointer; ` : '')} ` +type FirstColumnProps = { + columnWidth?: number, +} + +export const FirstColumn = styled.div` + position: sticky; + left: 0; + width: ${({ columnWidth }) => (columnWidth ? `${columnWidth}px` : 'auto')}; +` + export const PlayerNum = styled.span` + display: inline-block; + width: 20px; + flex-shrink: 0; + text-align: center; color: rgba(255, 255, 255, 0.5); ` +type PlayerNameProps = { + columnWidth?: number, +} + +export const PlayerName = styled.span` + display: inline-block; + margin-top: 2px; + text-overflow: ellipsis; + overflow: hidden; + + ${({ columnWidth }) => (columnWidth + ? css` + max-width: calc(${columnWidth}px - 31px); + ` + : css` + max-width: 110px; + `)} +` + +export const PlayerNameWrapper = styled.span` + position: relative; + + ${Tooltip} { + top: 15px; + } + + :hover { + ${Tooltip} { + display: block; + } + } +` + const ArrowButton = styled(ArrowButtonBase)` position: absolute; + width: 17px; margin-top: 2px; - z-index: 4; + background-color: #333333; + z-index: 3; ${isMobileDevice ? css` height: 45px; margin-top: 0; ` - : ''}; + : ''}; ` export const ArrowButtonRight = styled(ArrowButton)` @@ -146,4 +219,23 @@ export const ArrowButtonLeft = styled(ArrowButton)` export const Arrow = styled(ArrowBase)` width: 10px; height: 10px; + + ${isMobileDevice + ? css` + border-color: ${({ theme }) => theme.colors.white}; + ` + : ''}; +` + +export const ExpandButton = styled(ArrowButton)` + left: 20px; + top: 0; + + ${Arrow} { + left: 0; + + :last-child { + margin-left: 7px; + } + } ` diff --git a/src/features/MatchSidePlaylists/components/PlayersTable/types.tsx b/src/features/MatchSidePlaylists/components/PlayersTable/types.tsx new file mode 100644 index 00000000..85b9d054 --- /dev/null +++ b/src/features/MatchSidePlaylists/components/PlayersTable/types.tsx @@ -0,0 +1,8 @@ +export type PlayersTableProps = { + teamId: number, +} + +export type SortCondition = { + dir: 'asc' | 'desc', + paramId: number | null, +} diff --git a/src/features/MatchSidePlaylists/components/TabStats/hooks.tsx b/src/features/MatchSidePlaylists/components/TabStats/hooks.tsx index 0346586f..1d621ce3 100644 --- a/src/features/MatchSidePlaylists/components/TabStats/hooks.tsx +++ b/src/features/MatchSidePlaylists/components/TabStats/hooks.tsx @@ -1,4 +1,6 @@ -import { useState } from 'react' +import { useEffect, useState } from 'react' + +import isEmpty from 'lodash/isEmpty' import { useMatchPageStore } from 'features/MatchPage/store' @@ -7,21 +9,56 @@ import { StatsType, Tabs } from './config' export const useTabStats = () => { const [selectedTab, setSelectedTab] = useState(Tabs.TEAMS) - const { setStatsType, statsType } = useMatchPageStore() + const { + isEmptyPlayersStats, + profile: matchProfile, + setStatsType, + statsType, + teamsStats, + } = useMatchPageStore() const isFinalStatsType = statsType === StatsType.FINAL_STATS const switchTitleLexic = isFinalStatsType ? 'final_stats' : 'current_stats' const tooltipLexic = isFinalStatsType ? 'display_all_stats' : 'display_stats_according_to_video' + const isVisibleTeamsTab = !isEmpty(teamsStats) + const isVisibleTeam1PlayersTab = Boolean( + matchProfile && !isEmptyPlayersStats(matchProfile.team1.id), + ) + const isVisibleTeam2PlayersTab = Boolean( + matchProfile && !isEmptyPlayersStats(matchProfile.team2.id), + ) + const toggleStatsType = () => { const newStatsType = isFinalStatsType ? StatsType.CURRENT_STATS : StatsType.FINAL_STATS setStatsType(newStatsType) } + useEffect(() => { + switch (true) { + case isVisibleTeamsTab: + setSelectedTab(Tabs.TEAMS) + break + + case isVisibleTeam1PlayersTab: + setSelectedTab(Tabs.TEAM1) + break + + case isVisibleTeam2PlayersTab: + setSelectedTab(Tabs.TEAM2) + break + + default: + } + }, [isVisibleTeam1PlayersTab, isVisibleTeam2PlayersTab, isVisibleTeamsTab]) + return { isFinalStatsType, + isVisibleTeam1PlayersTab, + isVisibleTeam2PlayersTab, + isVisibleTeamsTab, selectedTab, setSelectedTab, switchTitleLexic, diff --git a/src/features/MatchSidePlaylists/components/TabStats/index.tsx b/src/features/MatchSidePlaylists/components/TabStats/index.tsx index 82311d18..d5b20d74 100644 --- a/src/features/MatchSidePlaylists/components/TabStats/index.tsx +++ b/src/features/MatchSidePlaylists/components/TabStats/index.tsx @@ -1,7 +1,11 @@ import { isMobileDevice } from 'config/userAgent' +import { getTeamAbbr } from 'helpers' + import { Tooltip } from 'features/Tooltip' import { T9n } from 'features/T9n' +import { useMatchPageStore } from 'features/MatchPage/store' +import { Name } from 'features/Name' import { Tabs } from './config' import { useTabStats } from './hooks' @@ -27,37 +31,59 @@ const tabPanes = { export const TabStats = () => { const { isFinalStatsType, + isVisibleTeam1PlayersTab, + isVisibleTeam2PlayersTab, + isVisibleTeamsTab, selectedTab, setSelectedTab, switchTitleLexic, toggleStatsType, tooltipLexic, } = useTabStats() + const { profile: matchProfile } = useMatchPageStore() const TabPane = tabPanes[selectedTab] + if (!matchProfile) return null + + const { team1, team2 } = matchProfile + return (
- setSelectedTab(Tabs.TEAMS)} - > - - - {/* setSelectedTab(Tabs.TEAM1)} - > - DIN - */} - {/* setSelectedTab(Tabs.TEAM2)} - > - SPA - */} + {isVisibleTeamsTab && ( + setSelectedTab(Tabs.TEAMS)} + > + + + )} + {isVisibleTeam1PlayersTab && ( + setSelectedTab(Tabs.TEAM1)} + > + + + )} + {isVisibleTeam2PlayersTab && ( + setSelectedTab(Tabs.TEAM2)} + > + + + )} @@ -69,7 +95,9 @@ export const TabStats = () => {
- +
) } diff --git a/src/features/MatchSidePlaylists/components/TeamsStatsTable/hooks.tsx b/src/features/MatchSidePlaylists/components/TeamsStatsTable/hooks.tsx index 965decfb..d4698aea 100644 --- a/src/features/MatchSidePlaylists/components/TeamsStatsTable/hooks.tsx +++ b/src/features/MatchSidePlaylists/components/TeamsStatsTable/hooks.tsx @@ -1,5 +1,6 @@ import isNumber from 'lodash/isNumber' import find from 'lodash/find' +import round from 'lodash/round' import type { Param } from 'requests' @@ -9,7 +10,7 @@ export const useTeamsStatsTable = () => { const { profile, teamsStats } = useMatchPageStore() const getDisplayedValue = (val: any) => ( - isNumber(val) ? val : '-' + isNumber(val) ? round(val, 2) : '-' ) const getStatItemById = (paramId: number) => { diff --git a/src/features/MatchSidePlaylists/hooks.tsx b/src/features/MatchSidePlaylists/hooks.tsx index 1fbf40d4..8a2bcf37 100644 --- a/src/features/MatchSidePlaylists/hooks.tsx +++ b/src/features/MatchSidePlaylists/hooks.tsx @@ -16,7 +16,9 @@ export const useMatchSidePlaylists = () => { const { closePopup, events, + isEmptyPlayersStats, matchPlaylists: playlists, + profile: matchProfile, teamsStats, tournamentData, } = useMatchPageStore() @@ -46,7 +48,14 @@ export const useMatchSidePlaylists = () => { const isStatsTabVisible = useMemo(() => ( !isEmpty(teamsStats) - ), [teamsStats]) + || (matchProfile?.team1.id && !isEmptyPlayersStats(matchProfile.team1.id)) + || (matchProfile?.team2.id && !isEmptyPlayersStats(matchProfile.team2.id)) + ), [ + isEmptyPlayersStats, + matchProfile?.team1.id, + matchProfile?.team2.id, + teamsStats, + ]) const hasLessThanFourTabs = compact([ isWatchTabVisible, @@ -57,15 +66,15 @@ export const useMatchSidePlaylists = () => { useEffect(() => { switch (true) { - case isWatchTabVisible: - setSelectedTab(Tabs.WATCH) - break - case isEventTabVisible: - setSelectedTab(Tabs.EVENTS) - break - case isPlayersTabVisible: - setSelectedTab(Tabs.PLAYERS) - break + // case isWatchTabVisible: + // setSelectedTab(Tabs.WATCH) + // break + // case isEventTabVisible: + // setSelectedTab(Tabs.EVENTS) + // break + // case isPlayersTabVisible: + // setSelectedTab(Tabs.PLAYERS) + // break case isStatsTabVisible: setSelectedTab(Tabs.STATS) break diff --git a/src/helpers/getTeamAbbr/index.tsx b/src/helpers/getTeamAbbr/index.tsx new file mode 100644 index 00000000..62a1eb51 --- /dev/null +++ b/src/helpers/getTeamAbbr/index.tsx @@ -0,0 +1,25 @@ +import toUpper from 'lodash/toUpper' +import split from 'lodash/split' +import size from 'lodash/size' + +import pipe from 'lodash/fp/pipe' +import take from 'lodash/fp/take' +import join from 'lodash/fp/join' +import map from 'lodash/fp/map' + +export const getTeamAbbr = (teamName: string) => { + const nameParts = split(teamName, ' ') + + return size(nameParts) > 1 + ? pipe( + map(take(1)), + join(''), + toUpper, + )(nameParts) + + : pipe( + take(3), + join(''), + toUpper, + )(nameParts[0]) +} diff --git a/src/helpers/index.tsx b/src/helpers/index.tsx index 734a5130..0577a810 100644 --- a/src/helpers/index.tsx +++ b/src/helpers/index.tsx @@ -8,3 +8,4 @@ export * from './secondsToHms' export * from './redirectToUrl' export * from './getRandomString' export * from './selectedApi' +export * from './getTeamAbbr' diff --git a/src/hooks/index.tsx b/src/hooks/index.tsx index f318328b..8219ac0e 100644 --- a/src/hooks/index.tsx +++ b/src/hooks/index.tsx @@ -4,3 +4,4 @@ export * from './useStorage' export * from './useInterval' export * from './useEventListener' export * from './useObjectState' +export * from './usePageParams' diff --git a/src/requests/getMatchParticipants.tsx b/src/requests/getMatchParticipants.tsx new file mode 100644 index 00000000..645c3c03 --- /dev/null +++ b/src/requests/getMatchParticipants.tsx @@ -0,0 +1,65 @@ +import isUndefined from 'lodash/isUndefined' + +import { SportTypes } from 'config' + +import { callApi } from 'helpers' + +export type Player = { + birthday: string | null, + c_country: number, + c_gender: number, + club_f_team: number, + club_shirt_num: number, + firstname_eng: string, + firstname_national: string | null, + firstname_rus: string, + height: number | null, + id: number, + is_gk: boolean, + lastname_eng: string, + lastname_national: string | null, + lastname_rus: string, + national_f_team: number | null, + national_shirt_num: number, + nickname_eng: string | null, + nickname_rus: string | null, + weight: number | null, +} + +type DataItem = { + players: Array, + team_id: number, +} + +type Response = { + data?: Array, + error?: { + code: string, + message: string, + }, +} + +type GetMatchParticipantsArgs = { + matchId: number, + second?: number, + sportType: SportTypes, +} + +export const getMatchParticipants = async ({ + matchId, + second, + sportType, +}: GetMatchParticipantsArgs) => { + const config = { + method: 'GET', + } + + const response: Response = await callApi({ + config, + url: `http://136.243.17.103:8888/ask/participants?sport_id=${sportType}&match_id=${matchId}${isUndefined(second) ? '' : `&second=${second}`}`, + }) + + if (response.error) Promise.reject(response) + + return Promise.resolve(response.data || []) +} diff --git a/src/requests/getPlayersStats.tsx b/src/requests/getPlayersStats.tsx new file mode 100644 index 00000000..3fb5d93f --- /dev/null +++ b/src/requests/getPlayersStats.tsx @@ -0,0 +1,54 @@ +import isUndefined from 'lodash/isUndefined' + +import { callApi } from 'helpers' + +export type PlayerParam = { + clickable: boolean, + data_type: string, + id: number, + lexic: number, + lexica_short: number | null, + markers: Array | null, + name_en: string, + name_ru: string, + val: number | null, +} + +export type PlayersStats = { + [playerId: string]: { + [paramId: string]: PlayerParam, + }, +} + +type Response = { + data?: PlayersStats, + error?: string, + message?: string, +} + +type GetPlayersStatsArgs = { + matchId: number, + second?: number, + sportName: string, + teamId: number, +} + +export const getPlayersStats = async ({ + matchId, + second, + sportName, + teamId, +}: GetPlayersStatsArgs) => { + const config = { + method: 'GET', + } + + const response: Response = await callApi({ + config, + url: `http://136.243.17.103:8888/${sportName}/matches/${matchId}/teams/${teamId}/players/stats${isUndefined(second) ? '' : `?second=${second}`}`, + }) + + if (response.error) Promise.reject(response) + + return Promise.resolve(response.data || {}) +} diff --git a/src/requests/getTeamsStats.tsx b/src/requests/getTeamsStats.tsx index 4be9afee..acdf40bd 100644 --- a/src/requests/getTeamsStats.tsx +++ b/src/requests/getTeamsStats.tsx @@ -47,7 +47,7 @@ export const getTeamsStats = async ({ const response: Response = await callApi({ config, - url: `https://statistic.insports.tv/${sportName}/matches/${matchId}/teams/stats?group_num=0${isUndefined(second) ? '' : `&second=${second}`}`, + url: `http://136.243.17.103:8888/${sportName}/matches/${matchId}/teams/stats?group_num=0${isUndefined(second) ? '' : `&second=${second}`}`, }) if (response.error) Promise.reject(response) diff --git a/src/requests/index.tsx b/src/requests/index.tsx index ca1042a0..364ac1d9 100644 --- a/src/requests/index.tsx +++ b/src/requests/index.tsx @@ -25,3 +25,5 @@ export * from './getPlayerPlaylists' export * from './getSubscriptions' export * from './buySubscription' export * from './getTeamsStats' +export * from './getPlayersStats' +export * from './getMatchParticipants'