Salieron al pasar el lint por todo el proyecto. De 47 a 0 (quedan 15 avisos:
<img> vs <Image /> y el <link> del tema, los dos deliberados).
- Footer y Video (42 de los 47, que en realidad eran 7 enlaces: el plugin repite
cada uno 6 veces): usaban `<a href="/terms-and-conditions">` SIN el idioma
delante. No estaba roto de milagro: el middleware lo salvaba mirando la cookie
NEXT_LOCALE. Pero cada clic se comía un 307 y recargaba la página entera en
vez de navegar en cliente, y el idioma lo decidía la cookie en vez de la URL
en la que estás. Ahora van con el `Link` de i18n, que ya existía.
- Turnstile: escribía una ref (`cb.current = onVerify`) DURANTE el render. Es el
patrón de "callback fresca", pero no está permitido: React puede descartar ese
render y dejarla mal. Pasa a un efecto.
- ActivateClient y ConfirmClient: ponían el estado de error con setState dentro
del efecto cuando NO hay hash. Eso se sabe ya al renderizar (es un prop), así
que se deriva del estado inicial y se ahorra un render.
- BattlepayList: `window.location.href = …` -> `.assign()`, igual que en la
tienda.
- CookieConsent: aquí el efecto es correcto y la regla no aplica, así que se
silencia explicando por qué: el consentimiento vive en una cookie del
navegador, en el servidor no existe, y leerlo al renderizar rompería la
hidratación (le saldría el banner a quien ya había decidido).
Verificado: desde /es/ el pie enlaza a /es/terms-and-conditions y desde /en/ a
/en/terms-and-conditions; portada, cookies, tienda y mi-cuenta siguen dando 200.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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>
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>
- lib/change-email.ts: requestEmailChange (valida pass/email/token, crea activación
con old_email/old_email_hash, email al correo actual), confirmOldEmail (marca is_used,
email al nuevo), confirmNewEmail (re-deriva verifier con el nuevo email + actualiza
battlenet_accounts y account; borra la activación).
- components/ConfirmClient.tsx: cliente genérico que confirma un hash por POST al abrir.
- Routes /api/account/change-email, /confirm-old-email, /confirm-new-email.
- Páginas /change-email (protegida) y /confirm-old-email, /confirm-new-email (auto).
- Catálogos ChangeEmail, ConfirmOldEmail, ConfirmNewEmail.
Verificado: change-email protegida (401/redirect), confirmaciones con hash inválido
-> invalidLink sin crash. AUTH 100% reimplementado en Next.js.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>