Added stats for general modes
This commit is contained in:
111
src/app/(stats)/player/[ign]/_stats/bedwars/bedwars-table.tsx
Normal file
111
src/app/(stats)/player/[ign]/_stats/bedwars/bedwars-table.tsx
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
|
||||||
|
import { _BedwarsStats, getBedwarsModeStats } from "@/lib/hypixel/bedwars"
|
||||||
|
import { Player } from "@/lib/schema/player"
|
||||||
|
|
||||||
|
export default function BedwarsStatTable({ stats }: { stats: Player["player"]["stats"]["Bedwars"] }) {
|
||||||
|
return (
|
||||||
|
<Table>
|
||||||
|
<BedwarsTableHeader />
|
||||||
|
<TableBody>
|
||||||
|
<SoloStats stats={stats} />
|
||||||
|
<DoublesStats stats={stats} />
|
||||||
|
<ThreesStats stats={stats} />
|
||||||
|
<FoursStats stats={stats} />
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function BedwarsTableHeader() {
|
||||||
|
const headerElements = [
|
||||||
|
"Mode",
|
||||||
|
"Kills",
|
||||||
|
"Deaths",
|
||||||
|
"KD",
|
||||||
|
"Kills",
|
||||||
|
"Deaths",
|
||||||
|
"KD",
|
||||||
|
"Wins",
|
||||||
|
"Losses",
|
||||||
|
"WL",
|
||||||
|
"WS",
|
||||||
|
"BB",
|
||||||
|
"BL",
|
||||||
|
"BBL"
|
||||||
|
]
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TableHeader>
|
||||||
|
<TableRow>
|
||||||
|
<TableHead></TableHead>
|
||||||
|
<TableHead colSpan={3}>Normal</TableHead>
|
||||||
|
<TableHead colSpan={3}>Finals</TableHead>
|
||||||
|
</TableRow>
|
||||||
|
<TableRow>
|
||||||
|
{headerElements.map((v, i) => {
|
||||||
|
return <TableHead key={i}>{v}</TableHead>
|
||||||
|
})}
|
||||||
|
</TableRow>
|
||||||
|
</TableHeader>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function SoloStats({ stats }: { stats: Player["player"]["stats"]["Bedwars"] }) {
|
||||||
|
const modeStats = getBedwarsModeStats("solo", stats as _BedwarsStats)
|
||||||
|
|
||||||
|
if (!modeStats) return null
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TableRow>
|
||||||
|
<TableCell>Solo</TableCell>
|
||||||
|
{modeStats.map((v, i) => {
|
||||||
|
return <TableCell key={i}>{v}</TableCell>
|
||||||
|
})}
|
||||||
|
</TableRow>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function DoublesStats({ stats }: { stats: Player["player"]["stats"]["Bedwars"] }) {
|
||||||
|
const modeStats = getBedwarsModeStats("doubles", stats as _BedwarsStats)
|
||||||
|
|
||||||
|
if (!modeStats) return null
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TableRow>
|
||||||
|
<TableCell>Doubles</TableCell>
|
||||||
|
{modeStats.map((v, i) => {
|
||||||
|
return <TableCell key={i}>{v}</TableCell>
|
||||||
|
})}
|
||||||
|
</TableRow>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function ThreesStats({ stats }: { stats: Player["player"]["stats"]["Bedwars"] }) {
|
||||||
|
const modeStats = getBedwarsModeStats("3s", stats as _BedwarsStats)
|
||||||
|
|
||||||
|
if (!modeStats) return null
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TableRow>
|
||||||
|
<TableCell>3v3v3v3</TableCell>
|
||||||
|
{modeStats.map((v, i) => {
|
||||||
|
return <TableCell key={i}>{v}</TableCell>
|
||||||
|
})}
|
||||||
|
</TableRow>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function FoursStats({ stats }: { stats: Player["player"]["stats"]["Bedwars"] }) {
|
||||||
|
const modeStats = getBedwarsModeStats("4s", stats as _BedwarsStats)
|
||||||
|
|
||||||
|
if (!modeStats) return null
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TableRow>
|
||||||
|
<TableCell>4v4v4v4</TableCell>
|
||||||
|
{modeStats.map((v, i) => {
|
||||||
|
return <TableCell key={i}>{v}</TableCell>
|
||||||
|
})}
|
||||||
|
</TableRow>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -10,6 +10,7 @@ import { ChevronDown, ChevronUp, Menu } from "lucide-react"
|
|||||||
import { useEffect, useRef, useState } from "react"
|
import { useEffect, useRef, useState } from "react"
|
||||||
import CollapsedStats from "../../_components/CollapsedStats"
|
import CollapsedStats from "../../_components/CollapsedStats"
|
||||||
import { BedwarsLevel, BedwarsProgress } from "./bedwars-components"
|
import { BedwarsLevel, BedwarsProgress } from "./bedwars-components"
|
||||||
|
import BedwarsStatTable from "./bedwars-table"
|
||||||
import BedwarsGeneralStats from "./stats"
|
import BedwarsGeneralStats from "./stats"
|
||||||
|
|
||||||
export default function BedwarsStats({ stats }: { stats: Player["player"]["stats"]["Bedwars"] }) {
|
export default function BedwarsStats({ stats }: { stats: Player["player"]["stats"]["Bedwars"] }) {
|
||||||
@@ -97,6 +98,8 @@ export default function BedwarsStats({ stats }: { stats: Player["player"]["stats
|
|||||||
<Separator className="my-4" />
|
<Separator className="my-4" />
|
||||||
<BedwarsProgress level={level} percent={percent} />
|
<BedwarsProgress level={level} percent={percent} />
|
||||||
<BedwarsGeneralStats statsChecked={stats} level={level} percent={percent} bbl={bbl} kd={kd} fkd={fkd} wl={wl} />
|
<BedwarsGeneralStats statsChecked={stats} level={level} percent={percent} bbl={bbl} kd={kd} fkd={fkd} wl={wl} />
|
||||||
|
<Separator className="my-4" />
|
||||||
|
<BedwarsStatTable stats={stats} />
|
||||||
</CollapsibleContent>
|
</CollapsibleContent>
|
||||||
</Collapsible>
|
</Collapsible>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export default function BedwarsGeneralStats(
|
|||||||
const stats = statsChecked!
|
const stats = statsChecked!
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex">
|
<div className="flex mb-10">
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
<BasicStat title="Level: " value={`${level}.${percent.toFixed(0)}`} />
|
<BasicStat title="Level: " value={`${level}.${percent.toFixed(0)}`} />
|
||||||
<Stat title="Prestige: ">
|
<Stat title="Prestige: ">
|
||||||
|
|||||||
116
src/components/ui/table.tsx
Normal file
116
src/components/ui/table.tsx
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import * as React from "react"
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
|
function Table({ className, ...props }: React.ComponentProps<"table">) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
data-slot="table-container"
|
||||||
|
className="relative w-full overflow-x-auto"
|
||||||
|
>
|
||||||
|
<table
|
||||||
|
data-slot="table"
|
||||||
|
className={cn("w-full caption-bottom text-sm", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function TableHeader({ className, ...props }: React.ComponentProps<"thead">) {
|
||||||
|
return (
|
||||||
|
<thead
|
||||||
|
data-slot="table-header"
|
||||||
|
className={cn("[&_tr]:border-b", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function TableBody({ className, ...props }: React.ComponentProps<"tbody">) {
|
||||||
|
return (
|
||||||
|
<tbody
|
||||||
|
data-slot="table-body"
|
||||||
|
className={cn("[&_tr:last-child]:border-0", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function TableFooter({ className, ...props }: React.ComponentProps<"tfoot">) {
|
||||||
|
return (
|
||||||
|
<tfoot
|
||||||
|
data-slot="table-footer"
|
||||||
|
className={cn(
|
||||||
|
"bg-muted/50 border-t font-medium [&>tr]:last:border-b-0",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function TableRow({ className, ...props }: React.ComponentProps<"tr">) {
|
||||||
|
return (
|
||||||
|
<tr
|
||||||
|
data-slot="table-row"
|
||||||
|
className={cn(
|
||||||
|
"hover:bg-muted/50 data-[state=selected]:bg-muted border-b transition-colors",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function TableHead({ className, ...props }: React.ComponentProps<"th">) {
|
||||||
|
return (
|
||||||
|
<th
|
||||||
|
data-slot="table-head"
|
||||||
|
className={cn(
|
||||||
|
"text-foreground h-10 px-2 text-left align-middle font-medium whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function TableCell({ className, ...props }: React.ComponentProps<"td">) {
|
||||||
|
return (
|
||||||
|
<td
|
||||||
|
data-slot="table-cell"
|
||||||
|
className={cn(
|
||||||
|
"p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function TableCaption({
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<"caption">) {
|
||||||
|
return (
|
||||||
|
<caption
|
||||||
|
data-slot="table-caption"
|
||||||
|
className={cn("text-muted-foreground mt-4 text-sm", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
Table,
|
||||||
|
TableHeader,
|
||||||
|
TableBody,
|
||||||
|
TableFooter,
|
||||||
|
TableHead,
|
||||||
|
TableRow,
|
||||||
|
TableCell,
|
||||||
|
TableCaption,
|
||||||
|
}
|
||||||
@@ -18,4 +18,3 @@ export async function getPlayer(uuid: string) {
|
|||||||
|
|
||||||
return data.player
|
return data.player
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -60,3 +60,36 @@ export function getLatestRoom(rooms?: Record<string, boolean>) {
|
|||||||
|
|
||||||
return latestRoom
|
return latestRoom
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type _BedwarsStats = Record<string, number> & { [key: `${string}_winstreak`]: number | undefined }
|
||||||
|
|
||||||
|
export function getBedwarsModeStats(mode: "solo" | "doubles" | "3s" | "4s", stats: _BedwarsStats) {
|
||||||
|
switch (mode) {
|
||||||
|
case "solo":
|
||||||
|
return bedwarsModeStats("eight_one", stats)
|
||||||
|
case "doubles":
|
||||||
|
return bedwarsModeStats("eight_two", stats)
|
||||||
|
case "3s":
|
||||||
|
return bedwarsModeStats("four_three", stats)
|
||||||
|
case "4s":
|
||||||
|
return bedwarsModeStats("four_four", stats)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function bedwarsModeStats(prefix: string, stats: _BedwarsStats) {
|
||||||
|
return [
|
||||||
|
stats[`${prefix}_kills_bedwars`],
|
||||||
|
stats[`${prefix}_deaths_bedwars`],
|
||||||
|
(stats[`${prefix}_kills_bedwars`] / stats[`${prefix}_deaths_bedwars`]).toFixed(2),
|
||||||
|
stats[`${prefix}_final_kills_bedwars`],
|
||||||
|
stats[`${prefix}_final_deaths_bedwars`],
|
||||||
|
(stats[`${prefix}_final_kills_bedwars`] / stats[`${prefix}_final_deaths_bedwars`]).toFixed(2),
|
||||||
|
stats[`${prefix}_wins_bedwars`],
|
||||||
|
stats[`${prefix}_losses_bedwars`],
|
||||||
|
(stats[`${prefix}_wins_bedwars`] / stats[`${prefix}_losses_bedwars`]).toFixed(2),
|
||||||
|
stats[`${prefix}_winstreak`] ?? "?",
|
||||||
|
stats[`${prefix}_beds_broken_bedwars`],
|
||||||
|
stats[`${prefix}_beds_lost_bedwars`],
|
||||||
|
(stats[`${prefix}_beds_broken_bedwars`] / stats[`${prefix}_beds_lost_bedwars`]).toFixed(2)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ export async function validatePlayer(ign: string) {
|
|||||||
if (!uuid) {
|
if (!uuid) {
|
||||||
return {
|
return {
|
||||||
error: true,
|
error: true,
|
||||||
message: "Player not found",
|
message: "Player not found"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -18,12 +18,13 @@ export async function validatePlayer(ign: string) {
|
|||||||
if (!player) {
|
if (!player) {
|
||||||
return {
|
return {
|
||||||
error: true,
|
error: true,
|
||||||
message: "Player never logged on to Hypixel",
|
message: "Player never logged on to Hypixel"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
error: false,
|
error: false,
|
||||||
message: "Player found",
|
message: "Player found"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,43 @@ export const playerSchema = z.looseObject({
|
|||||||
total_tickets_earned: z.number(),
|
total_tickets_earned: z.number(),
|
||||||
doublers: z.number(),
|
doublers: z.number(),
|
||||||
room: z.record(z.string(), z.boolean())
|
room: z.record(z.string(), z.boolean())
|
||||||
}).optional()
|
}).optional(),
|
||||||
|
eight_one_winstreak: z.number().optional(),
|
||||||
|
eight_one_kills_bedwars: z.number().default(0),
|
||||||
|
eight_one_deaths_bedwars: z.number().default(0),
|
||||||
|
eight_one_final_kills_bedwars: z.number().default(0),
|
||||||
|
eight_one_final_deaths_bedwars: z.number().default(0),
|
||||||
|
eight_one_wins_bedwars: z.number().default(0),
|
||||||
|
eight_one_losses_bedwars: z.number().default(0),
|
||||||
|
eight_one_beds_broken_bedwars: z.number().default(0),
|
||||||
|
eight_one_beds_lost_bedwars: z.number().default(0),
|
||||||
|
eight_two_winstreak: z.number().optional(),
|
||||||
|
eight_two_kills_bedwars: z.number().default(0),
|
||||||
|
eight_two_deaths_bedwars: z.number().default(0),
|
||||||
|
eight_two_final_kills_bedwars: z.number().default(0),
|
||||||
|
eight_two_final_deaths_bedwars: z.number().default(0),
|
||||||
|
eight_two_wins_bedwars: z.number().default(0),
|
||||||
|
eight_two_losses_bedwars: z.number().default(0),
|
||||||
|
eight_two_beds_broken_bedwars: z.number().default(0),
|
||||||
|
eight_two_beds_lost_bedwars: z.number().default(0),
|
||||||
|
four_three_winstreak: z.number().optional(),
|
||||||
|
four_three_kills_bedwars: z.number().default(0),
|
||||||
|
four_three_deaths_bedwars: z.number().default(0),
|
||||||
|
four_three_final_kills_bedwars: z.number().default(0),
|
||||||
|
four_three_final_deaths_bedwars: z.number().default(0),
|
||||||
|
four_three_wins_bedwars: z.number().default(0),
|
||||||
|
four_three_losses_bedwars: z.number().default(0),
|
||||||
|
four_three_beds_broken_bedwars: z.number().default(0),
|
||||||
|
four_three_beds_lost_bedwars: z.number().default(0),
|
||||||
|
four_four_winstreak: z.number().optional(),
|
||||||
|
four_four_kills_bedwars: z.number().default(0),
|
||||||
|
four_four_deaths_bedwars: z.number().default(0),
|
||||||
|
four_four_final_kills_bedwars: z.number().default(0),
|
||||||
|
four_four_final_deaths_bedwars: z.number().default(0),
|
||||||
|
four_four_wins_bedwars: z.number().default(0),
|
||||||
|
four_four_losses_bedwars: z.number().default(0),
|
||||||
|
four_four_beds_broken_bedwars: z.number().default(0),
|
||||||
|
four_four_beds_lost_bedwars: z.number().default(0)
|
||||||
}).optional()
|
}).optional()
|
||||||
}),
|
}),
|
||||||
quests: z.record(
|
quests: z.record(
|
||||||
|
|||||||
50
đ
50
đ
@@ -1,50 +0,0 @@
|
|||||||
import { PRESTIGE_ICONS, PRESTIGES, SLUMBER_WALLETS } from "@/data/hypixel/bedwars"
|
|
||||||
import { floorLevel } from "./formatters"
|
|
||||||
|
|
||||||
export function getBedwarsStar(level: number) {
|
|
||||||
if (level < 1100) {
|
|
||||||
return PRESTIGE_ICONS[0].symbol
|
|
||||||
}
|
|
||||||
|
|
||||||
if (level > 1100 && level < 2100) {
|
|
||||||
return PRESTIGE_ICONS[1].symbol
|
|
||||||
}
|
|
||||||
|
|
||||||
if (level > 2100 && level < 3100) {
|
|
||||||
return PRESTIGE_ICONS[2].symbol
|
|
||||||
}
|
|
||||||
|
|
||||||
return PRESTIGE_ICONS[3].symbol
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getTextColor(level: number) {
|
|
||||||
const floored = floorLevel(level, 100)
|
|
||||||
|
|
||||||
if (level > 5000) {
|
|
||||||
return PRESTIGES[PRESTIGES.length - 1].color
|
|
||||||
}
|
|
||||||
|
|
||||||
return PRESTIGES.find(l => l.level === floored)!.color
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getPrestigeName(level: number) {
|
|
||||||
const floored = floorLevel(level, 100)
|
|
||||||
|
|
||||||
if (level > 5000) {
|
|
||||||
return PRESTIGES[PRESTIGES.length - 1].name
|
|
||||||
}
|
|
||||||
|
|
||||||
return PRESTIGES.find(p => p.level === floored)!.name
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getWalletMax(name?: string) {
|
|
||||||
if (!name) return 25
|
|
||||||
|
|
||||||
const wallets = SLUMBER_WALLETS as Record<string, number>
|
|
||||||
|
|
||||||
if (!wallets[name]) return 25
|
|
||||||
|
|
||||||
return wallets[name]
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getLatesRoom(rooms: Record<string, boolean>)
|
|
||||||
52
ž
52
ž
@@ -1,52 +0,0 @@
|
|||||||
import { PRESTIGE_ICONS, PRESTIGES, SLUMBER_WALLETS } from "@/data/hypixel/bedwars"
|
|
||||||
import { floorLevel } from "./formatters"
|
|
||||||
|
|
||||||
export function getBedwarsStar(level: number) {
|
|
||||||
if (level < 1100) {
|
|
||||||
return PRESTIGE_ICONS[0].symbol
|
|
||||||
}
|
|
||||||
|
|
||||||
if (level > 1100 && level < 2100) {
|
|
||||||
return PRESTIGE_ICONS[1].symbol
|
|
||||||
}
|
|
||||||
|
|
||||||
if (level > 2100 && level < 3100) {
|
|
||||||
return PRESTIGE_ICONS[2].symbol
|
|
||||||
}
|
|
||||||
|
|
||||||
return PRESTIGE_ICONS[3].symbol
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getTextColor(level: number) {
|
|
||||||
const floored = floorLevel(level, 100)
|
|
||||||
|
|
||||||
if (level > 5000) {
|
|
||||||
return PRESTIGES[PRESTIGES.length - 1].color
|
|
||||||
}
|
|
||||||
|
|
||||||
return PRESTIGES.find(l => l.level === floored)!.color
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getPrestigeName(level: number) {
|
|
||||||
const floored = floorLevel(level, 100)
|
|
||||||
|
|
||||||
if (level > 5000) {
|
|
||||||
return PRESTIGES[PRESTIGES.length - 1].name
|
|
||||||
}
|
|
||||||
|
|
||||||
return PRESTIGES.find(p => p.level === floored)!.name
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getWalletMax(name?: string) {
|
|
||||||
if (!name) return 25
|
|
||||||
|
|
||||||
const wallets = SLUMBER_WALLETS as Record<string, number>
|
|
||||||
|
|
||||||
if (!wallets[name]) return 25
|
|
||||||
|
|
||||||
return wallets[name]
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getLatesRoom(rooms?: Record<string, boolean>) {
|
|
||||||
if (!rooms) return null
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user