Added arena brawl stats card
This commit is contained in:
@@ -16,6 +16,7 @@ import ArcadeStats from "./_stats/arcade/arcade"
|
|||||||
import BedwarsStats from "./_stats/bedwars/bedwars"
|
import BedwarsStats from "./_stats/bedwars/bedwars"
|
||||||
import BlitzStats from "./_stats/blitz/blitz"
|
import BlitzStats from "./_stats/blitz/blitz"
|
||||||
import BuildBattleStats from "./_stats/build-battle/build-battle"
|
import BuildBattleStats from "./_stats/build-battle/build-battle"
|
||||||
|
import ClassicStats from "./_stats/classic/classic"
|
||||||
import CopsAndCrimsStats from "./_stats/copsandcrims/copsandcrims"
|
import CopsAndCrimsStats from "./_stats/copsandcrims/copsandcrims"
|
||||||
import DuelsStats from "./_stats/duels/duels"
|
import DuelsStats from "./_stats/duels/duels"
|
||||||
import MegaWallsStats from "./_stats/megawalls/megawalls"
|
import MegaWallsStats from "./_stats/megawalls/megawalls"
|
||||||
@@ -98,7 +99,8 @@ export function PlayerStats(
|
|||||||
"arcade": <ArcadeStats stats={stats.Arcade} />,
|
"arcade": <ArcadeStats stats={stats.Arcade} />,
|
||||||
"speeduhc": <SpeedUHCStats stats={stats.SpeedUHC} uhcCoins={stats.UHC?.coins} />,
|
"speeduhc": <SpeedUHCStats stats={stats.SpeedUHC} uhcCoins={stats.UHC?.coins} />,
|
||||||
"smashheros": <SmashHerosStats stats={stats.SmashHeros} />,
|
"smashheros": <SmashHerosStats stats={stats.SmashHeros} />,
|
||||||
"warlords": <WarlordsStats stats={stats.Warlords} />
|
"warlords": <WarlordsStats stats={stats.Warlords} />,
|
||||||
|
"classic": <ClassicStats arenaBrawlStats={stats.ArenaBrawl} />
|
||||||
} as const
|
} as const
|
||||||
|
|
||||||
const defaultOrder = Object.keys(statsComponents)
|
const defaultOrder = Object.keys(statsComponents)
|
||||||
|
|||||||
46
src/app/(stats)/player/[ign]/_stats/classic/arenabrawl.tsx
Normal file
46
src/app/(stats)/player/[ign]/_stats/classic/arenabrawl.tsx
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import { Separator } from "@/components/ui/separator"
|
||||||
|
import { formatNumber } from "@/lib/formatters"
|
||||||
|
import { devide } from "@/lib/hypixel/general"
|
||||||
|
import { NonNullStats } from "@/lib/schema/player"
|
||||||
|
import GeneralStats from "../GeneralStats"
|
||||||
|
import { ArenaBrawlGeneralStats } from "./stats"
|
||||||
|
import { ArenaBrawlModeStatsTable } from "./table"
|
||||||
|
|
||||||
|
export default function ArenaBrawlStats({ stats }: { stats: NonNullStats["ArenaBrawl"] }) {
|
||||||
|
if (!stats) return null
|
||||||
|
|
||||||
|
const kills = stats.kills_1v1 + stats.kills_2v2 + stats.kills_4v4
|
||||||
|
const deaths = stats.deaths_1v1 + stats.deaths_2v2 + stats.deaths_4v4
|
||||||
|
const wins = stats.wins_1v1 + stats.wins_2v2 + stats.wins_4v4
|
||||||
|
const losses = stats.losses_1v1 + stats.losses_2v2 + stats.losses_4v4
|
||||||
|
const ws = stats.win_streaks_1v1 + stats.win_streaks_2v2 + stats.win_streaks_4v4
|
||||||
|
const kd = formatNumber(devide(kills, deaths))
|
||||||
|
const wl = formatNumber(devide(wins, losses))
|
||||||
|
|
||||||
|
return (
|
||||||
|
<GeneralStats
|
||||||
|
id="classic-arena"
|
||||||
|
title="Arena Brawl"
|
||||||
|
collapsedStats={[
|
||||||
|
{
|
||||||
|
title: <p>KD</p>,
|
||||||
|
stat: <p className="text-muted-foreground">{kd}</p>
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: <p>Wins</p>,
|
||||||
|
stat: <p className="text-muted-foreground">{formatNumber(wins)}</p>
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: <p>WL</p>,
|
||||||
|
stat: <p className="text-muted-foreground">{wl}</p>
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Separator className="my-4" />
|
||||||
|
<ArenaBrawlGeneralStats coins={stats.coins} keys={stats.keys} ws={ws} />
|
||||||
|
<Separator className="my-4" />
|
||||||
|
<ArenaBrawlModeStatsTable stats={stats} />
|
||||||
|
<Separator className="my-4" />
|
||||||
|
</GeneralStats>
|
||||||
|
)
|
||||||
|
}
|
||||||
31
src/app/(stats)/player/[ign]/_stats/classic/classic.tsx
Normal file
31
src/app/(stats)/player/[ign]/_stats/classic/classic.tsx
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import { AccordionContent, AccordionItem, AccordionTrigger } from "@/components/ui/accordion"
|
||||||
|
import { Card, CardContent } from "@/components/ui/card"
|
||||||
|
import { NonNullStats } from "@/lib/schema/player"
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
import CollapsedStats from "../../_components/CollapsedStats"
|
||||||
|
import ArenaBrawlStats from "./arenabrawl"
|
||||||
|
|
||||||
|
export default function ClassicStats({ arenaBrawlStats }: { arenaBrawlStats: NonNullStats["ArenaBrawl"] }) {
|
||||||
|
return (
|
||||||
|
<AccordionItem value="classic">
|
||||||
|
<Card className="py-0">
|
||||||
|
<CardContent>
|
||||||
|
<AccordionTrigger className={cn("items-center py-2 hover:no-underline hover:cursor-pointer overflow-y-auto")}>
|
||||||
|
<h1 className="text-xl font-bold">Classic</h1>
|
||||||
|
<div className="flex gap-4">
|
||||||
|
<CollapsedStats
|
||||||
|
stats={[{
|
||||||
|
title: <p>Modes</p>,
|
||||||
|
stat: <p className="text-muted-foreground">Arena Brawl | Paintball | Quakecraft | TKR | VampireZ | Walls</p>
|
||||||
|
}]}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</AccordionTrigger>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
<AccordionContent className="pt-4 mx-auto w-[95%]">
|
||||||
|
<ArenaBrawlStats stats={arenaBrawlStats} />
|
||||||
|
</AccordionContent>
|
||||||
|
</AccordionItem>
|
||||||
|
)
|
||||||
|
}
|
||||||
12
src/app/(stats)/player/[ign]/_stats/classic/stats.tsx
Normal file
12
src/app/(stats)/player/[ign]/_stats/classic/stats.tsx
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import { formatNumber } from "@/lib/formatters"
|
||||||
|
import { BasicStat } from "../../_components/Stats"
|
||||||
|
|
||||||
|
export function ArenaBrawlGeneralStats({ coins, keys, ws }: { coins: number, keys: number, ws: number }) {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<BasicStat title="Coins: " value={formatNumber(coins)} className="text-mc-gold" />
|
||||||
|
<BasicStat title="Keys: " value={formatNumber(keys)} className="text-mc-aqua" />
|
||||||
|
<BasicStat title="Win Streaks: " value={formatNumber(ws)} className="text-mc-yellow" />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
69
src/app/(stats)/player/[ign]/_stats/classic/table.tsx
Normal file
69
src/app/(stats)/player/[ign]/_stats/classic/table.tsx
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
|
||||||
|
import { formatNumber } from "@/lib/formatters"
|
||||||
|
import { getArenaBrawlModeName, getArenaBrawlModeStats, getArenaBrawlMostPlayedMode, getArenaBrawlOverallStats } from "@/lib/hypixel/classic/general"
|
||||||
|
import { NonNullStats } from "@/lib/schema/player"
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
|
export function ArenaBrawlModeStatsTable({ stats }: { stats: NonNullable<NonNullStats["ArenaBrawl"]> }) {
|
||||||
|
return (
|
||||||
|
<Table>
|
||||||
|
<ArenaBrawlModeStatsTableHeader />
|
||||||
|
<TableBody>
|
||||||
|
<ArenaBrawlModeStat modeId="1v1" stats={stats} />
|
||||||
|
<ArenaBrawlModeStat modeId="2v2" stats={stats} />
|
||||||
|
<ArenaBrawlModeStat modeId="4v4" stats={stats} />
|
||||||
|
<ArenaBrawlModeStat modeId="all" stats={stats} />
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function ArenaBrawlModeStat(
|
||||||
|
{ modeId, stats }: { modeId: Parameters<typeof getArenaBrawlModeStats>[0] | "all", stats: NonNullable<NonNullStats["ArenaBrawl"]> }
|
||||||
|
) {
|
||||||
|
if (modeId === "all") {
|
||||||
|
const modeStats = getArenaBrawlOverallStats(stats)
|
||||||
|
return (
|
||||||
|
<TableRow className="font-bold">
|
||||||
|
<TableCell>Overall</TableCell>
|
||||||
|
{modeStats.map((v, i) => {
|
||||||
|
return <TableCell key={i}>{formatNumber(v)}</TableCell>
|
||||||
|
})}
|
||||||
|
</TableRow>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const modeStats = getArenaBrawlModeStats(modeId, stats)
|
||||||
|
const modeName = getArenaBrawlModeName(modeId)
|
||||||
|
const mostPlayed = getArenaBrawlMostPlayedMode(stats) === modeId
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TableRow className={cn(mostPlayed && "text-mc-light-purple")}>
|
||||||
|
<TableCell>{modeName}</TableCell>
|
||||||
|
{modeStats.map((v, i) => {
|
||||||
|
return <TableCell key={i}>{formatNumber(v)}</TableCell>
|
||||||
|
})}
|
||||||
|
</TableRow>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function ArenaBrawlModeStatsTableHeader() {
|
||||||
|
const headerElements = [
|
||||||
|
"Mode",
|
||||||
|
"Kills",
|
||||||
|
"Deaths",
|
||||||
|
"KD",
|
||||||
|
"Wins",
|
||||||
|
"Losses",
|
||||||
|
"WL",
|
||||||
|
"Win Streaks"
|
||||||
|
]
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TableHeader>
|
||||||
|
<TableRow>
|
||||||
|
{headerElements.map((v, i) => <TableHead key={i} className="font-bold">{v}</TableHead>)}
|
||||||
|
</TableRow>
|
||||||
|
</TableHeader>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -35,7 +35,7 @@ function WarlordsClassStatsTableStat(
|
|||||||
const mostPlayed = getWarlordsMostPlayedClass(stats)?.id === classId
|
const mostPlayed = getWarlordsMostPlayedClass(stats)?.id === classId
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TableRow className={cn(mostPlayed && "text-mc-light-purple")}>
|
<TableRow className={cn(mostPlayed && "text-mc-light-purple", classId === "all" && "font-bold")}>
|
||||||
{classId === "all" ?
|
{classId === "all" ?
|
||||||
(
|
(
|
||||||
<TableCell>
|
<TableCell>
|
||||||
|
|||||||
5
src/data/hypixel/classic.ts
Normal file
5
src/data/hypixel/classic.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export const ARENABRAWLMODES = [
|
||||||
|
{ id: "1v1", name: "1v1" },
|
||||||
|
{ id: "2v2", name: "2v2" },
|
||||||
|
{ id: "4v4", name: "4v4" }
|
||||||
|
] as const
|
||||||
56
src/lib/hypixel/classic/general.ts
Normal file
56
src/lib/hypixel/classic/general.ts
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
import { ARENABRAWLMODES } from "@/data/hypixel/classic"
|
||||||
|
import { NonNullStats } from "@/lib/schema/player"
|
||||||
|
import { devide } from "../general"
|
||||||
|
|
||||||
|
export function getArenaBrawlModeName(modeId: typeof ARENABRAWLMODES[number]["id"]) {
|
||||||
|
return ARENABRAWLMODES.find(m => m.id === modeId)!.name
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getArenaBrawlMostPlayedMode(stats: NonNullable<NonNullStats["ArenaBrawl"]>) {
|
||||||
|
let mostPlayedMode: typeof ARENABRAWLMODES[number] | null = null
|
||||||
|
let maxGames = 0
|
||||||
|
|
||||||
|
for (const mode of ARENABRAWLMODES) {
|
||||||
|
const wins = stats[`wins_${mode.id}`] || 0
|
||||||
|
const losses = stats[`losses_${mode.id}`] || 0
|
||||||
|
const totalGames = wins + losses
|
||||||
|
|
||||||
|
if (totalGames > maxGames) {
|
||||||
|
maxGames = totalGames
|
||||||
|
mostPlayedMode = mode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return mostPlayedMode?.id || null
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getArenaBrawlOverallStats(stats: NonNullable<NonNullStats["ArenaBrawl"]>) {
|
||||||
|
const allModeStats = ARENABRAWLMODES.map(mode => getArenaBrawlModeStats(mode.id, stats))
|
||||||
|
const totalKills = allModeStats.reduce((sum, modeStats) => sum + (modeStats[0] || 0), 0)
|
||||||
|
const totalDeaths = allModeStats.reduce((sum, modeStats) => sum + (modeStats[1] || 0), 0)
|
||||||
|
const totalWins = allModeStats.reduce((sum, modeStats) => sum + (modeStats[3] || 0), 0)
|
||||||
|
const totalLosses = allModeStats.reduce((sum, modeStats) => sum + (modeStats[4] || 0), 0)
|
||||||
|
const maxWinStreak = Math.max(...allModeStats.map(modeStats => modeStats[6] || 0))
|
||||||
|
|
||||||
|
return [
|
||||||
|
totalKills,
|
||||||
|
totalDeaths,
|
||||||
|
devide(totalKills, totalDeaths),
|
||||||
|
totalWins,
|
||||||
|
totalLosses,
|
||||||
|
devide(totalWins, totalLosses),
|
||||||
|
maxWinStreak
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getArenaBrawlModeStats(modeId: typeof ARENABRAWLMODES[number]["id"], stats: NonNullable<NonNullStats["ArenaBrawl"]>) {
|
||||||
|
return [
|
||||||
|
stats[`kills_${modeId}`],
|
||||||
|
stats[`deaths_${modeId}`],
|
||||||
|
devide(stats[`kills_${modeId}`], stats[`deaths_${modeId}`]),
|
||||||
|
stats[`wins_${modeId}`],
|
||||||
|
stats[`losses_${modeId}`],
|
||||||
|
devide(stats[`wins_${modeId}`], stats[`losses_${modeId}`]),
|
||||||
|
stats[`win_streaks_${modeId}`]
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ import { arcadeStatsSchema } from "./stats/arcade"
|
|||||||
import { bedwarsStatsSchema } from "./stats/bedwars"
|
import { bedwarsStatsSchema } from "./stats/bedwars"
|
||||||
import { blitzStatsSchema } from "./stats/blitz"
|
import { blitzStatsSchema } from "./stats/blitz"
|
||||||
import { buildBattleStatsSchema } from "./stats/build-battle"
|
import { buildBattleStatsSchema } from "./stats/build-battle"
|
||||||
|
import { arenaBrawlStatsSchema } from "./stats/classic"
|
||||||
import { copsAndCrimsStatsSchema } from "./stats/copsandcrims"
|
import { copsAndCrimsStatsSchema } from "./stats/copsandcrims"
|
||||||
import { duelsStatsSchema } from "./stats/duels"
|
import { duelsStatsSchema } from "./stats/duels"
|
||||||
import { megawallsStats } from "./stats/megawalls"
|
import { megawallsStats } from "./stats/megawalls"
|
||||||
@@ -44,14 +45,16 @@ export const playerSchema = z.looseObject({
|
|||||||
Arcade: arcadeStatsSchema.optional(),
|
Arcade: arcadeStatsSchema.optional(),
|
||||||
SpeedUHC: speedUhcStatsSchema.optional(),
|
SpeedUHC: speedUhcStatsSchema.optional(),
|
||||||
SuperSmash: smashHerosStats.optional(),
|
SuperSmash: smashHerosStats.optional(),
|
||||||
Battleground: warlordsStatsSchema.optional()
|
Battleground: warlordsStatsSchema.optional(),
|
||||||
}).transform(({ Walls3, MCGO, HungerGames, SuperSmash, Battleground, ...rest }) => {
|
Arena: arenaBrawlStatsSchema.optional()
|
||||||
|
}).transform(({ Walls3, MCGO, HungerGames, SuperSmash, Battleground, Arena, ...rest }) => {
|
||||||
return {
|
return {
|
||||||
MegaWalls: Walls3,
|
MegaWalls: Walls3,
|
||||||
CopsAndCrims: MCGO,
|
CopsAndCrims: MCGO,
|
||||||
Blitz: HungerGames,
|
Blitz: HungerGames,
|
||||||
SmashHeros: SuperSmash,
|
SmashHeros: SuperSmash,
|
||||||
Warlords: Battleground,
|
Warlords: Battleground,
|
||||||
|
ArenaBrawl: Arena,
|
||||||
...rest
|
...rest
|
||||||
}
|
}
|
||||||
}).optional(),
|
}).optional(),
|
||||||
|
|||||||
21
src/lib/schema/stats/classic.ts
Normal file
21
src/lib/schema/stats/classic.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import z from "zod"
|
||||||
|
|
||||||
|
export const arenaBrawlStatsSchema = z.object({
|
||||||
|
coins: z.number().default(0),
|
||||||
|
keys: z.number().default(0),
|
||||||
|
kills_1v1: z.number().default(0),
|
||||||
|
kills_2v2: z.number().default(0),
|
||||||
|
kills_4v4: z.number().default(0),
|
||||||
|
deaths_1v1: z.number().default(0),
|
||||||
|
deaths_2v2: z.number().default(0),
|
||||||
|
deaths_4v4: z.number().default(0),
|
||||||
|
wins_1v1: z.number().default(0),
|
||||||
|
wins_2v2: z.number().default(0),
|
||||||
|
wins_4v4: z.number().default(0),
|
||||||
|
losses_1v1: z.number().default(0),
|
||||||
|
losses_2v2: z.number().default(0),
|
||||||
|
losses_4v4: z.number().default(0),
|
||||||
|
win_streaks_1v1: z.number().default(0),
|
||||||
|
win_streaks_2v2: z.number().default(0),
|
||||||
|
win_streaks_4v4: z.number().default(0)
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user