@cicero-zcash/react 0.1.0 → 0.2.0

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.
package/dist/index.mjs CHANGED
@@ -235,15 +235,99 @@ var ZucchiniWalletAdapter = class _ZucchiniWalletAdapter {
235
235
  }
236
236
  }
237
237
  this._lastAccounts = connection?.accounts || [];
238
- const balance = await this.getBalance({ address });
238
+ const network = await this.getNetwork();
239
+ const balance = await this.getBalance({ address, network });
239
240
  this._connected = true;
240
241
  this._address = address || null;
241
242
  return {
242
243
  address,
243
244
  connected: true,
245
+ network,
244
246
  balance: balance ?? void 0
245
247
  };
246
248
  }
249
+ /**
250
+ * Queries the active network of the Zucchini Wallet ('mainnet' | 'testnet').
251
+ */
252
+ async getNetwork() {
253
+ try {
254
+ const client = await this.getClient();
255
+ if (typeof client.network === "function") {
256
+ const net = await client.network();
257
+ if (net === "mainnet" || net === "testnet") {
258
+ return net;
259
+ }
260
+ }
261
+ } catch {
262
+ }
263
+ const raw = this.provider || (typeof window !== "undefined" ? window.zucchini || window.zcash : null);
264
+ if (raw && typeof raw.request === "function") {
265
+ try {
266
+ const res = await raw.request({ method: "getNetwork" });
267
+ if (res?.network === "main" || res === "main" || res === "mainnet") return "mainnet";
268
+ if (res?.network === "test" || res === "test" || res === "testnet") return "testnet";
269
+ } catch {
270
+ }
271
+ }
272
+ if (this._address) {
273
+ if (this._address.startsWith("utest1") || this._address.startsWith("ztestsapling") || this._address.startsWith("tm")) {
274
+ return "testnet";
275
+ }
276
+ if (this._address.startsWith("u1") || this._address.startsWith("zs1") || this._address.startsWith("t1")) {
277
+ return "mainnet";
278
+ }
279
+ }
280
+ return "mainnet";
281
+ }
282
+ /**
283
+ * Requests a network change. If the extension does not support programmatic
284
+ * switching, informs the application that manual user toggle is needed.
285
+ */
286
+ async switchNetwork(targetNetwork) {
287
+ const current = await this.getNetwork();
288
+ if (current === targetNetwork) {
289
+ return { success: true, currentNetwork: current };
290
+ }
291
+ const raw = this.provider || (typeof window !== "undefined" ? window.zucchini || window.zcash : null);
292
+ if (raw && typeof raw.request === "function") {
293
+ try {
294
+ await raw.request({
295
+ method: "switchNetwork",
296
+ params: { network: targetNetwork === "mainnet" ? "main" : "test" }
297
+ });
298
+ const updated = await this.getNetwork();
299
+ return { success: updated === targetNetwork, currentNetwork: updated };
300
+ } catch {
301
+ }
302
+ }
303
+ return {
304
+ success: false,
305
+ requiresManualSwitch: true,
306
+ currentNetwork: current
307
+ };
308
+ }
309
+ /**
310
+ * Subscribes to network change events from the wallet extension.
311
+ */
312
+ onNetworkChanged(listener) {
313
+ const raw = this.provider || (typeof window !== "undefined" ? window.zucchini || window.zcash : null);
314
+ const handler = async () => {
315
+ const net = await this.getNetwork();
316
+ listener(net);
317
+ };
318
+ if (raw?.on) {
319
+ raw.on("networkChanged", handler);
320
+ raw.on("chainChanged", handler);
321
+ raw.on("accountsChanged", handler);
322
+ return () => {
323
+ raw.off?.("networkChanged", handler);
324
+ raw.off?.("chainChanged", handler);
325
+ raw.off?.("accountsChanged", handler);
326
+ };
327
+ }
328
+ return () => {
329
+ };
330
+ }
247
331
  /**
248
332
  * Helper to normalize raw balance formats (e.g. number, string, zatoshis, or pool totals).
249
333
  */
@@ -411,7 +495,7 @@ var zucchiniWallet = {
411
495
  return {
412
496
  address: session.address,
413
497
  connected: true,
414
- network: options?.network || "mainnet",
498
+ network: session.network || options?.network || "mainnet",
415
499
  walletId: "zucchini",
416
500
  balance: session.balance
417
501
  };
@@ -422,6 +506,12 @@ var zucchiniWallet = {
422
506
  getBalance: async (options) => {
423
507
  return adapter.getBalance(options);
424
508
  },
509
+ getNetwork: async () => {
510
+ return adapter.getNetwork();
511
+ },
512
+ switchNetwork: async (network) => {
513
+ return adapter.switchNetwork(network);
514
+ },
425
515
  sendPayment: async (params) => {
426
516
  const res = await adapter.requestPayment({
427
517
  recipient: params.recipient,
@@ -1038,9 +1128,27 @@ var CiceroAccountModal = ({
1038
1128
  const [copied, setCopied] = useState3(false);
1039
1129
  const [showQr, setShowQr] = useState3(false);
1040
1130
  const [mounted, setMounted] = useState3(false);
1131
+ const [manualNotice, setManualNotice] = useState3(null);
1041
1132
  useEffect3(() => {
1042
1133
  setMounted(true);
1043
1134
  }, []);
1135
+ useEffect3(() => {
1136
+ setManualNotice(null);
1137
+ }, [network, isOpen]);
1138
+ const handleNetworkChange = async (targetNet) => {
1139
+ if (targetNet === network) {
1140
+ setManualNotice(null);
1141
+ return;
1142
+ }
1143
+ const res = await switchNetwork(targetNet);
1144
+ if (res?.requiresManualSwitch) {
1145
+ setManualNotice(
1146
+ `Wallet is currently active on ${network === "mainnet" ? "Mainnet" : "Testnet"}. Switch network inside your extension settings (Settings \u2192 Network) and Cicero will automatically update your balance.`
1147
+ );
1148
+ } else {
1149
+ setManualNotice(null);
1150
+ }
1151
+ };
1044
1152
  useEffect3(() => {
1045
1153
  const handleKeyDown = (e) => {
1046
1154
  if (e.key === "Escape" && isOpen) {
@@ -1167,29 +1275,34 @@ var CiceroAccountModal = ({
1167
1275
  )
1168
1276
  ] })
1169
1277
  ] }),
1170
- /* @__PURE__ */ jsxs2("div", { className: "flex items-center justify-between p-3 rounded-lg border border-[#ededed] bg-white text-xs", children: [
1171
- /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2", children: [
1172
- /* @__PURE__ */ jsx3(ArrowRightLeft, { className: "w-4 h-4 text-[#707070]" }),
1173
- /* @__PURE__ */ jsx3("span", { className: "text-[#171717] font-medium", children: "Network" })
1278
+ /* @__PURE__ */ jsxs2("div", { className: "space-y-2", children: [
1279
+ /* @__PURE__ */ jsxs2("div", { className: "flex items-center justify-between p-3 rounded-lg border border-[#ededed] bg-white text-xs", children: [
1280
+ /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2", children: [
1281
+ /* @__PURE__ */ jsx3(ArrowRightLeft, { className: "w-4 h-4 text-[#707070]" }),
1282
+ /* @__PURE__ */ jsx3("span", { className: "text-[#171717] font-medium", children: "Active Network" })
1283
+ ] }),
1284
+ /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-1 p-0.5 rounded bg-[#fafafa] border border-[#dfdfdf]", children: [
1285
+ /* @__PURE__ */ jsx3(
1286
+ "button",
1287
+ {
1288
+ type: "button",
1289
+ onClick: () => handleNetworkChange("mainnet"),
1290
+ className: `px-2 py-1 rounded text-[11px] font-medium transition-colors ${network === "mainnet" ? "bg-white shadow-sm text-[#24b47e] font-semibold" : "text-[#707070] hover:text-[#171717]"}`,
1291
+ children: "Mainnet"
1292
+ }
1293
+ ),
1294
+ /* @__PURE__ */ jsx3(
1295
+ "button",
1296
+ {
1297
+ type: "button",
1298
+ onClick: () => handleNetworkChange("testnet"),
1299
+ className: `px-2 py-1 rounded text-[11px] font-medium transition-colors ${network === "testnet" ? "bg-white shadow-sm text-amber-700 font-semibold" : "text-[#707070] hover:text-[#171717]"}`,
1300
+ children: "Testnet"
1301
+ }
1302
+ )
1303
+ ] })
1174
1304
  ] }),
1175
- /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-1 p-0.5 rounded bg-[#fafafa] border border-[#dfdfdf]", children: [
1176
- /* @__PURE__ */ jsx3(
1177
- "button",
1178
- {
1179
- onClick: () => switchNetwork("mainnet"),
1180
- className: `px-2 py-1 rounded text-[11px] font-medium transition-colors ${network === "mainnet" ? "bg-white shadow-sm text-[#24b47e] font-semibold" : "text-[#707070]"}`,
1181
- children: "Mainnet"
1182
- }
1183
- ),
1184
- /* @__PURE__ */ jsx3(
1185
- "button",
1186
- {
1187
- onClick: () => switchNetwork("testnet"),
1188
- className: `px-2 py-1 rounded text-[11px] font-medium transition-colors ${network === "testnet" ? "bg-white shadow-sm text-amber-700 font-semibold" : "text-[#707070]"}`,
1189
- children: "Testnet"
1190
- }
1191
- )
1192
- ] })
1305
+ manualNotice && /* @__PURE__ */ jsx3("div", { className: "p-2.5 rounded-md bg-amber-50 border border-amber-200 text-amber-800 text-[11px] leading-relaxed animate-in fade-in", children: /* @__PURE__ */ jsx3("span", { children: manualNotice }) })
1193
1306
  ] })
1194
1307
  ] }),
1195
1308
  /* @__PURE__ */ jsxs2("div", { className: "px-6 py-3.5 bg-[#fafafa] border-t border-[#ededed] flex items-center justify-between", children: [
@@ -1324,6 +1437,36 @@ var CiceroProvider = ({
1324
1437
  cleanupReady();
1325
1438
  };
1326
1439
  }, [autoConnect]);
1440
+ useEffect4(() => {
1441
+ if (typeof window === "undefined") return;
1442
+ const adapter2 = new ZucchiniWalletAdapter();
1443
+ const cleanup = adapter2.onNetworkChanged(async (detectedNet) => {
1444
+ setNetwork(detectedNet);
1445
+ localStorage.setItem("cicero_network", detectedNet);
1446
+ if (account.wallet?.id === "zucchini") {
1447
+ setBalance((prev) => ({ ...prev, isLoading: true }));
1448
+ try {
1449
+ const freshBal = await adapter2.getBalance({
1450
+ address: account.address || void 0,
1451
+ network: detectedNet
1452
+ });
1453
+ const activeZec = freshBal !== null && !isNaN(freshBal) ? freshBal : 0;
1454
+ setBalance({
1455
+ zec: activeZec,
1456
+ usd: convertZecToUsdRef.current(activeZec),
1457
+ isLoading: false
1458
+ });
1459
+ localStorage.setItem("cicero_balance", activeZec.toString());
1460
+ localStorage.setItem(`cicero_balance_${detectedNet}`, activeZec.toString());
1461
+ } catch {
1462
+ setBalance((prev) => ({ ...prev, isLoading: false }));
1463
+ }
1464
+ }
1465
+ });
1466
+ return () => {
1467
+ cleanup();
1468
+ };
1469
+ }, [account.wallet?.id, account.address]);
1327
1470
  useEffect4(() => {
1328
1471
  if (account.isConnected) {
1329
1472
  setBalance((prev) => {
@@ -1336,12 +1479,55 @@ var CiceroProvider = ({
1336
1479
  });
1337
1480
  }
1338
1481
  }, [account.isConnected, balance.zec, convertZecToUsd]);
1339
- const switchNetwork = useCallback2((newNet) => {
1340
- setNetwork(newNet);
1341
- if (typeof window !== "undefined") {
1342
- localStorage.setItem("cicero_network", newNet);
1343
- }
1344
- }, []);
1482
+ const switchNetwork = useCallback2(
1483
+ async (newNet) => {
1484
+ if (account.wallet?.switchNetwork) {
1485
+ try {
1486
+ const switchRes = await account.wallet.switchNetwork(newNet);
1487
+ if (switchRes && switchRes.requiresManualSwitch) {
1488
+ const currentNet = switchRes.currentNetwork || (account.wallet.getNetwork ? await account.wallet.getNetwork() : network);
1489
+ setNetwork(currentNet);
1490
+ if (typeof window !== "undefined") {
1491
+ localStorage.setItem("cicero_network", currentNet);
1492
+ }
1493
+ return {
1494
+ success: false,
1495
+ requiresManualSwitch: true,
1496
+ currentNetwork: currentNet
1497
+ };
1498
+ }
1499
+ } catch {
1500
+ }
1501
+ }
1502
+ setNetwork(newNet);
1503
+ if (typeof window !== "undefined") {
1504
+ localStorage.setItem("cicero_network", newNet);
1505
+ }
1506
+ if (account.wallet?.getBalance) {
1507
+ setBalance((prev) => ({ ...prev, isLoading: true }));
1508
+ try {
1509
+ const freshBal = await account.wallet.getBalance({
1510
+ address: account.address || void 0,
1511
+ network: newNet
1512
+ });
1513
+ const activeZec = freshBal !== null && !isNaN(freshBal) ? freshBal : 0;
1514
+ setBalance({
1515
+ zec: activeZec,
1516
+ usd: convertZecToUsdRef.current(activeZec),
1517
+ isLoading: false
1518
+ });
1519
+ if (typeof window !== "undefined" && freshBal !== null) {
1520
+ localStorage.setItem(`cicero_balance_${newNet}`, freshBal.toString());
1521
+ localStorage.setItem("cicero_balance", freshBal.toString());
1522
+ }
1523
+ } catch {
1524
+ setBalance((prev) => ({ ...prev, isLoading: false }));
1525
+ }
1526
+ }
1527
+ return { success: true, currentNetwork: newNet };
1528
+ },
1529
+ [account.wallet, account.address, network]
1530
+ );
1345
1531
  const connect = useCallback2(
1346
1532
  async (walletId, customAddressOrKey) => {
1347
1533
  const targetWallet = wallets.find((w) => w.id === walletId);
@@ -1368,6 +1554,13 @@ var CiceroProvider = ({
1368
1554
  session = await targetWallet.connect({ network });
1369
1555
  }
1370
1556
  const resolvedAddress = session.address || customAddressOrKey || null;
1557
+ const walletNetwork = session.network || (targetWallet.getNetwork ? await targetWallet.getNetwork() : network);
1558
+ if (walletNetwork && walletNetwork !== network) {
1559
+ setNetwork(walletNetwork);
1560
+ if (typeof window !== "undefined") {
1561
+ localStorage.setItem("cicero_network", walletNetwork);
1562
+ }
1563
+ }
1371
1564
  setAccount({
1372
1565
  address: resolvedAddress,
1373
1566
  viewingKey: session.viewingKey || null,
@@ -1660,834 +1853,24 @@ var CiceroConnectButton = ({
1660
1853
  ) });
1661
1854
  };
1662
1855
 
1663
- // src/components/CiceroPayButton.tsx
1664
- import { Shield as Shield5 } from "lucide-react";
1665
-
1666
- // src/hooks/useCiceroPayment.ts
1667
- import { useState as useState5, useEffect as useEffect5, useCallback as useCallback3, useMemo as useMemo2, useRef as useRef2 } from "react";
1668
- function useCiceroPayment({
1669
- recipient,
1670
- amount,
1671
- memo,
1672
- message,
1673
- network = "mainnet",
1674
- expiresInSeconds = 900,
1675
- // 15 mins
1676
- invoiceId,
1677
- customRpcUrl,
1678
- onSuccess,
1679
- onError,
1680
- onStatusChange
1681
- }) {
1682
- const onSuccessRef = useRef2(onSuccess);
1683
- onSuccessRef.current = onSuccess;
1684
- const onErrorRef = useRef2(onError);
1685
- onErrorRef.current = onError;
1686
- const onStatusChangeRef = useRef2(onStatusChange);
1687
- onStatusChangeRef.current = onStatusChange;
1688
- const [status, setStatus] = useState5("pending");
1689
- const [txId, setTxId] = useState5(null);
1690
- const [secondsRemaining, setSecondsRemaining] = useState5(expiresInSeconds);
1691
- const [isModalOpen, setIsModalOpen] = useState5(false);
1692
- const [zucchiniAvailable, setZucchiniAvailable] = useState5(false);
1693
- const [zucchiniAdapter] = useState5(() => new ZucchiniWalletAdapter());
1694
- const [zucchiniPaying, setZucchiniPaying] = useState5(false);
1695
- useEffect5(() => {
1696
- setZucchiniAvailable(ZucchiniWalletAdapter.isAvailable());
1697
- }, []);
1698
- const addressType = useMemo2(() => getAddressType(recipient), [recipient]);
1699
- const isShielded = useMemo2(() => isShieldedAddress(recipient), [recipient]);
1700
- const memoValidation = useMemo2(
1701
- () => validateMemoSupport(recipient, memo),
1702
- [recipient, memo]
1703
- );
1704
- const lastWarningRef = useRef2(null);
1705
- useEffect5(() => {
1706
- if (!memoValidation.valid && memoValidation.warning) {
1707
- if (lastWarningRef.current !== memoValidation.warning) {
1708
- lastWarningRef.current = memoValidation.warning;
1709
- onErrorRef.current?.(new Error(memoValidation.warning));
1710
- }
1711
- } else {
1712
- lastWarningRef.current = null;
1713
- }
1714
- }, [memoValidation.valid, memoValidation.warning]);
1715
- const zip321Uri = useMemo2(() => {
1716
- return generateZip321Uri({
1717
- address: recipient,
1718
- amount,
1719
- memo,
1720
- message
1721
- });
1722
- }, [recipient, amount, memo, message]);
1723
- const deepLinks = useMemo2(() => getWalletDeepLinks(zip321Uri), [zip321Uri]);
1724
- const updateStatus = useCallback3((newStatus) => {
1725
- setStatus(newStatus);
1726
- onStatusChangeRef.current?.(newStatus);
1727
- }, []);
1728
- useEffect5(() => {
1729
- if (status !== "pending") return;
1730
- const timer = setInterval(() => {
1731
- setSecondsRemaining((prev) => {
1732
- if (prev <= 1) {
1733
- clearInterval(timer);
1734
- updateStatus("expired");
1735
- return 0;
1736
- }
1737
- return prev - 1;
1738
- });
1739
- }, 1e3);
1740
- return () => clearInterval(timer);
1741
- }, [status, updateStatus]);
1742
- const resetPayment = useCallback3(() => {
1743
- setStatus("pending");
1744
- setTxId(null);
1745
- setSecondsRemaining(expiresInSeconds);
1746
- setZucchiniPaying(false);
1747
- }, [expiresInSeconds]);
1748
- const openModal = useCallback3(() => {
1749
- resetPayment();
1750
- setIsModalOpen(true);
1751
- }, [resetPayment]);
1752
- const closeModal = useCallback3(() => {
1753
- setIsModalOpen(false);
1754
- }, []);
1755
- const payWithZucchini = useCallback3(async () => {
1756
- setZucchiniPaying(true);
1757
- try {
1758
- await zucchiniAdapter.connect();
1759
- const numAmount = typeof amount === "number" ? amount : parseFloat(amount);
1760
- const result = await zucchiniAdapter.requestPayment({
1761
- recipient,
1762
- amount: numAmount,
1763
- memo
1764
- });
1765
- updateStatus("detected");
1766
- setTxId(result.txId);
1767
- setTimeout(() => {
1768
- updateStatus("confirmed");
1769
- onSuccessRef.current?.({
1770
- txId: result.txId,
1771
- amount: isNaN(numAmount) ? 0 : numAmount,
1772
- memo
1773
- });
1774
- setZucchiniPaying(false);
1775
- }, 1500);
1776
- } catch (err) {
1777
- const error = err instanceof Error ? err : new Error("Zucchini payment failed");
1778
- onErrorRef.current?.(error);
1779
- setZucchiniPaying(false);
1780
- }
1781
- }, [recipient, amount, memo, zucchiniAdapter, updateStatus]);
1782
- const simulateDetection = useCallback3(() => {
1783
- updateStatus("detected");
1784
- setTimeout(() => {
1785
- const mockTxId = `0x${Array.from(
1786
- { length: 64 },
1787
- () => Math.floor(Math.random() * 16).toString(16)
1788
- ).join("")}`;
1789
- setTxId(mockTxId);
1790
- updateStatus("confirmed");
1791
- const numAmount = typeof amount === "number" ? amount : parseFloat(amount);
1792
- onSuccessRef.current?.({
1793
- txId: mockTxId,
1794
- amount: isNaN(numAmount) ? 0 : numAmount,
1795
- memo
1796
- });
1797
- }, 2e3);
1798
- }, [amount, memo, updateStatus]);
1799
- return {
1800
- status,
1801
- txId,
1802
- secondsRemaining,
1803
- isModalOpen,
1804
- openModal,
1805
- closeModal,
1806
- resetPayment,
1807
- zip321Uri,
1808
- deepLinks,
1809
- addressType,
1810
- isShielded,
1811
- memoValidation,
1812
- simulateDetection,
1813
- invoiceId,
1814
- network,
1815
- customRpcUrl,
1816
- // Zucchini Wallet
1817
- zucchiniAvailable,
1818
- zucchiniPaying,
1819
- payWithZucchini
1820
- };
1821
- }
1822
-
1823
- // src/components/CiceroModal.tsx
1824
- import { useState as useState6, useEffect as useEffect6 } from "react";
1825
- import { createPortal as createPortal3 } from "react-dom";
1826
- import {
1827
- Shield as Shield4,
1828
- Copy as Copy2,
1829
- Check as Check2,
1830
- ExternalLink as ExternalLink3,
1831
- Clock,
1832
- CheckCircle2,
1833
- AlertCircle as AlertCircle2,
1834
- X as X3,
1835
- Lock,
1836
- Sparkles as Sparkles2,
1837
- Zap
1838
- } from "lucide-react";
1839
- import { Fragment as Fragment3, jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
1840
- var CiceroModal = ({
1841
- isOpen,
1842
- onClose,
1843
- recipient,
1844
- amount,
1845
- memo,
1846
- message,
1847
- network = "mainnet",
1848
- status,
1849
- txId,
1850
- secondsRemaining,
1851
- zip321Uri,
1852
- addressType,
1853
- isShielded,
1854
- memoValidation,
1855
- onSimulateDetection,
1856
- onResetPayment,
1857
- title = "Pay with Shielded Zcash",
1858
- subtitle = "Zero-Knowledge, Confidential Checkout",
1859
- showUsd = true,
1860
- zucchiniAvailable = false,
1861
- zucchiniPaying = false,
1862
- onPayWithZucchini
1863
- }) => {
1864
- const [copiedType, setCopiedType] = useState6(null);
1865
- const { convertZecToUsd } = useZcashPrice(showUsd);
1866
- useEffect6(() => {
1867
- const handleKeyDown = (e) => {
1868
- if (e.key === "Escape" && isOpen) {
1869
- onClose();
1870
- }
1871
- };
1872
- window.addEventListener("keydown", handleKeyDown);
1873
- return () => window.removeEventListener("keydown", handleKeyDown);
1874
- }, [isOpen, onClose]);
1875
- const [mounted, setMounted] = useState6(false);
1876
- useEffect6(() => {
1877
- setMounted(true);
1878
- }, []);
1879
- if (!isOpen || !mounted) return null;
1880
- const copyToClipboard = async (text, type) => {
1881
- try {
1882
- await navigator.clipboard.writeText(text);
1883
- setCopiedType(type);
1884
- setTimeout(() => setCopiedType(null), 2e3);
1885
- } catch {
1886
- }
1887
- };
1888
- const formatTime = (secs) => {
1889
- const m = Math.floor(secs / 60);
1890
- const s = secs % 60;
1891
- return `${m}:${s < 10 ? "0" : ""}${s}`;
1892
- };
1893
- const usdValue = convertZecToUsd(amount);
1894
- return createPortal3(
1895
- /* @__PURE__ */ jsxs5("div", { className: "fixed inset-0 z-[99999] flex items-center justify-center p-4 sm:p-6 overflow-y-auto", children: [
1896
- /* @__PURE__ */ jsx6(
1897
- "div",
1898
- {
1899
- className: "fixed inset-0 bg-[#171717]/60 backdrop-blur-sm transition-opacity z-[99999]",
1900
- onClick: onClose
1901
- }
1902
- ),
1903
- /* @__PURE__ */ jsxs5("div", { className: "relative w-full max-w-lg bg-white rounded-xl border border-[#ededed] shadow-2xl overflow-hidden z-[100000] text-[#171717] font-sans animate-in fade-in zoom-in-95 duration-150", children: [
1904
- /* @__PURE__ */ jsxs5("div", { className: "flex items-center justify-between px-6 py-4 border-b border-[#ededed] bg-[#fafafa]", children: [
1905
- /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-2.5", children: [
1906
- /* @__PURE__ */ jsx6("div", { className: "w-8 h-8 rounded-md bg-[#171717] flex items-center justify-center text-[#3ecf8e]", children: /* @__PURE__ */ jsx6(Shield4, { className: "w-4 h-4 fill-[#3ecf8e]" }) }),
1907
- /* @__PURE__ */ jsxs5("div", { children: [
1908
- /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-2", children: [
1909
- /* @__PURE__ */ jsx6("span", { className: "font-medium text-sm text-[#171717]", children: title }),
1910
- /* @__PURE__ */ jsx6("span", { className: "text-[10px] uppercase tracking-wider font-semibold px-2 py-0.5 rounded-full bg-[#3ecf8e]/15 text-[#24b47e] border border-[#3ecf8e]/30", children: isShielded ? "zk-Shielded" : "Transparent" }),
1911
- network === "testnet" && /* @__PURE__ */ jsx6("span", { className: "text-[10px] uppercase tracking-wider font-semibold px-2 py-0.5 rounded-full bg-amber-100 text-amber-800 border border-amber-200", children: "Testnet" })
1912
- ] }),
1913
- /* @__PURE__ */ jsx6("p", { className: "text-xs text-[#707070] mt-0.5", children: subtitle })
1914
- ] })
1915
- ] }),
1916
- /* @__PURE__ */ jsx6(
1917
- "button",
1918
- {
1919
- onClick: onClose,
1920
- className: "p-1 rounded-md text-[#707070] hover:text-[#171717] hover:bg-[#ededed] transition-colors",
1921
- "aria-label": "Close modal",
1922
- children: /* @__PURE__ */ jsx6(X3, { className: "w-4 h-4" })
1923
- }
1924
- )
1925
- ] }),
1926
- /* @__PURE__ */ jsxs5("div", { className: "px-6 py-2.5 bg-white border-b border-[#ededed] flex items-center justify-between text-xs", children: [
1927
- /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-2", children: [
1928
- status === "pending" && /* @__PURE__ */ jsxs5(Fragment3, { children: [
1929
- /* @__PURE__ */ jsxs5("span", { className: "relative flex h-2 w-2", children: [
1930
- /* @__PURE__ */ jsx6("span", { className: "animate-ping absolute inline-flex h-full w-full rounded-full bg-[#3ecf8e] opacity-75" }),
1931
- /* @__PURE__ */ jsx6("span", { className: "relative inline-flex rounded-full h-2 w-2 bg-[#24b47e]" })
1932
- ] }),
1933
- /* @__PURE__ */ jsx6("span", { className: "text-[#707070]", children: "Listening for transaction..." })
1934
- ] }),
1935
- status === "detected" && /* @__PURE__ */ jsxs5(Fragment3, { children: [
1936
- /* @__PURE__ */ jsxs5("span", { className: "relative flex h-2 w-2", children: [
1937
- /* @__PURE__ */ jsx6("span", { className: "animate-ping absolute inline-flex h-full w-full rounded-full bg-amber-400 opacity-75" }),
1938
- /* @__PURE__ */ jsx6("span", { className: "relative inline-flex rounded-full h-2 w-2 bg-amber-500" })
1939
- ] }),
1940
- /* @__PURE__ */ jsx6("span", { className: "text-amber-800 font-medium", children: "Transaction spotted in mempool! Confirming..." })
1941
- ] }),
1942
- status === "confirmed" && /* @__PURE__ */ jsxs5(Fragment3, { children: [
1943
- /* @__PURE__ */ jsx6(CheckCircle2, { className: "w-4 h-4 text-[#24b47e]" }),
1944
- /* @__PURE__ */ jsx6("span", { className: "text-[#24b47e] font-medium", children: "Payment Confirmed On-Chain!" })
1945
- ] }),
1946
- status === "expired" && /* @__PURE__ */ jsxs5(Fragment3, { children: [
1947
- /* @__PURE__ */ jsx6(AlertCircle2, { className: "w-4 h-4 text-rose-500" }),
1948
- /* @__PURE__ */ jsx6("span", { className: "text-rose-600 font-medium", children: "Payment window expired" })
1949
- ] })
1950
- ] }),
1951
- status === "pending" && /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-1 text-[#707070] font-mono text-[11px]", children: [
1952
- /* @__PURE__ */ jsx6(Clock, { className: "w-3 h-3" }),
1953
- /* @__PURE__ */ jsx6("span", { children: formatTime(secondsRemaining) })
1954
- ] })
1955
- ] }),
1956
- /* @__PURE__ */ jsx6("div", { className: "p-6 space-y-5", children: status === "confirmed" ? /* @__PURE__ */ jsxs5("div", { className: "py-6 text-center space-y-4", children: [
1957
- /* @__PURE__ */ jsx6("div", { className: "w-16 h-16 mx-auto rounded-full bg-[#3ecf8e]/15 border border-[#3ecf8e]/40 flex items-center justify-center text-[#24b47e] animate-bounce", children: /* @__PURE__ */ jsx6(CheckCircle2, { className: "w-8 h-8" }) }),
1958
- /* @__PURE__ */ jsxs5("div", { children: [
1959
- /* @__PURE__ */ jsx6("h3", { className: "text-lg font-medium text-[#171717]", children: "Payment Received & Shielded!" }),
1960
- /* @__PURE__ */ jsx6("p", { className: "text-xs text-[#707070] max-w-sm mx-auto mt-1", children: "Your transaction has been verified using zero-knowledge proofs. No sender or recipient address was leaked." })
1961
- ] }),
1962
- txId && /* @__PURE__ */ jsxs5("div", { className: "p-3 bg-[#fafafa] rounded-md border border-[#ededed] text-left", children: [
1963
- /* @__PURE__ */ jsxs5("div", { className: "flex items-center justify-between text-[11px] text-[#707070] mb-1", children: [
1964
- /* @__PURE__ */ jsx6("span", { children: "Transaction Hash" }),
1965
- /* @__PURE__ */ jsx6("span", { className: "text-[#24b47e] font-mono", children: "Shielded Note" })
1966
- ] }),
1967
- /* @__PURE__ */ jsx6("div", { className: "font-mono text-xs text-[#171717] break-all", children: txId })
1968
- ] }),
1969
- /* @__PURE__ */ jsx6(
1970
- "button",
1971
- {
1972
- onClick: onClose,
1973
- className: "w-full py-2.5 px-4 rounded-md bg-[#3ecf8e] text-[#171717] font-medium text-sm hover:bg-[#24b47e] transition-colors",
1974
- children: "Close & Return"
1975
- }
1976
- )
1977
- ] }) : /* @__PURE__ */ jsxs5(Fragment3, { children: [
1978
- /* @__PURE__ */ jsxs5("div", { className: "flex items-center justify-between p-4 bg-[#fafafa] rounded-lg border border-[#ededed]", children: [
1979
- /* @__PURE__ */ jsxs5("div", { children: [
1980
- /* @__PURE__ */ jsx6("span", { className: "text-xs text-[#707070] uppercase font-mono tracking-wider", children: "Total Amount" }),
1981
- /* @__PURE__ */ jsxs5("div", { className: "flex items-baseline gap-2 mt-0.5", children: [
1982
- /* @__PURE__ */ jsxs5("span", { className: "text-2xl font-semibold tracking-tight text-[#171717] font-mono", children: [
1983
- amount,
1984
- " ",
1985
- /* @__PURE__ */ jsx6("span", { className: "text-sm font-normal text-[#707070]", children: "ZEC" })
1986
- ] }),
1987
- usdValue && /* @__PURE__ */ jsxs5("span", { className: "text-xs text-[#707070] font-mono", children: [
1988
- "\u2248 $",
1989
- usdValue,
1990
- " USD"
1991
- ] })
1992
- ] })
1993
- ] }),
1994
- /* @__PURE__ */ jsxs5("div", { className: "text-right", children: [
1995
- /* @__PURE__ */ jsx6("span", { className: "text-[11px] text-[#707070] block font-mono", children: "Address Standard" }),
1996
- /* @__PURE__ */ jsx6("span", { className: "inline-block mt-0.5 px-2 py-0.5 text-xs font-mono font-medium rounded bg-white border border-[#dfdfdf] text-[#171717]", children: addressType === "unified" ? "Unified (ZIP-316)" : addressType === "sapling" ? "Sapling (Shielded)" : "Transparent" })
1997
- ] })
1998
- ] }),
1999
- message && /* @__PURE__ */ jsxs5("div", { className: "px-3.5 py-2 bg-[#fafafa] rounded-md border border-[#ededed] text-xs text-[#707070]", children: [
2000
- /* @__PURE__ */ jsx6("span", { className: "font-medium text-[#171717]", children: "Order Note: " }),
2001
- /* @__PURE__ */ jsx6("span", { children: message })
2002
- ] }),
2003
- /* @__PURE__ */ jsxs5("div", { className: "flex flex-col sm:flex-row items-center gap-5 p-4 rounded-lg border border-[#ededed] bg-white", children: [
2004
- /* @__PURE__ */ jsx6("div", { className: "flex-shrink-0", children: /* @__PURE__ */ jsx6(CiceroQRCode, { value: zip321Uri, size: 150 }) }),
2005
- /* @__PURE__ */ jsxs5("div", { className: "space-y-3 w-full text-center sm:text-left", children: [
2006
- /* @__PURE__ */ jsxs5("div", { children: [
2007
- /* @__PURE__ */ jsxs5("h4", { className: "text-sm font-medium text-[#171717] flex items-center justify-center sm:justify-start gap-1.5", children: [
2008
- /* @__PURE__ */ jsx6("span", { children: "Scan with Shielded Wallet" }),
2009
- /* @__PURE__ */ jsx6(Sparkles2, { className: "w-3.5 h-3.5 text-[#3ecf8e]" })
2010
- ] }),
2011
- /* @__PURE__ */ jsxs5("p", { className: "text-xs text-[#707070] mt-0.5 leading-relaxed", children: [
2012
- "Compatible with ",
2013
- /* @__PURE__ */ jsx6("strong", { className: "text-[#171717]", children: "Zashi" }),
2014
- ", ",
2015
- /* @__PURE__ */ jsx6("strong", { className: "text-[#171717]", children: "Ywallet" }),
2016
- ", or any ZIP-321 compliant Zcash wallet."
2017
- ] })
2018
- ] }),
2019
- /* @__PURE__ */ jsxs5(
2020
- "a",
2021
- {
2022
- href: zip321Uri,
2023
- className: "inline-flex items-center justify-center gap-1.5 w-full py-2 px-3 rounded-md bg-[#171717] text-white text-xs font-medium hover:bg-[#212121] transition-colors",
2024
- children: [
2025
- /* @__PURE__ */ jsx6("span", { children: "Open in Mobile / Desktop Wallet" }),
2026
- /* @__PURE__ */ jsx6(ExternalLink3, { className: "w-3.5 h-3.5 text-[#3ecf8e]" })
2027
- ]
2028
- }
2029
- ),
2030
- zucchiniAvailable && onPayWithZucchini && /* @__PURE__ */ jsx6(
2031
- "button",
2032
- {
2033
- onClick: onPayWithZucchini,
2034
- disabled: zucchiniPaying,
2035
- className: "inline-flex items-center justify-center gap-2 w-full py-2.5 px-3 rounded-md bg-[#3ecf8e] text-[#171717] text-xs font-semibold hover:bg-[#24b47e] transition-colors disabled:opacity-60 disabled:cursor-wait shadow-sm",
2036
- children: zucchiniPaying ? /* @__PURE__ */ jsxs5(Fragment3, { children: [
2037
- /* @__PURE__ */ jsx6("span", { className: "w-3.5 h-3.5 border-2 border-[#171717]/30 border-t-[#171717] rounded-full animate-spin" }),
2038
- /* @__PURE__ */ jsx6("span", { children: "Confirming in Zucchini..." })
2039
- ] }) : /* @__PURE__ */ jsxs5(Fragment3, { children: [
2040
- /* @__PURE__ */ jsx6("span", { className: "text-sm", children: "\u{1F952}" }),
2041
- /* @__PURE__ */ jsx6("span", { children: "Pay with Zucchini Wallet" })
2042
- ] })
2043
- }
2044
- ),
2045
- /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-2", children: [
2046
- /* @__PURE__ */ jsx6(
2047
- "button",
2048
- {
2049
- onClick: () => copyToClipboard(zip321Uri, "uri"),
2050
- className: "flex-1 py-1.5 px-2.5 rounded-md border border-[#ededed] hover:border-[#dfdfdf] hover:bg-[#fafafa] text-xs font-medium text-[#171717] transition-colors flex items-center justify-center gap-1",
2051
- children: copiedType === "uri" ? /* @__PURE__ */ jsxs5(Fragment3, { children: [
2052
- /* @__PURE__ */ jsx6(Check2, { className: "w-3 h-3 text-[#24b47e]" }),
2053
- /* @__PURE__ */ jsx6("span", { className: "text-[#24b47e]", children: "Copied URI" })
2054
- ] }) : /* @__PURE__ */ jsxs5(Fragment3, { children: [
2055
- /* @__PURE__ */ jsx6(Copy2, { className: "w-3 h-3 text-[#707070]" }),
2056
- /* @__PURE__ */ jsx6("span", { children: "Copy ZIP-321 URI" })
2057
- ] })
2058
- }
2059
- ),
2060
- /* @__PURE__ */ jsx6(
2061
- "button",
2062
- {
2063
- onClick: () => copyToClipboard(recipient, "address"),
2064
- className: "flex-1 py-1.5 px-2.5 rounded-md border border-[#ededed] hover:border-[#dfdfdf] hover:bg-[#fafafa] text-xs font-medium text-[#171717] transition-colors flex items-center justify-center gap-1",
2065
- children: copiedType === "address" ? /* @__PURE__ */ jsxs5(Fragment3, { children: [
2066
- /* @__PURE__ */ jsx6(Check2, { className: "w-3 h-3 text-[#24b47e]" }),
2067
- /* @__PURE__ */ jsx6("span", { className: "text-[#24b47e]", children: "Copied Address" })
2068
- ] }) : /* @__PURE__ */ jsxs5(Fragment3, { children: [
2069
- /* @__PURE__ */ jsx6(Copy2, { className: "w-3 h-3 text-[#707070]" }),
2070
- /* @__PURE__ */ jsx6("span", { children: "Copy Address" })
2071
- ] })
2072
- }
2073
- )
2074
- ] })
2075
- ] })
2076
- ] }),
2077
- /* @__PURE__ */ jsxs5("div", { className: "space-y-1.5 text-xs", children: [
2078
- /* @__PURE__ */ jsxs5("div", { className: "flex items-center justify-between text-[#707070]", children: [
2079
- /* @__PURE__ */ jsx6("span", { children: "Recipient Address" }),
2080
- /* @__PURE__ */ jsx6("span", { className: "font-mono text-[11px]", children: truncateAddress(recipient, 12, 10) })
2081
- ] }),
2082
- /* @__PURE__ */ jsx6("div", { className: "p-2 bg-[#fafafa] rounded-md border border-[#ededed] font-mono text-[11px] text-[#171717] break-all select-all", children: recipient })
2083
- ] }),
2084
- memo && /* @__PURE__ */ jsxs5("div", { className: "space-y-1.5 text-xs p-3 rounded-md bg-[#fafafa] border border-[#ededed]", children: [
2085
- /* @__PURE__ */ jsxs5("div", { className: "flex items-center justify-between", children: [
2086
- /* @__PURE__ */ jsxs5("span", { className: "flex items-center gap-1.5 font-medium text-[#171717]", children: [
2087
- /* @__PURE__ */ jsx6(Lock, { className: "w-3 h-3 text-[#3ecf8e]" }),
2088
- /* @__PURE__ */ jsx6("span", { children: "Encrypted Memo" })
2089
- ] }),
2090
- /* @__PURE__ */ jsxs5("span", { className: "text-[10px] font-mono text-[#707070]", children: [
2091
- memoValidation.byteLength,
2092
- "/512 bytes"
2093
- ] })
2094
- ] }),
2095
- /* @__PURE__ */ jsx6("p", { className: "font-mono text-xs text-[#171717] bg-white p-2 rounded border border-[#dfdfdf]", children: memo }),
2096
- /* @__PURE__ */ jsx6("p", { className: "text-[11px] text-[#707070]", children: "Only the recipient holding the viewing/spending key can decrypt this message on-chain." })
2097
- ] }),
2098
- memoValidation.warning && /* @__PURE__ */ jsxs5("div", { className: "p-2.5 rounded-md bg-amber-50 border border-amber-200 text-amber-800 text-xs flex items-start gap-2", children: [
2099
- /* @__PURE__ */ jsx6(AlertCircle2, { className: "w-4 h-4 flex-shrink-0 mt-0.5 text-amber-600" }),
2100
- /* @__PURE__ */ jsx6("span", { children: memoValidation.warning })
2101
- ] }),
2102
- /* @__PURE__ */ jsxs5("div", { className: "pt-2 border-t border-[#ededed] flex items-center justify-between", children: [
2103
- /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-1.5 text-[11px] text-[#707070]", children: [
2104
- /* @__PURE__ */ jsx6(Zap, { className: "w-3 h-3 text-[#3ecf8e]" }),
2105
- /* @__PURE__ */ jsx6("span", { children: "Demo Controls:" })
2106
- ] }),
2107
- /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-2", children: [
2108
- /* @__PURE__ */ jsx6(
2109
- "button",
2110
- {
2111
- onClick: onSimulateDetection,
2112
- className: "px-2.5 py-1 text-[11px] font-medium rounded border border-[#dfdfdf] hover:border-[#3ecf8e] hover:text-[#24b47e] bg-white text-[#171717] transition-colors",
2113
- children: "Simulate Payment"
2114
- }
2115
- ),
2116
- status === "expired" && /* @__PURE__ */ jsx6(
2117
- "button",
2118
- {
2119
- onClick: onResetPayment,
2120
- className: "px-2.5 py-1 text-[11px] font-medium rounded bg-[#171717] text-white hover:bg-[#212121] transition-colors",
2121
- children: "Refresh"
2122
- }
2123
- )
2124
- ] })
2125
- ] })
2126
- ] }) })
2127
- ] })
2128
- ] }),
2129
- document.body
2130
- );
2131
- };
2132
-
2133
- // src/components/CiceroPayButton.tsx
2134
- import { Fragment as Fragment4, jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
2135
- var CiceroPayButton = ({
2136
- recipient,
2137
- amount,
2138
- memo,
2139
- message,
2140
- label = "Pay with Zcash",
2141
- network = "mainnet",
2142
- variant = "primary",
2143
- size = "md",
2144
- showUsd = true,
2145
- modalTitle,
2146
- modalSubtitle,
2147
- expiresInSeconds = 900,
2148
- customRpcUrl,
2149
- invoiceId,
2150
- onSuccess,
2151
- onError,
2152
- onStatusChange,
2153
- className = "",
2154
- disabled = false
2155
- }) => {
2156
- const {
2157
- status,
2158
- txId,
2159
- secondsRemaining,
2160
- isModalOpen,
2161
- openModal,
2162
- closeModal,
2163
- resetPayment,
2164
- zip321Uri,
2165
- addressType,
2166
- isShielded,
2167
- memoValidation,
2168
- simulateDetection,
2169
- zucchiniAvailable,
2170
- zucchiniPaying,
2171
- payWithZucchini
2172
- } = useCiceroPayment({
2173
- recipient,
2174
- amount,
2175
- memo,
2176
- message,
2177
- network,
2178
- expiresInSeconds,
2179
- invoiceId,
2180
- customRpcUrl,
2181
- onSuccess,
2182
- onError,
2183
- onStatusChange
2184
- });
2185
- const sizeClasses = {
2186
- sm: "text-xs px-3 py-1.5 gap-1.5",
2187
- md: "text-sm px-4 py-2 gap-2",
2188
- lg: "text-base px-5 py-2.5 gap-2.5"
2189
- }[size];
2190
- const variantClasses = {
2191
- // Signature Supabase emerald CTA: #3ecf8e background, #171717 text, 6px radius
2192
- primary: "bg-[#3ecf8e] text-[#171717] hover:bg-[#24b47e] active:bg-[#24b47e] shadow-sm font-medium",
2193
- // Secondary outline on white
2194
- outline: "bg-white text-[#171717] border border-[#dfdfdf] hover:border-[#c7c7c7] hover:bg-[#fafafa] font-medium shadow-sm",
2195
- // Dark canvas-night
2196
- dark: "bg-[#1c1c1c] text-white hover:bg-[#242424] font-medium shadow-sm"
2197
- }[variant];
2198
- return /* @__PURE__ */ jsxs6(Fragment4, { children: [
2199
- /* @__PURE__ */ jsxs6(
2200
- "button",
2201
- {
2202
- type: "button",
2203
- onClick: openModal,
2204
- disabled,
2205
- className: `inline-flex items-center justify-center rounded-[6px] transition-all duration-150 select-none disabled:opacity-50 disabled:cursor-not-allowed ${sizeClasses} ${variantClasses} ${className}`,
2206
- children: [
2207
- /* @__PURE__ */ jsx7(
2208
- Shield5,
2209
- {
2210
- className: `flex-shrink-0 ${size === "sm" ? "w-3.5 h-3.5" : size === "lg" ? "w-5 h-5" : "w-4 h-4"} ${variant === "primary" ? "fill-[#171717]/20" : "text-[#3ecf8e]"}`
2211
- }
2212
- ),
2213
- /* @__PURE__ */ jsx7("span", { children: label })
2214
- ]
2215
- }
2216
- ),
2217
- /* @__PURE__ */ jsx7(
2218
- CiceroModal,
2219
- {
2220
- isOpen: isModalOpen,
2221
- onClose: closeModal,
2222
- recipient,
2223
- amount,
2224
- memo,
2225
- message,
2226
- network,
2227
- status,
2228
- txId,
2229
- secondsRemaining,
2230
- zip321Uri,
2231
- addressType,
2232
- isShielded,
2233
- memoValidation,
2234
- onSimulateDetection: simulateDetection,
2235
- onResetPayment: resetPayment,
2236
- title: modalTitle,
2237
- subtitle: modalSubtitle,
2238
- showUsd,
2239
- zucchiniAvailable,
2240
- zucchiniPaying,
2241
- onPayWithZucchini: payWithZucchini
2242
- }
2243
- )
2244
- ] });
2245
- };
2246
-
2247
- // src/components/CiceroInvoice.tsx
2248
- import { useState as useState7 } from "react";
2249
- import {
2250
- Shield as Shield6,
2251
- Copy as Copy3,
2252
- Check as Check3,
2253
- ExternalLink as ExternalLink4,
2254
- Clock as Clock2,
2255
- CheckCircle2 as CheckCircle22,
2256
- AlertCircle as AlertCircle3,
2257
- Lock as Lock2,
2258
- Sparkles as Sparkles3
2259
- } from "lucide-react";
2260
- import { Fragment as Fragment5, jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
2261
- var CiceroInvoice = ({
2262
- recipient,
2263
- amount,
2264
- memo,
2265
- message,
2266
- network = "mainnet",
2267
- expiresInSeconds = 900,
2268
- showUsd = true,
2269
- invoiceId,
2270
- customRpcUrl,
2271
- onSuccess,
2272
- onError,
2273
- onStatusChange,
2274
- className = ""
2275
- }) => {
2276
- const [copiedType, setCopiedType] = useState7(null);
2277
- const { convertZecToUsd } = useZcashPrice(showUsd);
2278
- const {
2279
- status,
2280
- txId,
2281
- secondsRemaining,
2282
- zip321Uri,
2283
- addressType,
2284
- isShielded,
2285
- memoValidation,
2286
- simulateDetection,
2287
- resetPayment,
2288
- zucchiniAvailable,
2289
- zucchiniPaying,
2290
- payWithZucchini
2291
- } = useCiceroPayment({
2292
- recipient,
2293
- amount,
2294
- memo,
2295
- message,
2296
- network,
2297
- expiresInSeconds,
2298
- invoiceId,
2299
- customRpcUrl,
2300
- onSuccess,
2301
- onError,
2302
- onStatusChange
2303
- });
2304
- const copyToClipboard = async (text, type) => {
2305
- try {
2306
- await navigator.clipboard.writeText(text);
2307
- setCopiedType(type);
2308
- setTimeout(() => setCopiedType(null), 2e3);
2309
- } catch {
2310
- }
2311
- };
2312
- const formatTime = (secs) => {
2313
- const m = Math.floor(secs / 60);
2314
- const s = secs % 60;
2315
- return `${m}:${s < 10 ? "0" : ""}${s}`;
2316
- };
2317
- const usdValue = convertZecToUsd(amount);
2318
- return /* @__PURE__ */ jsxs7(
2319
- "div",
2320
- {
2321
- className: `bg-white rounded-xl border border-[#ededed] shadow-sm overflow-hidden text-[#171717] font-sans ${className}`,
2322
- children: [
2323
- /* @__PURE__ */ jsxs7("div", { className: "flex items-center justify-between px-5 py-3.5 border-b border-[#ededed] bg-[#fafafa]", children: [
2324
- /* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-2", children: [
2325
- /* @__PURE__ */ jsx8("div", { className: "w-7 h-7 rounded-md bg-[#171717] flex items-center justify-center text-[#3ecf8e]", children: /* @__PURE__ */ jsx8(Shield6, { className: "w-3.5 h-3.5 fill-[#3ecf8e]" }) }),
2326
- /* @__PURE__ */ jsxs7("div", { children: [
2327
- /* @__PURE__ */ jsx8("span", { className: "font-medium text-xs text-[#171717]", children: "Shielded Zcash Invoice" }),
2328
- invoiceId && /* @__PURE__ */ jsxs7("span", { className: "text-[10px] text-[#707070] ml-2 font-mono", children: [
2329
- "#",
2330
- invoiceId
2331
- ] })
2332
- ] })
2333
- ] }),
2334
- /* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-2", children: [
2335
- /* @__PURE__ */ jsx8("span", { className: "text-[10px] font-mono px-1.5 py-0.5 rounded bg-white border border-[#dfdfdf] text-[#171717]", children: addressType === "unified" ? "Unified" : addressType === "sapling" ? "Sapling" : "Transparent" }),
2336
- /* @__PURE__ */ jsx8("span", { className: "text-[10px] uppercase tracking-wider font-semibold px-2 py-0.5 rounded-full bg-[#3ecf8e]/15 text-[#24b47e] border border-[#3ecf8e]/30", children: isShielded ? "zk-Shielded" : "Transparent" }),
2337
- network === "testnet" && /* @__PURE__ */ jsx8("span", { className: "text-[10px] uppercase tracking-wider font-semibold px-2 py-0.5 rounded-full bg-amber-100 text-amber-800 border border-amber-200", children: "Testnet" })
2338
- ] })
2339
- ] }),
2340
- /* @__PURE__ */ jsx8("div", { className: "p-5 space-y-4", children: status === "confirmed" ? /* @__PURE__ */ jsxs7("div", { className: "py-6 text-center space-y-3", children: [
2341
- /* @__PURE__ */ jsx8("div", { className: "w-12 h-12 mx-auto rounded-full bg-[#3ecf8e]/15 border border-[#3ecf8e]/40 flex items-center justify-center text-[#24b47e]", children: /* @__PURE__ */ jsx8(CheckCircle22, { className: "w-6 h-6" }) }),
2342
- /* @__PURE__ */ jsxs7("div", { children: [
2343
- /* @__PURE__ */ jsx8("h4", { className: "font-medium text-sm text-[#171717]", children: "Payment Verified!" }),
2344
- /* @__PURE__ */ jsx8("p", { className: "text-xs text-[#707070] mt-0.5", children: "Shielded transaction detected and settled on-chain." })
2345
- ] }),
2346
- txId && /* @__PURE__ */ jsx8("div", { className: "font-mono text-[11px] p-2 bg-[#fafafa] rounded border border-[#ededed] text-[#707070] break-all", children: txId })
2347
- ] }) : /* @__PURE__ */ jsxs7(Fragment5, { children: [
2348
- /* @__PURE__ */ jsxs7("div", { className: "flex items-center justify-between p-3.5 bg-[#fafafa] rounded-lg border border-[#ededed]", children: [
2349
- /* @__PURE__ */ jsxs7("div", { children: [
2350
- /* @__PURE__ */ jsx8("span", { className: "text-[10px] text-[#707070] uppercase font-mono tracking-wider", children: "Amount Due" }),
2351
- /* @__PURE__ */ jsxs7("div", { className: "flex items-baseline gap-2 mt-0.5", children: [
2352
- /* @__PURE__ */ jsxs7("span", { className: "text-xl font-semibold tracking-tight text-[#171717] font-mono", children: [
2353
- amount,
2354
- " ",
2355
- /* @__PURE__ */ jsx8("span", { className: "text-xs font-normal text-[#707070]", children: "ZEC" })
2356
- ] }),
2357
- usdValue && /* @__PURE__ */ jsxs7("span", { className: "text-xs text-[#707070] font-mono", children: [
2358
- "\u2248 $",
2359
- usdValue,
2360
- " USD"
2361
- ] })
2362
- ] })
2363
- ] }),
2364
- /* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-1.5 text-[#707070] font-mono text-xs", children: [
2365
- /* @__PURE__ */ jsx8(Clock2, { className: "w-3.5 h-3.5" }),
2366
- /* @__PURE__ */ jsx8("span", { children: formatTime(secondsRemaining) })
2367
- ] })
2368
- ] }),
2369
- /* @__PURE__ */ jsxs7("div", { className: "flex flex-col sm:flex-row items-center gap-4", children: [
2370
- /* @__PURE__ */ jsx8(CiceroQRCode, { value: zip321Uri, size: 140 }),
2371
- /* @__PURE__ */ jsxs7("div", { className: "space-y-2.5 w-full", children: [
2372
- zucchiniAvailable && /* @__PURE__ */ jsx8(
2373
- "button",
2374
- {
2375
- onClick: payWithZucchini,
2376
- disabled: zucchiniPaying,
2377
- className: "inline-flex items-center justify-center gap-1.5 w-full py-2 px-3 rounded-md bg-[#3ecf8e] text-[#171717] text-xs font-semibold hover:bg-[#24b47e] transition-colors disabled:opacity-60 shadow-sm",
2378
- children: zucchiniPaying ? /* @__PURE__ */ jsxs7(Fragment5, { children: [
2379
- /* @__PURE__ */ jsx8("span", { className: "w-3.5 h-3.5 border-2 border-[#171717]/30 border-t-[#171717] rounded-full animate-spin" }),
2380
- /* @__PURE__ */ jsx8("span", { children: "Confirming in Zucchini..." })
2381
- ] }) : /* @__PURE__ */ jsxs7(Fragment5, { children: [
2382
- /* @__PURE__ */ jsx8("span", { children: "\u{1F952}" }),
2383
- /* @__PURE__ */ jsx8("span", { children: "Pay with Zucchini Wallet" })
2384
- ] })
2385
- }
2386
- ),
2387
- /* @__PURE__ */ jsxs7(
2388
- "a",
2389
- {
2390
- href: zip321Uri,
2391
- className: "inline-flex items-center justify-center gap-1.5 w-full py-2 px-3 rounded-md bg-[#171717] text-white text-xs font-medium hover:bg-[#212121] transition-colors",
2392
- children: [
2393
- /* @__PURE__ */ jsx8("span", { children: "Pay with Wallet App" }),
2394
- /* @__PURE__ */ jsx8(ExternalLink4, { className: "w-3.5 h-3.5 text-[#3ecf8e]" })
2395
- ]
2396
- }
2397
- ),
2398
- /* @__PURE__ */ jsxs7("div", { className: "grid grid-cols-2 gap-2", children: [
2399
- /* @__PURE__ */ jsxs7(
2400
- "button",
2401
- {
2402
- onClick: () => copyToClipboard(zip321Uri, "uri"),
2403
- className: "py-1.5 px-2 rounded-md border border-[#ededed] hover:bg-[#fafafa] text-[11px] font-medium text-[#171717] transition-colors flex items-center justify-center gap-1",
2404
- children: [
2405
- copiedType === "uri" ? /* @__PURE__ */ jsx8(Check3, { className: "w-3 h-3 text-[#24b47e]" }) : /* @__PURE__ */ jsx8(Copy3, { className: "w-3 h-3 text-[#707070]" }),
2406
- /* @__PURE__ */ jsx8("span", { children: copiedType === "uri" ? "Copied" : "Copy URI" })
2407
- ]
2408
- }
2409
- ),
2410
- /* @__PURE__ */ jsxs7(
2411
- "button",
2412
- {
2413
- onClick: () => copyToClipboard(recipient, "address"),
2414
- className: "py-1.5 px-2 rounded-md border border-[#ededed] hover:bg-[#fafafa] text-[11px] font-medium text-[#171717] transition-colors flex items-center justify-center gap-1",
2415
- children: [
2416
- copiedType === "address" ? /* @__PURE__ */ jsx8(Check3, { className: "w-3 h-3 text-[#24b47e]" }) : /* @__PURE__ */ jsx8(Copy3, { className: "w-3 h-3 text-[#707070]" }),
2417
- /* @__PURE__ */ jsx8("span", { children: copiedType === "address" ? "Copied" : "Copy Addr" })
2418
- ]
2419
- }
2420
- )
2421
- ] }),
2422
- /* @__PURE__ */ jsxs7("div", { className: "text-[11px] text-[#707070] font-mono truncate", children: [
2423
- "To: ",
2424
- truncateAddress(recipient, 10, 8)
2425
- ] })
2426
- ] })
2427
- ] }),
2428
- memo && /* @__PURE__ */ jsxs7("div", { className: "p-2.5 bg-[#fafafa] rounded-md border border-[#ededed] text-xs", children: [
2429
- /* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-1 text-[11px] font-medium text-[#171717] mb-0.5", children: [
2430
- /* @__PURE__ */ jsx8(Lock2, { className: "w-3 h-3 text-[#3ecf8e]" }),
2431
- /* @__PURE__ */ jsx8("span", { children: "Encrypted Memo" })
2432
- ] }),
2433
- /* @__PURE__ */ jsx8("div", { className: "font-mono text-[11px] text-[#171717]", children: memo })
2434
- ] }),
2435
- memoValidation.warning && /* @__PURE__ */ jsxs7("div", { className: "p-2 rounded bg-amber-50 border border-amber-200 text-amber-800 text-[11px] flex items-start gap-1.5", children: [
2436
- /* @__PURE__ */ jsx8(AlertCircle3, { className: "w-3.5 h-3.5 flex-shrink-0 mt-0.5 text-amber-600" }),
2437
- /* @__PURE__ */ jsx8("span", { children: memoValidation.warning })
2438
- ] }),
2439
- status === "expired" && /* @__PURE__ */ jsxs7("div", { className: "p-2 rounded bg-rose-50 border border-rose-200 text-rose-800 text-xs flex items-center justify-between", children: [
2440
- /* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-1.5", children: [
2441
- /* @__PURE__ */ jsx8(AlertCircle3, { className: "w-3.5 h-3.5 text-rose-600" }),
2442
- /* @__PURE__ */ jsx8("span", { children: "Invoice has expired" })
2443
- ] }),
2444
- /* @__PURE__ */ jsx8(
2445
- "button",
2446
- {
2447
- onClick: resetPayment,
2448
- className: "px-2 py-0.5 text-[11px] font-medium rounded bg-[#171717] text-white hover:bg-[#212121]",
2449
- children: "Reset"
2450
- }
2451
- )
2452
- ] }),
2453
- /* @__PURE__ */ jsxs7("div", { className: "pt-2 border-t border-[#ededed] flex items-center justify-between text-[11px] text-[#707070]", children: [
2454
- /* @__PURE__ */ jsxs7("span", { className: "flex items-center gap-1", children: [
2455
- /* @__PURE__ */ jsx8(Sparkles3, { className: "w-3 h-3 text-[#3ecf8e]" }),
2456
- "Demo test"
2457
- ] }),
2458
- /* @__PURE__ */ jsx8(
2459
- "button",
2460
- {
2461
- onClick: simulateDetection,
2462
- className: "px-2 py-0.5 rounded border border-[#dfdfdf] hover:border-[#3ecf8e] text-[#171717] bg-white transition-colors",
2463
- children: "Simulate Success"
2464
- }
2465
- )
2466
- ] })
2467
- ] }) })
2468
- ]
2469
- }
2470
- );
2471
- };
2472
-
2473
1856
  // src/hooks/useZucchiniWallet.ts
2474
- import { useState as useState8, useEffect as useEffect7, useCallback as useCallback4 } from "react";
1857
+ import { useState as useState5, useEffect as useEffect5, useCallback as useCallback3 } from "react";
2475
1858
  function useZucchiniWallet(options = {}) {
2476
1859
  const { autoConnect = false } = options;
2477
- const [adapter2] = useState8(() => new ZucchiniWalletAdapter());
2478
- const [isAvailable, setIsAvailable] = useState8(false);
2479
- const [connectionStatus, setConnectionStatus] = useState8("disconnected");
2480
- const [paymentStatus, setPaymentStatus] = useState8("idle");
2481
- const [session, setSession] = useState8(null);
2482
- const [error, setError] = useState8(null);
2483
- useEffect7(() => {
1860
+ const [adapter2] = useState5(() => new ZucchiniWalletAdapter());
1861
+ const [isAvailable, setIsAvailable] = useState5(false);
1862
+ const [connectionStatus, setConnectionStatus] = useState5("disconnected");
1863
+ const [paymentStatus, setPaymentStatus] = useState5("idle");
1864
+ const [session, setSession] = useState5(null);
1865
+ const [error, setError] = useState5(null);
1866
+ useEffect5(() => {
2484
1867
  const detected = ZucchiniWalletAdapter.isAvailable();
2485
1868
  setIsAvailable(detected);
2486
1869
  if (detected && autoConnect) {
2487
1870
  connect();
2488
1871
  }
2489
1872
  }, []);
2490
- const connect = useCallback4(async () => {
1873
+ const connect = useCallback3(async () => {
2491
1874
  setConnectionStatus("connecting");
2492
1875
  setError(null);
2493
1876
  try {
@@ -2502,7 +1885,7 @@ function useZucchiniWallet(options = {}) {
2502
1885
  throw err;
2503
1886
  }
2504
1887
  }, [adapter2]);
2505
- const requestPayment = useCallback4(
1888
+ const requestPayment = useCallback3(
2506
1889
  async (params) => {
2507
1890
  setPaymentStatus("requesting");
2508
1891
  setError(null);
@@ -2519,7 +1902,7 @@ function useZucchiniWallet(options = {}) {
2519
1902
  },
2520
1903
  [adapter2]
2521
1904
  );
2522
- const disconnect = useCallback4(async () => {
1905
+ const disconnect = useCallback3(async () => {
2523
1906
  await adapter2.disconnect();
2524
1907
  setSession(null);
2525
1908
  setConnectionStatus("disconnected");
@@ -2548,9 +1931,6 @@ export {
2548
1931
  CiceroAccountModal,
2549
1932
  CiceroConnectButton,
2550
1933
  CiceroConnectModal,
2551
- CiceroInvoice,
2552
- CiceroModal,
2553
- CiceroPayButton,
2554
1934
  CiceroProvider,
2555
1935
  CiceroQRCode,
2556
1936
  ZucchiniWalletAdapter,
@@ -2568,7 +1948,6 @@ export {
2568
1948
  useAccountModal,
2569
1949
  useBalance,
2570
1950
  useCicero,
2571
- useCiceroPayment,
2572
1951
  useConnectModal,
2573
1952
  useZcashPrice,
2574
1953
  useZucchiniWallet,