send-gift: rediseño al original — es la tienda, pero regalando
El original lo dice en su propio texto ("los objetos disponibles son los mismos
de la tienda") y lo confirma su JS, que usa #store-list y .store-add-button: el
regalo NO tiene catálogo propio, es la tienda con el correo a otro personaje.
Nosotros teníamos una tabla aparte (home_item) con 8 objetos y precios en euros.
Ahora send-gift monta StoreBrowser en modo `gift`: mismo catálogo (3068 ítems,
PD/PV), mismo carrito con cantidades y las cuatro formas de pago. Antes NO tenía
Stripe: solo SumUp, PD y PV.
Dos pasos, como el original: primero #char-select-div (personaje de origen,
destino, confirmación y token) y solo al pulsar "Mostrar Regalos" aparece el
catálogo. Se borran SendGiftForm, /api/gift/checkout y lib/gift (ya no los usa
nadie); la tabla home_item se queda en la BD, sin usar.
Tres cosas que el usuario pidió y que estaban mal:
- El formulario va con `noValidate`: los avisos los damos nosotros en rojo
(#show-gif-response), no el navegador.
- "Mostrar Regalos" ahora valida contra el SERVIDOR (que el personaje de origen
sea tuyo, que el destino exista y que el token sea correcto). Antes elegías
objetos para descubrir al final que el destino no existía.
- BUG REAL: el nombre del destino distinguía mayúsculas. `characters.name` es
`utf8mb4_bin`, así que "innakh" NO encontraba a "Innakh" (comprobado: 0
resultados; con COLLATE, 1). `findCharacterByName` busca sin distinguir y
devuelve el nombre CANÓNICO, que es el que va al comando SOAP.
La validación vive en lib/gift-check y la usan las dos rutas: /api/gift/check (el
botón) y /api/gift/send, que revalida porque el cliente puede saltarse el paso 1.
También se quita del texto "El pago se realiza mediante SumUp": el original no lo
dice y además ya era falso con cuatro formas de pago.
Verificado: innakh / INNAKH / InNaKh resuelven a "Innakh"; token malo y destino
inexistente salen en rojo sin pasar al catálogo. Con 500 PD de saldo de prueba,
2 copias de un ítem de 200 pasan el cobro (deliveryFailed por el worldserver
caído, con su reembolso) y 3 dan insufficientPd: el servidor cobra por copias.
Datos de prueba borrados.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,14 +1,7 @@
|
||||
import type { Metadata } from 'next'
|
||||
import { NoteLegend } from '@/components/NoteLegend'
|
||||
import { getTranslations, setRequestLocale } from 'next-intl/server'
|
||||
import { redirect, Link } from '@/i18n/navigation'
|
||||
import { getSession } from '@/lib/session'
|
||||
import { getGameCharacters } from '@/lib/characters'
|
||||
import { getDPointsBalance, getVPointsBalance } from '@/lib/dpoints'
|
||||
import { getGiftCatalog } from '@/lib/gift'
|
||||
import { PageShell } from '@/components/PageShell'
|
||||
import { ServiceBox } from '@/components/ServiceBox'
|
||||
import { SendGiftForm } from '@/components/SendGiftForm'
|
||||
import { getRealmName } from '@/lib/realm'
|
||||
import { GiftPage } from '@/components/GiftPage'
|
||||
|
||||
export const dynamic = 'force-dynamic'
|
||||
|
||||
@@ -21,59 +14,5 @@ export async function generateMetadata({ params }: { params: Promise<{ locale: s
|
||||
export default async function SendGiftPage({ params }: { params: Promise<{ locale: string }> }) {
|
||||
const { locale } = await params
|
||||
setRequestLocale(locale)
|
||||
const t = await getTranslations('CharService')
|
||||
|
||||
const session = await getSession()
|
||||
if (!session.bnetId) redirect({ href: '/log-in', locale })
|
||||
if (!session.username) redirect({ href: '/select-account', locale })
|
||||
|
||||
const [chars, catalog, pdBalance, vpBalance] = await Promise.all([
|
||||
getGameCharacters(session.accountId!),
|
||||
getGiftCatalog(),
|
||||
getDPointsBalance(session.accountId!),
|
||||
getVPointsBalance(session.accountId!),
|
||||
])
|
||||
const currency = process.env.SUMUP_CURRENCY === 'EUR' ? '€' : process.env.SUMUP_CURRENCY || '€'
|
||||
|
||||
return (
|
||||
<PageShell title={t('sendGift.pageTitle')}>
|
||||
<ServiceBox>
|
||||
<br />
|
||||
<p>
|
||||
{t.rich('sendGift.intro', { s: (c) => <span>{c}</span> })}
|
||||
</p>
|
||||
<br />
|
||||
<p>
|
||||
{t('sendGift.explain1')}
|
||||
</p>
|
||||
<p>{t('sendGift.explain2')}</p>
|
||||
<br />
|
||||
<p>
|
||||
{t.rich('sendGift.explain3', { s: (c) => <span>{c}</span> })}
|
||||
</p>
|
||||
<br />
|
||||
<p>
|
||||
{t.rich('sendGift.securityTokenHint', { link: (c) => <Link href="/security-token" target="_blank">{c}</Link> })}
|
||||
</p>
|
||||
<br />
|
||||
<fieldset>
|
||||
<NoteLegend />
|
||||
<div className="separate2">
|
||||
<p>
|
||||
{t('sendGift.noteIrreversible')}
|
||||
</p>
|
||||
</div>
|
||||
</fieldset>
|
||||
<br />
|
||||
|
||||
<SendGiftForm
|
||||
characters={chars.map((c) => ({ name: c.name, classCss: c.classCss }))}
|
||||
catalog={catalog}
|
||||
currency={currency}
|
||||
pdBalance={pdBalance}
|
||||
vpBalance={vpBalance}
|
||||
/>
|
||||
</ServiceBox>
|
||||
</PageShell>
|
||||
)
|
||||
return <GiftPage locale={locale} realm={await getRealmName()} />
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user