Updated guild members
This commit is contained in:
257
src/app/(stats)/guild/[value]/_components/members.tsx
Normal file
257
src/app/(stats)/guild/[value]/_components/members.tsx
Normal file
@@ -0,0 +1,257 @@
|
||||
"use client"
|
||||
|
||||
import { Card, CardContent } from "@/components/ui/card"
|
||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
|
||||
import { getColor } from "@/lib/colors"
|
||||
import { formatDate, formatNumber } from "@/lib/formatters"
|
||||
import { head } from "@/lib/hypixel/general"
|
||||
import { Guild } from "@/lib/schema/guild"
|
||||
import { PlayerForGuild } from "@/lib/schema/player"
|
||||
import Image from "next/image"
|
||||
import Link from "next/link"
|
||||
import { useEffect, useState } from "react"
|
||||
|
||||
type MemberWithPlayer = Guild["guild"]["members"][number] & {
|
||||
player?: PlayerForGuild["player"]
|
||||
loading?: boolean
|
||||
error?: boolean
|
||||
}
|
||||
|
||||
export function GuildMembers({ members: mem }: { members: Guild["guild"]["members"] }) {
|
||||
const [members, setMembers] = useState<MemberWithPlayer[]>(
|
||||
mem.map(member => ({ ...member, loading: false, error: false }))
|
||||
)
|
||||
const [currentIndex, setCurrentIndex] = useState(0)
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
|
||||
const fetchMemberData = async (uuid: string, index: number) => {
|
||||
setMembers(prev => prev.map((member, i) => i === index ? { ...member, loading: true } : member))
|
||||
|
||||
try {
|
||||
const response = await fetch(`/api/guildmembers?uuid=${uuid}`)
|
||||
const data = await response.json()
|
||||
|
||||
if (data.error) {
|
||||
setMembers(prev => prev.map((member, i) => i === index ? { ...member, loading: false, error: true } : member))
|
||||
} else {
|
||||
setMembers(prev => prev.map((member, i) => i === index ? { ...member, loading: false, player: data.player } : member))
|
||||
}
|
||||
} catch {
|
||||
setMembers(prev => prev.map((member, i) => i === index ? { ...member, loading: false, error: true } : member))
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (currentIndex < members.length && !isLoading) {
|
||||
const timer = setTimeout(() => {
|
||||
setIsLoading(true)
|
||||
fetchMemberData(members[currentIndex].uuid, currentIndex).then(() => {
|
||||
setCurrentIndex(prev => prev + 1)
|
||||
setIsLoading(false)
|
||||
})
|
||||
}, 100)
|
||||
|
||||
return () => clearTimeout(timer)
|
||||
}
|
||||
}, [currentIndex, members, isLoading])
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead></TableHead>
|
||||
<TableHead>Name</TableHead>
|
||||
<TableHead>Rank</TableHead>
|
||||
<TableHead>Weekly GEXP</TableHead>
|
||||
<TableHead>Joined Since</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody className="space-y-4">
|
||||
{members.filter(member => member.player).map((member, i) => <MemberCard key={i} member={member} />)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
{currentIndex < members.length && (
|
||||
<div className="text-sm text-center text-muted-foreground">
|
||||
Loading members... ({members.filter(member => member.player).length}/{members.length})
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
function MemberCard({ member: m }: { member: MemberWithPlayer }) {
|
||||
return (
|
||||
<TableRow>
|
||||
<TableCell>
|
||||
<Link href={`https://namemc.com/profile/${m.uuid}`}>
|
||||
<Image
|
||||
src={head(m.uuid, 40)}
|
||||
width={40}
|
||||
height={40}
|
||||
alt={"Member head"}
|
||||
unoptimized
|
||||
className="shadow-2xl"
|
||||
/>
|
||||
</Link>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<PlayerRank
|
||||
rank={m.player?.newPackageRank}
|
||||
monthly={m.player?.monthlyPackageRank}
|
||||
rankColor={m.player?.monthlyRankColor}
|
||||
specialRank={m.player?.rank}
|
||||
prefix={m.player?.prefix}
|
||||
plusColor={m.player?.rankPlusColor}
|
||||
/>{" "}
|
||||
<PlayerIGN
|
||||
ign={m.player!.displayname}
|
||||
rank={m.player?.newPackageRank}
|
||||
monthly={m.player?.monthlyPackageRank}
|
||||
rankColor={m.player?.monthlyRankColor}
|
||||
specialRank={m.player?.rank}
|
||||
prefix={m.player?.prefix}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell>{m.rank}</TableCell>
|
||||
<TableCell>{formatNumber(Object.values(m.expHistory).reduce((a, b) => a + b))}</TableCell>
|
||||
<TableCell>{formatDate(m.joined)}</TableCell>
|
||||
</TableRow>
|
||||
)
|
||||
}
|
||||
|
||||
function PlayerIGN(
|
||||
{ ign, rank, monthly, rankColor, specialRank, prefix }: {
|
||||
ign: string
|
||||
rank: string | undefined
|
||||
monthly: string | undefined
|
||||
rankColor: string | undefined
|
||||
specialRank: string | undefined
|
||||
prefix: string | undefined
|
||||
}
|
||||
) {
|
||||
if (prefix === "[PIG+++]") {
|
||||
return <span className="text-mc-light-purple">{ign}</span>
|
||||
}
|
||||
|
||||
if (specialRank) {
|
||||
if (specialRank === "YOUTUBER") {
|
||||
return <span className="text-mc-red">{ign}</span>
|
||||
}
|
||||
|
||||
if (specialRank === "STAFF") {
|
||||
return <span className="text-mc-red">{ign}</span>
|
||||
}
|
||||
}
|
||||
|
||||
if (monthly === "SUPERSTAR") {
|
||||
if (rankColor === "GOLD") {
|
||||
return <span className="text-mc-gold">{ign}</span>
|
||||
} else {
|
||||
return <span className="text-mc-aqua">{ign}</span>
|
||||
}
|
||||
}
|
||||
|
||||
switch (rank) {
|
||||
case "VIP":
|
||||
return <span className="text-mc-green">{ign}</span>
|
||||
case "VIP_PLUS":
|
||||
return <span className="text-mc-green">{ign}</span>
|
||||
case "MVP":
|
||||
return <span className="text-mc-aqua">{ign}</span>
|
||||
case "MVP_PLUS":
|
||||
return <span className="text-mc-aqua">{ign}</span>
|
||||
default:
|
||||
return <span className="text-mc-gray">{ign}</span>
|
||||
}
|
||||
}
|
||||
|
||||
function PlayerRank(
|
||||
{ rank, monthly, plusColor, rankColor, specialRank, prefix }: {
|
||||
rank: string | undefined
|
||||
monthly: string | undefined
|
||||
plusColor?: string
|
||||
rankColor: string | undefined
|
||||
specialRank: string | undefined
|
||||
prefix: string | undefined
|
||||
}
|
||||
) {
|
||||
if (prefix === "[PIG+++]") {
|
||||
return (
|
||||
<>
|
||||
<span className="text-mc-light-purple">[PIG</span>
|
||||
<span className="text-mc-aqua">+++</span>
|
||||
<span className="text-mc-light-purple">]</span>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
if (specialRank) {
|
||||
if (specialRank === "YOUTUBER") {
|
||||
return (
|
||||
<>
|
||||
<span className="text-mc-red">[</span>
|
||||
<span className="text-mc-white">YOUTUBE</span>
|
||||
<span className="text-mc-red">]</span>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
if (specialRank === "STAFF") {
|
||||
return (
|
||||
<>
|
||||
<span className="text-mc-red">[</span>
|
||||
<span className="text-mc-gold">ዞ</span>
|
||||
<span className="text-mc-red">]</span>
|
||||
</>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (monthly === "SUPERSTAR") {
|
||||
if (rankColor === "GOLD") {
|
||||
return (
|
||||
<>
|
||||
<span className="text-mc-gold">[MVP</span>
|
||||
<span className={getColor(plusColor)}>++</span>
|
||||
<span className="text-mc-gold">]</span>
|
||||
</>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<>
|
||||
<span className="text-mc-aqua">[MVP</span>
|
||||
<span className={getColor(plusColor)}>++</span>
|
||||
<span className="text-mc-aqua">]</span>
|
||||
</>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
switch (rank) {
|
||||
case "VIP":
|
||||
return <span className="text-mc-green">[VIP]</span>
|
||||
case "VIP_PLUS":
|
||||
return (
|
||||
<>
|
||||
<span className="text-mc-green">[VIP</span>
|
||||
<span className="text-mc-gold">+</span>
|
||||
<span className="text-mc-green">]</span>
|
||||
</>
|
||||
)
|
||||
case "MVP":
|
||||
return <span className="text-mc-aqua">[MVP]</span>
|
||||
case "MVP_PLUS":
|
||||
return (
|
||||
<>
|
||||
<span className="text-mc-aqua">[MVP</span>
|
||||
<span className={getColor(plusColor)}>+</span>
|
||||
<span className="text-mc-aqua">]</span>
|
||||
</>
|
||||
)
|
||||
default:
|
||||
return null
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user