import { notFound } from 'next/navigation' import { getTranslations, setRequestLocale } from 'next-intl/server' import { Link } from '@/i18n/navigation' import { getCharacter, getCharacterEquipment, getCharacterCustomizations } from '@/lib/armory' import { raceName, className, classColor, factionOf, EQUIP_SLOTS } from '@/lib/wow-data' import { wowheadUrl, wowheadData } from '@/lib/wowhead' import { PageShell } from '@/components/PageShell' import { WowheadRefresh } from '@/components/WowheadRefresh' import { ArmoryModel3D } from '@/components/ArmoryModel3D' export const dynamic = 'force-dynamic' export default async function CharacterPage({ params, }: { params: Promise<{ locale: string; guid: string }> }) { const { locale, guid } = await params setRequestLocale(locale) const t = await getTranslations('Armory') const id = Number(guid) const character = await getCharacter(id) if (!character) notFound() const equipment = await getCharacterEquipment(id, locale) const customizations = await getCharacterCustomizations(id) const bySlot = new Map(equipment.map((e) => [e.slot, e])) const faction = factionOf(character.race) const factionLabel = faction === 'alliance' ? t('alliance') : faction === 'horde' ? t('horde') : '' // Modelo 3D: raza, género y equipo (entry + display; transmog si lo hay). // Slots de equipo que NO se dibujan en el modelo (cuello, anillos, abalorios): // se omiten para no pedir metadatos inexistentes (evita 404 en consola). const HIDDEN_SLOTS = new Set([1, 10, 11, 12, 13]) // Slot del visor: armadura usa inventory_type; armas por slot de equipo (mano // principal=21, secundaria=22/23). A distancia solo se ven arco/arma de fuego // (invType 15/26); las arrojadizas (25) y reliquias (28) no se dibujan → se omiten. const viewerSlot = (equipSlot: number, invType: number): number => { if (equipSlot === 15) return 21 if (equipSlot === 16) return invType === 23 ? 23 : 22 if (equipSlot === 17) return invType === 15 || invType === 26 ? invType : 0 return invType } const modelEquip = equipment .filter((e) => !HIDDEN_SLOTS.has(e.slot)) .map((e) => ({ slot: viewerSlot(e.slot, e.inventoryType), display: e.transmogDisplayId ?? e.displayId ?? 0, })) .filter((e) => e.slot > 0 && e.display > 0) return (

← {t('backToArmory')}

{/* Columna izquierda: identidad + modelo 3D */}

{character.name}

{t('level')} {character.level} · {raceName(character.race, locale)} ·{' '} {className(character.class, locale)}
{factionLabel && {factionLabel}} {character.online ? t('online') : t('offline')} {character.guildName && character.guildId && ( <{character.guildName}> )}
{/* Columna derecha: equipo */}

{t('equipment')}

{equipment.length === 0 ? (

{t('noEquipment')}

) : (
{EQUIP_SLOTS.map(({ slot, es, en }) => { const item = bySlot.get(slot) const slotName = locale === 'en' ? en : es if (!item) { return (
{slotName}
) } return (
{item.name} {slotName} {item.itemLevel ? ` · ${item.itemLevel}` : ''}
) })}
)}
) }