coinley-test 0.0.0 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/dist/index.esm.js +1057 -0
  2. package/dist/index.esm.js.map +1 -0
  3. package/dist/index.umd.js +2 -0
  4. package/dist/index.umd.js.map +1 -0
  5. package/dist/style.css +1 -0
  6. package/package.json +21 -18
  7. package/.github/workflows/azure-static-web-apps-gray-river-06ca63610.yml +0 -48
  8. package/eslint.config.js +0 -38
  9. package/index.html +0 -13
  10. package/postcss.config.js +0 -6
  11. package/src/CoinleyPayment.jsx +0 -787
  12. package/src/CoinleyProvider.jsx +0 -166
  13. package/src/PaymentAPI.js +0 -233
  14. package/src/assets/Henry's Resume (1).pdf +0 -0
  15. package/src/assets/Invoice 0.2.pdf +0 -0
  16. package/src/assets/Logomark.png +0 -0
  17. package/src/assets/about.jpg +0 -0
  18. package/src/assets/airbnb.jpg +0 -0
  19. package/src/assets/calculateload.jpg +0 -0
  20. package/src/assets/coinbase.jpg +0 -0
  21. package/src/assets/coinley-store-dark.svg +0 -22
  22. package/src/assets/coinley-store.svg +0 -22
  23. package/src/assets/hellosign.jpg +0 -0
  24. package/src/assets/hero.jpg +0 -0
  25. package/src/assets/medium.jpg +0 -0
  26. package/src/assets/panel.jpg +0 -0
  27. package/src/assets/react.svg +0 -1
  28. package/src/assets/selectappliances.jpg +0 -0
  29. package/src/assets/upwork.jpg +0 -0
  30. package/src/assets/zapier.jpg +0 -0
  31. package/src/index.css +0 -3
  32. package/src/index.js +0 -70
  33. package/src/main.jsx +0 -20
  34. package/src/styles/animations.css +0 -180
  35. package/src/styles/index.css +0 -94
  36. package/src/url.js +0 -1
  37. package/staticwebapp.config.json +0 -8
  38. package/tailwind.config.js +0 -31
  39. package/vercel.json +0 -8
  40. package/vite.config.js +0 -34
  41. /package/{public → dist}/Logomark.png +0 -0
  42. /package/{public → dist}/vite.svg +0 -0
@@ -0,0 +1,1057 @@
1
+ import React, { useState, useRef, useEffect, createContext, forwardRef, useContext, useImperativeHandle } from "react";
2
+ import { motion, AnimatePresence } from "framer-motion";
3
+ import { ArrowLeft, X, Sparkles, Wallet, Zap, QrCode, Loader2, ChevronDown, CheckCircle2, Copy, ExternalLink, AlertCircle } from "lucide-react";
4
+ import QRCodeLib from "qrcode";
5
+ import { createCoinleyWalletConfig, CoinleyWalletProvider, WalletModal, useWallet, useWalletConnect, useWalletTransaction, useWalletModal, ConnectButton } from "@coinley/wallet-connect-core";
6
+ import axios from "axios";
7
+ var jsxRuntime = { exports: {} };
8
+ var reactJsxRuntime_production_min = {};
9
+ /**
10
+ * @license React
11
+ * react-jsx-runtime.production.min.js
12
+ *
13
+ * Copyright (c) Facebook, Inc. and its affiliates.
14
+ *
15
+ * This source code is licensed under the MIT license found in the
16
+ * LICENSE file in the root directory of this source tree.
17
+ */
18
+ var f = React, k = Symbol.for("react.element"), l = Symbol.for("react.fragment"), m = 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 };
19
+ function q(c, a, g) {
20
+ var b, d = {}, e = null, h = null;
21
+ void 0 !== g && (e = "" + g);
22
+ void 0 !== a.key && (e = "" + a.key);
23
+ void 0 !== a.ref && (h = a.ref);
24
+ for (b in a) m.call(a, b) && !p.hasOwnProperty(b) && (d[b] = a[b]);
25
+ if (c && c.defaultProps) for (b in a = c.defaultProps, a) void 0 === d[b] && (d[b] = a[b]);
26
+ return { $$typeof: k, type: c, key: e, ref: h, props: d, _owner: n.current };
27
+ }
28
+ reactJsxRuntime_production_min.Fragment = l;
29
+ reactJsxRuntime_production_min.jsx = q;
30
+ reactJsxRuntime_production_min.jsxs = q;
31
+ {
32
+ jsxRuntime.exports = reactJsxRuntime_production_min;
33
+ }
34
+ var jsxRuntimeExports = jsxRuntime.exports;
35
+ class PaymentAPI {
36
+ constructor(baseURL, apiKey, apiSecret) {
37
+ this.apiKey = apiKey;
38
+ this.apiSecret = apiSecret;
39
+ this.api = axios.create({
40
+ baseURL: baseURL.endsWith("/") ? baseURL.slice(0, -1) : baseURL,
41
+ timeout: 3e4,
42
+ headers: {
43
+ "Content-Type": "application/json"
44
+ }
45
+ });
46
+ this.api.interceptors.request.use(
47
+ (config) => {
48
+ var _a;
49
+ config.headers["X-API-Key"] = this.apiKey;
50
+ config.headers["X-API-Secret"] = this.apiSecret;
51
+ const token = this.generateMerchantToken();
52
+ if (token) {
53
+ config.headers["Authorization"] = `Bearer ${token}`;
54
+ }
55
+ console.log("API Request:", {
56
+ method: (_a = config.method) == null ? void 0 : _a.toUpperCase(),
57
+ url: config.url,
58
+ data: config.data
59
+ });
60
+ return config;
61
+ },
62
+ (error) => {
63
+ console.error("Request interceptor error:", error);
64
+ return Promise.reject(error);
65
+ }
66
+ );
67
+ this.api.interceptors.response.use(
68
+ (response) => {
69
+ console.log("API Response:", {
70
+ status: response.status,
71
+ url: response.config.url,
72
+ data: response.data
73
+ });
74
+ return response;
75
+ },
76
+ (error) => {
77
+ var _a, _b, _c, _d, _e;
78
+ console.error("API Error:", {
79
+ status: (_a = error.response) == null ? void 0 : _a.status,
80
+ data: (_b = error.response) == null ? void 0 : _b.data,
81
+ message: error.message
82
+ });
83
+ if (((_c = error.response) == null ? void 0 : _c.status) === 401) {
84
+ throw new Error("Authentication failed. Please check your API credentials.");
85
+ } else if (((_d = error.response) == null ? void 0 : _d.status) === 404) {
86
+ throw new Error("API endpoint not found. Please check your API URL.");
87
+ } else if (((_e = error.response) == null ? void 0 : _e.status) >= 500) {
88
+ throw new Error("Server error. Please try again later.");
89
+ }
90
+ throw error;
91
+ }
92
+ );
93
+ }
94
+ generateMerchantToken() {
95
+ try {
96
+ const credentials = `${this.apiKey}:${this.apiSecret}`;
97
+ return btoa(credentials);
98
+ } catch (error) {
99
+ console.error("Failed to generate token:", error);
100
+ return null;
101
+ }
102
+ }
103
+ async createPayment(params) {
104
+ var _a, _b;
105
+ try {
106
+ const response = await this.api.post("/api/payments/create", params);
107
+ return response.data;
108
+ } catch (error) {
109
+ if ((_b = (_a = error.response) == null ? void 0 : _a.data) == null ? void 0 : _b.error) {
110
+ throw new Error(error.response.data.error);
111
+ }
112
+ throw new Error(error.message || "Failed to create payment");
113
+ }
114
+ }
115
+ async getPayment(paymentId) {
116
+ var _a, _b;
117
+ try {
118
+ const response = await this.api.get(`/api/payments/${paymentId}`);
119
+ return response.data;
120
+ } catch (error) {
121
+ if ((_b = (_a = error.response) == null ? void 0 : _a.data) == null ? void 0 : _b.error) {
122
+ throw new Error(error.response.data.error);
123
+ }
124
+ throw new Error(error.message || "Failed to get payment details");
125
+ }
126
+ }
127
+ async getNetworks() {
128
+ try {
129
+ const response = await this.api.get("/api/networks");
130
+ return response.data;
131
+ } catch (error) {
132
+ console.error("Get networks failed:", error);
133
+ return {
134
+ networks: [
135
+ {
136
+ id: "ethereum",
137
+ name: "Ethereum",
138
+ shortName: "ethereum",
139
+ chainId: "1",
140
+ type: "ethereum",
141
+ explorerUrl: "https://etherscan.io",
142
+ isTestnet: false
143
+ },
144
+ {
145
+ id: "bsc",
146
+ name: "Binance Smart Chain",
147
+ shortName: "bsc",
148
+ chainId: "56",
149
+ type: "bsc",
150
+ explorerUrl: "https://bscscan.com",
151
+ isTestnet: false
152
+ },
153
+ {
154
+ id: "polygon",
155
+ name: "Polygon",
156
+ shortName: "polygon",
157
+ chainId: "137",
158
+ type: "ethereum",
159
+ explorerUrl: "https://polygonscan.com",
160
+ isTestnet: false
161
+ }
162
+ ]
163
+ };
164
+ }
165
+ }
166
+ async getStablecoins() {
167
+ try {
168
+ const response = await this.api.get("/api/networks/stablecoins");
169
+ return response.data;
170
+ } catch (error) {
171
+ console.error("Get stablecoins failed:", error);
172
+ return {
173
+ stablecoins: [
174
+ {
175
+ id: "usdt-eth",
176
+ name: "Tether USD",
177
+ symbol: "USDT",
178
+ contractAddress: "0xdAC17F958D2ee523a2206206994597C13D831ec7",
179
+ decimals: 6,
180
+ isStablecoin: true,
181
+ networkId: "ethereum",
182
+ Network: {
183
+ id: "ethereum",
184
+ name: "Ethereum",
185
+ shortName: "ethereum",
186
+ type: "ethereum"
187
+ }
188
+ },
189
+ {
190
+ id: "usdc-eth",
191
+ name: "USD Coin",
192
+ symbol: "USDC",
193
+ contractAddress: "0xA0b86a33E6441d81d0B93bF9EE0f74ca32F7e6f6",
194
+ decimals: 6,
195
+ isStablecoin: true,
196
+ networkId: "ethereum",
197
+ Network: {
198
+ id: "ethereum",
199
+ name: "Ethereum",
200
+ shortName: "ethereum",
201
+ type: "ethereum"
202
+ }
203
+ }
204
+ ]
205
+ };
206
+ }
207
+ }
208
+ async verifyQRPayment(paymentId) {
209
+ var _a, _b;
210
+ try {
211
+ const response = await this.api.post("/api/payments/verify-qr", {
212
+ paymentId
213
+ });
214
+ return response.data;
215
+ } catch (error) {
216
+ if ((_b = (_a = error.response) == null ? void 0 : _a.data) == null ? void 0 : _b.error) {
217
+ throw new Error(error.response.data.error);
218
+ }
219
+ throw new Error(error.message || "Failed to verify payment");
220
+ }
221
+ }
222
+ async processPayment(paymentId, transactionHash, network, senderAddress) {
223
+ var _a, _b;
224
+ try {
225
+ const response = await this.api.post("/api/payments/process", {
226
+ paymentId,
227
+ transactionHash,
228
+ network,
229
+ senderAddress
230
+ });
231
+ return response.data;
232
+ } catch (error) {
233
+ if ((_b = (_a = error.response) == null ? void 0 : _a.data) == null ? void 0 : _b.error) {
234
+ throw new Error(error.response.data.error);
235
+ }
236
+ throw new Error(error.message || "Failed to process payment");
237
+ }
238
+ }
239
+ async healthCheck() {
240
+ try {
241
+ const response = await this.api.get("/api/health");
242
+ return response.status === 200;
243
+ } catch (error) {
244
+ console.error("Health check failed:", error);
245
+ return false;
246
+ }
247
+ }
248
+ }
249
+ const WalletIntegration = ({
250
+ selectedNetwork,
251
+ selectedToken,
252
+ paymentData,
253
+ onTransactionSent,
254
+ onError,
255
+ isConnecting,
256
+ setIsConnecting
257
+ }) => {
258
+ const { isConnected, address } = useWallet();
259
+ useWalletConnect();
260
+ const { sendTransaction } = useWalletTransaction();
261
+ useWalletModal();
262
+ useEffect(() => {
263
+ if (isConnected && paymentData && selectedNetwork && selectedToken) {
264
+ handleSendTransaction();
265
+ }
266
+ }, [isConnected, paymentData]);
267
+ const handleSendTransaction = async () => {
268
+ var _a;
269
+ if (!isConnected || !paymentData || !selectedToken) return;
270
+ try {
271
+ setIsConnecting(true);
272
+ const recipientAddress = (_a = paymentData.metadata) == null ? void 0 : _a.recipientWallet;
273
+ if (!recipientAddress) {
274
+ throw new Error("Recipient wallet address not found");
275
+ }
276
+ let txHash;
277
+ if (selectedToken.contractAddress) {
278
+ const amount = (paymentData.totalAmount * Math.pow(10, selectedToken.decimals)).toString();
279
+ const transferData = `0xa9059cbb${recipientAddress.slice(2).padStart(64, "0")}${parseInt(amount).toString(16).padStart(64, "0")}`;
280
+ txHash = await sendTransaction({
281
+ to: selectedToken.contractAddress,
282
+ data: transferData,
283
+ value: "0x0"
284
+ });
285
+ } else {
286
+ const value = (paymentData.totalAmount * Math.pow(10, 18)).toString(16);
287
+ txHash = await sendTransaction({
288
+ to: recipientAddress,
289
+ value: `0x${value}`
290
+ });
291
+ }
292
+ if (txHash) {
293
+ onTransactionSent(txHash);
294
+ }
295
+ } catch (error) {
296
+ console.error("Transaction failed:", error);
297
+ onError(error.message || "Transaction failed");
298
+ } finally {
299
+ setIsConnecting(false);
300
+ }
301
+ };
302
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-center space-y-6", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-4", children: [
303
+ /* @__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]" }) }),
304
+ /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-lg font-semibold", children: isConnected ? "Send Payment" : "Connect Your Wallet" }),
305
+ !isConnected ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-4", children: [
306
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-gray-600 dark:text-gray-400", children: "Connect your wallet to complete the payment" }),
307
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
308
+ ConnectButton,
309
+ {
310
+ theme: "gradient",
311
+ size: "large",
312
+ customText: "Connect Wallet"
313
+ }
314
+ )
315
+ ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-4", children: [
316
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-green-600 dark:text-green-400", children: [
317
+ "✅ Wallet Connected: ",
318
+ address == null ? void 0 : address.slice(0, 6),
319
+ "...",
320
+ address == null ? void 0 : address.slice(-4)
321
+ ] }),
322
+ paymentData && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-gray-50 dark:bg-gray-800 rounded-lg p-4 space-y-2", children: [
323
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center", children: [
324
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm text-gray-600 dark:text-gray-400", children: "Amount:" }),
325
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-medium", children: [
326
+ paymentData.totalAmount,
327
+ " ",
328
+ selectedToken == null ? void 0 : selectedToken.symbol
329
+ ] })
330
+ ] }),
331
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center", children: [
332
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm text-gray-600 dark:text-gray-400", children: "Network:" }),
333
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-medium", children: selectedNetwork == null ? void 0 : selectedNetwork.name })
334
+ ] })
335
+ ] }),
336
+ isConnecting && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-center space-x-2", children: [
337
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Loader2, { className: "w-5 h-5 animate-spin text-[#7042D2]" }),
338
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Processing transaction..." })
339
+ ] })
340
+ ] })
341
+ ] }) });
342
+ };
343
+ const CoinleyPayment = ({
344
+ apiKey,
345
+ apiSecret,
346
+ apiUrl = "http://localhost:9000",
347
+ onSuccess,
348
+ onError,
349
+ onClose,
350
+ isOpen,
351
+ config,
352
+ theme = "light",
353
+ merchantName,
354
+ debug = false
355
+ }) => {
356
+ const [currentStep, setCurrentStep] = useState("select-method");
357
+ const [networks, setNetworks] = useState([]);
358
+ const [tokens, setTokens] = useState([]);
359
+ const [selectedNetwork, setSelectedNetwork] = useState(null);
360
+ const [selectedToken, setSelectedToken] = useState(null);
361
+ const [paymentMethod, setPaymentMethod] = useState(null);
362
+ const [qrCode, setQrCode] = useState("");
363
+ const [paymentData, setPaymentData] = useState(null);
364
+ const [loading, setLoading] = useState(false);
365
+ const [error, setError] = useState("");
366
+ const [copied, setCopied] = useState(false);
367
+ const [txHash, setTxHash] = useState("");
368
+ const [isConnecting, setIsConnecting] = useState(false);
369
+ const paymentAPI = useRef(new PaymentAPI(apiUrl, apiKey, apiSecret));
370
+ const walletConfig = createCoinleyWalletConfig({
371
+ appName: merchantName || "Coinley Payment",
372
+ appDescription: "Crypto payment processing",
373
+ chains: ["ethereum", "polygon", "bsc", "arbitrum"]
374
+ });
375
+ useEffect(() => {
376
+ if (isOpen) {
377
+ initializePayment();
378
+ }
379
+ }, [isOpen]);
380
+ const initializePayment = async () => {
381
+ try {
382
+ setLoading(true);
383
+ setError("");
384
+ const [networksRes, tokensRes] = await Promise.all([
385
+ paymentAPI.current.getNetworks(),
386
+ paymentAPI.current.getStablecoins()
387
+ ]);
388
+ setNetworks(networksRes.networks || []);
389
+ setTokens(tokensRes.stablecoins || []);
390
+ if (debug) {
391
+ console.log("Initialized networks:", networksRes.networks);
392
+ console.log("Initialized tokens:", tokensRes.stablecoins);
393
+ }
394
+ } catch (err) {
395
+ console.error("Failed to initialize payment:", err);
396
+ setError("Failed to load payment options. Please try again.");
397
+ } finally {
398
+ setLoading(false);
399
+ }
400
+ };
401
+ const handleMethodSelect = (method) => {
402
+ setPaymentMethod(method);
403
+ setCurrentStep("select-network");
404
+ };
405
+ const handleNetworkSelect = async (network) => {
406
+ setSelectedNetwork(network);
407
+ const networkTokens = tokens.filter(
408
+ (token) => {
409
+ var _a;
410
+ return ((_a = token.Network) == null ? void 0 : _a.shortName) === network.shortName || token.networkId === network.id;
411
+ }
412
+ );
413
+ if (networkTokens.length > 0) {
414
+ const preferredToken = networkTokens.find((t) => t.symbol === "USDT") || networkTokens[0];
415
+ setSelectedToken(preferredToken);
416
+ await initiatePayment(network, preferredToken);
417
+ }
418
+ };
419
+ const initiatePayment = async (network, token) => {
420
+ try {
421
+ setLoading(true);
422
+ const paymentPayload = {
423
+ amount: config.amount,
424
+ currency: token.symbol,
425
+ network: network.shortName,
426
+ customerEmail: config.customerEmail,
427
+ callbackUrl: config.callbackUrl,
428
+ metadata: {
429
+ ...config.metadata,
430
+ paymentMethod,
431
+ selectedNetwork: network.shortName,
432
+ selectedToken: token.symbol
433
+ }
434
+ };
435
+ const payment = await paymentAPI.current.createPayment(paymentPayload);
436
+ setPaymentData(payment.payment);
437
+ if (paymentMethod === "wallet") {
438
+ setCurrentStep("wallet-connect");
439
+ } else {
440
+ await generateQRCode(payment.payment);
441
+ setCurrentStep("qr-code");
442
+ }
443
+ } catch (err) {
444
+ console.error("Payment initiation failed:", err);
445
+ setError(err.message || "Failed to create payment");
446
+ setCurrentStep("error");
447
+ } finally {
448
+ setLoading(false);
449
+ }
450
+ };
451
+ const generateQRCode = async (payment) => {
452
+ var _a, _b;
453
+ try {
454
+ const recipientAddress = ((_a = payment.metadata) == null ? void 0 : _a.recipientWallet) || ((_b = config.merchantWalletAddresses) == null ? void 0 : _b[(selectedNetwork == null ? void 0 : selectedNetwork.shortName) || ""]);
455
+ if (!recipientAddress) {
456
+ throw new Error("Recipient wallet address not found");
457
+ }
458
+ let qrData = "";
459
+ if ((selectedNetwork == null ? void 0 : selectedNetwork.type) === "ethereum" || (selectedNetwork == null ? void 0 : selectedNetwork.type) === "bsc") {
460
+ 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`;
461
+ } else if ((selectedNetwork == null ? void 0 : selectedNetwork.type) === "tron") {
462
+ qrData = `tron:${recipientAddress}?amount=${payment.totalAmount}`;
463
+ } else {
464
+ qrData = `${selectedToken == null ? void 0 : selectedToken.symbol}:${recipientAddress}?amount=${payment.totalAmount}`;
465
+ }
466
+ const qrCodeDataURL = await QRCodeLib.toDataURL(qrData, {
467
+ width: 256,
468
+ margin: 2,
469
+ color: {
470
+ dark: theme === "dark" ? "#FFFFFF" : "#000000",
471
+ light: theme === "dark" ? "#000000" : "#FFFFFF"
472
+ }
473
+ });
474
+ setQrCode(qrCodeDataURL);
475
+ startPaymentVerification(payment.id);
476
+ } catch (err) {
477
+ console.error("QR code generation failed:", err);
478
+ setError("Failed to generate QR code");
479
+ setCurrentStep("error");
480
+ }
481
+ };
482
+ const startPaymentVerification = async (paymentId) => {
483
+ const maxAttempts = 60;
484
+ let attempts = 0;
485
+ const checkPayment = async () => {
486
+ var _a;
487
+ try {
488
+ const result = await paymentAPI.current.verifyQRPayment(paymentId);
489
+ if (result.verified && ((_a = result.payment) == null ? void 0 : _a.transactionHash)) {
490
+ setTxHash(result.payment.transactionHash);
491
+ await handlePaymentSuccess(paymentId, result.payment.transactionHash);
492
+ return true;
493
+ }
494
+ attempts++;
495
+ if (attempts < maxAttempts) {
496
+ setTimeout(checkPayment, 5e3);
497
+ } else {
498
+ setError("Payment verification timeout. Please check your transaction.");
499
+ setCurrentStep("error");
500
+ }
501
+ return false;
502
+ } catch (err) {
503
+ console.error("Payment verification error:", err);
504
+ attempts++;
505
+ if (attempts < maxAttempts) {
506
+ setTimeout(checkPayment, 5e3);
507
+ } else {
508
+ setError("Payment verification failed");
509
+ setCurrentStep("error");
510
+ }
511
+ return false;
512
+ }
513
+ };
514
+ setTimeout(checkPayment, 2e3);
515
+ };
516
+ const handleTransactionSent = async (transactionHash) => {
517
+ setTxHash(transactionHash);
518
+ setCurrentStep("processing");
519
+ try {
520
+ await paymentAPI.current.processPayment(
521
+ paymentData.id,
522
+ transactionHash,
523
+ (selectedNetwork == null ? void 0 : selectedNetwork.shortName) || "",
524
+ ""
525
+ );
526
+ await handlePaymentSuccess(paymentData.id, transactionHash);
527
+ } catch (error2) {
528
+ console.error("Payment processing failed:", error2);
529
+ await handlePaymentSuccess(paymentData.id, transactionHash);
530
+ }
531
+ };
532
+ const handlePaymentSuccess = async (paymentId, transactionHash) => {
533
+ setCurrentStep("success");
534
+ if (onSuccess) {
535
+ onSuccess(paymentId, transactionHash, {
536
+ network: selectedNetwork == null ? void 0 : selectedNetwork.name,
537
+ token: selectedToken == null ? void 0 : selectedToken.symbol,
538
+ amount: paymentData == null ? void 0 : paymentData.totalAmount,
539
+ method: paymentMethod
540
+ });
541
+ }
542
+ };
543
+ const copyToClipboard = async (text) => {
544
+ try {
545
+ await navigator.clipboard.writeText(text);
546
+ setCopied(true);
547
+ setTimeout(() => setCopied(false), 2e3);
548
+ } catch (err) {
549
+ console.error("Failed to copy:", err);
550
+ }
551
+ };
552
+ const handleClose = () => {
553
+ setCurrentStep("select-method");
554
+ setPaymentMethod(null);
555
+ setSelectedNetwork(null);
556
+ setSelectedToken(null);
557
+ setQrCode("");
558
+ setPaymentData(null);
559
+ setError("");
560
+ setTxHash("");
561
+ if (onClose) {
562
+ onClose();
563
+ }
564
+ };
565
+ const goBack = () => {
566
+ if (currentStep === "select-network") {
567
+ setCurrentStep("select-method");
568
+ } else if (currentStep === "wallet-connect" || currentStep === "qr-code") {
569
+ setCurrentStep("select-network");
570
+ }
571
+ };
572
+ if (!isOpen) return null;
573
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(CoinleyWalletProvider, { config: walletConfig, walletConfig: { appName: merchantName || "Coinley Payment" }, children: [
574
+ /* @__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(
575
+ motion.div,
576
+ {
577
+ initial: { scale: 0.9, opacity: 0 },
578
+ animate: { scale: 1, opacity: 1 },
579
+ exit: { scale: 0.9, opacity: 0 },
580
+ 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"}`,
581
+ children: [
582
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "relative p-6 border-b border-gray-200 dark:border-gray-700", children: [
583
+ currentStep !== "select-method" && currentStep !== "success" && currentStep !== "error" && /* @__PURE__ */ jsxRuntimeExports.jsx(
584
+ "button",
585
+ {
586
+ onClick: goBack,
587
+ className: "absolute left-4 top-6 p-1 rounded-full hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors",
588
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(ArrowLeft, { className: "w-5 h-5" })
589
+ }
590
+ ),
591
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
592
+ "button",
593
+ {
594
+ onClick: handleClose,
595
+ className: "absolute right-4 top-6 p-1 rounded-full hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors",
596
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(X, { className: "w-5 h-5" })
597
+ }
598
+ ),
599
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-center", children: [
600
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-center space-x-2 mb-2", children: [
601
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Sparkles, { className: "w-5 h-5 text-[#7042D2]" }),
602
+ /* @__PURE__ */ jsxRuntimeExports.jsx("h2", { className: "text-xl font-bold", children: "Pay with Crypto" }),
603
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Sparkles, { className: "w-5 h-5 text-[#7042D2]" })
604
+ ] }),
605
+ merchantName && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm text-gray-600 dark:text-gray-400 mt-1", children: merchantName }),
606
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-2", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-2xl font-bold text-[#7042D2]", children: [
607
+ "$",
608
+ config.amount.toFixed(2)
609
+ ] }) })
610
+ ] })
611
+ ] }),
612
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "p-6 min-h-[400px]", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(AnimatePresence, { mode: "wait", children: [
613
+ currentStep === "select-method" && /* @__PURE__ */ jsxRuntimeExports.jsxs(
614
+ motion.div,
615
+ {
616
+ initial: { x: 20, opacity: 0 },
617
+ animate: { x: 0, opacity: 1 },
618
+ exit: { x: -20, opacity: 0 },
619
+ className: "space-y-4",
620
+ children: [
621
+ /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-lg font-semibold text-center mb-6", children: "Choose Payment Method" }),
622
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
623
+ motion.button,
624
+ {
625
+ whileHover: { scale: 1.02 },
626
+ whileTap: { scale: 0.98 },
627
+ onClick: () => handleMethodSelect("wallet"),
628
+ className: "w-full p-4 border-2 border-gray-200 dark:border-gray-700 rounded-xl hover:border-[#7042D2] transition-colors group",
629
+ children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center space-x-4", children: [
630
+ /* @__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]" }) }),
631
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-left", children: [
632
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "font-semibold", children: "Connect Wallet" }),
633
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-sm text-gray-600 dark:text-gray-400", children: "MetaMask, WalletConnect & more" })
634
+ ] }),
635
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Zap, { className: "w-5 h-5 text-[#7042D2] ml-auto" })
636
+ ] })
637
+ }
638
+ ),
639
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
640
+ motion.button,
641
+ {
642
+ whileHover: { scale: 1.02 },
643
+ whileTap: { scale: 0.98 },
644
+ onClick: () => handleMethodSelect("qr"),
645
+ className: "w-full p-4 border-2 border-gray-200 dark:border-gray-700 rounded-xl hover:border-[#7042D2] transition-colors group",
646
+ children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center space-x-4", children: [
647
+ /* @__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]" }) }),
648
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-left", children: [
649
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "font-semibold", children: "QR Code" }),
650
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-sm text-gray-600 dark:text-gray-400", children: "Scan with mobile wallet" })
651
+ ] })
652
+ ] })
653
+ }
654
+ )
655
+ ]
656
+ },
657
+ "select-method"
658
+ ),
659
+ currentStep === "select-network" && /* @__PURE__ */ jsxRuntimeExports.jsxs(
660
+ motion.div,
661
+ {
662
+ initial: { x: 20, opacity: 0 },
663
+ animate: { x: 0, opacity: 1 },
664
+ exit: { x: -20, opacity: 0 },
665
+ className: "space-y-4",
666
+ children: [
667
+ /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-lg font-semibold text-center mb-6", children: "Select Network" }),
668
+ 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(
669
+ motion.button,
670
+ {
671
+ whileHover: { scale: 1.02 },
672
+ whileTap: { scale: 0.98 },
673
+ onClick: () => handleNetworkSelect(network),
674
+ className: "w-full p-4 border-2 border-gray-200 dark:border-gray-700 rounded-xl hover:border-[#7042D2] transition-colors group",
675
+ children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center space-x-4", children: [
676
+ network.logo ? /* @__PURE__ */ jsxRuntimeExports.jsx(
677
+ "img",
678
+ {
679
+ src: network.logo,
680
+ alt: network.name,
681
+ className: "w-8 h-8 rounded-full"
682
+ }
683
+ ) : /* @__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() }) }),
684
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-left flex-1", children: [
685
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "font-semibold", children: network.name }),
686
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-sm text-gray-600 dark:text-gray-400", children: network.shortName.toUpperCase() })
687
+ ] }),
688
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronDown, { className: "w-5 h-5 text-gray-400 transform -rotate-90" })
689
+ ] })
690
+ },
691
+ network.id
692
+ )) })
693
+ ]
694
+ },
695
+ "select-network"
696
+ ),
697
+ currentStep === "wallet-connect" && /* @__PURE__ */ jsxRuntimeExports.jsx(
698
+ motion.div,
699
+ {
700
+ initial: { x: 20, opacity: 0 },
701
+ animate: { x: 0, opacity: 1 },
702
+ exit: { x: -20, opacity: 0 },
703
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(
704
+ WalletIntegration,
705
+ {
706
+ selectedNetwork,
707
+ selectedToken,
708
+ paymentData,
709
+ onTransactionSent: handleTransactionSent,
710
+ onError: setError,
711
+ isConnecting,
712
+ setIsConnecting
713
+ }
714
+ )
715
+ },
716
+ "wallet-connect"
717
+ ),
718
+ currentStep === "qr-code" && /* @__PURE__ */ jsxRuntimeExports.jsxs(
719
+ motion.div,
720
+ {
721
+ initial: { x: 20, opacity: 0 },
722
+ animate: { x: 0, opacity: 1 },
723
+ exit: { x: -20, opacity: 0 },
724
+ className: "text-center space-y-6",
725
+ children: [
726
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-4", children: [
727
+ /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-lg font-semibold", children: "Scan QR Code" }),
728
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-gray-600 dark:text-gray-400", children: "Use your mobile wallet to scan and pay" })
729
+ ] }),
730
+ qrCode && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "bg-white p-4 rounded-xl mx-auto inline-block", children: /* @__PURE__ */ jsxRuntimeExports.jsx("img", { src: qrCode, alt: "Payment QR Code", className: "w-48 h-48" }) }),
731
+ paymentData && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-3", children: [
732
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-gray-50 dark:bg-gray-800 rounded-lg p-4 space-y-2", children: [
733
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center", children: [
734
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm text-gray-600 dark:text-gray-400", children: "Network:" }),
735
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-medium", children: selectedNetwork == null ? void 0 : selectedNetwork.name })
736
+ ] }),
737
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center", children: [
738
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm text-gray-600 dark:text-gray-400", children: "Amount:" }),
739
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-medium", children: [
740
+ paymentData.totalAmount,
741
+ " ",
742
+ selectedToken == null ? void 0 : selectedToken.symbol
743
+ ] })
744
+ ] })
745
+ ] }),
746
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-center space-x-2 text-sm text-gray-600 dark:text-gray-400", children: [
747
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Loader2, { className: "w-4 h-4 animate-spin" }),
748
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Waiting for payment..." })
749
+ ] })
750
+ ] })
751
+ ]
752
+ },
753
+ "qr-code"
754
+ ),
755
+ currentStep === "processing" && /* @__PURE__ */ jsxRuntimeExports.jsxs(
756
+ motion.div,
757
+ {
758
+ initial: { scale: 0.8, opacity: 0 },
759
+ animate: { scale: 1, opacity: 1 },
760
+ className: "text-center space-y-6",
761
+ children: [
762
+ /* @__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]" }) }),
763
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
764
+ /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-lg font-semibold text-[#7042D2]", children: "Processing Payment..." }),
765
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-gray-600 dark:text-gray-400 mt-2", children: "Your transaction is being processed" })
766
+ ] })
767
+ ]
768
+ },
769
+ "processing"
770
+ ),
771
+ currentStep === "success" && /* @__PURE__ */ jsxRuntimeExports.jsxs(
772
+ motion.div,
773
+ {
774
+ initial: { scale: 0.8, opacity: 0 },
775
+ animate: { scale: 1, opacity: 1 },
776
+ className: "text-center space-y-6",
777
+ children: [
778
+ /* @__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" }) }),
779
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
780
+ /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-lg font-semibold text-green-600", children: "Payment Successful!" }),
781
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-gray-600 dark:text-gray-400 mt-2", children: "Your payment has been processed successfully" })
782
+ ] }),
783
+ 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: [
784
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm text-gray-600 dark:text-gray-400", children: "Transaction:" }),
785
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center space-x-2", children: [
786
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono text-sm", children: [
787
+ txHash.slice(0, 6),
788
+ "...",
789
+ txHash.slice(-4)
790
+ ] }),
791
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
792
+ "button",
793
+ {
794
+ onClick: () => copyToClipboard(txHash),
795
+ className: "p-1 hover:bg-gray-200 dark:hover:bg-gray-700 rounded",
796
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(Copy, { className: "w-4 h-4" })
797
+ }
798
+ ),
799
+ (selectedNetwork == null ? void 0 : selectedNetwork.explorerUrl) && /* @__PURE__ */ jsxRuntimeExports.jsx(
800
+ "a",
801
+ {
802
+ href: `${selectedNetwork.explorerUrl}/tx/${txHash}`,
803
+ target: "_blank",
804
+ rel: "noopener noreferrer",
805
+ className: "p-1 hover:bg-gray-200 dark:hover:bg-gray-700 rounded",
806
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(ExternalLink, { className: "w-4 h-4" })
807
+ }
808
+ )
809
+ ] })
810
+ ] }) }),
811
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
812
+ "button",
813
+ {
814
+ onClick: handleClose,
815
+ className: "w-full bg-[#7042D2] text-white py-3 rounded-lg font-semibold hover:bg-[#7042D2]/90 transition-colors",
816
+ children: "Close"
817
+ }
818
+ )
819
+ ]
820
+ },
821
+ "success"
822
+ ),
823
+ currentStep === "error" && /* @__PURE__ */ jsxRuntimeExports.jsxs(
824
+ motion.div,
825
+ {
826
+ initial: { scale: 0.8, opacity: 0 },
827
+ animate: { scale: 1, opacity: 1 },
828
+ className: "text-center space-y-6",
829
+ children: [
830
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-16 h-16 bg-red-100 rounded-full flex items-center justify-center mx-auto", children: /* @__PURE__ */ jsxRuntimeExports.jsx(AlertCircle, { className: "w-8 h-8 text-red-500" }) }),
831
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
832
+ /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-lg font-semibold text-red-600", children: "Payment Failed" }),
833
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-gray-600 dark:text-gray-400 mt-2", children: error || "Something went wrong. Please try again." })
834
+ ] }),
835
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-3", children: [
836
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
837
+ "button",
838
+ {
839
+ onClick: () => {
840
+ setCurrentStep("select-method");
841
+ setError("");
842
+ },
843
+ className: "w-full bg-[#7042D2] text-white py-3 rounded-lg font-semibold hover:bg-[#7042D2]/90 transition-colors",
844
+ children: "Try Again"
845
+ }
846
+ ),
847
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
848
+ "button",
849
+ {
850
+ onClick: handleClose,
851
+ className: "w-full border border-gray-300 dark:border-gray-600 py-3 rounded-lg font-semibold hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors",
852
+ children: "Close"
853
+ }
854
+ )
855
+ ] })
856
+ ]
857
+ },
858
+ "error"
859
+ )
860
+ ] }) }),
861
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-6 py-4 border-t border-gray-200 dark:border-gray-700 text-center", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-xs text-gray-500", children: [
862
+ "Powered by ",
863
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-semibold text-[#7042D2]", children: "Coinley" })
864
+ ] }) })
865
+ ]
866
+ }
867
+ ) }),
868
+ /* @__PURE__ */ jsxRuntimeExports.jsx(WalletModal, {})
869
+ ] });
870
+ };
871
+ const CoinleyContext = createContext(null);
872
+ const CoinleyProvider = ({
873
+ apiKey,
874
+ apiSecret,
875
+ apiUrl,
876
+ theme = "light",
877
+ debug = false,
878
+ children
879
+ }) => {
880
+ const [isOpen, setIsOpen] = React.useState(false);
881
+ const [paymentConfig, setPaymentConfig] = React.useState(null);
882
+ const [callbacks, setCallbacks] = React.useState({});
883
+ const [merchantName, setMerchantName] = React.useState("");
884
+ const openPayment = (config, checkoutCallbacks) => {
885
+ setPaymentConfig(config);
886
+ if (checkoutCallbacks) {
887
+ setCallbacks(checkoutCallbacks);
888
+ }
889
+ setIsOpen(true);
890
+ };
891
+ const closePayment = () => {
892
+ setIsOpen(false);
893
+ setPaymentConfig(null);
894
+ if (callbacks.onClose) {
895
+ callbacks.onClose();
896
+ }
897
+ };
898
+ const contextValue = {
899
+ openPayment,
900
+ closePayment
901
+ };
902
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(CoinleyContext.Provider, { value: contextValue, children: [
903
+ children,
904
+ isOpen && paymentConfig && /* @__PURE__ */ jsxRuntimeExports.jsx(
905
+ CoinleyPayment,
906
+ {
907
+ apiKey,
908
+ apiSecret,
909
+ apiUrl,
910
+ isOpen,
911
+ config: paymentConfig,
912
+ theme,
913
+ debug,
914
+ merchantName,
915
+ onSuccess: callbacks.onSuccess,
916
+ onError: callbacks.onError,
917
+ onClose: closePayment
918
+ }
919
+ )
920
+ ] });
921
+ };
922
+ const CoinleyCheckout = forwardRef(({
923
+ customerEmail = "",
924
+ merchantName = "",
925
+ onSuccess,
926
+ onError,
927
+ onClose,
928
+ theme = "light",
929
+ autoOpen = false,
930
+ testMode = false,
931
+ debug = false,
932
+ merchantWalletAddresses = {}
933
+ }, ref) => {
934
+ const context = useContext(CoinleyContext);
935
+ if (!context) {
936
+ throw new Error("CoinleyCheckout must be used within a CoinleyProvider");
937
+ }
938
+ const { openPayment, closePayment } = context;
939
+ const open = (config) => {
940
+ try {
941
+ if (debug) {
942
+ console.log("Opening Coinley checkout with config:", config);
943
+ }
944
+ if (!config.amount || config.amount <= 0) {
945
+ throw new Error("Amount must be greater than 0");
946
+ }
947
+ const finalConfig = {
948
+ ...config,
949
+ customerEmail: config.customerEmail || customerEmail,
950
+ merchantWalletAddresses: {
951
+ ...merchantWalletAddresses,
952
+ ...config.merchantWalletAddresses
953
+ },
954
+ metadata: {
955
+ ...config.metadata,
956
+ testMode,
957
+ checkoutVersion: "1.0.0"
958
+ }
959
+ };
960
+ const checkoutCallbacks = {
961
+ onSuccess,
962
+ onError,
963
+ onClose
964
+ };
965
+ openPayment(finalConfig, checkoutCallbacks);
966
+ } catch (error) {
967
+ console.error("Failed to open Coinley checkout:", error);
968
+ if (onError) {
969
+ onError(error);
970
+ }
971
+ }
972
+ };
973
+ const close = () => {
974
+ closePayment();
975
+ };
976
+ useImperativeHandle(ref, () => ({
977
+ open,
978
+ close
979
+ }));
980
+ return null;
981
+ });
982
+ CoinleyCheckout.displayName = "CoinleyCheckout";
983
+ const useCoinley = () => {
984
+ const context = useContext(CoinleyContext);
985
+ if (!context) {
986
+ throw new Error("useCoinley must be used within a CoinleyProvider");
987
+ }
988
+ return context;
989
+ };
990
+ const ThemeProvider = ({
991
+ initialTheme = "light",
992
+ children
993
+ }) => {
994
+ const [theme, setTheme] = React.useState(initialTheme);
995
+ React.useEffect(() => {
996
+ document.documentElement.setAttribute("data-coinley-theme", theme);
997
+ }, [theme]);
998
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: `coinley-theme-${theme}`, children });
999
+ };
1000
+ const VERSION = "0.0.0";
1001
+ const utils = {
1002
+ formatAmount: (amount, decimals = 2) => amount.toFixed(decimals),
1003
+ truncateAddress: (address, startChars = 6, endChars = 4) => {
1004
+ if (!address) return "";
1005
+ if (address.length <= startChars + endChars) return address;
1006
+ return `${address.slice(0, startChars)}...${address.slice(-endChars)}`;
1007
+ },
1008
+ isValidAddress: (address, network) => {
1009
+ if (!address) return false;
1010
+ switch (network.toLowerCase()) {
1011
+ case "ethereum":
1012
+ case "bsc":
1013
+ case "polygon":
1014
+ return /^0x[a-fA-F0-9]{40}$/.test(address);
1015
+ case "tron":
1016
+ return /^T[a-zA-Z0-9]{33}$/.test(address);
1017
+ case "solana":
1018
+ return /^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(address);
1019
+ default:
1020
+ return address.length > 0;
1021
+ }
1022
+ },
1023
+ copyToClipboard: async (text) => {
1024
+ try {
1025
+ await navigator.clipboard.writeText(text);
1026
+ return true;
1027
+ } catch {
1028
+ return false;
1029
+ }
1030
+ }
1031
+ };
1032
+ class CoinleyError extends Error {
1033
+ constructor(message, code) {
1034
+ super(message);
1035
+ this.name = "CoinleyError";
1036
+ this.code = code;
1037
+ }
1038
+ }
1039
+ const DEFAULT_CONFIG = {
1040
+ theme: "light",
1041
+ debug: false,
1042
+ testMode: false,
1043
+ autoOpen: false
1044
+ };
1045
+ export {
1046
+ CoinleyCheckout,
1047
+ CoinleyError,
1048
+ CoinleyPayment,
1049
+ CoinleyProvider,
1050
+ DEFAULT_CONFIG,
1051
+ PaymentAPI,
1052
+ ThemeProvider,
1053
+ VERSION,
1054
+ useCoinley,
1055
+ utils
1056
+ };
1057
+ //# sourceMappingURL=index.esm.js.map