d-points: dejar sólo Stripe y SumUp con compra de PD funcional
Elimina las pestañas de PayPal/dLocal/Crypto/Skrill y por país; deja Información + Stripe + SumUp (las dos únicas pasarelas que se usarán). - Stripe: totalmente funcional reutilizando createCheckoutSession + webhook + página de éxito. Nueva ruta /api/dpoints/checkout crea la sesión con importe elegido por el usuario (1 unidad = 100 PD). - SumUp: integración real (lib/sumup.ts) mediante checkout hospedado, habilitada al definir SUMUP_API_KEY/SUMUP_MERCHANT_CODE; si no, avisa. - Nuevo servicio de entrega `dpoints` (lib/paid-services.ts) que acredita PD en home_api_points; entrega idempotente vía reclamo atómico. - Página /d-points-success entrega ambos proveedores (session_id/ref). - Iconos SVG generados para cada pasarela (stripe/sumup, marca + wordmark). - Moneda configurable con DP_CURRENCY (por defecto EUR). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,54 @@
|
|||||||
|
import { setRequestLocale } from 'next-intl/server'
|
||||||
|
import { Link } from '@/i18n/navigation'
|
||||||
|
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'
|
||||||
|
|
||||||
|
export default async function DPointsSuccessPage({
|
||||||
|
params,
|
||||||
|
searchParams,
|
||||||
|
}: {
|
||||||
|
params: Promise<{ locale: string }>
|
||||||
|
searchParams: Promise<{ provider?: string; session_id?: string; ref?: string }>
|
||||||
|
}) {
|
||||||
|
const { locale } = await params
|
||||||
|
setRequestLocale(locale)
|
||||||
|
const { provider, session_id, ref } = await searchParams
|
||||||
|
|
||||||
|
// Entrega compartida con el webhook/return (idempotente vía reclamo atómico).
|
||||||
|
let status: 'ok' | 'already' | 'error' = 'error'
|
||||||
|
|
||||||
|
if (provider === 'sumup' && ref) {
|
||||||
|
const r = await fulfillSumUpCheckout(ref)
|
||||||
|
if (r.ok) status = 'ok'
|
||||||
|
else if (r.paid) status = 'already'
|
||||||
|
} else if (session_id) {
|
||||||
|
const r = await fulfillCheckoutSession(session_id)
|
||||||
|
if (r.ok) status = 'ok'
|
||||||
|
else if (await isSessionPaid(session_id)) status = 'already'
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PageShell title="Adquirir PD">
|
||||||
|
<div className="box-content">
|
||||||
|
<div className="body-box-content centered">
|
||||||
|
{status === 'ok' ? (
|
||||||
|
<span className="ok-form-response">¡Pago completado! Tus PD ya fueron acreditados a tu cuenta.</span>
|
||||||
|
) : status === 'already' ? (
|
||||||
|
<span className="ok-form-response">Este pago ya había sido procesado. Tus PD están acreditados.</span>
|
||||||
|
) : (
|
||||||
|
<span className="red-form-response">No pudimos confirmar tu pago. Si se realizó el cargo, contacta con soporte.</span>
|
||||||
|
)}
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<p>
|
||||||
|
<Link href="/account">← Regresar a mi cuenta</Link>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</PageShell>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
import type { Metadata } from 'next'
|
import type { Metadata } from 'next'
|
||||||
import { headers } from 'next/headers'
|
|
||||||
import { setRequestLocale } from 'next-intl/server'
|
import { setRequestLocale } from 'next-intl/server'
|
||||||
import { redirect } from '@/i18n/navigation'
|
import { redirect } from '@/i18n/navigation'
|
||||||
import { getSession } from '@/lib/session'
|
import { getSession } from '@/lib/session'
|
||||||
@@ -20,25 +19,11 @@ export default async function DPointsPage({ params }: { params: Promise<{ locale
|
|||||||
if (!session.username) redirect({ href: '/select-account', locale })
|
if (!session.username) redirect({ href: '/select-account', locale })
|
||||||
|
|
||||||
const realm = await getRealmName()
|
const realm = await getRealmName()
|
||||||
const h = await headers()
|
const currency = (process.env.DP_CURRENCY || 'eur').toLowerCase()
|
||||||
const ip = (h.get('x-forwarded-for') || '').split(',')[0].trim() || '0.0.0.0'
|
|
||||||
const host = h.get('x-forwarded-host') || h.get('host') || ''
|
|
||||||
const proto = h.get('x-forwarded-proto') || 'https'
|
|
||||||
const origin = host ? `${proto}://${host}` : ''
|
|
||||||
|
|
||||||
// Pasarelas automáticas: se habilitan al configurar sus credenciales por entorno.
|
|
||||||
const paypalBusiness = process.env.PAYPAL_BUSINESS_EMAIL || ''
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageShell title="Adquirir PD">
|
<PageShell title="Adquirir PD">
|
||||||
<DPointsTabs
|
<DPointsTabs realm={realm} currency={currency} />
|
||||||
realm={realm}
|
|
||||||
username={session.username!}
|
|
||||||
ip={ip}
|
|
||||||
locale={locale}
|
|
||||||
origin={origin}
|
|
||||||
paypalBusiness={paypalBusiness}
|
|
||||||
/>
|
|
||||||
</PageShell>
|
</PageShell>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,78 @@
|
|||||||
|
import { randomUUID } from 'crypto'
|
||||||
|
import { getSession } from '@/lib/session'
|
||||||
|
import { createCheckoutSession } from '@/lib/stripe'
|
||||||
|
import { createSumUpCheckout, sumupConfigured } from '@/lib/sumup'
|
||||||
|
import { PD_PER_UNIT, DP_MIN_AMOUNT, DP_MAX_AMOUNT } from '@/lib/dpoints'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inicia la compra de PD por Stripe o SumUp. El importe lo elige el usuario
|
||||||
|
* (1 unidad = 100 PD). Devuelve la URL de checkout a la que redirigir.
|
||||||
|
*/
|
||||||
|
export async function POST(request: Request) {
|
||||||
|
const session = await getSession()
|
||||||
|
if (!session.accountId || !session.username) {
|
||||||
|
return Response.json({ success: false, error: 'notAuthenticated' }, { status: 401 })
|
||||||
|
}
|
||||||
|
|
||||||
|
let body: Record<string, unknown> = {}
|
||||||
|
try {
|
||||||
|
body = await request.json()
|
||||||
|
} catch {
|
||||||
|
return Response.json({ success: false, error: 'invalidRequest' }, { status: 400 })
|
||||||
|
}
|
||||||
|
|
||||||
|
const provider = String(body.provider ?? '')
|
||||||
|
if (provider !== 'stripe' && provider !== 'sumup') {
|
||||||
|
return Response.json({ success: false, error: 'invalidProvider' }, { status: 400 })
|
||||||
|
}
|
||||||
|
|
||||||
|
const amount = Number(body.amount)
|
||||||
|
if (!Number.isInteger(amount) || amount < DP_MIN_AMOUNT || amount > DP_MAX_AMOUNT) {
|
||||||
|
return Response.json({ success: false, error: 'invalidAmount' })
|
||||||
|
}
|
||||||
|
|
||||||
|
const points = amount * PD_PER_UNIT
|
||||||
|
const site = process.env.SITE_URL || ''
|
||||||
|
const ip = (request.headers.get('x-forwarded-for') || '').split(',')[0].trim() || '0.0.0.0'
|
||||||
|
const currency = process.env.DP_CURRENCY || 'eur'
|
||||||
|
|
||||||
|
if (provider === 'stripe') {
|
||||||
|
const r = await createCheckoutSession({
|
||||||
|
accountId: session.accountId,
|
||||||
|
username: session.username,
|
||||||
|
email: session.bnetEmail || '',
|
||||||
|
acoreIp: ip,
|
||||||
|
amount,
|
||||||
|
currency,
|
||||||
|
characterName: session.username,
|
||||||
|
productName: `${points} PD`,
|
||||||
|
successUrl: `${site}/d-points-success?provider=stripe`,
|
||||||
|
cancelUrl: `${site}/d-points`,
|
||||||
|
metadata: {
|
||||||
|
service: 'dpoints',
|
||||||
|
accountId: String(session.accountId),
|
||||||
|
points: String(points),
|
||||||
|
amount: String(amount),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if (!r.success || !r.url) return Response.json({ success: false, error: 'stripeError' })
|
||||||
|
return Response.json({ success: true, url: r.url })
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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,
|
||||||
|
points,
|
||||||
|
reference,
|
||||||
|
description: `${points} PD`,
|
||||||
|
returnUrl: `${site}/d-points-success?provider=sumup&ref=${reference}`,
|
||||||
|
})
|
||||||
|
if (!r.success || !r.url) return Response.json({ success: false, error: r.error || 'sumupError' })
|
||||||
|
return Response.json({ success: true, url: r.url })
|
||||||
|
}
|
||||||
@@ -419,3 +419,11 @@ textarea:focus {
|
|||||||
.class-warlock { color: #9482c9; }
|
.class-warlock { color: #9482c9; }
|
||||||
.class-druid { color: #ff7d0a; }
|
.class-druid { color: #ff7d0a; }
|
||||||
.class-unknown { color: #f0b100; }
|
.class-unknown { color: #f0b100; }
|
||||||
|
|
||||||
|
/* Logos en línea de las pasarelas de pago (lista de métodos en /d-points) */
|
||||||
|
.pay-inline-logo {
|
||||||
|
height: 18px;
|
||||||
|
width: auto;
|
||||||
|
vertical-align: middle;
|
||||||
|
margin: 0 2px;
|
||||||
|
}
|
||||||
|
|||||||
+144
-670
@@ -1,23 +1,12 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import { useEffect, useState } from 'react'
|
import { useState } from 'react'
|
||||||
import { Link } from '@/i18n/navigation'
|
import { Link } from '@/i18n/navigation'
|
||||||
|
|
||||||
const IMG = '/nw-themes/nw-ryu/nw-images'
|
const LOGOS = '/nw-themes/nw-ryu/nw-images/nw-logos'
|
||||||
const LOGOS = `${IMG}/nw-logos`
|
const RANKS = '/nw-themes/nw-ryu/nw-images/nw-ranks'
|
||||||
const RANKS = `${IMG}/nw-ranks`
|
|
||||||
const FLAGS = `${IMG}/nw-country-flags`
|
|
||||||
|
|
||||||
type TabId = 'Info' | 'PayPal' | 'dLocal' | 'Crypto' | 'Skrill' | 'Argentina' | 'Chile' | 'Colombia' | 'Perú'
|
type TabId = 'Info' | 'Stripe' | 'SumUp'
|
||||||
|
|
||||||
// Las banderas son .png sólo para México y Panamá; el resto son .webp.
|
|
||||||
function flagSrc(code: string) {
|
|
||||||
const ext = code === 'mx' || code === 'pa' ? 'png' : 'webp'
|
|
||||||
return `${FLAGS}/${code}.${ext}`
|
|
||||||
}
|
|
||||||
function Flag({ code, name }: { code: string; name: string }) {
|
|
||||||
return <img src={flagSrc(code)} alt={name} title={`WoW ${name}`} />
|
|
||||||
}
|
|
||||||
|
|
||||||
const RANK_ROWS = [
|
const RANK_ROWS = [
|
||||||
['1_Newbie', 'Nivel 1', 'Desde 0 PD'],
|
['1_Newbie', 'Nivel 1', 'Desde 0 PD'],
|
||||||
@@ -36,23 +25,10 @@ const RANK_ROWS = [
|
|||||||
['14_GrandMaster', 'Nivel 14', 'Más de 10000 PD'],
|
['14_GrandMaster', 'Nivel 14', 'Más de 10000 PD'],
|
||||||
]
|
]
|
||||||
|
|
||||||
export function DPointsTabs({
|
export function DPointsTabs({ realm, currency }: { realm: string; currency: string }) {
|
||||||
realm,
|
|
||||||
username,
|
|
||||||
ip,
|
|
||||||
locale,
|
|
||||||
origin,
|
|
||||||
paypalBusiness,
|
|
||||||
}: {
|
|
||||||
realm: string
|
|
||||||
username: string
|
|
||||||
ip: string
|
|
||||||
locale: string
|
|
||||||
origin: string
|
|
||||||
paypalBusiness: string
|
|
||||||
}) {
|
|
||||||
const [active, setActive] = useState<TabId>('Info')
|
const [active, setActive] = useState<TabId>('Info')
|
||||||
const [showRanks, setShowRanks] = useState(false)
|
const [showRanks, setShowRanks] = useState(false)
|
||||||
|
const sym = currency === 'usd' ? '$' : '€'
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -68,30 +44,11 @@ export function DPointsTabs({
|
|||||||
<Link className="back-to-account-responsive" href="/account">Regresar</Link>
|
<Link className="back-to-account-responsive" href="/account">Regresar</Link>
|
||||||
</div>
|
</div>
|
||||||
<div className="dnt-sidebar dnt-methods">
|
<div className="dnt-sidebar dnt-methods">
|
||||||
<button className={`dnt-button-2 tablink${active === 'PayPal' ? ' dnt-selected' : ''}`} onClick={() => setActive('PayPal')}>
|
<button className={`dnt-button-2 tablink${active === 'Stripe' ? ' dnt-selected' : ''}`} onClick={() => setActive('Stripe')}>
|
||||||
<img src={`${LOGOS}/paypal-p-logo.webp`} alt="PayPal" title="PayPal" /> PayPal
|
<img src={`${LOGOS}/stripe-p-logo.svg`} alt="Stripe" title="Stripe" /> Stripe
|
||||||
</button>
|
</button>
|
||||||
<button className={`dnt-button-2 tablink${active === 'dLocal' ? ' dnt-selected' : ''}`} onClick={() => setActive('dLocal')}>
|
<button className={`dnt-button-2 tablink${active === 'SumUp' ? ' dnt-selected' : ''}`} onClick={() => setActive('SumUp')}>
|
||||||
<img src={`${LOGOS}/dlocalgo-logo.webp`} alt="dLocal" title="dLocal" /> dLocal go
|
<img src={`${LOGOS}/sumup-p-logo.svg`} alt="SumUp" title="SumUp" /> SumUp
|
||||||
</button>
|
|
||||||
<button className={`dnt-button-2 tablink${active === 'Crypto' ? ' dnt-selected' : ''}`} onClick={() => setActive('Crypto')}>
|
|
||||||
<i className="fab fa-bitcoin" style={{ color: '#f7931a' }}></i>{' '}
|
|
||||||
<span className="new-msg"><sup>¡Nuevo!</sup></span> Crypto
|
|
||||||
</button>
|
|
||||||
<button className={`dnt-button-2 tablink${active === 'Skrill' ? ' dnt-selected' : ''}`} onClick={() => setActive('Skrill')}>
|
|
||||||
<img src={`${LOGOS}/skrill-logo-small.webp`} alt="Skrill" title="Skrill" /> Skrill
|
|
||||||
</button>
|
|
||||||
<button className={`dnt-button-2 tablink${active === 'Argentina' ? ' dnt-selected' : ''}`} onClick={() => setActive('Argentina')}>
|
|
||||||
<Flag code="ar" name="Argentina" /> Argentina
|
|
||||||
</button>
|
|
||||||
<button className={`dnt-button-2 tablink${active === 'Chile' ? ' dnt-selected' : ''}`} onClick={() => setActive('Chile')}>
|
|
||||||
<Flag code="cl" name="Chile" /> Chile
|
|
||||||
</button>
|
|
||||||
<button className={`dnt-button-2 tablink${active === 'Colombia' ? ' dnt-selected' : ''}`} onClick={() => setActive('Colombia')}>
|
|
||||||
<Flag code="co" name="Colombia" /> Colombia
|
|
||||||
</button>
|
|
||||||
<button className={`dnt-button-2 tablink${active === 'Perú' ? ' dnt-selected' : ''}`} onClick={() => setActive('Perú')}>
|
|
||||||
<Flag code="pe" name="Perú" /> Perú
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -132,682 +89,199 @@ export function DPointsTabs({
|
|||||||
<br />
|
<br />
|
||||||
<span>¿Cuáles son los métodos de compra de PD?</span>
|
<span>¿Cuáles son los métodos de compra de PD?</span>
|
||||||
<p>Los métodos de compra disponibles actualmente son:</p>
|
<p>Los métodos de compra disponibles actualmente son:</p>
|
||||||
<p>- PayPal (Para todos los países)</p>
|
<p>- <img className="pay-inline-logo" src={`${LOGOS}/stripe-p-logo.svg`} alt="Stripe" /> Stripe (tarjeta de crédito/débito, para todos los países).</p>
|
||||||
<p>- dLocal Go para Argentina <Flag code="ar" name="Argentina" />, Bolivia <Flag code="bo" name="Bolivia" />, Chile <Flag code="cl" name="Chile" />, Colombia <Flag code="co" name="Colombia" />, Costa Rica <Flag code="cr" name="Costa Rica" />, Ecuador <Flag code="ec" name="Ecuador" />, Guatemala <Flag code="gt" name="Guatemala" />, México <Flag code="mx" name="México" />, Panamá <Flag code="pa" name="Panamá" />, Perú <Flag code="pe" name="Perú" />, Paraguay <Flag code="py" name="Paraguay" />, Uruguay <Flag code="uy" name="Uruguay" />.</p>
|
<p>- <img className="pay-inline-logo" src={`${LOGOS}/sumup-p-logo.svg`} alt="SumUp" /> SumUp (tarjeta de crédito/débito).</p>
|
||||||
<p>- Criptomonedas (Para todos los países)</p>
|
|
||||||
<p>- Skrill (Para todos los países)</p>
|
|
||||||
<p>- Métodos alternativos sólo para Argentina (<Flag code="ar" name="Argentina" /> ARG)</p>
|
|
||||||
<p>- Métodos alternativos sólo para Chile ( <Flag code="cl" name="Chile" /> CHI)</p>
|
|
||||||
<p>- Métodos alternativos sólo para Colombia (<Flag code="co" name="Colombia" /> COL)</p>
|
|
||||||
<p>- Métodos alternativos sólo para Perú (<Flag code="pe" name="Perú" /> PER)</p>
|
|
||||||
<br />
|
|
||||||
<p>Puedes hacer una sugerencia sobre nuevos métodos en nuestro foro de sugerencias <Link href="/forum">aquí</Link>.</p>
|
|
||||||
<br />
|
<br />
|
||||||
<hr />
|
<hr />
|
||||||
<br />
|
<br />
|
||||||
<span>¿Cuántos PD se reciben?</span>
|
<span>¿Cuántos PD se reciben?</span>
|
||||||
<p>Cada método indicará cuántos PD se reciben.</p>
|
<p>Por cada {sym}1 recibes 100 PD. La cantidad final se indica antes de confirmar el pago.</p>
|
||||||
<br />
|
<br />
|
||||||
<hr />
|
<hr />
|
||||||
<br />
|
<br />
|
||||||
<span>¿Tienes dudas o problemas con una compra?</span>
|
<span>¿Tienes dudas o problemas con una compra?</span>
|
||||||
<p>No realices una compra hasta estar completamente seguro de que has leído esta información y sabes cómo es el proceso que vayas a escoger.</p>
|
<p>No realices una compra hasta estar completamente seguro de que has leído esta información y sabes cómo es el proceso que vayas a escoger.</p>
|
||||||
<p>Si a pesar de leer este instructivo o el de alguna de nuestras herramientas, aún tienes dudas, el equipo de {realm} podrá asesorarte en cualquier momento. Puedes colocar un ticket en el servidor, o contactarnos mediante nuestra plataforma de Discord.</p>
|
<p>Si a pesar de leer este instructivo aún tienes dudas, el equipo de {realm} podrá asesorarte en cualquier momento. Puedes colocar un ticket en el servidor, o contactarnos mediante nuestra plataforma de Discord.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{active === 'PayPal' && (
|
{active === 'Stripe' && <StripeTab realm={realm} sym={sym} />}
|
||||||
<PayPalTab realm={realm} username={username} ip={ip} origin={origin} locale={locale} paypalBusiness={paypalBusiness} />
|
{active === 'SumUp' && <SumUpTab realm={realm} sym={sym} />}
|
||||||
)}
|
|
||||||
{active === 'dLocal' && <DLocalTab username={username} realm={realm} />}
|
|
||||||
{active === 'Crypto' && <CryptoTab username={username} realm={realm} />}
|
|
||||||
{active === 'Skrill' && <SkrillTab />}
|
|
||||||
{active === 'Argentina' && <ArgentinaTab />}
|
|
||||||
{active === 'Chile' && <ChileTab />}
|
|
||||||
{active === 'Colombia' && <ColombiaTab />}
|
|
||||||
{active === 'Perú' && <PeruTab />}
|
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Nota común para pasarelas automáticas sin backend configurado ---------- */
|
/* --------------------------- Lógica de pago común --------------------------- */
|
||||||
function gatewayUnavailable(realm: string) {
|
function checkoutError(error?: string): string {
|
||||||
alert(`Este método de pago aún no está disponible en ${realm}. Por favor, inténtalo de nuevo más tarde o utiliza otro método.`)
|
switch (error) {
|
||||||
|
case 'notConfigured':
|
||||||
|
return 'Este método de pago aún no está disponible. Por favor, utiliza otro método o inténtalo más tarde.'
|
||||||
|
case 'invalidAmount':
|
||||||
|
return 'La cantidad debe ser un número entero entre 1 y 200.'
|
||||||
|
case 'notAuthenticated':
|
||||||
|
return 'Tu sesión ha expirado. Inicia sesión de nuevo.'
|
||||||
|
default:
|
||||||
|
return 'No se pudo iniciar el pago. Inténtalo de nuevo.'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------------------------------- PayPal ---------------------------------- */
|
function usePayment(provider: 'stripe' | 'sumup') {
|
||||||
function PayPalTab({
|
const [amount, setAmount] = useState('')
|
||||||
realm,
|
|
||||||
username,
|
|
||||||
ip,
|
|
||||||
origin,
|
|
||||||
locale,
|
|
||||||
paypalBusiness,
|
|
||||||
}: {
|
|
||||||
realm: string
|
|
||||||
username: string
|
|
||||||
ip: string
|
|
||||||
origin: string
|
|
||||||
locale: string
|
|
||||||
paypalBusiness: string
|
|
||||||
}) {
|
|
||||||
const [accepted, setAccepted] = useState(false)
|
const [accepted, setAccepted] = useState(false)
|
||||||
const configured = Boolean(paypalBusiness)
|
const [busy, setBusy] = useState(false)
|
||||||
|
const [err, setErr] = useState<string | null>(null)
|
||||||
|
|
||||||
function onSubmit(e: React.FormEvent<HTMLFormElement>) {
|
async function pay(e: React.FormEvent<HTMLFormElement>, sym: string) {
|
||||||
if (!configured) {
|
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
gatewayUnavailable(realm)
|
if (!accepted) {
|
||||||
|
alert('Debes aceptar los Términos y Condiciones y la Política de Reembolso')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const form = e.currentTarget
|
const n = Number(amount)
|
||||||
const amount = (form.elements.namedItem('amount') as HTMLInputElement)?.value
|
if (!Number.isInteger(n) || n < 1 || n > 200) {
|
||||||
if (!window.confirm(`Por favor revisa que el valor en USD que has ingresado es correcto.\nEl valor ingresado es el costo final en USD que pagarás al ser redirigido.\n\nEl monto a pagar es ${amount} USD.`)) {
|
setErr(checkoutError('invalidAmount'))
|
||||||
e.preventDefault()
|
return
|
||||||
|
}
|
||||||
|
if (!window.confirm(`Vas a adquirir ${n * 100} PD por ${sym}${n}.\n¿Deseas continuar al pago?`)) return
|
||||||
|
setBusy(true)
|
||||||
|
setErr(null)
|
||||||
|
try {
|
||||||
|
const res = await fetch('/api/dpoints/checkout', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
credentials: 'same-origin',
|
||||||
|
body: JSON.stringify({ provider, amount: n }),
|
||||||
|
})
|
||||||
|
const d: { success?: boolean; url?: string; error?: string } = await res.json()
|
||||||
|
if (d.success && d.url) {
|
||||||
|
window.location.href = d.url
|
||||||
|
return
|
||||||
|
}
|
||||||
|
setErr(checkoutError(d.error))
|
||||||
|
setBusy(false)
|
||||||
|
} catch {
|
||||||
|
setErr(checkoutError())
|
||||||
|
setBusy(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return { amount, setAmount, accepted, setAccepted, busy, err, pay }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------- Formulario -------------------------------- */
|
||||||
|
function AmountForm({
|
||||||
|
provider,
|
||||||
|
sym,
|
||||||
|
buttonLabel,
|
||||||
|
}: {
|
||||||
|
provider: 'stripe' | 'sumup'
|
||||||
|
sym: string
|
||||||
|
buttonLabel: string
|
||||||
|
}) {
|
||||||
|
const st = usePayment(provider)
|
||||||
|
const points = Number(st.amount) > 0 ? Number(st.amount) * 100 : 0
|
||||||
return (
|
return (
|
||||||
<div className="box-content dnt-tab dnt-animate">
|
<>
|
||||||
<div className="body-box-content">
|
<p className="yellow-info centered">{sym}1 = 100 PD</p>
|
||||||
<span>¿Qué es PayPal?</span><img className="pp-icon" src={`${LOGOS}/paypal-logo.webp`} alt="PayPal" />
|
<p className="centered second-brown">Valor mínimo: {sym}1 · Valor máximo por transacción: {sym}200</p>
|
||||||
<p>Un servicio que te permite pagar, enviar dinero y aceptar pagos sin tener que introducir tus datos financieros continuamente. Paga con PayPal de forma más rápida y segura. 250 millones de personas de más de 200 países y mercados usan PayPal. Y en 25 divisas.<br />Más información sobre PayPal <a href="https://www.paypal.com/es/webapps/mpp/paypal-popup" target="_blank" rel="noopener noreferrer">aquí</a>.</p>
|
|
||||||
<br />
|
|
||||||
<hr />
|
|
||||||
<br />
|
|
||||||
<span>¿Cómo adquirir PD a través de PayPal?</span>
|
|
||||||
<p>Al ser un sistema auto-gestionado, las adquisiciones mediante este sistema son automáticas y en cuestión de minutos tras realizar tu compra, recibirás los PD en tu cuenta en la página web.</p>
|
|
||||||
<br />
|
|
||||||
<hr />
|
|
||||||
<br />
|
|
||||||
<p>- Introduce en el campo de texto que aparece más abajo (el recuadro negro), la cantidad que deseas adquirir en USD.</p>
|
|
||||||
<p>- Al presionar el botón ADQUIRIR PD, serás redirigido a la plataforma de PayPal donde tendrás que ingresar con tu cuenta de PayPal y confirmar la compra en su plataforma.</p>
|
|
||||||
<p>- Una vez que PayPal valide tu pago, tendrás los PD en tu cuenta.</p>
|
|
||||||
<br />
|
|
||||||
<p>Por favor ten en cuenta que a la hora de realizar tu compra, la cantidad a adquirir sólo acepta números enteros y el mínimo posible es $1 USD.</p>
|
|
||||||
<p>Ejemplos de valor incorrecto: <span className="red-info2">$5,90 | $22,30 | $53,10</span></p>
|
|
||||||
<p>Ejemplos de valor correcto: <span className="green-info2">$6 | $22 | $53</span></p>
|
|
||||||
<br /><br /><br />
|
|
||||||
<p className="yellow-info centered">$1 USD = 100 PD</p>
|
|
||||||
<p className="centered second-brown">Valor máximo por transacción: $200</p>
|
|
||||||
<br />
|
<br />
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<div className="separate2">
|
<div className="separate2">
|
||||||
<p className="centered red-info2">¡Importante!</p>
|
<p className="centered red-info2">¡Importante!</p>
|
||||||
<p className="centered">No añadas ceros decimales, sólo valores enteros.</p>
|
<p className="centered">Introduce sólo valores enteros (sin decimales).</p>
|
||||||
<p className="centered">Ejemplo: Si deseas 200 PD, escribe sólo el número 2, sin ceros.</p>
|
<p className="centered">Ejemplo: para 200 PD escribe 2.</p>
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<br />
|
<br />
|
||||||
<p className="centered">Cantidad en USD a adquirir</p>
|
<p className="centered">Cantidad en {sym === '$' ? 'USD' : 'EUR'} a adquirir</p>
|
||||||
<form className="centered" name="_xclick" id="pp-purch-form" action="https://www.paypal.com/cgi-bin/webscr" method="post" onSubmit={onSubmit}>
|
<form className="centered" onSubmit={(e) => st.pay(e, sym)}>
|
||||||
<input type="hidden" name="cmd" value="_xclick" />
|
|
||||||
<input type="number" name="amount" id="pp-input-value" placeholder="Cantidad en USD" min="1" max="200" step="1" required /> USD
|
|
||||||
<input type="hidden" name="charset" value="utf-8" />
|
|
||||||
<input type="hidden" name="custom" value={`username=${username}&ip=${ip}`} />
|
|
||||||
<input type="hidden" name="currency_code" value="USD" />
|
|
||||||
<input type="hidden" name="item_name" value="Points" />
|
|
||||||
<input type="hidden" name="item_number" value="2023" />
|
|
||||||
<input type="hidden" name="business" value={paypalBusiness} />
|
|
||||||
<input type="hidden" name="return" value={`${origin}/${locale}/account`} />
|
|
||||||
<input type="hidden" name="cancel_return" value={`${origin}/${locale}/account`} />
|
|
||||||
<input type="hidden" name="notify_url" value={`${origin}/api/paypal/ipn`} />
|
|
||||||
<br /><br />
|
|
||||||
<input type="checkbox" id="accept-terms-refund-pp" className="terms-check" name="accept-terms-refund-pp" checked={accepted} onChange={(e) => setAccepted(e.target.checked)} required />
|
|
||||||
<label htmlFor="accept-terms-refund-pp"> Acepto los <Link href="/terms-and-conditions" target="_blank">Términos y Condiciones</Link> y la <Link href="/refund-policy" target="_blank">Política de Reembolso</Link></label>
|
|
||||||
<br /><br />
|
|
||||||
<input type="submit" id="pp-dnt-button" className="dnt-button" value="ADQUIRIR PD" disabled={!accepted} />
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------------------------------- dLocal ---------------------------------- */
|
|
||||||
function DLocalTab({ username, realm }: { username: string; realm: string }) {
|
|
||||||
const [accepted, setAccepted] = useState(false)
|
|
||||||
return (
|
|
||||||
<div className="box-content dnt-tab dnt-animate">
|
|
||||||
<div className="body-box-content">
|
|
||||||
<span>¿Qué es dLocal Go?</span><img className="pp-icon" src={`${LOGOS}/dlocalgo-logo.webp`} alt="dLocal Go" />
|
|
||||||
<p>dLocal Go es una plataforma de pagos que permite una conexión en directo con todas las tarjetas de crédito y débito, pagos en efectivo y transferencias bancarias en diferentes países de América Latina.<br />Más información sobre dLocal Go <a href="https://dlocalgo.com/" target="_blank" rel="noopener noreferrer">aquí</a>.</p>
|
|
||||||
<br />
|
|
||||||
<hr />
|
|
||||||
<br />
|
|
||||||
<span>¿Cómo adquirir PD a través de dlocal Go?</span>
|
|
||||||
<p>Al ser un sistema auto-gestionado, las adquisiciones mediante este sistema son automáticas y tras realizar tu compra, recibirás los PD en tu cuenta en la página web.</p>
|
|
||||||
<div className="trade-information">
|
|
||||||
<p>Tiempo aproximado de procesamiento de pagos según método:</p>
|
|
||||||
<p>- Tarjeta de crédito/debito: De minutos a 1 día hábil</p>
|
|
||||||
<p>- Efectivo: 1 a 2 días hábiles</p>
|
|
||||||
<p>- Transferencia bancaria: 1 día hábil</p>
|
|
||||||
</div>
|
|
||||||
<br /><br />
|
|
||||||
<p><i className="fas fa-exclamation-triangle"></i> <span>Importante:</span></p>
|
|
||||||
<p>Los tiempos indicados en la tabla son orientativos. En algunas ocasiones, la demora puede ser mayor.</p>
|
|
||||||
<p>Ante cualquier duda con la demora, por favor contáctanos en nuestra plataforma de Discord o a través de los medios de contacto disponibles en <Link href="/help">Ayuda</Link>.</p>
|
|
||||||
<br />
|
|
||||||
<hr />
|
|
||||||
<br />
|
|
||||||
<p>- Introduce en el campo de texto que aparece más abajo (el recuadro negro), la cantidad que deseas adquirir en USD.</p>
|
|
||||||
<p>- Al presionar el botón ADQUIRIR PD, serás redirigido a la plataforma de dLocal Go donde tendrás que realizar el pago y completar la compra en su plataforma.</p>
|
|
||||||
<p>- Una vez que dLocal Go valide tu pago, tendrás los PD en tu cuenta.</p>
|
|
||||||
<br />
|
|
||||||
<p>Por favor ten en cuenta que a la hora de realizar tu compra, la cantidad a adquirir sólo acepta números enteros y el mínimo posible es $2 USD.</p>
|
|
||||||
<p>Ejemplos de valor incorrecto: <span className="red-info2">$5,90 | $22,30 | $53,10</span></p>
|
|
||||||
<p>Ejemplos de valor correcto: <span className="green-info2">$6 | $22 | $53</span></p>
|
|
||||||
<br /><br /><br />
|
|
||||||
<p className="yellow-info centered">$1 USD = 100 PD</p>
|
|
||||||
<p className="centered second-brown">Valor mínimo por transacción: $2</p>
|
|
||||||
<br />
|
|
||||||
<p className="centered">Cantidad en USD a adquirir</p>
|
|
||||||
<form className="centered" id="dlocal-form" onSubmit={(e) => { e.preventDefault(); if (!accepted) { alert('Debes aceptar los Términos y Condiciones y la Política de Reembolso'); return } gatewayUnavailable(realm) }}>
|
|
||||||
<input type="number" placeholder="Cantidad en USD" min="2" step="1" max="200" id="cantidad" name="cantidad" required /> USD
|
|
||||||
<input type="hidden" id="username" name="username" value={username} />
|
|
||||||
<br /><br />
|
|
||||||
<input type="checkbox" id="accept-terms-refund-dl" className="terms-check" name="accept-terms-refund-dl" checked={accepted} onChange={(e) => setAccepted(e.target.checked)} required />
|
|
||||||
<label htmlFor="accept-terms-refund-dl"> Acepto los <Link href="/terms-and-conditions" target="_blank">Términos y Condiciones</Link> y la <Link href="/refund-policy" target="_blank">Política de Reembolso</Link></label>
|
|
||||||
<br /><br />
|
|
||||||
<button className="dnt-button" id="dl-dnt-button" type="submit" disabled={!accepted}>Adquirir PD</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------------------------------- Crypto ---------------------------------- */
|
|
||||||
function CryptoTab({ username, realm }: { username: string; realm: string }) {
|
|
||||||
const [accepted, setAccepted] = useState(false)
|
|
||||||
return (
|
|
||||||
<div className="box-content dnt-tab dnt-animate">
|
|
||||||
<div className="body-box-content">
|
|
||||||
<span>¿Qué son las criptomonedas?</span><img className="pp-icon" src={`${LOGOS}/nowpayments-logo.png`} alt="NOWPayments" title="NOWPayments" />
|
|
||||||
<p>Las criptomonedas son monedas digitales descentralizadas que permiten realizar pagos de forma rápida, segura y sin intermediarios. Aceptamos más de 150 criptomonedas a través de NOWPayments.</p>
|
|
||||||
<p>Más información sobre NOWPayments <a href="https://nowpayments.io/" target="_blank" rel="noopener noreferrer">aquí</a>.</p>
|
|
||||||
<br />
|
|
||||||
<hr />
|
|
||||||
<br />
|
|
||||||
<span>¿Cómo adquirir PD con criptomonedas?</span>
|
|
||||||
<p>Al ser un sistema auto-gestionado, las adquisiciones mediante este sistema son automáticas y tras realizar tu compra, recibirás los PD en tu cuenta en la página web.</p>
|
|
||||||
<div className="trade-information">
|
|
||||||
<p>Tiempo aproximado de procesamiento según criptomoneda:</p>
|
|
||||||
<p>- BNB, USDT (BSC), USDC (BSC): 1-5 minutos</p>
|
|
||||||
<p>- ETH (Base), USDC (Base): 1-5 minutos</p>
|
|
||||||
<p>- Bitcoin (BTC): 10-60 minutos</p>
|
|
||||||
</div>
|
|
||||||
<br /><br />
|
|
||||||
<p><i className="fas fa-exclamation-triangle"></i> <span>Importante:</span></p>
|
|
||||||
<p>Los tiempos indicados son orientativos y dependen de la congestión de la red blockchain.</p>
|
|
||||||
<p>Ante cualquier duda, por favor contáctanos en nuestra plataforma de Discord o a través de los medios de contacto disponibles en <Link href="/help">Ayuda</Link>.</p>
|
|
||||||
<br />
|
|
||||||
<hr />
|
|
||||||
<br />
|
|
||||||
<p>- Introduce en el campo de texto la cantidad que deseas adquirir en USD.</p>
|
|
||||||
<p>- Al presionar el botón ADQUIRIR PD, serás redirigido a la plataforma de NOWPayments donde podrás elegir la criptomoneda con la que deseas pagar.</p>
|
|
||||||
<p>- Una vez que NOWPayments confirme tu pago en la blockchain, tendrás los PD en tu cuenta.</p>
|
|
||||||
<br />
|
|
||||||
<p>Por favor ten en cuenta que la cantidad a adquirir sólo acepta números enteros y el mínimo posible es $2 USD.</p>
|
|
||||||
<p>Ejemplos de valor incorrecto: <span className="red-info2">$5,90 | $22,30 | $53,10</span></p>
|
|
||||||
<p>Ejemplos de valor correcto: <span className="green-info2">$6 | $22 | $53</span></p>
|
|
||||||
<br /><br /><br />
|
|
||||||
<p className="yellow-info centered">$1 USD = 100 PD</p>
|
|
||||||
<p className="centered second-brown">Valor mínimo por transacción: $2 | Valor máximo: $200</p>
|
|
||||||
<br />
|
|
||||||
<fieldset>
|
|
||||||
<div className="separate2">
|
|
||||||
<p className="centered red-info2">¡Importante!</p>
|
|
||||||
<p className="centered">Envía el monto <span>EXACTO</span> que indica NOWPayments.</p>
|
|
||||||
<p className="centered">Si envías menos, el pago quedará pendiente y deberás contactar a soporte.</p>
|
|
||||||
</div>
|
|
||||||
</fieldset>
|
|
||||||
<br />
|
|
||||||
<p className="centered">Cantidad en USD a adquirir</p>
|
|
||||||
<form className="centered" id="nowpayments-form" onSubmit={(e) => { e.preventDefault(); if (!accepted) { alert('Debes aceptar los Términos y Condiciones y la Política de Reembolso'); return } gatewayUnavailable(realm) }}>
|
|
||||||
<input type="number" placeholder="Cantidad en USD" min="2" max="200" step="1" id="cantidad-np" name="cantidad" required /> USD
|
|
||||||
<input type="hidden" id="username-np" name="username" value={username} />
|
|
||||||
<br /><br />
|
|
||||||
<input type="checkbox" id="accept-terms-refund-np" className="terms-check" name="accept-terms-refund-np" checked={accepted} onChange={(e) => setAccepted(e.target.checked)} required />
|
|
||||||
<label htmlFor="accept-terms-refund-np"> Acepto los <Link href="/terms-and-conditions" target="_blank">Términos y Condiciones</Link> y la <Link href="/refund-policy" target="_blank">Política de Reembolso</Link></label>
|
|
||||||
<br /><br />
|
|
||||||
<button className="dnt-button" id="np-dnt-button" type="submit" disabled={!accepted}>Adquirir PD</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------------------------------- Skrill ---------------------------------- */
|
|
||||||
function SkrillTab() {
|
|
||||||
return (
|
|
||||||
<div className="box-content dnt-tab dnt-animate">
|
|
||||||
<div className="body-box-content">
|
|
||||||
<span>¿Qué es Skrill?</span><img className="pp-icon" src={`${LOGOS}/skrill-logo.webp`} alt="Skrill" />
|
|
||||||
<p>Skrill es una plataforma de pagos en línea rápida y segura. Envía dinero, paga y recibe pagos sin ingresar tus datos financieros constantemente. Presente en 200 países y acepta 40 monedas.</p>
|
|
||||||
<p>Más información sobre Skrill <a href="https://www.skrill.com/es/" target="_blank" rel="noopener noreferrer">aquí</a>.</p>
|
|
||||||
<br />
|
|
||||||
<hr />
|
|
||||||
<br />
|
|
||||||
<span>¿Cuál es el valor de los PD?</span>
|
|
||||||
<p>El valor será calculado según país en base al cambio indicado en el momento del envío.</p>
|
|
||||||
<br />
|
|
||||||
<p className="yellow-info centered">$1 USD = 100 PD</p>
|
|
||||||
<br />
|
|
||||||
<hr />
|
|
||||||
<br />
|
|
||||||
<span>¿Cómo adquirir PD por Skrill?</span>
|
|
||||||
<p>Paso 1) Inicia sesión en Skrill. Accede a tu cuenta desde la aplicación o la página web oficial de Skrill.</p>
|
|
||||||
<br />
|
|
||||||
<p>Paso 2) Envía el dinero</p>
|
|
||||||
<p>1. Selecciona la opción "Enviar" o "Send Money".</p>
|
|
||||||
<p>2. Elige "Skrill a Skrill".</p>
|
|
||||||
<p>3. Introduce el correo del destinatario: <a href="mailto:skrill@ultimowow.com">skrill@ultimowow.com</a></p>
|
|
||||||
<p>4. Indica el importe que deseas enviar.</p>
|
|
||||||
<p>5. Revisa los datos y confirma la operación.</p>
|
|
||||||
<br />
|
|
||||||
<p>Paso 3) Guarda el comprobante</p>
|
|
||||||
<p>Una vez completado el pago, realiza una captura de pantalla donde se vea claramente:</p>
|
|
||||||
<p>- El correo del destinatario.</p>
|
|
||||||
<p>- El importe enviado.</p>
|
|
||||||
<p>- El estado de la transacción (Completada, Exitosa o similar).</p>
|
|
||||||
<br />
|
|
||||||
<p>Paso 4) Envía la información</p>
|
|
||||||
<p>Envía un correo a <a href="mailto:skrill@ultimowow.com">skrill@ultimowow.com</a> indicando:</p>
|
|
||||||
<p className="second-brown">- El nombre de cualquier personaje de la cuenta donde deseas recibir los PD.</p>
|
|
||||||
<p className="second-brown">- La captura de pantalla de la transacción. No envíes el comprobante en formato PDF.</p>
|
|
||||||
<br />
|
|
||||||
<p>Paso 5) Recepción de PD</p>
|
|
||||||
<p>Una vez verificado el pago, los PD serán acreditados en tu cuenta lo antes posible. Cuando la entrega haya sido completada, serás informado.</p>
|
|
||||||
<br />
|
|
||||||
<hr />
|
|
||||||
<br />
|
|
||||||
<span>Contacto</span>
|
|
||||||
<p>Correo: <a href="mailto:skrill@ultimowow.com">skrill@ultimowow.com</a></p>
|
|
||||||
<br />
|
|
||||||
<p><i className="fas fa-exclamation-triangle"></i> Este método no es automático sino manual siendo realizado por la persona encargada.</p>
|
|
||||||
<p>Recomendamos no realizar ninguna acción sin comprobar primero si la persona encargada está disponible para entregar los PD.</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------- Argentina --------------------------------- */
|
|
||||||
function ArgentinaTab() {
|
|
||||||
const [usd, setUsd] = useState(1)
|
|
||||||
const [rate, setRate] = useState<number | null>(null)
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
let alive = true
|
|
||||||
fetch('https://dolarapi.com/v1/dolares/oficial')
|
|
||||||
.then((r) => (r.ok ? r.json() : Promise.reject(new Error('HTTP ' + r.status))))
|
|
||||||
.then((j) => { if (alive) setRate(typeof j?.venta === 'number' ? j.venta : null) })
|
|
||||||
.catch(() => {})
|
|
||||||
return () => { alive = false }
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
const fmtARS = (v: number) => v.toLocaleString('es-AR', { minimumFractionDigits: 2, maximumFractionDigits: 2 })
|
|
||||||
const validUsd = Number.isInteger(usd) && usd >= 1
|
|
||||||
const arsText = rate && validUsd ? fmtARS(rate * usd) : '—'
|
|
||||||
const pdText = validUsd ? String(usd * 100) : '—'
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="box-content dnt-tab dnt-animate">
|
|
||||||
<div className="body-box-content">
|
|
||||||
<span>¿Qué son los métodos alternativos para Argentina?</span>
|
|
||||||
<p>Son métodos disponibles para Argentina para aquellos que no tienen acceso a PayPal.</p>
|
|
||||||
<p>Este método trabaja con Pesos Argentinos.</p>
|
|
||||||
<br />
|
|
||||||
<hr />
|
|
||||||
<br />
|
|
||||||
<span>Métodos disponibles</span>
|
|
||||||
<p>- Transferencia bancaria en pesos argentinos (ARS)</p>
|
|
||||||
<br />
|
|
||||||
<hr />
|
|
||||||
<br />
|
|
||||||
<span>¿Cuál es el valor de los PD?</span>
|
|
||||||
<p>La cantidad de Pesos según país será en base al cambio indicado en el momento de la transferencia.</p>
|
|
||||||
<p>El siguiente recuadro permite hacer una conversión de USD a Pesos argentinos mostrando el valor final y no habrá impuestos ni recargos.</p>
|
|
||||||
<p>Se puede cambiar los valores para ver el precio de la cantidad deseada de PD.</p>
|
|
||||||
<br />
|
|
||||||
<p className="centered">
|
|
||||||
<span>Calculadora de conversión</span>
|
|
||||||
<br /><br />
|
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
|
placeholder={`Cantidad en ${sym === '$' ? 'USD' : 'EUR'}`}
|
||||||
min="1"
|
min="1"
|
||||||
|
max="200"
|
||||||
step="1"
|
step="1"
|
||||||
value={usd}
|
value={st.amount}
|
||||||
onChange={(e) => setUsd(parseInt(e.target.value, 10))}
|
onChange={(e) => st.setAmount(e.target.value)}
|
||||||
style={{ width: '60px', textAlign: 'center' }}
|
required
|
||||||
/>{' '}
|
/>{' '}
|
||||||
<span className="yellow-info">USD =</span>{' '}
|
{sym === '$' ? 'USD' : 'EUR'}
|
||||||
<span id="ars-output">{arsText}</span> <span className="yellow-info">ARS =</span>{' '}
|
{points > 0 && <p className="centered green-info2">Recibirás {points} PD</p>}
|
||||||
<span id="pd-output">{pdText}</span> <span className="yellow-info">PD</span>
|
|
||||||
</p>
|
|
||||||
<br />
|
|
||||||
<hr />
|
|
||||||
<br />
|
|
||||||
<span>¿Cómo adquirir PD por Transferencia?</span>
|
|
||||||
<p>Paso 1) Realiza la transferencia con los siguientes datos:</p>
|
|
||||||
<p> El valor en ARS puede obtenerse usando la calculadora disponible.</p>
|
|
||||||
<p> Ejemplo: Si deseas 200 PD, coloca 2 en la casilla USD y te dirá el monto en ARS</p>
|
|
||||||
<p> <span className="red-info2">Envía el monto exacto que indica la calculadora.</span></p>
|
|
||||||
<br />
|
|
||||||
<p>Paso 2) Envia el correo detallando:</p>
|
|
||||||
<p className="second-brown"> - Nombre de cualquier PERSONAJE de la cuenta donde deseas recibir los PD.</p>
|
|
||||||
<p className="second-brown"> - Cantidad de PD deseada.</p>
|
|
||||||
<p>Paso 3) Adjunta al correo una captura de pantalla (imagen, no pdf) del comprobante.</p>
|
|
||||||
<p>Paso 4) Envia el correo a la dirección indicada en <span>Contacto</span>.</p>
|
|
||||||
<p>Paso 5) Espera la respuesta al correo enviado.</p>
|
|
||||||
<p>Paso 6) Dentro del horario de atención, serás informado que has recibido los PD.</p>
|
|
||||||
<br />
|
|
||||||
<hr />
|
|
||||||
<br />
|
|
||||||
<span>Contacto</span>
|
|
||||||
<p>Correo: <a href="mailto:arg@ultimowow.com">arg@ultimowow.com</a></p>
|
|
||||||
<p>Lunes a Viernes por las tardes (Horario Argentina).</p>
|
|
||||||
<br /><br />
|
<br /><br />
|
||||||
<p><i className="fas fa-exclamation-triangle"></i> Este método no es automático sino manual siendo realizado por la persona encargada.</p>
|
<input
|
||||||
<p>Recomendamos no realizar ninguna acción sin comprobar primero si la persona encargada está disponible para entregar los PD.</p>
|
type="checkbox"
|
||||||
</div>
|
id={`accept-${provider}`}
|
||||||
</div>
|
className="terms-check"
|
||||||
)
|
checked={st.accepted}
|
||||||
}
|
onChange={(e) => st.setAccepted(e.target.checked)}
|
||||||
|
required
|
||||||
/* ----------------------------------- Chile ---------------------------------- */
|
/>
|
||||||
function ChileTab() {
|
<label htmlFor={`accept-${provider}`}> Acepto los <Link href="/terms-and-conditions" target="_blank">Términos y Condiciones</Link> y la <Link href="/refund-policy" target="_blank">Política de Reembolso</Link></label>
|
||||||
const rows: [string, string][] = [
|
|
||||||
['1.200 Pesos Chilenos', '100 PD'],
|
|
||||||
['3.600 Pesos Chilenos', '300 PD'],
|
|
||||||
['6.000 Pesos Chilenos', '500 PD'],
|
|
||||||
['9.600 Pesos Chilenos', '800 PD'],
|
|
||||||
['12.000 Pesos Chilenos', '1000 PD'],
|
|
||||||
['30.000 Pesos Chilenos', '2500 PD'],
|
|
||||||
['60.000 Pesos Chilenos', '5000 PD'],
|
|
||||||
]
|
|
||||||
return (
|
|
||||||
<div className="box-content dnt-tab dnt-animate">
|
|
||||||
<div className="body-box-content">
|
|
||||||
<span>¿Qué son los métodos alternativos para Chile?</span>
|
|
||||||
<p>Son métodos disponibles para Chile para aquellos que no tienen acceso a PayPal.</p>
|
|
||||||
<p>Este método trabaja con Pesos Chilenos.</p>
|
|
||||||
<br />
|
|
||||||
<hr />
|
|
||||||
<br />
|
|
||||||
<span>Métodos disponibles</span>
|
|
||||||
<p>- Transferencia bancaria en pesos chilenos (CLP)</p>
|
|
||||||
<p>- Mach en pesos chilenos (CLP)</p>
|
|
||||||
<br />
|
|
||||||
<hr />
|
|
||||||
<br />
|
|
||||||
<span>¿Cuál es el valor de los PD?</span>
|
|
||||||
<table className="points-center-table">
|
|
||||||
<tbody>
|
|
||||||
<tr><th>Precio</th><th>PD</th></tr>
|
|
||||||
{rows.map(([p, pd]) => (<tr key={p}><td>{p}</td><td>{pd}</td></tr>))}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<br />
|
|
||||||
<hr />
|
|
||||||
<br />
|
|
||||||
<span>¿Cómo adquirir PD por Transferencia?</span>
|
|
||||||
<p>Paso 1) Contacta con la persona encargada mediante Discord. El medio de contacto aparece al final de esta sección.</p>
|
|
||||||
<p>Paso 2) Debes informarle:</p>
|
|
||||||
<p>- Nombre de cualquier personaje de la cuenta donde deseas recibir los PD.</p>
|
|
||||||
<p>- Cantidad de PD deseada.</p>
|
|
||||||
<p>Paso 3) La persona encargada te dará los datos necesarios para la transferencia.</p>
|
|
||||||
<p>Paso 4) Confirma con la persona encargada el costo final antes de realizar la transferencia.</p>
|
|
||||||
<p>Si usas el método Mach, se te entregará un código QR para realizar la transferencia.</p>
|
|
||||||
<p>Paso 5) Una vez realizada la transferencia, deberás enviarla como imagen (no como archivo pdf) a la persona encargada.</p>
|
|
||||||
<p>Paso 6) Serás informado que has recibido los PD.</p>
|
|
||||||
<br />
|
|
||||||
<hr />
|
|
||||||
<br />
|
|
||||||
<span>Contacto</span>
|
|
||||||
<p>- Discord al usuario <span className="blue-gm">Bhaal</span> (ID <span className="blue-gm">dakiron</span>)</p>
|
|
||||||
<br />
|
|
||||||
<button className="discord-button" onClick={() => window.open('https://discordapp.com/users/300063037958914048', '_blank')}><img className="discord-icon" src={`${LOGOS}/discord-logo.webp`} alt="Discord" /> Discord</button>
|
|
||||||
<br /><br />
|
<br /><br />
|
||||||
<p>* Asegúrate que la persona que contactes tiene rango <span className="blue-gm">Maestro de Juego</span> en nuestro discord.</p>
|
{st.err && <p className="red-form-response">{st.err}</p>}
|
||||||
|
<button type="submit" className="dnt-button" disabled={!st.accepted || st.busy}>
|
||||||
|
{st.busy ? 'Redirigiendo…' : buttonLabel}
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------------------------------- Stripe ---------------------------------- */
|
||||||
|
function StripeTab({ realm, sym }: { realm: string; sym: string }) {
|
||||||
|
return (
|
||||||
|
<div className="box-content dnt-tab dnt-animate">
|
||||||
|
<div className="body-box-content">
|
||||||
|
<span>¿Qué es Stripe?</span><img className="pp-icon" src={`${LOGOS}/stripe-logo.svg`} alt="Stripe" />
|
||||||
|
<p>Stripe es una plataforma de pagos en línea segura que procesa tarjetas de crédito y débito de todo el mundo. Tus datos de pago se gestionan directamente en Stripe; {realm} nunca los almacena.<br />Más información sobre Stripe <a href="https://stripe.com/es" target="_blank" rel="noopener noreferrer">aquí</a>.</p>
|
||||||
<br />
|
<br />
|
||||||
<p><i className="fas fa-exclamation-triangle"></i> Este método no es automático sino manual siendo realizado por la persona encargada.</p>
|
<hr />
|
||||||
<p>Recomendamos no realizar ninguna acción sin comprobar primero si la persona encargada está disponible para entregar los PD.</p>
|
<br />
|
||||||
|
<span>¿Cómo adquirir PD a través de Stripe?</span>
|
||||||
|
<p>Al ser un sistema auto-gestionado, las adquisiciones son automáticas y en cuestión de minutos tras completar el pago recibirás los PD en tu cuenta.</p>
|
||||||
|
<br />
|
||||||
|
<hr />
|
||||||
|
<br />
|
||||||
|
<p>- Introduce en el campo de más abajo la cantidad que deseas adquirir.</p>
|
||||||
|
<p>- Al presionar <span>ADQUIRIR PD</span>, serás redirigido a la pasarela segura de Stripe para completar el pago con tu tarjeta.</p>
|
||||||
|
<p>- Una vez que Stripe valide tu pago, tendrás los PD en tu cuenta de forma automática.</p>
|
||||||
|
<br />
|
||||||
|
<p>Recuerda que la cantidad sólo acepta números enteros y el mínimo posible es {sym}1.</p>
|
||||||
|
<p>Ejemplos de valor incorrecto: <span className="red-info2">{sym}5,90 | {sym}22,30 | {sym}53,10</span></p>
|
||||||
|
<p>Ejemplos de valor correcto: <span className="green-info2">{sym}6 | {sym}22 | {sym}53</span></p>
|
||||||
|
<br /><br /><br />
|
||||||
|
<AmountForm provider="stripe" sym={sym} buttonLabel="ADQUIRIR PD" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --------------------------------- Colombia --------------------------------- */
|
/* ---------------------------------- SumUp ----------------------------------- */
|
||||||
function ColombiaTab() {
|
function SumUpTab({ realm, sym }: { realm: string; sym: string }) {
|
||||||
const rows: [string, string][] = [
|
|
||||||
['17.200 Pesos Colombianos', '300 PD'],
|
|
||||||
['23.000 Pesos Colombianos', '400 PD'],
|
|
||||||
['28.700 Pesos Colombianos', '500 PD'],
|
|
||||||
['34.400 Pesos Colombianos', '600 PD'],
|
|
||||||
['57.350 Pesos Colombianos', '1000 PD'],
|
|
||||||
['143.350 Pesos Colombianos', '2500 PD'],
|
|
||||||
]
|
|
||||||
return (
|
return (
|
||||||
<div className="box-content dnt-tab dnt-animate">
|
<div className="box-content dnt-tab dnt-animate">
|
||||||
<div className="body-box-content">
|
<div className="body-box-content">
|
||||||
<span>¿Qué son los métodos alternativos para Colombia?</span>
|
<span>¿Qué es SumUp?</span><img className="pp-icon" src={`${LOGOS}/sumup-logo.svg`} alt="SumUp" />
|
||||||
<p>Son métodos disponibles para Colombia para aquellos que no tienen acceso a PayPal que se lleva a cabo a través de un representante oficial, a través de diversos métodos de pago para un país en específico.</p>
|
<p>SumUp es una plataforma de pagos europea que permite pagar de forma rápida y segura con tarjeta de crédito o débito. Tus datos de pago se gestionan directamente en SumUp; {realm} nunca los almacena.<br />Más información sobre SumUp <a href="https://sumup.com/es-es/" target="_blank" rel="noopener noreferrer">aquí</a>.</p>
|
||||||
<p>Este método trabaja con Pesos Colombianos.</p>
|
|
||||||
<br />
|
<br />
|
||||||
<hr />
|
<hr />
|
||||||
<br />
|
<br />
|
||||||
<span>¿Cuál es el valor de los PD?</span>
|
<span>¿Cómo adquirir PD a través de SumUp?</span>
|
||||||
<table className="points-center-table">
|
<p>Al ser un sistema auto-gestionado, las adquisiciones son automáticas y tras completar el pago recibirás los PD en tu cuenta.</p>
|
||||||
<tbody>
|
|
||||||
<tr><th>Precio</th><th>PD</th></tr>
|
|
||||||
{rows.map(([p, pd]) => (<tr key={p}><td>{p}</td><td>{pd}</td></tr>))}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<br />
|
<br />
|
||||||
<hr />
|
<hr />
|
||||||
<br />
|
<br />
|
||||||
<span>¿Cómo adquiir PD por Representante?</span>
|
<p>- Introduce en el campo de más abajo la cantidad que deseas adquirir.</p>
|
||||||
<p>Para realizar una adquisición y recibir tus PD, tienes varios medios disponibles:</p>
|
<p>- Al presionar <span>ADQUIRIR PD</span>, serás redirigido a la pasarela segura de SumUp para completar el pago con tu tarjeta.</p>
|
||||||
<p>- Recarga NEQUI en Efectivo</p>
|
<p>- Una vez que SumUp valide tu pago, tendrás los PD en tu cuenta de forma automática.</p>
|
||||||
<p>- Recarga NEQUI mediante PSE</p>
|
|
||||||
<p>- Transferencia mediante NEQUI</p>
|
|
||||||
<p>- Consignación o transferencia bancaria</p>
|
|
||||||
<br />
|
|
||||||
<fieldset>
|
|
||||||
<legend>Por Recarga NEQUI en Efectivo</legend><img className="bolivia-banks-icon" src={`${LOGOS}/nequi-logo.webp`} alt="Nequi" />
|
|
||||||
<div className="separate">
|
|
||||||
<p>1 - Ubica el punto más cercano a donde estés <a href="https://www.nequi.com.co/mapas/" target="_blank" rel="noopener noreferrer">aquí</a>.</p>
|
|
||||||
<p>2 - Al entrar te solicitará conocer tu ubicación y debes hacer clic al botón Permitir.</p>
|
|
||||||
<p>3 - Cuando la web te pregunte ¿Qué quieres hacer? Selecciona la opción Recargar.</p>
|
|
||||||
<p>4 - Mira las ubicaciones que te aparecen señalados en el mapa en color amarillo (Para ver la dirección exacta toca el punto que deseas ver en el mapa).</p>
|
|
||||||
<p>5 - Ve al establecimiento elegido e indica que quieres Recargar a NEQUI X Pesos donde X es la cantidad de pesos correspondiente a los PD deseados (Verifica la tabla y coloca el valor correctamente).</p>
|
|
||||||
<p>6 - Necesitarás dar la siguiente información:</p>
|
|
||||||
<br />
|
|
||||||
<ul>
|
|
||||||
<li>Número de convenio: <span>63703</span></li>
|
|
||||||
<li>Número de celular: <span>3133639892</span></li>
|
|
||||||
</ul>
|
|
||||||
<br />
|
|
||||||
<p>7 - Solicita recibo de la transacción.</p>
|
|
||||||
<p>8 - Escanea o toma una foto de dicho recibo y envíalo al representante junto con la cantidad de PD y el nombre del personaje donde deseas recibir los PD.</p>
|
|
||||||
<p>9 - Espera a que el encargado te envíe respuesta por el medio que le enviaste el mensaje donde te indicará que ya fueron cargados los PD.</p>
|
|
||||||
</div>
|
|
||||||
</fieldset>
|
|
||||||
<br />
|
|
||||||
<fieldset>
|
|
||||||
<legend>Por Recarga NEQUI mediante PSE</legend><img className="bolivia-banks-icon" src={`${LOGOS}/nequi-logo.webp`} alt="Nequi" />
|
|
||||||
<div className="separate">
|
|
||||||
<p>El recargar NEQUI por PSE es un método que permite enviar dinero de una cuenta bancaria (de casi cualquier banco) a NEQUI.</p>
|
|
||||||
<p>Nota: Este método puede implicar que tengas activo algunos servicios en el banco donde tienes tu cuenta para poder realizarlo.</p>
|
|
||||||
<br />
|
|
||||||
<p>1 - Ingresa a la web de <a href="https://www.nequi.com.co/" target="_blank" rel="noopener noreferrer">Nequi</a>.</p>
|
|
||||||
<p>2 - Haz clic en la opción Recarga.</p>
|
|
||||||
<p>3 - Aparecerá un formulario que solicitará la siguiente información:</p>
|
|
||||||
<br />
|
|
||||||
<ul>
|
|
||||||
<li>Número de celular: <span>3133639892</span></li>
|
|
||||||
<li>Confirma el número de celular: <span>3133639892</span></li>
|
|
||||||
<li>Tipo de persona: <span>Natural</span></li>
|
|
||||||
<li>Cantidad: <span>Cantidad correspondiente a los PD deseados (Verifica la tabla y coloca correctamente el valor)</span></li>
|
|
||||||
</ul>
|
|
||||||
<br />
|
|
||||||
<p>4 - Haz clic en No soy robot y de ahí a Continuar.</p>
|
|
||||||
<p>5 - Al momento de dar a Continuar serás redireccionado a la web oficial de PSE, donde deberás ingresar TU cuenta de PSE (si nunca antes haz hecho pagos por PSE deberás registrarte).</p>
|
|
||||||
<p>6 - Cuando ingreses la cuenta de PSE serás redireccionado a la web de tu banco que accede a este servicio donde deberás completar el proceso que tenga el banco de TU cuenta bancaria (puede que algunos bancos cobren adicional por el acceso o uso de este servicio).</p>
|
|
||||||
<p>7 - Una vez completado y finalizado el pago por PSE, serás re direccionado a NEQUI donde te mostrará un enlace con el mensaje Ver comprobante al cual debes hacerle clic.</p>
|
|
||||||
<p>8 - Descarga el comprobante de pago para generar un archivo en formato pdf y envíalo al representante junto con la cantidad de PD y el nombre del personaje donde deseas recibir los PD.</p>
|
|
||||||
<p>9 - Espera a que el encargado te envíe respuesta por el medio que le enviaste el mensaje donde te indicará que ya fueron cargados los PD.</p>
|
|
||||||
</div>
|
|
||||||
</fieldset>
|
|
||||||
<br />
|
|
||||||
<fieldset>
|
|
||||||
<legend>Transferencia mediante NEQUI</legend><img className="bolivia-banks-icon" src={`${LOGOS}/nequi-logo.webp`} alt="Nequi" />
|
|
||||||
<div className="separate">
|
|
||||||
<p>1 - Ingresa a tu cuenta NEQUI Desde la App móvil de NEQUI Colombia.</p>
|
|
||||||
<p>2 - Al ingresar, selecciona el botón con el símbolo $ de color rosa.</p>
|
|
||||||
<p>3 - Selecciona la opción Envía plata.</p>
|
|
||||||
<p>4 - Indica desde dónde enviarás el dinero.</p>
|
|
||||||
<p>5 - En los campos que están en Envía a NEQUI coloca la siguiente información:</p>
|
|
||||||
<br />
|
|
||||||
<ul>
|
|
||||||
<li>Número de celular: <span>3133639892</span></li>
|
|
||||||
<li>Cantidad: <span>Cantidad correspondiente a los PD deseados (Verifica la tabla y coloca correctamente el valor)</span></li>
|
|
||||||
<li>Mensaje: <span>PD UltimoWoW</span></li>
|
|
||||||
</ul>
|
|
||||||
<br />
|
|
||||||
<p>6 - Presiona Continuar.</p>
|
|
||||||
<p>7 - Una vez que se termine de procesar el pago te mostrará la lista de tus movimientos, en el último sale el nombre de la persona relacionada a la cuenta transferida que es ROBERT PENA.</p>
|
|
||||||
<p>8 - Selecciona dicho movimiento para que te muestre los detalles del mismo.</p>
|
|
||||||
<p>9 - Toma una captura de pantalla de los detalles y envíalo al representante junto con la cantidad de PD y el nombre del personaje donde deseas recibir los PD.</p>
|
|
||||||
<p>10 - Espera a que el encargado te envíe respuesta por el medio que le enviaste el mensaje donde te indicará que ya fueron cargados los PD.</p>
|
|
||||||
</div>
|
|
||||||
</fieldset>
|
|
||||||
<br />
|
|
||||||
<fieldset>
|
|
||||||
<legend>Consignación o Transferencia a cuenta bancaria</legend><img className="bolivia-banks-icon" src={`${LOGOS}/bancolombia-logo.webp`} alt="Bancolombia" />
|
|
||||||
<div className="separate">
|
|
||||||
<p>Mediante este método deberas realizar una consignación en un banco o corresponsal bancario por el valor de los PD que quieres adquirir (Verifica la tabla y coloca correctamente el valor).</p>
|
|
||||||
<br />
|
|
||||||
<p>1 - Cuando realices la consignación te solicitarán los siguientes datos:</p>
|
|
||||||
<br />
|
|
||||||
<ul>
|
|
||||||
<li>Número de cuenta: <span>203-133849-78</span></li>
|
|
||||||
<li>A nombre de: <span>Robert Camilo Peña</span></li>
|
|
||||||
<li>Tipo de cuenta: <span>De ahorros</span></li>
|
|
||||||
<li>Banco: <span>Bancolombia</span></li>
|
|
||||||
</ul>
|
|
||||||
<br />
|
|
||||||
<p>2 - Solicita copia del recibo de transacción.</p>
|
|
||||||
<p>3 - Escanea o toma una foto del recibo y envíalo al representante junto con la cantidad de PD y el nombre del personaje donde deseas recibir los PD.</p>
|
|
||||||
<p>4 - Espera a que el encargado te envíe respuesta por el medio que le enviaste el mensaje donde te indicará que ya fueron cargados los PD.</p>
|
|
||||||
</div>
|
|
||||||
</fieldset>
|
|
||||||
<br />
|
|
||||||
<hr />
|
|
||||||
<br />
|
|
||||||
<span>¿Cómo contactar con el Representante?</span>
|
|
||||||
<p>Nombre: Robert Peña</p>
|
|
||||||
<p>Usuario de Discord: <span className="blue-gm">Raziel#1403</span></p>
|
|
||||||
<p>Lunes a Jueves: 15:00 a 22:00 (Horario Colombia)</p>
|
|
||||||
<p>Sábados y Domingos: 18:00 a 23:00 (Horario Colombia)</p>
|
|
||||||
<p className="red-info2">Importante: Los días Viernes no hay atención</p>
|
|
||||||
<br />
|
|
||||||
<button className="discord-button" onClick={() => window.open('https://discordapp.com/users/1053037915065831425', '_blank')}><img className="discord-icon" src={`${LOGOS}/discord-logo.webp`} alt="Discord" /> Discord</button>
|
|
||||||
<button className="wp-button" onClick={() => window.open('https://wa.me/573195069649', '_blank')}><img className="wp-icon" src={`${LOGOS}/whatsapp-logo.webp`} alt="WhatsApp" /> Whatsapp</button>
|
|
||||||
<br />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ----------------------------------- Perú ----------------------------------- */
|
|
||||||
function PeruTab() {
|
|
||||||
const rows: [string, string][] = [
|
|
||||||
['5.5 Soles Peruanos', '100 PD'],
|
|
||||||
['25,5 Soles Peruanos', '500 PD'],
|
|
||||||
['40 Soles Peruanos', '800 PD'],
|
|
||||||
['48 Soles Peruanos', '1000 PD'],
|
|
||||||
['118 Soles Peruanos', '2500 PD'],
|
|
||||||
]
|
|
||||||
return (
|
|
||||||
<div className="box-content dnt-tab dnt-animate">
|
|
||||||
<div className="body-box-content">
|
|
||||||
<span>¿Qué son los métodos alternativos para Perú?</span>
|
|
||||||
<p>Son métodos disponibles para aquellos que no tienen acceso a PayPal que se lleva a cabo a través de un representante oficial, a través de diversos métodos de pago para un país en específico.</p>
|
|
||||||
<p>Este método trabaja con Soles Peruanos.</p>
|
|
||||||
<br />
|
|
||||||
<hr />
|
|
||||||
<br />
|
|
||||||
<span>¿Cuál es el valor de los PD?</span>
|
|
||||||
<table className="points-center-table">
|
|
||||||
<tbody>
|
|
||||||
<tr><th>Precio</th><th>PD</th></tr>
|
|
||||||
{rows.map(([p, pd]) => (<tr key={p}><td>{p}</td><td>{pd}</td></tr>))}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<br />
|
|
||||||
<hr />
|
|
||||||
<br />
|
|
||||||
<span>¿Cómo adquirir PD por Representante?</span>
|
|
||||||
<p>Para realizar una adquisición y recibir tus PD, tienes varios medios disponibles:</p>
|
|
||||||
<p>- Recarga por medio de YAPE</p>
|
|
||||||
<p>- Recarga por medio de PLIN</p>
|
|
||||||
<p>- Pago presencial mediante OFICINA (LIMA)</p>
|
|
||||||
<p>- Transferencia bancaria y interbancaria</p>
|
|
||||||
<br />
|
|
||||||
<fieldset>
|
|
||||||
<legend>Recarga por medio de YAPE</legend>
|
|
||||||
<div className="separate">
|
|
||||||
<img className="peru-logo" src={`${LOGOS}/yape-peru.png`} alt="Yape" />
|
|
||||||
</div>
|
|
||||||
</fieldset>
|
|
||||||
<br />
|
|
||||||
<fieldset>
|
|
||||||
<legend>Pago por medio de PLIN</legend>
|
|
||||||
<div className="separate">
|
|
||||||
<p>Pago mediante número.</p>
|
|
||||||
<br />
|
|
||||||
<img className="peru-logo" src={`${LOGOS}/plin-peru.webp`} alt="Plin" />
|
|
||||||
</div>
|
|
||||||
</fieldset>
|
|
||||||
<br />
|
|
||||||
<fieldset>
|
|
||||||
<legend>Pago presencial mediante OFICINA</legend>
|
|
||||||
<div className="separate">
|
|
||||||
<p>Contactarse con el número mediante 941841649 previamente cita.</p>
|
|
||||||
<br />
|
|
||||||
<img className="peru-logo" src={`${LOGOS}/oficina-peru.png`} alt="Oficina" />
|
|
||||||
</div>
|
|
||||||
</fieldset>
|
|
||||||
<br />
|
|
||||||
<fieldset>
|
|
||||||
<legend>Transferencia bancaria y interbancaria</legend>
|
|
||||||
<div className="separate">
|
|
||||||
<p>Mediante este método deberas realizar una consignación en un banco o corresponsal bancario por el valor de los PD que quieres adquirir (Verifica la tabla y coloca correctamente el valor).</p>
|
|
||||||
<br />
|
|
||||||
<p>- BANCO BCP</p>
|
|
||||||
<p>- BANCO BBVA</p>
|
|
||||||
<p>- BANCO SCOTIABANK</p>
|
|
||||||
<p>- BANCO DE LA NACIÓN</p>
|
|
||||||
<br />
|
|
||||||
<p>Comunicarse previamente con el representante.</p>
|
|
||||||
</div>
|
|
||||||
</fieldset>
|
|
||||||
<br />
|
|
||||||
<p>Una vez realizado el proceso por cualquiera de los medios indicados, contactar con el Representante.</p>
|
|
||||||
<p>Si es en los horarios de atención, los PD serán cargados en minutos en la cuenta.</p>
|
|
||||||
<br />
|
|
||||||
<hr />
|
|
||||||
<br />
|
|
||||||
<span>¿Cómo contactar con el Representante?</span>
|
|
||||||
<p>Nombre: Anibal Gavidia Correa</p>
|
|
||||||
<p>Lunes a Jueves: 9:00 a 22:00 (Horario Perú)</p>
|
|
||||||
<p>Sábados y Domingos: 9:00 a 23:00 (Horario Perú)</p>
|
|
||||||
<br />
|
|
||||||
<button className="discord-button" onClick={() => window.open('https://discordapp.com/users/642217524737605642', '_blank')}><img className="discord-icon" src={`${LOGOS}/discord-logo.webp`} alt="Discord" /> Discord</button>
|
|
||||||
<button className="wp-button" onClick={() => window.open('https://wa.me/51941841649', '_blank')}><img className="wp-icon" src={`${LOGOS}/whatsapp-logo.webp`} alt="WhatsApp" /> Contacto</button>
|
|
||||||
<br />
|
<br />
|
||||||
|
<p>Recuerda que la cantidad sólo acepta números enteros y el mínimo posible es {sym}1.</p>
|
||||||
|
<p>Ejemplos de valor incorrecto: <span className="red-info2">{sym}5,90 | {sym}22,30 | {sym}53,10</span></p>
|
||||||
|
<p>Ejemplos de valor correcto: <span className="green-info2">{sym}6 | {sym}22 | {sym}53</span></p>
|
||||||
|
<br /><br /><br />
|
||||||
|
<AmountForm provider="sumup" sym={sym} buttonLabel="ADQUIRIR PD" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
import type { RowDataPacket } from 'mysql2'
|
||||||
|
import { db, DB } from './db'
|
||||||
|
|
||||||
|
/** Ratio de conversión: cada 1 unidad de moneda = 100 PD. */
|
||||||
|
export const PD_PER_UNIT = 100
|
||||||
|
/** Límites de compra por transacción (en unidades de moneda). */
|
||||||
|
export const DP_MIN_AMOUNT = 1
|
||||||
|
export const DP_MAX_AMOUNT = 200
|
||||||
|
|
||||||
|
/** Acredita PD (donate points) a una cuenta de juego en `home_api_points` (upsert). */
|
||||||
|
export async function creditDPoints(accountId: number, points: number): Promise<boolean> {
|
||||||
|
if (!accountId || !(points > 0)) return false
|
||||||
|
try {
|
||||||
|
const [rows] = await db(DB.default).query<RowDataPacket[]>(
|
||||||
|
'SELECT id FROM home_api_points WHERE accountID = ?',
|
||||||
|
[accountId],
|
||||||
|
)
|
||||||
|
if (rows[0]) {
|
||||||
|
await db(DB.default).query('UPDATE home_api_points SET dp = dp + ? WHERE accountID = ?', [points, accountId])
|
||||||
|
} else {
|
||||||
|
await db(DB.default).query('INSERT INTO home_api_points (accountID, vp, dp) VALUES (?, 0, ?)', [accountId, points])
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
} catch {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import { executeSoapCommand } from './soap'
|
import { executeSoapCommand } from './soap'
|
||||||
import { db, DB } from './db'
|
import { db, DB } from './db'
|
||||||
|
import { creditDPoints } from './dpoints'
|
||||||
import {
|
import {
|
||||||
getRenamePrice,
|
getRenamePrice,
|
||||||
getCustomizePrice,
|
getCustomizePrice,
|
||||||
@@ -78,6 +79,14 @@ export const PAID_SERVICES: Record<string, PaidServiceConfig> = {
|
|||||||
fulfill: (c, m) => soapFulfill(`.char changeaccount ${m.destination_account} ${c}`),
|
fulfill: (c, m) => soapFulfill(`.char changeaccount ${m.destination_account} ${c}`),
|
||||||
extraFields: ['destination_account'],
|
extraFields: ['destination_account'],
|
||||||
},
|
},
|
||||||
|
// Compra de PD (Adquirir PD): acredita puntos a la cuenta que hizo el pago.
|
||||||
|
// El importe lo elige el usuario, por eso `price` lee metadata.amount.
|
||||||
|
dpoints: {
|
||||||
|
price: (m) => Promise.resolve(Number(m.amount)),
|
||||||
|
productName: (_c, m) => `${Number(m.points)} PD`,
|
||||||
|
fulfill: (_c, m) => creditDPoints(Number(m.accountId), Number(m.points)),
|
||||||
|
extraFields: [],
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getPaidService(slug: string): PaidServiceConfig | null {
|
export function getPaidService(slug: string): PaidServiceConfig | null {
|
||||||
|
|||||||
@@ -0,0 +1,108 @@
|
|||||||
|
import type { RowDataPacket, ResultSetHeader } from 'mysql2'
|
||||||
|
import { db, DB } from './db'
|
||||||
|
import { creditDPoints, PD_PER_UNIT } from './dpoints'
|
||||||
|
|
||||||
|
const API = 'https://api.sumup.com/v0.1'
|
||||||
|
|
||||||
|
/** SumUp está disponible sólo si hay API key y merchant code configurados. */
|
||||||
|
export function sumupConfigured(): boolean {
|
||||||
|
return Boolean(process.env.SUMUP_API_KEY && process.env.SUMUP_MERCHANT_CODE)
|
||||||
|
}
|
||||||
|
|
||||||
|
function authHeaders(): Record<string, string> {
|
||||||
|
return {
|
||||||
|
Authorization: `Bearer ${process.env.SUMUP_API_KEY}`,
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CreateParams {
|
||||||
|
accountId: number
|
||||||
|
username: string
|
||||||
|
email: string
|
||||||
|
acoreIp: string
|
||||||
|
amount: number // importe en la moneda del comercio
|
||||||
|
points: number
|
||||||
|
reference: string
|
||||||
|
description: string
|
||||||
|
returnUrl: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Crea un checkout hospedado de SumUp y registra el pago en `home_stripelog`
|
||||||
|
* (reutilizamos la tabla de logs; `mode = 'sumup'`, `session_id = reference`).
|
||||||
|
* Devuelve la URL del checkout hospedado para redirigir al usuario.
|
||||||
|
*/
|
||||||
|
export async function createSumUpCheckout(p: CreateParams): Promise<{ success: boolean; url?: string; error?: string }> {
|
||||||
|
if (!sumupConfigured()) return { success: false, error: 'notConfigured' }
|
||||||
|
try {
|
||||||
|
const res = await fetch(`${API}/checkouts`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: authHeaders(),
|
||||||
|
body: JSON.stringify({
|
||||||
|
checkout_reference: p.reference,
|
||||||
|
amount: p.amount,
|
||||||
|
currency: process.env.SUMUP_CURRENCY || 'EUR',
|
||||||
|
merchant_code: process.env.SUMUP_MERCHANT_CODE,
|
||||||
|
description: p.description,
|
||||||
|
return_url: p.returnUrl,
|
||||||
|
hosted_checkout: { enabled: true },
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
if (!res.ok) return { success: false, error: `sumup_${res.status}` }
|
||||||
|
const data: { id?: string; hosted_checkout_url?: string } = await res.json()
|
||||||
|
const url = data.hosted_checkout_url
|
||||||
|
if (!url) return { success: false, error: 'noHostedUrl' }
|
||||||
|
|
||||||
|
await db(DB.default).query(
|
||||||
|
'INSERT INTO home_stripelog (account_id, username, email, acore_ip, stripe_ip, product_name, amount, session_id, mode, character_name, timestamp, fulfilled) ' +
|
||||||
|
'VALUES (?, ?, ?, ?, NULL, ?, ?, ?, ?, ?, NOW(), 0)',
|
||||||
|
[p.accountId, p.username, p.email, p.acoreIp, p.description, p.amount, p.reference, 'sumup', p.username],
|
||||||
|
)
|
||||||
|
return { success: true, url }
|
||||||
|
} catch (e) {
|
||||||
|
return { success: false, error: String(e) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** ¿El checkout con esta referencia está PAGADO en SumUp? */
|
||||||
|
async function isReferencePaid(reference: string): Promise<boolean> {
|
||||||
|
try {
|
||||||
|
const res = await fetch(`${API}/checkouts?checkout_reference=${encodeURIComponent(reference)}`, {
|
||||||
|
headers: authHeaders(),
|
||||||
|
})
|
||||||
|
if (!res.ok) return false
|
||||||
|
const list: { status?: string }[] = await res.json()
|
||||||
|
return Array.isArray(list) && list.some((c) => c.status === 'PAID')
|
||||||
|
} catch {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entrega un checkout SumUp pagado: verifica el estado, reclama de forma atómica
|
||||||
|
* (fulfilled 0->1) y acredita los PD. Idempotente. Devuelve true si acreditó ahora.
|
||||||
|
*/
|
||||||
|
export async function fulfillSumUpCheckout(reference: string): Promise<{ ok: boolean; paid: boolean }> {
|
||||||
|
if (!reference) return { ok: false, paid: false }
|
||||||
|
const paid = await isReferencePaid(reference)
|
||||||
|
if (!paid) return { ok: false, paid: false }
|
||||||
|
|
||||||
|
const [rows] = await db(DB.default).query<RowDataPacket[]>(
|
||||||
|
'SELECT id, account_id, amount FROM home_stripelog WHERE session_id = ? AND mode = ?',
|
||||||
|
[reference, 'sumup'],
|
||||||
|
)
|
||||||
|
const log = rows[0]
|
||||||
|
if (!log) return { ok: false, paid: true }
|
||||||
|
|
||||||
|
// Reclamo atómico: sólo gana quien pasa fulfilled 0->1.
|
||||||
|
const [res] = await db(DB.default).query<ResultSetHeader>(
|
||||||
|
'UPDATE home_stripelog SET fulfilled = 1 WHERE id = ? AND fulfilled = 0',
|
||||||
|
[log.id],
|
||||||
|
)
|
||||||
|
if (res.affectedRows === 0) return { ok: false, paid: true }
|
||||||
|
|
||||||
|
const points = Math.round(Number(log.amount) * PD_PER_UNIT)
|
||||||
|
const ok = await creditDPoints(Number(log.account_id), points)
|
||||||
|
return { ok, paid: true }
|
||||||
|
}
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 12 KiB |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 150 46" role="img" aria-label="Stripe">
|
||||||
|
<rect x="0" y="0" width="150" height="46" rx="9" fill="#635BFF"/>
|
||||||
|
<text x="75" y="31" text-anchor="middle" font-family="Arial, Helvetica, sans-serif" font-weight="700" font-size="24" letter-spacing="-1" fill="#ffffff">stripe</text>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 336 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" role="img" aria-label="Stripe">
|
||||||
|
<rect x="0" y="0" width="32" height="32" rx="7" fill="#635BFF"/>
|
||||||
|
<text x="16" y="23" text-anchor="middle" font-family="Arial, Helvetica, sans-serif" font-weight="700" font-size="20" fill="#ffffff">S</text>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 309 B |
@@ -0,0 +1,5 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 170 46" role="img" aria-label="SumUp">
|
||||||
|
<rect x="0" y="0" width="46" height="46" rx="9" fill="#1E64FF"/>
|
||||||
|
<path d="M13 13 H33 V26 L26 33 H13 Z" fill="#ffffff"/>
|
||||||
|
<text x="105" y="31" text-anchor="middle" font-family="Arial, Helvetica, sans-serif" font-weight="700" font-size="24" letter-spacing="-1" fill="#1E64FF">SumUp</text>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 391 B |
@@ -0,0 +1,4 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" role="img" aria-label="SumUp">
|
||||||
|
<rect x="0" y="0" width="32" height="32" rx="7" fill="#1E64FF"/>
|
||||||
|
<path d="M9 9 H23 V18 L18 23 H9 Z" fill="#ffffff"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 219 B |
Reference in New Issue
Block a user