Moved to react query

This commit is contained in:
2025-09-29 22:55:35 +02:00
parent 752c9f2a21
commit d6cc69b770
3 changed files with 60 additions and 48 deletions

View File

@@ -7,10 +7,9 @@ import { formatDate, formatNumber } from "@/lib/formatters"
import { head } from "@/lib/hypixel/general"
import { Guild } from "@/lib/schema/guild"
import { playerForGuildSchema } from "@/lib/schema/player"
import { QueryClient, QueryClientProvider, useQuery } from "@tanstack/react-query"
import Image from "next/image"
import Link from "next/link"
import { useEffect, useState } from "react"
import { toast } from "sonner"
import z from "zod"
type PlayerForGuild = z.infer<typeof playerForGuildSchema>
@@ -20,48 +19,69 @@ type MemberWithPlayer = Guild["guild"]["members"][number] & {
error?: boolean
}
export function GuildMembers({ members: mem, ranks }: { members: Guild["guild"]["members"], ranks: Guild["guild"]["ranks"] }) {
const [members, setMembers] = useState<MemberWithPlayer[]>(
mem.map(member => ({ ...member, loading: false, error: false }))
const queryClient = new QueryClient()
export function GuildMembers({ members, ranks }: { members: Guild["guild"]["members"], ranks: Guild["guild"]["ranks"] }) {
return (
<QueryClientProvider client={queryClient}>
<GuildMembersInternal members={members} ranks={ranks} />
</QueryClientProvider>
)
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 {
function useMemberData(uuid: string) {
return useQuery({
queryKey: ["guildMember", uuid],
queryFn: async () => {
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))
throw new Error(data.message || "Failed to fetch member data")
}
} catch {
setMembers(prev => prev.map((member, i) => i === index ? { ...member, loading: false, error: true } : member))
}
return data.player as PlayerForGuild["player"]
},
staleTime: 24 * 60 * 60 * 1000,
gcTime: 24 * 60 * 60 * 1000,
retry: 3,
retryDelay: attemptIndex => Math.min(1000 * 2 ** attemptIndex, 30000)
})
}
function MemberRow({ member }: { member: Guild["guild"]["members"][number] }) {
const { data: player, isLoading, isError } = useMemberData(member.uuid)
if (isLoading || (!player && !isError)) return null
if (isError || !player) return null
const memberWithPlayer: MemberWithPlayer = {
...member,
player,
loading: isLoading,
error: isError
}
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 <MemberCard member={memberWithPlayer} />
}
toast.info(`Loaded ${members.filter(member => member.player).length} out of ${members.length} guild members`, {
id: "guild.members.loader",
duration: 1000
})
function GuildMembersInternal({ members, ranks }: { members: Guild["guild"]["members"], ranks: Guild["guild"]["ranks"] }) {
const sortedMembers = [...members].sort((a, b) => {
if (a.rank === "Guild Master" && b.rank !== "Guild Master") return -1
if (b.rank === "Guild Master" && a.rank !== "Guild Master") return 1
return () => clearTimeout(timer)
const aRank = ranks?.find(rank => rank.name === a.rank)
const bRank = ranks?.find(rank => rank.name === b.rank)
const aPriority = aRank?.priority ?? Number.MIN_SAFE_INTEGER
const bPriority = bRank?.priority ?? Number.MIN_SAFE_INTEGER
if (aPriority !== bPriority) {
return bPriority - aPriority
}
}, [currentIndex, members, isLoading])
return a.uuid.localeCompare(b.uuid)
})
return (
<Card>
@@ -77,22 +97,7 @@ export function GuildMembers({ members: mem, ranks }: { members: Guild["guild"][
</TableRow>
</TableHeader>
<TableBody className="space-y-4">
{members.filter(member => member.player).sort((a, b) => {
if (a.rank === "Guild Master" && b.rank !== "Guild Master") return -1
if (b.rank === "Guild Master" && a.rank !== "Guild Master") return 1
const aRank = ranks?.find(rank => rank.name === a.rank)
const bRank = ranks?.find(rank => rank.name === b.rank)
const aPriority = aRank?.priority ?? Number.MIN_SAFE_INTEGER
const bPriority = bRank?.priority ?? Number.MIN_SAFE_INTEGER
if (aPriority !== bPriority) {
return bPriority - aPriority
}
return a.uuid.localeCompare(b.uuid)
}).map((member, i) => <MemberCard key={i} member={member} />)}
{sortedMembers.map(member => <MemberRow key={member.uuid} member={member} />)}
</TableBody>
</Table>
</CardContent>
@@ -139,3 +144,4 @@ function MemberCard({ member: m }: { member: MemberWithPlayer }) {
</TableRow>
)
}