'use client' import { useEffect, useRef, useState } from 'react' import { className, classColor, raceName } from '@/lib/wow-data' export type GuildMemberRow = { guid: number name: string race: number class: number gender: number level: number rank: number rankName: string achPoints: number role: string ilvl: number } const ROLE_META: Record = { tank: { icon: 'fas fa-shield-halved', color: '#4a90d9' }, healer: { icon: 'fas fa-plus', color: '#4ade5f' }, dps: { icon: 'fas fa-gavel', color: '#d9534f' }, } const CLASS_SLUG: Record = { 1: 'warrior', 2: 'paladin', 3: 'hunter', 4: 'rogue', 5: 'priest', 6: 'deathknight', 7: 'shaman', 8: 'mage', 9: 'warlock', 11: 'druid', } const RACE_SLUG: Record = { 1: 'human', 2: 'orc', 3: 'dwarf', 4: 'nightelf', 5: 'scourge', 6: 'tauren', 7: 'gnome', 8: 'troll', 9: 'goblin', 10: 'bloodelf', 11: 'draenei', 22: 'worgen', } const ICON = 'https://wow.zamimg.com/images/wow/icons/large' const classIcon = (c: number) => `${ICON}/classicon_${CLASS_SLUG[c] || 'warrior'}.jpg` const raceIcon = (r: number, g: number) => `${ICON}/race_${RACE_SLUG[r] || 'human'}_${g === 1 ? 'female' : 'male'}.jpg` export function ArmoryGuildRoster({ guildid, locale, initial, total: initialTotal, pageSize, classes, labels, }: { guildid: number locale: string initial: GuildMemberRow[] total: number pageSize: number classes: number[] labels: { view: string sortRank: string sortPoints: string sortLevel: string sortName: string sortIlvl: string ilvl: string filterClass: string allClasses: string filterRole: string allRoles: string roleTank: string roleHealer: string roleDps: string name: string race: string class: string role: string level: string rank: string points: string } }) { const [rows, setRows] = useState(initial) const [total, setTotal] = useState(initialTotal) const [page, setPage] = useState(1) const [sort, setSort] = useState('rank') const [cls, setCls] = useState(0) // 0 = todas const [role, setRole] = useState('') // '' = todas const [loading, setLoading] = useState(false) const pages = Math.max(1, Math.ceil(total / pageSize)) const load = async (p: number, s: string, c: number, r: string) => { setLoading(true) try { const q = new URLSearchParams({ guild: String(guildid), page: String(p), sort: s, locale }) if (c) q.set('classes', String(c)) if (r) q.set('roles', r) const res = await fetch(`/api/armory/guild-roster?${q.toString()}`) const data = await res.json() setRows(Array.isArray(data.members) ? data.members : []) setTotal(Number(data.total) || 0) } catch { setRows([]) } finally { setLoading(false) } } const skip = useRef(true) useEffect(() => { if (skip.current) { skip.current = false return } setPage(1) load(1, sort, cls, role) // eslint-disable-next-line react-hooks/exhaustive-deps }, [sort, cls, role]) const goto = (p: number) => { if (p < 1 || p > pages || p === page || loading) return setPage(p) load(p, sort, cls, role) } const from = Math.max(1, page - 2) const to = Math.min(pages, page + 2) const nums: number[] = [] for (let p = from; p <= to; p++) nums.push(p) const sortField = sort === 'points' ? labels.sortPoints : sort === 'level' ? labels.sortLevel : sort === 'name' ? labels.sortName : labels.sortRank return (
{rows.map((m) => ( ))}
{labels.name} {labels.race} {labels.class} {labels.role} {labels.level} {sort === 'points' ? labels.points : sort === 'ilvl' ? labels.ilvl : labels.rank}
{m.name} {raceName(m.race, {className(m.class, {(() => { const rm = ROLE_META[m.role] || ROLE_META.dps const label = m.role === 'tank' ? labels.roleTank : m.role === 'healer' ? labels.roleHealer : labels.roleDps return ( ) })()} {m.level} {sort === 'points' ? ( {m.achPoints.toLocaleString(locale)} ) : sort === 'ilvl' ? ( {m.ilvl || '—'} ) : ( {m.rankName || `#${m.rank}`} )}
{pages > 1 && (
{from > 1 && ( <> {from > 2 && } )} {nums.map((p) => ( ))} {to < pages && ( <> {to < pages - 1 && } )}
)}
) }