Component PaymentButton là một component React cung cấp giao diện thanh toán
hoàn chỉnh để chấp nhận thanh toán Solana. Nó xử lý kết nối ví, chọn token, xử
lý giao dịch và quản lý trạng thái UI ngay trong component. Ngay từ đầu, nó đi
kèm với nút và modal có thể tùy chỉnh:
Nút Tip
Nút Tip
Modal Thanh toán
Modal Thanh toán
Modal Mã QR Solana Pay
Modal Giỏ hàng
Cài đặt
pnpm add @solana-commerce/kit
Props của Component
PaymentButtonProps
Component PaymentButton chấp nhận các props sau:
Props Bắt buộc
config(SolanaCommerceConfig) - Object cấu hình chính cho component thanh toán. Đây là prop bắt buộc duy nhất. Xem SolanaCommerceConfig bên dưới.
Props Tùy chọn
-
paymentConfig(PaymentConfig) - Cấu hình riêng cho thanh toán bao gồm sản phẩm, ghi đè giá và bộ lấy giá tùy chỉnh. Xem PaymentConfig bên dưới. -
onPayment((amount: number, currency: string) => void) - Được gọi khi một thanh toán được khởi tạo sau khi người dùng xác nhận số tiền và loại tiền. Nhận số tiền thanh toán (tính theo đơn vị token, không phải lamport) và định danh loại tiền. -
onPaymentStart(() => void) - Được gọi khi luồng thanh toán bắt đầu, trước khi giao dịch thực sự được gửi đi. Sử dụng để hiển thị trạng thái loading hoặc theo dõi phân tích. -
onPaymentSuccess((signature: string) => void) - Được gọi khi giao dịch được xác nhận trên chuỗi. Nhận chữ ký giao dịch. Đây là nơi bạn nên cập nhật trạng thái đơn hàng, gửi email xác nhận, v.v. -
onPaymentError((error: Error) => void) - Được gọi khi thanh toán thất bại ở bất kỳ giai đoạn nào (kết nối ví, gửi giao dịch hoặc xác nhận). Object lỗi chứa chi tiết về nguyên nhân thất bại. -
onCancel(() => void) - Được gọi khi người dùng hủy rõ ràng luồng thanh toán (đóng modal hoặc nhấp hủy). -
children(React.ReactNode) - Phần tử kích hoạt tùy chỉnh (tùy chọn). Nếu được cung cấp, sẽ thay thế nút thanh toán mặc định. Phần tử con phải có thể nhấp được (ví dụ: một nút bấm). -
className(string) - Tên lớp CSS được áp dụng cho nút kích hoạt (chỉ được sử dụng khi không có phần tử con tùy chỉnh). -
style(React.CSSProperties) - Kiểu nội tuyến được áp dụng cho nút kích hoạt (chỉ được sử dụng khi không có phần tử con tùy chỉnh). -
variant('default' | 'icon-only') - Biến thể nút bấm. Mặc định hiển thị văn bản và biểu tượng,'icon-only'chỉ hiển thị biểu tượng thanh toán.
Các Đối Tượng Cấu Hình
SolanaCommerceConfig
Đối tượng cấu hình chính được truyền vào prop config.
Trường Bắt Buộc
-
merchant(MerchantConfig) - Thông tin người bán và chi tiết người nhận thanh toán. Xem MerchantConfig. -
mode('cart' | 'tip' | 'buyNow') - Chế độ thanh toán xác định văn bản hiển thị trên nút và luồng giao diện:'buyNow'- Mua sản phẩm đơn lẻ với số tiền cố định'cart'- Giỏ hàng với nhiều sản phẩm'tip'- Người dùng tự chọn số tiền (quyên góp/tiền boa)
Trường Tùy Chọn
-
position('inline' | 'overlay') - Cách hiển thị giao diện thanh toán. Mặc định là'overlay'.'overlay'- Mở trong lớp phủ modal/drawer'inline'- Nhúng trực tiếp vào trang
-
theme(ThemeConfig) - Tùy chọn tùy chỉnh giao diện. Xem ThemeConfig. -
network('mainnet' | 'devnet' | 'testnet') - Mạng Solana sẽ sử dụng. Mặc định là'mainnet'. -
rpcUrl(string) - URL điểm cuối RPC tùy chỉnh. Nếu không được cung cấp, sẽ sử dụng điểm cuối công khai mặc định cho mạng đã chọn. -
allowedMints(string[]) - Mảng các địa chỉ mint token để hạn chế phương thức thanh toán. Nếu không được cung cấp, tất cả các token được hỗ trợ (SOL, USDC, USDT) đều khả dụng. -
showQR(boolean) - Có hiển thị tùy chọn thanh toán bằng mã QR hay không. Hữu ích cho thiết bị di động và tích hợp Solana Pay. -
enableWalletConnect(boolean) - Bật hay tắt kết nối ví. Đặt thànhfalsenếu bạn đang xử lý kết nối ví bên ngoài. -
showMerchantInfo(boolean) - Hiển thị hay ẩn tên và logo người bán trong giao diện thanh toán. -
debug(boolean) - Bật ghi log chi tiết trên console để gỡ lỗi.
MerchantConfig
Xác định người nhận thanh toán và thông tin doanh nghiệp.
Trường Bắt Buộc
-
name(string) - Tên doanh nghiệp hoặc người bán được hiển thị cho người dùng trong quá trình thanh toán. -
wallet(string) - Địa chỉ ví Solana sẽ nhận thanh toán. Phải là địa chỉ Solana hợp lệ được mã hóa base58.
Trường Tùy Chọn
-
logo(string) - URL đến hình ảnh logo người bán. Được hiển thị trong giao diện thanh toán khishowMerchantInfođược bật. -
description(string) - Mô tả doanh nghiệp hiển thị cho người dùng.
ThemeConfig
Tùy chỉnh giao diện cho UI thanh toán.
Tất cả các trường đều là tùy chọn và có giá trị mặc định hợp lý.
-
primaryColor(string) - Màu thương hiệu chính được sử dụng cho nút bấm và điểm nhấn. Mặc định:'#9945FF'(tím Solana). -
secondaryColor(string) - Màu điểm nhấn phụ. Mặc định:'#14F195'(xanh lá Solana). -
backgroundColor(string) - Màu nền của modal/container. Mặc định:'#ffffff'. -
textColor(string) - Màu văn bản chính. Mặc định:'#111827'. -
borderRadius('none' | 'sm' | 'md' | 'lg' | 'xl' | 'full') - Bán kính bo tròn áp dụng cho các phần tử UI. Mặc định:'lg'.'none'= 0px'sm'= 12px'md'= 16px'lg'= 20px'xl'= 24px'full'= Bo tròn hoàn toàn (tùy theo ngữ cảnh)
-
fontFamily(string) - Họ font chữ cho tất cả văn bản. Mặc định:'system-ui, -apple-system, sans-serif'. -
buttonShadow('none' | 'sm' | 'md' | 'lg' | 'xl') - Bóng đổ cho nút bấm. Mặc định:'md'. -
buttonBorder('none' | 'black-10') - Kiểu viền cho nút bấm. Mặc định:'black-10'(viền đen nhẹ).
PaymentConfig
Cấu hình thanh toán nâng cao cho giá cả, số thập phân và sản phẩm.
Tất cả các trường đều là tùy chọn.
-
products(Product[]) - Mảng các sản phẩm cho chế độ'cart'hoặc'buyNow'. Bắt buộc khi sử dụng các chế độ này. Mỗi sản phẩm có:id(chuỗi, bắt buộc) - Mã định danh duy nhất của sản phẩmname(chuỗi, bắt buộc) - Tên sản phẩm hiển thị cho người dùngquantity(số, bắt buộc) - Số lượng của sản phẩm nàyprice(số, tùy chọn) - Giá mỗi đơn vị tính bằng USDunitAmount(số, tùy chọn) - Thay thế cho trườngpricedescription(chuỗi, tùy chọn) - Mô tả sản phẩm
-
solPriceUsd(number) - Giá SOL cố định tính bằng USD. Sử dụng tính năng này để thử nghiệm hoặc khi bạn muốn khóa giá SOL. Nếu không được cung cấp, component sẽ lấy giá hiện tại từ CoinGecko. -
getSolPrice(() => Promise<number>) - Hàm tùy chỉnh để lấy giá SOL. Sử dụng cho:- Các oracle giá riêng tư
- Tránh giới hạn tốc độ của API công khai
- Logic định giá tùy chỉnh
- Ứng dụng doanh nghiệp
Nếu không được cung cấp, mặc định sử dụng API công khai CoinGecko với bộ nhớ đệm 1 phút.
-
tokenDecimals({ [currency: string]: number }) - Ghi đè độ chính xác số thập phân của token. Hữu ích cho các token tùy chỉnh. Ví dụ:tokenDecimals: {'CUSTOM': 8,'USDC': 6 // Can override defaults} -
fallbackSolPriceUsd(number) - Giá SOL dự phòng nếu API giá thất bại và không có bộ nhớ đệm khả dụng. Nếu không có giá trị này, giao diện thanh toán sẽ hiển thị lỗi khi việc lấy giá thất bại.
Hooks Nội Bộ
Component PaymentButton sử dụng một số hooks nội bộ để quản lý trạng thái và
tính toán các giá trị:
useTheme(theme?: ThemeConfig)
Kết hợp cấu hình giao diện do người dùng cung cấp với các giá trị giao diện mặc
định. Trả về một đối tượng ThemeConfig hoàn chỉnh với tất cả các trường đã
được điền đầy đủ.
Giá trị giao diện mặc định:
primaryColor: '#9945FF'secondaryColor: '#14F195'backgroundColor: '#ffffff'textColor: '#111827'borderRadius: 'lg'fontFamily: 'system-ui, -apple-system, sans-serif'buttonShadow: 'md'buttonBorder: 'black-10'
Hook được ghi nhớ và chỉ tính toán lại khi cấu hình giao diện thay đổi.
useTotalAmount(mode, paymentConfig?)
Tính toán tổng số tiền thanh toán dựa trên chế độ thương mại và sản phẩm.
Hành vi theo chế độ:
- Chế độ
'tip'- Trả về0(số tiền do người dùng quyết định) - Chế độ
'cart'và'buyNow'- Tính tổngprice * quantitycho tất cả sản phẩm trongpaymentConfig.products
Hook xử lý các trường hợp đặc biệt:
- Giá bị thiếu hoặc không hợp lệ mặc định là
0 - Số lượng bị thiếu hoặc không hợp lệ mặc định là
0 - Đảm bảo tất cả các giá trị là số hữu hạn
- Hỗ trợ cả trường sản phẩm
pricevàunitAmount
Trả về tổng số tiền dưới dạng số (tính bằng USD cho giỏ hàng/mua ngay, 0 cho tiền boa).
usePaymentUrl(merchant, amount, mode)
Tạo URL Solana Pay cho thanh toán. URL này có thể được mã hóa thành mã QR để quét bằng ví di động.
Trả về: Một URL giao thức solana: với các tham số truy vấn cho:
recipient- Địa chỉ ví người bánamount- Số tiền thanh toánreference- Tham chiếu thanh toán duy nhất (được tạo từ dấu thời gian + chuỗi ngẫu nhiên)label- Tên người bán (được làm sạch cho URL an toàn)message- Thông điệp theo ngữ cảnh dựa trên chế độ
Trả về chuỗi rỗng nếu ví người bán không hợp lệ hoặc số tiền là <= 0.
Bảo mật: Tên người bán được làm sạch bằng sanitizeString() để ngăn chặn
các cuộc tấn công XSS thông qua chèn URL.
Xác thực & Xử lý Lỗi
Component thực hiện xác thực trước khi render:
-
Xác thực Ví - Sử dụng
isAddress()từgillđể xác thực địa chỉ ví người bán. Nếu không hợp lệ, render trạng thái lỗi thay vì giao diện thanh toán. -
Xác thực Giá - Đảm bảo giá được cấu hình hợp lệ:
- Đối với chế độ
'tip': Luôn hợp lệ (người dùng chọn số tiền) - Đối với chế độ
'cart'và'buyNow': Xác thực rằngtotalAmount > 0
- Đối với chế độ
-
An toàn SSR - Sử dụng phát hiện phía client để tránh lỗi không khớp hydration. Trạng thái
isClientđảm bảo các tính năng chỉ dành cho trình duyệt (nhưlocalStorageđể lưu trữ ví) chỉ chạy trên client.
Kiến trúc Component
PaymentButton bọc tất cả các children trong hai context provider:
-
AppProvider- Cung cấp trạng thái kết nối ví và connector client- Tự động kết nối: tắt theo mặc định
- Lưu trữ: Sử dụng
localStoragekhi khả dụng (chỉ phía client) - Chế độ debug: có thể cấu hình qua config
-
ArcProvider- Cung cấp Solana blockchain client và kết nối RPC- Network: Được xác định từ
config.network - RPC URL: Sử dụng phân giải phía server với dự phòng đến các endpoint công khai
- Network: Được xác định từ
Phân giải RPC URL
Component bao gồm cơ chế phân giải RPC URL tinh vi:
- Nếu
config.rpcUrlđược cung cấp, nó sẽ được sử dụng trực tiếp - Nếu không, nó gọi một resolver phía server để chọn các endpoint đáng tin cậy
- Dự phòng về
https://api.mainnet-beta.solana.comnếu phân giải thất bại - Phân giải diễn ra bất đồng bộ khi mount và cập nhật state
Chế độ Hiển thị
Chế độ overlay (position: 'overlay' hoặc mặc định):
- Hiển thị nút kích hoạt (tùy chỉnh hoặc mặc định)
- Mở giao diện thanh toán trong modal responsive (desktop) hoặc drawer (mobile)
- Sử dụng component
ResponsiveShellcho bố cục thích ứng
Chế độ inline (position: 'inline'):
- Nhúng giao diện thanh toán trực tiếp vào trang
- Không cần nút kích hoạt
- Hữu ích cho các trang thanh toán chuyên dụng
Cả hai chế độ đều sử dụng SecureIframeShell bên trong để hiển thị giao diện
thanh toán trong iframe được sandbox hóa để đảm bảo bảo mật.
Ví dụ Sử dụng
Thanh toán Cơ bản
<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 Tip với Custom Price Fetcher
<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}}/>
Giỏ hàng với Giao diện Tùy chỉnh
<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 })});}}/>
Nút Kích hoạt Tùy chỉnh
<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?