fansunited-data-layer 0.13.0 → 0.14.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/api/fansunited/constants.js +5 -0
- package/api/fansunited/constants.js.map +1 -0
- package/api/fansunited/football/competition/index.js +21 -0
- package/api/fansunited/football/competition/index.js.map +1 -0
- package/api/fansunited/football/competition/transformer.js +41 -0
- package/api/fansunited/football/competition/transformer.js.map +1 -0
- package/api/fansunited/football/competitions/index.js +56 -0
- package/api/fansunited/football/competitions/index.js.map +1 -0
- package/api/fansunited/football/competitions/transformer.js +68 -0
- package/api/fansunited/football/competitions/transformer.js.map +1 -0
- package/api/fansunited/football/http.js +7 -0
- package/api/fansunited/football/http.js.map +1 -0
- package/api/fansunited/football/matches/index.js +132 -0
- package/api/fansunited/football/matches/index.js.map +1 -0
- package/api/fansunited/football/matches/transformer.js +148 -0
- package/api/fansunited/football/matches/transformer.js.map +1 -0
- package/api/fansunited/football/players/index.js +60 -0
- package/api/fansunited/football/players/index.js.map +1 -0
- package/api/fansunited/football/players/transformer.js +85 -0
- package/api/fansunited/football/players/transformer.js.map +1 -0
- package/api/fansunited/football/search/index.js +64 -0
- package/api/fansunited/football/search/index.js.map +1 -0
- package/api/fansunited/football/search/transformer.js +114 -0
- package/api/fansunited/football/search/transformer.js.map +1 -0
- package/api/fansunited/football/teams/index.js +66 -0
- package/api/fansunited/football/teams/index.js.map +1 -0
- package/api/fansunited/football/teams/transformer.js +53 -0
- package/api/fansunited/football/teams/transformer.js.map +1 -0
- package/api/fansunited/http.d.ts.map +1 -1
- package/api/fansunited/http.js +70 -0
- package/api/fansunited/http.js.map +1 -0
- package/api/fansunited/search/constants.js +5 -0
- package/api/fansunited/search/constants.js.map +1 -0
- package/api/fansunited/search/http.js +7 -0
- package/api/fansunited/search/http.js.map +1 -0
- package/api/fansunited/search/index.js +308 -0
- package/api/fansunited/search/index.js.map +1 -0
- package/api/fansunited/search/transformer.js +374 -0
- package/api/fansunited/search/transformer.js.map +1 -0
- package/api/fansunited-sdk/loyalty/matches.js +21 -0
- package/api/fansunited-sdk/loyalty/matches.js.map +1 -0
- package/api/fansunited-sdk/loyalty/template.js +52 -0
- package/api/fansunited-sdk/loyalty/template.js.map +1 -0
- package/api/fansunited-sdk/odds/matches.js +109 -0
- package/api/fansunited-sdk/odds/matches.js.map +1 -0
- package/api/sportal365-sports/basketball/games/index.js +32 -0
- package/api/sportal365-sports/basketball/games/index.js.map +1 -0
- package/api/sportal365-sports/basketball/games/transformers/game.js +137 -0
- package/api/sportal365-sports/basketball/games/transformers/game.js.map +1 -0
- package/api/sportal365-sports/basketball/http.js +7 -0
- package/api/sportal365-sports/basketball/http.js.map +1 -0
- package/api/sportal365-sports/constants.js +15 -0
- package/api/sportal365-sports/constants.js.map +1 -0
- package/api/sportal365-sports/football/competitions/index.js +52 -0
- package/api/sportal365-sports/football/competitions/index.js.map +1 -0
- package/api/sportal365-sports/football/competitions/utils.js +92 -0
- package/api/sportal365-sports/football/competitions/utils.js.map +1 -0
- package/api/sportal365-sports/football/http.js +7 -0
- package/api/sportal365-sports/football/http.js.map +1 -0
- package/api/sportal365-sports/football/matches/index.js +206 -0
- package/api/sportal365-sports/football/matches/index.js.map +1 -0
- package/api/sportal365-sports/football/matches/transformers/commentary.js +27 -0
- package/api/sportal365-sports/football/matches/transformers/commentary.js.map +1 -0
- package/api/sportal365-sports/football/matches/transformers/lineup.js +74 -0
- package/api/sportal365-sports/football/matches/transformers/lineup.js.map +1 -0
- package/api/sportal365-sports/football/matches/transformers/match-event.js +60 -0
- package/api/sportal365-sports/football/matches/transformers/match-event.js.map +1 -0
- package/api/sportal365-sports/football/matches/transformers/match.js +195 -0
- package/api/sportal365-sports/football/matches/transformers/match.js.map +1 -0
- package/api/sportal365-sports/football/matches/transformers/odds.js +11 -0
- package/api/sportal365-sports/football/matches/transformers/odds.js.map +1 -0
- package/api/sportal365-sports/football/matches/transformers/statistics.js +41 -0
- package/api/sportal365-sports/football/matches/transformers/statistics.js.map +1 -0
- package/api/sportal365-sports/football/search/index.js +42 -0
- package/api/sportal365-sports/football/search/index.js.map +1 -0
- package/api/sportal365-sports/football/search/search.transformer.js +166 -0
- package/api/sportal365-sports/football/search/search.transformer.js.map +1 -0
- package/api/sportal365-sports/football/standings/index.js +28 -0
- package/api/sportal365-sports/football/standings/index.js.map +1 -0
- package/api/sportal365-sports/football/standings/standing.transformer.js +107 -0
- package/api/sportal365-sports/football/standings/standing.transformer.js.map +1 -0
- package/api/sportal365-sports/football/statistics/index.js +154 -0
- package/api/sportal365-sports/football/statistics/index.js.map +1 -0
- package/api/sportal365-sports/football/statistics/player-career.transformer.js +77 -0
- package/api/sportal365-sports/football/statistics/player-career.transformer.js.map +1 -0
- package/api/sportal365-sports/football/statistics/player-recent.transformer.js +54 -0
- package/api/sportal365-sports/football/statistics/player-recent.transformer.js.map +1 -0
- package/api/sportal365-sports/football/statistics/player-season.transformer.js +147 -0
- package/api/sportal365-sports/football/statistics/player-season.transformer.js.map +1 -0
- package/api/sportal365-sports/football/teams/index.js +73 -0
- package/api/sportal365-sports/football/teams/index.js.map +1 -0
- package/api/sportal365-sports/football/teams/utils.js +196 -0
- package/api/sportal365-sports/football/teams/utils.js.map +1 -0
- package/api/sportal365-sports/http.js +58 -0
- package/api/sportal365-sports/http.js.map +1 -0
- package/api/sportal365-sports/search/http.js +7 -0
- package/api/sportal365-sports/search/http.js.map +1 -0
- package/api/sportal365-sports/search/index.js +61 -0
- package/api/sportal365-sports/search/index.js.map +1 -0
- package/api/sportal365-sports/search/search.transformer.js +254 -0
- package/api/sportal365-sports/search/search.transformer.js.map +1 -0
- package/api/sportal365-sports/shared/odds.transformer.js +65 -0
- package/api/sportal365-sports/shared/odds.transformer.js.map +1 -0
- package/api/sportal365-sports/shared/providerRef.helper.js +31 -0
- package/api/sportal365-sports/shared/providerRef.helper.js.map +1 -0
- package/api/sportal365-sports/standings/http.js +7 -0
- package/api/sportal365-sports/standings/http.js.map +1 -0
- package/api/sportal365-sports/standings/index.js +29 -0
- package/api/sportal365-sports/standings/index.js.map +1 -0
- package/api/sportal365-sports/standings/standing.transformer.js +185 -0
- package/api/sportal365-sports/standings/standing.transformer.js.map +1 -0
- package/api/sportal365-sports/statistics/http.js +7 -0
- package/api/sportal365-sports/statistics/http.js.map +1 -0
- package/api/sportal365-sports/statistics/index.js +25 -0
- package/api/sportal365-sports/statistics/index.js.map +1 -0
- package/api/sportal365-sports/statistics/team-stats.transformer.js +16 -0
- package/api/sportal365-sports/statistics/team-stats.transformer.js.map +1 -0
- package/api/sportal365-sports/tennis/http.js +7 -0
- package/api/sportal365-sports/tennis/http.js.map +1 -0
- package/api/sportal365-sports/tennis/matches/index.js +34 -0
- package/api/sportal365-sports/tennis/matches/index.js.map +1 -0
- package/api/sportal365-sports/tennis/matches/transformers/match.js +193 -0
- package/api/sportal365-sports/tennis/matches/transformers/match.js.map +1 -0
- package/cache/cache-manager.js +136 -0
- package/cache/cache-manager.js.map +1 -0
- package/cache/memory-store.js +29 -0
- package/cache/memory-store.js.map +1 -0
- package/client.js +38 -12337
- package/client.js.map +1 -0
- package/config/index.js +20 -0
- package/config/index.js.map +1 -0
- package/fansunited-data-layer.js +146 -3553
- package/fansunited-data-layer.js.map +1 -0
- package/helpers/competition.helpers.js +11 -0
- package/helpers/competition.helpers.js.map +1 -0
- package/helpers/player.helpers.js +165 -0
- package/helpers/player.helpers.js.map +1 -0
- package/helpers/player.hooks.js +34 -0
- package/helpers/player.hooks.js.map +1 -0
- package/helpers/team.helpers.js +216 -0
- package/helpers/team.helpers.js.map +1 -0
- package/package.json +6 -8
- package/providers/competition/hooks/useCompetitionStats.js +10 -0
- package/providers/competition/hooks/useCompetitionStats.js.map +1 -0
- package/providers/competition/hooks/useGoalDistribution.js +23 -0
- package/providers/competition/hooks/useGoalDistribution.js.map +1 -0
- package/providers/competition/hooks/useMatchHelpers.js +85 -0
- package/providers/competition/hooks/useMatchHelpers.js.map +1 -0
- package/providers/competition/hooks/useStandingsCalculations.js +89 -0
- package/providers/competition/hooks/useStandingsCalculations.js.map +1 -0
- package/providers/competition/hooks/useStandingsHelpers.js +61 -0
- package/providers/competition/hooks/useStandingsHelpers.js.map +1 -0
- package/providers/competition/hooks/useTeamPosition.js +15 -0
- package/providers/competition/hooks/useTeamPosition.js.map +1 -0
- package/providers/competition/hooks/useTeamResultsTable.js +86 -0
- package/providers/competition/hooks/useTeamResultsTable.js.map +1 -0
- package/providers/competition/utils/competitionStats.js +109 -0
- package/providers/competition/utils/competitionStats.js.map +1 -0
- package/providers/competition/utils/goalDistribution.js +64 -0
- package/providers/competition/utils/goalDistribution.js.map +1 -0
- package/providers/competition/utils/standingsCalculations.js +152 -0
- package/providers/competition/utils/standingsCalculations.js.map +1 -0
- package/providers/competition.context.js +14 -0
- package/providers/competition.context.js.map +1 -0
- package/providers/competition.provider.js +187 -0
- package/providers/competition.provider.js.map +1 -0
- package/providers/fansunited-config.context.js +6 -0
- package/providers/fansunited-config.context.js.map +1 -0
- package/providers/fansunited-config.hooks.js +20 -0
- package/providers/fansunited-config.hooks.js.map +1 -0
- package/providers/fansunited-config.provider.js +9 -0
- package/providers/fansunited-config.provider.js.map +1 -0
- package/providers/fansunited-sdk.hook.js +50 -0
- package/providers/fansunited-sdk.hook.js.map +1 -0
- package/providers/leaderboard/hooks/useMatchHelpers.js +30 -0
- package/providers/leaderboard/hooks/useMatchHelpers.js.map +1 -0
- package/providers/leaderboard/hooks/useTemplateHelpers.js +39 -0
- package/providers/leaderboard/hooks/useTemplateHelpers.js.map +1 -0
- package/providers/leaderboard.context.js +14 -0
- package/providers/leaderboard.context.js.map +1 -0
- package/providers/leaderboard.provider.js +98 -0
- package/providers/leaderboard.provider.js.map +1 -0
- package/providers/match/hooks/useBatchMatchOdds.js +72 -0
- package/providers/match/hooks/useBatchMatchOdds.js.map +1 -0
- package/providers/match/hooks/useEventHelpers.js +46 -0
- package/providers/match/hooks/useEventHelpers.js.map +1 -0
- package/providers/match/hooks/useHeadToHeadHelpers.js +52 -0
- package/providers/match/hooks/useHeadToHeadHelpers.js.map +1 -0
- package/providers/match/hooks/useLineupHelpers.js +53 -0
- package/providers/match/hooks/useLineupHelpers.js.map +1 -0
- package/providers/match/hooks/useMatchStandingsCalculations.js +332 -0
- package/providers/match/hooks/useMatchStandingsCalculations.js.map +1 -0
- package/providers/match/hooks/useMatchStatus.js +37 -0
- package/providers/match/hooks/useMatchStatus.js.map +1 -0
- package/providers/match/hooks/useOddsHelpers.js +54 -0
- package/providers/match/hooks/useOddsHelpers.js.map +1 -0
- package/providers/match/hooks/useScoreHelpers.js +34 -0
- package/providers/match/hooks/useScoreHelpers.js.map +1 -0
- package/providers/match/hooks/useStandingsHelpers.js +53 -0
- package/providers/match/hooks/useStandingsHelpers.js.map +1 -0
- package/providers/match/hooks/useStatisticsHelpers.js +40 -0
- package/providers/match/hooks/useStatisticsHelpers.js.map +1 -0
- package/providers/match/hooks/useTeamHelpers.js +38 -0
- package/providers/match/hooks/useTeamHelpers.js.map +1 -0
- package/providers/match/hooks/useTeamStatsHelpers.js +141 -0
- package/providers/match/hooks/useTeamStatsHelpers.js.map +1 -0
- package/providers/match.context.js +14 -0
- package/providers/match.context.js.map +1 -0
- package/providers/match.provider.js +176 -0
- package/providers/match.provider.js.map +1 -0
- package/providers/team/hooks/useFormStats.js +116 -0
- package/providers/team/hooks/useFormStats.js.map +1 -0
- package/providers/team/hooks/useMatchHelpers.js +46 -0
- package/providers/team/hooks/useMatchHelpers.js.map +1 -0
- package/providers/team/hooks/useSquadHelpers.js +67 -0
- package/providers/team/hooks/useSquadHelpers.js.map +1 -0
- package/providers/team.context.js +14 -0
- package/providers/team.context.js.map +1 -0
- package/providers/team.provider.js +98 -0
- package/providers/team.provider.js.map +1 -0
- package/utilities/stats/core/helpers.js +105 -0
- package/utilities/stats/core/helpers.js.map +1 -0
- package/utilities/stats/core/types.js +5 -0
- package/utilities/stats/core/types.js.map +1 -0
- package/utilities/stats/match/headToHead.js +83 -0
- package/utilities/stats/match/headToHead.js.map +1 -0
- package/utilities/stats/match/homeVsAway.js +140 -0
- package/utilities/stats/match/homeVsAway.js.map +1 -0
- package/utilities/stats/match/overUnder.js +91 -0
- package/utilities/stats/match/overUnder.js.map +1 -0
- package/utilities/stats/match/result.js +21 -0
- package/utilities/stats/match/result.js.map +1 -0
- package/utilities/stats/team/commonOpponents.js +77 -0
- package/utilities/stats/team/commonOpponents.js.map +1 -0
- package/utilities/stats/team/goalStats.js +50 -0
- package/utilities/stats/team/goalStats.js.map +1 -0
- package/utilities/stats/team/streaks.js +183 -0
- package/utilities/stats/team/streaks.js.map +1 -0
- package/client.cjs +0 -8
- package/fansunited-data-layer.cjs +0 -1
- package/matches-BvHU-bP0.js +0 -1795
- package/matches-Ci0Ci_Mw.cjs +0 -1
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { useCallback, useMemo } from "react";
|
|
2
|
+
function useTeamHelpers(match) {
|
|
3
|
+
const getHomeTeam = useCallback(() => {
|
|
4
|
+
return match?.competitorOne;
|
|
5
|
+
}, [match]);
|
|
6
|
+
const getAwayTeam = useCallback(() => {
|
|
7
|
+
return match?.competitorTwo;
|
|
8
|
+
}, [match]);
|
|
9
|
+
const getTeamScore = useCallback(
|
|
10
|
+
(teamId) => {
|
|
11
|
+
if (!match?.score) return void 0;
|
|
12
|
+
const isHome = match.competitorOne.id === teamId;
|
|
13
|
+
const scoreStr = isHome ? match.score.competitorOne : match.score.competitorTwo;
|
|
14
|
+
if (!scoreStr) return void 0;
|
|
15
|
+
return parseInt(scoreStr, 10);
|
|
16
|
+
},
|
|
17
|
+
[match]
|
|
18
|
+
);
|
|
19
|
+
const isHomeTeam = useCallback(
|
|
20
|
+
(teamId) => {
|
|
21
|
+
return match?.competitorOne.id === teamId;
|
|
22
|
+
},
|
|
23
|
+
[match]
|
|
24
|
+
);
|
|
25
|
+
return useMemo(
|
|
26
|
+
() => ({
|
|
27
|
+
getHomeTeam,
|
|
28
|
+
getAwayTeam,
|
|
29
|
+
getTeamScore,
|
|
30
|
+
isHomeTeam
|
|
31
|
+
}),
|
|
32
|
+
[getHomeTeam, getAwayTeam, getTeamScore, isHomeTeam]
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
export {
|
|
36
|
+
useTeamHelpers
|
|
37
|
+
};
|
|
38
|
+
//# sourceMappingURL=useTeamHelpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useTeamHelpers.js","sources":["../../../../src/lib/providers/match/hooks/useTeamHelpers.ts"],"sourcesContent":["import { useCallback, useMemo } from \"react\";\nimport type { FUSportsMatch, FUSportsCompetitor } from \"../../../types/canonical\";\n\n/**\n * Hook for team-related helper functions\n */\nexport function useTeamHelpers(match: FUSportsMatch | undefined) {\n const getHomeTeam = useCallback((): FUSportsCompetitor | undefined => {\n return match?.competitorOne;\n }, [match]);\n\n const getAwayTeam = useCallback((): FUSportsCompetitor | undefined => {\n return match?.competitorTwo;\n }, [match]);\n\n const getTeamScore = useCallback(\n (teamId: string): number | undefined => {\n if (!match?.score) return undefined;\n\n const isHome = match.competitorOne.id === teamId;\n const scoreStr = isHome ? match.score.competitorOne : match.score.competitorTwo;\n\n if (!scoreStr) return undefined;\n return parseInt(scoreStr, 10);\n },\n [match]\n );\n\n const isHomeTeam = useCallback(\n (teamId: string): boolean => {\n return match?.competitorOne.id === teamId;\n },\n [match]\n );\n\n return useMemo(\n () => ({\n getHomeTeam,\n getAwayTeam,\n getTeamScore,\n isHomeTeam,\n }),\n [getHomeTeam, getAwayTeam, getTeamScore, isHomeTeam]\n );\n}\n"],"names":[],"mappings":";AAMO,SAAS,eAAe,OAAkC;AAC7D,QAAM,cAAc,YAAY,MAAsC;AAClE,WAAO,OAAO;AAAA,EAClB,GAAG,CAAC,KAAK,CAAC;AAEV,QAAM,cAAc,YAAY,MAAsC;AAClE,WAAO,OAAO;AAAA,EAClB,GAAG,CAAC,KAAK,CAAC;AAEV,QAAM,eAAe;AAAA,IACjB,CAAC,WAAuC;AACpC,UAAI,CAAC,OAAO,MAAO,QAAO;AAE1B,YAAM,SAAS,MAAM,cAAc,OAAO;AAC1C,YAAM,WAAW,SAAS,MAAM,MAAM,gBAAgB,MAAM,MAAM;AAElE,UAAI,CAAC,SAAU,QAAO;AACtB,aAAO,SAAS,UAAU,EAAE;AAAA,IAChC;AAAA,IACA,CAAC,KAAK;AAAA,EAAA;AAGV,QAAM,aAAa;AAAA,IACf,CAAC,WAA4B;AACzB,aAAO,OAAO,cAAc,OAAO;AAAA,IACvC;AAAA,IACA,CAAC,KAAK;AAAA,EAAA;AAGV,SAAO;AAAA,IACH,OAAO;AAAA,MACH;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IAAA;AAAA,IAEJ,CAAC,aAAa,aAAa,cAAc,UAAU;AAAA,EAAA;AAE3D;"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { useMemo } from "react";
|
|
2
|
+
function calculateStats(teamId, matches) {
|
|
3
|
+
let points = 0;
|
|
4
|
+
let goalsFor = 0;
|
|
5
|
+
let goalsAgainst = 0;
|
|
6
|
+
let played = 0;
|
|
7
|
+
matches.forEach((match) => {
|
|
8
|
+
const isCompetitorOne = match.competitorOne.id === teamId;
|
|
9
|
+
const teamScore = parseInt(
|
|
10
|
+
isCompetitorOne ? match.score?.competitorOne ?? "0" : match.score?.competitorTwo ?? "0"
|
|
11
|
+
);
|
|
12
|
+
const opponentScore = parseInt(
|
|
13
|
+
isCompetitorOne ? match.score?.competitorTwo ?? "0" : match.score?.competitorOne ?? "0"
|
|
14
|
+
);
|
|
15
|
+
played++;
|
|
16
|
+
goalsFor += teamScore;
|
|
17
|
+
goalsAgainst += opponentScore;
|
|
18
|
+
if (teamScore > opponentScore) {
|
|
19
|
+
points += 3;
|
|
20
|
+
} else if (teamScore === opponentScore) {
|
|
21
|
+
points += 1;
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
return {
|
|
25
|
+
pointsPerGame: played > 0 ? points / played : 0,
|
|
26
|
+
goalsForPerGame: played > 0 ? goalsFor / played : 0,
|
|
27
|
+
goalsAgainstPerGame: played > 0 ? goalsAgainst / played : 0,
|
|
28
|
+
played
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
function calculatePercentDiff(current, overall) {
|
|
32
|
+
if (overall === 0) return 0;
|
|
33
|
+
const diff = (current - overall) / overall * 100;
|
|
34
|
+
return Math.round(diff * 10) / 10;
|
|
35
|
+
}
|
|
36
|
+
function useTeamStatsHelpers(match, contextMatches) {
|
|
37
|
+
const cache = useMemo(() => /* @__PURE__ */ new Map(), [contextMatches]);
|
|
38
|
+
return useMemo(() => {
|
|
39
|
+
const getTeamForm = (teamId, homeAway = "all", matchCount = 8) => {
|
|
40
|
+
if (!contextMatches || contextMatches.length === 0) {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
const cacheKey = `${teamId}-${homeAway}-${matchCount}`;
|
|
44
|
+
if (cache.has(cacheKey)) {
|
|
45
|
+
return cache.get(cacheKey);
|
|
46
|
+
}
|
|
47
|
+
let finishedMatches = contextMatches.filter((m) => m.status.type === "FINISHED").filter((m) => m.competitorOne.id === teamId || m.competitorTwo.id === teamId).sort((a, b) => b.timing.kickoffTime.getTime() - a.timing.kickoffTime.getTime());
|
|
48
|
+
if (homeAway === "home") {
|
|
49
|
+
finishedMatches = finishedMatches.filter((m) => m.competitorOne.id === teamId);
|
|
50
|
+
} else if (homeAway === "away") {
|
|
51
|
+
finishedMatches = finishedMatches.filter((m) => m.competitorTwo.id === teamId);
|
|
52
|
+
}
|
|
53
|
+
if (finishedMatches.length === 0) {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
const overall = calculateStats(teamId, finishedMatches);
|
|
57
|
+
const formMatches = finishedMatches.slice(0, matchCount);
|
|
58
|
+
const form = calculateStats(teamId, formMatches);
|
|
59
|
+
const homeMatches = finishedMatches.filter((m) => m.competitorOne.id === teamId);
|
|
60
|
+
const homeOverall = calculateStats(teamId, homeMatches);
|
|
61
|
+
const homeFormMatches = homeMatches.slice(0, matchCount);
|
|
62
|
+
const homeForm = calculateStats(teamId, homeFormMatches);
|
|
63
|
+
const awayMatches = finishedMatches.filter((m) => m.competitorTwo.id === teamId);
|
|
64
|
+
const awayOverall = calculateStats(teamId, awayMatches);
|
|
65
|
+
const awayFormMatches = awayMatches.slice(0, matchCount);
|
|
66
|
+
const awayForm = calculateStats(teamId, awayFormMatches);
|
|
67
|
+
const result = {
|
|
68
|
+
// Overall
|
|
69
|
+
pointsPerGame: overall.pointsPerGame,
|
|
70
|
+
goalsForPerGame: overall.goalsForPerGame,
|
|
71
|
+
goalsAgainstPerGame: overall.goalsAgainstPerGame,
|
|
72
|
+
// Form
|
|
73
|
+
pointsPerGameForm: form.pointsPerGame,
|
|
74
|
+
goalsForPerGameForm: form.goalsForPerGame,
|
|
75
|
+
goalsAgainstPerGameForm: form.goalsAgainstPerGame,
|
|
76
|
+
// Difference
|
|
77
|
+
pointsPerGameDiffPercent: calculatePercentDiff(form.pointsPerGame, overall.pointsPerGame),
|
|
78
|
+
goalsForPerGameDiffPercent: calculatePercentDiff(form.goalsForPerGame, overall.goalsForPerGame),
|
|
79
|
+
goalsAgainstPerGameDiffPercent: calculatePercentDiff(
|
|
80
|
+
form.goalsAgainstPerGame,
|
|
81
|
+
overall.goalsAgainstPerGame
|
|
82
|
+
),
|
|
83
|
+
// Home
|
|
84
|
+
home: {
|
|
85
|
+
pointsPerGame: homeOverall.pointsPerGame,
|
|
86
|
+
goalsForPerGame: homeOverall.goalsForPerGame,
|
|
87
|
+
goalsAgainstPerGame: homeOverall.goalsAgainstPerGame,
|
|
88
|
+
pointsPerGameForm: homeForm.pointsPerGame,
|
|
89
|
+
goalsForPerGameForm: homeForm.goalsForPerGame,
|
|
90
|
+
goalsAgainstPerGameForm: homeForm.goalsAgainstPerGame,
|
|
91
|
+
pointsPerGameDiffPercent: calculatePercentDiff(homeForm.pointsPerGame, homeOverall.pointsPerGame),
|
|
92
|
+
goalsForPerGameDiffPercent: calculatePercentDiff(
|
|
93
|
+
homeForm.goalsForPerGame,
|
|
94
|
+
homeOverall.goalsForPerGame
|
|
95
|
+
),
|
|
96
|
+
goalsAgainstPerGameDiffPercent: calculatePercentDiff(
|
|
97
|
+
homeForm.goalsAgainstPerGame,
|
|
98
|
+
homeOverall.goalsAgainstPerGame
|
|
99
|
+
)
|
|
100
|
+
},
|
|
101
|
+
// Away
|
|
102
|
+
away: {
|
|
103
|
+
pointsPerGame: awayOverall.pointsPerGame,
|
|
104
|
+
goalsForPerGame: awayOverall.goalsForPerGame,
|
|
105
|
+
goalsAgainstPerGame: awayOverall.goalsAgainstPerGame,
|
|
106
|
+
pointsPerGameForm: awayForm.pointsPerGame,
|
|
107
|
+
goalsForPerGameForm: awayForm.goalsForPerGame,
|
|
108
|
+
goalsAgainstPerGameForm: awayForm.goalsAgainstPerGame,
|
|
109
|
+
pointsPerGameDiffPercent: calculatePercentDiff(awayForm.pointsPerGame, awayOverall.pointsPerGame),
|
|
110
|
+
goalsForPerGameDiffPercent: calculatePercentDiff(
|
|
111
|
+
awayForm.goalsForPerGame,
|
|
112
|
+
awayOverall.goalsForPerGame
|
|
113
|
+
),
|
|
114
|
+
goalsAgainstPerGameDiffPercent: calculatePercentDiff(
|
|
115
|
+
awayForm.goalsAgainstPerGame,
|
|
116
|
+
awayOverall.goalsAgainstPerGame
|
|
117
|
+
)
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
cache.set(cacheKey, result);
|
|
121
|
+
return result;
|
|
122
|
+
};
|
|
123
|
+
const getHomeTeamForm = (homeAway = "all", matchCount = 8) => {
|
|
124
|
+
if (!match?.competitorOne?.id) return null;
|
|
125
|
+
return getTeamForm(match.competitorOne.id, homeAway, matchCount);
|
|
126
|
+
};
|
|
127
|
+
const getAwayTeamForm = (homeAway = "all", matchCount = 8) => {
|
|
128
|
+
if (!match?.competitorTwo?.id) return null;
|
|
129
|
+
return getTeamForm(match.competitorTwo.id, homeAway, matchCount);
|
|
130
|
+
};
|
|
131
|
+
return {
|
|
132
|
+
getTeamForm,
|
|
133
|
+
getHomeTeamForm,
|
|
134
|
+
getAwayTeamForm
|
|
135
|
+
};
|
|
136
|
+
}, [match, contextMatches, cache]);
|
|
137
|
+
}
|
|
138
|
+
export {
|
|
139
|
+
useTeamStatsHelpers
|
|
140
|
+
};
|
|
141
|
+
//# sourceMappingURL=useTeamStatsHelpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useTeamStatsHelpers.js","sources":["../../../../src/lib/providers/match/hooks/useTeamStatsHelpers.ts"],"sourcesContent":["import { useMemo } from \"react\";\nimport type { FUSportsMatch } from \"../../../types/canonical\";\nimport type { HomeAwayFilter } from \"../../match.types\";\nimport type { TeamFormStats } from \"../../team/hooks/useFormStats\";\n\n/**\n * Calculate stats for a set of matches\n */\nfunction calculateStats(teamId: string, matches: FUSportsMatch[]) {\n let points = 0;\n let goalsFor = 0;\n let goalsAgainst = 0;\n let played = 0;\n\n matches.forEach((match) => {\n const isCompetitorOne = match.competitorOne.id === teamId;\n const teamScore = parseInt(\n isCompetitorOne ? (match.score?.competitorOne ?? \"0\") : (match.score?.competitorTwo ?? \"0\")\n );\n const opponentScore = parseInt(\n isCompetitorOne ? (match.score?.competitorTwo ?? \"0\") : (match.score?.competitorOne ?? \"0\")\n );\n\n played++;\n goalsFor += teamScore;\n goalsAgainst += opponentScore;\n\n if (teamScore > opponentScore) {\n points += 3;\n } else if (teamScore === opponentScore) {\n points += 1;\n }\n });\n\n return {\n pointsPerGame: played > 0 ? points / played : 0,\n goalsForPerGame: played > 0 ? goalsFor / played : 0,\n goalsAgainstPerGame: played > 0 ? goalsAgainst / played : 0,\n played,\n };\n}\n\n/**\n * Calculate percentage difference between two values\n */\nfunction calculatePercentDiff(current: number, overall: number): number {\n if (overall === 0) return 0;\n const diff = ((current - overall) / overall) * 100;\n return Math.round(diff * 10) / 10; // Round to 1 decimal place\n}\n\n/**\n * Hook that provides team stats calculation helpers\n */\nexport function useTeamStatsHelpers(match?: FUSportsMatch, contextMatches?: FUSportsMatch[]) {\n // Cache for memoizing calculation results\n const cache = useMemo(() => new Map<string, TeamFormStats | null>(), [contextMatches]);\n\n return useMemo(() => {\n /**\n * Get team form statistics\n * @param teamId - Team ID to calculate stats for\n * @param homeAway - Filter by location: \"home\", \"away\", or \"all\" (default: \"all\")\n * @param matchCount - Number of recent matches to consider for form (default: 8)\n */\n const getTeamForm = (\n teamId: string,\n homeAway: HomeAwayFilter = \"all\",\n matchCount: number = 8\n ): TeamFormStats | null => {\n if (!contextMatches || contextMatches.length === 0) {\n return null;\n }\n\n // Create cache key from parameters\n const cacheKey = `${teamId}-${homeAway}-${matchCount}`;\n\n // Return cached result if available\n if (cache.has(cacheKey)) {\n return cache.get(cacheKey)!;\n }\n\n // Get finished matches for this team, sorted by date (most recent first)\n let finishedMatches = contextMatches\n .filter((m) => m.status.type === \"FINISHED\")\n .filter((m) => m.competitorOne.id === teamId || m.competitorTwo.id === teamId)\n .sort((a, b) => b.timing.kickoffTime.getTime() - a.timing.kickoffTime.getTime());\n\n // Filter by home/away if specified\n if (homeAway === \"home\") {\n finishedMatches = finishedMatches.filter((m) => m.competitorOne.id === teamId);\n } else if (homeAway === \"away\") {\n finishedMatches = finishedMatches.filter((m) => m.competitorTwo.id === teamId);\n }\n\n if (finishedMatches.length === 0) {\n return null;\n }\n\n // Calculate overall stats\n const overall = calculateStats(teamId, finishedMatches);\n\n // Calculate form stats (last N matches)\n const formMatches = finishedMatches.slice(0, matchCount);\n const form = calculateStats(teamId, formMatches);\n\n // Calculate home stats\n const homeMatches = finishedMatches.filter((m) => m.competitorOne.id === teamId);\n const homeOverall = calculateStats(teamId, homeMatches);\n const homeFormMatches = homeMatches.slice(0, matchCount);\n const homeForm = calculateStats(teamId, homeFormMatches);\n\n // Calculate away stats\n const awayMatches = finishedMatches.filter((m) => m.competitorTwo.id === teamId);\n const awayOverall = calculateStats(teamId, awayMatches);\n const awayFormMatches = awayMatches.slice(0, matchCount);\n const awayForm = calculateStats(teamId, awayFormMatches);\n\n const result: TeamFormStats = {\n // Overall\n pointsPerGame: overall.pointsPerGame,\n goalsForPerGame: overall.goalsForPerGame,\n goalsAgainstPerGame: overall.goalsAgainstPerGame,\n\n // Form\n pointsPerGameForm: form.pointsPerGame,\n goalsForPerGameForm: form.goalsForPerGame,\n goalsAgainstPerGameForm: form.goalsAgainstPerGame,\n\n // Difference\n pointsPerGameDiffPercent: calculatePercentDiff(form.pointsPerGame, overall.pointsPerGame),\n goalsForPerGameDiffPercent: calculatePercentDiff(form.goalsForPerGame, overall.goalsForPerGame),\n goalsAgainstPerGameDiffPercent: calculatePercentDiff(\n form.goalsAgainstPerGame,\n overall.goalsAgainstPerGame\n ),\n\n // Home\n home: {\n pointsPerGame: homeOverall.pointsPerGame,\n goalsForPerGame: homeOverall.goalsForPerGame,\n goalsAgainstPerGame: homeOverall.goalsAgainstPerGame,\n pointsPerGameForm: homeForm.pointsPerGame,\n goalsForPerGameForm: homeForm.goalsForPerGame,\n goalsAgainstPerGameForm: homeForm.goalsAgainstPerGame,\n pointsPerGameDiffPercent: calculatePercentDiff(homeForm.pointsPerGame, homeOverall.pointsPerGame),\n goalsForPerGameDiffPercent: calculatePercentDiff(\n homeForm.goalsForPerGame,\n homeOverall.goalsForPerGame\n ),\n goalsAgainstPerGameDiffPercent: calculatePercentDiff(\n homeForm.goalsAgainstPerGame,\n homeOverall.goalsAgainstPerGame\n ),\n },\n\n // Away\n away: {\n pointsPerGame: awayOverall.pointsPerGame,\n goalsForPerGame: awayOverall.goalsForPerGame,\n goalsAgainstPerGame: awayOverall.goalsAgainstPerGame,\n pointsPerGameForm: awayForm.pointsPerGame,\n goalsForPerGameForm: awayForm.goalsForPerGame,\n goalsAgainstPerGameForm: awayForm.goalsAgainstPerGame,\n pointsPerGameDiffPercent: calculatePercentDiff(awayForm.pointsPerGame, awayOverall.pointsPerGame),\n goalsForPerGameDiffPercent: calculatePercentDiff(\n awayForm.goalsForPerGame,\n awayOverall.goalsForPerGame\n ),\n goalsAgainstPerGameDiffPercent: calculatePercentDiff(\n awayForm.goalsAgainstPerGame,\n awayOverall.goalsAgainstPerGame\n ),\n },\n };\n\n // Cache the result\n cache.set(cacheKey, result);\n\n return result;\n };\n\n /**\n * Get home team form statistics\n * @param homeAway - Filter by location: \"home\", \"away\", or \"all\" (default: \"all\")\n * @param matchCount - Number of recent matches to consider for form (default: 8)\n */\n const getHomeTeamForm = (homeAway: HomeAwayFilter = \"all\", matchCount: number = 8) => {\n if (!match?.competitorOne?.id) return null;\n return getTeamForm(match.competitorOne.id, homeAway, matchCount);\n };\n\n /**\n * Get away team form statistics\n * @param homeAway - Filter by location: \"home\", \"away\", or \"all\" (default: 8)\n * @param matchCount - Number of recent matches to consider for form (default: 8)\n */\n const getAwayTeamForm = (homeAway: HomeAwayFilter = \"all\", matchCount: number = 8) => {\n if (!match?.competitorTwo?.id) return null;\n return getTeamForm(match.competitorTwo.id, homeAway, matchCount);\n };\n\n return {\n getTeamForm,\n getHomeTeamForm,\n getAwayTeamForm,\n };\n }, [match, contextMatches, cache]);\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { createContext, useContext } from "react";
|
|
2
|
+
const MatchContext = createContext(null);
|
|
3
|
+
function useMatch() {
|
|
4
|
+
const context = useContext(MatchContext);
|
|
5
|
+
if (!context) {
|
|
6
|
+
throw new Error("useMatch must be used within MatchProvider");
|
|
7
|
+
}
|
|
8
|
+
return context;
|
|
9
|
+
}
|
|
10
|
+
export {
|
|
11
|
+
MatchContext,
|
|
12
|
+
useMatch
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=match.context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"match.context.js","sources":["../../src/lib/providers/match.context.ts"],"sourcesContent":["\"use client\";\n\nimport { createContext, useContext } from \"react\";\nimport type { MatchContextValue } from \"./match.types\";\n\n// ============================================================================\n// Context\n// ============================================================================\n\nexport const MatchContext = createContext<MatchContextValue | null>(null);\n\n// ============================================================================\n// Hook\n// ============================================================================\n\n/**\n * Hook to access match context\n * Must be used within a MatchProvider\n */\nexport function useMatch(): MatchContextValue {\n const context = useContext(MatchContext);\n if (!context) {\n throw new Error(\"useMatch must be used within MatchProvider\");\n }\n return context;\n}\n\n"],"names":[],"mappings":";AASO,MAAM,eAAe,cAAwC,IAAI;AAUjE,SAAS,WAA8B;AAC1C,QAAM,UAAU,WAAW,YAAY;AACvC,MAAI,CAAC,SAAS;AACV,UAAM,IAAI,MAAM,4CAA4C;AAAA,EAChE;AACA,SAAO;AACX;"}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useEffect, useCallback, useMemo } from "react";
|
|
3
|
+
import { MatchContext } from "./match.context.js";
|
|
4
|
+
import { getFootballMatch, getFootballMatchEvents, getFootballMatchStatistics, getFootballMatchCommentary } from "../api/sportal365-sports/football/matches/index.js";
|
|
5
|
+
import { useMatchStatus } from "./match/hooks/useMatchStatus.js";
|
|
6
|
+
import { useScoreHelpers } from "./match/hooks/useScoreHelpers.js";
|
|
7
|
+
import { useTeamHelpers } from "./match/hooks/useTeamHelpers.js";
|
|
8
|
+
import { useEventHelpers } from "./match/hooks/useEventHelpers.js";
|
|
9
|
+
import { useLineupHelpers } from "./match/hooks/useLineupHelpers.js";
|
|
10
|
+
import { useStatisticsHelpers } from "./match/hooks/useStatisticsHelpers.js";
|
|
11
|
+
import { useOddsHelpers } from "./match/hooks/useOddsHelpers.js";
|
|
12
|
+
import { useHeadToHeadHelpers } from "./match/hooks/useHeadToHeadHelpers.js";
|
|
13
|
+
import { useTeamStatsHelpers } from "./match/hooks/useTeamStatsHelpers.js";
|
|
14
|
+
import { useStandingsHelpers } from "./match/hooks/useStandingsHelpers.js";
|
|
15
|
+
import { useMatchStandingsCalculations } from "./match/hooks/useMatchStandingsCalculations.js";
|
|
16
|
+
import { useDataLayerConfig } from "./fansunited-config.hooks.js";
|
|
17
|
+
function MatchProvider({
|
|
18
|
+
matchId,
|
|
19
|
+
match: initialMatch,
|
|
20
|
+
lineups: initialLineups,
|
|
21
|
+
statistics: initialStatistics,
|
|
22
|
+
odds: initialOdds,
|
|
23
|
+
commentary: initialCommentary,
|
|
24
|
+
events: initialEvents,
|
|
25
|
+
headToHeadMatches,
|
|
26
|
+
standings: initialStandings,
|
|
27
|
+
contextMatches,
|
|
28
|
+
config,
|
|
29
|
+
autoRefresh = true,
|
|
30
|
+
refreshInterval = 3e4,
|
|
31
|
+
children
|
|
32
|
+
}) {
|
|
33
|
+
const dataLayerConfig = useDataLayerConfig();
|
|
34
|
+
const [match, setMatch] = useState(initialMatch);
|
|
35
|
+
const [lineups] = useState(initialLineups);
|
|
36
|
+
const [statistics, setStatistics] = useState(initialStatistics);
|
|
37
|
+
const [odds] = useState(initialOdds);
|
|
38
|
+
const [commentary, setCommentary] = useState(initialCommentary);
|
|
39
|
+
const [events, setEvents] = useState(initialEvents);
|
|
40
|
+
const [standings] = useState(initialStandings);
|
|
41
|
+
const [isRefreshing, setIsRefreshing] = useState(false);
|
|
42
|
+
const [lastRefreshed, setLastRefreshed] = useState(void 0);
|
|
43
|
+
useEffect(() => {
|
|
44
|
+
if (match) return;
|
|
45
|
+
const fetchInitialData = async () => {
|
|
46
|
+
try {
|
|
47
|
+
const matchData = await getFootballMatch(
|
|
48
|
+
matchId,
|
|
49
|
+
{
|
|
50
|
+
optionalData: ["MAIN_EVENTS", "LINEUP_STATUS"]
|
|
51
|
+
},
|
|
52
|
+
dataLayerConfig
|
|
53
|
+
);
|
|
54
|
+
setMatch(matchData);
|
|
55
|
+
} catch (error) {
|
|
56
|
+
console.error("[MatchProvider] Error fetching initial data:", error);
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
fetchInitialData();
|
|
60
|
+
}, [dataLayerConfig]);
|
|
61
|
+
const refresh = useCallback(async () => {
|
|
62
|
+
setIsRefreshing(true);
|
|
63
|
+
try {
|
|
64
|
+
const [matchData, eventsData, statisticsData, commentaryData] = await Promise.all([
|
|
65
|
+
getFootballMatch(
|
|
66
|
+
matchId,
|
|
67
|
+
{
|
|
68
|
+
optionalData: ["MAIN_EVENTS", "LINEUP_STATUS"]
|
|
69
|
+
},
|
|
70
|
+
dataLayerConfig
|
|
71
|
+
),
|
|
72
|
+
getFootballMatchEvents(matchId, void 0, dataLayerConfig).catch(() => []),
|
|
73
|
+
getFootballMatchStatistics(matchId, void 0, dataLayerConfig).catch(() => void 0),
|
|
74
|
+
getFootballMatchCommentary(matchId, void 0, dataLayerConfig).catch(() => [])
|
|
75
|
+
]);
|
|
76
|
+
setMatch(matchData);
|
|
77
|
+
setEvents(eventsData);
|
|
78
|
+
setStatistics(statisticsData);
|
|
79
|
+
setCommentary(commentaryData);
|
|
80
|
+
setLastRefreshed(/* @__PURE__ */ new Date());
|
|
81
|
+
} catch (error) {
|
|
82
|
+
console.error("[MatchProvider] Error refreshing match data:", error);
|
|
83
|
+
} finally {
|
|
84
|
+
setIsRefreshing(false);
|
|
85
|
+
}
|
|
86
|
+
}, [matchId, dataLayerConfig]);
|
|
87
|
+
useEffect(() => {
|
|
88
|
+
if (!autoRefresh || !match) return;
|
|
89
|
+
const statusType = match.status?.type || "";
|
|
90
|
+
const statusCode = match.status?.code || "";
|
|
91
|
+
const isLive = statusType === "LIVE" || statusCode === "live";
|
|
92
|
+
if (!isLive) return;
|
|
93
|
+
const interval = setInterval(() => {
|
|
94
|
+
refresh();
|
|
95
|
+
}, refreshInterval);
|
|
96
|
+
return () => clearInterval(interval);
|
|
97
|
+
}, [autoRefresh, refreshInterval, match, refresh]);
|
|
98
|
+
const matchStatusHelpers = useMatchStatus(match);
|
|
99
|
+
const scoreHelpers = useScoreHelpers(match);
|
|
100
|
+
const teamHelpers = useTeamHelpers(match);
|
|
101
|
+
const eventHelpers = useEventHelpers(match, events);
|
|
102
|
+
const lineupHelpers = useLineupHelpers(match, lineups);
|
|
103
|
+
const statisticsHelpers = useStatisticsHelpers(match, statistics);
|
|
104
|
+
const oddsHelpers = useOddsHelpers(odds);
|
|
105
|
+
const headToHeadHelpers = useHeadToHeadHelpers(match, headToHeadMatches);
|
|
106
|
+
const teamStatsHelpers = useTeamStatsHelpers(match, contextMatches);
|
|
107
|
+
const standingsHelpers = useStandingsHelpers(standings);
|
|
108
|
+
const standingsCalculations = useMatchStandingsCalculations(standings, contextMatches);
|
|
109
|
+
const value = useMemo(() => {
|
|
110
|
+
return {
|
|
111
|
+
// Core identifier
|
|
112
|
+
matchId,
|
|
113
|
+
// Core data
|
|
114
|
+
match,
|
|
115
|
+
lineups,
|
|
116
|
+
statistics,
|
|
117
|
+
odds,
|
|
118
|
+
commentary,
|
|
119
|
+
events,
|
|
120
|
+
headToHeadMatches,
|
|
121
|
+
standings,
|
|
122
|
+
// Context matches
|
|
123
|
+
contextMatches,
|
|
124
|
+
// Loading and refresh state
|
|
125
|
+
isRefreshing,
|
|
126
|
+
lastRefreshed,
|
|
127
|
+
// Custom configuration
|
|
128
|
+
config,
|
|
129
|
+
// Refresh method
|
|
130
|
+
refresh,
|
|
131
|
+
// Helper methods
|
|
132
|
+
...matchStatusHelpers,
|
|
133
|
+
...scoreHelpers,
|
|
134
|
+
...teamHelpers,
|
|
135
|
+
...eventHelpers,
|
|
136
|
+
...lineupHelpers,
|
|
137
|
+
...statisticsHelpers,
|
|
138
|
+
...oddsHelpers,
|
|
139
|
+
...headToHeadHelpers,
|
|
140
|
+
...teamStatsHelpers,
|
|
141
|
+
...standingsHelpers,
|
|
142
|
+
...standingsCalculations
|
|
143
|
+
};
|
|
144
|
+
}, [
|
|
145
|
+
matchId,
|
|
146
|
+
match,
|
|
147
|
+
lineups,
|
|
148
|
+
statistics,
|
|
149
|
+
odds,
|
|
150
|
+
commentary,
|
|
151
|
+
events,
|
|
152
|
+
headToHeadMatches,
|
|
153
|
+
standings,
|
|
154
|
+
contextMatches,
|
|
155
|
+
isRefreshing,
|
|
156
|
+
lastRefreshed,
|
|
157
|
+
config,
|
|
158
|
+
refresh,
|
|
159
|
+
matchStatusHelpers,
|
|
160
|
+
scoreHelpers,
|
|
161
|
+
teamHelpers,
|
|
162
|
+
eventHelpers,
|
|
163
|
+
lineupHelpers,
|
|
164
|
+
statisticsHelpers,
|
|
165
|
+
oddsHelpers,
|
|
166
|
+
headToHeadHelpers,
|
|
167
|
+
teamStatsHelpers,
|
|
168
|
+
standingsHelpers,
|
|
169
|
+
standingsCalculations
|
|
170
|
+
]);
|
|
171
|
+
return /* @__PURE__ */ jsx(MatchContext.Provider, { value, children });
|
|
172
|
+
}
|
|
173
|
+
export {
|
|
174
|
+
MatchProvider
|
|
175
|
+
};
|
|
176
|
+
//# sourceMappingURL=match.provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"match.provider.js","sources":["../../src/lib/providers/match.provider.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState, useEffect, useMemo, useCallback } from \"react\";\nimport type {\n FUSportsMatch,\n FUSportsMatchLineups,\n FUSportsMatchStatistics,\n FUSportsMatchOdds,\n FUSportsCommentaryItem,\n FUSportsMatchEvent,\n FUSportsStandings,\n} from \"../types/canonical\";\nimport { MatchContext } from \"./match.context\";\nimport type { MatchContextValue, MatchProviderProps } from \"./match.types\";\nimport {\n getFootballMatch,\n getFootballMatchEvents,\n getFootballMatchStatistics,\n getFootballMatchCommentary,\n} from \"../api/sportal365-sports/football/matches\";\nimport { useMatchStatus } from \"./match/hooks/useMatchStatus\";\nimport { useScoreHelpers } from \"./match/hooks/useScoreHelpers\";\nimport { useTeamHelpers } from \"./match/hooks/useTeamHelpers\";\nimport { useEventHelpers } from \"./match/hooks/useEventHelpers\";\nimport { useLineupHelpers } from \"./match/hooks/useLineupHelpers\";\nimport { useStatisticsHelpers } from \"./match/hooks/useStatisticsHelpers\";\nimport { useOddsHelpers } from \"./match/hooks/useOddsHelpers\";\nimport { useHeadToHeadHelpers } from \"./match/hooks/useHeadToHeadHelpers\";\nimport { useTeamStatsHelpers } from \"./match/hooks/useTeamStatsHelpers\";\nimport { useStandingsHelpers } from \"./match/hooks/useStandingsHelpers\";\nimport { useMatchStandingsCalculations } from \"./match/hooks/useMatchStandingsCalculations\";\nimport { useDataLayerConfig } from \"./fansunited-config.hooks\";\n\n// ============================================================================\n// Provider Component\n// ============================================================================\n\nexport function MatchProvider({\n matchId,\n match: initialMatch,\n lineups: initialLineups,\n statistics: initialStatistics,\n odds: initialOdds,\n commentary: initialCommentary,\n events: initialEvents,\n headToHeadMatches,\n standings: initialStandings,\n contextMatches,\n config,\n autoRefresh = true,\n refreshInterval = 30000,\n children,\n}: MatchProviderProps) {\n // Get data layer config from context\n const dataLayerConfig = useDataLayerConfig();\n\n // Core data state\n const [match, setMatch] = useState<FUSportsMatch | undefined>(initialMatch);\n const [lineups] = useState<FUSportsMatchLineups | undefined>(initialLineups);\n const [statistics, setStatistics] = useState<FUSportsMatchStatistics | undefined>(initialStatistics);\n const [odds] = useState<FUSportsMatchOdds | undefined>(initialOdds);\n const [commentary, setCommentary] = useState<FUSportsCommentaryItem[] | undefined>(initialCommentary);\n const [events, setEvents] = useState<FUSportsMatchEvent[] | undefined>(initialEvents);\n const [standings] = useState<FUSportsStandings | undefined>(initialStandings);\n\n // Refresh state\n const [isRefreshing, setIsRefreshing] = useState(false);\n const [lastRefreshed, setLastRefreshed] = useState<Date | undefined>(undefined);\n\n // Initial fetch for match (only once if not provided)\n useEffect(() => {\n if (match) return;\n\n const fetchInitialData = async () => {\n try {\n const matchData = await getFootballMatch(\n matchId,\n {\n optionalData: [\"MAIN_EVENTS\", \"LINEUP_STATUS\"],\n },\n dataLayerConfig\n );\n\n setMatch(matchData);\n } catch (error) {\n console.error(\"[MatchProvider] Error fetching initial data:\", error);\n }\n };\n\n fetchInitialData();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [dataLayerConfig]);\n\n // Refresh function - only refreshes dynamic data (match, events, statistics, commentary)\n const refresh = useCallback(async () => {\n setIsRefreshing(true);\n try {\n const [matchData, eventsData, statisticsData, commentaryData] = await Promise.all([\n getFootballMatch(\n matchId,\n {\n optionalData: [\"MAIN_EVENTS\", \"LINEUP_STATUS\"],\n },\n dataLayerConfig\n ),\n getFootballMatchEvents(matchId, undefined, dataLayerConfig).catch(() => []),\n getFootballMatchStatistics(matchId, undefined, dataLayerConfig).catch(() => undefined),\n getFootballMatchCommentary(matchId, undefined, dataLayerConfig).catch(() => []),\n ]);\n\n setMatch(matchData);\n setEvents(eventsData);\n setStatistics(statisticsData);\n setCommentary(commentaryData);\n setLastRefreshed(new Date());\n } catch (error) {\n console.error(\"[MatchProvider] Error refreshing match data:\", error);\n } finally {\n setIsRefreshing(false);\n }\n }, [matchId, dataLayerConfig]);\n\n // Auto-refresh for live matches\n useEffect(() => {\n if (!autoRefresh || !match) return;\n\n const statusType = match.status?.type || \"\";\n const statusCode = match.status?.code || \"\";\n const isLive = statusType === \"LIVE\" || statusCode === \"live\";\n\n if (!isLive) return;\n\n const interval = setInterval(() => {\n refresh();\n }, refreshInterval);\n\n return () => clearInterval(interval);\n }, [autoRefresh, refreshInterval, match, refresh]);\n\n // Use custom hooks for helper functions\n const matchStatusHelpers = useMatchStatus(match);\n const scoreHelpers = useScoreHelpers(match);\n const teamHelpers = useTeamHelpers(match);\n const eventHelpers = useEventHelpers(match, events);\n const lineupHelpers = useLineupHelpers(match, lineups);\n const statisticsHelpers = useStatisticsHelpers(match, statistics);\n const oddsHelpers = useOddsHelpers(odds);\n const headToHeadHelpers = useHeadToHeadHelpers(match, headToHeadMatches);\n const teamStatsHelpers = useTeamStatsHelpers(match, contextMatches);\n const standingsHelpers = useStandingsHelpers(standings);\n const standingsCalculations = useMatchStandingsCalculations(standings, contextMatches);\n\n // Memoize context value\n const value = useMemo<MatchContextValue>(() => {\n return {\n // Core identifier\n matchId,\n\n // Core data\n match,\n lineups,\n statistics,\n odds,\n commentary,\n events,\n headToHeadMatches,\n standings,\n\n // Context matches\n contextMatches,\n\n // Loading and refresh state\n isRefreshing,\n lastRefreshed,\n\n // Custom configuration\n config,\n\n // Refresh method\n refresh,\n\n // Helper methods\n ...matchStatusHelpers,\n ...scoreHelpers,\n ...teamHelpers,\n ...eventHelpers,\n ...lineupHelpers,\n ...statisticsHelpers,\n ...oddsHelpers,\n ...headToHeadHelpers,\n ...teamStatsHelpers,\n ...standingsHelpers,\n ...standingsCalculations,\n };\n }, [\n matchId,\n match,\n lineups,\n statistics,\n odds,\n commentary,\n events,\n headToHeadMatches,\n standings,\n contextMatches,\n isRefreshing,\n lastRefreshed,\n config,\n refresh,\n matchStatusHelpers,\n scoreHelpers,\n teamHelpers,\n eventHelpers,\n lineupHelpers,\n statisticsHelpers,\n oddsHelpers,\n headToHeadHelpers,\n teamStatsHelpers,\n standingsHelpers,\n standingsCalculations,\n ]);\n\n return <MatchContext.Provider value={value}>{children}</MatchContext.Provider>;\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAqCO,SAAS,cAAc;AAAA,EAC1B;AAAA,EACA,OAAO;AAAA,EACP,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,MAAM;AAAA,EACN,YAAY;AAAA,EACZ,QAAQ;AAAA,EACR;AAAA,EACA,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA,cAAc;AAAA,EACd,kBAAkB;AAAA,EAClB;AACJ,GAAuB;AAEnB,QAAM,kBAAkB,mBAAA;AAGxB,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAoC,YAAY;AAC1E,QAAM,CAAC,OAAO,IAAI,SAA2C,cAAc;AAC3E,QAAM,CAAC,YAAY,aAAa,IAAI,SAA8C,iBAAiB;AACnG,QAAM,CAAC,IAAI,IAAI,SAAwC,WAAW;AAClE,QAAM,CAAC,YAAY,aAAa,IAAI,SAA+C,iBAAiB;AACpG,QAAM,CAAC,QAAQ,SAAS,IAAI,SAA2C,aAAa;AACpF,QAAM,CAAC,SAAS,IAAI,SAAwC,gBAAgB;AAG5E,QAAM,CAAC,cAAc,eAAe,IAAI,SAAS,KAAK;AACtD,QAAM,CAAC,eAAe,gBAAgB,IAAI,SAA2B,MAAS;AAG9E,YAAU,MAAM;AACZ,QAAI,MAAO;AAEX,UAAM,mBAAmB,YAAY;AACjC,UAAI;AACA,cAAM,YAAY,MAAM;AAAA,UACpB;AAAA,UACA;AAAA,YACI,cAAc,CAAC,eAAe,eAAe;AAAA,UAAA;AAAA,UAEjD;AAAA,QAAA;AAGJ,iBAAS,SAAS;AAAA,MACtB,SAAS,OAAO;AACZ,gBAAQ,MAAM,gDAAgD,KAAK;AAAA,MACvE;AAAA,IACJ;AAEA,qBAAA;AAAA,EAEJ,GAAG,CAAC,eAAe,CAAC;AAGpB,QAAM,UAAU,YAAY,YAAY;AACpC,oBAAgB,IAAI;AACpB,QAAI;AACA,YAAM,CAAC,WAAW,YAAY,gBAAgB,cAAc,IAAI,MAAM,QAAQ,IAAI;AAAA,QAC9E;AAAA,UACI;AAAA,UACA;AAAA,YACI,cAAc,CAAC,eAAe,eAAe;AAAA,UAAA;AAAA,UAEjD;AAAA,QAAA;AAAA,QAEJ,uBAAuB,SAAS,QAAW,eAAe,EAAE,MAAM,MAAM,EAAE;AAAA,QAC1E,2BAA2B,SAAS,QAAW,eAAe,EAAE,MAAM,MAAM,MAAS;AAAA,QACrF,2BAA2B,SAAS,QAAW,eAAe,EAAE,MAAM,MAAM,CAAA,CAAE;AAAA,MAAA,CACjF;AAED,eAAS,SAAS;AAClB,gBAAU,UAAU;AACpB,oBAAc,cAAc;AAC5B,oBAAc,cAAc;AAC5B,uBAAiB,oBAAI,MAAM;AAAA,IAC/B,SAAS,OAAO;AACZ,cAAQ,MAAM,gDAAgD,KAAK;AAAA,IACvE,UAAA;AACI,sBAAgB,KAAK;AAAA,IACzB;AAAA,EACJ,GAAG,CAAC,SAAS,eAAe,CAAC;AAG7B,YAAU,MAAM;AACZ,QAAI,CAAC,eAAe,CAAC,MAAO;AAE5B,UAAM,aAAa,MAAM,QAAQ,QAAQ;AACzC,UAAM,aAAa,MAAM,QAAQ,QAAQ;AACzC,UAAM,SAAS,eAAe,UAAU,eAAe;AAEvD,QAAI,CAAC,OAAQ;AAEb,UAAM,WAAW,YAAY,MAAM;AAC/B,cAAA;AAAA,IACJ,GAAG,eAAe;AAElB,WAAO,MAAM,cAAc,QAAQ;AAAA,EACvC,GAAG,CAAC,aAAa,iBAAiB,OAAO,OAAO,CAAC;AAGjD,QAAM,qBAAqB,eAAe,KAAK;AAC/C,QAAM,eAAe,gBAAgB,KAAK;AAC1C,QAAM,cAAc,eAAe,KAAK;AACxC,QAAM,eAAe,gBAAgB,OAAO,MAAM;AAClD,QAAM,gBAAgB,iBAAiB,OAAO,OAAO;AACrD,QAAM,oBAAoB,qBAAqB,OAAO,UAAU;AAChE,QAAM,cAAc,eAAe,IAAI;AACvC,QAAM,oBAAoB,qBAAqB,OAAO,iBAAiB;AACvE,QAAM,mBAAmB,oBAAoB,OAAO,cAAc;AAClE,QAAM,mBAAmB,oBAAoB,SAAS;AACtD,QAAM,wBAAwB,8BAA8B,WAAW,cAAc;AAGrF,QAAM,QAAQ,QAA2B,MAAM;AAC3C,WAAO;AAAA;AAAA,MAEH;AAAA;AAAA,MAGA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAGA;AAAA;AAAA,MAGA;AAAA,MACA;AAAA;AAAA,MAGA;AAAA;AAAA,MAGA;AAAA;AAAA,MAGA,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,IAAA;AAAA,EAEX,GAAG;AAAA,IACC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA,CACH;AAED,SAAO,oBAAC,aAAa,UAAb,EAAsB,OAAe,SAAA,CAAS;AAC1D;"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { useCallback, useMemo } from "react";
|
|
2
|
+
function calculateStats(teamId, matches) {
|
|
3
|
+
let points = 0;
|
|
4
|
+
let goalsFor = 0;
|
|
5
|
+
let goalsAgainst = 0;
|
|
6
|
+
let played = 0;
|
|
7
|
+
matches.forEach((match) => {
|
|
8
|
+
const isCompetitorOne = match.competitorOne.id === teamId;
|
|
9
|
+
const teamScore = parseInt(
|
|
10
|
+
isCompetitorOne ? match.score?.competitorOne ?? "0" : match.score?.competitorTwo ?? "0"
|
|
11
|
+
);
|
|
12
|
+
const opponentScore = parseInt(
|
|
13
|
+
isCompetitorOne ? match.score?.competitorTwo ?? "0" : match.score?.competitorOne ?? "0"
|
|
14
|
+
);
|
|
15
|
+
played++;
|
|
16
|
+
goalsFor += teamScore;
|
|
17
|
+
goalsAgainst += opponentScore;
|
|
18
|
+
if (teamScore > opponentScore) {
|
|
19
|
+
points += 3;
|
|
20
|
+
} else if (teamScore === opponentScore) {
|
|
21
|
+
points += 1;
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
return {
|
|
25
|
+
pointsPerGame: played > 0 ? points / played : 0,
|
|
26
|
+
goalsForPerGame: played > 0 ? goalsFor / played : 0,
|
|
27
|
+
goalsAgainstPerGame: played > 0 ? goalsAgainst / played : 0,
|
|
28
|
+
played
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
function calculatePercentDiff(current, overall) {
|
|
32
|
+
if (overall === 0) return 0;
|
|
33
|
+
const diff = (current - overall) / overall * 100;
|
|
34
|
+
return Math.round(diff * 10) / 10;
|
|
35
|
+
}
|
|
36
|
+
function useFormStatsHelper(teamId, matches) {
|
|
37
|
+
const getFormStats = useCallback(
|
|
38
|
+
(formMatchCount = 8) => {
|
|
39
|
+
if (!teamId) return null;
|
|
40
|
+
const finishedMatches = matches.filter((m) => m.status.type === "FINISHED").filter((m) => m.competitorOne.id === teamId || m.competitorTwo.id === teamId).sort((a, b) => b.timing.kickoffTime.getTime() - a.timing.kickoffTime.getTime());
|
|
41
|
+
if (finishedMatches.length === 0) {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
const overall = calculateStats(teamId, finishedMatches);
|
|
45
|
+
const formMatches = finishedMatches.slice(0, formMatchCount);
|
|
46
|
+
const form = calculateStats(teamId, formMatches);
|
|
47
|
+
const homeMatches = finishedMatches.filter((m) => m.competitorOne.id === teamId);
|
|
48
|
+
const homeOverall = calculateStats(teamId, homeMatches);
|
|
49
|
+
const homeFormMatches = homeMatches.slice(0, formMatchCount);
|
|
50
|
+
const homeForm = calculateStats(teamId, homeFormMatches);
|
|
51
|
+
const awayMatches = finishedMatches.filter((m) => m.competitorTwo.id === teamId);
|
|
52
|
+
const awayOverall = calculateStats(teamId, awayMatches);
|
|
53
|
+
const awayFormMatches = awayMatches.slice(0, formMatchCount);
|
|
54
|
+
const awayForm = calculateStats(teamId, awayFormMatches);
|
|
55
|
+
return {
|
|
56
|
+
// Overall
|
|
57
|
+
pointsPerGame: overall.pointsPerGame,
|
|
58
|
+
goalsForPerGame: overall.goalsForPerGame,
|
|
59
|
+
goalsAgainstPerGame: overall.goalsAgainstPerGame,
|
|
60
|
+
// Form
|
|
61
|
+
pointsPerGameForm: form.pointsPerGame,
|
|
62
|
+
goalsForPerGameForm: form.goalsForPerGame,
|
|
63
|
+
goalsAgainstPerGameForm: form.goalsAgainstPerGame,
|
|
64
|
+
// Difference
|
|
65
|
+
pointsPerGameDiffPercent: calculatePercentDiff(form.pointsPerGame, overall.pointsPerGame),
|
|
66
|
+
goalsForPerGameDiffPercent: calculatePercentDiff(form.goalsForPerGame, overall.goalsForPerGame),
|
|
67
|
+
goalsAgainstPerGameDiffPercent: calculatePercentDiff(
|
|
68
|
+
form.goalsAgainstPerGame,
|
|
69
|
+
overall.goalsAgainstPerGame
|
|
70
|
+
),
|
|
71
|
+
// Home
|
|
72
|
+
home: {
|
|
73
|
+
pointsPerGame: homeOverall.pointsPerGame,
|
|
74
|
+
goalsForPerGame: homeOverall.goalsForPerGame,
|
|
75
|
+
goalsAgainstPerGame: homeOverall.goalsAgainstPerGame,
|
|
76
|
+
pointsPerGameForm: homeForm.pointsPerGame,
|
|
77
|
+
goalsForPerGameForm: homeForm.goalsForPerGame,
|
|
78
|
+
goalsAgainstPerGameForm: homeForm.goalsAgainstPerGame,
|
|
79
|
+
pointsPerGameDiffPercent: calculatePercentDiff(homeForm.pointsPerGame, homeOverall.pointsPerGame),
|
|
80
|
+
goalsForPerGameDiffPercent: calculatePercentDiff(
|
|
81
|
+
homeForm.goalsForPerGame,
|
|
82
|
+
homeOverall.goalsForPerGame
|
|
83
|
+
),
|
|
84
|
+
goalsAgainstPerGameDiffPercent: calculatePercentDiff(
|
|
85
|
+
homeForm.goalsAgainstPerGame,
|
|
86
|
+
homeOverall.goalsAgainstPerGame
|
|
87
|
+
)
|
|
88
|
+
},
|
|
89
|
+
// Away
|
|
90
|
+
away: {
|
|
91
|
+
pointsPerGame: awayOverall.pointsPerGame,
|
|
92
|
+
goalsForPerGame: awayOverall.goalsForPerGame,
|
|
93
|
+
goalsAgainstPerGame: awayOverall.goalsAgainstPerGame,
|
|
94
|
+
pointsPerGameForm: awayForm.pointsPerGame,
|
|
95
|
+
goalsForPerGameForm: awayForm.goalsForPerGame,
|
|
96
|
+
goalsAgainstPerGameForm: awayForm.goalsAgainstPerGame,
|
|
97
|
+
pointsPerGameDiffPercent: calculatePercentDiff(awayForm.pointsPerGame, awayOverall.pointsPerGame),
|
|
98
|
+
goalsForPerGameDiffPercent: calculatePercentDiff(
|
|
99
|
+
awayForm.goalsForPerGame,
|
|
100
|
+
awayOverall.goalsForPerGame
|
|
101
|
+
),
|
|
102
|
+
goalsAgainstPerGameDiffPercent: calculatePercentDiff(
|
|
103
|
+
awayForm.goalsAgainstPerGame,
|
|
104
|
+
awayOverall.goalsAgainstPerGame
|
|
105
|
+
)
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
},
|
|
109
|
+
[teamId, matches]
|
|
110
|
+
);
|
|
111
|
+
return useMemo(() => ({ getFormStats }), [getFormStats]);
|
|
112
|
+
}
|
|
113
|
+
export {
|
|
114
|
+
useFormStatsHelper
|
|
115
|
+
};
|
|
116
|
+
//# sourceMappingURL=useFormStats.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useFormStats.js","sources":["../../../../src/lib/providers/team/hooks/useFormStats.ts"],"sourcesContent":["import { useMemo, useCallback } from \"react\";\nimport type { FUSportsMatch } from \"../../../types/canonical\";\n\n/**\n * Team form statistics for a season\n */\nexport interface TeamFormStats {\n // Overall stats\n pointsPerGame: number;\n goalsForPerGame: number;\n goalsAgainstPerGame: number;\n\n // Form stats (last N matches)\n pointsPerGameForm: number;\n goalsForPerGameForm: number;\n goalsAgainstPerGameForm: number;\n\n // Difference in percent (form vs overall)\n pointsPerGameDiffPercent: number;\n goalsForPerGameDiffPercent: number;\n goalsAgainstPerGameDiffPercent: number;\n\n // Home stats\n home: {\n pointsPerGame: number;\n goalsForPerGame: number;\n goalsAgainstPerGame: number;\n pointsPerGameForm: number;\n goalsForPerGameForm: number;\n goalsAgainstPerGameForm: number;\n pointsPerGameDiffPercent: number;\n goalsForPerGameDiffPercent: number;\n goalsAgainstPerGameDiffPercent: number;\n };\n\n // Away stats\n away: {\n pointsPerGame: number;\n goalsForPerGame: number;\n goalsAgainstPerGame: number;\n pointsPerGameForm: number;\n goalsForPerGameForm: number;\n goalsAgainstPerGameForm: number;\n pointsPerGameDiffPercent: number;\n goalsForPerGameDiffPercent: number;\n goalsAgainstPerGameDiffPercent: number;\n };\n}\n\n/**\n * Calculate stats for a set of matches\n */\nfunction calculateStats(teamId: string, matches: FUSportsMatch[]) {\n let points = 0;\n let goalsFor = 0;\n let goalsAgainst = 0;\n let played = 0;\n\n matches.forEach((match) => {\n const isCompetitorOne = match.competitorOne.id === teamId;\n const teamScore = parseInt(\n isCompetitorOne ? (match.score?.competitorOne ?? \"0\") : (match.score?.competitorTwo ?? \"0\")\n );\n const opponentScore = parseInt(\n isCompetitorOne ? (match.score?.competitorTwo ?? \"0\") : (match.score?.competitorOne ?? \"0\")\n );\n\n played++;\n goalsFor += teamScore;\n goalsAgainst += opponentScore;\n\n if (teamScore > opponentScore) {\n points += 3;\n } else if (teamScore === opponentScore) {\n points += 1;\n }\n });\n\n return {\n pointsPerGame: played > 0 ? points / played : 0,\n goalsForPerGame: played > 0 ? goalsFor / played : 0,\n goalsAgainstPerGame: played > 0 ? goalsAgainst / played : 0,\n played,\n };\n}\n\n/**\n * Calculate percentage difference between two values\n */\nfunction calculatePercentDiff(current: number, overall: number): number {\n if (overall === 0) return 0;\n const diff = ((current - overall) / overall) * 100;\n return Math.round(diff * 10) / 10; // Round to 1 decimal place\n}\n\n/**\n * Hook for calculating team form statistics\n */\nexport function useFormStats(teamId: string | undefined, matches: FUSportsMatch[], formMatchCount: number = 8) {\n return useMemo<TeamFormStats | null>(() => {\n if (!teamId) return null;\n\n // Get finished matches sorted by date (most recent first)\n const finishedMatches = matches\n .filter((m) => m.status.type === \"FINISHED\")\n .filter((m) => m.competitorOne.id === teamId || m.competitorTwo.id === teamId)\n .sort((a, b) => b.timing.kickoffTime.getTime() - a.timing.kickoffTime.getTime());\n\n if (finishedMatches.length === 0) {\n return null;\n }\n\n // Calculate overall stats\n const overall = calculateStats(teamId, finishedMatches);\n\n // Calculate form stats (last N matches)\n const formMatches = finishedMatches.slice(0, formMatchCount);\n const form = calculateStats(teamId, formMatches);\n\n // Calculate home stats\n const homeMatches = finishedMatches.filter((m) => m.competitorOne.id === teamId);\n const homeOverall = calculateStats(teamId, homeMatches);\n const homeFormMatches = homeMatches.slice(0, formMatchCount);\n const homeForm = calculateStats(teamId, homeFormMatches);\n\n // Calculate away stats\n const awayMatches = finishedMatches.filter((m) => m.competitorTwo.id === teamId);\n const awayOverall = calculateStats(teamId, awayMatches);\n const awayFormMatches = awayMatches.slice(0, formMatchCount);\n const awayForm = calculateStats(teamId, awayFormMatches);\n\n return {\n // Overall\n pointsPerGame: overall.pointsPerGame,\n goalsForPerGame: overall.goalsForPerGame,\n goalsAgainstPerGame: overall.goalsAgainstPerGame,\n\n // Form\n pointsPerGameForm: form.pointsPerGame,\n goalsForPerGameForm: form.goalsForPerGame,\n goalsAgainstPerGameForm: form.goalsAgainstPerGame,\n\n // Difference\n pointsPerGameDiffPercent: calculatePercentDiff(form.pointsPerGame, overall.pointsPerGame),\n goalsForPerGameDiffPercent: calculatePercentDiff(form.goalsForPerGame, overall.goalsForPerGame),\n goalsAgainstPerGameDiffPercent: calculatePercentDiff(form.goalsAgainstPerGame, overall.goalsAgainstPerGame),\n\n // Home\n home: {\n pointsPerGame: homeOverall.pointsPerGame,\n goalsForPerGame: homeOverall.goalsForPerGame,\n goalsAgainstPerGame: homeOverall.goalsAgainstPerGame,\n pointsPerGameForm: homeForm.pointsPerGame,\n goalsForPerGameForm: homeForm.goalsForPerGame,\n goalsAgainstPerGameForm: homeForm.goalsAgainstPerGame,\n pointsPerGameDiffPercent: calculatePercentDiff(homeForm.pointsPerGame, homeOverall.pointsPerGame),\n goalsForPerGameDiffPercent: calculatePercentDiff(homeForm.goalsForPerGame, homeOverall.goalsForPerGame),\n goalsAgainstPerGameDiffPercent: calculatePercentDiff(\n homeForm.goalsAgainstPerGame,\n homeOverall.goalsAgainstPerGame\n ),\n },\n\n // Away\n away: {\n pointsPerGame: awayOverall.pointsPerGame,\n goalsForPerGame: awayOverall.goalsForPerGame,\n goalsAgainstPerGame: awayOverall.goalsAgainstPerGame,\n pointsPerGameForm: awayForm.pointsPerGame,\n goalsForPerGameForm: awayForm.goalsForPerGame,\n goalsAgainstPerGameForm: awayForm.goalsAgainstPerGame,\n pointsPerGameDiffPercent: calculatePercentDiff(awayForm.pointsPerGame, awayOverall.pointsPerGame),\n goalsForPerGameDiffPercent: calculatePercentDiff(awayForm.goalsForPerGame, awayOverall.goalsForPerGame),\n goalsAgainstPerGameDiffPercent: calculatePercentDiff(\n awayForm.goalsAgainstPerGame,\n awayOverall.goalsAgainstPerGame\n ),\n },\n };\n }, [teamId, matches, formMatchCount]);\n}\n\n/**\n * Hook that returns a function to calculate form stats on demand\n * This is used in the TeamProvider to provide a getFormStats method\n */\nexport function useFormStatsHelper(teamId: string, matches: FUSportsMatch[]) {\n const getFormStats = useCallback(\n (formMatchCount: number = 8): TeamFormStats | null => {\n if (!teamId) return null;\n\n // Get finished matches sorted by date (most recent first)\n const finishedMatches = matches\n .filter((m) => m.status.type === \"FINISHED\")\n .filter((m) => m.competitorOne.id === teamId || m.competitorTwo.id === teamId)\n .sort((a, b) => b.timing.kickoffTime.getTime() - a.timing.kickoffTime.getTime());\n\n if (finishedMatches.length === 0) {\n return null;\n }\n\n // Calculate overall stats\n const overall = calculateStats(teamId, finishedMatches);\n\n // Calculate form stats (last N matches)\n const formMatches = finishedMatches.slice(0, formMatchCount);\n const form = calculateStats(teamId, formMatches);\n\n // Calculate home stats\n const homeMatches = finishedMatches.filter((m) => m.competitorOne.id === teamId);\n const homeOverall = calculateStats(teamId, homeMatches);\n const homeFormMatches = homeMatches.slice(0, formMatchCount);\n const homeForm = calculateStats(teamId, homeFormMatches);\n\n // Calculate away stats\n const awayMatches = finishedMatches.filter((m) => m.competitorTwo.id === teamId);\n const awayOverall = calculateStats(teamId, awayMatches);\n const awayFormMatches = awayMatches.slice(0, formMatchCount);\n const awayForm = calculateStats(teamId, awayFormMatches);\n\n return {\n // Overall\n pointsPerGame: overall.pointsPerGame,\n goalsForPerGame: overall.goalsForPerGame,\n goalsAgainstPerGame: overall.goalsAgainstPerGame,\n\n // Form\n pointsPerGameForm: form.pointsPerGame,\n goalsForPerGameForm: form.goalsForPerGame,\n goalsAgainstPerGameForm: form.goalsAgainstPerGame,\n\n // Difference\n pointsPerGameDiffPercent: calculatePercentDiff(form.pointsPerGame, overall.pointsPerGame),\n goalsForPerGameDiffPercent: calculatePercentDiff(form.goalsForPerGame, overall.goalsForPerGame),\n goalsAgainstPerGameDiffPercent: calculatePercentDiff(\n form.goalsAgainstPerGame,\n overall.goalsAgainstPerGame\n ),\n\n // Home\n home: {\n pointsPerGame: homeOverall.pointsPerGame,\n goalsForPerGame: homeOverall.goalsForPerGame,\n goalsAgainstPerGame: homeOverall.goalsAgainstPerGame,\n pointsPerGameForm: homeForm.pointsPerGame,\n goalsForPerGameForm: homeForm.goalsForPerGame,\n goalsAgainstPerGameForm: homeForm.goalsAgainstPerGame,\n pointsPerGameDiffPercent: calculatePercentDiff(homeForm.pointsPerGame, homeOverall.pointsPerGame),\n goalsForPerGameDiffPercent: calculatePercentDiff(\n homeForm.goalsForPerGame,\n homeOverall.goalsForPerGame\n ),\n goalsAgainstPerGameDiffPercent: calculatePercentDiff(\n homeForm.goalsAgainstPerGame,\n homeOverall.goalsAgainstPerGame\n ),\n },\n\n // Away\n away: {\n pointsPerGame: awayOverall.pointsPerGame,\n goalsForPerGame: awayOverall.goalsForPerGame,\n goalsAgainstPerGame: awayOverall.goalsAgainstPerGame,\n pointsPerGameForm: awayForm.pointsPerGame,\n goalsForPerGameForm: awayForm.goalsForPerGame,\n goalsAgainstPerGameForm: awayForm.goalsAgainstPerGame,\n pointsPerGameDiffPercent: calculatePercentDiff(awayForm.pointsPerGame, awayOverall.pointsPerGame),\n goalsForPerGameDiffPercent: calculatePercentDiff(\n awayForm.goalsForPerGame,\n awayOverall.goalsForPerGame\n ),\n goalsAgainstPerGameDiffPercent: calculatePercentDiff(\n awayForm.goalsAgainstPerGame,\n awayOverall.goalsAgainstPerGame\n ),\n },\n };\n },\n [teamId, matches]\n );\n\n return useMemo(() => ({ getFormStats }), [getFormStats]);\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { useCallback, useMemo } from "react";
|
|
2
|
+
function useMatchHelpers(teamId, matches) {
|
|
3
|
+
const getLastMatch = useCallback(() => {
|
|
4
|
+
const finishedMatches = matches.filter(
|
|
5
|
+
(m) => m.status.type === "FINISHED" && (m.competitorOne.id === teamId || m.competitorTwo.id === teamId)
|
|
6
|
+
).sort((a, b) => b.timing.kickoffTime.getTime() - a.timing.kickoffTime.getTime());
|
|
7
|
+
return finishedMatches[0];
|
|
8
|
+
}, [teamId, matches]);
|
|
9
|
+
const getNextMatch = useCallback(() => {
|
|
10
|
+
const now = /* @__PURE__ */ new Date();
|
|
11
|
+
const upcomingMatches = matches.filter(
|
|
12
|
+
(m) => m.status.code === "not_started" && m.timing.kickoffTime > now && (m.competitorOne.id === teamId || m.competitorTwo.id === teamId)
|
|
13
|
+
).sort((a, b) => a.timing.kickoffTime.getTime() - b.timing.kickoffTime.getTime());
|
|
14
|
+
return upcomingMatches[0];
|
|
15
|
+
}, [teamId, matches]);
|
|
16
|
+
const getLiveMatch = useCallback(() => {
|
|
17
|
+
return matches.find(
|
|
18
|
+
(m) => m.status.code === "live" && (m.competitorOne.id === teamId || m.competitorTwo.id === teamId)
|
|
19
|
+
);
|
|
20
|
+
}, [teamId, matches]);
|
|
21
|
+
const getUpcomingMatches = useCallback(() => {
|
|
22
|
+
const now = /* @__PURE__ */ new Date();
|
|
23
|
+
return matches.filter(
|
|
24
|
+
(m) => (m.status.code === "not_started" || m.status.code === "live") && (m.timing.kickoffTime >= now || m.status.code === "live") && (m.competitorOne.id === teamId || m.competitorTwo.id === teamId)
|
|
25
|
+
).sort((a, b) => a.timing.kickoffTime.getTime() - b.timing.kickoffTime.getTime());
|
|
26
|
+
}, [teamId, matches]);
|
|
27
|
+
const getFinishedMatches = useCallback(() => {
|
|
28
|
+
return matches.filter(
|
|
29
|
+
(m) => m.status.type === "FINISHED" && (m.competitorOne.id === teamId || m.competitorTwo.id === teamId)
|
|
30
|
+
).sort((a, b) => b.timing.kickoffTime.getTime() - a.timing.kickoffTime.getTime());
|
|
31
|
+
}, [teamId, matches]);
|
|
32
|
+
return useMemo(
|
|
33
|
+
() => ({
|
|
34
|
+
getLastMatch,
|
|
35
|
+
getNextMatch,
|
|
36
|
+
getLiveMatch,
|
|
37
|
+
getUpcomingMatches,
|
|
38
|
+
getFinishedMatches
|
|
39
|
+
}),
|
|
40
|
+
[getLastMatch, getNextMatch, getLiveMatch, getUpcomingMatches, getFinishedMatches]
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
export {
|
|
44
|
+
useMatchHelpers
|
|
45
|
+
};
|
|
46
|
+
//# sourceMappingURL=useMatchHelpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useMatchHelpers.js","sources":["../../../../src/lib/providers/team/hooks/useMatchHelpers.ts"],"sourcesContent":["import { useCallback, useMemo } from \"react\";\nimport type { FUSportsMatch } from \"../../../types/canonical\";\n\n/**\n * Hook for team match-related helper functions\n */\nexport function useMatchHelpers(teamId: string, matches: FUSportsMatch[]) {\n /**\n * Get the last finished match for the team\n */\n const getLastMatch = useCallback(() => {\n const finishedMatches = matches\n .filter(\n (m) => m.status.type === \"FINISHED\" && (m.competitorOne.id === teamId || m.competitorTwo.id === teamId)\n )\n .sort((a, b) => b.timing.kickoffTime.getTime() - a.timing.kickoffTime.getTime());\n\n return finishedMatches[0];\n }, [teamId, matches]);\n\n /**\n * Get the next upcoming match for the team\n */\n const getNextMatch = useCallback(() => {\n const now = new Date();\n const upcomingMatches = matches\n .filter(\n (m) =>\n m.status.code === \"not_started\" &&\n m.timing.kickoffTime > now &&\n (m.competitorOne.id === teamId || m.competitorTwo.id === teamId)\n )\n .sort((a, b) => a.timing.kickoffTime.getTime() - b.timing.kickoffTime.getTime());\n\n return upcomingMatches[0];\n }, [teamId, matches]);\n\n /**\n * Get the current live match for the team (if any)\n */\n const getLiveMatch = useCallback(() => {\n return matches.find(\n (m) => m.status.code === \"live\" && (m.competitorOne.id === teamId || m.competitorTwo.id === teamId)\n );\n }, [teamId, matches]);\n\n /**\n * Get all upcoming matches for the team (sorted by kickoff time, earliest first)\n */\n const getUpcomingMatches = useCallback(() => {\n const now = new Date();\n return matches\n .filter(\n (m) =>\n (m.status.code === \"not_started\" || m.status.code === \"live\") &&\n (m.timing.kickoffTime >= now || m.status.code === \"live\") &&\n (m.competitorOne.id === teamId || m.competitorTwo.id === teamId)\n )\n .sort((a, b) => a.timing.kickoffTime.getTime() - b.timing.kickoffTime.getTime());\n }, [teamId, matches]);\n\n /**\n * Get all finished matches for the team (sorted by kickoff time, most recent first)\n */\n const getFinishedMatches = useCallback(() => {\n return matches\n .filter(\n (m) => m.status.type === \"FINISHED\" && (m.competitorOne.id === teamId || m.competitorTwo.id === teamId)\n )\n .sort((a, b) => b.timing.kickoffTime.getTime() - a.timing.kickoffTime.getTime());\n }, [teamId, matches]);\n\n return useMemo(\n () => ({\n getLastMatch,\n getNextMatch,\n getLiveMatch,\n getUpcomingMatches,\n getFinishedMatches,\n }),\n [getLastMatch, getNextMatch, getLiveMatch, getUpcomingMatches, getFinishedMatches]\n );\n}\n"],"names":[],"mappings":";AAMO,SAAS,gBAAgB,QAAgB,SAA0B;AAItE,QAAM,eAAe,YAAY,MAAM;AACnC,UAAM,kBAAkB,QACnB;AAAA,MACG,CAAC,MAAM,EAAE,OAAO,SAAS,eAAe,EAAE,cAAc,OAAO,UAAU,EAAE,cAAc,OAAO;AAAA,IAAA,EAEnG,KAAK,CAAC,GAAG,MAAM,EAAE,OAAO,YAAY,QAAA,IAAY,EAAE,OAAO,YAAY,SAAS;AAEnF,WAAO,gBAAgB,CAAC;AAAA,EAC5B,GAAG,CAAC,QAAQ,OAAO,CAAC;AAKpB,QAAM,eAAe,YAAY,MAAM;AACnC,UAAM,0BAAU,KAAA;AAChB,UAAM,kBAAkB,QACnB;AAAA,MACG,CAAC,MACG,EAAE,OAAO,SAAS,iBAClB,EAAE,OAAO,cAAc,QACtB,EAAE,cAAc,OAAO,UAAU,EAAE,cAAc,OAAO;AAAA,IAAA,EAEhE,KAAK,CAAC,GAAG,MAAM,EAAE,OAAO,YAAY,QAAA,IAAY,EAAE,OAAO,YAAY,SAAS;AAEnF,WAAO,gBAAgB,CAAC;AAAA,EAC5B,GAAG,CAAC,QAAQ,OAAO,CAAC;AAKpB,QAAM,eAAe,YAAY,MAAM;AACnC,WAAO,QAAQ;AAAA,MACX,CAAC,MAAM,EAAE,OAAO,SAAS,WAAW,EAAE,cAAc,OAAO,UAAU,EAAE,cAAc,OAAO;AAAA,IAAA;AAAA,EAEpG,GAAG,CAAC,QAAQ,OAAO,CAAC;AAKpB,QAAM,qBAAqB,YAAY,MAAM;AACzC,UAAM,0BAAU,KAAA;AAChB,WAAO,QACF;AAAA,MACG,CAAC,OACI,EAAE,OAAO,SAAS,iBAAiB,EAAE,OAAO,SAAS,YACrD,EAAE,OAAO,eAAe,OAAO,EAAE,OAAO,SAAS,YACjD,EAAE,cAAc,OAAO,UAAU,EAAE,cAAc,OAAO;AAAA,IAAA,EAEhE,KAAK,CAAC,GAAG,MAAM,EAAE,OAAO,YAAY,QAAA,IAAY,EAAE,OAAO,YAAY,SAAS;AAAA,EACvF,GAAG,CAAC,QAAQ,OAAO,CAAC;AAKpB,QAAM,qBAAqB,YAAY,MAAM;AACzC,WAAO,QACF;AAAA,MACG,CAAC,MAAM,EAAE,OAAO,SAAS,eAAe,EAAE,cAAc,OAAO,UAAU,EAAE,cAAc,OAAO;AAAA,IAAA,EAEnG,KAAK,CAAC,GAAG,MAAM,EAAE,OAAO,YAAY,QAAA,IAAY,EAAE,OAAO,YAAY,SAAS;AAAA,EACvF,GAAG,CAAC,QAAQ,OAAO,CAAC;AAEpB,SAAO;AAAA,IACH,OAAO;AAAA,MACH;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IAAA;AAAA,IAEJ,CAAC,cAAc,cAAc,cAAc,oBAAoB,kBAAkB;AAAA,EAAA;AAEzF;"}
|