parent
6f694eeb9f
commit
269ddad403
@ -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<Player>, |
||||||
|
team2: Array<Player>, |
||||||
|
} |
||||||
|
|
||||||
|
export const usePlayersStats = ({ |
||||||
|
matchProfile, |
||||||
|
playingProgress, |
||||||
|
statsType, |
||||||
|
}: UsePlayersStatsArgs) => { |
||||||
|
const [playersStats, setPlayersStats] = useObjectState<Record<string, PlayersStats>>({}) |
||||||
|
const [playersData, setPlayersData] = useState<PlayersData>({ 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, |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,12 @@ |
|||||||
|
import { useState } from 'react' |
||||||
|
|
||||||
|
import { StatsType } from 'features/MatchSidePlaylists/components/TabStats/config' |
||||||
|
|
||||||
|
export const useStatsTab = () => { |
||||||
|
const [statsType, setStatsType] = useState<StatsType>(StatsType.FINAL_STATS) |
||||||
|
|
||||||
|
return { |
||||||
|
setStatsType, |
||||||
|
statsType, |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,78 @@ |
|||||||
|
import { |
||||||
|
useEffect, |
||||||
|
useState, |
||||||
|
useMemo, |
||||||
|
} from 'react' |
||||||
|
|
||||||
|
import throttle from 'lodash/throttle' |
||||||
|
|
||||||
|
import type { MatchInfo } from 'requests' |
||||||
|
import { getTeamsStats, TeamStatItem } from 'requests' |
||||||
|
|
||||||
|
import { usePageParams } from 'hooks/usePageParams' |
||||||
|
|
||||||
|
import { StatsType } from 'features/MatchSidePlaylists/components/TabStats/config' |
||||||
|
|
||||||
|
const REQUEST_DELAY = 3000 |
||||||
|
const STATS_POLL_INTERVAL = 30000 |
||||||
|
|
||||||
|
type UseTeamsStatsArgs = { |
||||||
|
matchProfile: MatchInfo, |
||||||
|
playingProgress: number, |
||||||
|
statsType: StatsType, |
||||||
|
} |
||||||
|
|
||||||
|
export const useTeamsStats = ({ |
||||||
|
matchProfile, |
||||||
|
playingProgress, |
||||||
|
statsType, |
||||||
|
}: UseTeamsStatsArgs) => { |
||||||
|
const [teamsStats, setTeamsStats] = useState<{ |
||||||
|
[teamId: string]: Array<TeamStatItem>, |
||||||
|
}>({}) |
||||||
|
|
||||||
|
const { profileId: matchId, sportName } = usePageParams() |
||||||
|
|
||||||
|
const progressSec = Math.floor(playingProgress / 1000) |
||||||
|
|
||||||
|
const isCurrentStats = statsType === StatsType.CURRENT_STATS |
||||||
|
|
||||||
|
const fetchTeamsStats = useMemo(() => throttle((second?: number) => { |
||||||
|
if (!sportName) return |
||||||
|
|
||||||
|
getTeamsStats({ |
||||||
|
matchId, |
||||||
|
second, |
||||||
|
sportName, |
||||||
|
}).then(setTeamsStats) |
||||||
|
}, REQUEST_DELAY), [matchId, sportName]) |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
let timer: ReturnType<typeof setInterval> |
||||||
|
|
||||||
|
if (!isCurrentStats) { |
||||||
|
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 { |
||||||
|
statsType, |
||||||
|
teamsStats, |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,6 @@ |
|||||||
|
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 |
||||||
@ -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<SortCondition>({ 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, |
||||||
|
} |
||||||
|
} |
||||||
@ -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, |
||||||
|
} |
||||||
|
} |
||||||
@ -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<SetStateAction<SortCondition>>, |
||||||
|
teamId: number, |
||||||
|
} |
||||||
|
|
||||||
|
type HeaderParam = Pick<PlayerParam, 'id' | 'lexica_short' | 'lexic'> |
||||||
|
|
||||||
|
export const useTable = ({ |
||||||
|
setSortCondition, |
||||||
|
teamId, |
||||||
|
}: UseTableArgs) => { |
||||||
|
const containerRef = useRef<HTMLDivElement>(null) |
||||||
|
const tableWrapperRef = useRef<HTMLDivElement>(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, Record<string, HeaderParam>>( |
||||||
|
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<HeaderParam, Array<number>>( |
||||||
|
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<HTMLDivElement>) => { |
||||||
|
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, |
||||||
|
} |
||||||
|
} |
||||||
@ -1,243 +1,166 @@ |
|||||||
|
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 { |
import { |
||||||
|
Container, |
||||||
|
TableWrapper, |
||||||
Table, |
Table, |
||||||
Thead, |
FirstColumn, |
||||||
Th, |
Cell, |
||||||
Tbody, |
Row, |
||||||
Tr, |
|
||||||
Td, |
|
||||||
PlayerNum, |
PlayerNum, |
||||||
|
PlayerNameWrapper, |
||||||
|
PlayerName, |
||||||
ParamShortTitle, |
ParamShortTitle, |
||||||
|
ArrowButtonRight, |
||||||
|
ArrowButtonLeft, |
||||||
|
Arrow, |
||||||
|
ExpandButton, |
||||||
|
Tooltip, |
||||||
} from './styled' |
} from './styled' |
||||||
|
|
||||||
export const PlayersTable = () => ( |
export const PlayersTable = (props: PlayersTableProps) => { |
||||||
<Table> |
const { |
||||||
<Thead> |
containerRef, |
||||||
<Th /> |
firstColumnWidth, |
||||||
<Th> |
getDisplayedValue, |
||||||
<ParamShortTitle>Min</ParamShortTitle> |
getFullName, |
||||||
</Th> |
getPlayerParams, |
||||||
<Th sorted> |
handleScroll, |
||||||
<ParamShortTitle>Pt</ParamShortTitle> |
handleSortClick, |
||||||
</Th> |
isExpanded, |
||||||
<Th> |
paramColumnWidth, |
||||||
<ParamShortTitle>Reb</ParamShortTitle> |
params, |
||||||
</Th> |
players, |
||||||
<Th> |
showExpandButton, |
||||||
<ParamShortTitle>Ass</ParamShortTitle> |
showLeftArrow, |
||||||
</Th> |
showRightArrow, |
||||||
<Th> |
slideLeft, |
||||||
<ParamShortTitle>To</ParamShortTitle> |
slideRight, |
||||||
</Th> |
sortCondition, |
||||||
</Thead> |
tableWrapperRef, |
||||||
<Tbody> |
toggleIsExpanded, |
||||||
<Tr> |
} = usePlayersTable(props) |
||||||
<Td><PlayerNum>57</PlayerNum> Selikhov</Td> |
|
||||||
<Td clickable>97</Td> |
return ( |
||||||
<Td sorted>12</Td> |
<Container |
||||||
<Td>2</Td> |
ref={containerRef} |
||||||
<Td>1</Td> |
isExpanded={isExpanded} |
||||||
<Td>4</Td> |
> |
||||||
</Tr> |
<TableWrapper |
||||||
<Tr> |
ref={tableWrapperRef} |
||||||
<Td><PlayerNum>57</PlayerNum> Selikhov</Td> |
isExpanded={isExpanded} |
||||||
<Td clickable>97</Td> |
onScroll={handleScroll} |
||||||
<Td sorted>12</Td> |
> |
||||||
<Td>2</Td> |
{!isExpanded && ( |
||||||
<Td>1</Td> |
<Fragment> |
||||||
<Td>4</Td> |
{showLeftArrow && ( |
||||||
</Tr> |
<ArrowButtonLeft |
||||||
<Tr> |
aria-label='Scroll to left' |
||||||
<Td><PlayerNum>57</PlayerNum> Selikhov</Td> |
onClick={slideLeft} |
||||||
<Td clickable>97</Td> |
> |
||||||
<Td sorted>12</Td> |
<Arrow direction='left' /> |
||||||
<Td>2</Td> |
</ArrowButtonLeft> |
||||||
<Td>1</Td> |
)} |
||||||
<Td>4</Td> |
{showRightArrow && ( |
||||||
</Tr> |
<ArrowButtonRight |
||||||
<Tr> |
aria-label='Scroll to right' |
||||||
<Td><PlayerNum>57</PlayerNum> Selikhov</Td> |
onClick={slideRight} |
||||||
<Td clickable>97</Td> |
> |
||||||
<Td sorted>12</Td> |
<Arrow direction='right' /> |
||||||
<Td>2</Td> |
</ArrowButtonRight> |
||||||
<Td>1</Td> |
)} |
||||||
<Td>4</Td> |
</Fragment> |
||||||
</Tr> |
)} |
||||||
<Tr> |
<FirstColumn columnWidth={firstColumnWidth}> |
||||||
<Td><PlayerNum>57</PlayerNum> Selikhov</Td> |
<Row> |
||||||
<Td clickable>97</Td> |
<Cell> |
||||||
<Td sorted>12</Td> |
{showExpandButton && ( |
||||||
<Td>2</Td> |
<ExpandButton |
||||||
<Td>1</Td> |
aria-label={isExpanded ? 'Reduce' : 'Expand'} |
||||||
<Td>4</Td> |
onClick={toggleIsExpanded} |
||||||
</Tr> |
> |
||||||
<Tr> |
<Arrow direction={isExpanded ? 'right' : 'left'} /> |
||||||
<Td><PlayerNum>57</PlayerNum> Selikhov</Td> |
<Arrow direction={isExpanded ? 'right' : 'left'} /> |
||||||
<Td clickable>97</Td> |
</ExpandButton> |
||||||
<Td sorted>12</Td> |
)} |
||||||
<Td>2</Td> |
</Cell> |
||||||
<Td>1</Td> |
</Row> |
||||||
<Td>4</Td> |
{map(players, (player) => { |
||||||
</Tr> |
const fullName = getFullName(player) |
||||||
<Tr> |
|
||||||
<Td><PlayerNum>57</PlayerNum> Selikhov</Td> |
return ( |
||||||
<Td clickable>97</Td> |
<Row key={player.id}> |
||||||
<Td sorted>12</Td> |
<Cell> |
||||||
<Td>2</Td> |
<PlayerNum> |
||||||
<Td>1</Td> |
{player.club_shirt_num} |
||||||
<Td>4</Td> |
</PlayerNum>{' '} |
||||||
</Tr> |
<PlayerNameWrapper> |
||||||
<Tr> |
<PlayerName columnWidth={firstColumnWidth}> |
||||||
<Td><PlayerNum>57</PlayerNum> Selikhov</Td> |
{fullName} |
||||||
<Td clickable>97</Td> |
</PlayerName> |
||||||
<Td sorted>12</Td> |
<Tooltip> |
||||||
<Td>2</Td> |
<PlayerName>{fullName}</PlayerName> |
||||||
<Td>1</Td> |
</Tooltip> |
||||||
<Td>4</Td> |
</PlayerNameWrapper> |
||||||
</Tr> |
</Cell> |
||||||
<Tr> |
</Row> |
||||||
<Td><PlayerNum>57</PlayerNum> Selikhov</Td> |
) |
||||||
<Td clickable>97</Td> |
})} |
||||||
<Td sorted>12</Td> |
</FirstColumn> |
||||||
<Td>2</Td> |
<Table> |
||||||
<Td>1</Td> |
<Row> |
||||||
<Td>4</Td> |
{map(params, ({ |
||||||
</Tr> |
id, |
||||||
<Tr> |
lexic, |
||||||
<Td><PlayerNum>57</PlayerNum> Selikhov</Td> |
lexica_short, |
||||||
<Td clickable>97</Td> |
}) => ( |
||||||
<Td sorted>12</Td> |
<Cell |
||||||
<Td>2</Td> |
key={id} |
||||||
<Td>1</Td> |
columnWidth={paramColumnWidth} |
||||||
<Td>4</Td> |
onClick={handleSortClick(id)} |
||||||
</Tr> |
sorted={sortCondition.paramId === id} |
||||||
<Tr> |
headerCell |
||||||
<Td><PlayerNum>57</PlayerNum> Selikhov</Td> |
> |
||||||
<Td clickable>97</Td> |
<ParamShortTitle t={lexica_short || ''} /> |
||||||
<Td sorted>12</Td> |
<Tooltip> |
||||||
<Td>2</Td> |
<T9n t={lexic} /> |
||||||
<Td>1</Td> |
</Tooltip> |
||||||
<Td>4</Td> |
</Cell> |
||||||
</Tr> |
))} |
||||||
<Tr> |
</Row> |
||||||
<Td><PlayerNum>57</PlayerNum> Selikhov</Td> |
|
||||||
<Td clickable>97</Td> |
{map(players, (player) => ( |
||||||
<Td sorted>12</Td> |
<Row key={player.id}> |
||||||
<Td>2</Td> |
{map(params, ({ id }) => { |
||||||
<Td>1</Td> |
const playerParam = getPlayerParams(player.id)[id] as PlayerParam | undefined |
||||||
<Td>4</Td> |
const value = playerParam ? getDisplayedValue(playerParam) : '-' |
||||||
</Tr> |
const clickable = Boolean(playerParam?.clickable) && !includes([0, '-'], value) |
||||||
<Tr> |
const sorted = sortCondition.paramId === id |
||||||
<Td><PlayerNum>57</PlayerNum> Selikhov</Td> |
|
||||||
<Td clickable>97</Td> |
return ( |
||||||
<Td sorted>12</Td> |
<Cell |
||||||
<Td>2</Td> |
columnWidth={paramColumnWidth} |
||||||
<Td>1</Td> |
key={id} |
||||||
<Td>4</Td> |
clickable={clickable} |
||||||
</Tr> |
sorted={sorted} |
||||||
<Tr> |
> |
||||||
<Td><PlayerNum>57</PlayerNum> Selikhov</Td> |
{value} |
||||||
<Td clickable>97</Td> |
</Cell> |
||||||
<Td sorted>12</Td> |
) |
||||||
<Td>2</Td> |
})} |
||||||
<Td>1</Td> |
</Row> |
||||||
<Td>4</Td> |
))} |
||||||
</Tr> |
</Table> |
||||||
<Tr> |
</TableWrapper> |
||||||
<Td><PlayerNum>57</PlayerNum> Selikhov</Td> |
</Container> |
||||||
<Td clickable>97</Td> |
) |
||||||
<Td sorted>12</Td> |
} |
||||||
<Td>2</Td> |
|
||||||
<Td>1</Td> |
|
||||||
<Td>4</Td> |
|
||||||
</Tr> |
|
||||||
<Tr> |
|
||||||
<Td><PlayerNum>57</PlayerNum> Selikhov</Td> |
|
||||||
<Td clickable>97</Td> |
|
||||||
<Td sorted>12</Td> |
|
||||||
<Td>2</Td> |
|
||||||
<Td>1</Td> |
|
||||||
<Td>4</Td> |
|
||||||
</Tr> |
|
||||||
<Tr> |
|
||||||
<Td><PlayerNum>57</PlayerNum> Selikhov</Td> |
|
||||||
<Td clickable>97</Td> |
|
||||||
<Td sorted>12</Td> |
|
||||||
<Td>2</Td> |
|
||||||
<Td>1</Td> |
|
||||||
<Td>4</Td> |
|
||||||
</Tr> |
|
||||||
<Tr> |
|
||||||
<Td><PlayerNum>57</PlayerNum> Selikhov</Td> |
|
||||||
<Td clickable>97</Td> |
|
||||||
<Td sorted>12</Td> |
|
||||||
<Td>2</Td> |
|
||||||
<Td>1</Td> |
|
||||||
<Td>4</Td> |
|
||||||
</Tr> |
|
||||||
<Tr> |
|
||||||
<Td><PlayerNum>57</PlayerNum> Selikhov</Td> |
|
||||||
<Td clickable>97</Td> |
|
||||||
<Td sorted>12</Td> |
|
||||||
<Td>2</Td> |
|
||||||
<Td>1</Td> |
|
||||||
<Td>4</Td> |
|
||||||
</Tr> |
|
||||||
<Tr> |
|
||||||
<Td><PlayerNum>57</PlayerNum> Selikhov</Td> |
|
||||||
<Td clickable>97</Td> |
|
||||||
<Td sorted>12</Td> |
|
||||||
<Td>2</Td> |
|
||||||
<Td>1</Td> |
|
||||||
<Td>4</Td> |
|
||||||
</Tr> |
|
||||||
<Tr> |
|
||||||
<Td><PlayerNum>57</PlayerNum> Selikhov</Td> |
|
||||||
<Td clickable>97</Td> |
|
||||||
<Td sorted>12</Td> |
|
||||||
<Td>2</Td> |
|
||||||
<Td>1</Td> |
|
||||||
<Td>4</Td> |
|
||||||
</Tr> |
|
||||||
<Tr> |
|
||||||
<Td><PlayerNum>57</PlayerNum> Selikhov</Td> |
|
||||||
<Td clickable>97</Td> |
|
||||||
<Td sorted>12</Td> |
|
||||||
<Td>2</Td> |
|
||||||
<Td>1</Td> |
|
||||||
<Td>4</Td> |
|
||||||
</Tr> |
|
||||||
<Tr> |
|
||||||
<Td><PlayerNum>57</PlayerNum> Selikhov</Td> |
|
||||||
<Td clickable>97</Td> |
|
||||||
<Td sorted>12</Td> |
|
||||||
<Td>2</Td> |
|
||||||
<Td>1</Td> |
|
||||||
<Td>4</Td> |
|
||||||
</Tr> |
|
||||||
<Tr> |
|
||||||
<Td><PlayerNum>57</PlayerNum> Selikhov</Td> |
|
||||||
<Td clickable>97</Td> |
|
||||||
<Td sorted>12</Td> |
|
||||||
<Td>2</Td> |
|
||||||
<Td>1</Td> |
|
||||||
<Td>4</Td> |
|
||||||
</Tr> |
|
||||||
<Tr> |
|
||||||
<Td><PlayerNum>57</PlayerNum> Selikhov</Td> |
|
||||||
<Td clickable>97</Td> |
|
||||||
<Td sorted>12</Td> |
|
||||||
<Td>2</Td> |
|
||||||
<Td>1</Td> |
|
||||||
<Td>4</Td> |
|
||||||
</Tr> |
|
||||||
<Tr> |
|
||||||
<Td><PlayerNum>57</PlayerNum> Selikhov</Td> |
|
||||||
<Td clickable>97</Td> |
|
||||||
<Td sorted>12</Td> |
|
||||||
<Td>2</Td> |
|
||||||
<Td>1</Td> |
|
||||||
<Td>4</Td> |
|
||||||
</Tr> |
|
||||||
</Tbody> |
|
||||||
</Table> |
|
||||||
) |
|
||||||
|
|||||||
@ -0,0 +1,8 @@ |
|||||||
|
export type PlayersTableProps = { |
||||||
|
teamId: number, |
||||||
|
} |
||||||
|
|
||||||
|
export type SortCondition = { |
||||||
|
dir: 'asc' | 'desc', |
||||||
|
paramId: number | null, |
||||||
|
} |
||||||
@ -0,0 +1,68 @@ |
|||||||
|
import { useEffect, useState } from 'react' |
||||||
|
|
||||||
|
import isEmpty from 'lodash/isEmpty' |
||||||
|
|
||||||
|
import { useMatchPageStore } from 'features/MatchPage/store' |
||||||
|
|
||||||
|
import { StatsType, Tabs } from './config' |
||||||
|
|
||||||
|
export const useTabStats = () => { |
||||||
|
const [selectedTab, setSelectedTab] = useState<Tabs>(Tabs.TEAMS) |
||||||
|
|
||||||
|
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, |
||||||
|
toggleStatsType, |
||||||
|
tooltipLexic, |
||||||
|
} |
||||||
|
} |
||||||
@ -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,31 @@ |
|||||||
|
import isNumber from 'lodash/isNumber' |
||||||
|
import find from 'lodash/find' |
||||||
|
import round from 'lodash/round' |
||||||
|
|
||||||
|
import type { Param } from 'requests' |
||||||
|
|
||||||
|
import { useMatchPageStore } from 'features/MatchPage/store' |
||||||
|
|
||||||
|
export const useTeamsStatsTable = () => { |
||||||
|
const { profile, teamsStats } = useMatchPageStore() |
||||||
|
|
||||||
|
const getDisplayedValue = (val: any) => ( |
||||||
|
isNumber(val) ? round(val, 2) : '-' |
||||||
|
) |
||||||
|
|
||||||
|
const getStatItemById = (paramId: number) => { |
||||||
|
if (!profile) return null |
||||||
|
|
||||||
|
return find(teamsStats[profile?.team2.id], ({ param1 }) => param1.id === paramId) || null |
||||||
|
} |
||||||
|
|
||||||
|
const isClickable = (param: Param) => ( |
||||||
|
Boolean(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> |
||||||
|
) |
||||||
|
} |
||||||
@ -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]) |
||||||
|
} |
||||||
@ -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<Player>, |
||||||
|
team_id: number, |
||||||
|
} |
||||||
|
|
||||||
|
type Response = { |
||||||
|
data?: Array<DataItem>, |
||||||
|
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 || []) |
||||||
|
} |
||||||
@ -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<number> | 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 || {}) |
||||||
|
} |
||||||
@ -0,0 +1,56 @@ |
|||||||
|
import isUndefined from 'lodash/isUndefined' |
||||||
|
|
||||||
|
import { callApi } from 'helpers' |
||||||
|
|
||||||
|
export type Param = { |
||||||
|
clickable: boolean, |
||||||
|
data_type: string, |
||||||
|
id: number, |
||||||
|
lexic: number, |
||||||
|
markers: Array<number>, |
||||||
|
name_en: string, |
||||||
|
name_ru: string, |
||||||
|
val: number | null, |
||||||
|
} |
||||||
|
|
||||||
|
export type TeamStatItem = { |
||||||
|
lexic: number, |
||||||
|
name_en: string, |
||||||
|
name_ru: string, |
||||||
|
order: number, |
||||||
|
param1: Param, |
||||||
|
param2: Param | null, |
||||||
|
} |
||||||
|
|
||||||
|
type Response = { |
||||||
|
data?: { |
||||||
|
[teamId: string]: Array<TeamStatItem>, |
||||||
|
}, |
||||||
|
error?: string, |
||||||
|
message?: string, |
||||||
|
} |
||||||
|
|
||||||
|
type GetTeamsStatsArgs = { |
||||||
|
matchId: number, |
||||||
|
second?: number, |
||||||
|
sportName: string, |
||||||
|
} |
||||||
|
|
||||||
|
export const getTeamsStats = async ({ |
||||||
|
matchId, |
||||||
|
second, |
||||||
|
sportName, |
||||||
|
}: GetTeamsStatsArgs) => { |
||||||
|
const config = { |
||||||
|
method: 'GET', |
||||||
|
} |
||||||
|
|
||||||
|
const response: Response = await callApi({ |
||||||
|
config, |
||||||
|
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) |
||||||
|
|
||||||
|
return Promise.resolve(response.data || {}) |
||||||
|
} |
||||||
Loading…
Reference in new issue