diff --git a/src/features/MatchPage/components/LiveMatch/helpers.tsx b/src/features/MatchPage/components/LiveMatch/helpers.tsx index df315409..165601ab 100644 --- a/src/features/MatchPage/components/LiveMatch/helpers.tsx +++ b/src/features/MatchPage/components/LiveMatch/helpers.tsx @@ -3,8 +3,11 @@ import find from 'lodash/find' import reduce from 'lodash/reduce' import concat from 'lodash/concat' -import type { Episodes } from 'requests/getMatchPlaylists' -import type { MatchInfo } from 'requests/getMatchInfo' +import type { + MatchInfo, + MatchScore, + Episodes, +} from 'requests' import type { Chapters, Chapter } from 'features/StreamPlayer/types' @@ -13,16 +16,25 @@ import { FULL_GAME_KEY } from '../../helpers/buildPlaylists' export const FULL_MATCH_BOUNDARY = '0' +type GetFullMatchChaptersArgs = { + matchScore?: MatchScore, + playlist: MatchPlaylistOption, + profile: MatchInfo, + url: string, +} + /** * Формирует эпизоды плейлиста Полный матч * API не выдает полный матч как плейлист, формируем на фронте * */ -const getFullMatchChapters = ( - profile: MatchInfo, - url: string, - playlist: MatchPlaylistOption, -) => { - const bound = find(profile?.video_bounds, { h: FULL_MATCH_BOUNDARY }) +const getFullMatchChapters = ({ + matchScore, + playlist, + profile, + url, +}: GetFullMatchChaptersArgs) => { + const videoBounds = matchScore?.video_bounds || profile?.video_bounds + const bound = find(videoBounds, { h: FULL_MATCH_BOUNDARY }) const durationMs = (bound && !profile?.live) ? ((playlist.duration ?? 0) - Number(bound.s)) * 1000 @@ -42,14 +54,22 @@ const getFullMatchChapters = ( ] } +type GetPlaylistChaptersArgs = { + episodes: Episodes, + matchScore?: MatchScore, + profile: MatchInfo, + url: string, +} + /** * Формирует эпизоды плейлистов матча и игроков * */ -const getPlaylistChapters = ( - profile: MatchInfo, - url: string, - episodes: Episodes, -) => reduce( +const getPlaylistChapters = ({ + episodes, + matchScore, + profile, + url, +}: GetPlaylistChaptersArgs) => reduce( episodes, ( acc: Chapters, @@ -58,7 +78,8 @@ const getPlaylistChapters = ( ) => { if (episode.s >= episode.e) return acc - const bound = find(profile?.video_bounds, { h: String(episode.h) }) + const videoBounds = matchScore?.video_bounds || profile?.video_bounds + const bound = find(videoBounds, { h: String(episode.h) }) const boundStart = bound ? Number(bound.s) : 0 const episodeDuration = (episode.e - episode.s) * 1000 @@ -79,6 +100,7 @@ const getPlaylistChapters = ( ) type Args = { + matchScore?: MatchScore, profile: MatchInfo, selectedPlaylist?: PlaylistOption, url: string, @@ -88,21 +110,24 @@ type Args = { * Формирует список эпизодов из выбранного плейлиста для плеера */ export const buildChapters = ({ + matchScore, profile, selectedPlaylist, url, }: Args): Chapters => { if (!selectedPlaylist) return [] if (selectedPlaylist.id === FULL_GAME_KEY) { - return getFullMatchChapters( + return getFullMatchChapters({ + matchScore, + playlist: selectedPlaylist, profile, url, - selectedPlaylist, - ) + }) } - return getPlaylistChapters( + return getPlaylistChapters({ + episodes: selectedPlaylist.episodes, + matchScore, profile, url, - selectedPlaylist.episodes, - ) + }) } diff --git a/src/features/MatchPage/components/LiveMatch/hooks/useChapters.tsx b/src/features/MatchPage/components/LiveMatch/hooks/useChapters.tsx index 146134aa..527b90eb 100644 --- a/src/features/MatchPage/components/LiveMatch/hooks/useChapters.tsx +++ b/src/features/MatchPage/components/LiveMatch/hooks/useChapters.tsx @@ -1,7 +1,10 @@ import { useMemo } from 'react' +import { useQueryClient } from 'react-query' + +import { querieKeys } from 'config' import type { PlaylistOption } from 'features/MatchPage/types' -import type { MatchInfo } from 'requests/getMatchInfo' +import type { MatchInfo, MatchScore } from 'requests' import { buildChapters } from '../helpers' @@ -16,13 +19,19 @@ export const useChapters = ({ selectedPlaylist, url, }: Args) => { + const client = useQueryClient() + + const matchScore = client.getQueryData(querieKeys.matchScore) + const chapters = useMemo( () => buildChapters({ + matchScore, profile, selectedPlaylist, url, }), [ + matchScore, profile, selectedPlaylist, url, diff --git a/src/features/MatchPage/components/MatchDescription/index.tsx b/src/features/MatchPage/components/MatchDescription/index.tsx index cc69648e..4648d086 100644 --- a/src/features/MatchPage/components/MatchDescription/index.tsx +++ b/src/features/MatchPage/components/MatchDescription/index.tsx @@ -57,7 +57,7 @@ export const MatchDescription = () => { const { data: queryScore } = useQuery({ queryFn: async () => { - if (profile?.live && !isScoreHidden) { + if (profile?.live) { const score = await getMatchScore({ profileId, sportType }) return score } diff --git a/src/features/MatchPage/helpers/fullMatchDuration.tsx b/src/features/MatchPage/helpers/fullMatchDuration.tsx deleted file mode 100644 index f31b20b2..00000000 --- a/src/features/MatchPage/helpers/fullMatchDuration.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import find from 'lodash/find' - -import type { MatchInfo } from 'requests/getMatchInfo' - -import { FULL_MATCH_BOUNDARY } from 'features/MatchPage/components/LiveMatch/helpers' - -export const calculateDuration = (profile: MatchInfo) => { - const bound = find(profile?.video_bounds, { h: FULL_MATCH_BOUNDARY }) - if (!bound) return 0 - return Number(bound.e) - Number(bound.s) -} diff --git a/src/features/MatchPage/store/hooks/index.tsx b/src/features/MatchPage/store/hooks/index.tsx index 7ab9855f..3e12ba13 100644 --- a/src/features/MatchPage/store/hooks/index.tsx +++ b/src/features/MatchPage/store/hooks/index.tsx @@ -240,7 +240,7 @@ export const useMatchPage = () => { : true ), [profile?.date]) - const { tournamentData } = useTournamentData(matchProfile?.tournament.id ?? null) + const { tournamentData } = useTournamentData(matchProfile) const filteredEvents = useMemo(() => { switch (true) { diff --git a/src/features/MatchPage/store/hooks/useMatchData.tsx b/src/features/MatchPage/store/hooks/useMatchData.tsx index 892e274f..3ec80e74 100644 --- a/src/features/MatchPage/store/hooks/useMatchData.tsx +++ b/src/features/MatchPage/store/hooks/useMatchData.tsx @@ -17,6 +17,7 @@ import { useMatchPopupStore } from 'features/MatchPopup' import { useMatchPlaylists } from './useMatchPlaylists' import { useEvents } from './useEvents' +import { initialPlaylist } from './useSelectedPlaylist' const MATCH_DATA_POLL_INTERVAL = 60000 const MATCH_PLAYLISTS_DELAY = 5000 @@ -43,7 +44,7 @@ export const useMatchData = (profile: MatchInfo) => { const chaptersDuration = useDuration(chapters) / 1000 const fullMatchDuration = matchDuration useEffect(() => { - if (!profile) return + if (!profile || (profile.live && Number(profile.c_match_calc_status) <= 1)) return fetchMatchPlaylists({ fullMatchDuration, id: matchId, @@ -75,12 +76,12 @@ export const useMatchData = (profile: MatchInfo) => { }) useEffect(() => { - if (profile?.live) { + if (profile?.live && Number(profile.c_match_calc_status) > 1) { start() } else { stop() } - }, [profile?.live, start, stop]) + }, [profile?.live, profile?.c_match_calc_status, start, stop]) useEffect(() => { selectedPlaylist?.id === FULL_GAME_KEY && setMatchDuration(chaptersDuration) @@ -88,7 +89,7 @@ export const useMatchData = (profile: MatchInfo) => { }, [profile, chaptersDuration]) useEffect(() => { - setSelectedPlaylist(matchPlaylists.match[0]) + setSelectedPlaylist(matchPlaylists.match[0] || initialPlaylist) // eslint-disable-next-line }, [matchId]) diff --git a/src/features/MatchPage/store/hooks/useMatchPlaylists.tsx b/src/features/MatchPage/store/hooks/useMatchPlaylists.tsx index 66cb79f0..17718042 100644 --- a/src/features/MatchPage/store/hooks/useMatchPlaylists.tsx +++ b/src/features/MatchPage/store/hooks/useMatchPlaylists.tsx @@ -17,7 +17,7 @@ import type { Playlists } from 'features/MatchPage/types' import { buildPlaylists, FULL_GAME_KEY } from 'features/MatchPage/helpers/buildPlaylists' import { usePlaylistLexics } from './usePlaylistLexics' -import { useSelectedPlaylist } from './useSelectedPlaylist' +import { initialPlaylist, useSelectedPlaylist } from './useSelectedPlaylist' type ArgsFetchMatchPlaylists = { fullMatchDuration: number, @@ -71,7 +71,7 @@ export const useMatchPlaylists = (profile: MatchInfo) => { useEffect(() => { if (selectedPlaylist?.id !== FULL_GAME_KEY) return - setSelectedPlaylist(matchPlaylists?.match[0]) + setSelectedPlaylist(matchPlaylists?.match[0] || initialPlaylist) // eslint-disable-next-line react-hooks/exhaustive-deps }, [ matchPlaylists?.match, diff --git a/src/features/MatchPage/store/hooks/usePlayersStats.tsx b/src/features/MatchPage/store/hooks/usePlayersStats.tsx index 285bc4ba..4249f023 100644 --- a/src/features/MatchPage/store/hooks/usePlayersStats.tsx +++ b/src/features/MatchPage/store/hooks/usePlayersStats.tsx @@ -4,6 +4,7 @@ import { useEffect, useState, } from 'react' +import { useQueryClient } from 'react-query' import throttle from 'lodash/throttle' import isEmpty from 'lodash/isEmpty' @@ -11,12 +12,16 @@ import every from 'lodash/every' import find from 'lodash/find' import isUndefined from 'lodash/isUndefined' -import type { +import { querieKeys } from 'config' + +import type { MatchScore } from 'requests' +import { MatchInfo, PlayersStats, Player, + getPlayersStats, + getMatchParticipants, } from 'requests' -import { getPlayersStats, getMatchParticipants } from 'requests' import { useObjectState, usePageParams } from 'hooks' @@ -57,6 +62,10 @@ export const usePlayersStats = ({ sportType, } = usePageParams() + const client = useQueryClient() + + const matchScore = client.getQueryData(querieKeys.matchScore) + const isCurrentStats = statsType === StatsType.CURRENT_STATS const isEmptyPlayersStats = (teamId: number) => ( @@ -66,17 +75,19 @@ export const usePlayersStats = ({ ) const fetchPlayers = useMemo(() => throttle(async (second?: number) => { + const videoBounds = matchScore?.video_bounds || matchProfile?.video_bounds + if ( !matchProfile?.team1.id || !matchProfile?.team2.id - || !matchProfile?.video_bounds + || !videoBounds ) return null try { return getMatchParticipants({ matchId, sportType, - ...(!isUndefined(second) && getHalfTime(matchProfile.video_bounds, second)), + ...(!isUndefined(second) && getHalfTime(videoBounds, second)), }) } catch (e) { return Promise.reject(e) @@ -86,18 +97,21 @@ export const usePlayersStats = ({ matchProfile?.team1.id, matchProfile?.team2.id, matchProfile?.video_bounds, + matchScore?.video_bounds, sportType, ]) const fetchPlayersStats = useMemo(() => (async (team: 'team1' | 'team2', second?: number) => { - if (!sportName || !matchProfile?.[team].id || !matchProfile?.video_bounds) return null + const videoBounds = matchScore?.video_bounds || matchProfile?.video_bounds + + if (!sportName || !matchProfile?.[team].id || !videoBounds) return null try { return getPlayersStats({ matchId, sportName, teamId: matchProfile[team].id, - ...(!isUndefined(second) && getHalfTime(matchProfile.video_bounds, second)), + ...(!isUndefined(second) && getHalfTime(videoBounds, second)), }) } catch (e) { return Promise.reject(e) @@ -111,7 +125,10 @@ export const usePlayersStats = ({ ]) const fetchData = useMemo(() => throttle(async (second?: number) => { - if (selectedPlaylist?.id !== FULL_GAME_KEY || !matchProfile?.video_bounds) return + if ( + selectedPlaylist?.id !== FULL_GAME_KEY + || (matchProfile?.live && Number(matchProfile.c_match_calc_status) <= 1) + ) return const [res1, res2, res3] = await Promise.all([ fetchPlayers(second), @@ -140,7 +157,8 @@ export const usePlayersStats = ({ setPlayersStats, matchProfile?.team1.id, matchProfile?.team2.id, - matchProfile?.video_bounds, + matchProfile?.live, + matchProfile?.c_match_calc_status, setIsPlayersStatsFetching, ]) diff --git a/src/features/MatchPage/store/hooks/useSelectedPlaylist.tsx b/src/features/MatchPage/store/hooks/useSelectedPlaylist.tsx index ee732c5b..5c8f8827 100644 --- a/src/features/MatchPage/store/hooks/useSelectedPlaylist.tsx +++ b/src/features/MatchPage/store/hooks/useSelectedPlaylist.tsx @@ -1,6 +1,8 @@ import type { MouseEvent } from 'react' import { useState, useCallback } from 'react' +import { indexLexics } from 'config/lexics/indexLexics' + import { getPlayerPlaylists } from 'requests/getPlayerPlaylists' import { usePageParams } from 'hooks/usePageParams' @@ -11,10 +13,19 @@ import { PlaylistTypes, } from 'features/MatchPage/types' import { defaultSettings } from 'features/MatchPopup/types' +import { FULL_GAME_KEY } from 'features/MatchPage/helpers/buildPlaylists' + +export const initialPlaylist = { + duration: 0, + episodes: [], + id: FULL_GAME_KEY, + lexic: indexLexics.full_game, + type: 0, +} export const useSelectedPlaylist = () => { const { profileId: matchId, sportType } = usePageParams() - const [selectedPlaylist, setSelectedPlaylist] = useState() + const [selectedPlaylist, setSelectedPlaylist] = useState(initialPlaylist) const fetchPlayerEpisodes = useCallback((playlistOption: PlayerPlaylistOption) => ( getPlayerPlaylists({ diff --git a/src/features/MatchPage/store/hooks/useTeamsStats.tsx b/src/features/MatchPage/store/hooks/useTeamsStats.tsx index 81694b3c..f5f6c589 100644 --- a/src/features/MatchPage/store/hooks/useTeamsStats.tsx +++ b/src/features/MatchPage/store/hooks/useTeamsStats.tsx @@ -4,14 +4,17 @@ import { useState, useMemo, } from 'react' +import { useQueryClient } from 'react-query' import throttle from 'lodash/throttle' import isUndefined from 'lodash/isUndefined' -import type { MatchInfo } from 'requests' +import { querieKeys } from 'config' + +import type { MatchInfo, MatchScore } from 'requests' import { getTeamsStats, TeamStatItem } from 'requests' -import { usePageParams } from 'hooks/usePageParams' +import { usePageParams } from 'hooks' import type { PlaylistOption } from 'features/MatchPage/types' import { StatsType } from 'features/MatchSidePlaylists/components/TabStats/config' @@ -42,16 +45,27 @@ export const useTeamsStats = ({ const { profileId: matchId, sportName } = usePageParams() + const client = useQueryClient() + + const matchScore = client.getQueryData(querieKeys.matchScore) + const isCurrentStats = statsType === StatsType.CURRENT_STATS const fetchTeamsStats = useMemo(() => throttle(async (second?: number) => { - if (!sportName || selectedPlaylist?.id !== FULL_GAME_KEY || !matchProfile?.video_bounds) return + const videoBounds = matchScore?.video_bounds || matchProfile?.video_bounds + + if ( + !sportName + || selectedPlaylist?.id !== FULL_GAME_KEY + || !videoBounds + || (matchProfile?.live && Number(matchProfile.c_match_calc_status) <= 1) + ) return try { const data = await getTeamsStats({ matchId, sportName, - ...(!isUndefined(second) && getHalfTime(matchProfile.video_bounds, second)), + ...(!isUndefined(second) && getHalfTime(videoBounds, second)), }) setTeamsStats(data) @@ -61,6 +75,9 @@ export const useTeamsStats = ({ } catch (e) {} }, REQUEST_DELAY), [ matchProfile?.video_bounds, + matchProfile?.c_match_calc_status, + matchProfile?.live, + matchScore?.video_bounds, selectedPlaylist?.id, matchId, setIsTeamsStatsFetching, diff --git a/src/features/MatchPage/store/hooks/useTournamentData.tsx b/src/features/MatchPage/store/hooks/useTournamentData.tsx index d3a55aa5..86840b8a 100644 --- a/src/features/MatchPage/store/hooks/useTournamentData.tsx +++ b/src/features/MatchPage/store/hooks/useTournamentData.tsx @@ -12,6 +12,7 @@ import sortBy from 'lodash/sortBy' import type { Match } from 'features/Matches' import { prepareMatches } from 'features/Matches/helpers/prepareMatches' +import type { MatchInfo } from 'requests' import { getTournamentMatches } from 'requests' import { parseDate } from 'helpers/parseDate' @@ -20,14 +21,18 @@ import { usePageParams } from 'hooks/usePageParams' import { TournamentData } from '../../types' -export const useTournamentData = (tournamentId: number | null) => { +export const useTournamentData = (matchProfile: MatchInfo) => { const { sportType } = usePageParams() const [tournamentMatches, setTournamentMatches] = useState>([]) const [matchDates, setMatchDates] = useState>([]) + const tournamentId = matchProfile?.tournament.id ?? null + useEffect(() => { if (!isNull(tournamentId)) { + if (matchProfile?.live && Number(matchProfile.c_match_calc_status) <= 1) return + (async () => { const matchesBySection = await getTournamentMatches({ limit: 1000, @@ -44,7 +49,12 @@ export const useTournamentData = (tournamentId: number | null) => { setTournamentMatches(sortBy(prepareMatches(matchesBySection.broadcast), ['date'])) })() } - }, [tournamentId, sportType]) + }, [ + tournamentId, + sportType, + matchProfile?.live, + matchProfile?.c_match_calc_status, + ]) const tournamentData: TournamentData = useMemo(() => ({ matchDates, diff --git a/src/features/MatchSidePlaylists/components/PlayersTable/hooks/useTable.tsx b/src/features/MatchSidePlaylists/components/PlayersTable/hooks/useTable.tsx index 5ad49b80..65c38b1f 100644 --- a/src/features/MatchSidePlaylists/components/PlayersTable/hooks/useTable.tsx +++ b/src/features/MatchSidePlaylists/components/PlayersTable/hooks/useTable.tsx @@ -11,6 +11,7 @@ import { useLayoutEffect, useMemo, } from 'react' +import { useQueryClient } from 'react-query' import size from 'lodash/size' import isNil from 'lodash/isNil' @@ -19,9 +20,13 @@ import forEach from 'lodash/forEach' import values from 'lodash/values' import map from 'lodash/map' -import { isMobileDevice } from 'config' +import { isMobileDevice, querieKeys } from 'config' -import type { PlayerParam, PlayersStats } from 'requests' +import type { + PlayerParam, + PlayersStats, + MatchScore, +} from 'requests' import { getStatsEvents } from 'requests' import { usePageParams, useToggle } from 'hooks' @@ -74,6 +79,10 @@ export const useTable = ({ } = useMatchPageStore() const { profileId, sportType } = usePageParams() + const client = useQueryClient() + + const matchScore = client.getQueryData(querieKeys.matchScore) + const params = useMemo(() => ( reduce>( playersStats[teamId], @@ -181,6 +190,8 @@ export const useTable = ({ setWatchAllEpisodesTimer(false) setIsPlayingFiltersEpisodes(false) + const videoBounds = matchScore?.video_bounds || profile?.video_bounds + setPlayingData({ player: { id: playerId, @@ -199,8 +210,8 @@ export const useTable = ({ playerId, sportType, teamId, - ...(statsType === StatsType.CURRENT_STATS && profile?.video_bounds && ( - getHalfTime(profile.video_bounds, playingProgress) + ...(statsType === StatsType.CURRENT_STATS && videoBounds && ( + getHalfTime(videoBounds, playingProgress) )), }) diff --git a/src/features/MatchSidePlaylists/components/TeamsStatsTable/Cell.tsx b/src/features/MatchSidePlaylists/components/TeamsStatsTable/Cell.tsx index a8ff7b9d..4f0a183d 100644 --- a/src/features/MatchSidePlaylists/components/TeamsStatsTable/Cell.tsx +++ b/src/features/MatchSidePlaylists/components/TeamsStatsTable/Cell.tsx @@ -1,10 +1,15 @@ import { Fragment, useRef } from 'react' +import { useQueryClient } from 'react-query' import isNumber from 'lodash/isNumber' -import { KEYBOARD_KEYS } from 'config' +import { KEYBOARD_KEYS, querieKeys } from 'config' -import type { Param, TeamStatItem } from 'requests' +import type { + Param, + TeamStatItem, + MatchScore, +} from 'requests' import { getStatsEvents } from 'requests' import { usePageParams, useEventListener } from 'hooks' @@ -47,6 +52,10 @@ export const Cell = ({ watchAllEpisodesTimer, } = useMatchPageStore() + const client = useQueryClient() + + const matchScore = client.getQueryData(querieKeys.matchScore) + const isClickable = (param: Param) => ( Boolean(param.val) && param.clickable ) @@ -58,6 +67,8 @@ export const Cell = ({ const onParamClick = async (param: Param) => { if (!isClickable(param)) return + const videoBounds = matchScore?.video_bounds || profile?.video_bounds + setWatchAllEpisodesTimer(false) setIsPlayingFiltersEpisodes(false) @@ -78,8 +89,8 @@ export const Cell = ({ paramId: param.id, sportType, teamId, - ...(statsType === StatsType.CURRENT_STATS && profile?.video_bounds && ( - getHalfTime(profile.video_bounds, playingProgress) + ...(statsType === StatsType.CURRENT_STATS && videoBounds && ( + getHalfTime(videoBounds, playingProgress) )), }) diff --git a/src/features/MatchSidePlaylists/hooks.tsx b/src/features/MatchSidePlaylists/hooks.tsx index 74329c73..ee556c44 100644 --- a/src/features/MatchSidePlaylists/hooks.tsx +++ b/src/features/MatchSidePlaylists/hooks.tsx @@ -19,7 +19,7 @@ export const useMatchSidePlaylists = () => { teamsStats, } = useMatchPageStore() - const isWatchTabVisible = true + const isWatchTabVisible = !matchProfile?.live || Number(matchProfile.c_match_calc_status) > 1 const isEventTabVisible = useMemo(() => ( events.length > 0 diff --git a/src/requests/getMatchInfo.tsx b/src/requests/getMatchInfo.tsx index 2c0a34d7..8ce9b456 100644 --- a/src/requests/getMatchInfo.tsx +++ b/src/requests/getMatchInfo.tsx @@ -35,8 +35,17 @@ export type VideoBound = { export type VideoBounds = Array +export enum MatchStatuses { + Upcoming = 1, + Active, + Timeout, + Finished, + Parsed, +} + export type MatchInfo = { access?: boolean, + c_match_calc_status: MatchStatuses | null, calc: boolean, country: TournamentType, country_id: number, diff --git a/src/requests/getMatchScore.tsx b/src/requests/getMatchScore.tsx index d46a5dff..523e965a 100644 --- a/src/requests/getMatchScore.tsx +++ b/src/requests/getMatchScore.tsx @@ -2,14 +2,18 @@ import { callApi } from 'helpers' import { API_ROOT } from 'config' -import type { Team, MatchTournament } from 'requests/getMatchInfo' +import type { + Team, + MatchTournament, + VideoBounds, +} from 'requests/getMatchInfo' type Params = { profileId: number, sportType: number, } -type Response = { +export type MatchScore = { match_date: string, match_date_utc: string, match_id: number, @@ -17,9 +21,10 @@ type Response = { team1: Team, team2: Team, tournament: MatchTournament, + video_bounds: VideoBounds | null, } -export const getMatchScore = ({ profileId, sportType }: Params): Promise => { +export const getMatchScore = ({ profileId, sportType }: Params): Promise => { const url = `${API_ROOT}/v1/matches/${sportType}/${profileId}/scores` const config = {