'use client' import { useState } from 'react' import { useTranslations } from 'next-intl' import { Turnstile } from '@/components/Turnstile' import { CharacterSelect, type CharOption } from '@/components/CharacterSelect' function tradeErrorKey(error?: string): string { switch (error) { case 'missingFields': return 'missingFields' case 'invalidAmount': return 'invalidAmount' case 'characterNotFound': case 'characterNotOwned': return 'characterInvalid' case 'captcha': return 'captcha' case 'wrongPassword': return 'wrongPassword' case 'invalidToken': return 'invalidToken' case 'insufficientPoints': return 'insufficientPoints' case 'codeNotFound': return 'codeNotFound' case 'codeUnavailable': return 'codeUnavailable' case 'cannotRedeemOwn': return 'cannotRedeemOwn' case 'characterOnline': return 'characterOnline' case 'insufficientGold': return 'insufficientGold' case 'creatorInsufficient': return 'creatorInsufficient' case 'locked': return 'locked' case 'deliveryFailed': return 'deliveryFailed' case 'notAuthenticated': return 'notAuthenticated' default: return 'generic' } } function PasswordInput({ id, value, onChange, placeholder, maxLength, }: { id: string value: string onChange: (v: string) => void placeholder: string maxLength: number }) { const [show, setShow] = useState(false) return ( <> onChange(e.target.value)} placeholder={placeholder} />{' '} setShow((s) => !s)} /> ) } /* ---------------------------------- VENTA ---------------------------------- */ function SellForm({ characters, visible }: { characters: CharOption[]; visible: boolean }) { const t = useTranslations('Points') const tradeError = (error?: string) => t(`trade.errors.${tradeErrorKey(error)}`) const [points, setPoints] = useState('') const [gold, setGold] = useState('') const [character, setCharacter] = useState('') const [password, setPassword] = useState('') const [token, setToken] = useState('') const [captcha, setCaptcha] = useState('') const [captchaKey, setCaptchaKey] = useState(0) const [busy, setBusy] = useState(false) const [message, setMessage] = useState<{ ok: boolean; text: string } | null>(null) const [created, setCreated] = useState<{ code: string; points: number; gold: number } | null>(null) async function handleSubmit(e: React.FormEvent) { e.preventDefault() if (busy) return setBusy(true) setMessage(null) setCreated(null) try { const res = await fetch('/api/dpoints/trade/create', { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'same-origin', body: JSON.stringify({ points: Number(points), gold: Number(gold), character, password, token: token.trim(), turnstile: captcha, }), }) const data: { success?: boolean; error?: string; code?: { code: string; points: number; gold: number } } = await res.json() if (data.success && data.code) { setCreated(data.code) setMessage({ ok: true, text: t('trade.codeCreated') }) setPoints('') setGold('') setPassword('') setToken('') } else { setMessage({ ok: false, text: tradeError(data.error) }) setCaptcha('') setCaptchaKey((k) => k + 1) } } catch { setMessage({ ok: false, text: tradeError() }) setCaptcha('') setCaptchaKey((k) => k + 1) } finally { setBusy(false) } } return (
{t('trade.sellPointsLabel')}
setPoints(e.target.value)} placeholder={t('trade.sellPointsPlaceholder')} required />
{t('trade.sellGoldLabel')}
setGold(e.target.value)} placeholder={t('trade.sellGoldPlaceholder')} required />
{t('trade.sellCharLabel')}

setToken(e.target.value)} placeholder={t('trade.tokenPlaceholder')} required />

{message && {message.text}} {created && (
{t('trade.createdLegend')}

{t('trade.codeIdLabel')} {created.code}

{t.rich('trade.createdValue', { points: created.points, gold: created.gold, s: (c) => {c} })}

{t('trade.createdHint')}

)}
) } /* ---------------------------------- COMPRA --------------------------------- */ function BuyForm({ characters, visible }: { characters: CharOption[]; visible: boolean }) { const t = useTranslations('Points') const tradeError = (error?: string) => t(`trade.errors.${tradeErrorKey(error)}`) const [code, setCode] = useState('') const [character, setCharacter] = useState('') const [password, setPassword] = useState('') const [token, setToken] = useState('') const [captcha, setCaptcha] = useState('') const [captchaKey, setCaptchaKey] = useState(0) const [busy, setBusy] = useState(false) const [message, setMessage] = useState<{ ok: boolean; text: string } | null>(null) const [checkInfo, setCheckInfo] = useState<{ points: number; gold: number } | null>(null) async function handleCheck() { if (busy || !code.trim()) return setBusy(true) setMessage(null) setCheckInfo(null) try { const res = await fetch('/api/dpoints/trade/check', { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'same-origin', body: JSON.stringify({ code: code.trim() }), }) const data: { success?: boolean; error?: string; points?: number; gold?: number } = await res.json() if (data.success && data.points != null && data.gold != null) { setCheckInfo({ points: data.points, gold: data.gold }) setMessage({ ok: true, text: t('trade.checkResult', { points: data.points, gold: data.gold }) }) } else { setMessage({ ok: false, text: tradeError(data.error) }) } } catch { setMessage({ ok: false, text: tradeError() }) } finally { setBusy(false) } } async function handleRedeem(e: React.FormEvent) { e.preventDefault() if (busy) return if (!window.confirm(t('trade.redeemConfirm'))) return setBusy(true) setMessage(null) try { const res = await fetch('/api/dpoints/trade/redeem', { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'same-origin', body: JSON.stringify({ code: code.trim(), character, password, token: token.trim(), turnstile: captcha }), }) const data: { success?: boolean; error?: string; points?: number; gold?: number } = await res.json() if (data.success) { setMessage({ ok: true, text: t('trade.redeemSuccess', { points: data.points ?? 0, gold: data.gold ?? 0, character }) }) setCode('') setPassword('') setToken('') setCheckInfo(null) } else { setMessage({ ok: false, text: tradeError(data.error) }) setCaptcha('') setCaptchaKey((k) => k + 1) } } catch { setMessage({ ok: false, text: tradeError() }) setCaptcha('') setCaptchaKey((k) => k + 1) } finally { setBusy(false) } } return (
{checkInfo && ( )}
{t('trade.buyCodeLabel')}
setCode(e.target.value)} placeholder={t('trade.buyCodePlaceholder')} required />

{t('trade.checkInfo', { points: checkInfo.points, gold: checkInfo.gold })}

{t('trade.buyCharLabel')}

setToken(e.target.value)} placeholder={t('trade.tokenPlaceholder')} required />

{message && {message.text}}
) } export function TradePointsForm({ characters }: { characters: CharOption[] }) { const t = useTranslations('Points') // Como el original: al cargar no se muestra ningĂșn formulario; se revela al // pulsar VENTA o COMPRA. const [active, setActive] = useState<'sell' | 'buy' | null>(null) if (characters.length === 0) { return (

{t('trade.noCharacters')}
) } return (




) }