QR-коди — це найпоширеніший спосіб з'єднати веб-застосунки з мобільними
гаманцями. Solana Pay включає вбудовану функцію createQR на базі
@solana/qr-code-styling — додаткові пакети для QR-кодів не потрібні.
Базова генерація QR-кодів
Згенерувати та відобразити QR-код
import { address } from "@solana/kit";import { encodeURL, createQR } from "@solana/pay";// Create payment URLconst url = encodeURL({recipient: address("FvJ8k8HhXp4a3zQyFMZd4FvEqcYdYE7gSZWxrEBRfBsB"),amount: 0.05,label: "Coffee Shop",message: "Grande Americano"});// Generate QR code and append to DOMconst qr = createQR(url);qr.append(document.getElementById("payment-qr"));
Налаштування QR-кодів
Функція createQR приймає необов'язкові параметри для розміру, кольору фону та
кольору переднього плану:
// createQR(url, size?, background?, color?)const qr = createQR(url, 400, "#F5F5F5", "#512DA8");qr.append(document.getElementById("payment-qr"));
Отримання параметрів QR для розширеного використання
Використовуйте createQROptions, щоб отримати об'єкт конфігурації для більшого
контролю:
import { createQROptions } from "@solana/pay";const options = createQROptions(url, 300, "#ffffff", "#000000");// Pass to @solana/qr-code-styling or customize further
Використання клієнта для продавців
Клієнт для продавців також надає методи для роботи з QR-кодами:
import { address } from "@solana/kit";import { createMerchantClient } from "@solana/pay";const merchant = createMerchantClient({rpcUrl: "https://api.mainnet-beta.solana.com"});const recipient = address("FvJ8k8HhXp4a3zQyFMZd4FvEqcYdYE7gSZWxrEBRfBsB");const url = merchant.pay.encodeURL({ recipient, amount: 1.5 });// Generate QR codeconst qr = merchant.pay.createQR(url);qr.append(document.getElementById("qr-code"));
Інтеграція з React
Базовий компонент React
import { useEffect, useRef } from "react";import { address } from "@solana/kit";import { encodeURL, createQR } from "@solana/pay";function PaymentQR({ recipient, amount, label, message }) {const qrRef = useRef<HTMLDivElement>(null);useEffect(() => {const url = encodeURL({recipient: address(recipient),amount,label,message});const qr = createQR(url, 300);// Clear previous QR code and append new oneif (qrRef.current) {qrRef.current.innerHTML = "";qr.append(qrRef.current);}}, [recipient, amount, label, message]);return (<div><div ref={qrRef} /><p className="text-center mt-2 text-sm text-gray-600">Scan with your Solana wallet</p></div>);}// Usage<PaymentQRrecipient="FvJ8k8HhXp4a3zQyFMZd4FvEqcYdYE7gSZWxrEBRfBsB"amount={1.5}label="Online Store"message="Order #12345"/>;
QR-код платежу з оновленням статусу
import { useEffect, useRef, useState } from "react";import type { Address } from "@solana/kit";import { address, generateKeyPair, getAddressFromPublicKey } from "@solana/kit";import { encodeURL, createQR, createMerchantClient } from "@solana/pay";function PaymentQRWithStatus({ recipient, amount, label }) {const qrRef = useRef<HTMLDivElement>(null);const [status, setStatus] = useState<"pending" | "confirmed" | "timeout">("pending");const [reference, setReference] = useState<Address | null>(null);useEffect(() => {let interval: ReturnType<typeof setInterval>;let timeout: ReturnType<typeof setTimeout>;let cancelled = false;async function setup() {// Generate unique referenceconst keypair = await generateKeyPair();const ref = await getAddressFromPublicKey(keypair.publicKey);setReference(ref);const url = encodeURL({recipient: address(recipient),amount,reference: ref,label});const qr = createQR(url, 300);if (qrRef.current) {qrRef.current.innerHTML = "";qr.append(qrRef.current);}// Start monitoringconst merchant = createMerchantClient({rpcUrl: "https://api.mainnet-beta.solana.com"});interval = setInterval(async () => {try {const found = await merchant.pay.findReference(ref);await merchant.pay.validateTransfer(found.signature, {recipient: address(recipient),amount,reference: ref});if (!cancelled) {setStatus("confirmed");clearInterval(interval);clearTimeout(timeout);}} catch {// Not found yet}}, 2000);// Timeout after 5 minutestimeout = setTimeout(() => {clearInterval(interval);if (!cancelled) setStatus("timeout");},5 * 60 * 1000);}setup();return () => {cancelled = true;clearInterval(interval);clearTimeout(timeout);};}, [recipient, amount, label]);return (<div className="relative"><div ref={qrRef} />{status === "confirmed" && (<div className="absolute inset-0 flex items-center justify-center bg-green-500 bg-opacity-90 rounded-lg"><div className="text-white text-center"><p className="font-semibold">Payment Confirmed!</p></div></div>)}{status === "timeout" && (<p className="text-center mt-2 text-sm text-red-600">Payment timed out. Please try again.</p>)}</div>);}
Інтеграція з Point of Sale
Відображення QR-коду на POS-терміналі
import { address, generateKeyPair, getAddressFromPublicKey } from "@solana/kit";import { encodeURL, createQR, createMerchantClient } from "@solana/pay";class POSTerminal {private merchantWallet;private merchant;constructor(merchantWallet, rpcUrl) {this.merchantWallet = address(merchantWallet);this.merchant = createMerchantClient({ rpcUrl });}async createOrder(items, customLabel) {const total = items.reduce((sum, item) => sum + item.price, 0);const keypair = await generateKeyPair();const reference = await getAddressFromPublicKey(keypair.publicKey);const orderId = Date.now().toString();const url = this.merchant.pay.encodeURL({recipient: this.merchantWallet,amount: total,reference,label: customLabel || "Point of Sale",message: `Receipt #${orderId}`,memo: `POS-${orderId}`});const qr = this.merchant.pay.createQR(url, 400);return { orderId, total, reference, qr, url };}async monitorPayment(reference, amount, callback) {const checkPayment = async () => {try {const found = await this.merchant.pay.findReference(reference);await this.merchant.pay.validateTransfer(found.signature, {recipient: this.merchantWallet,amount,reference});callback({ success: true, signature: found.signature });return true;} catch {return false;}};const interval = setInterval(async () => {const found = await checkPayment();if (found) clearInterval(interval);}, 1000);// Timeout after 5 minutessetTimeout(() => {clearInterval(interval);callback({ success: false, error: "Payment timeout" });},5 * 60 * 1000);}}// Usageconst pos = new POSTerminal("FvJ8k8HhXp4a3zQyFMZd4FvEqcYdYE7gSZWxrEBRfBsB","https://api.mainnet-beta.solana.com");const { qr, reference, total } = await pos.createOrder([{ name: "Coffee", price: 3.5 },{ name: "Muffin", price: 2.25 }],"Local Coffee Shop");// Display QR codeqr.append(document.getElementById("pos-display"));// Monitor for paymentpos.monitorPayment(reference, total, (result) => {if (result.success) {console.log("Payment received!", result.signature);} else {console.log("Payment failed or timed out");}});
Відображення, оптимізоване для мобільних пристроїв
На мобільних пристроях варто надавати пряме посилання поряд з QR-кодом:
function MobilePayment({ paymentUrl }) {const qrRef = useRef(null);const isMobile = /Android|iPhone|iPad|iPod/i.test(navigator.userAgent);useEffect(() => {const qr = createQR(paymentUrl, isMobile ? 250 : 300);if (qrRef.current) {qrRef.current.innerHTML = "";qr.append(qrRef.current);}}, [paymentUrl, isMobile]);return (<div><div ref={qrRef} />{isMobile && (<buttononClick={() => window.open(paymentUrl.toString())}className="mt-4 bg-purple-600 text-white px-6 py-3 rounded-lg w-full">Open in Wallet</button>)}</div>);}
Доступність
function AccessiblePaymentQR({ paymentUrl, amount, label }) {const qrRef = useRef(null);useEffect(() => {const qr = createQR(paymentUrl);if (qrRef.current) {qrRef.current.innerHTML = "";qr.append(qrRef.current);}}, [paymentUrl]);return (<divrole="img"aria-label={`Payment QR code for ${amount} SOL to ${label}`}><div ref={qrRef} />{/* Manual URL copy option */}<details className="mt-2"><summary className="cursor-pointer text-sm text-gray-600">Copy payment URL manually</summary><inputtype="text"value={paymentUrl.toString()}readOnlyclassName="w-full mt-1 p-2 border rounded text-xs"onClick={(e) => e.target.select()}/></details></div>);}
Is this page helpful?