UNPKG

coinley-test

Version:

Beautiful blockchain payment gateway SDK for seamless crypto payments - React & vanilla js

1,043 lines 162 kB
import React, { useState, useRef, useEffect, createContext, forwardRef, useContext, useImperativeHandle } from "react"; import { motion, AnimatePresence } from "framer-motion"; import { ArrowLeft, X, Sparkles, Wallet, Zap, QrCode, Loader2, ChevronDown, CheckCircle2, Copy, ExternalLink, AlertCircle } from "lucide-react"; import { createCoinleyWalletConfig, CoinleyWalletProvider, WalletModal, useWallet, useWalletConnect, useWalletDetection, useWalletTransaction, useWalletModal } from "@coinley/wallet-connect-core"; import axios from "axios"; import ReactDOM from "react-dom"; var jsxRuntime = { exports: {} }; var reactJsxRuntime_production_min = {}; /** * @license React * react-jsx-runtime.production.min.js * * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ var f = React, k = Symbol.for("react.element"), l = Symbol.for("react.fragment"), m$1 = Object.prototype.hasOwnProperty, n = f.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner, p = { key: true, ref: true, __self: true, __source: true }; function q(c, a, g) { var b, d = {}, e = null, h = null; void 0 !== g && (e = "" + g); void 0 !== a.key && (e = "" + a.key); void 0 !== a.ref && (h = a.ref); for (b in a) m$1.call(a, b) && !p.hasOwnProperty(b) && (d[b] = a[b]); if (c && c.defaultProps) for (b in a = c.defaultProps, a) void 0 === d[b] && (d[b] = a[b]); return { $$typeof: k, type: c, key: e, ref: h, props: d, _owner: n.current }; } reactJsxRuntime_production_min.Fragment = l; reactJsxRuntime_production_min.jsx = q; reactJsxRuntime_production_min.jsxs = q; { jsxRuntime.exports = reactJsxRuntime_production_min; } var jsxRuntimeExports = jsxRuntime.exports; class PaymentAPI { constructor(baseURL, apiKey, apiSecret) { this.apiKey = apiKey; this.apiSecret = apiSecret; this.api = axios.create({ baseURL: baseURL.endsWith("/") ? baseURL.slice(0, -1) : baseURL, timeout: 3e4, headers: { "Content-Type": "application/json" } }); this.api.interceptors.request.use( (config) => { var _a; config.headers["X-API-Key"] = this.apiKey; config.headers["X-API-Secret"] = this.apiSecret; const token = this.generateMerchantToken(); if (token) { config.headers["Authorization"] = `Bearer ${token}`; } console.log("API Request:", { method: (_a = config.method) == null ? void 0 : _a.toUpperCase(), url: config.url, data: config.data }); return config; }, (error) => { console.error("Request interceptor error:", error); return Promise.reject(error); } ); this.api.interceptors.response.use( (response) => { console.log("API Response:", { status: response.status, url: response.config.url, data: response.data }); return response; }, (error) => { var _a, _b, _c, _d, _e; console.error("API Error:", { status: (_a = error.response) == null ? void 0 : _a.status, data: (_b = error.response) == null ? void 0 : _b.data, message: error.message }); if (((_c = error.response) == null ? void 0 : _c.status) === 401) { throw new Error("Authentication failed. Please check your API credentials."); } else if (((_d = error.response) == null ? void 0 : _d.status) === 404) { throw new Error("API endpoint not found. Please check your API URL."); } else if (((_e = error.response) == null ? void 0 : _e.status) >= 500) { throw new Error("Server error. Please try again later."); } throw error; } ); } generateMerchantToken() { try { const credentials = `${this.apiKey}:${this.apiSecret}`; return btoa(credentials); } catch (error) { console.error("Failed to generate token:", error); return null; } } async createPayment(params) { var _a, _b; try { const response = await this.api.post("/api/payments/create", params); return response.data; } catch (error) { if ((_b = (_a = error.response) == null ? void 0 : _a.data) == null ? void 0 : _b.error) { throw new Error(error.response.data.error); } throw new Error(error.message || "Failed to create payment"); } } async getPayment(paymentId) { var _a, _b; try { const response = await this.api.get(`/api/payments/${paymentId}`); return response.data; } catch (error) { if ((_b = (_a = error.response) == null ? void 0 : _a.data) == null ? void 0 : _b.error) { throw new Error(error.response.data.error); } throw new Error(error.message || "Failed to get payment details"); } } async getNetworks() { try { const response = await this.api.get("/api/networks"); return response.data; } catch (error) { console.error("Get networks failed:", error); return { networks: [ { id: "ethereum", name: "Ethereum", shortName: "ethereum", chainId: "1", type: "ethereum", explorerUrl: "https://etherscan.io", isTestnet: false }, { id: "bsc", name: "Binance Smart Chain", shortName: "bsc", chainId: "56", type: "bsc", explorerUrl: "https://bscscan.com", isTestnet: false }, { id: "polygon", name: "Polygon", shortName: "polygon", chainId: "137", type: "ethereum", explorerUrl: "https://polygonscan.com", isTestnet: false } ] }; } } async getStablecoins() { try { const response = await this.api.get("/api/networks/stablecoins"); return response.data; } catch (error) { console.error("Get stablecoins failed:", error); return { stablecoins: [ { id: "usdt-eth", name: "Tether USD", symbol: "USDT", contractAddress: "0xdAC17F958D2ee523a2206206994597C13D831ec7", decimals: 6, isStablecoin: true, networkId: "ethereum", Network: { id: "ethereum", name: "Ethereum", shortName: "ethereum", type: "ethereum" } }, { id: "usdc-eth", name: "USD Coin", symbol: "USDC", contractAddress: "0xA0b86a33E6441d81d0B93bF9EE0f74ca32F7e6f6", decimals: 6, isStablecoin: true, networkId: "ethereum", Network: { id: "ethereum", name: "Ethereum", shortName: "ethereum", type: "ethereum" } } ] }; } } async verifyQRPayment(paymentId) { var _a, _b; try { const response = await this.api.post("/api/payments/verify-qr", { paymentId }); return response.data; } catch (error) { if ((_b = (_a = error.response) == null ? void 0 : _a.data) == null ? void 0 : _b.error) { throw new Error(error.response.data.error); } throw new Error(error.message || "Failed to verify payment"); } } async processPayment(paymentId, transactionHash, network, senderAddress) { var _a, _b; try { const response = await this.api.post("/api/payments/process", { paymentId, transactionHash, network, senderAddress }); return response.data; } catch (error) { if ((_b = (_a = error.response) == null ? void 0 : _a.data) == null ? void 0 : _b.error) { throw new Error(error.response.data.error); } throw new Error(error.message || "Failed to process payment"); } } async healthCheck() { try { const response = await this.api.get("/api/health"); return response.status === 200; } catch (error) { console.error("Health check failed:", error); return false; } } } const WalletIntegration = ({ selectedNetwork, selectedToken, paymentData, config, onTransactionSent, onError, isConnecting, setIsConnecting }) => { const { isConnected, address, disconnect } = useWallet(); const { connectWallet, isPending } = useWalletConnect(); const { detectedWallets, hasWallets, walletCount } = useWalletDetection(); const { sendTransaction } = useWalletTransaction(); const { openModal } = useWalletModal(); detectedWallets.filter( (wallet) => wallet.name.toLowerCase().includes("metamask") || wallet.provider === "injected" || wallet.name.toLowerCase().includes("coinbase") || wallet.name.toLowerCase().includes("wallet connect") ); const handleConnectSpecificWallet = async (walletType) => { try { setIsConnecting(true); if (isConnected) { await disconnect(); await new Promise((resolve) => setTimeout(resolve, 1e3)); } if (walletType === "metamask" && window.ethereum && window.ethereum.isMetaMask) { try { await window.ethereum.request({ method: "eth_requestAccounts" }); console.log("✅ Connected directly to MetaMask"); } catch (error) { console.error("MetaMask connection failed:", error); throw error; } } else { await connectWallet(walletType); } } catch (error) { console.error("Wallet connection failed:", error); onError(error.message || "Failed to connect wallet"); } finally { setIsConnecting(false); } }; const handleOpenModal = () => { try { console.log("Attempting to open wallet modal..."); openModal(); } catch (error) { console.error("Failed to open modal:", error); handleConnectSpecificWallet("injected"); } }; const handleSendPayment = async () => { var _a; if (!isConnected || !paymentData || !selectedToken) { onError("Wallet not connected or payment data missing"); return; } try { setIsConnecting(true); console.log("🔍 Transaction Debug:"); console.log("Connected wallet address:", address); console.log("Payment data:", paymentData); console.log("Selected token:", selectedToken); console.log("Selected network:", selectedNetwork); let recipientAddress = (_a = paymentData.metadata) == null ? void 0 : _a.recipientWallet; console.log("Merchant recipient address:", recipientAddress); if (!recipientAddress || typeof recipientAddress !== "string") { throw new Error("Merchant wallet address not found in payment data"); } if (!recipientAddress.match(/^0x[a-fA-F0-9]{40}$/)) { throw new Error(`Invalid merchant address format: ${recipientAddress}`); } let txHash; if (selectedToken.contractAddress) { console.log("🔍 ERC-20 Transaction Details:"); console.log("Token contract:", selectedToken.contractAddress); console.log("Token decimals:", selectedToken.decimals); console.log("Payment amount:", paymentData.totalAmount); const decimals = selectedToken.decimals || 6; const amount = Math.floor(paymentData.totalAmount * Math.pow(10, decimals)); console.log("Calculated amount (with decimals):", amount); const methodId = "0xa9059cbb"; const addressWithoutPrefix = recipientAddress.slice(2); const recipientPadded = addressWithoutPrefix.toLowerCase().padStart(64, "0"); const amountPadded = amount.toString(16).padStart(64, "0"); const transferData = `${methodId}${recipientPadded}${amountPadded}`; console.log("🔍 Transaction Data:"); console.log("Method ID:", methodId); console.log("Recipient (padded):", recipientPadded); console.log("Amount (padded):", amountPadded); console.log("Full data:", transferData); const txParams = { to: selectedToken.contractAddress, data: transferData, value: "0x0" }; console.log("📤 Sending ERC-20 transaction:", txParams); txHash = await sendTransaction(txParams); } else { const value = Math.floor(paymentData.totalAmount * Math.pow(10, 18)); const valueHex = `0x${value.toString(16)}`; const txParams = { to: recipientAddress, value: valueHex }; console.log("📤 Sending native transaction:", txParams); txHash = await sendTransaction(txParams); } if (txHash) { console.log("✅ Transaction sent successfully:", txHash); onTransactionSent(txHash); } } catch (error) { console.error("❌ Transaction failed:", error); onError(error.message || "Transaction failed"); } finally { setIsConnecting(false); } }; const handleDisconnect = async () => { try { await disconnect(); } catch (error) { console.error("Disconnect error:", error); } }; return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-center space-y-6", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-4", children: [ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-16 h-16 bg-[#7042D2] bg-opacity-20 rounded-full flex items-center justify-center mx-auto", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Wallet, { className: "w-8 h-8 text-[#7042D2]" }) }), !isConnected ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [ /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-lg font-semibold", children: "Connect Your Wallet" }), /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-gray-600 dark:text-gray-400 text-sm", children: "Choose your preferred wallet to complete the payment" }), /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-3", children: [ /* @__PURE__ */ jsxRuntimeExports.jsxs( "button", { onClick: () => handleConnectSpecificWallet("metamask"), disabled: isPending || isConnecting, className: "w-full p-3 border border-gray-300 rounded-lg hover:border-[#7042D2] flex items-center space-x-3 transition-colors disabled:opacity-50", children: [ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xl", children: "🦊" }), /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-left flex-1", children: [ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "font-medium", children: "MetaMask" }), /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs text-gray-500", children: "Connect with MetaMask" }) ] }) ] } ), /* @__PURE__ */ jsxRuntimeExports.jsxs( "button", { onClick: handleOpenModal, disabled: isPending || isConnecting, className: "w-full p-3 border border-gray-300 rounded-lg hover:border-[#7042D2] flex items-center space-x-3 transition-colors disabled:opacity-50", children: [ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xl", children: "💼" }), /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-left flex-1", children: [ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "font-medium", children: "Other Wallets" }), /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs text-gray-500", children: "Choose from available wallets" }) ] }) ] } ), /* @__PURE__ */ jsxRuntimeExports.jsx( "button", { onClick: () => handleConnectSpecificWallet("injected"), disabled: isPending || isConnecting, className: "w-full p-2 text-sm border border-dashed border-gray-300 rounded-lg hover:border-[#7042D2] transition-colors disabled:opacity-50", children: "Try Direct Connection" } ) ] }), isConnecting && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-center space-x-2 text-gray-600", children: [ /* @__PURE__ */ jsxRuntimeExports.jsx(Loader2, { className: "w-4 h-4 animate-spin" }), /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Connecting..." }) ] }) ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [ /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-lg font-semibold text-green-600", children: "Wallet Connected ✅" }), /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-gray-50 dark:bg-gray-800 rounded-lg p-4 space-y-3", children: [ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center", children: [ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm text-gray-600 dark:text-gray-400", children: "Address:" }), /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center space-x-2", children: [ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono text-sm", children: [ address == null ? void 0 : address.slice(0, 6), "...", address == null ? void 0 : address.slice(-4) ] }), /* @__PURE__ */ jsxRuntimeExports.jsx( "button", { onClick: handleDisconnect, className: "text-xs text-red-600 hover:text-red-800", children: "Disconnect" } ) ] }) ] }), paymentData && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center", children: [ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm text-gray-600 dark:text-gray-400", children: "Amount:" }), /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-medium", children: [ paymentData.totalAmount, " ", selectedToken == null ? void 0 : selectedToken.symbol ] }) ] }), /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center", children: [ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm text-gray-600 dark:text-gray-400", children: "Network:" }), /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-medium", children: selectedNetwork == null ? void 0 : selectedNetwork.name }) ] }) ] }) ] }), /* @__PURE__ */ jsxRuntimeExports.jsx( "button", { onClick: handleSendPayment, disabled: isConnecting, className: "w-full bg-[#7042D2] text-white py-4 rounded-lg font-semibold hover:bg-[#7042D2]/90 transition-colors disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center space-x-2", children: isConnecting ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [ /* @__PURE__ */ jsxRuntimeExports.jsx(Loader2, { className: "w-5 h-5 animate-spin" }), /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Processing Payment..." }) ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [ /* @__PURE__ */ jsxRuntimeExports.jsx(Zap, { className: "w-5 h-5" }), /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Send Payment" }) ] }) } ), /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-xs text-gray-500", children: [ "Make sure you have enough ", selectedToken == null ? void 0 : selectedToken.symbol, " and ETH for gas fees" ] }) ] }) ] }) }); }; const CoinleyPayment = ({ apiKey, apiSecret, apiUrl = "http://localhost:9000", onSuccess, onError, onClose, isOpen, config, theme = "light", merchantName, debug = false }) => { const [currentStep, setCurrentStep] = useState("select-method"); const [networks, setNetworks] = useState([]); const [tokens, setTokens] = useState([]); const [selectedNetwork, setSelectedNetwork] = useState(null); const [selectedToken, setSelectedToken] = useState(null); const [paymentMethod, setPaymentMethod] = useState(null); const [qrCode, setQrCode] = useState(""); const [paymentData, setPaymentData] = useState(null); const [loading, setLoading] = useState(false); const [error, setError] = useState(""); const [copied, setCopied] = useState(false); const [txHash, setTxHash] = useState(""); const [isConnecting, setIsConnecting] = useState(false); const paymentAPI = useRef(new PaymentAPI(apiUrl, apiKey, apiSecret)); const walletConfig = createCoinleyWalletConfig({ appName: merchantName || "Coinley Payment", appDescription: "Crypto payment processing", // Fix: Provide proper chain configurations instead of just IDs chains: [ { id: 1, name: "Ethereum", network: "ethereum", rpcUrls: { default: { http: ["https://eth.llamarpc.com"] } }, nativeCurrency: { name: "Ethereum", symbol: "ETH", decimals: 18 } }, { id: 56, name: "BNB Smart Chain", network: "bsc", rpcUrls: { default: { http: ["https://bsc-dataseed1.binance.org"] } }, nativeCurrency: { name: "BNB", symbol: "BNB", decimals: 18 } } ] }); useEffect(() => { if (isOpen) { initializePayment(); } }, [isOpen]); const initializePayment = async () => { try { setLoading(true); setError(""); const [networksRes, tokensRes] = await Promise.all([ paymentAPI.current.getNetworks(), paymentAPI.current.getStablecoins() ]); setNetworks(networksRes.networks || []); setTokens(tokensRes.stablecoins || []); if (debug) { console.log("Initialized networks:", networksRes.networks); console.log("Initialized tokens:", tokensRes.stablecoins); } } catch (err) { console.error("Failed to initialize payment:", err); setError("Failed to load payment options. Please try again."); } finally { setLoading(false); } }; const handleMethodSelect = (method) => { setPaymentMethod(method); setCurrentStep("select-network"); }; const handleNetworkSelect = async (network) => { setSelectedNetwork(network); const networkTokens = tokens.filter( (token) => { var _a; return ((_a = token.Network) == null ? void 0 : _a.shortName) === network.shortName || token.networkId === network.id; } ); if (networkTokens.length > 1) { setCurrentStep("select-token"); } else if (networkTokens.length === 1) { const token = networkTokens[0]; setSelectedToken(token); await initiatePayment(network, token); } else { setError(`No supported tokens found for ${network.name}`); setCurrentStep("error"); } }; const handleTokenSelect = async (token) => { setSelectedToken(token); await initiatePayment(selectedNetwork, token); }; const initiatePayment = async (network, token) => { try { setLoading(true); const paymentPayload = { amount: config.amount, currency: token.symbol, network: network.shortName, customerEmail: config.customerEmail, callbackUrl: config.callbackUrl, metadata: { ...config.metadata, paymentMethod, selectedNetwork: network.shortName, selectedToken: token.symbol, // Add the merchant wallet addresses to metadata merchantWalletAddresses: config.merchantWalletAddresses } }; console.log("🔍 Payment payload with merchant wallets:", paymentPayload); const payment = await paymentAPI.current.createPayment(paymentPayload); setPaymentData(payment.payment); if (paymentMethod === "wallet") { setCurrentStep("wallet-connect"); } else { await generateQRCode(payment.payment); setCurrentStep("qr-code"); } } catch (err) { console.error("Payment initiation failed:", err); setError(err.message || "Failed to create payment"); setCurrentStep("error"); } finally { setLoading(false); } }; const generateQRCode = async (payment) => { var _a, _b; try { const recipientAddress = ((_a = payment.metadata) == null ? void 0 : _a.recipientWallet) || ((_b = config.merchantWalletAddresses) == null ? void 0 : _b[(selectedNetwork == null ? void 0 : selectedNetwork.shortName) || ""]); if (!recipientAddress) { throw new Error("Recipient wallet address not found"); } let qrData = ""; if ((selectedNetwork == null ? void 0 : selectedNetwork.type) === "ethereum" || (selectedNetwork == null ? void 0 : selectedNetwork.type) === "bsc") { qrData = (selectedToken == null ? void 0 : selectedToken.contractAddress) ? `ethereum:${selectedToken.contractAddress}/transfer?address=${recipientAddress}&uint256=${payment.totalAmount * Math.pow(10, selectedToken.decimals)}` : `ethereum:${recipientAddress}?value=${payment.totalAmount}e18`; } else if ((selectedNetwork == null ? void 0 : selectedNetwork.type) === "tron") { qrData = `tron:${recipientAddress}?amount=${payment.totalAmount}`; } else { qrData = `${selectedToken == null ? void 0 : selectedToken.symbol}:${recipientAddress}?amount=${payment.totalAmount}`; } setQrCode(recipientAddress); startPaymentVerification(payment.id); } catch (err) { console.error("QR code generation failed:", err); setError("Failed to generate QR code"); setCurrentStep("error"); } }; const startPaymentVerification = async (paymentId) => { const maxAttempts = 60; let attempts = 0; const checkPayment = async () => { var _a; try { const result = await paymentAPI.current.verifyQRPayment(paymentId); if (result.verified && ((_a = result.payment) == null ? void 0 : _a.transactionHash)) { setTxHash(result.payment.transactionHash); await handlePaymentSuccess(paymentId, result.payment.transactionHash); return true; } attempts++; if (attempts < maxAttempts) { setTimeout(checkPayment, 5e3); } else { setError("Payment verification timeout. Please check your transaction."); setCurrentStep("error"); } return false; } catch (err) { console.error("Payment verification error:", err); attempts++; if (attempts < maxAttempts) { setTimeout(checkPayment, 5e3); } else { setError("Payment verification failed"); setCurrentStep("error"); } return false; } }; setTimeout(checkPayment, 2e3); }; const handleTransactionSent = async (transactionHash) => { setTxHash(transactionHash); setCurrentStep("processing"); try { await paymentAPI.current.processPayment( paymentData.id, transactionHash, (selectedNetwork == null ? void 0 : selectedNetwork.shortName) || "", "" ); await handlePaymentSuccess(paymentData.id, transactionHash); } catch (error2) { console.error("Payment processing failed:", error2); await handlePaymentSuccess(paymentData.id, transactionHash); } }; const handlePaymentSuccess = async (paymentId, transactionHash) => { setCurrentStep("success"); if (onSuccess) { onSuccess(paymentId, transactionHash, { network: selectedNetwork == null ? void 0 : selectedNetwork.name, token: selectedToken == null ? void 0 : selectedToken.symbol, amount: paymentData == null ? void 0 : paymentData.totalAmount, method: paymentMethod }); } }; const copyToClipboard = async (text) => { try { await navigator.clipboard.writeText(text); setCopied(true); setTimeout(() => setCopied(false), 2e3); } catch (err) { console.error("Failed to copy:", err); } }; const handleClose = () => { setCurrentStep("select-method"); setPaymentMethod(null); setSelectedNetwork(null); setSelectedToken(null); setQrCode(""); setPaymentData(null); setError(""); setTxHash(""); if (onClose) { onClose(); } }; const goBack = () => { if (currentStep === "select-network") { setCurrentStep("select-method"); } else if (currentStep === "select-token") { setCurrentStep("select-network"); } else if (currentStep === "wallet-connect" || currentStep === "qr-code") { const networkTokens = tokens.filter( (token) => { var _a; return ((_a = token.Network) == null ? void 0 : _a.shortName) === (selectedNetwork == null ? void 0 : selectedNetwork.shortName) || token.networkId === (selectedNetwork == null ? void 0 : selectedNetwork.id); } ); if (networkTokens.length > 1) { setCurrentStep("select-token"); } else { setCurrentStep("select-network"); } } }; if (!isOpen) return null; return /* @__PURE__ */ jsxRuntimeExports.jsxs(CoinleyWalletProvider, { config: walletConfig, walletConfig: { appName: merchantName || "Coinley Payment" }, children: [ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-50 backdrop-blur-sm", children: /* @__PURE__ */ jsxRuntimeExports.jsxs( motion.div, { initial: { scale: 0.9, opacity: 0 }, animate: { scale: 1, opacity: 1 }, exit: { scale: 0.9, opacity: 0 }, className: `relative w-full max-w-md mx-4 rounded-2xl shadow-2xl overflow-hidden ${theme === "dark" ? "bg-gray-900 text-white" : "bg-white text-gray-900"}`, children: [ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "relative p-6 border-b border-gray-200 dark:border-gray-700", children: [ currentStep !== "select-method" && currentStep !== "success" && currentStep !== "error" && /* @__PURE__ */ jsxRuntimeExports.jsx( "button", { onClick: goBack, className: "absolute left-4 top-6 p-1 rounded-full hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors", children: /* @__PURE__ */ jsxRuntimeExports.jsx(ArrowLeft, { className: "w-5 h-5" }) } ), /* @__PURE__ */ jsxRuntimeExports.jsx( "button", { onClick: handleClose, className: "absolute right-4 top-6 p-1 rounded-full hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors", children: /* @__PURE__ */ jsxRuntimeExports.jsx(X, { className: "w-5 h-5" }) } ), /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-center", children: [ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-center space-x-2 mb-2", children: [ /* @__PURE__ */ jsxRuntimeExports.jsx(Sparkles, { className: "w-5 h-5 text-[#7042D2]" }), /* @__PURE__ */ jsxRuntimeExports.jsx("h2", { className: "text-xl font-bold", children: "Pay with Crypto" }), /* @__PURE__ */ jsxRuntimeExports.jsx(Sparkles, { className: "w-5 h-5 text-[#7042D2]" }) ] }), merchantName && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm text-gray-600 dark:text-gray-400 mt-1", children: merchantName }), /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-2", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-2xl font-bold text-[#7042D2]", children: [ "$", config.amount.toFixed(2) ] }) }) ] }) ] }), /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "p-6 min-h-[400px]", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(AnimatePresence, { mode: "wait", children: [ currentStep === "select-method" && /* @__PURE__ */ jsxRuntimeExports.jsxs( motion.div, { initial: { x: 20, opacity: 0 }, animate: { x: 0, opacity: 1 }, exit: { x: -20, opacity: 0 }, className: "space-y-4", children: [ /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-lg font-semibold text-center mb-6", children: "Choose Payment Method" }), /* @__PURE__ */ jsxRuntimeExports.jsx( motion.button, { whileHover: { scale: 1.02 }, whileTap: { scale: 0.98 }, onClick: () => handleMethodSelect("wallet"), className: "w-full p-4 border-2 border-gray-200 dark:border-gray-700 rounded-xl hover:border-[#7042D2] transition-colors group", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center space-x-4", children: [ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "p-3 bg-[#7042D2] bg-opacity-10 rounded-lg group-hover:bg-opacity-20 transition-colors", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Wallet, { className: "w-6 h-6 text-[#7042D2]" }) }), /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-left", children: [ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "font-semibold", children: "Connect Wallet" }), /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-sm text-gray-600 dark:text-gray-400", children: "MetaMask, WalletConnect & more" }) ] }), /* @__PURE__ */ jsxRuntimeExports.jsx(Zap, { className: "w-5 h-5 text-[#7042D2] ml-auto" }) ] }) } ), /* @__PURE__ */ jsxRuntimeExports.jsx( motion.button, { whileHover: { scale: 1.02 }, whileTap: { scale: 0.98 }, onClick: () => handleMethodSelect("qr"), className: "w-full p-4 border-2 border-gray-200 dark:border-gray-700 rounded-xl hover:border-[#7042D2] transition-colors group", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center space-x-4", children: [ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "p-3 bg-[#7042D2] bg-opacity-10 rounded-lg group-hover:bg-opacity-20 transition-colors", children: /* @__PURE__ */ jsxRuntimeExports.jsx(QrCode, { className: "w-6 h-6 text-[#7042D2]" }) }), /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-left", children: [ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "font-semibold", children: "QR Code" }), /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-sm text-gray-600 dark:text-gray-400", children: "Scan with mobile wallet" }) ] }) ] }) } ) ] }, "select-method" ), currentStep === "select-network" && /* @__PURE__ */ jsxRuntimeExports.jsxs( motion.div, { initial: { x: 20, opacity: 0 }, animate: { x: 0, opacity: 1 }, exit: { x: -20, opacity: 0 }, className: "space-y-4", children: [ /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-lg font-semibold text-center mb-6", children: "Select Network" }), loading ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex justify-center py-8", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Loader2, { className: "w-8 h-8 animate-spin text-[#7042D2]" }) }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-3", children: networks.map((network) => /* @__PURE__ */ jsxRuntimeExports.jsx( motion.button, { whileHover: { scale: 1.02 }, whileTap: { scale: 0.98 }, onClick: () => handleNetworkSelect(network), className: "w-full p-4 border-2 border-gray-200 dark:border-gray-700 rounded-xl hover:border-[#7042D2] transition-colors group", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center space-x-4", children: [ network.logo ? /* @__PURE__ */ jsxRuntimeExports.jsx( "img", { src: network.logo, alt: network.name, className: "w-8 h-8 rounded-full" } ) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-8 h-8 bg-[#7042D2] bg-opacity-20 rounded-full flex items-center justify-center", children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm font-bold text-[#7042D2]", children: network.shortName.charAt(0).toUpperCase() }) }), /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-left flex-1", children: [ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "font-semibold", children: network.name }), /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-sm text-gray-600 dark:text-gray-400", children: network.shortName.toUpperCase() }) ] }), /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronDown, { className: "w-5 h-5 text-gray-400 transform -rotate-90" }) ] }) }, network.id )) }) ] }, "select-network" ), currentStep === "select-token" && /* @__PURE__ */ jsxRuntimeExports.jsxs( motion.div, { initial: { x: 20, opacity: 0 }, animate: { x: 0, opacity: 1 }, exit: { x: -20, opacity: 0 }, className: "space-y-4", children: [ /* @__PURE__ */ jsxRuntimeExports.jsxs("h3", { className: "text-lg font-semibold text-center mb-6", children: [ "Select Token on ", selectedNetwork == null ? void 0 : selectedNetwork.name ] }), loading ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex justify-center py-8", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Loader2, { className: "w-8 h-8 animate-spin text-[#7042D2]" }) }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-3", children: tokens.filter( (token) => { var _a; return ((_a = token.Network) == null ? void 0 : _a.shortName) === (selectedNetwork == null ? void 0 : selectedNetwork.shortName) || token.networkId === (selectedNetwork == null ? void 0 : selectedNetwork.id); } ).map((token) => /* @__PURE__ */ jsxRuntimeExports.jsx( motion.button, { whileHover: { scale: 1.02 }, whileTap: { scale: 0.98 }, onClick: () => handleTokenSelect(token), className: "w-full p-4 border-2 border-gray-200 dark:border-gray-700 rounded-xl hover:border-[#7042D2] transition-colors group", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center space-x-4", children: [ token.logo ? /* @__PURE__ */ jsxRuntimeExports.jsx( "img", { src: token.logo, alt: token.symbol, className: "w-8 h-8 rounded-full" } ) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-8 h-8 bg-[#7042D2] bg-opacity-20 rounded-full flex items-center justify-center", children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm font-bold text-[#7042D2]", children: token.symbol.charAt(0) }) }), /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-left flex-1", children: [ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "font-semibold", children: token.name }), /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-sm text-gray-600 dark:text-gray-400", children: [ token.symbol, token.isStablecoin && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ml-2 px-2 py-0.5 bg-green-100 text-green-600 text-xs rounded-full", children: "Stablecoin" }) ] }) ] }), /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronDown, { className: "w-5 h-5 text-gray-400 transform -rotate-90" }) ] }) }, token.id )) }) ] }, "select-token" ), currentStep === "wallet-connect" && /* @__PURE__ */ jsxRuntimeExports.jsx( motion.div, { initial: { x: 20, opacity: 0 }, animate: { x: 0, opacity: 1 }, exit: { x: -20, opacity: 0 }, children: /* @__PURE__ */ jsxRuntimeExports.jsx( WalletIntegration, { selectedNetwork, selectedToken, paymentData, config, onTransactionSent: handleTransactionSent, onError: setError, isConnecting, setIsConnecting } ) }, "wallet-connect" ), currentStep === "qr-code" && /* @__PURE__ */ jsxRuntimeExports.jsxs( motion.div, { initial: { x: 20, opacity: 0 }, animate: { x: 0, opacity: 1 }, exit: { x: -20, opacity: 0 }, className: "text-center space-y-6", children: [ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-4", children: [ /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-lg font-semibold", children: "Scan QR Code" }), /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-gray-600 dark:text-gray-400", children: "Use your mobile wallet to scan and pay" }) ] }), qrCode && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "bg-white p-4 rounded-xl mx-auto inline-block", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "w-48 h-48 flex items-center justify-center text-gray-500", children: [ "QR Code: ", qrCode.slice(0, 10), "...", qrCode.slice(-4) ] }) }), paymentData && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-3", children: [ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-gray-50 dark:bg-gray-800 rounded-lg p-4 space-y-2", children: [ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center", children: [ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm text-gray-600 dark:text-gray-400", children: "Network:" }), /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-medium", children: selectedNetwork == null ? void 0 : selectedNetwork.name }) ] }), /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center", children: [ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm text-gray-600 dark:text-gray-400", children: "Amount:" }), /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-medium", children: [ paymentData.totalAmount, " ", selectedToken == null ? void 0 : selectedToken.symbol ] }) ] }) ] }), /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-center space-x-2 text-sm text-gray-600 dark:text-gray-400", children: [ /* @__PURE__ */ jsxRuntimeExports.jsx(Loader2, { className: "w-4 h-4 animate-spin" }), /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Waiting for payment..." }) ] }) ] }) ] }, "qr-code" ), currentStep === "processing" && /* @__PURE__ */ jsxRuntimeExports.jsxs( motion.div, { initial: { scale: 0.8, opacity: 0 }, animate: { scale: 1, opacity: 1 }, className: "text-center space-y-6", children: [ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-16 h-16 bg-[#7042D2] bg-opacity-20 rounded-full flex items-center justify-center mx-auto", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Loader2, { className: "w-8 h-8 animate-spin text-[#7042D2]" }) }), /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-lg font-semibold text-[#7042D2]", children: "Processing Payment..." }), /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-gray-600 dark:text-gray-400 mt-2", children: "Your transaction is being processed" }) ] }) ] }, "processing" ), currentStep === "success" && /* @__PURE__ */ jsxRuntimeExports.jsxs( motion.div, { initial: { scale: 0.8, opacity: 0 }, animate: { scale: 1, opacity: 1 }, className: "text-center space-y-6", children: [ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-16 h-16 bg-green-100 rounded-full flex items-center justify-center mx-auto", children: /* @__PURE__ */ jsxRuntimeExports.jsx(CheckCircle2, { className: "w-8 h-8 text-green-500" }) }), /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-lg font-semibold text-green-600", children: "Payment Successful!" }), /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-gray-600 dark:text-gray-400 mt-2", children: "Your payment has been processed successfully" }) ] }), txHash && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "bg-gray-50 dark:bg-gray-800 rounded-lg p-4", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center", children: [ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm text-gray-600 dark:text-gray-400", children: "Transaction:" }), /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center space-x-2", children: [ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono text-sm", children: [ txHash.slice(0, 6), "...", txHash.slice(-4) ] }), /* @__PURE__ */ jsxRuntimeExports.jsx( "button", { onClick: () => copyToClipboard(txHash), className: "p-1 hover:bg-gray-200 dark:hover:bg-gray-700 rounded", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Copy, { className: "w-4 h-4" }) } ), (selectedNetwork == null ? void 0 : selectedNetwork.explorerUrl) && /* @__PURE__ */ jsxRuntimeExports.jsx( "a", { hr