Commit Graph

240 Commits

Author SHA1 Message Date
Inna 0244d0f8ef rename-guild: el texto informativo refleja las 3 formas de pago
El párrafo "Requiere 1000 PD" era estático y contradecía el nuevo selector.
Ahora indica el coste equivalente (1000 PD o 10 €) y que se puede elegir la
forma de pago (PD, tarjeta con Stripe o SumUp), que ya se muestra en el
formulario.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 22:01:56 +00:00
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 071b1d5f0e login: noValidate para usar red-response en vez del aviso nativo
El navegador mostraba "Rellene este campo" (required) en lugar del error del sitio.
noValidate en el form deja que la validación en cliente ya existente muestre el
red-form-response (missingFields).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 20:55:14 +00:00
Inna 8ca3975cac create-account: desactivar validación nativa (noValidate) para usar red-response
El navegador mostraba su tooltip nativo "Rellene este campo" en los inputs required
en vez del mensaje de error del sitio. Con noValidate en el form, la validación en
cliente (clientError) muestra el red-form-response también para campos vacíos.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 20:52:12 +00:00
Inna c1f865dfa5 create-account: validación en cliente con red-response inmediato
Antes los errores (contraseñas/correos que no coinciden, campos vacíos) solo se
mostraban en rojo tras el envío al servidor. Ahora se validan en el cliente y se
muestran al instante como red-form-response, sin llamada al servidor. Nueva clave
emailMismatch. El servidor sigue haciendo la validación final (Gmail, existe, etc.).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 20:50:30 +00:00
Inna 5d0d2bb089 Renombrar /register -> /create-account + rediseño (Battle.net)
Mueve la página de registro a /create-account (los enlaces del header y del login
apuntan ahí; /register ahora da 404 con el 404 del sitio). Rediseño según el
diseño aportado, adaptado a Battle.net (cuenta por email, sin usuario): caja de
info bnet (tipo bnet, reglas de contraseña/Gmail, activación, login por correo),
ojos para mostrar/ocultar contraseña, checkbox de "no accedo desde EEUU" +
términos (con enlaces), ambos requeridos para habilitar el botón, y bloqueo de
pegar en confirmar contraseña/correo. i18n ES/EN. No incluye FingerprintJS
(antiabuso por huella de dispositivo, requiere backend; la protección es Turnstile
+ Gmail + activación).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 20:44:15 +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 8a5ce82afa Rango de cuenta por TOTAL DONADO (Stripe + SumUp), no por saldo
El nivel/rango usaba el saldo de PD actual, que baja al gastar. Ahora se basa en
el total donado = suma de pagos confirmados (Stripe mode test/live + SumUp),
convertidos a PD (amount * 100). Cuenta todas las pasarelas y donaciones mixtas y
no baja al gastar PD. Se usa max(donatedPD, saldo) para no rebajar el rango a
nadie (p.ej. PD de promo). getAccountDashboard expone donatedPD. Verificado:
cuenta 15 con €43 en pagos -> Nivel 11 aunque el saldo sea 0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 20:25:54 +00:00
Inna dc3cd411f6 Zonas ES: añadir a mano los 3 ids restantes (cobertura EN/ES completa)
15921 'The Den' -> 'La Guarida'; 16406/16407 '[DNT]' (marcador interno de
Blizzard, se conserva). Ahora todos los ids del mapa EN tienen también ES.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 20:19:19 +00:00
Inna 01948ba356 Zonas ES: añadir las que faltaban desde FusionCMS (9156 -> 9672)
Fusiona las 516 zonas ausentes del wow_zones.php español de FusionCMS en
lib/data/zone-names.json (solo las que faltaban; se conservan las existentes),
ordenado por id. Ahora todos los ids con nombre EN tienen también ES.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 20:17:11 +00:00
Inna 2e9106f0bf Ficha de personaje: zona/raza/clase multiidioma (ES/EN)
Añade mapa de zonas en inglés (lib/data/zone-names-en.json, 9675 zonas de
FusionCMS wow_zones.php; cobertura 100% de los ids del mapa ES) y nombres de
raza/clase EN (wow_constants.php). getZoneName/getRaceName/getClassName aceptan
locale (EN cae a ES si falta). getAccountDashboard(session, locale) lo propaga y
my-account pasa el idioma. El dinero (oro/plata/cobre) usa iconos, universal.
Verificado: Innadin -> Human/Paladin/Stormwind City en /en.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 20:11:30 +00:00
Inna 794021f9a3 changelogs: fecha por idioma (es-ES / en-US)
formatFecha usaba es-ES fijo; ahora recibe el locale y formatea en en-US para
inglés. /en/changelogs muestra "July 14, 2026 at 07:55 PM"; /es/ en español.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 19:58:31 +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 cc6c76859c Foro multiidioma: nombres/descripciones de categorías y foros (ES/EN)
forum_categories.name_en y forums.name_en/description_en (sql/add_forum_en.sql,
aplicado en prod y traducidos los existentes: Comunidad/Anuncios/Discusión general).
getForumIndex(locale) y getForum(id, locale) usan EN si existe, si no caen al
español. Las páginas del foro pasan el locale. Labels (Temas/Mensajes) ya estaban
traducidos. Verificado: /en/forum en inglés, /es/forum en español.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 19:50:20 +00:00
Inna 1d2aae5df2 ban-history: alcance y estado multiidioma
getSanctions devuelve claves (scopeKey account/battlenet/character + scopeName;
statusKey active/activePermanent/expired) en vez de español. La página traduce
alcance ("Character: {name}") y estado; "Permanente" ya usaba clave. Motivo y
autor son datos del GM (no se traducen). Nuevas claves History.ban.scope/status.
Verificado con sanciones de prueba (todos los combos resuelven en es y en).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 19:44:09 +00:00
Inna 16ae9f0db8 security-history: acción y estado web multiidioma
La lib devolvía la acción ("Token de seguridad solicitado") y el estado del login
web ("Conexión exitosa"/"Contraseña incorrecta") en español. Ahora devuelve claves
(actionKey='tokenRequested'; statusKey='success'/'wrongPassword'/'other' + statusRaw)
y la página las traduce (History.security.action/webStatus). El coloreado rojo pasa
a depender de statusKey==='wrongPassword'. Verificado con datos reales.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 19:39:46 +00:00
Inna 19d3c43a76 trans-history: concepto multiidioma (helper de concepto compartido)
Extrae la lógica de concepto traducible a lib/tx-concept.ts (buildConcept +
purchasedPD + SERVICE_CONCEPT) y la reutilizan points-history y trans-history.
La columna Concepto de trans-history ahora se traduce (reusa History.points.concept.*)
en vez de mostrar el product_name en español. Corrige también la sombra de
variable en PlatformBox (map t -> tx). Verificado con la cuenta 15.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 19:35:18 +00:00
Inna b2e7ab1b88 points-history: concepto/método/estado multiidioma
Los valores de las columnas Concepto/Método/Estado venían en español desde la lib.
Ahora getPointsHistory devuelve CLAVES (conceptKey+args, method 'vote'/'promo',
status 'delivered'/'pending'/'credited') y la página las traduce. Concepto por
servicio ("Rename character: {char}", "Vote on {site}", "Code {code}", "{n} PD");
los pagos heredados sin servicio caen a conceptRaw. Claves nuevas en History.points.
Verificado con la cuenta 15: todas las combinaciones resuelven en es y en.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 19:29:20 +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 81e1450e6b i18n: títulos de pestaña por idioma (metadata -> generateMetadata)
Los <title> estáticos estaban en español fijo. Se migran 31 páginas a
generateMetadata reutilizando la clave de título ya traducida de cada página
(o del <h1>). Se traducen además los PageShell title hardcodeados de las 6
páginas CharServiceB y los títulos de download-client y changelogs (+ su
mensaje de error). tsc/build OK, paridad es/en, <title> cambia por idioma.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 19:07:25 +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 906a18000e Header: versión en el CSS del tema para forzar recarga de caché
El nav ya mide igual que el original (1112px, items 174px, Futura) tras el fix de
box-sizing; el CSS del tema se servía sin versión y quedaba cacheado. Se añade
?v=2 a novawow-style.css para bustear la caché del navegador.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 15:50:04 +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 dd748d64d8 Header: restaurar content-box en el nav (tamaño como el original)
El tema nw-ryu se diseñó para content-box; los items del nav usan min-width:126px
+ padding:24px (ancho total 174px). El preflight de Tailwind fuerza border-box, que
mete el padding dentro del min-width -> items ~48px más estrechos y header apretado
respecto a ultimowow.com. Se revierte a content-box en .nav-bar a / .nav-dropdown-btn
/ .nav-dropdown-content a (mismo patrón que ya se hizo con inputs/tablas/img).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 15:10:03 +00:00
Inna adb2d86f0b select-account: mostrar WOW1/WOW2/WOW3 en vez de 15#1/15#2/15#3
El selector de cuentas de juego listaba el nombre interno (15#1). Ahora usa
wowAccountLabel (mismo criterio que my-account/cabecera): «15#1» → «WOW1». La
etiqueta se calcula en el Server Component (bnet.ts importa crypto, no vale en
cliente) y se pasa al formulario.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 14:57:30 +00:00
Inna 1f533981c7 Login: navegación completa tras autenticar (cabecera no se actualizaba)
Con router.push el layout persiste entre rutas, así que la cabecera seguía
mostrando "Conectar/Crear cuenta" tras el login hasta recargar. Ahora login y
select-account hacen window.location.assign(/{locale}/...) para que el servidor
re-renderice el layout/cabecera con la sesión nueva.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 14:54:40 +00:00
Inna d9c29bdc68 log-out: redirect relativo (arreglar localhost tras el proxy)
Construir la URL desde request.url daba https://localhost:3001/es detrás de Caddy
(usa la dirección interna). Ahora el Location es relativo (/es), que el navegador
resuelve contra el dominio público real.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 14:49:12 +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 0aed48db4b Añadir ruta /log-out (cierre de sesión) por idioma
Route Handler GET en app/[locale]/log-out: destruye la cookie de sesión y
redirige (303) a /{locale}. Enlace directo visitable (/es/log-out, /en/log-out)
sin depender de JS; reutiliza getSession().destroy().

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 14:41:19 +00:00
Inna 6ba36f0ace i18n: prefijo de idioma en todas las rutas (localePrefix always)
Antes el idioma por defecto (es) se servía sin prefijo. Ahora todas las URLs
llevan /es o /en; la raíz / redirige a /es y las rutas sin prefijo redirigen al
idioma por defecto con prefijo.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 14:37:39 +00:00
Inna dcd59074cf security-history: mostrar WOW1 + cuenta Battle.net en vez de 15#1
La columna Usuario mostraba el nombre interno de la cuenta de juego (15#1). Ahora
muestra la etiqueta WOW1 (nº tras #; con varias serían WOW2, WOW3…) y debajo la
cuenta Battle.net (email), sin añadir columnas. Helper wowAccountLabel extraído a
lib/bnet.ts (mismo criterio que my-account).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 14:33:50 +00:00
Inna 41b42eddc2 Añadir /security-history (Historial de seguridad): actividad, reino, web
Tres tablas: actividad (solicitudes de token, home_securitytoken), conexiones
al reino (logs_ip_actions + account.last_ip/last_login como conexión actual),
y conexiones web (home_loginattempt, estado Exito/Fracaso -> Conexión exitosa/
Contraseña incorrecta). lib/security-history.ts (getSecurityHistory), tolerante
si falta la tabla. Django era stub.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 14:27:51 +00:00
Inna 72e8000b26 Añadir /ban-history (Historial de sanciones): baneos y muteos
Lee las BD de AzerothCore: baneos de account_banned (cuenta),
battlenet_account_bans (Battle.net) y character_banned (personajes de la
cuenta); muteos de account_muted. Estado Activo/Activo (permanente)/Expirado
según bandate/unbandate/active. Dos tablas (baneos con alcance, muteos) + info.
lib/ban-history.ts (getSanctions), tolerante si AC no está poblado. Django stub.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 14:22:05 +00:00
Inna edde2f78ab Añadir /trans-history (Historial de transacciones): solo Stripe y SumUp
Dos cajas por pasarela (Stripe mode test/live, SumUp mode sumup) desde
home_stripelog, con logo, nota y tabla ID/Estado/Concepto/Fecha/Cantidad.
Estado PAID (fulfilled=1) / PENDING. Se omiten dLocal, Crypto y PayPal del
diseño original. lib/trans-history.ts (getPaymentTransactions). Django era stub.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 14:14:08 +00:00
Inna 869ce07871 Añadir /points-history (Historial de PD y PV) con Stripe y SumUp
Historial unificado por cuenta que combina las fuentes reales: home_stripelog
(pagos Stripe mode test/live + SumUp mode sumup), home_votelog (PV de votos) y
home_promoredemption (PD/PV por código). Detecta compras de PD ("N PD") vs
servicios pagados en €. lib/points-history.ts (getPointsHistory + getPointsBalances)
y página con el diseño (info + tabla Fecha/Concepto/Método/PD/PV/Importe/Estado
+ saldo actual). El Django original solo tenía un stub.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 14:07:02 +00:00
Inna fc98ddb624 send-gift: subir precios de 0.50 a 1.00 € (mínimo de cobro de SumUp)
SumUp no permite cobros por debajo de 1 €. Se actualizan las dos pociones
(0.50 -> 1.00) en el seed y en la BD de prod.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-14 13:57:23 +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