fansunited-data-layer 0.12.1 → 0.14.1

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.
Files changed (261) hide show
  1. package/api/fansunited/constants.js +5 -0
  2. package/api/fansunited/constants.js.map +1 -0
  3. package/api/fansunited/football/competition/index.js +21 -0
  4. package/api/fansunited/football/competition/index.js.map +1 -0
  5. package/api/fansunited/football/competition/transformer.js +41 -0
  6. package/api/fansunited/football/competition/transformer.js.map +1 -0
  7. package/api/fansunited/football/competitions/index.js +56 -0
  8. package/api/fansunited/football/competitions/index.js.map +1 -0
  9. package/api/fansunited/football/competitions/transformer.js +68 -0
  10. package/api/fansunited/football/competitions/transformer.js.map +1 -0
  11. package/api/fansunited/football/http.js +7 -0
  12. package/api/fansunited/football/http.js.map +1 -0
  13. package/api/fansunited/football/matches/index.js +132 -0
  14. package/api/fansunited/football/matches/index.js.map +1 -0
  15. package/api/fansunited/football/matches/transformer.js +148 -0
  16. package/api/fansunited/football/matches/transformer.js.map +1 -0
  17. package/api/fansunited/football/players/index.js +60 -0
  18. package/api/fansunited/football/players/index.js.map +1 -0
  19. package/api/fansunited/football/players/transformer.js +85 -0
  20. package/api/fansunited/football/players/transformer.js.map +1 -0
  21. package/api/fansunited/football/search/index.js +64 -0
  22. package/api/fansunited/football/search/index.js.map +1 -0
  23. package/api/fansunited/football/search/transformer.js +114 -0
  24. package/api/fansunited/football/search/transformer.js.map +1 -0
  25. package/api/fansunited/football/teams/index.js +66 -0
  26. package/api/fansunited/football/teams/index.js.map +1 -0
  27. package/api/fansunited/football/teams/transformer.js +53 -0
  28. package/api/fansunited/football/teams/transformer.js.map +1 -0
  29. package/api/fansunited/http.js +74 -0
  30. package/api/fansunited/http.js.map +1 -0
  31. package/api/fansunited/search/constants.js +5 -0
  32. package/api/fansunited/search/constants.js.map +1 -0
  33. package/api/fansunited/search/http.js +7 -0
  34. package/api/fansunited/search/http.js.map +1 -0
  35. package/api/fansunited/search/index.js +308 -0
  36. package/api/fansunited/search/index.js.map +1 -0
  37. package/api/fansunited/search/transformer.js +374 -0
  38. package/api/fansunited/search/transformer.js.map +1 -0
  39. package/api/fansunited-sdk/loyalty/matches.js +21 -0
  40. package/api/fansunited-sdk/loyalty/matches.js.map +1 -0
  41. package/api/fansunited-sdk/loyalty/template.js +52 -0
  42. package/api/fansunited-sdk/loyalty/template.js.map +1 -0
  43. package/api/fansunited-sdk/odds/matches.js +109 -0
  44. package/api/fansunited-sdk/odds/matches.js.map +1 -0
  45. package/api/sportal365-sports/basketball/games/index.js +32 -0
  46. package/api/sportal365-sports/basketball/games/index.js.map +1 -0
  47. package/api/sportal365-sports/basketball/games/transformers/game.js +137 -0
  48. package/api/sportal365-sports/basketball/games/transformers/game.js.map +1 -0
  49. package/api/sportal365-sports/basketball/http.js +7 -0
  50. package/api/sportal365-sports/basketball/http.js.map +1 -0
  51. package/api/sportal365-sports/constants.js +15 -0
  52. package/api/sportal365-sports/constants.js.map +1 -0
  53. package/api/sportal365-sports/football/competitions/index.js +52 -0
  54. package/api/sportal365-sports/football/competitions/index.js.map +1 -0
  55. package/api/sportal365-sports/football/competitions/utils.js +92 -0
  56. package/api/sportal365-sports/football/competitions/utils.js.map +1 -0
  57. package/api/sportal365-sports/football/http.js +7 -0
  58. package/api/sportal365-sports/football/http.js.map +1 -0
  59. package/api/sportal365-sports/football/index.d.ts +2 -2
  60. package/api/sportal365-sports/football/index.d.ts.map +1 -1
  61. package/api/sportal365-sports/football/matches/index.js +206 -0
  62. package/api/sportal365-sports/football/matches/index.js.map +1 -0
  63. package/api/sportal365-sports/football/matches/transformers/commentary.js +27 -0
  64. package/api/sportal365-sports/football/matches/transformers/commentary.js.map +1 -0
  65. package/api/sportal365-sports/football/matches/transformers/lineup.js +74 -0
  66. package/api/sportal365-sports/football/matches/transformers/lineup.js.map +1 -0
  67. package/api/sportal365-sports/football/matches/transformers/match-event.js +60 -0
  68. package/api/sportal365-sports/football/matches/transformers/match-event.js.map +1 -0
  69. package/api/sportal365-sports/football/matches/transformers/match.js +195 -0
  70. package/api/sportal365-sports/football/matches/transformers/match.js.map +1 -0
  71. package/api/sportal365-sports/football/matches/transformers/odds.js +11 -0
  72. package/api/sportal365-sports/football/matches/transformers/odds.js.map +1 -0
  73. package/api/sportal365-sports/football/matches/transformers/statistics.js +41 -0
  74. package/api/sportal365-sports/football/matches/transformers/statistics.js.map +1 -0
  75. package/api/sportal365-sports/football/search/index.js +42 -0
  76. package/api/sportal365-sports/football/search/index.js.map +1 -0
  77. package/api/sportal365-sports/football/search/search.transformer.js +166 -0
  78. package/api/sportal365-sports/football/search/search.transformer.js.map +1 -0
  79. package/api/sportal365-sports/football/standings/index.js +28 -0
  80. package/api/sportal365-sports/football/standings/index.js.map +1 -0
  81. package/api/sportal365-sports/football/standings/standing.transformer.js +107 -0
  82. package/api/sportal365-sports/football/standings/standing.transformer.js.map +1 -0
  83. package/api/sportal365-sports/football/statistics/index.d.ts +46 -1
  84. package/api/sportal365-sports/football/statistics/index.d.ts.map +1 -1
  85. package/api/sportal365-sports/football/statistics/index.js +154 -0
  86. package/api/sportal365-sports/football/statistics/index.js.map +1 -0
  87. package/api/sportal365-sports/football/statistics/player-career.transformer.d.ts +11 -0
  88. package/api/sportal365-sports/football/statistics/player-career.transformer.d.ts.map +1 -0
  89. package/api/sportal365-sports/football/statistics/player-career.transformer.js +77 -0
  90. package/api/sportal365-sports/football/statistics/player-career.transformer.js.map +1 -0
  91. package/api/sportal365-sports/football/statistics/player-career.types.d.ts +115 -0
  92. package/api/sportal365-sports/football/statistics/player-career.types.d.ts.map +1 -0
  93. package/api/sportal365-sports/football/statistics/player-recent.transformer.d.ts +11 -0
  94. package/api/sportal365-sports/football/statistics/player-recent.transformer.d.ts.map +1 -0
  95. package/api/sportal365-sports/football/statistics/player-recent.transformer.js +54 -0
  96. package/api/sportal365-sports/football/statistics/player-recent.transformer.js.map +1 -0
  97. package/api/sportal365-sports/football/statistics/player-recent.types.d.ts +31 -0
  98. package/api/sportal365-sports/football/statistics/player-recent.types.d.ts.map +1 -0
  99. package/api/sportal365-sports/football/statistics/player-season.transformer.js +147 -0
  100. package/api/sportal365-sports/football/statistics/player-season.transformer.js.map +1 -0
  101. package/api/sportal365-sports/football/teams/index.js +73 -0
  102. package/api/sportal365-sports/football/teams/index.js.map +1 -0
  103. package/api/sportal365-sports/football/teams/utils.js +196 -0
  104. package/api/sportal365-sports/football/teams/utils.js.map +1 -0
  105. package/api/sportal365-sports/http.js +58 -0
  106. package/api/sportal365-sports/http.js.map +1 -0
  107. package/api/sportal365-sports/index.d.ts +2 -2
  108. package/api/sportal365-sports/index.d.ts.map +1 -1
  109. package/api/sportal365-sports/search/http.js +7 -0
  110. package/api/sportal365-sports/search/http.js.map +1 -0
  111. package/api/sportal365-sports/search/index.js +61 -0
  112. package/api/sportal365-sports/search/index.js.map +1 -0
  113. package/api/sportal365-sports/search/search.transformer.js +254 -0
  114. package/api/sportal365-sports/search/search.transformer.js.map +1 -0
  115. package/api/sportal365-sports/shared/odds.transformer.js +65 -0
  116. package/api/sportal365-sports/shared/odds.transformer.js.map +1 -0
  117. package/api/sportal365-sports/shared/providerRef.helper.js +31 -0
  118. package/api/sportal365-sports/shared/providerRef.helper.js.map +1 -0
  119. package/api/sportal365-sports/standings/http.js +7 -0
  120. package/api/sportal365-sports/standings/http.js.map +1 -0
  121. package/api/sportal365-sports/standings/index.js +29 -0
  122. package/api/sportal365-sports/standings/index.js.map +1 -0
  123. package/api/sportal365-sports/standings/standing.transformer.js +185 -0
  124. package/api/sportal365-sports/standings/standing.transformer.js.map +1 -0
  125. package/api/sportal365-sports/statistics/http.js +7 -0
  126. package/api/sportal365-sports/statistics/http.js.map +1 -0
  127. package/api/sportal365-sports/statistics/index.js +25 -0
  128. package/api/sportal365-sports/statistics/index.js.map +1 -0
  129. package/api/sportal365-sports/statistics/team-stats.transformer.js +16 -0
  130. package/api/sportal365-sports/statistics/team-stats.transformer.js.map +1 -0
  131. package/api/sportal365-sports/tennis/http.js +7 -0
  132. package/api/sportal365-sports/tennis/http.js.map +1 -0
  133. package/api/sportal365-sports/tennis/matches/index.js +34 -0
  134. package/api/sportal365-sports/tennis/matches/index.js.map +1 -0
  135. package/api/sportal365-sports/tennis/matches/transformers/match.js +193 -0
  136. package/api/sportal365-sports/tennis/matches/transformers/match.js.map +1 -0
  137. package/cache/cache-manager.js +136 -0
  138. package/cache/cache-manager.js.map +1 -0
  139. package/cache/memory-store.js +29 -0
  140. package/cache/memory-store.js.map +1 -0
  141. package/client.js +38 -12337
  142. package/client.js.map +1 -0
  143. package/config/index.js +20 -0
  144. package/config/index.js.map +1 -0
  145. package/fansunited-data-layer.js +146 -3551
  146. package/fansunited-data-layer.js.map +1 -0
  147. package/helpers/competition.helpers.js +11 -0
  148. package/helpers/competition.helpers.js.map +1 -0
  149. package/helpers/player.helpers.js +165 -0
  150. package/helpers/player.helpers.js.map +1 -0
  151. package/helpers/player.hooks.js +34 -0
  152. package/helpers/player.hooks.js.map +1 -0
  153. package/helpers/team.helpers.js +216 -0
  154. package/helpers/team.helpers.js.map +1 -0
  155. package/index.d.ts +3 -3
  156. package/index.d.ts.map +1 -1
  157. package/package.json +6 -8
  158. package/providers/competition/hooks/useCompetitionStats.js +10 -0
  159. package/providers/competition/hooks/useCompetitionStats.js.map +1 -0
  160. package/providers/competition/hooks/useGoalDistribution.js +23 -0
  161. package/providers/competition/hooks/useGoalDistribution.js.map +1 -0
  162. package/providers/competition/hooks/useMatchHelpers.js +85 -0
  163. package/providers/competition/hooks/useMatchHelpers.js.map +1 -0
  164. package/providers/competition/hooks/useStandingsCalculations.js +89 -0
  165. package/providers/competition/hooks/useStandingsCalculations.js.map +1 -0
  166. package/providers/competition/hooks/useStandingsHelpers.js +61 -0
  167. package/providers/competition/hooks/useStandingsHelpers.js.map +1 -0
  168. package/providers/competition/hooks/useTeamPosition.js +15 -0
  169. package/providers/competition/hooks/useTeamPosition.js.map +1 -0
  170. package/providers/competition/hooks/useTeamResultsTable.js +86 -0
  171. package/providers/competition/hooks/useTeamResultsTable.js.map +1 -0
  172. package/providers/competition/utils/competitionStats.js +109 -0
  173. package/providers/competition/utils/competitionStats.js.map +1 -0
  174. package/providers/competition/utils/goalDistribution.js +64 -0
  175. package/providers/competition/utils/goalDistribution.js.map +1 -0
  176. package/providers/competition/utils/standingsCalculations.js +152 -0
  177. package/providers/competition/utils/standingsCalculations.js.map +1 -0
  178. package/providers/competition.context.js +14 -0
  179. package/providers/competition.context.js.map +1 -0
  180. package/providers/competition.provider.js +187 -0
  181. package/providers/competition.provider.js.map +1 -0
  182. package/providers/fansunited-config.context.js +6 -0
  183. package/providers/fansunited-config.context.js.map +1 -0
  184. package/providers/fansunited-config.hooks.js +20 -0
  185. package/providers/fansunited-config.hooks.js.map +1 -0
  186. package/providers/fansunited-config.provider.js +9 -0
  187. package/providers/fansunited-config.provider.js.map +1 -0
  188. package/providers/fansunited-sdk.hook.js +50 -0
  189. package/providers/fansunited-sdk.hook.js.map +1 -0
  190. package/providers/leaderboard/hooks/useMatchHelpers.js +30 -0
  191. package/providers/leaderboard/hooks/useMatchHelpers.js.map +1 -0
  192. package/providers/leaderboard/hooks/useTemplateHelpers.js +39 -0
  193. package/providers/leaderboard/hooks/useTemplateHelpers.js.map +1 -0
  194. package/providers/leaderboard.context.js +14 -0
  195. package/providers/leaderboard.context.js.map +1 -0
  196. package/providers/leaderboard.provider.js +98 -0
  197. package/providers/leaderboard.provider.js.map +1 -0
  198. package/providers/match/hooks/useBatchMatchOdds.js +72 -0
  199. package/providers/match/hooks/useBatchMatchOdds.js.map +1 -0
  200. package/providers/match/hooks/useEventHelpers.js +46 -0
  201. package/providers/match/hooks/useEventHelpers.js.map +1 -0
  202. package/providers/match/hooks/useHeadToHeadHelpers.js +52 -0
  203. package/providers/match/hooks/useHeadToHeadHelpers.js.map +1 -0
  204. package/providers/match/hooks/useLineupHelpers.js +53 -0
  205. package/providers/match/hooks/useLineupHelpers.js.map +1 -0
  206. package/providers/match/hooks/useMatchStandingsCalculations.js +332 -0
  207. package/providers/match/hooks/useMatchStandingsCalculations.js.map +1 -0
  208. package/providers/match/hooks/useMatchStatus.js +37 -0
  209. package/providers/match/hooks/useMatchStatus.js.map +1 -0
  210. package/providers/match/hooks/useOddsHelpers.js +54 -0
  211. package/providers/match/hooks/useOddsHelpers.js.map +1 -0
  212. package/providers/match/hooks/useScoreHelpers.js +34 -0
  213. package/providers/match/hooks/useScoreHelpers.js.map +1 -0
  214. package/providers/match/hooks/useStandingsHelpers.js +53 -0
  215. package/providers/match/hooks/useStandingsHelpers.js.map +1 -0
  216. package/providers/match/hooks/useStatisticsHelpers.js +40 -0
  217. package/providers/match/hooks/useStatisticsHelpers.js.map +1 -0
  218. package/providers/match/hooks/useTeamHelpers.js +38 -0
  219. package/providers/match/hooks/useTeamHelpers.js.map +1 -0
  220. package/providers/match/hooks/useTeamStatsHelpers.js +141 -0
  221. package/providers/match/hooks/useTeamStatsHelpers.js.map +1 -0
  222. package/providers/match.context.js +14 -0
  223. package/providers/match.context.js.map +1 -0
  224. package/providers/match.provider.js +176 -0
  225. package/providers/match.provider.js.map +1 -0
  226. package/providers/team/hooks/useFormStats.js +116 -0
  227. package/providers/team/hooks/useFormStats.js.map +1 -0
  228. package/providers/team/hooks/useMatchHelpers.js +46 -0
  229. package/providers/team/hooks/useMatchHelpers.js.map +1 -0
  230. package/providers/team/hooks/useSquadHelpers.js +67 -0
  231. package/providers/team/hooks/useSquadHelpers.js.map +1 -0
  232. package/providers/team.context.js +14 -0
  233. package/providers/team.context.js.map +1 -0
  234. package/providers/team.provider.js +98 -0
  235. package/providers/team.provider.js.map +1 -0
  236. package/types/canonical/index.d.ts +1 -1
  237. package/types/canonical/index.d.ts.map +1 -1
  238. package/types/canonical/statistics.types.d.ts +102 -0
  239. package/types/canonical/statistics.types.d.ts.map +1 -1
  240. package/utilities/stats/core/helpers.js +105 -0
  241. package/utilities/stats/core/helpers.js.map +1 -0
  242. package/utilities/stats/core/types.js +5 -0
  243. package/utilities/stats/core/types.js.map +1 -0
  244. package/utilities/stats/match/headToHead.js +83 -0
  245. package/utilities/stats/match/headToHead.js.map +1 -0
  246. package/utilities/stats/match/homeVsAway.js +140 -0
  247. package/utilities/stats/match/homeVsAway.js.map +1 -0
  248. package/utilities/stats/match/overUnder.js +91 -0
  249. package/utilities/stats/match/overUnder.js.map +1 -0
  250. package/utilities/stats/match/result.js +21 -0
  251. package/utilities/stats/match/result.js.map +1 -0
  252. package/utilities/stats/team/commonOpponents.js +77 -0
  253. package/utilities/stats/team/commonOpponents.js.map +1 -0
  254. package/utilities/stats/team/goalStats.js +50 -0
  255. package/utilities/stats/team/goalStats.js.map +1 -0
  256. package/utilities/stats/team/streaks.js +183 -0
  257. package/utilities/stats/team/streaks.js.map +1 -0
  258. package/client.cjs +0 -8
  259. package/fansunited-data-layer.cjs +0 -1
  260. package/matches-CB-dSXEA.js +0 -1633
  261. package/matches-DvC2VSyO.cjs +0 -1
@@ -0,0 +1,67 @@
1
+ import { useMemo, useCallback } from "react";
2
+ function useSquadHelpers(squad) {
3
+ const players = useMemo(() => squad?.players ?? [], [squad]);
4
+ const getPlayer = useCallback((id) => players.find((p) => p.id === id), [players]);
5
+ const getPlayerByShirtNumber = useCallback(
6
+ (shirtNumber) => players.find((p) => p.shirtNumber === shirtNumber),
7
+ [players]
8
+ );
9
+ const getPlayersByPosition = useCallback(
10
+ (position) => players.filter((p) => p.position === position),
11
+ [players]
12
+ );
13
+ const getActiveSquad = useCallback(() => players.filter((p) => p.status === "ACTIVE"), [players]);
14
+ const getInactiveSquad = useCallback(() => players.filter((p) => p.status === "INACTIVE"), [players]);
15
+ const getSquadByContractType = useCallback(
16
+ (contractType) => players.filter((p) => p.contractType === contractType),
17
+ [players]
18
+ );
19
+ const getGoalkeepers = useCallback(
20
+ () => players.filter((p) => p.position?.toLowerCase().includes("keeper")),
21
+ [players]
22
+ );
23
+ const getDefenders = useCallback(
24
+ () => players.filter((p) => p.position?.toLowerCase().includes("defender")),
25
+ [players]
26
+ );
27
+ const getMidfielders = useCallback(
28
+ () => players.filter((p) => p.position?.toLowerCase().includes("midfielder")),
29
+ [players]
30
+ );
31
+ const getForwards = useCallback(
32
+ () => players.filter(
33
+ (p) => p.position?.toLowerCase().includes("forward") || p.position?.toLowerCase().includes("attacker")
34
+ ),
35
+ [players]
36
+ );
37
+ return useMemo(
38
+ () => ({
39
+ getPlayer,
40
+ getPlayerByShirtNumber,
41
+ getPlayersByPosition,
42
+ getActiveSquad,
43
+ getInactiveSquad,
44
+ getSquadByContractType,
45
+ getGoalkeepers,
46
+ getDefenders,
47
+ getMidfielders,
48
+ getForwards
49
+ }),
50
+ [
51
+ getPlayer,
52
+ getPlayerByShirtNumber,
53
+ getPlayersByPosition,
54
+ getActiveSquad,
55
+ getInactiveSquad,
56
+ getSquadByContractType,
57
+ getGoalkeepers,
58
+ getDefenders,
59
+ getMidfielders,
60
+ getForwards
61
+ ]
62
+ );
63
+ }
64
+ export {
65
+ useSquadHelpers
66
+ };
67
+ //# sourceMappingURL=useSquadHelpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useSquadHelpers.js","sources":["../../../../src/lib/providers/team/hooks/useSquadHelpers.ts"],"sourcesContent":["import { useCallback, useMemo } from \"react\";\nimport type { FUSportsSquad } from \"../../../types/canonical\";\n\n/**\n * Hook for squad-related helper functions\n */\nexport function useSquadHelpers(squad: FUSportsSquad | null) {\n const players = useMemo(() => squad?.players ?? [], [squad]);\n\n const getPlayer = useCallback((id: string) => players.find((p) => p.id === id), [players]);\n\n const getPlayerByShirtNumber = useCallback(\n (shirtNumber: number) => players.find((p) => p.shirtNumber === shirtNumber),\n [players]\n );\n\n const getPlayersByPosition = useCallback(\n (position: string) => players.filter((p) => p.position === position),\n [players]\n );\n\n const getActiveSquad = useCallback(() => players.filter((p) => p.status === \"ACTIVE\"), [players]);\n\n const getInactiveSquad = useCallback(() => players.filter((p) => p.status === \"INACTIVE\"), [players]);\n\n const getSquadByContractType = useCallback(\n (contractType: \"PERMANENT\" | \"LOAN\" | \"UNKNOWN\") => players.filter((p) => p.contractType === contractType),\n [players]\n );\n\n const getGoalkeepers = useCallback(\n () => players.filter((p) => p.position?.toLowerCase().includes(\"keeper\")),\n [players]\n );\n\n const getDefenders = useCallback(\n () => players.filter((p) => p.position?.toLowerCase().includes(\"defender\")),\n [players]\n );\n\n const getMidfielders = useCallback(\n () => players.filter((p) => p.position?.toLowerCase().includes(\"midfielder\")),\n [players]\n );\n\n const getForwards = useCallback(\n () =>\n players.filter(\n (p) => p.position?.toLowerCase().includes(\"forward\") || p.position?.toLowerCase().includes(\"attacker\")\n ),\n [players]\n );\n\n return useMemo(\n () => ({\n getPlayer,\n getPlayerByShirtNumber,\n getPlayersByPosition,\n getActiveSquad,\n getInactiveSquad,\n getSquadByContractType,\n getGoalkeepers,\n getDefenders,\n getMidfielders,\n getForwards,\n }),\n [\n getPlayer,\n getPlayerByShirtNumber,\n getPlayersByPosition,\n getActiveSquad,\n getInactiveSquad,\n getSquadByContractType,\n getGoalkeepers,\n getDefenders,\n getMidfielders,\n getForwards,\n ]\n );\n}\n"],"names":[],"mappings":";AAMO,SAAS,gBAAgB,OAA6B;AACzD,QAAM,UAAU,QAAQ,MAAM,OAAO,WAAW,CAAA,GAAI,CAAC,KAAK,CAAC;AAE3D,QAAM,YAAY,YAAY,CAAC,OAAe,QAAQ,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,CAAC;AAEzF,QAAM,yBAAyB;AAAA,IAC3B,CAAC,gBAAwB,QAAQ,KAAK,CAAC,MAAM,EAAE,gBAAgB,WAAW;AAAA,IAC1E,CAAC,OAAO;AAAA,EAAA;AAGZ,QAAM,uBAAuB;AAAA,IACzB,CAAC,aAAqB,QAAQ,OAAO,CAAC,MAAM,EAAE,aAAa,QAAQ;AAAA,IACnE,CAAC,OAAO;AAAA,EAAA;AAGZ,QAAM,iBAAiB,YAAY,MAAM,QAAQ,OAAO,CAAC,MAAM,EAAE,WAAW,QAAQ,GAAG,CAAC,OAAO,CAAC;AAEhG,QAAM,mBAAmB,YAAY,MAAM,QAAQ,OAAO,CAAC,MAAM,EAAE,WAAW,UAAU,GAAG,CAAC,OAAO,CAAC;AAEpG,QAAM,yBAAyB;AAAA,IAC3B,CAAC,iBAAmD,QAAQ,OAAO,CAAC,MAAM,EAAE,iBAAiB,YAAY;AAAA,IACzG,CAAC,OAAO;AAAA,EAAA;AAGZ,QAAM,iBAAiB;AAAA,IACnB,MAAM,QAAQ,OAAO,CAAC,MAAM,EAAE,UAAU,YAAA,EAAc,SAAS,QAAQ,CAAC;AAAA,IACxE,CAAC,OAAO;AAAA,EAAA;AAGZ,QAAM,eAAe;AAAA,IACjB,MAAM,QAAQ,OAAO,CAAC,MAAM,EAAE,UAAU,YAAA,EAAc,SAAS,UAAU,CAAC;AAAA,IAC1E,CAAC,OAAO;AAAA,EAAA;AAGZ,QAAM,iBAAiB;AAAA,IACnB,MAAM,QAAQ,OAAO,CAAC,MAAM,EAAE,UAAU,YAAA,EAAc,SAAS,YAAY,CAAC;AAAA,IAC5E,CAAC,OAAO;AAAA,EAAA;AAGZ,QAAM,cAAc;AAAA,IAChB,MACI,QAAQ;AAAA,MACJ,CAAC,MAAM,EAAE,UAAU,cAAc,SAAS,SAAS,KAAK,EAAE,UAAU,YAAA,EAAc,SAAS,UAAU;AAAA,IAAA;AAAA,IAE7G,CAAC,OAAO;AAAA,EAAA;AAGZ,SAAO;AAAA,IACH,OAAO;AAAA,MACH;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IAAA;AAAA,IAEJ;AAAA,MACI;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IAAA;AAAA,EACJ;AAER;"}
@@ -0,0 +1,14 @@
1
+ import { createContext, useContext } from "react";
2
+ const TeamContext = createContext(null);
3
+ function useTeam() {
4
+ const context = useContext(TeamContext);
5
+ if (!context) {
6
+ throw new Error("useTeam must be used within TeamProvider");
7
+ }
8
+ return context;
9
+ }
10
+ export {
11
+ TeamContext,
12
+ useTeam
13
+ };
14
+ //# sourceMappingURL=team.context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"team.context.js","sources":["../../src/lib/providers/team.context.ts"],"sourcesContent":["\"use client\";\n\nimport { createContext, useContext } from \"react\";\nimport type { TeamContextValue } from \"./team.types\";\n\n// ============================================================================\n// Context\n// ============================================================================\n\nexport const TeamContext = createContext<TeamContextValue | null>(null);\n\n// ============================================================================\n// Hook\n// ============================================================================\n\n/**\n * Hook to access team context\n * Must be used within a TeamProvider\n */\nexport function useTeam(): TeamContextValue {\n const context = useContext(TeamContext);\n if (!context) {\n throw new Error(\"useTeam must be used within TeamProvider\");\n }\n return context;\n}\n\n"],"names":[],"mappings":";AASO,MAAM,cAAc,cAAuC,IAAI;AAU/D,SAAS,UAA4B;AACxC,QAAM,UAAU,WAAW,WAAW;AACtC,MAAI,CAAC,SAAS;AACV,UAAM,IAAI,MAAM,0CAA0C;AAAA,EAC9D;AACA,SAAO;AACX;"}
@@ -0,0 +1,98 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { useState, useEffect, useCallback, useMemo } from "react";
3
+ import { TeamContext } from "./team.context.js";
4
+ import { getFootballTeam, getFootballTeamSquad } from "../api/sportal365-sports/football/teams/index.js";
5
+ import { useSquadHelpers } from "./team/hooks/useSquadHelpers.js";
6
+ import { useMatchHelpers } from "./team/hooks/useMatchHelpers.js";
7
+ import { useFormStatsHelper } from "./team/hooks/useFormStats.js";
8
+ import { useDataLayerConfig } from "./fansunited-config.hooks.js";
9
+ function TeamProvider({
10
+ teamId,
11
+ team: initialTeam,
12
+ squad: initialSquad,
13
+ matches: initialMatches = [],
14
+ config,
15
+ autoRefresh = false,
16
+ refreshInterval = 6e4,
17
+ children
18
+ }) {
19
+ const dataLayerConfig = useDataLayerConfig();
20
+ const [team, setTeam] = useState(initialTeam);
21
+ const [squad, setSquad] = useState(initialSquad ?? null);
22
+ const [matches] = useState(initialMatches);
23
+ const [isRefreshing, setIsRefreshing] = useState(false);
24
+ const [lastRefreshed, setLastRefreshed] = useState(void 0);
25
+ useEffect(() => {
26
+ if (team && squad) return;
27
+ const fetchInitialData = async () => {
28
+ try {
29
+ const [teamData, squadData] = await Promise.all([
30
+ !team ? getFootballTeam(teamId, void 0, dataLayerConfig) : Promise.resolve(team),
31
+ !squad ? getFootballTeamSquad(teamId, void 0, dataLayerConfig) : Promise.resolve(squad)
32
+ ]);
33
+ if (!team) setTeam(teamData);
34
+ if (!squad) setSquad(squadData);
35
+ } catch (error) {
36
+ console.error("Failed to fetch initial team data:", error);
37
+ }
38
+ };
39
+ fetchInitialData();
40
+ }, [dataLayerConfig]);
41
+ const refresh = useCallback(async () => {
42
+ setIsRefreshing(true);
43
+ try {
44
+ const [teamData, squadData] = await Promise.all([
45
+ getFootballTeam(teamId, void 0, dataLayerConfig),
46
+ getFootballTeamSquad(teamId, void 0, dataLayerConfig)
47
+ ]);
48
+ setTeam(teamData);
49
+ setSquad(squadData);
50
+ setLastRefreshed(/* @__PURE__ */ new Date());
51
+ } catch (error) {
52
+ console.error("Failed to refresh team data:", error);
53
+ } finally {
54
+ setIsRefreshing(false);
55
+ }
56
+ }, [teamId, dataLayerConfig]);
57
+ useEffect(() => {
58
+ if (!autoRefresh) return;
59
+ const interval = setInterval(refresh, refreshInterval);
60
+ return () => clearInterval(interval);
61
+ }, [autoRefresh, refreshInterval, refresh]);
62
+ const squadHelpers = useSquadHelpers(squad);
63
+ const effectiveTeamId = team?.id ?? teamId;
64
+ const matchHelpers = useMatchHelpers(effectiveTeamId, matches);
65
+ const { getFormStats } = useFormStatsHelper(effectiveTeamId, matches);
66
+ const contextValue = useMemo(() => {
67
+ return {
68
+ teamId,
69
+ team,
70
+ isRefreshing,
71
+ lastRefreshed,
72
+ squad,
73
+ matches,
74
+ config,
75
+ refresh,
76
+ getFormStats,
77
+ ...squadHelpers,
78
+ ...matchHelpers
79
+ };
80
+ }, [
81
+ teamId,
82
+ team,
83
+ isRefreshing,
84
+ lastRefreshed,
85
+ squad,
86
+ matches,
87
+ config,
88
+ refresh,
89
+ getFormStats,
90
+ squadHelpers,
91
+ matchHelpers
92
+ ]);
93
+ return /* @__PURE__ */ jsx(TeamContext.Provider, { value: contextValue, children });
94
+ }
95
+ export {
96
+ TeamProvider
97
+ };
98
+ //# sourceMappingURL=team.provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"team.provider.js","sources":["../../src/lib/providers/team.provider.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState, useEffect, useMemo, useCallback } from \"react\";\nimport type { FUSportsSquad, FUSportsCompetitor, FUSportsMatch } from \"../types/canonical\";\nimport { TeamContext } from \"./team.context\";\nimport type { TeamContextValue, TeamProviderProps } from \"./team.types\";\nimport { getFootballTeam, getFootballTeamSquad } from \"../api/sportal365-sports/football/teams\";\nimport { useSquadHelpers } from \"./team/hooks/useSquadHelpers\";\nimport { useMatchHelpers } from \"./team/hooks/useMatchHelpers\";\nimport { useFormStatsHelper } from \"./team/hooks/useFormStats\";\nimport { useDataLayerConfig } from \"./fansunited-config.hooks\";\n\n// ============================================================================\n// Provider Component\n// ============================================================================\n\nexport function TeamProvider({\n teamId,\n team: initialTeam,\n squad: initialSquad,\n matches: initialMatches = [],\n config,\n autoRefresh = false,\n refreshInterval = 60000,\n children,\n}: TeamProviderProps) {\n // Get data layer config from context\n const dataLayerConfig = useDataLayerConfig();\n\n // Core data state\n const [team, setTeam] = useState<FUSportsCompetitor | undefined>(initialTeam);\n const [squad, setSquad] = useState<FUSportsSquad | null>(initialSquad ?? null);\n const [matches] = useState<FUSportsMatch[]>(initialMatches);\n\n // Refresh state\n const [isRefreshing, setIsRefreshing] = useState(false);\n const [lastRefreshed, setLastRefreshed] = useState<Date | undefined>(undefined);\n\n // DON'T update state from props - this causes infinite loops in Next.js\n // The initial values are set once, and only the refresh() function updates them\n\n // Initial fetch for team and squad (only once if not provided)\n useEffect(() => {\n if (team && squad) return;\n\n const fetchInitialData = async () => {\n try {\n const [teamData, squadData] = await Promise.all([\n !team ? getFootballTeam(teamId, undefined, dataLayerConfig) : Promise.resolve(team),\n !squad ? getFootballTeamSquad(teamId, undefined, dataLayerConfig) : Promise.resolve(squad),\n ]);\n\n if (!team) setTeam(teamData);\n if (!squad) setSquad(squadData);\n } catch (error) {\n console.error(\"Failed to fetch initial team data:\", error);\n }\n };\n\n fetchInitialData();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [dataLayerConfig]);\n\n // Refresh function\n const refresh = useCallback(async () => {\n setIsRefreshing(true);\n try {\n const [teamData, squadData] = await Promise.all([\n getFootballTeam(teamId, undefined, dataLayerConfig),\n getFootballTeamSquad(teamId, undefined, dataLayerConfig),\n ]);\n\n setTeam(teamData);\n setSquad(squadData);\n setLastRefreshed(new Date());\n } catch (error) {\n console.error(\"Failed to refresh team data:\", error);\n } finally {\n setIsRefreshing(false);\n }\n }, [teamId, dataLayerConfig]);\n\n // Auto-refresh effect\n useEffect(() => {\n if (!autoRefresh) return;\n\n const interval = setInterval(refresh, refreshInterval);\n return () => clearInterval(interval);\n }, [autoRefresh, refreshInterval, refresh]);\n\n // Squad helpers\n const squadHelpers = useSquadHelpers(squad);\n\n // Match helpers - use team.id (numeric ID) if available, otherwise fall back to teamId\n const effectiveTeamId = team?.id ?? teamId;\n const matchHelpers = useMatchHelpers(effectiveTeamId, matches);\n\n // Form stats helper\n const { getFormStats } = useFormStatsHelper(effectiveTeamId, matches);\n\n // Memoize context value\n const contextValue = useMemo<TeamContextValue>(() => {\n return {\n teamId,\n team,\n isRefreshing,\n lastRefreshed,\n squad,\n matches,\n config,\n refresh,\n getFormStats,\n ...squadHelpers,\n ...matchHelpers,\n };\n }, [\n teamId,\n team,\n isRefreshing,\n lastRefreshed,\n squad,\n matches,\n config,\n refresh,\n getFormStats,\n squadHelpers,\n matchHelpers,\n ]);\n\n return <TeamContext.Provider value={contextValue}>{children}</TeamContext.Provider>;\n}\n"],"names":[],"mappings":";;;;;;;;AAgBO,SAAS,aAAa;AAAA,EACzB;AAAA,EACA,MAAM;AAAA,EACN,OAAO;AAAA,EACP,SAAS,iBAAiB,CAAA;AAAA,EAC1B;AAAA,EACA,cAAc;AAAA,EACd,kBAAkB;AAAA,EAClB;AACJ,GAAsB;AAElB,QAAM,kBAAkB,mBAAA;AAGxB,QAAM,CAAC,MAAM,OAAO,IAAI,SAAyC,WAAW;AAC5E,QAAM,CAAC,OAAO,QAAQ,IAAI,SAA+B,gBAAgB,IAAI;AAC7E,QAAM,CAAC,OAAO,IAAI,SAA0B,cAAc;AAG1D,QAAM,CAAC,cAAc,eAAe,IAAI,SAAS,KAAK;AACtD,QAAM,CAAC,eAAe,gBAAgB,IAAI,SAA2B,MAAS;AAM9E,YAAU,MAAM;AACZ,QAAI,QAAQ,MAAO;AAEnB,UAAM,mBAAmB,YAAY;AACjC,UAAI;AACA,cAAM,CAAC,UAAU,SAAS,IAAI,MAAM,QAAQ,IAAI;AAAA,UAC5C,CAAC,OAAO,gBAAgB,QAAQ,QAAW,eAAe,IAAI,QAAQ,QAAQ,IAAI;AAAA,UAClF,CAAC,QAAQ,qBAAqB,QAAQ,QAAW,eAAe,IAAI,QAAQ,QAAQ,KAAK;AAAA,QAAA,CAC5F;AAED,YAAI,CAAC,KAAM,SAAQ,QAAQ;AAC3B,YAAI,CAAC,MAAO,UAAS,SAAS;AAAA,MAClC,SAAS,OAAO;AACZ,gBAAQ,MAAM,sCAAsC,KAAK;AAAA,MAC7D;AAAA,IACJ;AAEA,qBAAA;AAAA,EAEJ,GAAG,CAAC,eAAe,CAAC;AAGpB,QAAM,UAAU,YAAY,YAAY;AACpC,oBAAgB,IAAI;AACpB,QAAI;AACA,YAAM,CAAC,UAAU,SAAS,IAAI,MAAM,QAAQ,IAAI;AAAA,QAC5C,gBAAgB,QAAQ,QAAW,eAAe;AAAA,QAClD,qBAAqB,QAAQ,QAAW,eAAe;AAAA,MAAA,CAC1D;AAED,cAAQ,QAAQ;AAChB,eAAS,SAAS;AAClB,uBAAiB,oBAAI,MAAM;AAAA,IAC/B,SAAS,OAAO;AACZ,cAAQ,MAAM,gCAAgC,KAAK;AAAA,IACvD,UAAA;AACI,sBAAgB,KAAK;AAAA,IACzB;AAAA,EACJ,GAAG,CAAC,QAAQ,eAAe,CAAC;AAG5B,YAAU,MAAM;AACZ,QAAI,CAAC,YAAa;AAElB,UAAM,WAAW,YAAY,SAAS,eAAe;AACrD,WAAO,MAAM,cAAc,QAAQ;AAAA,EACvC,GAAG,CAAC,aAAa,iBAAiB,OAAO,CAAC;AAG1C,QAAM,eAAe,gBAAgB,KAAK;AAG1C,QAAM,kBAAkB,MAAM,MAAM;AACpC,QAAM,eAAe,gBAAgB,iBAAiB,OAAO;AAG7D,QAAM,EAAE,aAAA,IAAiB,mBAAmB,iBAAiB,OAAO;AAGpE,QAAM,eAAe,QAA0B,MAAM;AACjD,WAAO;AAAA,MACH;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,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,EAAA,CACH;AAED,6BAAQ,YAAY,UAAZ,EAAqB,OAAO,cAAe,UAAS;AAChE;"}
@@ -7,7 +7,7 @@ export type { FUSportsCountry, FUSportsCity, FUSportsCompetitor, FUSportsCompeti
7
7
  export type { FUSportsMatchScore, FUSportsMatchStatus, FUSportsMatchTiming, FUSportsMatchWinner, FUSportsMatch, FUSportsMatchSimple, } from "./match.types";
8
8
  export type { FUSportsFootballEventType, FUSportsOtherEventType, FUSportsMatchEvent } from "./event.types";
9
9
  export type { FUSportsLineupMember, FUSportsCompetitorLineup, FUSportsMatchLineups } from "./lineup.types";
10
- export type { FUSportsMatchPeriod, FUSportsStatisticEntry, FUSportsCompetitorStatistics, FUSportsMatchStatistics, FUSportsPlayerStatistic, FUSportsPlayerSeasonStatistics, FUSportsTeamSeasonStatistics, } from "./statistics.types";
10
+ export type { FUSportsMatchPeriod, FUSportsStatisticEntry, FUSportsCompetitorStatistics, FUSportsMatchStatistics, FUSportsPlayerStatistic, FUSportsPlayerSeasonStatistics, FUSportsCareerTournamentSeason, FUSportsCareerTeam, FUSportsPlayerCareerStatisticsEntry, FUSportsPlayerCareerStatistics, FUSportsPlayerRecentStatistics, FUSportsTeamSeasonStatistics, } from "./statistics.types";
11
11
  export type { FUSportsBettingOperatorBranding, FUSportsBettingOperator, FUSportsOddSelection, FUSportsMarketPeriod, FUSportsMarketType, FUSportsOddMarket, FUSportsBettingOperatorOdds, FUSportsMatchOdds, FUSportsBatchMatchOdds, } from "./odds.types";
12
12
  export type { FUSportsCommentaryDetail, FUSportsCommentaryMeta, FUSportsCommentaryItem } from "./commentary.types";
13
13
  export type { FUSportsStandingEntry, FUSportsCompetitorForm, FUSportsStandingLegendItem, FUSportsStandingsMetadata, FUSportsStandings, FUSportsStandingsTable, } from "./standing.types";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/types/canonical/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,YAAY,EACR,eAAe,EACf,YAAY,EACZ,kBAAkB,EAClB,sBAAsB,EACtB,sBAAsB,EACtB,wBAAwB,EACxB,sBAAsB,EACtB,kBAAkB,EAClB,cAAc,EACd,aAAa,EACb,aAAa,EACb,qBAAqB,EACrB,mBAAmB,EACnB,aAAa,EACb,gBAAgB,EAChB,cAAc,EACd,mBAAmB,EACnB,wBAAwB,EACxB,aAAa,EACb,eAAe,EACf,eAAe,EACf,UAAU,EAEV,0BAA0B,EAC1B,mBAAmB,EACnB,qBAAqB,EACrB,sBAAsB,EACtB,oBAAoB,EACpB,oBAAoB,GACvB,MAAM,cAAc,CAAC;AAGtB,YAAY,EACR,kBAAkB,EAClB,mBAAmB,EACnB,mBAAmB,EACnB,mBAAmB,EACnB,aAAa,EACb,mBAAmB,GACtB,MAAM,eAAe,CAAC;AAGvB,YAAY,EAAE,yBAAyB,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAG3G,YAAY,EAAE,oBAAoB,EAAE,wBAAwB,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAG3G,YAAY,EACR,mBAAmB,EACnB,sBAAsB,EACtB,4BAA4B,EAC5B,uBAAuB,EACvB,uBAAuB,EACvB,8BAA8B,EAC9B,4BAA4B,GAC/B,MAAM,oBAAoB,CAAC;AAG5B,YAAY,EACR,+BAA+B,EAC/B,uBAAuB,EACvB,oBAAoB,EACpB,oBAAoB,EACpB,kBAAkB,EAClB,iBAAiB,EACjB,2BAA2B,EAC3B,iBAAiB,EACjB,sBAAsB,GACzB,MAAM,cAAc,CAAC;AAGtB,YAAY,EAAE,wBAAwB,EAAE,sBAAsB,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAGnH,YAAY,EACR,qBAAqB,EACrB,sBAAsB,EACtB,0BAA0B,EAC1B,yBAAyB,EACzB,iBAAiB,EACjB,sBAAsB,GACzB,MAAM,kBAAkB,CAAC;AAG1B,YAAY,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAGxE,YAAY,EACR,wBAAwB,EACxB,8BAA8B,EAC9B,0BAA0B,EAC1B,wBAAwB,EACxB,6BAA6B,EAC7B,yBAAyB,EACzB,yBAAyB,EACzB,oBAAoB,EACpB,qBAAqB,GACxB,MAAM,gBAAgB,CAAC;AAGxB,YAAY,EACR,mBAAmB,EACnB,oBAAoB,EACpB,8BAA8B,EAC9B,2BAA2B,EAC3B,8BAA8B,EAC9B,8BAA8B,EAC9B,+BAA+B,EAC/B,gCAAgC,EAChC,+BAA+B,EAC/B,iCAAiC,EACjC,+BAA+B,EAC/B,oCAAoC,EACpC,+BAA+B,EAC/B,iCAAiC,EACjC,0BAA0B,EAC1B,2BAA2B,GAC9B,MAAM,uBAAuB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/types/canonical/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,YAAY,EACR,eAAe,EACf,YAAY,EACZ,kBAAkB,EAClB,sBAAsB,EACtB,sBAAsB,EACtB,wBAAwB,EACxB,sBAAsB,EACtB,kBAAkB,EAClB,cAAc,EACd,aAAa,EACb,aAAa,EACb,qBAAqB,EACrB,mBAAmB,EACnB,aAAa,EACb,gBAAgB,EAChB,cAAc,EACd,mBAAmB,EACnB,wBAAwB,EACxB,aAAa,EACb,eAAe,EACf,eAAe,EACf,UAAU,EAEV,0BAA0B,EAC1B,mBAAmB,EACnB,qBAAqB,EACrB,sBAAsB,EACtB,oBAAoB,EACpB,oBAAoB,GACvB,MAAM,cAAc,CAAC;AAGtB,YAAY,EACR,kBAAkB,EAClB,mBAAmB,EACnB,mBAAmB,EACnB,mBAAmB,EACnB,aAAa,EACb,mBAAmB,GACtB,MAAM,eAAe,CAAC;AAGvB,YAAY,EAAE,yBAAyB,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAG3G,YAAY,EAAE,oBAAoB,EAAE,wBAAwB,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAG3G,YAAY,EACR,mBAAmB,EACnB,sBAAsB,EACtB,4BAA4B,EAC5B,uBAAuB,EACvB,uBAAuB,EACvB,8BAA8B,EAC9B,8BAA8B,EAC9B,kBAAkB,EAClB,mCAAmC,EACnC,8BAA8B,EAC9B,8BAA8B,EAC9B,4BAA4B,GAC/B,MAAM,oBAAoB,CAAC;AAG5B,YAAY,EACR,+BAA+B,EAC/B,uBAAuB,EACvB,oBAAoB,EACpB,oBAAoB,EACpB,kBAAkB,EAClB,iBAAiB,EACjB,2BAA2B,EAC3B,iBAAiB,EACjB,sBAAsB,GACzB,MAAM,cAAc,CAAC;AAGtB,YAAY,EAAE,wBAAwB,EAAE,sBAAsB,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAGnH,YAAY,EACR,qBAAqB,EACrB,sBAAsB,EACtB,0BAA0B,EAC1B,yBAAyB,EACzB,iBAAiB,EACjB,sBAAsB,GACzB,MAAM,kBAAkB,CAAC;AAG1B,YAAY,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAGxE,YAAY,EACR,wBAAwB,EACxB,8BAA8B,EAC9B,0BAA0B,EAC1B,wBAAwB,EACxB,6BAA6B,EAC7B,yBAAyB,EACzB,yBAAyB,EACzB,oBAAoB,EACpB,qBAAqB,GACxB,MAAM,gBAAgB,CAAC;AAGxB,YAAY,EACR,mBAAmB,EACnB,oBAAoB,EACpB,8BAA8B,EAC9B,2BAA2B,EAC3B,8BAA8B,EAC9B,8BAA8B,EAC9B,+BAA+B,EAC/B,gCAAgC,EAChC,+BAA+B,EAC/B,iCAAiC,EACjC,+BAA+B,EAC/B,oCAAoC,EACpC,+BAA+B,EAC/B,iCAAiC,EACjC,0BAA0B,EAC1B,2BAA2B,GAC9B,MAAM,uBAAuB,CAAC"}
@@ -70,6 +70,108 @@ export interface FUSportsPlayerSeasonStatistics {
70
70
  totalCards?: number;
71
71
  rawStatistics?: FUSportsPlayerStatistic[];
72
72
  }
73
+ /**
74
+ * Tournament season summary for career statistics
75
+ */
76
+ export interface FUSportsCareerTournamentSeason {
77
+ id: string;
78
+ name: string;
79
+ uuid: string;
80
+ active: boolean;
81
+ tournament: {
82
+ id: string;
83
+ name: string;
84
+ uuid: string;
85
+ type: string;
86
+ region: string;
87
+ logo?: string;
88
+ country?: {
89
+ id: string;
90
+ name: string;
91
+ uuid: string;
92
+ };
93
+ };
94
+ }
95
+ /**
96
+ * Team summary for career statistics
97
+ */
98
+ export interface FUSportsCareerTeam {
99
+ id: string;
100
+ name: string;
101
+ uuid: string;
102
+ threeLetterCode: string;
103
+ type: string;
104
+ logo?: string;
105
+ }
106
+ /**
107
+ * Single entry in a player's career statistics.
108
+ * Each entry represents stats for one tournament season with one team.
109
+ */
110
+ export interface FUSportsPlayerCareerStatisticsEntry {
111
+ tournamentSeason: FUSportsCareerTournamentSeason;
112
+ team: FUSportsCareerTeam;
113
+ appearances?: number;
114
+ started?: number;
115
+ substituteIn?: number;
116
+ substituteOut?: number;
117
+ minutes?: number;
118
+ minutesSubstitute?: number;
119
+ goals?: number;
120
+ goalsSubstitute?: number;
121
+ penaltyGoals?: number;
122
+ ownGoals?: number;
123
+ assists?: number;
124
+ shots?: number;
125
+ shotsOnTarget?: number;
126
+ yellowCards?: number;
127
+ redCards?: number;
128
+ foulsCommitted?: number;
129
+ penaltiesCommitted?: number;
130
+ penaltiesMissed?: number;
131
+ penaltiesReceived?: number;
132
+ penaltiesSaved?: number;
133
+ cleansheets?: number;
134
+ offsides?: number;
135
+ position?: string;
136
+ age?: number;
137
+ shirtNumber?: number | null;
138
+ }
139
+ /**
140
+ * A player's full career statistics across all tournaments and teams.
141
+ */
142
+ export interface FUSportsPlayerCareerStatistics {
143
+ playerId: string;
144
+ playerName: string;
145
+ playerUuid: string;
146
+ entries: FUSportsPlayerCareerStatisticsEntry[];
147
+ }
148
+ /**
149
+ * Player recent statistics - aggregated stats from a player's last N matches,
150
+ * along with the matches themselves and the teams they played for.
151
+ */
152
+ export interface FUSportsPlayerRecentStatistics {
153
+ playerId: string;
154
+ playerName: string;
155
+ playerUuid: string;
156
+ position: string;
157
+ /** Teams the player played for in the recent matches */
158
+ teams: FUSportsCareerTeam[];
159
+ /** The recent matches included in the statistics */
160
+ matches: import("./match.types").FUSportsMatch[];
161
+ appearances?: number;
162
+ started?: number;
163
+ substituteIn?: number;
164
+ substituteOut?: number;
165
+ minutes?: number;
166
+ minutesSubstitute?: number;
167
+ goals?: number;
168
+ goalsSubstitute?: number;
169
+ penaltyGoals?: number;
170
+ assists?: number;
171
+ yellowCards?: number;
172
+ redCards?: number;
173
+ rawStatistics?: FUSportsPlayerStatistic[];
174
+ }
73
175
  /**
74
176
  * Team seasonal statistics - aggregate stats for a team in a season
75
177
  */
@@ -1 +1 @@
1
- {"version":3,"file":"statistics.types.d.ts","sourceRoot":"","sources":["../../../src/lib/types/canonical/statistics.types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG,WAAW,GAAG,YAAY,GAAG,aAAa,GAAG,YAAY,CAAC;AAE5F;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACnC,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,mBAAmB,CAAC;CAChC;AAED;;GAEG;AACH,MAAM,WAAW,4BAA4B;IACzC,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,sBAAsB,EAAE,CAAC;CACxC;AAED;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACpC,aAAa,EAAE,4BAA4B,CAAC;IAC5C,aAAa,EAAE,4BAA4B,CAAC;CAC/C;AAMD;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,8BAA8B;IAC3C,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAGhB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAG3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IAGjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC;IAGvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAG5B,eAAe,CAAC,EAAE,MAAM,CAAC;IAGzB,WAAW,CAAC,EAAE,MAAM,CAAC;IAGrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAG3B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAGlB,UAAU,CAAC,EAAE,MAAM,CAAC;IAGpB,aAAa,CAAC,EAAE,uBAAuB,EAAE,CAAC;CAC7C;AAMD;;GAEG;AACH,MAAM,WAAW,4BAA4B;IACzC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,sBAAsB,EAAE,CAAC;CACxC"}
1
+ {"version":3,"file":"statistics.types.d.ts","sourceRoot":"","sources":["../../../src/lib/types/canonical/statistics.types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,105 @@
1
+ function calcPercentage(count, total) {
2
+ return total > 0 ? count / total * 100 : 0;
3
+ }
4
+ function calcAverage(sum, count) {
5
+ return count > 0 ? sum / count : 0;
6
+ }
7
+ function formatStatValue(value, isPercentage = false, decimals = 2) {
8
+ if (isPercentage) {
9
+ return `${Math.round(value)}%`;
10
+ }
11
+ if (Number.isInteger(value)) {
12
+ return value.toString();
13
+ }
14
+ return value.toFixed(decimals);
15
+ }
16
+ function formatWithAverage(total, matchesPlayed) {
17
+ const totalValue = typeof total === "string" ? parseFloat(total) : total;
18
+ if (isNaN(totalValue) || matchesPlayed === 0) return "0";
19
+ const average = (totalValue / matchesPlayed).toFixed(1);
20
+ return `${totalValue} (${average} avg)`;
21
+ }
22
+ function formatAsAverage(total, matchesPlayed) {
23
+ const totalValue = typeof total === "string" ? parseFloat(total) : total;
24
+ if (isNaN(totalValue) || matchesPlayed === 0) return "0.0";
25
+ return (totalValue / matchesPlayed).toFixed(1);
26
+ }
27
+ function formatPossessionPercentage(value) {
28
+ const numValue = parseFloat(value);
29
+ if (isNaN(numValue)) return "0%";
30
+ return `${Math.round(numValue)}%`;
31
+ }
32
+ function analyzeMatch(match, _teamId, isHome) {
33
+ if (match.status?.type !== "FINISHED") return null;
34
+ if (!match.score) return null;
35
+ const score1 = parseInt(match.score.competitorOne || "0");
36
+ const score2 = parseInt(match.score.competitorTwo || "0");
37
+ const goalsFor = isHome ? score1 : score2;
38
+ const goalsAgainst = isHome ? score2 : score1;
39
+ let halfTimeGoalsFor = null;
40
+ let halfTimeGoalsAgainst = null;
41
+ const halfTimeScore = match.score.breakdown?.halfTime;
42
+ if (halfTimeScore) {
43
+ const ht1 = parseInt(halfTimeScore.competitorOne || "0");
44
+ const ht2 = parseInt(halfTimeScore.competitorTwo || "0");
45
+ halfTimeGoalsFor = isHome ? ht1 : ht2;
46
+ halfTimeGoalsAgainst = isHome ? ht2 : ht1;
47
+ }
48
+ const stats = match.statistics;
49
+ let cornersFor = null;
50
+ let cornersAgainst = null;
51
+ if (stats) {
52
+ const cornerStat = stats.find?.((s) => s.type === "CORNERS");
53
+ if (cornerStat) {
54
+ cornersFor = isHome ? cornerStat.competitorOne : cornerStat.competitorTwo;
55
+ cornersAgainst = isHome ? cornerStat.competitorTwo : cornerStat.competitorOne;
56
+ }
57
+ }
58
+ return {
59
+ goalsFor,
60
+ goalsAgainst,
61
+ halfTimeGoalsFor,
62
+ halfTimeGoalsAgainst,
63
+ cornersFor,
64
+ cornersAgainst,
65
+ isWin: goalsFor > goalsAgainst,
66
+ isDraw: goalsFor === goalsAgainst,
67
+ isLoss: goalsFor < goalsAgainst
68
+ };
69
+ }
70
+ function isTeamHome(match, teamId) {
71
+ return match.competitorOne.id === teamId;
72
+ }
73
+ function isTeamAway(match, teamId) {
74
+ return match.competitorTwo.id === teamId;
75
+ }
76
+ function isTeamInMatch(match, teamId) {
77
+ return isTeamHome(match, teamId) || isTeamAway(match, teamId);
78
+ }
79
+ function isMatchFinished(match) {
80
+ return match.status?.type === "FINISHED";
81
+ }
82
+ function getTeamScore(match, teamId) {
83
+ const isHome = isTeamHome(match, teamId);
84
+ return parseInt(isHome ? match.score?.competitorOne || "0" : match.score?.competitorTwo || "0");
85
+ }
86
+ function getOpponentScore(match, teamId) {
87
+ const isHome = isTeamHome(match, teamId);
88
+ return parseInt(isHome ? match.score?.competitorTwo || "0" : match.score?.competitorOne || "0");
89
+ }
90
+ export {
91
+ analyzeMatch,
92
+ calcAverage,
93
+ calcPercentage,
94
+ formatAsAverage,
95
+ formatPossessionPercentage,
96
+ formatStatValue,
97
+ formatWithAverage,
98
+ getOpponentScore,
99
+ getTeamScore,
100
+ isMatchFinished,
101
+ isTeamAway,
102
+ isTeamHome,
103
+ isTeamInMatch
104
+ };
105
+ //# sourceMappingURL=helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helpers.js","sources":["../../../../src/lib/utilities/stats/core/helpers.ts"],"sourcesContent":["/**\n * Shared calculation helper functions.\n */\n\nimport type { FUSportsMatch } from \"../../../types/canonical\";\nimport type { MatchAnalysis } from \"./types\";\n\n/**\n * Calculate percentage from count and total.\n * @returns Percentage value (0-100)\n */\nexport function calcPercentage(count: number, total: number): number {\n return total > 0 ? (count / total) * 100 : 0;\n}\n\n/**\n * Calculate average from sum and count.\n */\nexport function calcAverage(sum: number, count: number): number {\n return count > 0 ? sum / count : 0;\n}\n\n/**\n * Format a number as a display value.\n * @param value - The numeric value to format\n * @param isPercentage - If true, appends % symbol\n * @param decimals - Number of decimal places (default: 2)\n */\nexport function formatStatValue(value: number, isPercentage = false, decimals = 2): string {\n if (isPercentage) {\n return `${Math.round(value)}%`;\n }\n if (Number.isInteger(value)) {\n return value.toString();\n }\n return value.toFixed(decimals);\n}\n\n/**\n * Format stats with total and average per match.\n * @example formatWithAverage(10, 5) => \"10 (2.0 avg)\"\n */\nexport function formatWithAverage(total: string | number, matchesPlayed: number): string {\n const totalValue = typeof total === \"string\" ? parseFloat(total) : total;\n if (isNaN(totalValue) || matchesPlayed === 0) return \"0\";\n const average = (totalValue / matchesPlayed).toFixed(1);\n return `${totalValue} (${average} avg)`;\n}\n\n/**\n * Format stats as average only.\n * @example formatAsAverage(10, 5) => \"2.0\"\n */\nexport function formatAsAverage(total: string | number, matchesPlayed: number): string {\n const totalValue = typeof total === \"string\" ? parseFloat(total) : total;\n if (isNaN(totalValue) || matchesPlayed === 0) return \"0.0\";\n return (totalValue / matchesPlayed).toFixed(1);\n}\n\n/**\n * Format possession percentage with % symbol.\n */\nexport function formatPossessionPercentage(value: string): string {\n const numValue = parseFloat(value);\n if (isNaN(numValue)) return \"0%\";\n return `${Math.round(numValue)}%`;\n}\n\n/**\n * Analyze a match from a team's perspective.\n * @returns MatchAnalysis or null if match is not finished\n */\nexport function analyzeMatch(match: FUSportsMatch, _teamId: string, isHome: boolean): MatchAnalysis | null {\n if (match.status?.type !== \"FINISHED\") return null;\n if (!match.score) return null;\n\n const score1 = parseInt(match.score.competitorOne || \"0\");\n const score2 = parseInt(match.score.competitorTwo || \"0\");\n\n const goalsFor = isHome ? score1 : score2;\n const goalsAgainst = isHome ? score2 : score1;\n\n // Try to get half-time scores from score breakdown\n let halfTimeGoalsFor: number | null = null;\n let halfTimeGoalsAgainst: number | null = null;\n\n const halfTimeScore = match.score.breakdown?.halfTime;\n if (halfTimeScore) {\n const ht1 = parseInt(halfTimeScore.competitorOne || \"0\");\n const ht2 = parseInt(halfTimeScore.competitorTwo || \"0\");\n halfTimeGoalsFor = isHome ? ht1 : ht2;\n halfTimeGoalsAgainst = isHome ? ht2 : ht1;\n }\n\n // Try to get corner stats from match statistics\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const stats = (match as any).statistics;\n let cornersFor: number | null = null;\n let cornersAgainst: number | null = null;\n\n if (stats) {\n const cornerStat = stats.find?.((s: { type?: string }) => s.type === \"CORNERS\");\n if (cornerStat) {\n cornersFor = isHome ? cornerStat.competitorOne : cornerStat.competitorTwo;\n cornersAgainst = isHome ? cornerStat.competitorTwo : cornerStat.competitorOne;\n }\n }\n\n return {\n goalsFor,\n goalsAgainst,\n halfTimeGoalsFor,\n halfTimeGoalsAgainst,\n cornersFor,\n cornersAgainst,\n isWin: goalsFor > goalsAgainst,\n isDraw: goalsFor === goalsAgainst,\n isLoss: goalsFor < goalsAgainst,\n };\n}\n\n/**\n * Check if a team is the home team in a match.\n */\nexport function isTeamHome(match: FUSportsMatch, teamId: string): boolean {\n return match.competitorOne.id === teamId;\n}\n\n/**\n * Check if a team is the away team in a match.\n */\nexport function isTeamAway(match: FUSportsMatch, teamId: string): boolean {\n return match.competitorTwo.id === teamId;\n}\n\n/**\n * Check if a team participates in a match.\n */\nexport function isTeamInMatch(match: FUSportsMatch, teamId: string): boolean {\n return isTeamHome(match, teamId) || isTeamAway(match, teamId);\n}\n\n/**\n * Check if a match is finished.\n */\nexport function isMatchFinished(match: FUSportsMatch): boolean {\n return match.status?.type === \"FINISHED\";\n}\n\n/**\n * Get team's score from a match.\n */\nexport function getTeamScore(match: FUSportsMatch, teamId: string): number {\n const isHome = isTeamHome(match, teamId);\n return parseInt(isHome ? match.score?.competitorOne || \"0\" : match.score?.competitorTwo || \"0\");\n}\n\n/**\n * Get opponent's score from a match.\n */\nexport function getOpponentScore(match: FUSportsMatch, teamId: string): number {\n const isHome = isTeamHome(match, teamId);\n return parseInt(isHome ? match.score?.competitorTwo || \"0\" : match.score?.competitorOne || \"0\");\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ const GOAL_EVENT_TYPES = ["GOAL", "PENALTY_GOAL", "OWN_GOAL"];
2
+ export {
3
+ GOAL_EVENT_TYPES
4
+ };
5
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sources":["../../../../src/lib/utilities/stats/core/types.ts"],"sourcesContent":["/**\n * Shared types for statistics calculations.\n */\n\nimport type { FUSportsMatch } from \"../../../types/canonical\";\n\n/**\n * Analyzed match data from a team's perspective.\n */\nexport interface MatchAnalysis {\n goalsFor: number;\n goalsAgainst: number;\n halfTimeGoalsFor: number | null;\n halfTimeGoalsAgainst: number | null;\n cornersFor: number | null;\n cornersAgainst: number | null;\n isWin: boolean;\n isDraw: boolean;\n isLoss: boolean;\n}\n\n/**\n * Match result from a team's perspective.\n */\nexport interface MatchResult {\n score: string;\n result: \"W\" | \"D\" | \"L\";\n isHome: boolean;\n}\n\n/**\n * Filter function type for match filtering.\n */\nexport type MatchFilter = (match: FUSportsMatch, teamId: string, isHome: boolean) => boolean;\n\n/**\n * Venue filter type.\n */\nexport type VenueFilter = \"home\" | \"away\";\n\n/**\n * Goal event types that count as a goal.\n */\nexport const GOAL_EVENT_TYPES = [\"GOAL\", \"PENALTY_GOAL\", \"OWN_GOAL\"] as const;\n"],"names":[],"mappings":"AA2CO,MAAM,mBAAmB,CAAC,QAAQ,gBAAgB,UAAU;"}
@@ -0,0 +1,83 @@
1
+ function calculateH2HStats(matches, homeTeamId, awayTeamId) {
2
+ const h2hMatches = matches.filter((m) => {
3
+ if (m.status?.type !== "FINISHED" || !m.score) return false;
4
+ const hasHomeTeam = m.competitorOne.id === homeTeamId || m.competitorTwo.id === homeTeamId;
5
+ const hasAwayTeam = m.competitorOne.id === awayTeamId || m.competitorTwo.id === awayTeamId;
6
+ return hasHomeTeam && hasAwayTeam;
7
+ });
8
+ let homeTeamWins = 0;
9
+ let awayTeamWins = 0;
10
+ let draws = 0;
11
+ let homeTeamGoals = 0;
12
+ let awayTeamGoals = 0;
13
+ h2hMatches.forEach((match) => {
14
+ const score1 = parseInt(match.score?.competitorOne || "0");
15
+ const score2 = parseInt(match.score?.competitorTwo || "0");
16
+ const isHomeTeamCompetitorOne = match.competitorOne.id === homeTeamId;
17
+ const homeGoals = isHomeTeamCompetitorOne ? score1 : score2;
18
+ const awayGoals = isHomeTeamCompetitorOne ? score2 : score1;
19
+ homeTeamGoals += homeGoals;
20
+ awayTeamGoals += awayGoals;
21
+ if (homeGoals > awayGoals) {
22
+ homeTeamWins++;
23
+ } else if (awayGoals > homeGoals) {
24
+ awayTeamWins++;
25
+ } else {
26
+ draws++;
27
+ }
28
+ });
29
+ const totalMatches = h2hMatches.length;
30
+ return {
31
+ totalMatches,
32
+ homeTeamWins,
33
+ awayTeamWins,
34
+ draws,
35
+ homeTeamGoals,
36
+ awayTeamGoals,
37
+ homeTeamWinPercentage: totalMatches > 0 ? homeTeamWins / totalMatches * 100 : 0,
38
+ awayTeamWinPercentage: totalMatches > 0 ? awayTeamWins / totalMatches * 100 : 0,
39
+ drawPercentage: totalMatches > 0 ? draws / totalMatches * 100 : 0,
40
+ homeTeamAvgGoals: totalMatches > 0 ? homeTeamGoals / totalMatches : 0,
41
+ awayTeamAvgGoals: totalMatches > 0 ? awayTeamGoals / totalMatches : 0
42
+ };
43
+ }
44
+ function getRecentH2HMeetings(matches, homeTeamId, awayTeamId, limit = 5) {
45
+ const h2hMatches = matches.filter((m) => {
46
+ if (m.status?.type !== "FINISHED" || !m.score) return false;
47
+ const hasHomeTeam = m.competitorOne.id === homeTeamId || m.competitorTwo.id === homeTeamId;
48
+ const hasAwayTeam = m.competitorOne.id === awayTeamId || m.competitorTwo.id === awayTeamId;
49
+ return hasHomeTeam && hasAwayTeam;
50
+ }).sort((a, b) => new Date(b.timing.kickoffTime).getTime() - new Date(a.timing.kickoffTime).getTime()).slice(0, limit);
51
+ return h2hMatches.map((match) => {
52
+ const score1 = parseInt(match.score?.competitorOne || "0");
53
+ const score2 = parseInt(match.score?.competitorTwo || "0");
54
+ const isHomeTeamCompetitorOne = match.competitorOne.id === homeTeamId;
55
+ const homeGoals = isHomeTeamCompetitorOne ? score1 : score2;
56
+ const awayGoals = isHomeTeamCompetitorOne ? score2 : score1;
57
+ let winner;
58
+ if (homeGoals > awayGoals) winner = "home";
59
+ else if (awayGoals > homeGoals) winner = "away";
60
+ else winner = "draw";
61
+ return {
62
+ id: match.id,
63
+ date: new Date(match.timing.kickoffTime).toLocaleDateString("en-GB", {
64
+ day: "numeric",
65
+ month: "short",
66
+ year: "numeric"
67
+ }),
68
+ homeTeamName: match.competitorOne.name,
69
+ awayTeamName: match.competitorTwo.name,
70
+ homeTeamLogo: match.competitorOne.assets?.logo,
71
+ awayTeamLogo: match.competitorTwo.assets?.logo,
72
+ homeScore: score1,
73
+ awayScore: score2,
74
+ venue: match.venue?.name,
75
+ winner
76
+ };
77
+ });
78
+ }
79
+ export {
80
+ calculateH2HStats,
81
+ getRecentH2HMeetings
82
+ };
83
+ //# sourceMappingURL=headToHead.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"headToHead.js","sources":["../../../../src/lib/utilities/stats/match/headToHead.ts"],"sourcesContent":["/**\n * Head-to-head statistics calculations between two teams.\n *\n * Note: To fetch H2H matches from the API, use `getFootballMatches` with both team IDs:\n *\n * ```typescript\n * import { getFootballMatches } from 'fansunited-data-layer';\n *\n * const h2hMatches = await getFootballMatches({\n * teamIds: [homeTeamId, awayTeamId],\n * teamIdsOperator: 'AND',\n * statusTypes: ['FINISHED'],\n * sortDirection: 'desc',\n * limit: 50,\n * offset: 0\n * });\n *\n * const stats = calculateH2HStats(h2hMatches, homeTeamId, awayTeamId);\n * ```\n */\n\nimport type { FUSportsMatch } from \"../../../types/canonical\";\n\nexport interface H2HStats {\n totalMatches: number;\n homeTeamWins: number;\n awayTeamWins: number;\n draws: number;\n homeTeamGoals: number;\n awayTeamGoals: number;\n homeTeamWinPercentage: number;\n awayTeamWinPercentage: number;\n drawPercentage: number;\n homeTeamAvgGoals: number;\n awayTeamAvgGoals: number;\n}\n\nexport interface H2HMatch {\n id: string;\n date: string;\n homeTeamName: string;\n awayTeamName: string;\n homeTeamLogo?: string;\n awayTeamLogo?: string;\n homeScore: number;\n awayScore: number;\n venue?: string;\n /** Which team won from perspective of the two teams we're comparing */\n winner: \"home\" | \"away\" | \"draw\";\n}\n\n/**\n * Calculate H2H statistics between two teams from an array of matches.\n *\n * The matches array should contain only matches between these two teams.\n * Use `getFootballMatches` with `teamIds` and `teamIdsOperator: 'AND'` to fetch H2H matches.\n *\n * @param matches - Array of matches between the two teams (fetch using getFootballMatches)\n * @param homeTeamId - ID of the home team in the current context\n * @param awayTeamId - ID of the away team in the current context\n * @returns H2H statistics\n */\nexport function calculateH2HStats(matches: FUSportsMatch[], homeTeamId: string, awayTeamId: string): H2HStats {\n // Filter for finished matches between the two teams\n const h2hMatches = matches.filter((m) => {\n if (m.status?.type !== \"FINISHED\" || !m.score) return false;\n // Ensure match is between the two specified teams\n const hasHomeTeam = m.competitorOne.id === homeTeamId || m.competitorTwo.id === homeTeamId;\n const hasAwayTeam = m.competitorOne.id === awayTeamId || m.competitorTwo.id === awayTeamId;\n return hasHomeTeam && hasAwayTeam;\n });\n\n let homeTeamWins = 0;\n let awayTeamWins = 0;\n let draws = 0;\n let homeTeamGoals = 0;\n let awayTeamGoals = 0;\n\n h2hMatches.forEach((match) => {\n const score1 = parseInt(match.score?.competitorOne || \"0\");\n const score2 = parseInt(match.score?.competitorTwo || \"0\");\n\n // Determine which competitor is our \"home\" team\n const isHomeTeamCompetitorOne = match.competitorOne.id === homeTeamId;\n\n const homeGoals = isHomeTeamCompetitorOne ? score1 : score2;\n const awayGoals = isHomeTeamCompetitorOne ? score2 : score1;\n\n homeTeamGoals += homeGoals;\n awayTeamGoals += awayGoals;\n\n if (homeGoals > awayGoals) {\n homeTeamWins++;\n } else if (awayGoals > homeGoals) {\n awayTeamWins++;\n } else {\n draws++;\n }\n });\n\n const totalMatches = h2hMatches.length;\n\n return {\n totalMatches,\n homeTeamWins,\n awayTeamWins,\n draws,\n homeTeamGoals,\n awayTeamGoals,\n homeTeamWinPercentage: totalMatches > 0 ? (homeTeamWins / totalMatches) * 100 : 0,\n awayTeamWinPercentage: totalMatches > 0 ? (awayTeamWins / totalMatches) * 100 : 0,\n drawPercentage: totalMatches > 0 ? (draws / totalMatches) * 100 : 0,\n homeTeamAvgGoals: totalMatches > 0 ? homeTeamGoals / totalMatches : 0,\n awayTeamAvgGoals: totalMatches > 0 ? awayTeamGoals / totalMatches : 0,\n };\n}\n\n/**\n * Get formatted list of recent H2H meetings.\n *\n * The matches array should contain only matches between these two teams.\n * Use `getFootballMatches` with `teamIds` and `teamIdsOperator: 'AND'` to fetch H2H matches.\n *\n * @param matches - Array of matches between the two teams (fetch using getFootballMatches)\n * @param homeTeamId - ID of the home team in the current context\n * @param awayTeamId - ID of the away team in the current context (used for determining winner perspective)\n * @param limit - Maximum number of recent meetings to return\n * @returns Array of formatted H2H matches\n */\nexport function getRecentH2HMeetings(\n matches: FUSportsMatch[],\n homeTeamId: string,\n awayTeamId: string,\n limit: number = 5\n): H2HMatch[] {\n const h2hMatches = matches\n .filter((m) => {\n if (m.status?.type !== \"FINISHED\" || !m.score) return false;\n // Ensure match is between the two specified teams\n const hasHomeTeam = m.competitorOne.id === homeTeamId || m.competitorTwo.id === homeTeamId;\n const hasAwayTeam = m.competitorOne.id === awayTeamId || m.competitorTwo.id === awayTeamId;\n return hasHomeTeam && hasAwayTeam;\n })\n .sort((a, b) => new Date(b.timing.kickoffTime).getTime() - new Date(a.timing.kickoffTime).getTime())\n .slice(0, limit);\n\n return h2hMatches.map((match) => {\n const score1 = parseInt(match.score?.competitorOne || \"0\");\n const score2 = parseInt(match.score?.competitorTwo || \"0\");\n\n // Determine winner from perspective of homeTeamId\n const isHomeTeamCompetitorOne = match.competitorOne.id === homeTeamId;\n const homeGoals = isHomeTeamCompetitorOne ? score1 : score2;\n const awayGoals = isHomeTeamCompetitorOne ? score2 : score1;\n\n let winner: \"home\" | \"away\" | \"draw\";\n if (homeGoals > awayGoals) winner = \"home\";\n else if (awayGoals > homeGoals) winner = \"away\";\n else winner = \"draw\";\n\n return {\n id: match.id,\n date: new Date(match.timing.kickoffTime).toLocaleDateString(\"en-GB\", {\n day: \"numeric\",\n month: \"short\",\n year: \"numeric\",\n }),\n homeTeamName: match.competitorOne.name,\n awayTeamName: match.competitorTwo.name,\n homeTeamLogo: match.competitorOne.assets?.logo,\n awayTeamLogo: match.competitorTwo.assets?.logo,\n homeScore: score1,\n awayScore: score2,\n venue: match.venue?.name,\n winner,\n };\n });\n}\n"],"names":[],"mappings":"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"}