El componente PaymentButton es un componente de React que proporciona una
interfaz completa de pago para aceptar pagos en Solana. Maneja internamente la
conexión de billeteras, la selección de tokens, el procesamiento de
transacciones y la gestión del estado de la interfaz. De forma predeterminada,
viene con botones y modales personalizables:
Botón de Propina
Botón de Propina
Modal de Pago
Modal de Pago
Modal de Código QR de Solana Pay
Modal del Carrito
Instalación
pnpm add @solana-commerce/kit
Props del Componente
PaymentButtonProps
El componente PaymentButton acepta las siguientes props:
Props Requeridas
config(SolanaCommerceConfig) - Objeto de configuración principal para el componente de pago. Esta es la única prop requerida. Consulte SolanaCommerceConfig a continuación.
Props Opcionales
-
paymentConfig(PaymentConfig) - Configuración específica del pago que incluye productos, sobreescrituras de precios y captadores de precios personalizados. Consulte PaymentConfig a continuación. -
onPayment((amount: number, currency: string) => void) - Se invoca cuando se inicia un pago después de que el usuario confirma el monto y la moneda. Recibe el monto del pago (en unidades de token, no en lamports) y el identificador de la moneda. -
onPaymentStart(() => void) - Se invoca cuando comienza el flujo de pago, antes de que se envíe la transacción real. Úselo para mostrar estados de carga o seguimiento de análisis. -
onPaymentSuccess((signature: string) => void) - Se invoca cuando la transacción se confirma en la cadena. Recibe la firma de la transacción. Aquí es donde debe actualizar el estado del pedido, enviar correos de confirmación, etc. -
onPaymentError((error: Error) => void) - Se invoca cuando el pago falla en cualquier etapa (conexión de billetera, envío de transacción o confirmación). El objeto de error contiene detalles sobre lo que salió mal. -
onCancel(() => void) - Se invoca cuando el usuario cancela explícitamente el flujo de pago (cierra el modal o hace clic en cancelar). -
children(React.ReactNode) - Elemento disparador personalizado opcional. Si se proporciona, reemplaza el botón de pago predeterminado. El elemento hijo debe ser clicable (por ejemplo, un botón). -
className(string) - Nombre de clase CSS aplicado al botón disparador (solo se usa cuando no se proporcionan elementos hijos personalizados). -
style(React.CSSProperties) - Estilos en línea aplicados al botón disparador (solo se usan cuando no se proporcionan elementos hijos personalizados). -
variant('default' | 'icon-only') - Variante del botón. Por defecto muestra texto e icono,'icon-only'muestra solo el icono de pago.
Objetos de Configuración
SolanaCommerceConfig
El objeto de configuración principal que se pasa a la prop config.
Campos Requeridos
-
merchant(MerchantConfig) - Información del comerciante y detalles del destinatario del pago. Ver MerchantConfig. -
mode('cart' | 'tip' | 'buyNow') - Modo de pago que determina el texto mostrado en el botón y el flujo de la interfaz:'buyNow'- Compra de un solo producto con monto fijo'cart'- Carrito de compras con múltiples productos'tip'- El usuario elige su propio monto (donaciones/propinas)
Campos Opcionales
-
position('inline' | 'overlay') - Cómo se muestra la interfaz de pago. Por defecto es'overlay'.'overlay'- Se abre en una superposición modal/drawer'inline'- Integrado directamente en la página
-
theme(ThemeConfig) - Opciones de personalización visual. Ver ThemeConfig. -
network('mainnet' | 'devnet' | 'testnet') - Red de Solana a utilizar. Por defecto es'mainnet'. -
rpcUrl(string) - URL del endpoint RPC personalizado. Si no se proporciona, utiliza un endpoint público predeterminado para la red seleccionada. -
allowedMints(string[]) - Array de direcciones mint de tokens para restringir los métodos de pago. Si no se proporciona, todos los tokens compatibles (SOL, USDC, USDT) están disponibles. -
showQR(boolean) - Si se debe mostrar la opción de pago con código QR. Útil para móviles e integración con Solana Pay. -
enableWalletConnect(boolean) - Si se habilita la conexión de billetera. Configúralo comofalsesi estás gestionando la conexión de billetera externamente. -
showMerchantInfo(boolean) - Si se muestra el nombre y logotipo del comerciante en la interfaz de pago. -
debug(boolean) - Habilita el registro detallado en consola para depuración.
MerchantConfig
Define el destinatario del pago y la información del negocio.
Campos Obligatorios
-
name(string) - Nombre del negocio o comerciante mostrado a los usuarios durante la compra. -
wallet(string) - Dirección de billetera Solana que recibirá los pagos. Debe ser una dirección Solana válida codificada en base58.
Campos Opcionales
-
logo(string) - URL de la imagen del logotipo del comerciante. Se muestra en la interfaz de pago cuandoshowMerchantInfoestá habilitado. -
description(string) - Descripción del negocio mostrada a los usuarios.
ThemeConfig
Personalización visual para la interfaz de pago.
Todos los campos son opcionales y tienen valores predeterminados razonables.
-
primaryColor(string) - Color principal de la marca usado para botones y acentos. Predeterminado:'#9945FF'(púrpura Solana). -
secondaryColor(string) - Color de acento secundario. Predeterminado:'#14F195'(verde Solana). -
backgroundColor(string) - Color de fondo del modal/contenedor. Predeterminado:'#ffffff'. -
textColor(string) - Color de texto principal. Predeterminado:'#111827'. -
borderRadius('none' | 'sm' | 'md' | 'lg' | 'xl' | 'full') - Radio de borde aplicado a los elementos de la interfaz. Predeterminado:'lg'.'none'= 0px'sm'= 12px'md'= 16px'lg'= 20px'xl'= 24px'full'= Completamente redondeado (según el contexto)
-
fontFamily(string) - Familia de fuentes para todo el texto. Predeterminado:'system-ui, -apple-system, sans-serif'. -
buttonShadow('none' | 'sm' | 'md' | 'lg' | 'xl') - Sombra proyectada para botones. Predeterminado:'md'. -
buttonBorder('none' | 'black-10') - Estilo de borde para botones. Predeterminado:'black-10'(borde negro sutil).
PaymentConfig
Configuración avanzada de pago para precios, decimales y productos.
Todos los campos son opcionales.
-
products(Product[]) - Array de productos para los modos'cart'o'buyNow'. Requerido al usar estos modos. Cada producto tiene:id(string, requerido) - Identificador único del productoname(string, requerido) - Nombre del producto mostrado al usuarioquantity(number, requerido) - Cantidad de este productoprice(number, opcional) - Precio por unidad en USDunitAmount(number, opcional) - Alternativa al campopricedescription(string, opcional) - Descripción del producto
-
solPriceUsd(number) - Precio fijo de SOL en USD. Úsalo para pruebas o cuando quieras fijar el precio de SOL. Si no se proporciona, el componente obtiene el precio actual de CoinGecko. -
getSolPrice(() => Promise<number>) - Función personalizada para obtener el precio de SOL. Úsala para:- Oráculos de precios privados
- Evitar límites de tasa de APIs públicas
- Lógica de precios personalizada
- Aplicaciones empresariales
Si no se proporciona, por defecto usa la API pública de CoinGecko con caché de 1 minuto.
-
tokenDecimals({ [currency: string]: number }) - Anula la precisión decimal del token. Útil para tokens personalizados. Ejemplo:tokenDecimals: {'CUSTOM': 8,'USDC': 6 // Can override defaults} -
fallbackSolPriceUsd(number) - Precio de respaldo de SOL si la API de precios falla y no hay caché disponible. Sin esto, la interfaz de pago mostrará un error si falla la obtención del precio.
Hooks Internos
El componente PaymentButton utiliza varios hooks internos para gestionar el
estado y calcular valores:
useTheme(theme?: ThemeConfig)
Combina la configuración de tema proporcionada por el usuario con los valores de
tema predeterminados. Devuelve un objeto ThemeConfig completo con todos los
campos poblados.
Valores de tema predeterminados:
primaryColor: '#9945FF'secondaryColor: '#14F195'backgroundColor: '#ffffff'textColor: '#111827'borderRadius: 'lg'fontFamily: 'system-ui, -apple-system, sans-serif'buttonShadow: 'md'buttonBorder: 'black-10'
El hook está memoizado y solo recalcula cuando cambia la configuración del tema.
useTotalAmount(mode, paymentConfig?)
Calcula el monto total del pago basado en el modo de comercio y los productos.
Comportamiento por modo:
- Modo
'tip'- Devuelve0(el monto lo determina el usuario) - Modos
'cart'y'buyNow'- Sumaprice * quantitypara todos los productos enpaymentConfig.products
El hook maneja casos especiales:
- Los precios faltantes o inválidos se establecen por defecto en
0 - Las cantidades faltantes o inválidas se establecen por defecto en
0 - Asegura que todos los valores sean números finitos
- Soporta tanto los campos de producto
pricecomounitAmount
Devuelve el monto total como un número (en USD para carrito/comprar ahora, 0 para propina).
usePaymentUrl(merchant, amount, mode)
Genera una URL de Solana Pay para el pago. Esta URL puede codificarse como un código QR para escanear con billeteras móviles.
Devuelve: Una URL del protocolo solana: con parámetros de consulta para:
recipient- Dirección de billetera del comercianteamount- Monto del pagoreference- Referencia de pago única (generada a partir de marca de tiempo + cadena aleatoria)label- Nombre del comerciante (sanitizado para seguridad de URL)message- Mensaje contextual basado en el modo
Devuelve una cadena vacía si la billetera del comerciante es inválida o el monto
es <= 0.
Seguridad: El nombre del comerciante se sanitiza usando sanitizeString()
para prevenir ataques XSS a través de inyección de URL.
Validación y Manejo de Errores
El componente realiza validación antes de renderizar:
-
Validación de Billetera - Usa
isAddress()degillpara validar la dirección de billetera del comerciante. Si es inválida, renderiza un estado de error en lugar de la interfaz de pago. -
Validación de Precios - Asegura que haya precios válidos configurados:
- Para modo
'tip': Siempre válido (el usuario elige el monto) - Para modos
'cart'y'buyNow': Valida quetotalAmount > 0
- Para modo
-
Seguridad SSR - Utiliza detección del lado del cliente para prevenir discrepancias de hidratación. El estado
isClientasegura que las funcionalidades exclusivas del navegador (comolocalStoragepara la persistencia de billeteras) solo se ejecuten en el cliente.
Arquitectura de Componentes
El PaymentButton envuelve todos los elementos hijos en dos proveedores de
contexto:
-
AppProvider- Proporciona el estado de conexión de la billetera y el cliente conector- Conexión automática: deshabilitada por defecto
- Almacenamiento: Utiliza
localStoragecuando está disponible (solo del lado del cliente) - Modo de depuración: configurable mediante configuración
-
ArcProvider- Proporciona el cliente de blockchain de Solana y la conexión RPC- Red: Determinada desde
config.network - URL RPC: Utiliza resolución del lado del servidor con respaldo a endpoints públicos
- Red: Determinada desde
Resolución de URL RPC
El componente incluye resolución sofisticada de URL RPC:
- Si se proporciona
config.rpcUrl, se utiliza directamente - De lo contrario, llama a un resolvedor del lado del servidor que selecciona endpoints confiables
- Recurre a
https://api.mainnet-beta.solana.comsi falla la resolución - La resolución ocurre de forma asíncrona al montar y actualiza el estado
Modos de Renderizado
Modo overlay (position: 'overlay' o por defecto):
- Renderiza un botón disparador (personalizado o predeterminado)
- Abre la interfaz de pago en un modal responsivo (escritorio) o cajón (móvil)
- Utiliza el componente
ResponsiveShellpara diseños adaptativos
Modo inline (position: 'inline'):
- Incrusta la interfaz de pago directamente en la página
- No requiere botón disparador
- Útil para páginas de pago dedicadas
Ambos modos utilizan SecureIframeShell internamente para renderizar la
interfaz de pago en un iframe aislado por seguridad.
Ejemplos de Uso
Pago Básico
<PaymentButtonconfig={{merchant: {name: "Coffee Shop",wallet: "your-wallet-address"},mode: "buyNow"}}paymentConfig={{products: [{id: "coffee-001",name: "Espresso",price: 4.5,quantity: 1}]}}onPaymentSuccess={(sig) => {console.log("Payment confirmed:", sig);}}/>
Widget de Propina con Obtención de Precio Personalizada
<PaymentButtonconfig={{merchant: {name: "Content Creator",wallet: "creator-wallet"},mode: "tip"}}paymentConfig={{// Use your own price API to avoid rate limitsgetSolPrice: async () => {const res = await fetch("/custom-api/solana-price");const data = await res.json();return data.price;},// Fallback if your API failsfallbackSolPriceUsd: 200}}/>
Carrito de Compras con Tema Personalizado
<PaymentButtonconfig={{merchant: {name: "My Store",wallet: "store-wallet",logo: "/logo.png"},mode: "cart",theme: {primaryColor: "#FF6B6B",backgroundColor: "#1a1a1a",textColor: "#ffffff",borderRadius: "xl",buttonShadow: "lg"},showMerchantInfo: true}}paymentConfig={{products: [{ id: "1", name: "T-Shirt", price: 25, quantity: 2 },{ id: "2", name: "Hoodie", price: 45, quantity: 1 }]}}onPaymentSuccess={(signature) => {// Verify transaction on your backendfetch("/api/verify-payment", {method: "POST",body: JSON.stringify({ signature })});}}/>
Botón Disparador Personalizado
<PaymentButtonconfig={{merchant: { name: "Shop", wallet: "address" },mode: "buyNow"}}paymentConfig={{products: [{ id: "1", name: "Product", price: 10, quantity: 1 }]}}><button className="custom-button">🚀 Pay with Solana</button></PaymentButton>
Is this page helpful?