Commit Graph

78 Commits

Author SHA1 Message Date
Inna 20ee5a83c8 rename-guild: permitir pagar con PD, Stripe o SumUp
Renombrar hermandad ya no es solo PD: ahora ofrece el mismo selector de
forma de pago que el resto de servicios (saldo PD / tarjeta Stripe / tarjeta
SumUp). El coste es equivalente: 1000 PD = 10 €.

- lib/guild: se separa la validación (checkGuildRenameEligibility) del
  renombrado por SOAP (renameGuildBySoap); nuevo GUILD_RENAME_EUR (10 €).
- paid-services: entrada 'rename-guild' para que la reconciliación/webhook
  entregue el servicio tras el pago con tarjeta.
- nueva ruta /api/guild/rename/checkout con las 3 pasarelas (valida
  elegibilidad antes de cobrar); se elimina la antigua /api/guild/rename.
- RenameGuildForm usa PaymentMethodSelect y redirige a service-success.
- i18n: Paid.rename-guild (title/success) para la página de éxito.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 21:56:44 +00:00
Inna 1b0920d11f Permitir pagar los servicios con PD, Stripe o SumUp (elección)
Los 9 servicios con precio en euros (rename, customize, change-race,
change-faction, level-up, gold, transfer, restore-item, send-gift) ahora
ofrecen un selector de forma de pago con las 3 opciones: saldo PD, tarjeta
(Stripe) o tarjeta (SumUp).

- lib/dpoints: spendDPoints() descuenta PD de forma atómica (FOR UPDATE).
- lib/pay-with-dpoints: paga con saldo PD, ejecuta la acción al momento y
  reembolsa si la ejecución falla; 100 PD = 1 €.
- rutas checkout (character/[service] y gift): rama provider='pd' que valida
  saldo, descuenta, ejecuta fulfill y devuelve la URL de éxito (sin pasarela).
- service-success: rama provider='pd' (la entrega ya se hizo en el checkout).
- PaymentMethodSelect: componente compartido con coste por método y saldo;
  desactiva PD si no hay saldo suficiente.
- Formularios (PaidServiceForm, Gold, Transfer, RestoreItems, SendGift) y sus
  páginas pasan el saldo PD y envían el método elegido + locale.
- i18n: namespace Pay (es/en); añadidas claves Paid.restore-item que faltaban.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 21:44:31 +00:00
Inna 942fe2e397 Fix captcha: resetear Turnstile tras un fallo (token de un solo uso)
Al fallar (p.ej. contraseña incorrecta) el token de Turnstile ya se consumió en el
servidor; el reintento reenviaba el mismo token y daba "captcha fallida" aunque
estuviera resuelto. Se resetea el widget (setCaptcha('') + captchaKey++ con
<Turnstile key={captchaKey}>, mismo patrón que recover/restore/quest) en login,
create-account y trade-points (venta y canje). El check de código no usa captcha,
no se resetea ahí.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 21:17:37 +00:00
Inna 20e1d5a6b5 Renombrar /login -> /log-in en toda la web (/login da 404)
Mueve la página de login a /log-in y actualiza todas las referencias (enlace
CONECTAR del header y los redirect de auth de ~45 páginas). /login ahora da 404.
La API /api/auth/login no se toca (solo la ruta de página).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 21:03:31 +00:00
Inna 14125dbd72 Formularios: noValidate en todos para usar red-response del sitio
Desactiva la validación nativa del navegador ("Rellene este campo", formato de
email) en el resto de formularios (recover, reset-password, trade-points,
rename-guild, transfer-dp, gold, promo, transfer, quest, send-gift, 2FA, restore).
Los errores se muestran como red-form-response (por validación en cliente o del
servidor), consistente con login y create-account. Botones ya gateados por campos.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 20:57:39 +00:00
Inna f37bf71dc0 d-points: tabla de niveles especifica también el importe en euros
La tabla de niveles mostraba solo PD ("Hasta 100 PD"); ahora añade el equivalente
en la moneda (100 PD = 1 €): "Hasta 100 PD (1 €)" / "Up to 100 PD (1 €)". Se
sustituyen los 14 mensajes range1..14 por 3 plantillas parametrizadas
(rangeFrom/rangeUpTo/rangeOver) con {pd}/{price}/{sym}; RANK_ROWS lleva el umbral
en PD y el tipo. Adaptado a la moneda (DP_CURRENCY).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 20:34:45 +00:00
Inna 85c5c995ee Admin del foro: gestionar traducción EN de categorías y foros
Los formularios de crear categoría/foro aceptan nombre/descripción en inglés, y
se añade EDICIÓN en línea de categorías (name, name_en, order) y foros (name,
name_en, description, description_en). lib/admin-forum: createCategory/createForum
con EN + updateCategory/updateForum; rutas PUT en category/[id] y forum/[id].
Claves Admin nuevas (nombre/descripción EN). Verificado: listado con EN + update
round-trip; PUT protegido (403 sin admin).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 19:55:54 +00:00
Inna 86c9b01c76 Noticias multiidioma (ES/EN) con fallback
home_noticia gana columnas titulo_en/contenido_en (sql/add_news_en.sql). getNoticias(locale)
usa la versión EN si existe, si no cae al español (título y contenido independientes); la fecha
también se formatea por idioma. El panel de admin permite escribir la traducción al crear y EDITAR
noticias existentes (nuevo PUT /api/admin/news/[id], updateNews). Claves Admin nuevas (título/
contenido EN, editar/guardar). Probado: /en/ muestra EN, /es/ ES; PUT guardado (403 sin sesión).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 19:14:07 +00:00
Inna 651d8deafc i18n: traducir toda la app (ES + EN) — páginas y componentes con texto hardcodeado
Se externaliza el texto español hardcodeado de ~55 archivos a next-intl y se añaden
traducciones al inglés, con paridad de claves es/en. Nuevos namespaces: History,
CharService, CharServiceB, Points, Legal, UI, Misc (+ altas en Common/Admin).

- Historiales (PD/PV, transacciones, sanciones, seguridad), servicios de personaje
  (transfer, send-gift, quest, restore-*, change-*, customize, level-up, gold, rename),
  PD/pagos (d-points, trade, promo, transfer-dp, rename-guild, DPointsTabs), páginas
  legales (cookies, privacidad, términos, reembolsos, aviso legal, contacto), layout
  (cabecera, footer, cookies, 2FA, descargas, jugadores, recluta) y páginas varias
  (home, reino, ayuda, addons, 2falogin).
- Textos con markup inline via t.rich; interpolación con ICU.
- Componente <NoteLegend/> para la leyenda NOTA/NOTE compartida.
- payLabel/confirmText de los servicios de pago traducidos.
- Verificado: tsc OK, next build OK, todas las claves t() resuelven en es y en,
  todos los t.rich casan etiquetas, páginas 200 en /es/ y /en/ sin claves crudas.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 18:58:54 +00:00
Inna e457a43f05 Header: nombre del reino en mayúsculas (fuente Futura consistente)
El nombre del reino (p.ej. "Trinity") salía en minúsculas y las minúsculas caían
a una fuente de reserva (Futura es de mayúsculas), desentonando con el resto del
nav. Se muestra en mayúsculas como los demás ítems.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 15:57:21 +00:00
Inna 434011624c Barra final solo en la raíz de idioma (/es/), resto de rutas sin barra
trailingSlash true ponía barra en todo (/es/content-creators/). Se pasa a
skipTrailingSlashRedirect + normalización en middleware: raíz de idioma /es → /es/
(con barra), y cualquier sub-ruta con barra final se redirige sin ella
(/es/x/ → /es/x). Sin bucles. Las /api quedan fuera del middleware (sin 308).
El redirect del logout apunta a /es/.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 15:36:13 +00:00
Inna d0490e06fe URLs con barra final (trailingSlash) como el sitio original
next.config: trailingSlash true → /es redirige a /es/ y los enlaces se generan
con barra. Se ajustan a barra final los destinos internos que se enlazan a mano
(logout /log-out/ y su redirect, y los window.location.assign de login/
select-account) para evitar el salto 308 extra.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 15:18:06 +00:00
Inna c5a90d744a Header: enlaces internos con <Link> (prefijo de idioma)
Los enlaces internos del header eran <a> planos sin prefijo (/download-client…);
ahora usan <Link> de next-intl → /es/download-client, /es/changelogs, reino,
jugadores, videos, ayuda y los logos. Externos (WOTLK DB) y el logout (route
handler) siguen como <a>. Resuelve también los avisos no-html-link-for-pages.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 15:12:59 +00:00
Inna 9e6a8f8231 Quitar URLs javascript: (React 19 las bloquea)
React 19 bloquea href="javascript:void(0)". SiteHeader: DESCONECTAR ahora enlaza
a /{locale}/log-out (ruta real), el menú hamburguesa y el logo pequeño usan
role/button o href real. PostActions (foro): editar/eliminar pasan a role=button.
Se elimina el logout por fetch del header (lo hace la ruta /log-out).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 14:46:17 +00:00
Inna 9b1f1ecf63 send-gift: cuadrícula de objetos 4/fila centrada + paginación
Aplana el catálogo y lo pagina (8 por página = 2 filas de 4) con controles
Atrás / 1 2 3 / Siguiente centrados. Nuevas clases .gift-grid (grid 4 cols,
responsive a 2 en móvil) y .gift-pagination en novawow-style.css.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 13:56:25 +00:00
Inna 1a2d40ee9c Añadir /send-gift (Enviar regalo) pagado por SumUp
Envía ítems de la tienda por correo al personaje de un amigo, pagado por
SumUp. lib/gift.ts (catálogo por categoría, priceCart con precios reales de
BD, sendGiftByMail vía SOAP .send items troceado a 12/correo + anti-inyección);
servicio send-gift en PAID_SERVICES; ruta dedicada /api/gift/checkout (origen
propio, destino existe, token de seguridad, carrito); SendGiftForm + página con
el diseño; i18n Paid[send-gift]; seed_giftitems.sql (4 cat, 8 ítems).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 13:49:56 +00:00
Inna 671632a6a0 web-next: /restore-items cobra por SumUp (1€/ítem) en vez de PD
- Nuevo servicio de pago `restore-item` (getRestoreItemPrice default 1€, fulfill
  SOAP `.item restore <recover_id> <char>`). Al pulsar "Recuperar" se crea un
  checkout de SumUp y al pagar se ejecuta el restore.
- Se quita el descuento de 100 PD y el gate "No tienes PD suficientes".
- La búsqueda sigue igual (gratis, cooldown 8h, Turnstile).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 13:17:23 +00:00
Inna 03f75e189c web-next: /restore-character y /restore-items con todas las condiciones
- /restore-character: recupera personajes borrados por BD (como .character deleted
  restore). Condiciones: nivel>60, borrado <30 días, DK no si ya hay DK activo,
  nombre libre, cooldown 12h/personaje. Gratis. Tabla home_restorehistory.
- /restore-items: recupera ítems borrados vía SOAP del core (.item restore list /
  .item restore); el core aplica calidad/equipable/BoP/<7días. Cada ítem 100 PD
  (reembolso si SOAP falla), consulta con cooldown 8h/personaje + Turnstile.
  Tabla home_itemsearchhistory.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 13:09:11 +00:00
Inna d95fa932f9 web-next: /transfer-character (transferir personaje por SumUp con todas las condiciones)
- Nueva ruta /transfer-character (10€ SumUp); borra /transfer (Stripe) y actualiza
  el link del panel.
- lib/transfer-character.ts: precheck con todas las condiciones — personaje offline,
  contraseña, token de seguridad, 2FA activo, cuenta destino válida (≠ propia) y,
  para Caballeros de la Muerte, la cuenta destino debe tener un personaje nivel >=55
  y no tener ya un DK; + bloqueo de 5s tras transferencia reciente.
- El hook precheck de PaidServiceConfig ahora recibe {accountId,email,character,body}.
- TransferForm: contraseña + token (con ojos), provider sumup, confirm.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 12:52:25 +00:00
Inna eaae16e33a web-next: change-race/faction/level-up/gold por SumUp + rastreador de misiones
- /change-race-character (3€), /change-faction-character (5€, valida condiciones:
  sin hermandad/correo/subastas/capitán-arena y oro <= cap por nivel),
  /level-up-character (10€), /gold-character (oro por correo SOAP). Cada uno borra
  su ruta antigua y actualiza el link del panel.
- SumUp: hook precheck en PaidServiceConfig (condiciones cambio de facción);
  columna home_stripelog.metadata para campos extra (gold_amount).
- /quest-character: rastreador de estado de misiones/cadenas (clase, Hijos de
  Hodir, misión por ID) en personaje offline; cooldowns por categoría, Turnstile,
  IDs de misión verificados en wotlkdb 3.3.5a. Tabla home_questsearchhistory.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 12:39:28 +00:00
Inna f7a376bd7c web-next: rename-character/customize-character por SumUp + renombrado de rutas
- /rename-character y /customize-character: renombrar/personalizar pagados por SumUp
  (getRenamePrice/getCustomizePrice). SumUp ahora es service-aware: columna
  home_stripelog.service; createSumUpCheckout guarda service+character;
  fulfillSumUpCheckout despacha a la acción del servicio (.char rename/customi) o,
  sin service, acredita PD. [service]/checkout acepta provider:'sumup';
  PaidServiceForm acepta provider+confirmText; service-success maneja el return SumUp.
  Se eliminan las antiguas /rename y /customize (Stripe).
- /revive-character (comparte ReviveServiceContent); se elimina /revive.
- Renombres de ruta + todos sus enlaces:
  /account -> /my-account, /recruit -> /recruit-a-friend, /unstuck -> /unstuck-character.
  (/select-account y /api/account/* intactos.)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 11:35:56 +00:00
Inna 6ca94c2803 web-next: selector de personaje coloreado + rediseño unstuck + fixes vote/account-info
- CharacterSelect: componente reutilizable que colorea las opciones por clase
  (class="priest big-font"…) y el <select> con la clase seleccionada. Usado en
  unstuck, revive, gold, transfer, trade-points, servicios de pago y recruit.
  getGameCharacters ahora devuelve classCss.
- /unstuck (+revive): diseño del original (info + NOTA, prompt, opciones coloreadas,
  botón "Desbloqueado"/"Revivido" con refresh).
- /vote-points: seed de los 4 sitios con logos y URLs (sql/seed_votesites.sql);
  botón voted-button para sitios en cooldown; etiqueta "Nota:" separada.
- account-info.png (imagen nueva) y CSS de los paneles de cuenta: se añade
  background-blend-mode: saturation y background-size en #account-settings y
  .account-fieldset para que la imagen salga como el original.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 10:55:43 +00:00
Inna b9803adeb9 web-next: rediseño de security-token, recover, vote-points + rename-guild
- /security-token: diseño completo del original (info + advertencia + NOTA 7 días),
  fecha en formato HH:MM:SS DD-MM-YYYY, botón "Token enviado", enlace a /recover.
- /recover: 4 opciones (contraseña por usuario, nombre de cuenta, token de seguridad
  y enlace de activación por correo); recuperación de token nueva; Turnstile por envío.
- /vote-points: caja de info con las 7 secciones Q&A + panel "Sitios de votación" con
  tarjetas inline-div (imagen, PV, último voto), botón refrescar; abre el sitio y acredita
  PV al volver. lib/vote.ts + getVoteSitesForAccount.
- /rename-guild: renombra una hermandad de la que la cuenta es Maestro por 1000 PD +
  token de seguridad; SOAP .guild rename con comillas; reembolsa los PD si SOAP falla.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 10:06:49 +00:00
Inna 66d056c04b web-next: herramientas de PD (transferir, comercio, códigos de promoción)
- /transfer-d-points: transferir PD a la cuenta dueña de un personaje
  (requiere token de seguridad; movimiento atómico con FOR UPDATE).
- /trade-points: comercio PD<->oro mediante códigos de 1 solo uso
  (contraseña + token + Turnstile; oro al creador por SOAP; expira 1h;
  lock de 5s tras canjear; rollback total si falla la entrega).
- /promo-code: canje de códigos por PD/PV (sensibles a mayúsculas/minúsculas,
  usos limitados, 1 canje por cuenta).
- /admin/promo: panel para crear / editar / activar / desactivar / borrar
  códigos de promoción.
- Tablas nuevas (sql/): home_tradecode, home_promocode, home_promoredemption.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 09:27:11 +00:00
Inna 4e089b5ebb Añadir ruta /security-2falogin (verificación en 2 pasos / TOTP)
Activación de 2FA (TOTP) para el login del juego, guardando el secreto en
acore_auth.account.totp_secret tal como lo lee el bnetserver 3.4.3.

- lib/two-factor.ts: TOTP (HMAC-SHA1, 30s, 6 dígitos, ±1) idéntico al core
  (verificado contra los vectores RFC 6238), Base32, otpauth, y codificado
  del secreto: crudo por defecto o AES-128-GCM (ciphertext‖IV12‖tag12) si se
  define TOTP_MASTER_SECRET (mismo hex que TOTPMasterSecret del servidor).
- Flujo seguro sin bloqueos: el secreto se genera y queda PENDIENTE en la
  sesión; sólo se escribe en la cuenta tras verificar un código válido.
- /api/account/2fa: activar (password + token de seguridad), verificar y
  desactivar (con código actual). QR generado en el servidor (el secreto no
  sale a terceros).
- Página + componente fieles al markup (preview, pasos, copiar clave, ojos).

Verificado E2E: activar -> QR/secreto -> verificar -> totp_secret = 20 bytes
(igual al secreto escaneado) -> desactivar -> NULL.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 21:37:13 +00:00
Inna 89f6e5689f d-points: dejar sólo Stripe y SumUp con compra de PD funcional
Elimina las pestañas de PayPal/dLocal/Crypto/Skrill y por país; deja
Información + Stripe + SumUp (las dos únicas pasarelas que se usarán).

- Stripe: totalmente funcional reutilizando createCheckoutSession + webhook
  + página de éxito. Nueva ruta /api/dpoints/checkout crea la sesión con
  importe elegido por el usuario (1 unidad = 100 PD).
- SumUp: integración real (lib/sumup.ts) mediante checkout hospedado,
  habilitada al definir SUMUP_API_KEY/SUMUP_MERCHANT_CODE; si no, avisa.
- Nuevo servicio de entrega `dpoints` (lib/paid-services.ts) que acredita
  PD en home_api_points; entrega idempotente vía reclamo atómico.
- Página /d-points-success entrega ambos proveedores (session_id/ref).
- Iconos SVG generados para cada pasarela (stripe/sumup, marca + wordmark).
- Moneda configurable con DP_CURRENCY (por defecto EUR).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 17:14:29 +00:00
Inna 44fcedbe62 Añadir ruta /d-points (Adquirir PD) con pasarelas multi-método
Reproduce fielmente el panel de compra de PD de UltimoWoW como componente
cliente con pestañas (Información, PayPal, dLocal Go, Crypto, Skrill y
métodos alternativos por país: Argentina, Chile, Colombia, Perú).

- Página servidor con login requerido (redirige a /login y /select-account
  como battlepay); inyecta username de la cuenta de juego e IP reales.
- Pestañas, tabla de rangos con mostrar/ocultar, y calculadora ARS
  (dolarapi) migradas a estado/efectos de React.
- Formularios con casilla de T&C que habilita el botón; PayPal usa
  PAYPAL_BUSINESS_EMAIL por entorno; dLocal/NOWPayments muestran aviso
  hasta configurar su backend (no se fabrican credenciales/gateways).
- Banderas por país y logo de NOWPayments añadido a nw-logos.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 16:59:53 +00:00
Inna c3e57ff25e web-next: /recruit según el markup (Información + Panel RAF con recompensas)
- Reescrita la página: box «Información» con la guía completa de Recluta a un
  amigo (marca → nombre del reino) + box «Panel de Recluta a un amigo».
- Nuevo RecruitPanel: estadísticas (cuenta reclutada, amigos reclutados, amigos
  al nivel 80, recompensas reclamadas X/6) + tabla de recompensas (objetivo,
  objeto con icono y color de calidad, estado) con botón Reclamar para las
  disponibles + sección «Recompensas disponibles». Sustituye a RecruitClaim.
- lib/recruit-claim: getRecruitStats (isRecruited + recruitedCount).
- Colores de calidad de objeto .q0-.q5 en globals.css.
- Sembradas las 6 recompensas en home_recruitreward (seed en sql/).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 16:14:10 +00:00
Inna a7fb4f7943 web-next: fix layout del formulario de añadir cuenta (mensaje abajo)
El <form> dentro del <p> «Nombre de la cuenta» era HTML inválido y el mensaje
salía inline (en inglés «Wrong password» partía en «Add Wrong / Password»).
Se quita el form: input+botón (onClick, Enter) en un span-bloque .add-account-box
debajo del nombre, y el mensaje en .add-account-msg (display:block) en su propia
línea. Igual en ES y EN.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 15:54:50 +00:00
Inna c2e35d33ea web-next: botón «+» para crear cuentas de juego (WOW2, WOW3…)
Junto al «Nombre de la cuenta» hay un botón «+» que pide la contraseña y crea
una nueva cuenta de juego bajo la Battle.net. Ruta /api/account/add-game-account:
verifica la contraseña (authenticate contra battlenet_accounts), calcula el
siguiente battlenet_index (máx 8) y crea la fila `account` con SRP6 Grunt
derivado de la contraseña (gameMakeRegistration) — igual que la activación, así
la cuenta sirve para entrar al juego. Recarga completa al crear/cambiar.
GameAccountSwitcher siempre presente (select si >1, texto si 1) + «+».

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 15:50:18 +00:00
Inna e62ab94054 web-next: selector de cuenta INLINE en «Nombre de la cuenta» + fix iconos al cambiar
- El desplegable WOW1/WOW2… ya no es un box aparte: va dentro del campo «Nombre
  de la cuenta» (select compacto .account-select). Con una sola cuenta, texto plano.
- FIX iconos: el cambio de cuenta hacía router.refresh() (navegación suave) que en
  algunos navegadores dejaba caer las hojas de estilo/FA y no se recuperaban. Ahora
  hace window.location.reload() (recarga completa) → todo se recarga bien.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 15:39:46 +00:00
Inna e1983eee9e web-next: selector de cuenta de juego (WOW1/WOW2…) en /account
Si la Battle.net tiene más de una cuenta de juego, /account muestra un
desplegable «Cargar datos de la cuenta» (WOW1, WOW2…). Al cambiar, fija la
cuenta activa en la sesión vía /api/auth/select-account y refresca → toda la
página (datos, personajes, servicios, compras) opera sobre la cuenta elegida
(la sesión.accountId manda). Con una sola cuenta no aparece (como hasta ahora).
components/GameAccountSwitcher.tsx (client) + getGameAccounts en la page.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 15:28:09 +00:00
Inna 24482eaea0 web-next: «Cambiar correo» usa el mismo icono que «Cambiar contraseña»
En «Opciones de cuenta», change-email pasa de email-icon a password-icon.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 15:09:47 +00:00
Inna eb030ef966 web-next: «Opciones de cuenta» reordenado según el markup
accountTools en el orden del markup: cambiar contraseña, 2FA (email-icon,
label purple-info), transferir PD, comercio de PD, código promoción, token,
recluta, renombrar hermandad, votar, adquirir PD. «Cambiar correo» (que
tenemos y no está en la lista) al final; panel admin el último (solo admin).
Tool.labelClass para el morado del 2FA. Iconos nuevos del sprite: trade-pd-icon
(-299 -928) y color .purple-info (#b172ff) añadidos al tema. Claves i18n nuevas
(svc2FA/TransferDP/TradePD/Promo/RenameGuild/DPoints). Rutas nuevas → 404 aún.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 15:04:46 +00:00
Inna 38b4989268 web-next: panel «Opciones de personaje» completo y en orden + sprite de iconos nuevo
- characterTools reordenado y completado según el markup del usuario (14 items):
  ...gold, Rastreador de misiones (/quest), transfer, Recuperar personaje
  (/restore-character), Recuperar ítems (/restore-items), Tienda (/store),
  Enviar regalo (/send-gift). Se retira battlepay del panel (queda en cabecera).
  Claves i18n nuevas (svcQuest/RestoreChar/RestoreItems/StoreItems/SendGift).
- Sprite de iconos actualizado a account-icons.png (de uw-ryu) que incluye el
  icono de regalo; CSS: .acc-icon → .png, send-gift-icon (-424 -553) y promo-icon
  reubicado (-174 -928), verificado que las 25 posiciones restantes coinciden.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 14:19:54 +00:00
Inna efbc7ec623 web-next: panel HISTORIALES en /account (debajo de Opciones de personaje)
Tercer panel plegable «HISTORIALES» (id account-history) con 4 herramientas:
Historial de PD y PV, transacciones, sanciones y seguridad (points-history/
trans-history/ban-history/security-history; iconos pointsh/dnth/banh/securityh).
Arranca CERRADO como los otros dos (el usuario lo abre al click). Prop
defaultOpen añadido a Panel (no usado aquí). Claves i18n en Account (es/en).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 14:01:31 +00:00
Inna 7df9cc408a web-next: footer usa el nombre del reino (realmlist) en copyright y diseño
Las dos líneas del pie (© Copyright NovaWoW™ y Diseño: "NovaWoW" Por Inna
Hoover Brown) ahora usan el nombre del reino de realmlist (getRealmName).
Footer pasa a async server component.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 13:37:13 +00:00
Inna 1fc235c24f web-next: usar el nombre del reino (realmlist) en menú, estado y título
- Menú de navegación: el desplegable «NovaWoW» ahora muestra el nombre del
  reino de realmlist (Header pasa realmName a SiteHeader).
- Home: el título «NovaWoW WOTLK 3.4.3» y el nombre del recuadro de estado
  (antes home_serverselection.name) usan el nombre del reino de realmlist.
Ahora el reino es «Trinity». El logo (alt) y el texto de intro se mantienen
como marca.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 13:34:51 +00:00
Inna e448f34305 web-next: enlace CHANGELOG de la cabecera → /changelogs
Apuntaba a un tema del foro externo (foro.novawow.com); ahora va a la página
interna /changelogs (API de Gitea).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 13:19:39 +00:00
Inna 0affbb2ced web-next: top de logros por PUNTOS reales + fix logro Nivel 80
- «Top de logros» ahora suma los PUNTOS de logros (no el nº): JOIN a
  acore_world.achievement_points (id→points), poblada desde el DB2 Achievement
  del build 3.4.3.54261 (wago.tools). Columna «Puntos de logros». Seed en
  sql/achievement_points.sql (1912 logros).
- Fix: el logro «Nivel 80» es el id 13 (logros de nivel WotLK van de +10:
  6=Nv10,7=Nv20…12=Nv70,13=Nv80), no el 20. «Primeros del reino» ahora se
  puebla correctamente.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 13:10:55 +00:00
Inna 5d724afb8d web-next: página de jugadores /<slug>-players con datos reales de la BD
Extiende la ruta dinámica [realm] para servir también /<slug>-players (slug
del reino en realmlist). PlayersBoard (server) consulta acore_characters:
- Personajes creados por clase (conteo por clase y facción) + totales.
- Top de muertes con honor (characters.totalKills/todayKills, LIMIT 10).
- Top de logros (nº de logros por personaje vía character_achievement;
  los «puntos» no existen en la BD del servidor, vienen del DBC del cliente).
- Primeros del reino - Nivel 80 (primer personaje por fecha del logro 20 =
  Nivel 80, overall/por clase/por raza; vacío si aún no hay nivel 80).
Imágenes reales del tema (nw-classes/nw-races/nw-icons). lib/players.ts con
los mapas de clase/raza/facción. RealmInfo extraído a su componente. Enlace
JUGADORES de la cabecera ahora dinámico (/<slug>-players), como REINO.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 12:53:50 +00:00
Inna cae1c224b0 web-next: enlace REINO de la cabecera dinámico (/<slug>-realm)
El menú de la cabecera enlazaba a /novawow-realm fijo. Ahora Header (server)
calcula el slug desde realmlist (getRealmName + realmSlug) y lo pasa a
SiteHeader como realmHref → el enlace REINO apunta a /trinity-realm (o al
reino que haya). Acompaña a la ruta dinámica [realm].

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 12:41:44 +00:00
Inna 5da124cf28 web-next: página /download-client (descarga del cliente por torrent)
Ruta con el markup del tema + lógica interactiva (componente cliente
ClientDownload): selector de idioma (esES/esMX/enUS/enGB) que muestra el
selector de SO y la descripción del idioma; al elegir SO «Mac OS Catalina»
aparece la guía de CrossOver; el botón DESCARGAR abre el magnet link
correspondiente (btih por idioma + trackers comunes) o muestra error si
falta elegir. Clases del tema (game-download-select/g-download-button).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 12:20:37 +00:00
Inna 57e91480d1 web-next: «Personalizar» abre panel granular de cookies (uw-cookie-details)
El botón Personalizar del banner ahora despliega un panel con checkboxes por
categoría (Necesarias fija+desactivada, Analíticas, Marketing) y «Guardar
preferencias», tal como el markup del usuario. Al guardar, escribe la cookie
uw_cookie_consent con la selección granular y sincroniza con Zaraz. Categorías
alineadas a las del panel (Necesarias/Analíticas/Marketing); ConsentStatus y
acceptAll/rejectAll usan las mismas. Estilos del panel en globals.css.

Verificado: Personalizar abre el panel, marcar Analíticas + Guardar deja la
cookie {necessary,analytics:true,marketing:false} y /cookies lo refleja.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 12:02:49 +00:00
Inna 4ebe3c34d3 web-next: banner de consentimiento de cookies + estado de la API (Zaraz)
- Banner real `uw-cookie-content` (Rechazar/Personalizar/Aceptar todas) fijo
  abajo y site-wide (montado en el layout, componente CookieBanner). Aparece
  en la primera visita, guarda la decisión en la cookie uw_cookie_consent (1
  año) y se sincroniza con Cloudflare Zaraz si está presente
  (zaraz.consent.setAll / .modal). Estilos en globals.css.
- «Personalizar» abre el modal granular de Zaraz (o /cookies si no hay Zaraz).
- window.UWCookies {showBanner, revokeConsent, acceptAll, rejectAll}.
- Página /cookies: panel «Tu estado de consentimiento» (ConsentStatus) que
  muestra los datos EN VIVO de la API de Zaraz (zaraz.consent.getAll()) por
  propósito; si Zaraz no está, cae a la preferencia guardada por categoría.

Verificado con navegador: el banner aparece, «Aceptar todas» lo oculta y
escribe la cookie, y el panel de /cookies refleja el estado.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 11:58:54 +00:00
Inna e289a87d1f web-next: página /cookies (Declaración de Cookies) + consentimiento Zaraz
Crea la ruta de Declaración de Cookies con el markup del tema y las 5 tablas
de cookies (uw-cookie-table, estilizadas en globals.css) + estilos de listas
y botones (btn-uw). Los enlaces internos .php se cablean a las rutas Next
(/privacy-policy, /contact-us).

Sistema de consentimiento = Cloudflare Zaraz (elección del usuario):
components/CookieConsent.tsx expone window.UWCookies.showBanner()
(zaraz.consent.modal=true) y revokeConsent() (zaraz.consent.setAll(false)),
que Cloudflare activa cuando el dominio pasa por su proxy con Zaraz Consent;
degrada con aviso si Zaraz no está presente. El footer ya enlazaba aquí.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 11:49:16 +00:00
Inna d6acba4ad5 web-next: mover «Panel de administración» dentro de «Opciones de cuenta»
Antes era un tool-button suelto a ancho completo (podía desbordarse). Ahora
es una celda más de la rejilla de 2 columnas del panel «Opciones de cuenta»
(solo admins), con el mismo contorno/ancho que el resto (Token de seguridad,
etc.). Utilidades y Herramientas se mantiene igual.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 11:09:10 +00:00
Inna 6337de73ad web-next: /account idéntico al my-account de Django
La página de cuenta no se parecía a la de Django (oro descuadrado, info como
tabla, herramientas en grupos abiertos). Reescrita para replicar el
partials/my-account.html + isla AccountDashboard de Django:

- Información en DOS fieldsets (.account-fieldset): «Datos básicos» (cuentas,
  correos, fecha de registro, IPs) y «Estado de la cuenta» (insignia de rango
  nw-rank + PD/PV/créditos/token + baneo + reclutamiento). lib/account.ts
  ampliado para traer reg_mail/email/joindate/last_ip/last_attempt_ip, estado
  de baneo (account_banned) y nº de reclutados.
- Personajes en char-box con el markup exacto de Django: retrato flotante +
  oro EN LÍNEA (monedas width=10). Antes las monedas salían a tamaño nativo
  (descuadre) y apiladas.
- Herramientas en paneles plegables (acordeón) «OPCIONES DE CUENTA / OPCIONES
  DE PERSONAJE» como Django (componente cliente AccountTools), con los
  servicios ya implementados en Next y las etiquetas/descripciones exactas.
- globals.css: revertir otro reset del preflight de Tailwind — img{display:
  block} apilaba verticalmente los iconos en línea (monedas); el tema los usa
  inline como la web Django. Volvemos a img{display:inline}.

Verificado con Playwright (login real con cuenta de prueba + captura): info,
personajes con oro en línea y paneles que expanden con sus iconos; home sin
regresión por el cambio de img.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 10:58:36 +00:00
Inna 51203c7eee web-next: paridad de los campos de login con el tema Django
- Turnstile: quitar clases Tailwind del wrapper (my-3/flex/justify-center)
  → estilo inline neutral centrado, como la web Django.
- login/register/recover: el boton ya NO arranca deshabilitado (gris) por
  falta de captcha; se ve activo como en Django. El captcha lo sigue
  validando el servidor (devuelve captchaFailed). Se quita el SITE_KEY
  cliente ya innecesario.
- reset-password: pagina que habia quedado sin migrar (usaba nw-btn/
  nw-input/mx-auto/text-amber) → PageShell + middle-center-table + inputs
  planos + recover-button + alert-message, igual que el resto del flujo.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 10:08:14 +00:00
Inna cc158d3819 web-next: migrar toda la UI al tema real nw-ryu
Reescritura completa del frontend Next.js del sistema visual Tailwind
"simulado" al tema Django original (nw-ryu), para paridad pixel con la
web actual antes del cutover.

- Tema real: copia de static/nw-themes/nw-ryu + favicons a public/, el
  layout carga el novavow-style.css real de ultimo (gana la cascada sobre
  Tailwind) + Font Awesome.
- Shell replicando los partials Django: SiteHeader, Video, Social, Footer,
  ServerClock; home con estructura real (main-page/middle-content/...).
- Helpers reutilizables: PageShell (main-page > middle-content > body-content
  > title-content) y ServiceBox (title-box-content + back-to-account).
- Paginas migradas a clases reales del tema (fieldset/tool-button/char-box/
  item-box/info-box-light/max-center-table/alert-message/botones reales),
  eliminando el markup Tailwind (.nw-btn/.nw-card/.nw-input):
  auth (login/register/recover/reset/select-account/activate),
  cuenta + servicios de personaje (revive/unstuck/rename/customize/
  change-race/change-faction/level-up/gold/transfer + pago Stripe),
  ajustes (change-password/change-email/security-token),
  comunidad (vote-points/recruit/battlepay), foro completo, y
  admin (indice + 7 secciones + los Admin*Manager).
- Se conserva el bilingue (next-intl); claves nuevas en messages/es|en.json.

Verificado: typecheck + build OK; rutas protegidas 307->login; sin
MISSING_MESSAGE; cero Tailwind residual (solo .nw-tool-btn/.nw-page,
clases propias en globals.css).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 09:54:58 +00:00