+ {t('successTitle')}
+ {okName ? (
+ {t('success', { name: okName })}
+ ) : (
+ {t('error')}
+ )}
+
+ )
+}
diff --git a/web-next/app/api/character/rename/checkout/route.ts b/web-next/app/api/character/rename/checkout/route.ts
new file mode 100644
index 0000000..5a1fe65
--- /dev/null
+++ b/web-next/app/api/character/rename/checkout/route.ts
@@ -0,0 +1,41 @@
+import { getSession } from '@/lib/session'
+import { getGameCharacters } from '@/lib/characters'
+import { getRenamePrice } from '@/lib/prices'
+import { createCheckoutSession } from '@/lib/stripe'
+
+export async function POST(request: Request) {
+ const session = await getSession()
+ if (!session.accountId) return Response.json({ success: false, error: 'notAuthenticated' }, { status: 401 })
+
+ let character = ''
+ try {
+ const body = await request.json()
+ character = String(body.character ?? '')
+ } catch {
+ return Response.json({ success: false, error: 'invalidRequest' }, { status: 400 })
+ }
+ if (!character) return Response.json({ success: false, error: 'invalidCharacter' })
+
+ const chars = await getGameCharacters(session.accountId)
+ if (!chars.find((c) => c.name === character)) {
+ return Response.json({ success: false, error: 'invalidCharacter' })
+ }
+
+ const price = await getRenamePrice()
+ const site = process.env.SITE_URL || ''
+ const ip = (request.headers.get('x-forwarded-for') || '').split(',')[0].trim() || '0.0.0.0'
+
+ const r = await createCheckoutSession({
+ accountId: session.accountId,
+ username: session.username || '',
+ email: session.bnetEmail || '',
+ acoreIp: ip,
+ amount: price,
+ characterName: character,
+ productName: `Renombrar personaje: ${character}`,
+ successUrl: `${site}/rename/success`,
+ cancelUrl: `${site}/rename`,
+ })
+ if (!r.success || !r.url) return Response.json({ success: false, error: 'stripeError' })
+ return Response.json({ success: true, url: r.url })
+}
diff --git a/web-next/components/PaidServiceForm.tsx b/web-next/components/PaidServiceForm.tsx
new file mode 100644
index 0000000..fa1fdf3
--- /dev/null
+++ b/web-next/components/PaidServiceForm.tsx
@@ -0,0 +1,77 @@
+'use client'
+
+import { useState } from 'react'
+import { useTranslations } from 'next-intl'
+
+interface Props {
+ characters: string[]
+ checkoutEndpoint: string
+ payLabel: string // ya formateado con el precio
+}
+
+/** Selector de personaje + botón de pago. Redirige al Checkout de Stripe. */
+export function PaidServiceForm({ characters, checkoutEndpoint, payLabel }: Props) {
+ const t = useTranslations('Services')
+ const [character, setCharacter] = useState('')
+ const [busy, setBusy] = useState(false)
+ const [error, setError] = useState