Skip to content

Commit

Permalink
Merge pull request #75 from qlemaire22/add-player-statistics-page
Browse files Browse the repository at this point in the history
Add player statistics page
  • Loading branch information
robertvanhoesel authored Feb 16, 2024
2 parents 5c7a4d7 + c8c7b3a commit b2a65ac
Show file tree
Hide file tree
Showing 15 changed files with 265 additions and 81 deletions.
31 changes: 31 additions & 0 deletions src/components/widgets/FactionDropdown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { createEffect, createSignal, onMount } from "solid-js"
import { SelectButton, type SelectButtonOption } from "../ui/SelectButton"
import infernals from "../../assets/game/factions/infernals-small-glow.png"
import vanguard from "../../assets/game/factions/vanguard-small-glow.png"
import { Race } from "../../lib/api"

const factionOptions: SelectButtonOption[] = [
{
label: "Infernals",
value: Race.INFERNALS,
icon: infernals.src,
},
{ label: "Vanguard", value: Race.VANGUARD, icon: vanguard.src },
]

export function FactionDropdown(props: { queryParam: string; selected: (typeof factionOptions)[number]["value"] }) {
const selected = props.selected ?? "all"
const [faction, setFaction] = createSignal(
factionOptions.find((option) => option.value === selected) || factionOptions[0]
)

createEffect(() => {
const urlParams = new URLSearchParams(window.location.search)
if (faction()?.value === selected) return
if (faction()?.value && faction()?.value != "all") urlParams.set(props.queryParam, faction()?.value!)
else urlParams.delete(props.queryParam)
window.location.href = `${window.location.pathname}${urlParams.size ? "?" + urlParams.toString() : ""}`
})

return <SelectButton options={factionOptions} value={faction} setValue={setFaction} />
}
1 change: 1 addition & 0 deletions src/components/widgets/GameLengthChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ export function GameLengthChart(props: GameLengthProps) {
intersect: false,
mode: "index",
},
maxBarThickness: 50,
plugins: {
title: {
display: false,
Expand Down
70 changes: 70 additions & 0 deletions src/components/widgets/MmrHistoryChart.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// @ts-nocheck

import { onMount } from "solid-js"
import { Chart, Title, Tooltip, Colors, TimeScale, type ChartOptions, type ChartData } from "chart.js"
import { Line } from "solid-chartjs"
import "chartjs-adapter-date-fns"

type MmrHistoryChartProps = {
labels: string[]
data: number[]
}

const longNumberFormatter = new Intl.NumberFormat("en-us")

export function MmrHistoryChart(props: MmrHistoryChartProps) {
let canvas: HTMLCanvasElement
onMount(() => {
Chart.register(Title, Tooltip, Colors, TimeScale)
})

const chartData: ChartData = {
labels: props.labels,
datasets: [
{
label: "MMR",
data: props.data,
tension: 0.3,
borderColor: "#9E9E9E",
pointRadius: 5,
pointHoverRadius: 2,
pointBorderColor: "transparent",
},
],
}

const chartOptions: ChartOptions = {
responsive: true,
maintainAspectRatio: true,
interaction: {
intersect: false,
mode: "index",
},
scales: {
y: {
ticks: {
precision: 0,
},
offset: true,
},
x: {
type: "time",
time: { unit: "day", tooltipFormat: "d MMM, y" },
},
},
plugins: {
tooltip: {
displayColors: false,
callbacks: {
label: (c) => `MMR: ${Math.round(c.parsed.y)}`,
},
},
},
}

return (
<div class="relative w-full overflow-hidden">
<Line data={chartData} options={chartOptions} height={100} width={300} ref={(c) => (canvas = c)} />
</div>
)
}
1 change: 1 addition & 0 deletions src/layouts/PlayerLayout.astro
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ const playerInfo = (await getCollection("players")).find((p) => p.data.playerId
current={[
{ href: `/players/${slug}`, label: "Overview" },
{ href: `/players/${slug}/matches`, label: "Match History" },
{ href: `/players/${slug}/statistics`, label: "Statistics" },
]}
/>
<HeaderContent>
Expand Down
5 changes: 3 additions & 2 deletions src/lib/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@ export type { ActivityStatistics } from "./models/ActivityStatistics"
export type { ActivityStatisticsActivity } from "./models/ActivityStatisticsActivity"
export type { ActivityStatisticsEntry } from "./models/ActivityStatisticsEntry"
export type { ActivityStatisticsServerEntry } from "./models/ActivityStatisticsServerEntry"
export { Aggregation } from "./models/Aggregation"
export type { ErrorResponse } from "./models/ErrorResponse"
export { Leaderboard } from "./models/Leaderboard"
export type { LeaderboardDumpResponse } from "./models/LeaderboardDumpResponse"
export type { LeaderboardEntryHistory } from "./models/LeaderboardEntryHistory"
export type { LeaderboardEntryHistoryEntry } from "./models/LeaderboardEntryHistoryEntry"
export type { LeaderboardEntryHistoryRow } from "./models/LeaderboardEntryHistoryRow"
export type { LeaderboardEntryResponse } from "./models/LeaderboardEntryResponse"
export { LeaderboardOrder } from "./models/LeaderboardOrder"
export type { LeaderboardResponse } from "./models/LeaderboardResponse"
Expand All @@ -35,13 +36,13 @@ export type { PlayerMatchupsStatsEntry } from "./models/PlayerMatchupsStatsEntry
export type { PlayerMatchupsStatsMatchup } from "./models/PlayerMatchupsStatsMatchup"
export type { PlayerOpponentsStats } from "./models/PlayerOpponentsStats"
export type { PlayerOpponentsStatsOpponent } from "./models/PlayerOpponentsStatsOpponent"
export type { PlayerPreferences } from "./models/PlayerPreferences"
export type { PlayerResponse } from "./models/PlayerResponse"
export type { PlayerStatsEntry } from "./models/PlayerStatsEntry"
export type { PlayerStatsEntryAggregated } from "./models/PlayerStatsEntryAggregated"
export type { PlayerStatsEntryNumBreakdown } from "./models/PlayerStatsEntryNumBreakdown"
export { ProfilePrivacy } from "./models/ProfilePrivacy"
export { Race } from "./models/Race"
export { Resolution } from "./models/Resolution"
export type { StatsByTime } from "./models/StatsByTime"
export type { StatsByTimeEntry } from "./models/StatsByTimeEntry"
export type { StatsByTimeHistoryPoint } from "./models/StatsByTimeHistoryPoint"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
import type { ProfilePrivacy } from "./ProfilePrivacy"
export type PlayerPreferences = {
privacy_profile?: ProfilePrivacy | null
export enum Aggregation {
LAST = "last",
MAX_MMR = "max_mmr",
MAX_POINTS = "max_points",
}
9 changes: 7 additions & 2 deletions src/lib/api/models/LeaderboardEntryHistory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
import type { LeaderboardEntryHistoryEntry } from "./LeaderboardEntryHistoryEntry"
import type { Aggregation } from "./Aggregation"
import type { LeaderboardEntryHistoryRow } from "./LeaderboardEntryHistoryRow"
import type { Resolution } from "./Resolution"
export type LeaderboardEntryHistory = {
history: Array<LeaderboardEntryHistoryEntry>
cached_at: string
resolution: Resolution
aggregation: Aggregation
history: Array<LeaderboardEntryHistoryRow>
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
export type LeaderboardEntryHistoryEntry = {
export type LeaderboardEntryHistoryRow = {
time: string
mmr: number
max_confirmed_mmr?: number | null
mmr?: number | null
points?: number | null
}
1 change: 0 additions & 1 deletion src/lib/api/models/Race.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,4 @@
export enum Race {
INFERNALS = "infernals",
VANGUARD = "vanguard",
RANDOM = "random",
}
10 changes: 10 additions & 0 deletions src/lib/api/models/Resolution.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/* generated using openapi-typescript-codegen -- do no edit */
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
export enum Resolution {
MINUTE = "minute",
HOUR = "hour",
DAY = "day",
WEEK = "week",
}
10 changes: 10 additions & 0 deletions src/lib/api/services/LeaderboardEntriesApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
import type { Aggregation } from "../models/Aggregation"
import type { LeaderboardEntryHistory } from "../models/LeaderboardEntryHistory"
import type { Resolution } from "../models/Resolution"
import type { CancelablePromise } from "../core/CancelablePromise"
import { OpenAPI } from "../core/OpenAPI"
import { request as __request } from "../core/request"
Expand All @@ -13,18 +15,26 @@ export class LeaderboardEntriesApi {
*/
public static getLeaderboardEntryHistory({
leaderboardEntryId,
resolution,
aggregation,
}: {
/**
* Player Leaderboard Entry ID
*/
leaderboardEntryId: string
resolution?: Resolution | null
aggregation?: Aggregation | null
}): CancelablePromise<LeaderboardEntryHistory> {
return __request(OpenAPI, {
method: "GET",
url: "/v0/leaderboard-entries/{leaderboard_entry_id}/history",
path: {
leaderboard_entry_id: leaderboardEntryId,
},
query: {
resolution: resolution,
aggregation: aggregation,
},
errors: {
404: `Player leaderboard entry was not found`,
500: `Server error`,
Expand Down
56 changes: 3 additions & 53 deletions src/lib/api/services/PlayersApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import type { PlayerActivityStats } from "../models/PlayerActivityStats"
import type { PlayerMatchesResponse } from "../models/PlayerMatchesResponse"
import type { PlayerMatchupsStats } from "../models/PlayerMatchupsStats"
import type { PlayerOpponentsStats } from "../models/PlayerOpponentsStats"
import type { PlayerPreferences } from "../models/PlayerPreferences"
import type { PlayerResponse } from "../models/PlayerResponse"
import type { Race } from "../models/Race"
import type { CancelablePromise } from "../core/CancelablePromise"
Expand Down Expand Up @@ -45,6 +44,7 @@ export class PlayersApi {
public static getPlayerMatches({
playerId,
race,
opponentPlayerId,
page,
count,
}: {
Expand All @@ -53,6 +53,7 @@ export class PlayersApi {
*/
playerId: string
race?: Race | null
opponentPlayerId?: string | null
page?: number | null
count?: number | null
}): CancelablePromise<PlayerMatchesResponse> {
Expand All @@ -64,6 +65,7 @@ export class PlayersApi {
},
query: {
race: race,
opponent_player_id: opponentPlayerId,
page: page,
count: count,
},
Expand Down Expand Up @@ -97,58 +99,6 @@ export class PlayersApi {
},
})
}
/**
* @returns PlayerPreferences Player found successfully
* @throws ApiError
*/
public static getPlayerPreferences({
playerId,
}: {
/**
* Player ID
*/
playerId: string
}): CancelablePromise<PlayerPreferences> {
return __request(OpenAPI, {
method: "GET",
url: "/v0/players/{player_id}/preferences",
path: {
player_id: playerId,
},
errors: {
404: `Player was not found`,
500: `Server error`,
},
})
}
/**
* @returns PlayerPreferences Player preferences updated successfully
* @throws ApiError
*/
public static updatePlayerPreferences({
playerId,
requestBody,
}: {
/**
* Player ID
*/
playerId: string
requestBody: PlayerPreferences
}): CancelablePromise<PlayerPreferences> {
return __request(OpenAPI, {
method: "PUT",
url: "/v0/players/{player_id}/preferences",
path: {
player_id: playerId,
},
body: requestBody,
mediaType: "application/json",
errors: {
404: `Player was not found`,
500: `Server error`,
},
})
}
/**
* @returns PlayerActivityStats Player found successfully
* @throws ApiError
Expand Down
1 change: 0 additions & 1 deletion src/lib/labels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { League, Race } from "./api"
export const raceLabels: Record<Race, string> = {
infernals: "Infernals",
vanguard: "Vanguard",
random: "Random",
}

export const leagueLabels: Record<League, string> = {
Expand Down
18 changes: 2 additions & 16 deletions src/pages/players/[id]-[username]/matches.astro
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,13 @@ import PlayerLayout from "../../../layouts/PlayerLayout.astro"
import { MatchHistory } from "../../../components/widgets/MatchHistory.tsx"
import { PlayersApi, Race } from "../../../lib/api"
import Section from "../../../components/layout/Section.astro"
import { getDataOrErrorResponse } from "../../../lib/utils"
const { page = 1, faction } = Object.fromEntries(new URL(Astro.request.url).searchParams.entries())
// to be moved to own file
async function getDataOrErrorResponse<T extends readonly unknown[] | []>(
...values: T
): Promise<[{ -readonly [P in keyof T]: Awaited<T[P]> }, error: Response | null]> {
try {
const result = await Promise.all(values)
return [result, null]
} catch (e) {
return [[] as any, new Response(null, { status: 500, statusText: `${e}` })]
}
}
const playerId = Astro.params.id!
const [[player], error] = await getDataOrErrorResponse(
PlayersApi.getPlayer({ playerId }),
PlayersApi.getPlayerMatches({ playerId })
)
const [[player], error] = await getDataOrErrorResponse(PlayersApi.getPlayer({ playerId }))
if (error) return error
---

Expand Down
Loading

0 comments on commit b2a65ac

Please sign in to comment.