Armería: búsqueda insensible a mayúsculas, autocompletar y proxy del visor 3D
Tres arreglos: 1) Búsqueda insensible a mayúsculas/minúsculas. Las consultas usaban LIKE directo (sensible según la colación de la tabla), así que 'test' no encontraba 'Test'. Ahora comparan con LOWER(col) LIKE LOWER(?). 2) Autocompletar tipo wowhead. Nuevo /api/armory/suggest + ArmorySearchBox reescrito: al teclear (≥1 carácter, con debounce) muestra un desplegable con personajes, ítems y hermandades que coinciden; clic va directo a la ficha/wowhead. Enter o el botón siguen haciendo la búsqueda completa. 3) Visor 3D «no disponible». Causa: el contenido de wow.zamimg.com/modelviewer no envía cabeceras CORS (el propio README de wow-model-viewer pide un proxy). Se añade un rewrite en next.config (/modelviewer/* -> zamimg) para servirlo same-origin, y el visor usa esas rutas. Además, si falla la resolución de ítems se renderiza el personaje sin equipo, y los errores se registran en consola para diagnóstico. Verificado: 'test' encuentra 'Test'; el autocompletar responde; el proxy /modelviewer/live/viewer/viewer.min.js sirve 200 same-origin. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -15,9 +15,11 @@ import { useEffect, useRef, useState } from 'react'
|
||||
* slot del visor. displayid = transmog si lo hay, si no el del ítem equipado.
|
||||
*/
|
||||
|
||||
const ZAM_VIEWER = 'https://wow.zamimg.com/modelviewer/live/viewer/viewer.min.js'
|
||||
// Same-origin (proxy /modelviewer/* -> zamimg en next.config): evita el bloqueo CORS
|
||||
// del visor, que es lo que dejaba el modelo «no disponible».
|
||||
const ZAM_VIEWER = '/modelviewer/live/viewer/viewer.min.js'
|
||||
const JQUERY = 'https://code.jquery.com/jquery-3.7.1.min.js'
|
||||
const CONTENT_PATH = 'https://wow.zamimg.com/modelviewer/live/'
|
||||
const CONTENT_PATH = '/modelviewer/live/'
|
||||
|
||||
type Win = typeof window & { jQuery?: unknown; $?: unknown; ZamModelViewer?: unknown; CONTENT_PATH?: string }
|
||||
|
||||
@@ -61,10 +63,17 @@ export function ArmoryModel3D({
|
||||
const mv = await import('wow-model-viewer')
|
||||
if (cancelled || !ref.current) return
|
||||
|
||||
const items = await mv.findItemsInEquipments(
|
||||
equip.map((e) => ({ slot: e.slot, entry: e.entry, displayid: e.displayid })),
|
||||
'live',
|
||||
)
|
||||
// La resolución de ítems hace consultas al CDN y puede fallar; si falla, se
|
||||
// renderiza al menos el personaje sin equipo en vez de dejar la ficha vacía.
|
||||
let items: unknown[] = []
|
||||
try {
|
||||
items = await mv.findItemsInEquipments(
|
||||
equip.map((e) => ({ slot: e.slot, entry: e.entry, displayid: e.displayid })),
|
||||
'live',
|
||||
)
|
||||
} catch (err) {
|
||||
console.warn('[armory-3d] no se pudieron resolver los ítems del modelo:', err)
|
||||
}
|
||||
if (cancelled || !ref.current) return
|
||||
|
||||
ref.current.id = ref.current.id || `armory-model-${race}-${gender}`
|
||||
@@ -73,7 +82,8 @@ export function ArmoryModel3D({
|
||||
clearTimeout(failTimer)
|
||||
setState('ok')
|
||||
}
|
||||
} catch {
|
||||
} catch (err) {
|
||||
console.error('[armory-3d] no se pudo cargar el visor 3D:', err)
|
||||
if (!cancelled) {
|
||||
clearTimeout(failTimer)
|
||||
setState('fail')
|
||||
|
||||
Reference in New Issue
Block a user