diff --git a/web-next/app/[locale]/rename-character/page.tsx b/web-next/app/[locale]/rename-character/page.tsx
new file mode 100644
index 0000000..2eb3b74
--- /dev/null
+++ b/web-next/app/[locale]/rename-character/page.tsx
@@ -0,0 +1,66 @@
+import type { Metadata } from 'next'
+import { setRequestLocale } from 'next-intl/server'
+import { redirect } from '@/i18n/navigation'
+import { getSession } from '@/lib/session'
+import { getGameCharacters } from '@/lib/characters'
+import { getRenamePrice } from '@/lib/prices'
+import { PageShell } from '@/components/PageShell'
+import { ServiceBox } from '@/components/ServiceBox'
+import { PaidServiceForm } from '@/components/PaidServiceForm'
+
+export const dynamic = 'force-dynamic'
+
+export const metadata: Metadata = { title: 'Renombrar personaje' }
+
+export default async function RenameCharacterPage({ params }: { params: Promise<{ locale: string }> }) {
+ const { locale } = await params
+ setRequestLocale(locale)
+
+ const session = await getSession()
+ if (!session.bnetId) redirect({ href: '/login', locale })
+ if (!session.username) redirect({ href: '/select-account', locale })
+
+ const [chars, price] = await Promise.all([getGameCharacters(session.accountId!), getRenamePrice()])
+
+ return (
+
+ )
+}
diff --git a/web-next/app/[locale]/rename/page.tsx b/web-next/app/[locale]/rename/page.tsx
deleted file mode 100644
index 6319f92..0000000
--- a/web-next/app/[locale]/rename/page.tsx
+++ /dev/null
@@ -1,8 +0,0 @@
-import { ServicePageContent } from '@/components/ServicePageContent'
-
-export const dynamic = 'force-dynamic'
-
-export default async function Page({ params }: { params: Promise<{ locale: string }> }) {
- const { locale } = await params
- return
-}
diff --git a/web-next/app/[locale]/revive-character/page.tsx b/web-next/app/[locale]/revive-character/page.tsx
new file mode 100644
index 0000000..fab48bf
--- /dev/null
+++ b/web-next/app/[locale]/revive-character/page.tsx
@@ -0,0 +1,8 @@
+import { ReviveServiceContent } from '@/components/ReviveServiceContent'
+
+export const dynamic = 'force-dynamic'
+
+export default async function ReviveCharacterPage({ params }: { params: Promise<{ locale: string }> }) {
+ const { locale } = await params
+ return
+}
diff --git a/web-next/app/[locale]/security-2falogin/page.tsx b/web-next/app/[locale]/security-2falogin/page.tsx
index 8daac6c..b6de089 100644
--- a/web-next/app/[locale]/security-2falogin/page.tsx
+++ b/web-next/app/[locale]/security-2falogin/page.tsx
@@ -27,8 +27,8 @@ export default async function Security2faLoginPage({ params }: { params: Promise
Información
- Regresar a mi cuenta
- Regresar
+ Regresar a mi cuenta
+ Regresar
diff --git a/web-next/app/[locale]/select-account/SelectAccountForm.tsx b/web-next/app/[locale]/select-account/SelectAccountForm.tsx
index e87ea9f..1a713a7 100644
--- a/web-next/app/[locale]/select-account/SelectAccountForm.tsx
+++ b/web-next/app/[locale]/select-account/SelectAccountForm.tsx
@@ -27,7 +27,7 @@ export function SelectAccountForm({ accounts }: { accounts: GameAccount[] }) {
body: JSON.stringify({ accountId: id }),
})
const data: { success?: boolean } = await res.json()
- if (data.success) router.push('/account')
+ if (data.success) router.push('/my-account')
else {
setError(t('error'))
setBusy(null)
diff --git a/web-next/app/[locale]/service-success/page.tsx b/web-next/app/[locale]/service-success/page.tsx
index 6c72ca9..2608a24 100644
--- a/web-next/app/[locale]/service-success/page.tsx
+++ b/web-next/app/[locale]/service-success/page.tsx
@@ -1,6 +1,7 @@
import { getTranslations, setRequestLocale } from 'next-intl/server'
import { fulfillCheckoutSession } from '@/lib/fulfill'
import { isSessionPaid } from '@/lib/stripe'
+import { fulfillSumUpCheckout } from '@/lib/sumup'
import { PageShell } from '@/components/PageShell'
export const dynamic = 'force-dynamic'
@@ -10,19 +11,24 @@ export default async function ServiceSuccessPage({
searchParams,
}: {
params: Promise<{ locale: string }>
- searchParams: Promise<{ service?: string; session_id?: string }>
+ searchParams: Promise<{ service?: string; session_id?: string; provider?: string; ref?: string }>
}) {
const { locale } = await params
setRequestLocale(locale)
- const { service: urlService, session_id } = await searchParams
+ const { service: urlService, session_id, provider, ref } = await searchParams
const t = await getTranslations('Paid')
- // Entrega compartida con el webhook (idempotente). Si el webhook ya entregó,
- // el reclamo atómico devuelve ok=false pero el pago sigue confirmado.
+ // Entrega compartida con el webhook/reconciliación (idempotente vía reclamo atómico).
let status: 'delivered' | 'already' | 'error' = 'error'
let okName: string | null = null
let service = urlService ?? null
- if (session_id) {
+ if (provider === 'sumup' && ref) {
+ const r = await fulfillSumUpCheckout(ref)
+ service = r.service ?? urlService ?? null
+ okName = r.character ?? null
+ if (r.ok) status = 'delivered'
+ else if (r.paid) status = 'already'
+ } else if (session_id) {
const r = await fulfillCheckoutSession(session_id, urlService)
service = r.service ?? urlService ?? null
if (r.ok) {
diff --git a/web-next/app/[locale]/unstuck/page.tsx b/web-next/app/[locale]/unstuck-character/page.tsx
similarity index 100%
rename from web-next/app/[locale]/unstuck/page.tsx
rename to web-next/app/[locale]/unstuck-character/page.tsx
diff --git a/web-next/app/api/character/[service]/checkout/route.ts b/web-next/app/api/character/[service]/checkout/route.ts
index e95af15..036f978 100644
--- a/web-next/app/api/character/[service]/checkout/route.ts
+++ b/web-next/app/api/character/[service]/checkout/route.ts
@@ -1,6 +1,8 @@
+import { randomUUID } from 'crypto'
import { getSession } from '@/lib/session'
import { getGameCharacters } from '@/lib/characters'
import { createCheckoutSession } from '@/lib/stripe'
+import { createSumUpCheckout, sumupConfigured } from '@/lib/sumup'
import { getPaidService } from '@/lib/paid-services'
export async function POST(request: Request, { params }: { params: Promise<{ service: string }> }) {
@@ -39,6 +41,29 @@ export async function POST(request: Request, { params }: { params: Promise<{ ser
const site = process.env.SITE_URL || ''
const ip = (request.headers.get('x-forwarded-for') || '').split(',')[0].trim() || '0.0.0.0'
+ const productName = cfg.productName(character, metadata)
+
+ // Pago por SumUp (euros): al pagar, la reconciliación/return ejecuta la acción
+ // del servicio sobre el personaje (no acredita PD).
+ if (String(body.provider) === 'sumup') {
+ if (!sumupConfigured()) return Response.json({ success: false, error: 'notConfigured' })
+ const reference = randomUUID()
+ const r = await createSumUpCheckout({
+ accountId: session.accountId,
+ username: session.username || '',
+ email: session.bnetEmail || '',
+ acoreIp: ip,
+ amount: price,
+ points: 0,
+ reference,
+ description: productName,
+ returnUrl: `${site}/service-success?service=${service}&provider=sumup&ref=${reference}`,
+ service,
+ characterName: character,
+ })
+ if (!r.success || !r.url) return Response.json({ success: false, error: r.error || 'sumupError' })
+ return Response.json({ success: true, url: r.url })
+ }
const r = await createCheckoutSession({
accountId: session.accountId,
@@ -47,7 +72,7 @@ export async function POST(request: Request, { params }: { params: Promise<{ ser
acoreIp: ip,
amount: price,
characterName: character,
- productName: cfg.productName(character, metadata),
+ productName,
successUrl: `${site}/service-success?service=${service}`,
cancelUrl: `${site}/${service}`,
metadata,
diff --git a/web-next/components/AccountTools.tsx b/web-next/components/AccountTools.tsx
index 1282a69..189cd59 100644
--- a/web-next/components/AccountTools.tsx
+++ b/web-next/components/AccountTools.tsx
@@ -19,7 +19,7 @@ export function AccountTools({ isAdmin }: { isAdmin: boolean }) {
{ href: '/trade-points', icon: 'trade-pd-icon', label: t('svcTradePD'), desc: t('svcTradePDDesc') },
{ href: '/promo-code', icon: 'promo-icon', label: t('svcPromo'), desc: t('svcPromoDesc') },
{ href: '/security-token', icon: 'token-icon', label: t('svcToken'), desc: t('svcTokenDesc') },
- { href: '/recruit', icon: 'recruit-a-friend-icon', label: t('svcRecruit'), desc: t('svcRecruitDesc') },
+ { href: '/recruit-a-friend', icon: 'recruit-a-friend-icon', label: t('svcRecruit'), desc: t('svcRecruitDesc') },
{ href: '/rename-guild', icon: 'rename-guild-icon', label: t('svcRenameGuild'), desc: t('svcRenameGuildDesc') },
{ href: '/vote-points', icon: 'vote-icon', label: t('svcVote'), desc: t('svcVoteDesc') },
{ href: '/d-points', icon: 'dnt-icon', label: t('svcDPoints'), desc: t('svcDPointsDesc') },
@@ -29,10 +29,10 @@ export function AccountTools({ isAdmin }: { isAdmin: boolean }) {
...(isAdmin ? [{ href: '/admin', icon: 'store-icon', label: `🛡️ ${t('adminPanel')}`, desc: t('adminPanelDesc') }] : []),
]
const characterTools: Tool[] = [
- { href: '/unstuck', icon: 'unstuck-icon', label: t('svcUnstuck'), desc: t('svcUnstuckDesc') },
- { href: '/revive', icon: 'revive-icon', label: t('svcRevive'), desc: t('svcReviveDesc') },
- { href: '/rename', icon: 'rename-icon', label: t('svcRename'), desc: t('svcRenameDesc') },
- { href: '/customize', icon: 'customize-icon', label: t('svcCustomize'), desc: t('svcCustomizeDesc') },
+ { href: '/unstuck-character', icon: 'unstuck-icon', label: t('svcUnstuck'), desc: t('svcUnstuckDesc') },
+ { href: '/revive-character', icon: 'revive-icon', label: t('svcRevive'), desc: t('svcReviveDesc') },
+ { href: '/rename-character', icon: 'rename-icon', label: t('svcRename'), desc: t('svcRenameDesc') },
+ { href: '/customize-character', icon: 'customize-icon', label: t('svcCustomize'), desc: t('svcCustomizeDesc') },
{ href: '/change-race', icon: 'change-race-icon', label: t('svcChangeRace'), desc: t('svcChangeRaceDesc') },
{ href: '/change-faction', icon: 'change-faction-icon', label: t('svcChangeFaction'), desc: t('svcChangeFactionDesc') },
{ href: '/level-up', icon: 'level-up-icon', label: t('svcLevelUp'), desc: t('svcLevelUpDesc') },
diff --git a/web-next/components/DPointsTabs.tsx b/web-next/components/DPointsTabs.tsx
index 8e25728..c19fecf 100644
--- a/web-next/components/DPointsTabs.tsx
+++ b/web-next/components/DPointsTabs.tsx
@@ -40,8 +40,8 @@ export function DPointsTabs({ realm, currency }: { realm: string; currency: stri
>
Información
- Regresar a mi cuenta
- Regresar
+ Regresar a mi cuenta
+ Regresar