'use client' import { useState } from 'react' import { useTranslations, useLocale } from 'next-intl' import { CharacterSelect, type CharOption } from '@/components/CharacterSelect' import { PaymentMethodSelect, pdCostOf, type PayMethod } from '@/components/PaymentMethodSelect' import { WowheadLink } from '@/components/WowheadLink' import { Turnstile } from '@/components/Turnstile' interface DeletedItem { recoverId: number itemId: number name: string count: number } function itemsError(t: ReturnType, error?: string, minutes?: number): string { switch (error) { case 'characterNotOwned': return t('restoreItems.errors.characterNotOwned') case 'cooldown': return t('restoreItems.errors.cooldown', { minutes: minutes ?? 0 }) case 'soapError': return t('restoreItems.errors.soapError') case 'insufficientPoints': return t('restoreItems.errors.insufficientPoints') case 'captcha': return t('restoreItems.errors.captcha') case 'notAuthenticated': return t('restoreItems.errors.notAuthenticated') default: return t('restoreItems.errors.default') } } export function RestoreItemsForm({ characters, price, pdBalance }: { characters: CharOption[]; price: number; pdBalance: number }) { const t = useTranslations('CharService') const tpay = useTranslations('Pay') const locale = useLocale() const [character, setCharacter] = useState('') const [method, setMethod] = useState(pdBalance >= pdCostOf(price) ? 'pd' : 'sumup') const [captcha, setCaptcha] = useState('') const [captchaKey, setCaptchaKey] = useState(0) const [busy, setBusy] = useState(false) const [items, setItems] = useState(null) const [message, setMessage] = useState<{ ok: boolean; text: string } | null>(null) async function search(e: React.FormEvent) { e.preventDefault() if (busy || !character) return setBusy(true) setMessage(null) try { const res = await fetch('/api/character/restore-items/search', { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'same-origin', body: JSON.stringify({ character, turnstile: captcha }), }) const data: { success?: boolean; error?: string; minutes?: number; items?: DeletedItem[] } = await res.json() if (data.success) { setItems(data.items ?? []) if ((data.items ?? []).length === 0) setMessage({ ok: true, text: t('restoreItems.noDeletedItemsMsg') }) } else { setMessage({ ok: false, text: itemsError(t, data.error, data.minutes) }) } } catch { setMessage({ ok: false, text: itemsError(t) }) } finally { setBusy(false) setCaptcha('') setCaptchaKey((k) => k + 1) } } async function restore(item: DeletedItem) { if (busy) return if (!window.confirm(t('restoreItems.confirm', { name: item.name, price }))) return setBusy(true) setMessage(null) try { const res = await fetch('/api/character/restore-item/checkout', { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'same-origin', body: JSON.stringify({ character, recover_id: String(item.recoverId), provider: method, locale }), }) const data: { success?: boolean; url?: string; error?: string; message?: string } = await res.json() if (data.success && data.url) { window.location.assign(data.url) // éxito PD, o checkout de SumUp/Stripe return } const payErr = data.error && tpay.has(`errors.${data.error}`) ? tpay(`errors.${data.error}`) : undefined setMessage({ ok: false, text: data.message || payErr || itemsError(t, data.error) }) setBusy(false) } catch { setMessage({ ok: false, text: itemsError(t) }) setBusy(false) } } function reset() { setItems(null) setMessage(null) setCharacter('') setCaptcha('') setCaptchaKey((k) => k + 1) } return (
{items === null ? (

) : (

{t('restoreItems.deletedItemsOf', { character })}

{items.length === 0 ? (

{t('restoreItems.noDeletedItems')}

) : ( <> {items.map((it) => ( ))}
{it.name} {it.count > 1 ? ` x${it.count}` : ''}
)}

{ e.preventDefault(); reset() }}>{t('restoreItems.queryOther')}

)}
{message && {message.text}}
) }