Files
hypixel-stats/src/app/(stats)/player/[ign]/_components/sidebar.tsx

256 lines
9.9 KiB
TypeScript

import { BasicSidebarItem, SidebarItem } from "@/app/(stats)/_components/sidebar"
import { Button } from "@/components/ui/button"
import { Card, CardContent } from "@/components/ui/card"
import { Separator } from "@/components/ui/separator"
import { getColor } from "@/lib/colors"
import { formatDate, formatNumber } from "@/lib/formatters"
import { getCoinMultiplier, getTotalChallenges, getTotalCoins, getTotalQuests, rewardClaimed } from "@/lib/hypixel/general/stats"
import { getGame, getGameMode } from "@/lib/hypixel/general/status"
import { getGuildMember, getGuildRankTag, getMemberGEXP, getMemberWeeklyGEXP } from "@/lib/hypixel/guild/guild"
import { Guild } from "@/lib/schema/guild"
import { Player } from "@/lib/schema/player"
import { Session } from "@/lib/schema/status"
import Link from "next/link"
import SocialIcons from "./social-icons"
type SidebarProps = {
level: number
ign: string
player: Player["player"]
guild: Guild["guild"] | undefined
rank: string | undefined
specialRank: string | undefined
eulaCoins: boolean | undefined
session: Session["session"] | null
}
export default function Sidebar({ level, ign, player, guild, rank, specialRank, eulaCoins, session }: SidebarProps) {
const levelMultiplier = getCoinMultiplier(level, rank, specialRank, eulaCoins)
const levelMultiplierVal = levelMultiplier.value
const levelMultiplierText = levelMultiplier.level === true ? `(Level ${level.toString().split(".")[0]})` : `(${levelMultiplier.name})`
function General() {
return (
<div className="flex justify-between px-8">
<div className="text-center">
<p>Hypixel level</p>
<p>{formatNumber(level)}</p>
</div>
<div className="text-center">
<p>Karma</p>
<p className="text-mc-light-purple">{formatNumber(player.karma)}</p>
</div>
</div>
)
}
function Coins() {
return (
<div>
<BasicSidebarItem title="Coin multiplier: " value={`x${levelMultiplierVal} ${levelMultiplierText}`} />
<SidebarItem title="Total coins: ">
<span className="text-mc-gold">
{formatNumber(getTotalCoins(player.stats))}
</span>
</SidebarItem>
</div>
)
}
function Other() {
return (
<div>
<p>
<span>
<Link href={`/achievements/${ign}`} className="font-bold underline">
Achievement Points
</Link>
</span>
<span className="font-bold">{": "}</span>
<span>{formatNumber(player.achievementPoints ?? 0)}</span>
</p>
<p>
<span>
<Link href={`/quests/${ign}`} className="font-bold underline">
Quests Completed
</Link>
</span>
<span className="font-bold">{": "}</span>
<span>{formatNumber(getTotalQuests(player.quests))}</span>
</p>
<BasicSidebarItem title="Challenges Completed: " value={formatNumber(getTotalChallenges(player.challenges))} />
</div>
)
}
function DailyRewards() {
return (
<div>
<SidebarItem title="Today's Reward: ">
<span
className={`${rewardClaimed(player.lastClaimedReward) === true ? "font-bold text-mc-green" : undefined}`}
>
{rewardClaimed(player.lastClaimedReward) ? "Claimed" : "Unclaimed"}
</span>
</SidebarItem>
<BasicSidebarItem title="Rewards Claimed: " value={player.totalRewards ?? 0} />
<BasicSidebarItem title="Reward Streak: " value={player.rewardStreak ?? 0} />
<BasicSidebarItem title="Top Reward Streak: " value={player.rewardHighScore ?? 0} />
</div>
)
}
function Gifting() {
return (
<div>
<BasicSidebarItem title="Gifts Given: " value={player.giftingMeta?.giftsGiven ?? 0} />
<BasicSidebarItem title="Ranks Given: " value={player.giftingMeta?.ranksGiven ?? 0} />
</div>
)
}
function Logins() {
return (
<div>
<BasicSidebarItem title="First Login: " value={formatDate(player.firstLogin ?? 0)} />
<BasicSidebarItem title="Last Login: " value={formatDate(player.lastLogin ?? 0)} />
</div>
)
}
function SkyblockButton() {
return (
<Button asChild variant="outline">
<Link href={`https://sky.shiiyu.moe/stats/${player.displayname}`}>
View SkyBlock Stats
</Link>
</Button>
)
}
function GuildInfo() {
if (!guild) return null
return (
<>
<div className="flex flex-col gap-8">
<div>
<Link href={`/guild/${ign}`}>
<h1 className="text-xl font-bold underline">Guild</h1>
</Link>
<SidebarItem title="Name: ">
<span className={getColor(guild.tagColor, "text", "gray")}>{guild.name}</span>
</SidebarItem>
<BasicSidebarItem title="Members: " value={guild.members.length} />
</div>
<div>
<SidebarItem title="Rank: ">
<span>{`${getGuildMember(guild, player.uuid)?.rank} `}</span>
<span className={getColor(guild.tagColor, "text", "gray")}>
{getGuildRankTag(guild, player.uuid)}
</span>
</SidebarItem>
<BasicSidebarItem title="Daily GEXP: " value={formatNumber(getMemberGEXP(guild, player.uuid, 0) ?? 0)} />
<BasicSidebarItem title="Weekly GEXP: " value={formatNumber(getMemberWeeklyGEXP(guild, player.uuid) ?? 0)} />
<BasicSidebarItem title="Joined: " value={formatDate(getGuildMember(guild, player.uuid)?.joined ?? 0)} />
</div>
</div>
<Separator className="my-4" />
</>
)
}
function OnlineStatus() {
if (!session?.online) {
return (
<>
<div className="flex flex-col gap-2">
<h2 className="text-xl font-bold">Online Status</h2>
<BasicSidebarItem title="Status: " value="Offline" />
</div>
<Separator className="my-4" />
</>
)
}
const noMapGameTypes = ["BUILD_BATTLE", "HOUSING", "REPLAY"]
const noMapArcadeModes = [
"DAYONE",
"DEFENDER",
"DRAGONWARS2",
"DROPPER",
"SOCCER",
"STARWARS",
"SIMON_SAYS",
"PARTY",
"DRAW_THEIR_THING",
"PIXEL_PARTY",
"THROW_OUT"
]
const showMode = !(session.gameType === "REPLAY")
const showMap = session.map !== undefined &&
session.gameType !== undefined &&
!noMapGameTypes.includes(session.gameType) &&
session.mode !== undefined &&
!(session.gameType === "ARCADE" && noMapArcadeModes.includes(session.mode))
const mode = session.mode === "LOBBY" ? "Lobby" : getGameMode(session.gameType, session.mode)
return (
<>
<div className="flex flex-col gap-2">
<h2 className="text-xl font-bold">Online Status</h2>
<div>
{session.gameType && <BasicSidebarItem title="Game: " value={getGame(session.gameType)?.name || "Unknown"} />}
{showMode && <BasicSidebarItem title="Mode: " value={mode || "Unknown"} />}
{showMap && <BasicSidebarItem title="Map: " value={session.map || "Unknown"} />}
</div>
</div>
<Separator className="my-4" />
</>
)
}
function SoicalLinks() {
return (
<div className="flex flex-col gap-2">
<h1 className="text-xl font-bold underline">Social Links</h1>
<div className="flex gap-2">
<SocialIcons
discord={player?.socialMedia?.links?.DISCORD}
twitch={player?.socialMedia?.links?.TWITCH}
youtube={player?.socialMedia?.links?.YOUTUBE}
twitter={player?.socialMedia?.links?.TWITTER}
hypixel={player?.socialMedia?.links?.HYPIXEL}
/>
</div>
</div>
)
}
return (
<Card className="mx-auto w-full lg:mx-0 lg:w-1/4 max-w-120 md:max-w-3/10">
<CardContent>
<General />
<Separator className="my-4" />
<Coins />
<Separator className="my-4" />
<Other />
<Separator className="my-4" />
<DailyRewards />
<Separator className="my-4" />
<Gifting />
<Separator className="my-4" />
<Logins />
<Separator className="my-4" />
<SkyblockButton />
<Separator className="my-4" />
<GuildInfo />
<OnlineStatus />
<SoicalLinks />
</CardContent>
</Card>
)
}