Files
NightSpire/web-next/components/ArmoryBattlegrounds.tsx
T
Inna beba7301a1 Armería: PvP campos de batalla, logros por categoría, bandas/mazmorras y página de hermandad
- PvP: pestaña Campos de batalla (pvpstats) con resultado, stats por partida y fecha/hora.
- Logros: rejilla por categoría con anillos de progreso + detalle por categoría
  (datos de Achievement.db2 + Achievement_Category.db2, iconos vía wowhead).
- Bandas: progreso por dificultad (10/25/heroico) con jefes reales de DungeonEncounter.db2
  y tooltip de jefes; agrupado por expansión (Clásico/TBC/WotLK).
- Mazmorras: mismo sistema, Normal + Heroico, Clásico/TBC/WotLK.
- Página de hermandad estilo armería: cabecera (emblema, puntos = unión de logros de
  miembros sin duplicar, nº miembros, fundada), pestañas Hermandad/Logros, roster con
  iconos de clase/raza, columna Función (rol por spec), filtros clase/función,
  orden por rango/puntos/nivel de objeto/nivel/nombre, paginación.
- Barra lateral: mensaje diario con login (iron-session, gated por pertenencia),
  logros recientes y desgloses de clases y funciones.
- Cabecera de personaje: enlace a la hermandad + nombre del reino.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 01:18:30 +00:00

156 lines
5.7 KiB
TypeScript

import type { BgMatch } from '@/lib/armory'
/** Nombre + color por BattlegroundTypeId (3.4.3 WotLK). */
const BG_TYPES: Record<number, { es: string; en: string; color: string; icon: string }> = {
1: { es: 'Valle de Alterac', en: 'Alterac Valley', color: '#4a90d9', icon: 'fas fa-mountain' },
2: { es: 'Garganta Grito de Guerra', en: 'Warsong Gulch', color: '#2ecc71', icon: 'fas fa-flag' },
3: { es: 'Cuenca de Arathi', en: 'Arathi Basin', color: '#e0a13a', icon: 'fas fa-tower-observation' },
7: { es: 'Ojo de la Tormenta', en: 'Eye of the Storm', color: '#9b59b6', icon: 'fas fa-bolt' },
9: { es: 'Costa de los Ancestros', en: 'Strand of the Ancients', color: '#c0703a', icon: 'fas fa-ship' },
30: { es: 'Isla de la Conquista', en: 'Isle of Conquest', color: '#5dade2', icon: 'fas fa-anchor' },
32: { es: 'Campo de batalla aleatorio', en: 'Random Battleground', color: '#888888', icon: 'fas fa-dice' },
}
export type BgLabels = {
history: string
desc: string
matches: string
wins: string
losses: string
winRate: string
result: string
win: string
loss: string
kb: string
hk: string
deaths: string
damage: string
healing: string
honor: string
date: string
none: string
battleground: string
}
export function ArmoryBattlegrounds({
locale,
rows,
matches,
wins,
losses,
winRate,
labels,
}: {
locale: string
rows: BgMatch[]
matches: number
wins: number
losses: number
winRate: number
labels: BgLabels
}) {
const fmt = (n: number) => n.toLocaleString(locale)
const fmtDate = (iso: string) => {
const d = new Date(iso)
if (Number.isNaN(d.getTime())) return '—'
const day = d.toLocaleDateString(locale, { day: '2-digit', month: 'short', year: 'numeric' })
const time = d.toLocaleTimeString(locale, { hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false })
return (
<span className="armory-bg-dt">
<span className="armory-bg-dt-d">{day}</span>
<span className="armory-bg-dt-t">{time}</span>
</span>
)
}
const bgOf = (type: number) =>
BG_TYPES[type] || { es: `BG #${type}`, en: `BG #${type}`, color: '#777', icon: 'fas fa-khanda' }
return (
<div className="armory-panel armory-bg-panel">
<div className="armory-bg-header">
<div className="armory-quest-title">
<i className="fas fa-flag-checkered" /> {labels.history}
</div>
<p className="armory-bg-desc">{labels.desc}</p>
</div>
<div className="armory-bg-summary">
<div className="armory-bg-stat">
<span className="armory-bg-stat-num" style={{ color: '#ffd100' }}>
{fmt(matches)}
</span>
<span className="armory-bg-stat-lbl">{labels.matches}</span>
</div>
<div className="armory-bg-stat">
<span className="armory-bg-stat-num" style={{ color: '#2ecc71' }}>
{fmt(wins)}
</span>
<span className="armory-bg-stat-lbl">{labels.wins}</span>
</div>
<div className="armory-bg-stat">
<span className="armory-bg-stat-num" style={{ color: '#ff5555' }}>
{fmt(losses)}
</span>
<span className="armory-bg-stat-lbl">{labels.losses}</span>
</div>
<div className="armory-bg-stat">
<span className="armory-bg-stat-num" style={{ color: '#e0a13a' }}>
{winRate}%
</span>
<span className="armory-bg-stat-lbl">{labels.winRate}</span>
</div>
</div>
{rows.length === 0 ? (
<p className="armory-hint">{labels.none}</p>
) : (
<div className="armory-bg-table-wrap">
<table className="armory-quest-table armory-bg-table">
<thead>
<tr>
<th>{labels.battleground}</th>
<th className="armory-bg-c">{labels.result}</th>
<th className="armory-bg-c">{labels.kb}</th>
<th className="armory-bg-c">{labels.hk}</th>
<th className="armory-bg-c">{labels.deaths}</th>
<th className="armory-bg-c">{labels.damage}</th>
<th className="armory-bg-c">{labels.healing}</th>
<th className="armory-bg-c">{labels.honor}</th>
<th className="armory-bg-c">{labels.date}</th>
</tr>
</thead>
<tbody>
{rows.map((m) => {
const bg = bgOf(m.type)
const name = locale === 'en' ? bg.en : bg.es
return (
<tr key={m.id}>
<td>
<span className="armory-bg-name">
<span className="armory-bg-ico" style={{ background: bg.color }}>
<i className={bg.icon} />
</span>
{name}
</span>
</td>
<td className="armory-bg-c">
<span className={`armory-bg-res ${m.won ? 'win' : 'loss'}`}>{m.won ? labels.win : labels.loss}</span>
</td>
<td className="armory-bg-c armory-bg-kb">{fmt(m.killingBlows)}</td>
<td className="armory-bg-c">{fmt(m.honorableKills)}</td>
<td className="armory-bg-c">{fmt(m.deaths)}</td>
<td className="armory-bg-c">{fmt(m.damage)}</td>
<td className="armory-bg-c">{fmt(m.healing)}</td>
<td className="armory-bg-c armory-bg-honor">{fmt(m.bonusHonor)}</td>
<td className="armory-bg-c armory-bg-date">{fmtDate(m.date)}</td>
</tr>
)
})}
</tbody>
</table>
</div>
)}
</div>
)
}