@swype-org/react-sdk 0.1.30 → 0.1.32

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.js CHANGED
@@ -33,6 +33,9 @@ var darkTheme = {
33
33
  successBg: "#0f2f2a",
34
34
  error: "#d46a72",
35
35
  errorBg: "#301d21",
36
+ warning: "#F57C00",
37
+ warningBg: "#3D2E00",
38
+ warningText: "#FFB74D",
36
39
  shadow: "0 1px 4px rgba(0,0,0,0.35)",
37
40
  shadowLg: "0 18px 44px rgba(0,0,0,0.42)",
38
41
  radius: "14px",
@@ -57,6 +60,9 @@ var lightTheme = {
57
60
  successBg: "#e6f7f1",
58
61
  error: "#ce6670",
59
62
  errorBg: "#fdf1f2",
63
+ warning: "#F57C00",
64
+ warningBg: "#FFF8E1",
65
+ warningText: "#5D4037",
60
66
  shadow: "0 1px 3px rgba(12, 31, 39, 0.08)",
61
67
  shadowLg: "0 20px 48px rgba(19, 61, 75, 0.14)",
62
68
  radius: "14px",
@@ -1388,703 +1394,6 @@ function Spinner({ size = 40, label }) {
1388
1394
  }
1389
1395
  );
1390
1396
  }
1391
- function ProviderCard({ provider, selected, onClick }) {
1392
- const { tokens } = useSwypeConfig();
1393
- const [hovered, setHovered] = useState(false);
1394
- return /* @__PURE__ */ jsxs(
1395
- "button",
1396
- {
1397
- onClick,
1398
- onMouseEnter: () => setHovered(true),
1399
- onMouseLeave: () => setHovered(false),
1400
- style: {
1401
- display: "flex",
1402
- alignItems: "center",
1403
- gap: "12px",
1404
- width: "100%",
1405
- padding: "14px 16px",
1406
- background: selected ? tokens.accent + "18" : hovered ? tokens.bgHover : tokens.bgInput,
1407
- border: `1.5px solid ${selected ? tokens.accent : tokens.border}`,
1408
- borderRadius: tokens.radiusLg,
1409
- cursor: "pointer",
1410
- transition: "all 0.15s ease",
1411
- color: tokens.text,
1412
- fontFamily: "inherit",
1413
- fontSize: "0.95rem",
1414
- fontWeight: 500,
1415
- textAlign: "left",
1416
- outline: "none"
1417
- },
1418
- children: [
1419
- provider.logoURI ? /* @__PURE__ */ jsx(
1420
- "img",
1421
- {
1422
- src: provider.logoURI,
1423
- alt: provider.name,
1424
- style: {
1425
- width: 32,
1426
- height: 32,
1427
- borderRadius: "50%",
1428
- objectFit: "contain"
1429
- }
1430
- }
1431
- ) : /* @__PURE__ */ jsx(
1432
- "div",
1433
- {
1434
- style: {
1435
- width: 32,
1436
- height: 32,
1437
- borderRadius: "50%",
1438
- background: tokens.accent + "30",
1439
- display: "flex",
1440
- alignItems: "center",
1441
- justifyContent: "center",
1442
- fontSize: "0.875rem",
1443
- fontWeight: 700,
1444
- color: tokens.accent,
1445
- flexShrink: 0
1446
- },
1447
- children: provider.name.charAt(0).toUpperCase()
1448
- }
1449
- ),
1450
- /* @__PURE__ */ jsx("span", { children: provider.name }),
1451
- selected && /* @__PURE__ */ jsx(
1452
- "svg",
1453
- {
1454
- width: "18",
1455
- height: "18",
1456
- viewBox: "0 0 24 24",
1457
- fill: "none",
1458
- style: { marginLeft: "auto", flexShrink: 0 },
1459
- children: /* @__PURE__ */ jsx(
1460
- "path",
1461
- {
1462
- d: "M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41L9 16.17z",
1463
- fill: tokens.accent
1464
- }
1465
- )
1466
- }
1467
- )
1468
- ]
1469
- }
1470
- );
1471
- }
1472
- function AccountDropdown({
1473
- accounts,
1474
- selectedAccountId,
1475
- onSelect,
1476
- selectedWalletId,
1477
- onWalletSelect
1478
- }) {
1479
- const { tokens } = useSwypeConfig();
1480
- const [open, setOpen] = useState(false);
1481
- const containerRef = useRef(null);
1482
- const selected = accounts.find((a) => a.id === selectedAccountId);
1483
- const selectedWallet = selected?.wallets.find(
1484
- (w) => w.id === selectedWalletId
1485
- );
1486
- useEffect(() => {
1487
- if (!open) return;
1488
- const handleClick = (e) => {
1489
- if (containerRef.current && !containerRef.current.contains(e.target)) {
1490
- setOpen(false);
1491
- }
1492
- };
1493
- document.addEventListener("mousedown", handleClick);
1494
- return () => document.removeEventListener("mousedown", handleClick);
1495
- }, [open]);
1496
- if (accounts.length === 0) return null;
1497
- const hasMultipleChoices = accounts.length > 1 || accounts.length === 1 && onWalletSelect && accounts[0].wallets.filter((w) => w.balance.available.amount > 0).length > 1;
1498
- if (!hasMultipleChoices) {
1499
- return /* @__PURE__ */ jsxs(
1500
- "div",
1501
- {
1502
- style: {
1503
- display: "flex",
1504
- alignItems: "center",
1505
- gap: "6px",
1506
- fontSize: "0.85rem",
1507
- color: tokens.textSecondary
1508
- },
1509
- children: [
1510
- /* @__PURE__ */ jsx("span", { style: { fontWeight: 500 }, children: accounts[0].name }),
1511
- (selectedWallet ?? accounts[0].wallets[0]) && /* @__PURE__ */ jsx(
1512
- "span",
1513
- {
1514
- style: {
1515
- fontSize: "0.75rem",
1516
- color: tokens.textMuted,
1517
- fontFamily: '"SF Mono", "Fira Code", monospace'
1518
- },
1519
- children: selectedWallet ? `${selectedWallet.chain.name} \xB7 ${selectedWallet.name}` : accounts[0].wallets[0]?.name
1520
- }
1521
- )
1522
- ]
1523
- }
1524
- );
1525
- }
1526
- const getAccountBalance = (account) => {
1527
- let total = 0;
1528
- for (const w of account.wallets) {
1529
- total += w.balance.available.amount;
1530
- }
1531
- return total > 0 ? `$${total.toFixed(2)}` : "";
1532
- };
1533
- const hasActiveWallet = (account) => account.wallets.some((w) => w.status === "ACTIVE");
1534
- return /* @__PURE__ */ jsxs("div", { ref: containerRef, style: { position: "relative" }, children: [
1535
- /* @__PURE__ */ jsxs(
1536
- "button",
1537
- {
1538
- onClick: () => setOpen(!open),
1539
- style: {
1540
- display: "flex",
1541
- alignItems: "center",
1542
- gap: "6px",
1543
- background: tokens.bgCard,
1544
- border: `1px solid ${tokens.border}`,
1545
- cursor: "pointer",
1546
- padding: "7px 10px",
1547
- borderRadius: "999px",
1548
- color: tokens.textSecondary,
1549
- fontFamily: "inherit",
1550
- fontSize: "0.85rem",
1551
- outline: "none"
1552
- },
1553
- children: [
1554
- /* @__PURE__ */ jsx("span", { style: { fontWeight: 500, color: tokens.text }, children: selected?.name ?? "Select account" }),
1555
- (selectedWallet ?? selected?.wallets?.[0]) && /* @__PURE__ */ jsx(
1556
- "span",
1557
- {
1558
- style: {
1559
- fontSize: "0.75rem",
1560
- color: tokens.textMuted,
1561
- fontFamily: '"SF Mono", "Fira Code", monospace'
1562
- },
1563
- children: selectedWallet ? `${selectedWallet.chain.name} \xB7 ${selectedWallet.name}` : selected.wallets[0].name
1564
- }
1565
- ),
1566
- /* @__PURE__ */ jsx(
1567
- "svg",
1568
- {
1569
- width: "12",
1570
- height: "12",
1571
- viewBox: "0 0 24 24",
1572
- fill: "none",
1573
- style: {
1574
- transform: open ? "rotate(180deg)" : "rotate(0deg)",
1575
- transition: "transform 0.15s ease",
1576
- flexShrink: 0
1577
- },
1578
- children: /* @__PURE__ */ jsx(
1579
- "path",
1580
- {
1581
- d: "M7 10l5 5 5-5",
1582
- stroke: tokens.textMuted,
1583
- strokeWidth: "2",
1584
- strokeLinecap: "round",
1585
- strokeLinejoin: "round"
1586
- }
1587
- )
1588
- }
1589
- )
1590
- ]
1591
- }
1592
- ),
1593
- open && /* @__PURE__ */ jsx(
1594
- "div",
1595
- {
1596
- style: {
1597
- position: "absolute",
1598
- top: "100%",
1599
- left: 0,
1600
- right: 0,
1601
- marginTop: "4px",
1602
- background: tokens.bgCard,
1603
- border: `1px solid ${tokens.border}`,
1604
- borderRadius: tokens.radiusLg,
1605
- boxShadow: tokens.shadowLg,
1606
- zIndex: 50,
1607
- overflow: "hidden",
1608
- minWidth: "220px"
1609
- },
1610
- children: accounts.map((account) => {
1611
- const isAcctSelected = account.id === selectedAccountId;
1612
- const balance = getAccountBalance(account);
1613
- const active = hasActiveWallet(account);
1614
- const walletsWithBalance = account.wallets.filter(
1615
- (w) => w.balance.available.amount > 0
1616
- );
1617
- const showWallets = onWalletSelect && walletsWithBalance.length > 0;
1618
- return /* @__PURE__ */ jsxs("div", { children: [
1619
- /* @__PURE__ */ jsxs(
1620
- "button",
1621
- {
1622
- onClick: () => {
1623
- onSelect(account.id);
1624
- if (!showWallets) setOpen(false);
1625
- },
1626
- style: {
1627
- display: "flex",
1628
- alignItems: "center",
1629
- justifyContent: "space-between",
1630
- width: "100%",
1631
- padding: "10px 14px",
1632
- background: isAcctSelected && !selectedWalletId ? tokens.accent + "12" : "transparent",
1633
- border: "none",
1634
- borderBottom: showWallets ? "none" : `1px solid ${tokens.border}`,
1635
- cursor: "pointer",
1636
- color: tokens.text,
1637
- fontFamily: "inherit",
1638
- fontSize: "0.85rem",
1639
- textAlign: "left",
1640
- outline: "none",
1641
- transition: "background 0.1s ease"
1642
- },
1643
- children: [
1644
- /* @__PURE__ */ jsxs("div", { style: { minWidth: 0, flex: 1 }, children: [
1645
- /* @__PURE__ */ jsxs(
1646
- "div",
1647
- {
1648
- style: {
1649
- display: "flex",
1650
- alignItems: "center",
1651
- gap: "6px"
1652
- },
1653
- children: [
1654
- /* @__PURE__ */ jsx("span", { style: { fontWeight: 500 }, children: account.name }),
1655
- active && /* @__PURE__ */ jsx(
1656
- "span",
1657
- {
1658
- style: {
1659
- fontSize: "0.6rem",
1660
- fontWeight: 600,
1661
- color: tokens.success,
1662
- background: tokens.successBg,
1663
- padding: "2px 7px",
1664
- borderRadius: "999px",
1665
- textTransform: "uppercase",
1666
- letterSpacing: "0.03em"
1667
- },
1668
- children: "Active"
1669
- }
1670
- )
1671
- ]
1672
- }
1673
- ),
1674
- balance && /* @__PURE__ */ jsx(
1675
- "div",
1676
- {
1677
- style: {
1678
- fontSize: "0.75rem",
1679
- color: tokens.textMuted,
1680
- marginTop: "2px"
1681
- },
1682
- children: balance
1683
- }
1684
- )
1685
- ] }),
1686
- isAcctSelected && !selectedWalletId && /* @__PURE__ */ jsx(
1687
- "svg",
1688
- {
1689
- width: "14",
1690
- height: "14",
1691
- viewBox: "0 0 24 24",
1692
- fill: "none",
1693
- style: { flexShrink: 0, marginLeft: "8px" },
1694
- children: /* @__PURE__ */ jsx(
1695
- "path",
1696
- {
1697
- d: "M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41L9 16.17z",
1698
- fill: tokens.accent
1699
- }
1700
- )
1701
- }
1702
- )
1703
- ]
1704
- }
1705
- ),
1706
- showWallets && walletsWithBalance.map((wallet, wIdx) => {
1707
- const isWalletSelected = isAcctSelected && wallet.id === selectedWalletId;
1708
- const walletBal = wallet.balance.available.amount > 0 ? `$${wallet.balance.available.amount.toFixed(2)}` : "";
1709
- const isLastWallet = wIdx === walletsWithBalance.length - 1;
1710
- return /* @__PURE__ */ jsxs(
1711
- "button",
1712
- {
1713
- onClick: () => {
1714
- onWalletSelect(account.id, wallet.id);
1715
- setOpen(false);
1716
- },
1717
- style: {
1718
- display: "flex",
1719
- alignItems: "center",
1720
- justifyContent: "space-between",
1721
- width: "100%",
1722
- padding: "8px 14px 8px 28px",
1723
- background: isWalletSelected ? tokens.accent + "12" : "transparent",
1724
- border: "none",
1725
- borderBottom: isLastWallet ? `1px solid ${tokens.border}` : "none",
1726
- cursor: "pointer",
1727
- color: tokens.text,
1728
- fontFamily: "inherit",
1729
- fontSize: "0.8rem",
1730
- textAlign: "left",
1731
- outline: "none",
1732
- transition: "background 0.1s ease"
1733
- },
1734
- children: [
1735
- /* @__PURE__ */ jsxs(
1736
- "div",
1737
- {
1738
- style: {
1739
- display: "flex",
1740
- alignItems: "center",
1741
- gap: "6px",
1742
- minWidth: 0,
1743
- flex: 1
1744
- },
1745
- children: [
1746
- /* @__PURE__ */ jsx(
1747
- "span",
1748
- {
1749
- style: {
1750
- fontWeight: 500,
1751
- fontSize: "0.8rem"
1752
- },
1753
- children: wallet.chain.name
1754
- }
1755
- ),
1756
- /* @__PURE__ */ jsx(
1757
- "span",
1758
- {
1759
- style: {
1760
- fontSize: "0.7rem",
1761
- color: tokens.textMuted,
1762
- fontFamily: '"SF Mono", "Fira Code", monospace'
1763
- },
1764
- children: wallet.name
1765
- }
1766
- ),
1767
- walletBal && /* @__PURE__ */ jsx(
1768
- "span",
1769
- {
1770
- style: {
1771
- fontSize: "0.7rem",
1772
- color: tokens.textMuted,
1773
- marginLeft: "auto"
1774
- },
1775
- children: walletBal
1776
- }
1777
- )
1778
- ]
1779
- }
1780
- ),
1781
- isWalletSelected && /* @__PURE__ */ jsx(
1782
- "svg",
1783
- {
1784
- width: "12",
1785
- height: "12",
1786
- viewBox: "0 0 24 24",
1787
- fill: "none",
1788
- style: {
1789
- flexShrink: 0,
1790
- marginLeft: "8px"
1791
- },
1792
- children: /* @__PURE__ */ jsx(
1793
- "path",
1794
- {
1795
- d: "M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41L9 16.17z",
1796
- fill: tokens.accent
1797
- }
1798
- )
1799
- }
1800
- )
1801
- ]
1802
- },
1803
- wallet.id
1804
- );
1805
- })
1806
- ] }, account.id);
1807
- })
1808
- }
1809
- )
1810
- ] });
1811
- }
1812
- var ASSETS = ["USDC", "USDT"];
1813
- function AdvancedSettings({
1814
- settings,
1815
- onChange,
1816
- chains,
1817
- providers,
1818
- onConnectNewAccount,
1819
- connectingNewAccount
1820
- }) {
1821
- const { tokens } = useSwypeConfig();
1822
- const [open, setOpen] = useState(false);
1823
- const [showProviders, setShowProviders] = useState(false);
1824
- return /* @__PURE__ */ jsxs("div", { style: { marginTop: "12px" }, children: [
1825
- /* @__PURE__ */ jsxs(
1826
- "button",
1827
- {
1828
- onClick: () => setOpen(!open),
1829
- style: {
1830
- display: "flex",
1831
- alignItems: "center",
1832
- gap: "6px",
1833
- background: "transparent",
1834
- border: "none",
1835
- cursor: "pointer",
1836
- padding: "4px 0",
1837
- color: tokens.textMuted,
1838
- fontFamily: "inherit",
1839
- fontSize: "0.8rem",
1840
- fontWeight: 500,
1841
- outline: "none",
1842
- letterSpacing: "0.02em"
1843
- },
1844
- children: [
1845
- /* @__PURE__ */ jsx(
1846
- "svg",
1847
- {
1848
- width: "10",
1849
- height: "10",
1850
- viewBox: "0 0 24 24",
1851
- fill: "none",
1852
- style: {
1853
- transform: open ? "rotate(180deg)" : "rotate(0deg)",
1854
- transition: "transform 0.15s ease"
1855
- },
1856
- children: /* @__PURE__ */ jsx(
1857
- "path",
1858
- {
1859
- d: "M7 10l5 5 5-5",
1860
- stroke: tokens.textMuted,
1861
- strokeWidth: "2.5",
1862
- strokeLinecap: "round",
1863
- strokeLinejoin: "round"
1864
- }
1865
- )
1866
- }
1867
- ),
1868
- "Advanced options"
1869
- ]
1870
- }
1871
- ),
1872
- open && /* @__PURE__ */ jsxs(
1873
- "div",
1874
- {
1875
- style: {
1876
- marginTop: "10px",
1877
- padding: "14px",
1878
- background: tokens.bgInput,
1879
- borderRadius: tokens.radiusLg,
1880
- border: `1px solid ${tokens.border}`
1881
- },
1882
- children: [
1883
- /* @__PURE__ */ jsxs("div", { style: { marginBottom: "14px" }, children: [
1884
- /* @__PURE__ */ jsx(
1885
- "label",
1886
- {
1887
- style: {
1888
- display: "block",
1889
- fontSize: "0.7rem",
1890
- fontWeight: 600,
1891
- color: tokens.textMuted,
1892
- textTransform: "uppercase",
1893
- letterSpacing: "0.05em",
1894
- marginBottom: "6px"
1895
- },
1896
- children: "Asset"
1897
- }
1898
- ),
1899
- /* @__PURE__ */ jsx("div", { style: { display: "flex", gap: "6px" }, children: ASSETS.map((asset) => {
1900
- const isSelected = settings.asset === asset;
1901
- return /* @__PURE__ */ jsx(
1902
- "button",
1903
- {
1904
- onClick: () => onChange({
1905
- ...settings,
1906
- asset: isSelected ? null : asset
1907
- }),
1908
- style: {
1909
- padding: "7px 14px",
1910
- fontSize: "0.8rem",
1911
- fontWeight: 600,
1912
- fontFamily: "inherit",
1913
- borderRadius: "999px",
1914
- border: `1.5px solid ${isSelected ? tokens.accent : tokens.border}`,
1915
- background: isSelected ? tokens.accent + "18" : tokens.bgCard,
1916
- color: isSelected ? tokens.accent : tokens.text,
1917
- cursor: "pointer",
1918
- outline: "none",
1919
- transition: "all 0.12s ease"
1920
- },
1921
- children: asset
1922
- },
1923
- asset
1924
- );
1925
- }) })
1926
- ] }),
1927
- chains.length > 0 && /* @__PURE__ */ jsxs("div", { style: { marginBottom: "14px" }, children: [
1928
- /* @__PURE__ */ jsx(
1929
- "label",
1930
- {
1931
- style: {
1932
- display: "block",
1933
- fontSize: "0.7rem",
1934
- fontWeight: 600,
1935
- color: tokens.textMuted,
1936
- textTransform: "uppercase",
1937
- letterSpacing: "0.05em",
1938
- marginBottom: "6px"
1939
- },
1940
- children: "Chain"
1941
- }
1942
- ),
1943
- /* @__PURE__ */ jsx("div", { style: { display: "flex", flexWrap: "wrap", gap: "6px" }, children: chains.map((chain) => {
1944
- const isSelected = settings.chain === chain.name;
1945
- return /* @__PURE__ */ jsx(
1946
- "button",
1947
- {
1948
- onClick: () => onChange({
1949
- ...settings,
1950
- chain: isSelected ? null : chain.name
1951
- }),
1952
- style: {
1953
- padding: "7px 14px",
1954
- fontSize: "0.8rem",
1955
- fontWeight: 600,
1956
- fontFamily: "inherit",
1957
- borderRadius: "999px",
1958
- border: `1.5px solid ${isSelected ? tokens.accent : tokens.border}`,
1959
- background: isSelected ? tokens.accent + "18" : tokens.bgCard,
1960
- color: isSelected ? tokens.accent : tokens.text,
1961
- cursor: "pointer",
1962
- outline: "none",
1963
- transition: "all 0.12s ease"
1964
- },
1965
- children: chain.name
1966
- },
1967
- chain.id
1968
- );
1969
- }) })
1970
- ] }),
1971
- /* @__PURE__ */ jsx("div", { children: !showProviders ? /* @__PURE__ */ jsxs(
1972
- "button",
1973
- {
1974
- onClick: () => setShowProviders(true),
1975
- disabled: connectingNewAccount,
1976
- style: {
1977
- display: "flex",
1978
- alignItems: "center",
1979
- gap: "6px",
1980
- background: tokens.bgCard,
1981
- border: `1px dashed ${tokens.border}`,
1982
- borderRadius: "999px",
1983
- padding: "10px 14px",
1984
- width: "100%",
1985
- cursor: connectingNewAccount ? "not-allowed" : "pointer",
1986
- color: tokens.textSecondary,
1987
- fontFamily: "inherit",
1988
- fontSize: "0.825rem",
1989
- fontWeight: 500,
1990
- outline: "none",
1991
- opacity: connectingNewAccount ? 0.5 : 1,
1992
- transition: "opacity 0.1s ease"
1993
- },
1994
- children: [
1995
- /* @__PURE__ */ jsx(
1996
- "svg",
1997
- {
1998
- width: "14",
1999
- height: "14",
2000
- viewBox: "0 0 24 24",
2001
- fill: "none",
2002
- children: /* @__PURE__ */ jsx(
2003
- "path",
2004
- {
2005
- d: "M12 5v14M5 12h14",
2006
- stroke: tokens.textMuted,
2007
- strokeWidth: "2",
2008
- strokeLinecap: "round"
2009
- }
2010
- )
2011
- }
2012
- ),
2013
- "Connect new account"
2014
- ]
2015
- }
2016
- ) : /* @__PURE__ */ jsxs("div", { children: [
2017
- /* @__PURE__ */ jsxs(
2018
- "div",
2019
- {
2020
- style: {
2021
- display: "flex",
2022
- alignItems: "center",
2023
- justifyContent: "space-between",
2024
- marginBottom: "8px"
2025
- },
2026
- children: [
2027
- /* @__PURE__ */ jsx(
2028
- "label",
2029
- {
2030
- style: {
2031
- fontSize: "0.7rem",
2032
- fontWeight: 600,
2033
- color: tokens.textMuted,
2034
- textTransform: "uppercase",
2035
- letterSpacing: "0.05em"
2036
- },
2037
- children: "Select provider"
2038
- }
2039
- ),
2040
- /* @__PURE__ */ jsx(
2041
- "button",
2042
- {
2043
- onClick: () => setShowProviders(false),
2044
- style: {
2045
- background: "transparent",
2046
- border: "none",
2047
- cursor: "pointer",
2048
- color: tokens.textMuted,
2049
- fontSize: "0.75rem",
2050
- fontFamily: "inherit",
2051
- outline: "none",
2052
- padding: "2px 4px"
2053
- },
2054
- children: "Cancel"
2055
- }
2056
- )
2057
- ]
2058
- }
2059
- ),
2060
- /* @__PURE__ */ jsx(
2061
- "div",
2062
- {
2063
- style: {
2064
- display: "flex",
2065
- flexDirection: "column",
2066
- gap: "6px"
2067
- },
2068
- children: providers.map((p) => /* @__PURE__ */ jsx(
2069
- ProviderCard,
2070
- {
2071
- provider: p,
2072
- selected: false,
2073
- onClick: () => {
2074
- onConnectNewAccount(p.id);
2075
- setShowProviders(false);
2076
- }
2077
- },
2078
- p.id
2079
- ))
2080
- }
2081
- )
2082
- ] }) })
2083
- ]
2084
- }
2085
- )
2086
- ] });
2087
- }
2088
1397
 
2089
1398
  // src/auth.ts
2090
1399
  var EMAIL_PATTERN = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
@@ -2135,14 +1444,6 @@ function getTransferStatus(polledTransfer, localTransfer) {
2135
1444
  const transfer = resolvePreferredTransfer(polledTransfer, localTransfer);
2136
1445
  return transfer?.status ?? "UNKNOWN";
2137
1446
  }
2138
- function getDisplayTransferStatus(polledTransfer, localTransfer) {
2139
- return getTransferStatus(polledTransfer, localTransfer).toUpperCase();
2140
- }
2141
- function getTransferIdSuffix(polledTransfer, localTransfer) {
2142
- const transfer = resolvePreferredTransfer(polledTransfer, localTransfer);
2143
- if (!transfer?.id) return "n/a";
2144
- return transfer.id.slice(-8);
2145
- }
2146
1447
  function hasProcessingTimedOut(processingStartedAtMs, nowMs) {
2147
1448
  if (!processingStartedAtMs) return false;
2148
1449
  return nowMs - processingStartedAtMs >= PROCESSING_TIMEOUT_MS;
@@ -2162,98 +1463,1945 @@ function isMobileUserAgent(userAgent) {
2162
1463
  function shouldUseWalletConnector(options) {
2163
1464
  return options.useWalletConnector ?? !isMobileUserAgent(options.userAgent);
2164
1465
  }
2165
- var ACTIVE_CREDENTIAL_STORAGE_KEY = "swype_active_credential_id";
2166
- var MIN_SEND_AMOUNT_USD = 0.25;
2167
- function computeSmartDefaults(accts, transferAmount) {
2168
- if (accts.length === 0) return null;
2169
- for (const acct of accts) {
2170
- for (const wallet of acct.wallets) {
2171
- if (wallet.status === "ACTIVE") {
2172
- const bestSource = wallet.sources.find(
2173
- (s) => s.balance.available.amount >= transferAmount
2174
- );
2175
- if (bestSource) {
2176
- return { accountId: acct.id, walletId: wallet.id };
2177
- }
1466
+ function ScreenLayout({ children, footer }) {
1467
+ const { tokens } = useSwypeConfig();
1468
+ return /* @__PURE__ */ jsxs("div", { style: containerStyle(tokens.bgCard), children: [
1469
+ /* @__PURE__ */ jsx("div", { style: bodyStyle, children }),
1470
+ footer && /* @__PURE__ */ jsx("div", { style: footerStyle, children: footer })
1471
+ ] });
1472
+ }
1473
+ var containerStyle = (bg) => ({
1474
+ display: "flex",
1475
+ flexDirection: "column",
1476
+ minHeight: "100%",
1477
+ maxWidth: 420,
1478
+ width: "100%",
1479
+ margin: "0 auto",
1480
+ background: bg,
1481
+ fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
1482
+ boxSizing: "border-box"
1483
+ });
1484
+ var bodyStyle = {
1485
+ flex: 1,
1486
+ padding: "0 24px",
1487
+ display: "flex",
1488
+ flexDirection: "column"
1489
+ };
1490
+ var footerStyle = {
1491
+ padding: "16px 24px 24px",
1492
+ marginTop: "auto"
1493
+ };
1494
+ function ScreenHeader({ title, right, onBack, badge }) {
1495
+ const { tokens } = useSwypeConfig();
1496
+ return /* @__PURE__ */ jsxs("div", { style: headerStyle, children: [
1497
+ /* @__PURE__ */ jsx("div", { style: leftSlotStyle, children: onBack && /* @__PURE__ */ jsx("button", { type: "button", onClick: onBack, style: backButtonStyle(tokens.text), "aria-label": "Go back", children: /* @__PURE__ */ jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ jsx("path", { d: "M15 18l-6-6 6-6", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }) }) }),
1498
+ /* @__PURE__ */ jsxs("div", { style: centerSlotStyle, children: [
1499
+ title && /* @__PURE__ */ jsx("span", { style: titleStyle(tokens.text), children: title }),
1500
+ badge && /* @__PURE__ */ jsx("span", { style: badgeStyle(tokens.textMuted), children: badge })
1501
+ ] }),
1502
+ /* @__PURE__ */ jsx("div", { style: rightSlotStyle, children: right })
1503
+ ] });
1504
+ }
1505
+ var headerStyle = {
1506
+ display: "flex",
1507
+ alignItems: "center",
1508
+ padding: "16px 0",
1509
+ minHeight: 52
1510
+ };
1511
+ var leftSlotStyle = { flex: "0 0 40px" };
1512
+ var rightSlotStyle = { flex: "0 0 40px", display: "flex", justifyContent: "flex-end" };
1513
+ var centerSlotStyle = {
1514
+ flex: 1,
1515
+ display: "flex",
1516
+ alignItems: "center",
1517
+ justifyContent: "center",
1518
+ gap: 8
1519
+ };
1520
+ var backButtonStyle = (color) => ({
1521
+ background: "transparent",
1522
+ border: "none",
1523
+ cursor: "pointer",
1524
+ padding: 4,
1525
+ color,
1526
+ display: "flex",
1527
+ alignItems: "center",
1528
+ justifyContent: "center"
1529
+ });
1530
+ var titleStyle = (color) => ({
1531
+ fontSize: "0.9rem",
1532
+ fontWeight: 600,
1533
+ color,
1534
+ letterSpacing: "-0.01em"
1535
+ });
1536
+ var badgeStyle = (color) => ({
1537
+ fontSize: "0.78rem",
1538
+ fontWeight: 500,
1539
+ color
1540
+ });
1541
+ function PoweredByFooter() {
1542
+ const { tokens } = useSwypeConfig();
1543
+ return /* @__PURE__ */ jsxs("div", { style: containerStyle2(tokens.textMuted), children: [
1544
+ /* @__PURE__ */ jsx("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ jsx(
1545
+ "path",
1546
+ {
1547
+ d: "M18 8h-1V6c0-2.76-2.24-5-5-5S7 3.24 7 6v2H6c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V10c0-1.1-.9-2-2-2zM12 17c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2zm3-9H9V6c0-1.66 1.34-3 3-3s3 1.34 3 3v2z",
1548
+ fill: "currentColor"
2178
1549
  }
1550
+ ) }),
1551
+ /* @__PURE__ */ jsx("span", { children: "Powered by Swype" }),
1552
+ /* @__PURE__ */ jsx("span", { style: dotStyle, children: "\xB7" }),
1553
+ /* @__PURE__ */ jsx("span", { children: "Non-custodial" })
1554
+ ] });
1555
+ }
1556
+ var containerStyle2 = (color) => ({
1557
+ display: "flex",
1558
+ alignItems: "center",
1559
+ justifyContent: "center",
1560
+ gap: 6,
1561
+ fontSize: "0.75rem",
1562
+ color,
1563
+ padding: "12px 0 4px"
1564
+ });
1565
+ var dotStyle = { opacity: 0.5 };
1566
+ function PrimaryButton({ children, onClick, disabled, loading, icon }) {
1567
+ const { tokens } = useSwypeConfig();
1568
+ const isDisabled = disabled || loading;
1569
+ return /* @__PURE__ */ jsxs(
1570
+ "button",
1571
+ {
1572
+ type: "button",
1573
+ onClick,
1574
+ disabled: isDisabled,
1575
+ style: buttonStyle(tokens, isDisabled),
1576
+ children: [
1577
+ icon && /* @__PURE__ */ jsx("span", { style: iconWrapStyle, children: icon }),
1578
+ loading ? "Please wait..." : children
1579
+ ]
2179
1580
  }
2180
- }
2181
- let bestAccount = null;
2182
- let bestWallet = null;
2183
- let bestBalance = -1;
2184
- let bestIsActive = false;
2185
- for (const acct of accts) {
2186
- for (const wallet of acct.wallets) {
2187
- const walletBal = wallet.balance.available.amount;
2188
- const isActive = wallet.status === "ACTIVE";
2189
- if (walletBal > bestBalance || walletBal === bestBalance && isActive && !bestIsActive) {
2190
- bestBalance = walletBal;
2191
- bestAccount = acct;
2192
- bestWallet = wallet;
2193
- bestIsActive = isActive;
2194
- }
1581
+ );
1582
+ }
1583
+ var buttonStyle = (tokens, disabled) => ({
1584
+ width: "100%",
1585
+ padding: "16px 24px",
1586
+ background: `linear-gradient(180deg, ${tokens.accent}, ${tokens.accentHover})`,
1587
+ color: tokens.accentText,
1588
+ border: "none",
1589
+ borderRadius: 999,
1590
+ fontSize: "1rem",
1591
+ fontWeight: 700,
1592
+ cursor: disabled ? "not-allowed" : "pointer",
1593
+ opacity: disabled ? 0.5 : 1,
1594
+ transition: "filter 0.15s ease, transform 0.15s ease",
1595
+ fontFamily: "inherit",
1596
+ boxShadow: "0 8px 18px rgba(40, 182, 122, 0.22)",
1597
+ display: "flex",
1598
+ alignItems: "center",
1599
+ justifyContent: "center",
1600
+ gap: 8
1601
+ });
1602
+ var iconWrapStyle = {
1603
+ display: "flex",
1604
+ alignItems: "center"
1605
+ };
1606
+ function OutlineButton({ children, onClick, disabled }) {
1607
+ const { tokens } = useSwypeConfig();
1608
+ return /* @__PURE__ */ jsx(
1609
+ "button",
1610
+ {
1611
+ type: "button",
1612
+ onClick,
1613
+ disabled,
1614
+ style: buttonStyle2(tokens, disabled),
1615
+ children
2195
1616
  }
1617
+ );
1618
+ }
1619
+ var buttonStyle2 = (tokens, disabled) => ({
1620
+ width: "100%",
1621
+ padding: "16px 24px",
1622
+ background: tokens.bgCard,
1623
+ color: tokens.text,
1624
+ border: `1.5px solid ${tokens.border}`,
1625
+ borderRadius: 999,
1626
+ fontSize: "0.95rem",
1627
+ fontWeight: 600,
1628
+ cursor: disabled ? "not-allowed" : "pointer",
1629
+ opacity: disabled ? 0.5 : 1,
1630
+ fontFamily: "inherit",
1631
+ transition: "opacity 0.15s ease"
1632
+ });
1633
+ var defaultIcon = /* @__PURE__ */ jsx("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ jsx(
1634
+ "path",
1635
+ {
1636
+ d: "M12 1L3 5v6c0 5.55 3.84 10.74 9 12 5.16-1.26 9-6.45 9-12V5l-9-4zm0 10.99h7c-.53 4.12-3.28 7.79-7 8.94V12H5V6.3l7-3.11v8.8z",
1637
+ fill: "currentColor"
2196
1638
  }
2197
- if (bestAccount) {
2198
- return {
2199
- accountId: bestAccount.id,
2200
- walletId: bestWallet?.id ?? null
2201
- };
2202
- }
2203
- return { accountId: accts[0].id, walletId: null };
1639
+ ) });
1640
+ function InfoBanner({ children, icon }) {
1641
+ const { tokens } = useSwypeConfig();
1642
+ return /* @__PURE__ */ jsxs("div", { style: containerStyle3(tokens.accent), children: [
1643
+ /* @__PURE__ */ jsx("span", { style: iconStyle, children: icon ?? defaultIcon }),
1644
+ /* @__PURE__ */ jsx("span", { style: textStyle, children })
1645
+ ] });
2204
1646
  }
2205
- function parseRawBalance(rawBalance, decimals) {
2206
- const parsed = Number(rawBalance);
2207
- if (!Number.isFinite(parsed)) return 0;
2208
- return parsed / 10 ** decimals;
1647
+ var containerStyle3 = (accent) => ({
1648
+ display: "flex",
1649
+ alignItems: "flex-start",
1650
+ gap: 10,
1651
+ padding: "14px 16px",
1652
+ background: `${accent}0D`,
1653
+ borderRadius: 16,
1654
+ fontSize: "0.82rem",
1655
+ lineHeight: 1.5,
1656
+ color: "inherit"
1657
+ });
1658
+ var iconStyle = {
1659
+ flexShrink: 0,
1660
+ marginTop: 1,
1661
+ display: "flex"
1662
+ };
1663
+ var textStyle = { flex: 1 };
1664
+ function WarningBanner({ title, children }) {
1665
+ return /* @__PURE__ */ jsxs("div", { style: containerStyle4, children: [
1666
+ /* @__PURE__ */ jsxs("div", { style: headerStyle2, children: [
1667
+ /* @__PURE__ */ jsx("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", style: iconStyle2, children: /* @__PURE__ */ jsx("path", { d: "M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z", fill: "#F57C00" }) }),
1668
+ /* @__PURE__ */ jsx("strong", { children: title })
1669
+ ] }),
1670
+ /* @__PURE__ */ jsx("div", { style: bodyStyle2, children })
1671
+ ] });
2209
1672
  }
2210
- function buildSelectSourceChoices(options) {
2211
- const chainChoices = [];
2212
- const chainIndexByName = /* @__PURE__ */ new Map();
2213
- for (const option of options) {
2214
- const chainName = option.chainName;
2215
- const tokenSymbol = option.tokenSymbol;
2216
- const balance = parseRawBalance(option.rawBalance, option.decimals);
2217
- let chainChoice;
2218
- const existingChainIdx = chainIndexByName.get(chainName);
2219
- if (existingChainIdx === void 0) {
2220
- chainChoice = { chainName, balance: 0, tokens: [] };
2221
- chainIndexByName.set(chainName, chainChoices.length);
2222
- chainChoices.push(chainChoice);
2223
- } else {
2224
- chainChoice = chainChoices[existingChainIdx];
1673
+ var containerStyle4 = {
1674
+ padding: "14px 16px",
1675
+ background: "#FFF8E1",
1676
+ border: "1px solid #FFE082",
1677
+ borderRadius: 16,
1678
+ fontSize: "0.84rem",
1679
+ lineHeight: 1.5,
1680
+ color: "#5D4037"
1681
+ };
1682
+ var headerStyle2 = {
1683
+ display: "flex",
1684
+ alignItems: "center",
1685
+ gap: 8,
1686
+ marginBottom: 4,
1687
+ fontWeight: 600,
1688
+ color: "#37474F"
1689
+ };
1690
+ var iconStyle2 = { flexShrink: 0 };
1691
+ var bodyStyle2 = { color: "#6D4C41" };
1692
+ function IconCircle({ children, variant = "accent", size = 56 }) {
1693
+ const { tokens } = useSwypeConfig();
1694
+ const bgMap = {
1695
+ accent: `${tokens.accent}18`,
1696
+ success: tokens.successBg,
1697
+ error: tokens.errorBg
1698
+ };
1699
+ return /* @__PURE__ */ jsx("div", { style: circleStyle(bgMap[variant], size), children });
1700
+ }
1701
+ var circleStyle = (bg, size) => ({
1702
+ width: size,
1703
+ height: size,
1704
+ borderRadius: "50%",
1705
+ background: bg,
1706
+ display: "flex",
1707
+ alignItems: "center",
1708
+ justifyContent: "center",
1709
+ margin: "0 auto",
1710
+ flexShrink: 0
1711
+ });
1712
+ function OtpInput({ value, onChange, length = 6, disabled }) {
1713
+ const { tokens } = useSwypeConfig();
1714
+ const inputsRef = useRef([]);
1715
+ const digits = value.padEnd(length, "").split("").slice(0, length);
1716
+ const focusInput = useCallback((index) => {
1717
+ const clamped = Math.max(0, Math.min(index, length - 1));
1718
+ inputsRef.current[clamped]?.focus();
1719
+ }, [length]);
1720
+ const handleChange = useCallback((index, char) => {
1721
+ const digit = char.replace(/\D/g, "").slice(0, 1);
1722
+ const next = digits.slice();
1723
+ next[index] = digit;
1724
+ const joined = next.join("").replace(/\s/g, "");
1725
+ onChange(joined);
1726
+ if (digit && index < length - 1) {
1727
+ focusInput(index + 1);
2225
1728
  }
2226
- chainChoice.balance += balance;
2227
- const existingToken = chainChoice.tokens.find((token) => token.tokenSymbol === tokenSymbol);
2228
- if (existingToken) {
2229
- existingToken.balance += balance;
2230
- } else {
2231
- chainChoice.tokens.push({ tokenSymbol, balance });
1729
+ }, [digits, onChange, length, focusInput]);
1730
+ const handleKeyDown = useCallback((index, e) => {
1731
+ if (e.key === "Backspace" && !digits[index] && index > 0) {
1732
+ focusInput(index - 1);
1733
+ } else if (e.key === "ArrowLeft" && index > 0) {
1734
+ focusInput(index - 1);
1735
+ } else if (e.key === "ArrowRight" && index < length - 1) {
1736
+ focusInput(index + 1);
2232
1737
  }
2233
- }
2234
- return chainChoices;
1738
+ }, [digits, focusInput, length]);
1739
+ const handlePaste = useCallback((e) => {
1740
+ e.preventDefault();
1741
+ const pasted = e.clipboardData.getData("text").replace(/\D/g, "").slice(0, length);
1742
+ onChange(pasted);
1743
+ focusInput(Math.min(pasted.length, length - 1));
1744
+ }, [onChange, length, focusInput]);
1745
+ return /* @__PURE__ */ jsx("div", { style: containerStyle5, children: digits.map((digit, i) => /* @__PURE__ */ jsx(
1746
+ "input",
1747
+ {
1748
+ ref: (el) => {
1749
+ inputsRef.current[i] = el;
1750
+ },
1751
+ type: "text",
1752
+ inputMode: "numeric",
1753
+ autoComplete: i === 0 ? "one-time-code" : "off",
1754
+ maxLength: 1,
1755
+ value: digit.trim(),
1756
+ disabled,
1757
+ onChange: (e) => handleChange(i, e.target.value),
1758
+ onKeyDown: (e) => handleKeyDown(i, e),
1759
+ onPaste: i === 0 ? handlePaste : void 0,
1760
+ onFocus: (e) => e.target.select(),
1761
+ style: inputStyle(tokens, !!digit.trim())
1762
+ },
1763
+ i
1764
+ )) });
2235
1765
  }
2236
- function SwypePayment({
2237
- destination,
2238
- onComplete,
2239
- onError,
2240
- useWalletConnector,
2241
- idempotencyKey,
2242
- merchantAuthorization
1766
+ var containerStyle5 = {
1767
+ display: "flex",
1768
+ gap: 8,
1769
+ justifyContent: "center"
1770
+ };
1771
+ var inputStyle = (tokens, filled) => ({
1772
+ width: 44,
1773
+ height: 52,
1774
+ borderRadius: 12,
1775
+ border: `1.5px solid ${filled ? tokens.borderFocus : tokens.border}`,
1776
+ background: tokens.bgInput,
1777
+ color: tokens.text,
1778
+ fontSize: "1.25rem",
1779
+ fontWeight: 600,
1780
+ fontFamily: "inherit",
1781
+ textAlign: "center",
1782
+ outline: "none",
1783
+ caretColor: tokens.borderFocus,
1784
+ transition: "border-color 0.15s ease"
1785
+ });
1786
+ function LimitSlider({
1787
+ value,
1788
+ min,
1789
+ max,
1790
+ step = 1,
1791
+ onChange,
1792
+ ticks,
1793
+ disabled
2243
1794
  }) {
2244
- const { apiBaseUrl, tokens, depositAmount } = useSwypeConfig();
2245
- const { ready, authenticated, user, logout, getAccessToken } = usePrivy();
2246
- const {
2247
- sendCode: sendEmailCode,
2248
- loginWithCode: loginWithEmailCode,
2249
- state: emailLoginState
2250
- } = useLoginWithEmail();
2251
- const {
2252
- sendCode: sendSmsCode,
2253
- loginWithCode: loginWithSmsCode,
2254
- state: smsLoginState
2255
- } = useLoginWithSms();
2256
- const [step, setStep] = useState("login");
1795
+ const { tokens } = useSwypeConfig();
1796
+ const pct = (value - min) / (max - min) * 100;
1797
+ const handleChange = useCallback(
1798
+ (e) => onChange(Number(e.target.value)),
1799
+ [onChange]
1800
+ );
1801
+ return /* @__PURE__ */ jsxs("div", { className: "swype-slider-wrap", style: wrapperStyle, children: [
1802
+ /* @__PURE__ */ jsxs("div", { style: trackContainerStyle, children: [
1803
+ /* @__PURE__ */ jsx("div", { style: trackBgStyle(tokens.border) }),
1804
+ /* @__PURE__ */ jsx("div", { style: trackFillStyle(tokens.accent, pct) }),
1805
+ /* @__PURE__ */ jsx(
1806
+ "input",
1807
+ {
1808
+ type: "range",
1809
+ min,
1810
+ max,
1811
+ step,
1812
+ value,
1813
+ onChange: handleChange,
1814
+ disabled,
1815
+ style: rangeInputStyle
1816
+ }
1817
+ )
1818
+ ] }),
1819
+ ticks && ticks.length > 0 && /* @__PURE__ */ jsx("div", { style: ticksStyle, children: ticks.map((tick) => /* @__PURE__ */ jsxs("span", { style: tickLabelStyle(tokens.textMuted), children: [
1820
+ "$",
1821
+ tick
1822
+ ] }, tick)) }),
1823
+ /* @__PURE__ */ jsx("style", { children: sliderThumbCss(tokens.accent) })
1824
+ ] });
1825
+ }
1826
+ var wrapperStyle = { width: "100%" };
1827
+ var trackContainerStyle = {
1828
+ position: "relative",
1829
+ height: 28,
1830
+ display: "flex",
1831
+ alignItems: "center"
1832
+ };
1833
+ var trackBgStyle = (color) => ({
1834
+ position: "absolute",
1835
+ left: 0,
1836
+ right: 0,
1837
+ height: 4,
1838
+ borderRadius: 2,
1839
+ background: color
1840
+ });
1841
+ var trackFillStyle = (color, pct) => ({
1842
+ position: "absolute",
1843
+ left: 0,
1844
+ width: `${pct}%`,
1845
+ height: 4,
1846
+ borderRadius: 2,
1847
+ background: color
1848
+ });
1849
+ var rangeInputStyle = {
1850
+ position: "absolute",
1851
+ left: 0,
1852
+ right: 0,
1853
+ width: "100%",
1854
+ height: 28,
1855
+ margin: 0,
1856
+ cursor: "pointer",
1857
+ zIndex: 2,
1858
+ WebkitAppearance: "none",
1859
+ appearance: "none",
1860
+ background: "transparent"
1861
+ };
1862
+ var ticksStyle = {
1863
+ display: "flex",
1864
+ justifyContent: "space-between",
1865
+ marginTop: 6
1866
+ };
1867
+ var tickLabelStyle = (color) => ({
1868
+ fontSize: "0.72rem",
1869
+ fontWeight: 500,
1870
+ color
1871
+ });
1872
+ var sliderThumbCss = (accent) => `
1873
+ .swype-slider-wrap input[type="range"]::-webkit-slider-runnable-track {
1874
+ height: 4px;
1875
+ background: transparent;
1876
+ }
1877
+ .swype-slider-wrap input[type="range"]::-webkit-slider-thumb {
1878
+ -webkit-appearance: none;
1879
+ width: 20px;
1880
+ height: 20px;
1881
+ border-radius: 50%;
1882
+ background: ${accent};
1883
+ border: 3px solid #fff;
1884
+ box-shadow: 0 2px 6px rgba(0,0,0,0.15);
1885
+ cursor: pointer;
1886
+ margin-top: -8px;
1887
+ }
1888
+ .swype-slider-wrap input[type="range"]::-moz-range-track {
1889
+ height: 4px;
1890
+ background: transparent;
1891
+ border: none;
1892
+ }
1893
+ .swype-slider-wrap input[type="range"]::-moz-range-thumb {
1894
+ width: 14px;
1895
+ height: 14px;
1896
+ border-radius: 50%;
1897
+ background: ${accent};
1898
+ border: 3px solid #fff;
1899
+ box-shadow: 0 2px 6px rgba(0,0,0,0.15);
1900
+ cursor: pointer;
1901
+ }
1902
+ `;
1903
+ function SourceCard({ name, address, verified, onChangeSource }) {
1904
+ const { tokens } = useSwypeConfig();
1905
+ return /* @__PURE__ */ jsxs("div", { style: containerStyle6(tokens), children: [
1906
+ /* @__PURE__ */ jsxs("div", { style: leftStyle, children: [
1907
+ /* @__PURE__ */ jsx("div", { style: iconStyle3(tokens.textMuted), children: /* @__PURE__ */ jsx("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ jsx(
1908
+ "path",
1909
+ {
1910
+ d: "M21 7H3c-1.1 0-2 .9-2 2v6c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2V9c0-1.1-.9-2-2-2zm0 8H3V9h18v6z",
1911
+ fill: "currentColor"
1912
+ }
1913
+ ) }) }),
1914
+ /* @__PURE__ */ jsxs("div", { children: [
1915
+ /* @__PURE__ */ jsxs("div", { style: nameRowStyle, children: [
1916
+ /* @__PURE__ */ jsx("span", { style: nameStyle(tokens.text), children: name }),
1917
+ verified && /* @__PURE__ */ jsx("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ jsx("path", { d: "M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41L9 16.17z", fill: tokens.accent }) })
1918
+ ] }),
1919
+ address && /* @__PURE__ */ jsx("span", { style: addressStyle(tokens.textMuted), children: address })
1920
+ ] })
1921
+ ] }),
1922
+ onChangeSource && /* @__PURE__ */ jsx("button", { type: "button", onClick: onChangeSource, style: changeStyle(tokens.accent), children: "Change source" })
1923
+ ] });
1924
+ }
1925
+ var containerStyle6 = (tokens) => ({
1926
+ display: "flex",
1927
+ alignItems: "center",
1928
+ justifyContent: "space-between",
1929
+ padding: "12px 16px",
1930
+ background: tokens.bgInput,
1931
+ border: `1px solid ${tokens.border}`,
1932
+ borderRadius: 16
1933
+ });
1934
+ var leftStyle = {
1935
+ display: "flex",
1936
+ alignItems: "center",
1937
+ gap: 10
1938
+ };
1939
+ var iconStyle3 = (color) => ({
1940
+ color,
1941
+ display: "flex",
1942
+ alignItems: "center"
1943
+ });
1944
+ var nameRowStyle = {
1945
+ display: "flex",
1946
+ alignItems: "center",
1947
+ gap: 4
1948
+ };
1949
+ var nameStyle = (color) => ({
1950
+ fontWeight: 600,
1951
+ fontSize: "0.9rem",
1952
+ color
1953
+ });
1954
+ var addressStyle = (color) => ({
1955
+ fontSize: "0.72rem",
1956
+ color,
1957
+ fontFamily: '"SF Mono", "Fira Code", monospace'
1958
+ });
1959
+ var changeStyle = (color) => ({
1960
+ background: "transparent",
1961
+ border: "none",
1962
+ color,
1963
+ fontWeight: 600,
1964
+ fontSize: "0.82rem",
1965
+ cursor: "pointer",
1966
+ fontFamily: "inherit",
1967
+ padding: 0
1968
+ });
1969
+ function StepList({ steps }) {
1970
+ const { tokens } = useSwypeConfig();
1971
+ return /* @__PURE__ */ jsx("div", { style: listStyle, children: steps.map((step, i) => {
1972
+ const isComplete = step.status === "complete";
1973
+ const isActive = step.status === "active";
1974
+ return /* @__PURE__ */ jsxs("div", { style: rowStyle, children: [
1975
+ /* @__PURE__ */ jsx(
1976
+ "div",
1977
+ {
1978
+ style: badgeStyle2(
1979
+ isComplete ? tokens.accent : isActive ? tokens.accent : tokens.border,
1980
+ isComplete || isActive
1981
+ ),
1982
+ children: isComplete ? /* @__PURE__ */ jsx("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ jsx("path", { d: "M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41L9 16.17z", fill: "#fff" }) }) : /* @__PURE__ */ jsx("span", { style: badgeNumberStyle(isActive), children: i + 1 })
1983
+ }
1984
+ ),
1985
+ /* @__PURE__ */ jsxs("div", { style: labelContainerStyle, children: [
1986
+ /* @__PURE__ */ jsx("span", { style: labelStyle(isComplete || isActive ? tokens.text : tokens.textMuted), children: step.label }),
1987
+ step.detail && /* @__PURE__ */ jsx("span", { style: detailStyle(tokens.textMuted), children: step.detail })
1988
+ ] })
1989
+ ] }, i);
1990
+ }) });
1991
+ }
1992
+ var listStyle = {
1993
+ display: "flex",
1994
+ flexDirection: "column",
1995
+ gap: 12
1996
+ };
1997
+ var rowStyle = {
1998
+ display: "flex",
1999
+ alignItems: "center",
2000
+ gap: 12
2001
+ };
2002
+ var badgeStyle2 = (color, filled) => ({
2003
+ width: 28,
2004
+ height: 28,
2005
+ borderRadius: "50%",
2006
+ background: filled ? color : "transparent",
2007
+ border: filled ? "none" : `1.5px solid ${color}`,
2008
+ display: "flex",
2009
+ alignItems: "center",
2010
+ justifyContent: "center",
2011
+ flexShrink: 0
2012
+ });
2013
+ var badgeNumberStyle = (active) => ({
2014
+ fontSize: "0.75rem",
2015
+ fontWeight: 600,
2016
+ color: active ? "#fff" : "inherit"
2017
+ });
2018
+ var labelContainerStyle = {
2019
+ display: "flex",
2020
+ flexDirection: "column"
2021
+ };
2022
+ var labelStyle = (color) => ({
2023
+ fontSize: "0.9rem",
2024
+ fontWeight: 500,
2025
+ color
2026
+ });
2027
+ var detailStyle = (color) => ({
2028
+ fontSize: "0.75rem",
2029
+ color
2030
+ });
2031
+ function SettingsMenu({ onLogout }) {
2032
+ const { tokens } = useSwypeConfig();
2033
+ const [open, setOpen] = useState(false);
2034
+ const menuRef = useRef(null);
2035
+ const toggle = useCallback(() => setOpen((prev) => !prev), []);
2036
+ useEffect(() => {
2037
+ if (!open) return;
2038
+ const handleClickOutside = (e) => {
2039
+ if (menuRef.current && !menuRef.current.contains(e.target)) {
2040
+ setOpen(false);
2041
+ }
2042
+ };
2043
+ document.addEventListener("mousedown", handleClickOutside);
2044
+ return () => document.removeEventListener("mousedown", handleClickOutside);
2045
+ }, [open]);
2046
+ return /* @__PURE__ */ jsxs("div", { ref: menuRef, style: containerStyle7, children: [
2047
+ /* @__PURE__ */ jsx("button", { type: "button", onClick: toggle, style: triggerStyle(tokens.text), "aria-label": "Settings", children: /* @__PURE__ */ jsxs("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", children: [
2048
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "5", r: "2", fill: "currentColor" }),
2049
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "2", fill: "currentColor" }),
2050
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "19", r: "2", fill: "currentColor" })
2051
+ ] }) }),
2052
+ open && /* @__PURE__ */ jsx("div", { style: dropdownStyle(tokens), children: /* @__PURE__ */ jsxs(
2053
+ "button",
2054
+ {
2055
+ type: "button",
2056
+ onClick: () => {
2057
+ setOpen(false);
2058
+ onLogout();
2059
+ },
2060
+ style: menuItemStyle(tokens),
2061
+ children: [
2062
+ /* @__PURE__ */ jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", style: { marginRight: 8, flexShrink: 0 }, children: [
2063
+ /* @__PURE__ */ jsx("path", { d: "M9 21H5a2 2 0 01-2-2V5a2 2 0 012-2h4", stroke: tokens.error, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }),
2064
+ /* @__PURE__ */ jsx("polyline", { points: "16 17 21 12 16 7", stroke: tokens.error, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }),
2065
+ /* @__PURE__ */ jsx("line", { x1: "21", y1: "12", x2: "9", y2: "12", stroke: tokens.error, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" })
2066
+ ] }),
2067
+ "Log out"
2068
+ ]
2069
+ }
2070
+ ) })
2071
+ ] });
2072
+ }
2073
+ var containerStyle7 = {
2074
+ position: "relative"
2075
+ };
2076
+ var triggerStyle = (color) => ({
2077
+ background: "transparent",
2078
+ border: "none",
2079
+ cursor: "pointer",
2080
+ padding: 4,
2081
+ color,
2082
+ display: "flex",
2083
+ alignItems: "center",
2084
+ justifyContent: "center"
2085
+ });
2086
+ var dropdownStyle = (tokens) => ({
2087
+ position: "absolute",
2088
+ right: 0,
2089
+ top: "100%",
2090
+ marginTop: 4,
2091
+ minWidth: 140,
2092
+ background: tokens.bgCard,
2093
+ border: `1px solid ${tokens.border}`,
2094
+ borderRadius: 12,
2095
+ boxShadow: tokens.shadow,
2096
+ zIndex: 100,
2097
+ overflow: "hidden"
2098
+ });
2099
+ var menuItemStyle = (tokens) => ({
2100
+ width: "100%",
2101
+ display: "flex",
2102
+ alignItems: "center",
2103
+ padding: "12px 16px",
2104
+ background: "transparent",
2105
+ border: "none",
2106
+ cursor: "pointer",
2107
+ fontFamily: "inherit",
2108
+ fontSize: "0.85rem",
2109
+ fontWeight: 500,
2110
+ color: tokens.error
2111
+ });
2112
+ function LoginScreen({
2113
+ authInput,
2114
+ onAuthInputChange,
2115
+ onSubmit,
2116
+ sending,
2117
+ error,
2118
+ onBack
2119
+ }) {
2120
+ const { tokens } = useSwypeConfig();
2121
+ const disabled = authInput.trim().length === 0 || sending;
2122
+ const walletLogos = ["MM", "R", "O", "P", "+"];
2123
+ return /* @__PURE__ */ jsxs(
2124
+ ScreenLayout,
2125
+ {
2126
+ footer: /* @__PURE__ */ jsxs(Fragment, { children: [
2127
+ /* @__PURE__ */ jsx(PrimaryButton, { onClick: onSubmit, disabled, loading: sending, children: "Continue" }),
2128
+ /* @__PURE__ */ jsxs("div", { style: dividerStyle(tokens), children: [
2129
+ /* @__PURE__ */ jsx("div", { style: dividerLineStyle(tokens.border) }),
2130
+ /* @__PURE__ */ jsx("span", { children: "works with" }),
2131
+ /* @__PURE__ */ jsx("div", { style: dividerLineStyle(tokens.border) })
2132
+ ] }),
2133
+ /* @__PURE__ */ jsx("div", { style: logosRowStyle, children: walletLogos.map((label) => /* @__PURE__ */ jsx("div", { style: logoCircleStyle(tokens), children: label }, label)) }),
2134
+ /* @__PURE__ */ jsx(PoweredByFooter, {})
2135
+ ] }),
2136
+ children: [
2137
+ /* @__PURE__ */ jsx(ScreenHeader, { onBack }),
2138
+ /* @__PURE__ */ jsxs("div", { style: contentStyle, children: [
2139
+ /* @__PURE__ */ jsx(IconCircle, { variant: "accent", size: 56, children: /* @__PURE__ */ jsx("svg", { width: "28", height: "28", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ jsx(
2140
+ "path",
2141
+ {
2142
+ d: "M12 1L3 5v6c0 5.55 3.84 10.74 9 12 5.16-1.26 9-6.45 9-12V5l-9-4z",
2143
+ fill: tokens.accent
2144
+ }
2145
+ ) }) }),
2146
+ /* @__PURE__ */ jsx("h2", { style: headingStyle(tokens.text), children: "One-time setup.\nOne-tap deposits after." }),
2147
+ /* @__PURE__ */ jsx("p", { style: subtitleStyle(tokens.textSecondary), children: "Protected by Face ID." }),
2148
+ error && /* @__PURE__ */ jsx("div", { style: errorStyle(tokens), children: error }),
2149
+ /* @__PURE__ */ jsx(
2150
+ "input",
2151
+ {
2152
+ id: "swype-login-identifier",
2153
+ type: "text",
2154
+ inputMode: "text",
2155
+ autoComplete: "username",
2156
+ placeholder: "Email or phone number",
2157
+ value: authInput,
2158
+ onChange: (e) => onAuthInputChange(e.target.value),
2159
+ onKeyDown: (e) => {
2160
+ if (e.key === "Enter" && !disabled) onSubmit();
2161
+ },
2162
+ style: inputStyle2(tokens)
2163
+ }
2164
+ )
2165
+ ] })
2166
+ ]
2167
+ }
2168
+ );
2169
+ }
2170
+ var contentStyle = {
2171
+ textAlign: "center",
2172
+ flex: 1,
2173
+ display: "flex",
2174
+ flexDirection: "column",
2175
+ alignItems: "center",
2176
+ paddingTop: 24
2177
+ };
2178
+ var headingStyle = (color) => ({
2179
+ fontSize: "1.65rem",
2180
+ fontWeight: 700,
2181
+ lineHeight: 1.2,
2182
+ letterSpacing: "-0.02em",
2183
+ color,
2184
+ margin: "20px 0 8px",
2185
+ whiteSpace: "pre-line"
2186
+ });
2187
+ var subtitleStyle = (color) => ({
2188
+ fontSize: "0.84rem",
2189
+ color,
2190
+ margin: "0 0 24px",
2191
+ lineHeight: 1.5
2192
+ });
2193
+ var inputStyle2 = (tokens) => ({
2194
+ width: "100%",
2195
+ padding: "15px 16px",
2196
+ borderRadius: 16,
2197
+ border: `1px solid ${tokens.border}`,
2198
+ background: tokens.bgInput,
2199
+ color: tokens.text,
2200
+ fontSize: "0.95rem",
2201
+ fontFamily: "inherit",
2202
+ outline: "none",
2203
+ boxSizing: "border-box"
2204
+ });
2205
+ var errorStyle = (tokens) => ({
2206
+ background: tokens.errorBg,
2207
+ border: `1px solid ${tokens.error}66`,
2208
+ borderRadius: 16,
2209
+ padding: "11px 14px",
2210
+ color: tokens.error,
2211
+ fontSize: "0.84rem",
2212
+ marginBottom: 14,
2213
+ lineHeight: 1.5,
2214
+ width: "100%",
2215
+ textAlign: "left"
2216
+ });
2217
+ var dividerStyle = (tokens) => ({
2218
+ display: "flex",
2219
+ alignItems: "center",
2220
+ gap: 10,
2221
+ margin: "20px 0 14px",
2222
+ color: tokens.textMuted,
2223
+ fontSize: "0.82rem"
2224
+ });
2225
+ var dividerLineStyle = (color) => ({
2226
+ flex: 1,
2227
+ height: 1,
2228
+ background: color
2229
+ });
2230
+ var logosRowStyle = {
2231
+ display: "flex",
2232
+ justifyContent: "center",
2233
+ gap: 12,
2234
+ marginBottom: 8
2235
+ };
2236
+ var logoCircleStyle = (tokens) => ({
2237
+ width: 34,
2238
+ height: 34,
2239
+ borderRadius: 999,
2240
+ border: `1px solid ${tokens.border}`,
2241
+ background: tokens.bgInput,
2242
+ color: tokens.textMuted,
2243
+ display: "flex",
2244
+ alignItems: "center",
2245
+ justifyContent: "center",
2246
+ fontSize: "0.72rem",
2247
+ fontWeight: 600
2248
+ });
2249
+ var RESEND_COOLDOWN_SECONDS = 30;
2250
+ function OtpVerifyScreen({
2251
+ maskedIdentifier,
2252
+ otpCode,
2253
+ onOtpChange,
2254
+ onVerify,
2255
+ onResend,
2256
+ onBack,
2257
+ verifying,
2258
+ error
2259
+ }) {
2260
+ const { tokens } = useSwypeConfig();
2261
+ const disabled = otpCode.trim().length !== 6 || verifying;
2262
+ const [cooldown, setCooldown] = useState(RESEND_COOLDOWN_SECONDS);
2263
+ const intervalRef = useRef(null);
2264
+ useEffect(() => {
2265
+ setCooldown(RESEND_COOLDOWN_SECONDS);
2266
+ intervalRef.current = setInterval(() => {
2267
+ setCooldown((prev) => {
2268
+ if (prev <= 1) {
2269
+ if (intervalRef.current) clearInterval(intervalRef.current);
2270
+ return 0;
2271
+ }
2272
+ return prev - 1;
2273
+ });
2274
+ }, 1e3);
2275
+ return () => {
2276
+ if (intervalRef.current) clearInterval(intervalRef.current);
2277
+ };
2278
+ }, []);
2279
+ const handleResend = useCallback(() => {
2280
+ if (cooldown > 0) return;
2281
+ onResend();
2282
+ setCooldown(RESEND_COOLDOWN_SECONDS);
2283
+ intervalRef.current = setInterval(() => {
2284
+ setCooldown((prev) => {
2285
+ if (prev <= 1) {
2286
+ if (intervalRef.current) clearInterval(intervalRef.current);
2287
+ return 0;
2288
+ }
2289
+ return prev - 1;
2290
+ });
2291
+ }, 1e3);
2292
+ }, [cooldown, onResend]);
2293
+ return /* @__PURE__ */ jsxs(
2294
+ ScreenLayout,
2295
+ {
2296
+ footer: /* @__PURE__ */ jsxs(Fragment, { children: [
2297
+ /* @__PURE__ */ jsx(PrimaryButton, { onClick: onVerify, disabled, loading: verifying, children: "Verify" }),
2298
+ /* @__PURE__ */ jsx("p", { style: hintStyle(tokens.textMuted), children: "Didn't get the code? Check your spam folder" }),
2299
+ /* @__PURE__ */ jsx(PoweredByFooter, {})
2300
+ ] }),
2301
+ children: [
2302
+ /* @__PURE__ */ jsx(ScreenHeader, { onBack }),
2303
+ /* @__PURE__ */ jsxs("div", { style: contentStyle2, children: [
2304
+ /* @__PURE__ */ jsx(IconCircle, { variant: "accent", size: 56, children: /* @__PURE__ */ jsx("svg", { width: "28", height: "28", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ jsx(
2305
+ "path",
2306
+ {
2307
+ d: "M12 1L3 5v6c0 5.55 3.84 10.74 9 12 5.16-1.26 9-6.45 9-12V5l-9-4z",
2308
+ fill: tokens.accent
2309
+ }
2310
+ ) }) }),
2311
+ /* @__PURE__ */ jsx("h2", { style: headingStyle2(tokens.text), children: "Check your email" }),
2312
+ /* @__PURE__ */ jsxs("p", { style: subtitleStyle2(tokens.textSecondary), children: [
2313
+ "We sent a 6-digit code to",
2314
+ "\n",
2315
+ /* @__PURE__ */ jsx("strong", { children: maskedIdentifier })
2316
+ ] }),
2317
+ error && /* @__PURE__ */ jsx("div", { style: errorBannerStyle(tokens), children: error }),
2318
+ /* @__PURE__ */ jsx(OtpInput, { value: otpCode, onChange: onOtpChange, disabled: verifying }),
2319
+ /* @__PURE__ */ jsx(
2320
+ "button",
2321
+ {
2322
+ type: "button",
2323
+ onClick: handleResend,
2324
+ disabled: cooldown > 0,
2325
+ style: resendStyle(tokens.textMuted, cooldown > 0),
2326
+ children: cooldown > 0 ? `Resend code in ${cooldown}s` : "Resend code"
2327
+ }
2328
+ )
2329
+ ] })
2330
+ ]
2331
+ }
2332
+ );
2333
+ }
2334
+ var contentStyle2 = {
2335
+ textAlign: "center",
2336
+ flex: 1,
2337
+ display: "flex",
2338
+ flexDirection: "column",
2339
+ alignItems: "center",
2340
+ paddingTop: 24
2341
+ };
2342
+ var headingStyle2 = (color) => ({
2343
+ fontSize: "1.5rem",
2344
+ fontWeight: 700,
2345
+ letterSpacing: "-0.02em",
2346
+ color,
2347
+ margin: "20px 0 8px"
2348
+ });
2349
+ var subtitleStyle2 = (color) => ({
2350
+ fontSize: "0.88rem",
2351
+ color,
2352
+ margin: "0 0 28px",
2353
+ lineHeight: 1.5,
2354
+ whiteSpace: "pre-line"
2355
+ });
2356
+ var errorBannerStyle = (tokens) => ({
2357
+ background: tokens.errorBg,
2358
+ border: `1px solid ${tokens.error}66`,
2359
+ borderRadius: 16,
2360
+ padding: "11px 14px",
2361
+ color: tokens.error,
2362
+ fontSize: "0.84rem",
2363
+ marginBottom: 14,
2364
+ lineHeight: 1.5,
2365
+ width: "100%",
2366
+ textAlign: "left"
2367
+ });
2368
+ var resendStyle = (color, disabled) => ({
2369
+ background: "transparent",
2370
+ border: "none",
2371
+ color,
2372
+ cursor: disabled ? "default" : "pointer",
2373
+ fontFamily: "inherit",
2374
+ fontSize: "0.82rem",
2375
+ marginTop: 16,
2376
+ padding: 0,
2377
+ opacity: disabled ? 0.6 : 1
2378
+ });
2379
+ var hintStyle = (color) => ({
2380
+ textAlign: "center",
2381
+ fontSize: "0.78rem",
2382
+ color,
2383
+ margin: "12px 0 0"
2384
+ });
2385
+ function CreatePasskeyScreen({
2386
+ onCreatePasskey,
2387
+ onSkip,
2388
+ onBack,
2389
+ creating,
2390
+ error
2391
+ }) {
2392
+ const { tokens } = useSwypeConfig();
2393
+ return /* @__PURE__ */ jsxs(
2394
+ ScreenLayout,
2395
+ {
2396
+ footer: /* @__PURE__ */ jsxs(Fragment, { children: [
2397
+ /* @__PURE__ */ jsx(PrimaryButton, { onClick: onCreatePasskey, disabled: creating, loading: creating, children: "Create passkey" }),
2398
+ /* @__PURE__ */ jsx("button", { type: "button", onClick: onSkip, style: skipStyle(tokens.textMuted), disabled: creating, children: "Skip for now" }),
2399
+ /* @__PURE__ */ jsx(PoweredByFooter, {})
2400
+ ] }),
2401
+ children: [
2402
+ /* @__PURE__ */ jsx(ScreenHeader, { onBack }),
2403
+ /* @__PURE__ */ jsxs("div", { style: contentStyle3, children: [
2404
+ /* @__PURE__ */ jsx(IconCircle, { variant: "accent", size: 64, children: /* @__PURE__ */ jsxs("svg", { width: "36", height: "36", viewBox: "0 0 24 24", fill: "none", children: [
2405
+ /* @__PURE__ */ jsx("rect", { x: "4", y: "4", width: "16", height: "16", rx: "3", stroke: tokens.accent, strokeWidth: "1.5", strokeDasharray: "3 2" }),
2406
+ /* @__PURE__ */ jsx("circle", { cx: "9", cy: "10", r: "1", fill: tokens.accent }),
2407
+ /* @__PURE__ */ jsx("circle", { cx: "15", cy: "10", r: "1", fill: tokens.accent }),
2408
+ /* @__PURE__ */ jsx("path", { d: "M9 14c0 1.5 1.34 2.5 3 2.5s3-1 3-2.5", stroke: tokens.accent, strokeWidth: "1.2", strokeLinecap: "round" })
2409
+ ] }) }),
2410
+ /* @__PURE__ */ jsx("h2", { style: headingStyle3(tokens.text), children: "Create your passkey" }),
2411
+ /* @__PURE__ */ jsx("p", { style: subtitleStyle3(tokens.textSecondary), children: "Use Face ID to sign in instantly \u2014 no passwords, no codes." }),
2412
+ error && /* @__PURE__ */ jsx("div", { style: errorBannerStyle2(tokens), children: error }),
2413
+ /* @__PURE__ */ jsx(InfoBanner, { children: "Your passkey is stored securely on your device. Swype never sees your biometric data." })
2414
+ ] })
2415
+ ]
2416
+ }
2417
+ );
2418
+ }
2419
+ var contentStyle3 = {
2420
+ textAlign: "center",
2421
+ flex: 1,
2422
+ display: "flex",
2423
+ flexDirection: "column",
2424
+ alignItems: "center",
2425
+ paddingTop: 32
2426
+ };
2427
+ var headingStyle3 = (color) => ({
2428
+ fontSize: "1.45rem",
2429
+ fontWeight: 700,
2430
+ letterSpacing: "-0.02em",
2431
+ color,
2432
+ margin: "24px 0 8px"
2433
+ });
2434
+ var subtitleStyle3 = (color) => ({
2435
+ fontSize: "0.9rem",
2436
+ color,
2437
+ margin: "0 0 28px",
2438
+ lineHeight: 1.5,
2439
+ maxWidth: 280
2440
+ });
2441
+ var errorBannerStyle2 = (tokens) => ({
2442
+ background: tokens.errorBg,
2443
+ border: `1px solid ${tokens.error}66`,
2444
+ borderRadius: 16,
2445
+ padding: "11px 14px",
2446
+ color: tokens.error,
2447
+ fontSize: "0.84rem",
2448
+ marginBottom: 14,
2449
+ lineHeight: 1.5,
2450
+ width: "100%",
2451
+ textAlign: "left"
2452
+ });
2453
+ var skipStyle = (color) => ({
2454
+ background: "transparent",
2455
+ border: "none",
2456
+ color,
2457
+ cursor: "pointer",
2458
+ fontFamily: "inherit",
2459
+ fontSize: "0.88rem",
2460
+ fontWeight: 500,
2461
+ display: "block",
2462
+ width: "100%",
2463
+ textAlign: "center",
2464
+ padding: "12px 0 0"
2465
+ });
2466
+ var WALLET_EMOJIS = {
2467
+ metamask: "\u{1F98A}",
2468
+ rabby: "\u{1F430}",
2469
+ ora: "\u2666\uFE0F",
2470
+ phantom: "\u{1F47B}"
2471
+ };
2472
+ function WalletPickerScreen({
2473
+ providers,
2474
+ onSelectProvider,
2475
+ onBack
2476
+ }) {
2477
+ const { tokens } = useSwypeConfig();
2478
+ const [hoveredId, setHoveredId] = useState(null);
2479
+ const displayProviders = providers.length > 0 ? providers : [
2480
+ { id: "metamask", name: "MetaMask" },
2481
+ { id: "rabby", name: "Rabby" },
2482
+ { id: "ora", name: "Ora" },
2483
+ { id: "phantom", name: "Phantom" }
2484
+ ];
2485
+ return /* @__PURE__ */ jsxs(
2486
+ ScreenLayout,
2487
+ {
2488
+ footer: /* @__PURE__ */ jsxs(Fragment, { children: [
2489
+ /* @__PURE__ */ jsx("p", { style: hintStyle2(tokens.textMuted), children: "You'll set your deposit limit in your wallet app." }),
2490
+ /* @__PURE__ */ jsx(PoweredByFooter, {})
2491
+ ] }),
2492
+ children: [
2493
+ /* @__PURE__ */ jsx(ScreenHeader, { title: "Set up Swype", onBack }),
2494
+ /* @__PURE__ */ jsx("h2", { style: headingStyle4(tokens.text), children: "Where are your stablecoins?" }),
2495
+ /* @__PURE__ */ jsx("p", { style: subtitleStyle4(tokens.textSecondary), children: "Select the wallet you want to deposit from" }),
2496
+ /* @__PURE__ */ jsxs("div", { style: gridStyle, children: [
2497
+ displayProviders.map((p) => {
2498
+ const emoji = WALLET_EMOJIS[p.name.toLowerCase()] ?? p.name.charAt(0);
2499
+ const isHovered = hoveredId === p.id;
2500
+ return /* @__PURE__ */ jsxs(
2501
+ "button",
2502
+ {
2503
+ onClick: () => onSelectProvider(p.id),
2504
+ onMouseEnter: () => setHoveredId(p.id),
2505
+ onMouseLeave: () => setHoveredId(null),
2506
+ style: cardStyle(tokens, isHovered),
2507
+ children: [
2508
+ "logoURI" in p && p.logoURI ? /* @__PURE__ */ jsx(
2509
+ "img",
2510
+ {
2511
+ src: p.logoURI,
2512
+ alt: p.name,
2513
+ style: logoImgStyle
2514
+ }
2515
+ ) : /* @__PURE__ */ jsx("span", { style: emojiStyle, children: emoji }),
2516
+ /* @__PURE__ */ jsx("span", { style: nameStyle2(tokens.text), children: p.name })
2517
+ ]
2518
+ },
2519
+ p.id
2520
+ );
2521
+ }),
2522
+ /* @__PURE__ */ jsxs(
2523
+ "button",
2524
+ {
2525
+ onClick: () => onSelectProvider("other"),
2526
+ onMouseEnter: () => setHoveredId("other"),
2527
+ onMouseLeave: () => setHoveredId(null),
2528
+ style: cardStyle(tokens, hoveredId === "other"),
2529
+ children: [
2530
+ /* @__PURE__ */ jsx("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", style: { margin: "0 auto" }, children: /* @__PURE__ */ jsx(
2531
+ "path",
2532
+ {
2533
+ d: "M19 19H5V5h7V3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2v-7h-2v7zM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7z",
2534
+ fill: tokens.textMuted
2535
+ }
2536
+ ) }),
2537
+ /* @__PURE__ */ jsx("span", { style: nameStyle2(tokens.text), children: "Other" })
2538
+ ]
2539
+ }
2540
+ )
2541
+ ] })
2542
+ ]
2543
+ }
2544
+ );
2545
+ }
2546
+ var headingStyle4 = (color) => ({
2547
+ fontSize: "1.35rem",
2548
+ fontWeight: 700,
2549
+ letterSpacing: "-0.02em",
2550
+ color,
2551
+ margin: "8px 0 4px"
2552
+ });
2553
+ var subtitleStyle4 = (color) => ({
2554
+ fontSize: "0.88rem",
2555
+ color,
2556
+ margin: "0 0 24px"
2557
+ });
2558
+ var gridStyle = {
2559
+ display: "grid",
2560
+ gridTemplateColumns: "1fr 1fr",
2561
+ gap: 12
2562
+ };
2563
+ var cardStyle = (tokens, hovered) => ({
2564
+ display: "flex",
2565
+ flexDirection: "column",
2566
+ alignItems: "center",
2567
+ justifyContent: "center",
2568
+ gap: 8,
2569
+ padding: "20px 12px",
2570
+ background: hovered ? tokens.bgHover : tokens.bgInput,
2571
+ border: `1.5px solid ${tokens.border}`,
2572
+ borderRadius: 16,
2573
+ cursor: "pointer",
2574
+ fontFamily: "inherit",
2575
+ transition: "background 0.15s ease",
2576
+ outline: "none"
2577
+ });
2578
+ var emojiStyle = {
2579
+ fontSize: "1.75rem",
2580
+ lineHeight: 1
2581
+ };
2582
+ var logoImgStyle = {
2583
+ width: 32,
2584
+ height: 32,
2585
+ borderRadius: 8,
2586
+ objectFit: "contain"
2587
+ };
2588
+ var nameStyle2 = (color) => ({
2589
+ fontSize: "0.88rem",
2590
+ fontWeight: 600,
2591
+ color
2592
+ });
2593
+ var hintStyle2 = (color) => ({
2594
+ textAlign: "center",
2595
+ fontSize: "0.82rem",
2596
+ color,
2597
+ margin: "0 0 4px"
2598
+ });
2599
+ var DEFAULT_MAX = 500;
2600
+ var ABSOLUTE_MIN = 1;
2601
+ function buildTicks(min, max) {
2602
+ if (max <= min) return [min];
2603
+ const range = max - min;
2604
+ const candidates = [1, 2, 5, 10, 25, 50, 100, 250];
2605
+ const step = candidates.find((s) => range / s <= 5) ?? Math.ceil(range / 4);
2606
+ const ticks = [];
2607
+ for (let v = min; v <= max; v += step) {
2608
+ ticks.push(Math.round(v * 100) / 100);
2609
+ }
2610
+ if (ticks[ticks.length - 1] !== max) ticks.push(max);
2611
+ return ticks;
2612
+ }
2613
+ function SetupScreen({
2614
+ availableBalance,
2615
+ tokenCount,
2616
+ sourceName,
2617
+ onSetupOneTap,
2618
+ onBack,
2619
+ onLogout,
2620
+ loading,
2621
+ error
2622
+ }) {
2623
+ const { tokens } = useSwypeConfig();
2624
+ const effectiveMax = Math.min(DEFAULT_MAX, availableBalance > 0 ? availableBalance : DEFAULT_MAX);
2625
+ const effectiveMin = Math.min(ABSOLUTE_MIN, effectiveMax);
2626
+ const sliderStep = effectiveMax <= 10 ? 0.5 : effectiveMax <= 50 ? 1 : 5;
2627
+ const ticks = buildTicks(effectiveMin, effectiveMax);
2628
+ const [limit, setLimit] = useState(() => Math.min(100, effectiveMax));
2629
+ return /* @__PURE__ */ jsxs(
2630
+ ScreenLayout,
2631
+ {
2632
+ footer: /* @__PURE__ */ jsxs(Fragment, { children: [
2633
+ /* @__PURE__ */ jsx(
2634
+ PrimaryButton,
2635
+ {
2636
+ onClick: () => onSetupOneTap(limit),
2637
+ disabled: loading,
2638
+ loading,
2639
+ children: "Set up One-Tap"
2640
+ }
2641
+ ),
2642
+ /* @__PURE__ */ jsx(PoweredByFooter, {})
2643
+ ] }),
2644
+ children: [
2645
+ /* @__PURE__ */ jsx(ScreenHeader, { title: "Swype Setup", badge: "Simple", onBack, right: /* @__PURE__ */ jsx(SettingsMenu, { onLogout }) }),
2646
+ /* @__PURE__ */ jsx("h2", { style: headingStyle5(tokens.text), children: "Set up One-Tap deposits" }),
2647
+ /* @__PURE__ */ jsx("p", { style: subtitleStyle5(tokens.textSecondary), children: "Set your limit for instant deposits. Like a contactless card \u2014 you choose the max." }),
2648
+ error && /* @__PURE__ */ jsx("div", { style: errorBannerStyle3(tokens), children: error }),
2649
+ /* @__PURE__ */ jsxs("div", { style: balanceRowStyle, children: [
2650
+ /* @__PURE__ */ jsxs("div", { style: balanceLeftStyle, children: [
2651
+ /* @__PURE__ */ jsx("div", { style: coinIconStyle(tokens.accent), children: /* @__PURE__ */ jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", children: [
2652
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10", fill: "currentColor" }),
2653
+ /* @__PURE__ */ jsx("text", { x: "12", y: "16", textAnchor: "middle", fontSize: "12", fill: "#fff", fontWeight: "700", children: "$" })
2654
+ ] }) }),
2655
+ /* @__PURE__ */ jsxs("div", { children: [
2656
+ /* @__PURE__ */ jsx("div", { style: balanceLabelStyle(tokens.textMuted), children: "Available" }),
2657
+ /* @__PURE__ */ jsxs("div", { style: balanceValueStyle(tokens.text), children: [
2658
+ "$",
2659
+ availableBalance.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 })
2660
+ ] })
2661
+ ] })
2662
+ ] }),
2663
+ tokenCount > 0 && /* @__PURE__ */ jsxs("div", { style: tokenBadgeStyle(tokens), children: [
2664
+ /* @__PURE__ */ jsx("span", { style: tokenDotStyle(tokens.accent) }),
2665
+ tokenCount,
2666
+ " ",
2667
+ /* @__PURE__ */ jsx("span", { style: chevronStyle, children: ">" })
2668
+ ] })
2669
+ ] }),
2670
+ /* @__PURE__ */ jsxs("div", { style: limitSectionStyle, children: [
2671
+ /* @__PURE__ */ jsx("div", { style: limitLabelStyle(tokens.textMuted), children: "Your One-Tap limit" }),
2672
+ /* @__PURE__ */ jsxs("div", { style: limitValueStyle(tokens.text), children: [
2673
+ "$",
2674
+ limit
2675
+ ] }),
2676
+ /* @__PURE__ */ jsx(
2677
+ LimitSlider,
2678
+ {
2679
+ value: limit,
2680
+ min: effectiveMin,
2681
+ max: effectiveMax,
2682
+ step: sliderStep,
2683
+ ticks,
2684
+ onChange: setLimit
2685
+ }
2686
+ )
2687
+ ] }),
2688
+ /* @__PURE__ */ jsx("div", { style: bannerWrapStyle, children: /* @__PURE__ */ jsx(InfoBanner, { children: "Funds stay in your wallet until you deposit. Swype never holds your money." }) }),
2689
+ /* @__PURE__ */ jsxs("button", { type: "button", style: linkStyle(tokens.accent), children: [
2690
+ /* @__PURE__ */ jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", style: { marginRight: 6 }, children: [
2691
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "2" }),
2692
+ /* @__PURE__ */ jsx("path", { d: "M12 16v-4M12 8h.01", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" })
2693
+ ] }),
2694
+ "How does this work?"
2695
+ ] })
2696
+ ]
2697
+ }
2698
+ );
2699
+ }
2700
+ var headingStyle5 = (color) => ({
2701
+ fontSize: "1.3rem",
2702
+ fontWeight: 700,
2703
+ letterSpacing: "-0.02em",
2704
+ color,
2705
+ margin: "8px 0 4px"
2706
+ });
2707
+ var subtitleStyle5 = (color) => ({
2708
+ fontSize: "0.86rem",
2709
+ color,
2710
+ margin: "0 0 24px",
2711
+ lineHeight: 1.5
2712
+ });
2713
+ var errorBannerStyle3 = (tokens) => ({
2714
+ background: tokens.errorBg,
2715
+ border: `1px solid ${tokens.error}66`,
2716
+ borderRadius: 16,
2717
+ padding: "11px 14px",
2718
+ color: tokens.error,
2719
+ fontSize: "0.84rem",
2720
+ marginBottom: 14,
2721
+ lineHeight: 1.5
2722
+ });
2723
+ var balanceRowStyle = {
2724
+ display: "flex",
2725
+ alignItems: "center",
2726
+ justifyContent: "space-between",
2727
+ marginBottom: 24
2728
+ };
2729
+ var balanceLeftStyle = {
2730
+ display: "flex",
2731
+ alignItems: "center",
2732
+ gap: 10
2733
+ };
2734
+ var coinIconStyle = (color) => ({
2735
+ color,
2736
+ display: "flex",
2737
+ alignItems: "center"
2738
+ });
2739
+ var balanceLabelStyle = (color) => ({
2740
+ fontSize: "0.72rem",
2741
+ color,
2742
+ fontWeight: 500
2743
+ });
2744
+ var balanceValueStyle = (color) => ({
2745
+ fontSize: "1.1rem",
2746
+ fontWeight: 700,
2747
+ color
2748
+ });
2749
+ var tokenBadgeStyle = (tokens) => ({
2750
+ display: "flex",
2751
+ alignItems: "center",
2752
+ gap: 4,
2753
+ fontSize: "0.78rem",
2754
+ color: tokens.textMuted,
2755
+ border: `1px solid ${tokens.border}`,
2756
+ borderRadius: 999,
2757
+ padding: "4px 10px"
2758
+ });
2759
+ var tokenDotStyle = (color) => ({
2760
+ width: 8,
2761
+ height: 8,
2762
+ borderRadius: "50%",
2763
+ background: color,
2764
+ display: "inline-block"
2765
+ });
2766
+ var chevronStyle = { fontSize: "0.68rem", marginLeft: 2 };
2767
+ var limitSectionStyle = {
2768
+ textAlign: "center",
2769
+ marginBottom: 24
2770
+ };
2771
+ var limitLabelStyle = (color) => ({
2772
+ fontSize: "0.8rem",
2773
+ color,
2774
+ marginBottom: 4
2775
+ });
2776
+ var limitValueStyle = (color) => ({
2777
+ fontSize: "2.2rem",
2778
+ fontWeight: 700,
2779
+ color,
2780
+ marginBottom: 12
2781
+ });
2782
+ var bannerWrapStyle = { marginBottom: 16 };
2783
+ var linkStyle = (color) => ({
2784
+ background: "transparent",
2785
+ border: "none",
2786
+ color,
2787
+ cursor: "pointer",
2788
+ fontFamily: "inherit",
2789
+ fontSize: "0.82rem",
2790
+ fontWeight: 500,
2791
+ display: "flex",
2792
+ alignItems: "center",
2793
+ padding: 0,
2794
+ marginBottom: 16
2795
+ });
2796
+ function SetupStatusScreen({
2797
+ complete,
2798
+ limit,
2799
+ tokensApproved,
2800
+ currentStepLabel,
2801
+ merchantName,
2802
+ onContinue,
2803
+ onLogout,
2804
+ error
2805
+ }) {
2806
+ const { tokens } = useSwypeConfig();
2807
+ const steps = complete ? [
2808
+ {
2809
+ label: "One-Tap ready",
2810
+ detail: `$${limit} limit \xB7 ${tokensApproved} token${tokensApproved !== 1 ? "s" : ""} approved`,
2811
+ status: "complete"
2812
+ },
2813
+ { label: "Done", status: "complete" }
2814
+ ] : [
2815
+ {
2816
+ label: currentStepLabel ?? "Approving tokens",
2817
+ status: "active"
2818
+ },
2819
+ { label: "Done", status: "pending" }
2820
+ ];
2821
+ return /* @__PURE__ */ jsxs(
2822
+ ScreenLayout,
2823
+ {
2824
+ footer: complete ? /* @__PURE__ */ jsxs(Fragment, { children: [
2825
+ /* @__PURE__ */ jsx(PrimaryButton, { onClick: onContinue, children: merchantName ? `Return to ${merchantName}` : "Continue" }),
2826
+ /* @__PURE__ */ jsx("p", { style: swipeHintStyle(tokens.textMuted), children: "Swipe to deposit \u2014 no approvals needed." })
2827
+ ] }) : void 0,
2828
+ children: [
2829
+ /* @__PURE__ */ jsx(ScreenHeader, { right: /* @__PURE__ */ jsx(SettingsMenu, { onLogout }) }),
2830
+ /* @__PURE__ */ jsxs("div", { style: contentStyle4, children: [
2831
+ complete ? /* @__PURE__ */ jsxs(Fragment, { children: [
2832
+ /* @__PURE__ */ jsx(IconCircle, { variant: "success", size: 64, children: /* @__PURE__ */ jsx("svg", { width: "32", height: "32", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ jsx("path", { d: "M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41L9 16.17z", fill: tokens.success }) }) }),
2833
+ /* @__PURE__ */ jsx("h2", { style: headingStyle6(tokens.text), children: "You're all set!" })
2834
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
2835
+ /* @__PURE__ */ jsx(Spinner, { size: 48 }),
2836
+ /* @__PURE__ */ jsx("h2", { style: headingStyle6(tokens.text), children: "Setting up One-Tap..." })
2837
+ ] }),
2838
+ error && /* @__PURE__ */ jsx("div", { style: errorBannerStyle4(tokens), children: error }),
2839
+ /* @__PURE__ */ jsx("div", { style: stepsWrapStyle, children: /* @__PURE__ */ jsx(StepList, { steps }) }),
2840
+ !complete && /* @__PURE__ */ jsx("p", { style: waitHintStyle(tokens.textMuted), children: "Usually takes a few seconds" }),
2841
+ complete && /* @__PURE__ */ jsx("p", { style: readyHintStyle(tokens.textSecondary), children: "You can now deposit instantly from any partner app." })
2842
+ ] })
2843
+ ]
2844
+ }
2845
+ );
2846
+ }
2847
+ var contentStyle4 = {
2848
+ flex: 1,
2849
+ display: "flex",
2850
+ flexDirection: "column",
2851
+ alignItems: "center",
2852
+ justifyContent: "center",
2853
+ textAlign: "center",
2854
+ padding: "0 24px"
2855
+ };
2856
+ var headingStyle6 = (color) => ({
2857
+ fontSize: "1.45rem",
2858
+ fontWeight: 700,
2859
+ letterSpacing: "-0.02em",
2860
+ color,
2861
+ margin: "20px 0 16px"
2862
+ });
2863
+ var errorBannerStyle4 = (tokens) => ({
2864
+ background: tokens.errorBg,
2865
+ border: `1px solid ${tokens.error}66`,
2866
+ borderRadius: 16,
2867
+ padding: "11px 14px",
2868
+ color: tokens.error,
2869
+ fontSize: "0.84rem",
2870
+ marginBottom: 14,
2871
+ lineHeight: 1.5,
2872
+ width: "100%",
2873
+ textAlign: "left"
2874
+ });
2875
+ var stepsWrapStyle = {
2876
+ width: "100%",
2877
+ maxWidth: 280,
2878
+ textAlign: "left",
2879
+ marginBottom: 16
2880
+ };
2881
+ var waitHintStyle = (color) => ({
2882
+ fontSize: "0.82rem",
2883
+ color,
2884
+ margin: 0
2885
+ });
2886
+ var readyHintStyle = (color) => ({
2887
+ fontSize: "0.88rem",
2888
+ color,
2889
+ margin: "8px 0 0",
2890
+ lineHeight: 1.5,
2891
+ maxWidth: 280
2892
+ });
2893
+ var swipeHintStyle = (color) => ({
2894
+ textAlign: "center",
2895
+ fontSize: "0.8rem",
2896
+ color,
2897
+ margin: "12px 0 0"
2898
+ });
2899
+ var MIN_DEPOSIT = 1;
2900
+ function DepositScreen({
2901
+ merchantName,
2902
+ sourceName,
2903
+ sourceAddress,
2904
+ sourceVerified,
2905
+ availableBalance,
2906
+ remainingLimit,
2907
+ tokenCount,
2908
+ initialAmount,
2909
+ estimatedFeePct,
2910
+ estimatedFeeUsd,
2911
+ processing,
2912
+ error,
2913
+ onDeposit,
2914
+ onChangeSource,
2915
+ onSwitchWallet,
2916
+ onBack,
2917
+ onLogout
2918
+ }) {
2919
+ const { tokens } = useSwypeConfig();
2920
+ const [amount, setAmount] = useState(initialAmount);
2921
+ const sliderMax = Math.min(remainingLimit, availableBalance, 500);
2922
+ const isLowBalance = availableBalance < MIN_DEPOSIT;
2923
+ const canDeposit = amount >= MIN_DEPOSIT && amount <= remainingLimit && !isLowBalance && !processing;
2924
+ const headerTitle = merchantName ? `Deposit to ${merchantName}` : "Deposit";
2925
+ if (isLowBalance) {
2926
+ return /* @__PURE__ */ jsxs(
2927
+ ScreenLayout,
2928
+ {
2929
+ footer: /* @__PURE__ */ jsxs(Fragment, { children: [
2930
+ /* @__PURE__ */ jsx(PrimaryButton, { onClick: onSwitchWallet, children: "Switch wallet" }),
2931
+ /* @__PURE__ */ jsx("p", { style: switchHintStyle(tokens.textMuted), children: "Use a different wallet with more balance" }),
2932
+ /* @__PURE__ */ jsx("div", { style: outlineBtnWrapStyle, children: /* @__PURE__ */ jsx(OutlineButton, { onClick: onBack, children: "Back to deposit options" }) }),
2933
+ /* @__PURE__ */ jsx(PoweredByFooter, {})
2934
+ ] }),
2935
+ children: [
2936
+ /* @__PURE__ */ jsx(ScreenHeader, { title: headerTitle, onBack, right: /* @__PURE__ */ jsx(SettingsMenu, { onLogout }) }),
2937
+ /* @__PURE__ */ jsx(
2938
+ SourceCard,
2939
+ {
2940
+ name: sourceName,
2941
+ address: sourceAddress,
2942
+ verified: sourceVerified,
2943
+ onChangeSource
2944
+ }
2945
+ ),
2946
+ /* @__PURE__ */ jsx("div", { style: amountDisplayStyle, children: /* @__PURE__ */ jsxs("span", { style: amountStyle({ ...tokens, dimmed: true }), children: [
2947
+ "$",
2948
+ amount.toFixed(2)
2949
+ ] }) }),
2950
+ /* @__PURE__ */ jsxs("div", { style: balanceRowStyle2, children: [
2951
+ /* @__PURE__ */ jsxs("div", { style: balanceLeftStyle2, children: [
2952
+ /* @__PURE__ */ jsx("div", { style: coinIconStyle2(tokens.warning), children: /* @__PURE__ */ jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", children: [
2953
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10", fill: "currentColor" }),
2954
+ /* @__PURE__ */ jsx("text", { x: "12", y: "16", textAnchor: "middle", fontSize: "12", fill: "#fff", fontWeight: "700", children: "$" })
2955
+ ] }) }),
2956
+ /* @__PURE__ */ jsxs("div", { children: [
2957
+ /* @__PURE__ */ jsx("div", { style: balanceLabelStyle2(tokens.textMuted), children: "Available" }),
2958
+ /* @__PURE__ */ jsxs("div", { style: { ...balanceAmountStyle, color: tokens.warning }, children: [
2959
+ "$",
2960
+ availableBalance.toFixed(2)
2961
+ ] })
2962
+ ] })
2963
+ ] }),
2964
+ /* @__PURE__ */ jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ jsx("path", { d: "M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z", fill: tokens.warning }) })
2965
+ ] }),
2966
+ /* @__PURE__ */ jsxs(WarningBanner, { title: "Not enough funds", children: [
2967
+ "Your wallet balance is $",
2968
+ availableBalance.toFixed(2),
2969
+ " \u2014 you need at least $",
2970
+ MIN_DEPOSIT.toFixed(2),
2971
+ " to deposit via One-Tap."
2972
+ ] })
2973
+ ]
2974
+ }
2975
+ );
2976
+ }
2977
+ return /* @__PURE__ */ jsxs(
2978
+ ScreenLayout,
2979
+ {
2980
+ footer: /* @__PURE__ */ jsxs(Fragment, { children: [
2981
+ /* @__PURE__ */ jsxs(PrimaryButton, { onClick: () => onDeposit(amount), disabled: !canDeposit, loading: processing, children: [
2982
+ "Deposit $",
2983
+ amount.toFixed(2)
2984
+ ] }),
2985
+ /* @__PURE__ */ jsx("p", { style: noApprovalStyle(tokens.textMuted), children: "No approval needed \xB7 within your One-Tap limit" }),
2986
+ /* @__PURE__ */ jsxs("p", { style: routeStyle(tokens.textMuted), children: [
2987
+ "From ",
2988
+ sourceName,
2989
+ " ",
2990
+ merchantName ? `\u2192 ${merchantName}` : ""
2991
+ ] }),
2992
+ /* @__PURE__ */ jsx(PoweredByFooter, {})
2993
+ ] }),
2994
+ children: [
2995
+ /* @__PURE__ */ jsx(ScreenHeader, { title: headerTitle, badge: "Simple", onBack, right: /* @__PURE__ */ jsx(SettingsMenu, { onLogout }) }),
2996
+ /* @__PURE__ */ jsx(
2997
+ SourceCard,
2998
+ {
2999
+ name: sourceName,
3000
+ address: sourceAddress,
3001
+ verified: sourceVerified,
3002
+ onChangeSource
3003
+ }
3004
+ ),
3005
+ /* @__PURE__ */ jsx("div", { style: amountDisplayStyle, children: /* @__PURE__ */ jsxs("span", { style: amountStyle(tokens), children: [
3006
+ "$",
3007
+ amount.toFixed(2)
3008
+ ] }) }),
3009
+ /* @__PURE__ */ jsxs("div", { style: balanceRowStyle2, children: [
3010
+ /* @__PURE__ */ jsxs("div", { style: balanceLeftStyle2, children: [
3011
+ /* @__PURE__ */ jsx("div", { style: coinIconStyle2(tokens.accent), children: /* @__PURE__ */ jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", children: [
3012
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10", fill: "currentColor" }),
3013
+ /* @__PURE__ */ jsx("text", { x: "12", y: "16", textAnchor: "middle", fontSize: "12", fill: "#fff", fontWeight: "700", children: "$" })
3014
+ ] }) }),
3015
+ /* @__PURE__ */ jsxs("div", { children: [
3016
+ /* @__PURE__ */ jsxs("div", { style: balanceLabelStyle2(tokens.textMuted), children: [
3017
+ "Paying from ",
3018
+ sourceName
3019
+ ] }),
3020
+ /* @__PURE__ */ jsxs("div", { style: balanceAmountStyle, children: [
3021
+ "$",
3022
+ availableBalance.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 })
3023
+ ] })
3024
+ ] })
3025
+ ] }),
3026
+ tokenCount > 0 && /* @__PURE__ */ jsxs("div", { style: tokenBadgeStyle2(tokens), children: [
3027
+ /* @__PURE__ */ jsx("span", { style: tokenDotStyle2(tokens.accent) }),
3028
+ tokenCount,
3029
+ " ",
3030
+ /* @__PURE__ */ jsx("span", { style: chevronStyle2, children: ">" })
3031
+ ] })
3032
+ ] }),
3033
+ /* @__PURE__ */ jsx(
3034
+ LimitSlider,
3035
+ {
3036
+ value: amount,
3037
+ min: MIN_DEPOSIT,
3038
+ max: sliderMax > MIN_DEPOSIT ? sliderMax : 20,
3039
+ step: 0.5,
3040
+ ticks: [MIN_DEPOSIT, 5, 10, 20].filter((t) => t <= sliderMax || t <= 20),
3041
+ onChange: setAmount
3042
+ }
3043
+ ),
3044
+ /* @__PURE__ */ jsxs("div", { style: detailsStyle, children: [
3045
+ /* @__PURE__ */ jsxs("div", { style: detailRowStyle(tokens.textMuted), children: [
3046
+ "Remaining limit: ",
3047
+ /* @__PURE__ */ jsxs("strong", { style: { color: tokens.text }, children: [
3048
+ "$",
3049
+ remainingLimit.toFixed(2)
3050
+ ] })
3051
+ ] }),
3052
+ estimatedFeeUsd != null && estimatedFeePct != null && /* @__PURE__ */ jsxs("div", { style: detailRowStyle(tokens.textMuted), children: [
3053
+ "Fee: ~$",
3054
+ estimatedFeeUsd.toFixed(2),
3055
+ " (",
3056
+ estimatedFeePct.toFixed(1),
3057
+ "%)"
3058
+ ] })
3059
+ ] }),
3060
+ error && /* @__PURE__ */ jsx("div", { style: errorBannerStyle5(tokens), children: error })
3061
+ ]
3062
+ }
3063
+ );
3064
+ }
3065
+ var amountDisplayStyle = {
3066
+ textAlign: "center",
3067
+ padding: "20px 0 8px"
3068
+ };
3069
+ var amountStyle = (opts) => ({
3070
+ fontSize: "2.5rem",
3071
+ fontWeight: 700,
3072
+ color: opts.dimmed ? "#ccc" : opts.text ?? "#12222b",
3073
+ letterSpacing: "-0.02em"
3074
+ });
3075
+ var balanceRowStyle2 = {
3076
+ display: "flex",
3077
+ alignItems: "center",
3078
+ justifyContent: "space-between",
3079
+ marginBottom: 16
3080
+ };
3081
+ var balanceLeftStyle2 = {
3082
+ display: "flex",
3083
+ alignItems: "center",
3084
+ gap: 10
3085
+ };
3086
+ var coinIconStyle2 = (color) => ({
3087
+ color,
3088
+ display: "flex",
3089
+ alignItems: "center"
3090
+ });
3091
+ var balanceLabelStyle2 = (color) => ({
3092
+ fontSize: "0.72rem",
3093
+ color,
3094
+ fontWeight: 500
3095
+ });
3096
+ var balanceAmountStyle = {
3097
+ fontSize: "1rem",
3098
+ fontWeight: 700
3099
+ };
3100
+ var tokenBadgeStyle2 = (tokens) => ({
3101
+ display: "flex",
3102
+ alignItems: "center",
3103
+ gap: 4,
3104
+ fontSize: "0.78rem",
3105
+ color: tokens.textMuted,
3106
+ border: `1px solid ${tokens.border}`,
3107
+ borderRadius: 999,
3108
+ padding: "4px 10px"
3109
+ });
3110
+ var tokenDotStyle2 = (color) => ({
3111
+ width: 8,
3112
+ height: 8,
3113
+ borderRadius: "50%",
3114
+ background: color,
3115
+ display: "inline-block"
3116
+ });
3117
+ var chevronStyle2 = { fontSize: "0.68rem", marginLeft: 2 };
3118
+ var detailsStyle = {
3119
+ textAlign: "center",
3120
+ marginTop: 12,
3121
+ marginBottom: 8
3122
+ };
3123
+ var detailRowStyle = (color) => ({
3124
+ fontSize: "0.8rem",
3125
+ color,
3126
+ marginBottom: 4
3127
+ });
3128
+ var errorBannerStyle5 = (tokens) => ({
3129
+ background: tokens.errorBg,
3130
+ border: `1px solid ${tokens.error}66`,
3131
+ borderRadius: 16,
3132
+ padding: "11px 14px",
3133
+ color: tokens.error,
3134
+ fontSize: "0.84rem",
3135
+ marginTop: 8,
3136
+ lineHeight: 1.5
3137
+ });
3138
+ var noApprovalStyle = (color) => ({
3139
+ textAlign: "center",
3140
+ fontSize: "0.78rem",
3141
+ color,
3142
+ margin: "12px 0 2px"
3143
+ });
3144
+ var routeStyle = (color) => ({
3145
+ textAlign: "center",
3146
+ fontSize: "0.75rem",
3147
+ color,
3148
+ margin: "0 0 4px"
3149
+ });
3150
+ var switchHintStyle = (color) => ({
3151
+ textAlign: "center",
3152
+ fontSize: "0.8rem",
3153
+ color,
3154
+ margin: "10px 0"
3155
+ });
3156
+ var outlineBtnWrapStyle = {
3157
+ marginBottom: 8
3158
+ };
3159
+ function SuccessScreen({
3160
+ amount,
3161
+ currency,
3162
+ merchantName,
3163
+ sourceName,
3164
+ remainingLimit,
3165
+ onDone,
3166
+ onLogout,
3167
+ onIncreaseLimits,
3168
+ onManageAccount
3169
+ }) {
3170
+ const { tokens } = useSwypeConfig();
3171
+ return /* @__PURE__ */ jsxs(
3172
+ ScreenLayout,
3173
+ {
3174
+ footer: /* @__PURE__ */ jsxs(Fragment, { children: [
3175
+ /* @__PURE__ */ jsx(PrimaryButton, { onClick: onDone, children: "Done" }),
3176
+ onManageAccount && /* @__PURE__ */ jsx("button", { type: "button", onClick: onManageAccount, style: manageStyle(tokens.textMuted), children: "Manage Swype account \u2192" }),
3177
+ /* @__PURE__ */ jsx(PoweredByFooter, {})
3178
+ ] }),
3179
+ children: [
3180
+ /* @__PURE__ */ jsx(
3181
+ ScreenHeader,
3182
+ {
3183
+ right: /* @__PURE__ */ jsx(SettingsMenu, { onLogout })
3184
+ }
3185
+ ),
3186
+ /* @__PURE__ */ jsxs("div", { style: contentStyle5, children: [
3187
+ /* @__PURE__ */ jsx(IconCircle, { variant: "success", size: 64, children: /* @__PURE__ */ jsx("svg", { width: "32", height: "32", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ jsx("path", { d: "M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41L9 16.17z", fill: tokens.success }) }) }),
3188
+ /* @__PURE__ */ jsxs("h2", { style: headingStyle7(tokens.text), children: [
3189
+ "$",
3190
+ amount.toFixed(2),
3191
+ " deposited"
3192
+ ] }),
3193
+ merchantName && /* @__PURE__ */ jsxs("p", { style: subtitleStyle6(tokens.textSecondary), children: [
3194
+ "to ",
3195
+ merchantName
3196
+ ] }),
3197
+ /* @__PURE__ */ jsxs("div", { style: summaryCardStyle(tokens), children: [
3198
+ sourceName && /* @__PURE__ */ jsxs("div", { style: summaryRowStyle, children: [
3199
+ /* @__PURE__ */ jsx("span", { style: summaryLabelStyle(tokens.textMuted), children: "From" }),
3200
+ /* @__PURE__ */ jsx("span", { style: summaryValueStyle(tokens.text), children: sourceName })
3201
+ ] }),
3202
+ /* @__PURE__ */ jsxs("div", { style: summaryRowStyle, children: [
3203
+ /* @__PURE__ */ jsx("span", { style: summaryLabelStyle(tokens.textMuted), children: "Time" }),
3204
+ /* @__PURE__ */ jsx("span", { style: summaryValueStyle(tokens.text), children: "just now" })
3205
+ ] }),
3206
+ remainingLimit != null && /* @__PURE__ */ jsxs("div", { style: summaryRowStyle, children: [
3207
+ /* @__PURE__ */ jsx("span", { style: summaryLabelStyle(tokens.textMuted), children: "Remaining limit" }),
3208
+ /* @__PURE__ */ jsxs("span", { style: { ...summaryValueStyle(tokens.text), color: tokens.accent }, children: [
3209
+ "$",
3210
+ remainingLimit.toFixed(2)
3211
+ ] })
3212
+ ] })
3213
+ ] }),
3214
+ onIncreaseLimits && /* @__PURE__ */ jsxs("div", { style: upsellCardStyle(tokens), children: [
3215
+ /* @__PURE__ */ jsxs("div", { style: upsellHeaderStyle, children: [
3216
+ /* @__PURE__ */ jsx("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", style: { marginRight: 6 }, children: /* @__PURE__ */ jsx("path", { d: "M7 14l5-5 5 5", stroke: tokens.accent, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }),
3217
+ /* @__PURE__ */ jsx("strong", { children: "Want higher limits?" })
3218
+ ] }),
3219
+ /* @__PURE__ */ jsx("p", { style: upsellBodyStyle(tokens.textSecondary), children: "Increase your One-Tap limit to deposit more without re-approving." }),
3220
+ /* @__PURE__ */ jsx("button", { type: "button", onClick: onIncreaseLimits, style: upsellLinkStyle(tokens.accent), children: "Increase One-Tap limit" })
3221
+ ] })
3222
+ ] })
3223
+ ]
3224
+ }
3225
+ );
3226
+ }
3227
+ var contentStyle5 = {
3228
+ flex: 1,
3229
+ display: "flex",
3230
+ flexDirection: "column",
3231
+ alignItems: "center",
3232
+ paddingTop: 16
3233
+ };
3234
+ var headingStyle7 = (color) => ({
3235
+ fontSize: "1.5rem",
3236
+ fontWeight: 700,
3237
+ letterSpacing: "-0.02em",
3238
+ color,
3239
+ margin: "20px 0 4px"
3240
+ });
3241
+ var subtitleStyle6 = (color) => ({
3242
+ fontSize: "0.9rem",
3243
+ color,
3244
+ margin: "0 0 20px"
3245
+ });
3246
+ var summaryCardStyle = (tokens) => ({
3247
+ width: "100%",
3248
+ padding: "14px 16px",
3249
+ background: tokens.bgInput,
3250
+ border: `1px solid ${tokens.border}`,
3251
+ borderRadius: 20,
3252
+ marginBottom: 16
3253
+ });
3254
+ var summaryRowStyle = {
3255
+ display: "flex",
3256
+ justifyContent: "space-between",
3257
+ alignItems: "center",
3258
+ padding: "6px 0"
3259
+ };
3260
+ var summaryLabelStyle = (color) => ({
3261
+ fontSize: "0.84rem",
3262
+ color
3263
+ });
3264
+ var summaryValueStyle = (color) => ({
3265
+ fontSize: "0.88rem",
3266
+ fontWeight: 600,
3267
+ color
3268
+ });
3269
+ var upsellCardStyle = (tokens) => ({
3270
+ width: "100%",
3271
+ padding: "16px",
3272
+ background: tokens.bgInput,
3273
+ border: `1px solid ${tokens.border}`,
3274
+ borderRadius: 20,
3275
+ marginBottom: 16
3276
+ });
3277
+ var upsellHeaderStyle = {
3278
+ display: "flex",
3279
+ alignItems: "center",
3280
+ fontSize: "0.88rem",
3281
+ marginBottom: 4
3282
+ };
3283
+ var upsellBodyStyle = (color) => ({
3284
+ fontSize: "0.8rem",
3285
+ color,
3286
+ margin: "4px 0 10px",
3287
+ lineHeight: 1.5
3288
+ });
3289
+ var upsellLinkStyle = (color) => ({
3290
+ background: "transparent",
3291
+ border: "none",
3292
+ color,
3293
+ fontWeight: 600,
3294
+ fontSize: "0.84rem",
3295
+ cursor: "pointer",
3296
+ fontFamily: "inherit",
3297
+ padding: 0
3298
+ });
3299
+ var manageStyle = (color) => ({
3300
+ background: "transparent",
3301
+ border: "none",
3302
+ color,
3303
+ cursor: "pointer",
3304
+ fontFamily: "inherit",
3305
+ fontSize: "0.84rem",
3306
+ fontWeight: 500,
3307
+ display: "block",
3308
+ width: "100%",
3309
+ textAlign: "center",
3310
+ padding: "12px 0 0"
3311
+ });
3312
+ var ACTIVE_CREDENTIAL_STORAGE_KEY = "swype_active_credential_id";
3313
+ var MIN_SEND_AMOUNT_USD = 0.25;
3314
+ function computeSmartDefaults(accts, transferAmount) {
3315
+ if (accts.length === 0) return null;
3316
+ for (const acct of accts) {
3317
+ for (const wallet of acct.wallets) {
3318
+ if (wallet.status === "ACTIVE") {
3319
+ const bestSource = wallet.sources.find(
3320
+ (s) => s.balance.available.amount >= transferAmount
3321
+ );
3322
+ if (bestSource) {
3323
+ return { accountId: acct.id, walletId: wallet.id };
3324
+ }
3325
+ }
3326
+ }
3327
+ }
3328
+ let bestAccount = null;
3329
+ let bestWallet = null;
3330
+ let bestBalance = -1;
3331
+ let bestIsActive = false;
3332
+ for (const acct of accts) {
3333
+ for (const wallet of acct.wallets) {
3334
+ const walletBal = wallet.balance.available.amount;
3335
+ const isActive = wallet.status === "ACTIVE";
3336
+ if (walletBal > bestBalance || walletBal === bestBalance && isActive && !bestIsActive) {
3337
+ bestBalance = walletBal;
3338
+ bestAccount = acct;
3339
+ bestWallet = wallet;
3340
+ bestIsActive = isActive;
3341
+ }
3342
+ }
3343
+ }
3344
+ if (bestAccount) {
3345
+ return {
3346
+ accountId: bestAccount.id,
3347
+ walletId: bestWallet?.id ?? null
3348
+ };
3349
+ }
3350
+ return { accountId: accts[0].id, walletId: null };
3351
+ }
3352
+ function parseRawBalance(rawBalance, decimals) {
3353
+ const parsed = Number(rawBalance);
3354
+ if (!Number.isFinite(parsed)) return 0;
3355
+ return parsed / 10 ** decimals;
3356
+ }
3357
+ function buildSelectSourceChoices(options) {
3358
+ const chainChoices = [];
3359
+ const chainIndexByName = /* @__PURE__ */ new Map();
3360
+ for (const option of options) {
3361
+ const { chainName, tokenSymbol } = option;
3362
+ const balance = parseRawBalance(option.rawBalance, option.decimals);
3363
+ let chainChoice;
3364
+ const existingIdx = chainIndexByName.get(chainName);
3365
+ if (existingIdx === void 0) {
3366
+ chainChoice = { chainName, balance: 0, tokens: [] };
3367
+ chainIndexByName.set(chainName, chainChoices.length);
3368
+ chainChoices.push(chainChoice);
3369
+ } else {
3370
+ chainChoice = chainChoices[existingIdx];
3371
+ }
3372
+ chainChoice.balance += balance;
3373
+ const existing = chainChoice.tokens.find((t) => t.tokenSymbol === tokenSymbol);
3374
+ if (existing) {
3375
+ existing.balance += balance;
3376
+ } else {
3377
+ chainChoice.tokens.push({ tokenSymbol, balance });
3378
+ }
3379
+ }
3380
+ return chainChoices;
3381
+ }
3382
+ function SwypePayment({
3383
+ destination,
3384
+ onComplete,
3385
+ onError,
3386
+ useWalletConnector,
3387
+ idempotencyKey,
3388
+ merchantAuthorization,
3389
+ merchantName,
3390
+ onBack
3391
+ }) {
3392
+ const { apiBaseUrl, tokens, depositAmount } = useSwypeConfig();
3393
+ const { ready, authenticated, user, logout, getAccessToken } = usePrivy();
3394
+ const {
3395
+ sendCode: sendEmailCode,
3396
+ loginWithCode: loginWithEmailCode,
3397
+ state: emailLoginState
3398
+ } = useLoginWithEmail();
3399
+ const {
3400
+ sendCode: sendSmsCode,
3401
+ loginWithCode: loginWithSmsCode,
3402
+ state: smsLoginState
3403
+ } = useLoginWithSms();
3404
+ const [step, setStep] = useState("login");
2257
3405
  const [error, setError] = useState(null);
2258
3406
  const [providers, setProviders] = useState([]);
2259
3407
  const [accounts, setAccounts] = useState([]);
@@ -2266,10 +3414,6 @@ function SwypePayment({
2266
3414
  const [amount, setAmount] = useState(
2267
3415
  depositAmount != null ? depositAmount.toString() : ""
2268
3416
  );
2269
- const [advancedSettings, setAdvancedSettings] = useState({
2270
- asset: null,
2271
- chain: null
2272
- });
2273
3417
  const [transfer, setTransfer] = useState(null);
2274
3418
  const [creatingTransfer, setCreatingTransfer] = useState(false);
2275
3419
  const [registeringPasskey, setRegisteringPasskey] = useState(false);
@@ -2278,10 +3422,11 @@ function SwypePayment({
2278
3422
  return window.localStorage.getItem(ACTIVE_CREDENTIAL_STORAGE_KEY);
2279
3423
  });
2280
3424
  const [authInput, setAuthInput] = useState("");
2281
- const [verificationTarget, setVerificationTarget] = useState(
2282
- null
2283
- );
3425
+ const [verificationTarget, setVerificationTarget] = useState(null);
2284
3426
  const [otpCode, setOtpCode] = useState("");
3427
+ const [oneTapLimit, setOneTapLimit] = useState(100);
3428
+ const [setupComplete, setSetupComplete] = useState(false);
3429
+ const [setupStepLabel, setSetupStepLabel] = useState(void 0);
2285
3430
  const [mobileFlow, setMobileFlow] = useState(false);
2286
3431
  const pollingTransferIdRef = useRef(null);
2287
3432
  const mobileSigningTransferIdRef = useRef(null);
@@ -2307,9 +3452,7 @@ function SwypePayment({
2307
3452
  const activeOtpStatus = verificationTarget?.kind === "email" ? emailLoginState.status : verificationTarget?.kind === "phone" ? smsLoginState.status : "initial";
2308
3453
  const activeOtpErrorMessage = verificationTarget?.kind === "email" && emailLoginState.status === "error" ? emailLoginState.error?.message ?? "Failed to continue with email." : verificationTarget?.kind === "phone" && smsLoginState.status === "error" ? smsLoginState.error?.message ?? "Failed to continue with phone number." : null;
2309
3454
  useEffect(() => {
2310
- if (activeOtpErrorMessage) {
2311
- setError(activeOtpErrorMessage);
2312
- }
3455
+ if (activeOtpErrorMessage) setError(activeOtpErrorMessage);
2313
3456
  }, [activeOtpErrorMessage]);
2314
3457
  const handleSendLoginCode = useCallback(async () => {
2315
3458
  const normalizedIdentifier = normalizeAuthIdentifier(authInput);
@@ -2326,9 +3469,9 @@ function SwypePayment({
2326
3469
  await sendSmsCode({ phoneNumber: normalizedIdentifier.value });
2327
3470
  }
2328
3471
  setVerificationTarget(normalizedIdentifier);
3472
+ setStep("otp-verify");
2329
3473
  } catch (err) {
2330
- const msg = err instanceof Error ? err.message : "Failed to send verification code";
2331
- setError(msg);
3474
+ setError(err instanceof Error ? err.message : "Failed to send verification code");
2332
3475
  }
2333
3476
  }, [authInput, sendEmailCode, sendSmsCode]);
2334
3477
  const handleVerifyLoginCode = useCallback(async () => {
@@ -2346,8 +3489,7 @@ function SwypePayment({
2346
3489
  await loginWithSmsCode({ code: trimmedCode });
2347
3490
  }
2348
3491
  } catch (err) {
2349
- const msg = err instanceof Error ? err.message : "Failed to verify code";
2350
- setError(msg);
3492
+ setError(err instanceof Error ? err.message : "Failed to verify code");
2351
3493
  }
2352
3494
  }, [verificationTarget, otpCode, loginWithEmailCode, loginWithSmsCode]);
2353
3495
  const handleResendLoginCode = useCallback(async () => {
@@ -2360,17 +3502,12 @@ function SwypePayment({
2360
3502
  await sendSmsCode({ phoneNumber: verificationTarget.value });
2361
3503
  }
2362
3504
  } catch (err) {
2363
- const msg = err instanceof Error ? err.message : "Failed to resend code";
2364
- setError(msg);
3505
+ setError(err instanceof Error ? err.message : "Failed to resend code");
2365
3506
  }
2366
3507
  }, [verificationTarget, sendEmailCode, sendSmsCode]);
2367
- const handleEditIdentifier = useCallback(() => {
2368
- setError(null);
2369
- setVerificationTarget(null);
2370
- setOtpCode("");
2371
- }, []);
2372
3508
  useEffect(() => {
2373
- if (!ready || !authenticated || step !== "login") return;
3509
+ if (!ready || !authenticated) return;
3510
+ if (step !== "login" && step !== "otp-verify") return;
2374
3511
  let cancelled = false;
2375
3512
  setError(null);
2376
3513
  resetHeadlessLogin();
@@ -2382,15 +3519,11 @@ function SwypePayment({
2382
3519
  if (cancelled) return;
2383
3520
  const allPasskeys = config.passkeys ?? (config.passkey ? [config.passkey] : []);
2384
3521
  if (allPasskeys.length === 0) {
2385
- setStep("register-passkey");
3522
+ setStep("create-passkey");
2386
3523
  return;
2387
3524
  }
2388
3525
  if (activeCredentialId && allPasskeys.some((p) => p.credentialId === activeCredentialId)) {
2389
- if (depositAmount != null && depositAmount > 0) {
2390
- setStep("ready");
2391
- } else {
2392
- setStep("enter-amount");
2393
- }
3526
+ setStep("deposit");
2394
3527
  return;
2395
3528
  }
2396
3529
  if (cancelled) return;
@@ -2400,42 +3533,23 @@ function SwypePayment({
2400
3533
  if (matched) {
2401
3534
  setActiveCredentialId(matched);
2402
3535
  window.localStorage.setItem(ACTIVE_CREDENTIAL_STORAGE_KEY, matched);
2403
- if (depositAmount != null && depositAmount > 0) {
2404
- setStep("ready");
2405
- } else {
2406
- setStep("enter-amount");
2407
- }
3536
+ setStep("deposit");
2408
3537
  return;
2409
3538
  }
2410
- setStep("register-passkey");
3539
+ setStep("create-passkey");
2411
3540
  } catch {
2412
- if (!cancelled) {
2413
- if (depositAmount != null && depositAmount > 0) {
2414
- setStep("ready");
2415
- } else {
2416
- setStep("enter-amount");
2417
- }
2418
- }
3541
+ if (!cancelled) setStep("deposit");
2419
3542
  }
2420
3543
  };
2421
3544
  checkPasskey();
2422
3545
  return () => {
2423
3546
  cancelled = true;
2424
3547
  };
2425
- }, [
2426
- ready,
2427
- authenticated,
2428
- step,
2429
- depositAmount,
2430
- apiBaseUrl,
2431
- getAccessToken,
2432
- activeCredentialId,
2433
- resetHeadlessLogin
2434
- ]);
3548
+ }, [ready, authenticated, step, apiBaseUrl, getAccessToken, activeCredentialId, resetHeadlessLogin]);
2435
3549
  const loadingDataRef = useRef(false);
2436
3550
  useEffect(() => {
2437
3551
  if (!authenticated) return;
2438
- if (step === "login") return;
3552
+ if (step === "login" || step === "otp-verify") return;
2439
3553
  if (accounts.length > 0 || loadingDataRef.current) return;
2440
3554
  if (!activeCredentialId) return;
2441
3555
  let cancelled = false;
@@ -2463,10 +3577,12 @@ function SwypePayment({
2463
3577
  } else if (prov.length > 0) {
2464
3578
  setSelectedProviderId(prov[0].id);
2465
3579
  }
3580
+ if (accts.length === 0 && step === "deposit") {
3581
+ setStep("wallet-picker");
3582
+ }
2466
3583
  } catch (err) {
2467
3584
  if (!cancelled) {
2468
- const msg = err instanceof Error ? err.message : "Failed to load data";
2469
- setError(msg);
3585
+ setError(err instanceof Error ? err.message : "Failed to load data");
2470
3586
  }
2471
3587
  } finally {
2472
3588
  if (!cancelled) {
@@ -2480,15 +3596,15 @@ function SwypePayment({
2480
3596
  cancelled = true;
2481
3597
  loadingDataRef.current = false;
2482
3598
  };
2483
- }, [authenticated, step, accounts.length, apiBaseUrl, getAccessToken, activeCredentialId]);
3599
+ }, [authenticated, step, accounts.length, apiBaseUrl, getAccessToken, activeCredentialId, depositAmount]);
2484
3600
  useEffect(() => {
2485
3601
  if (!polling.transfer) return;
2486
3602
  if (polling.transfer.status === "COMPLETED") {
2487
- setStep("complete");
3603
+ setStep("success");
2488
3604
  setTransfer(polling.transfer);
2489
3605
  onComplete?.(polling.transfer);
2490
3606
  } else if (polling.transfer.status === "FAILED") {
2491
- setStep("complete");
3607
+ setStep("success");
2492
3608
  setTransfer(polling.transfer);
2493
3609
  setError("Transfer failed.");
2494
3610
  }
@@ -2504,13 +3620,11 @@ function SwypePayment({
2504
3620
  const elapsedMs = Date.now() - processingStartedAtRef.current;
2505
3621
  const remainingMs = PROCESSING_TIMEOUT_MS - elapsedMs;
2506
3622
  const handleTimeout = () => {
2507
- if (!hasProcessingTimedOut(processingStartedAtRef.current, Date.now())) {
2508
- return;
2509
- }
3623
+ if (!hasProcessingTimedOut(processingStartedAtRef.current, Date.now())) return;
2510
3624
  const status = getTransferStatus(polling.transfer, transfer);
2511
3625
  const msg = buildProcessingTimeoutMessage(status);
2512
3626
  polling.stopPolling();
2513
- setStep("ready");
3627
+ setStep("deposit");
2514
3628
  setError(msg);
2515
3629
  onError?.(msg);
2516
3630
  };
@@ -2519,15 +3633,12 @@ function SwypePayment({
2519
3633
  return;
2520
3634
  }
2521
3635
  const timeoutId = window.setTimeout(handleTimeout, remainingMs);
2522
- return () => {
2523
- window.clearTimeout(timeoutId);
2524
- };
3636
+ return () => window.clearTimeout(timeoutId);
2525
3637
  }, [step, polling.transfer, transfer, polling.stopPolling, onError]);
2526
3638
  useEffect(() => {
2527
3639
  if (!mobileFlow) return;
2528
3640
  const polledTransfer = polling.transfer;
2529
- if (!polledTransfer) return;
2530
- if (polledTransfer.status !== "AUTHORIZED") return;
3641
+ if (!polledTransfer || polledTransfer.status !== "AUTHORIZED") return;
2531
3642
  if (transferSigning.signing) return;
2532
3643
  if (mobileSigningTransferIdRef.current === polledTransfer.id) return;
2533
3644
  mobileSigningTransferIdRef.current = polledTransfer.id;
@@ -2548,18 +3659,14 @@ function SwypePayment({
2548
3659
  if (!mobileFlow) return;
2549
3660
  const transferIdToResume = pollingTransferIdRef.current ?? transfer?.id;
2550
3661
  if (!transferIdToResume) return;
2551
- if (!polling.isPolling) {
2552
- polling.startPolling(transferIdToResume);
2553
- }
3662
+ if (!polling.isPolling) polling.startPolling(transferIdToResume);
2554
3663
  const handleVisibility = () => {
2555
3664
  if (document.visibilityState === "visible") {
2556
3665
  polling.startPolling(transferIdToResume);
2557
3666
  }
2558
3667
  };
2559
3668
  document.addEventListener("visibilitychange", handleVisibility);
2560
- return () => {
2561
- document.removeEventListener("visibilitychange", handleVisibility);
2562
- };
3669
+ return () => document.removeEventListener("visibilitychange", handleVisibility);
2563
3670
  }, [mobileFlow, transfer?.id, polling.isPolling, polling.startPolling]);
2564
3671
  const pendingSelectSourceAction = authExecutor.pendingSelectSource;
2565
3672
  const selectSourceChoices = useMemo(() => {
@@ -2578,15 +3685,11 @@ function SwypePayment({
2578
3685
  setSelectSourceTokenSymbol("");
2579
3686
  return;
2580
3687
  }
2581
- if (initializedSelectSourceActionRef.current === pendingSelectSourceAction.id) {
2582
- return;
2583
- }
2584
- const hasRecommendedOption = !!selectSourceRecommended && selectSourceChoices.some(
2585
- (chain) => chain.chainName === selectSourceRecommended.chainName && chain.tokens.some(
2586
- (token) => token.tokenSymbol === selectSourceRecommended.tokenSymbol
2587
- )
3688
+ if (initializedSelectSourceActionRef.current === pendingSelectSourceAction.id) return;
3689
+ const hasRecommended = !!selectSourceRecommended && selectSourceChoices.some(
3690
+ (chain) => chain.chainName === selectSourceRecommended.chainName && chain.tokens.some((t) => t.tokenSymbol === selectSourceRecommended.tokenSymbol)
2588
3691
  );
2589
- if (hasRecommendedOption && selectSourceRecommended) {
3692
+ if (hasRecommended && selectSourceRecommended) {
2590
3693
  setSelectSourceChainName(selectSourceRecommended.chainName);
2591
3694
  setSelectSourceTokenSymbol(selectSourceRecommended.tokenSymbol);
2592
3695
  } else if (selectSourceChoices.length > 0 && selectSourceChoices[0].tokens.length > 0) {
@@ -2598,8 +3701,35 @@ function SwypePayment({
2598
3701
  }
2599
3702
  initializedSelectSourceActionRef.current = pendingSelectSourceAction.id;
2600
3703
  }, [pendingSelectSourceAction, selectSourceChoices, selectSourceRecommended]);
2601
- const handlePay = useCallback(async () => {
2602
- const parsedAmount = parseFloat(amount);
3704
+ const selectedAccount = accounts.find((a) => a.id === selectedAccountId);
3705
+ const selectedWallet = selectedAccount?.wallets.find((w) => w.id === selectedWalletId);
3706
+ const sourceName = selectedAccount?.name ?? selectedWallet?.chain.name ?? "Wallet";
3707
+ const sourceAddress = selectedWallet ? `${selectedWallet.name.slice(0, 6)}...${selectedWallet.name.slice(-4)}` : void 0;
3708
+ const sourceVerified = selectedWallet?.status === "ACTIVE";
3709
+ const maxSourceBalance = useMemo(() => {
3710
+ let max = 0;
3711
+ for (const acct of accounts) {
3712
+ for (const wallet of acct.wallets) {
3713
+ for (const source of wallet.sources) {
3714
+ if (source.balance.available.amount > max) {
3715
+ max = source.balance.available.amount;
3716
+ }
3717
+ }
3718
+ }
3719
+ }
3720
+ return max;
3721
+ }, [accounts]);
3722
+ const tokenCount = useMemo(() => {
3723
+ let count = 0;
3724
+ for (const acct of accounts) {
3725
+ for (const wallet of acct.wallets) {
3726
+ count += wallet.sources.length;
3727
+ }
3728
+ }
3729
+ return count;
3730
+ }, [accounts]);
3731
+ const handlePay = useCallback(async (depositAmount2) => {
3732
+ const parsedAmount = depositAmount2;
2603
3733
  if (isNaN(parsedAmount) || parsedAmount < MIN_SEND_AMOUNT_USD) {
2604
3734
  setError(`Minimum amount is $${MIN_SEND_AMOUNT_USD.toFixed(2)}.`);
2605
3735
  return;
@@ -2610,7 +3740,7 @@ function SwypePayment({
2610
3740
  }
2611
3741
  if (!activeCredentialId) {
2612
3742
  setError("Create a passkey on this device before continuing.");
2613
- setStep("register-passkey");
3743
+ setStep("create-passkey");
2614
3744
  return;
2615
3745
  }
2616
3746
  setStep("processing");
@@ -2680,12 +3810,11 @@ function SwypePayment({
2680
3810
  const msg = err instanceof Error ? err.message : "Transfer failed";
2681
3811
  setError(msg);
2682
3812
  onError?.(msg);
2683
- setStep("ready");
3813
+ setStep("deposit");
2684
3814
  } finally {
2685
3815
  setCreatingTransfer(false);
2686
3816
  }
2687
3817
  }, [
2688
- amount,
2689
3818
  sourceId,
2690
3819
  sourceType,
2691
3820
  activeCredentialId,
@@ -2697,10 +3826,103 @@ function SwypePayment({
2697
3826
  transferSigning,
2698
3827
  polling,
2699
3828
  onError,
2700
- useWalletConnector
3829
+ useWalletConnector,
3830
+ idempotencyKey,
3831
+ merchantAuthorization
3832
+ ]);
3833
+ const handleRegisterPasskey = useCallback(async () => {
3834
+ setRegisteringPasskey(true);
3835
+ setError(null);
3836
+ try {
3837
+ const token = await getAccessToken();
3838
+ if (!token) throw new Error("Not authenticated");
3839
+ const passkeyDisplayName = user?.email?.address ?? user?.google?.name ?? user?.id ?? "Swype User";
3840
+ const { credentialId, publicKey } = await createPasskeyCredential({
3841
+ userId: user?.id ?? "unknown",
3842
+ displayName: passkeyDisplayName
3843
+ });
3844
+ await registerPasskey(apiBaseUrl, token, credentialId, publicKey);
3845
+ setActiveCredentialId(credentialId);
3846
+ window.localStorage.setItem(ACTIVE_CREDENTIAL_STORAGE_KEY, credentialId);
3847
+ if (accounts.length === 0) {
3848
+ setStep("wallet-picker");
3849
+ } else {
3850
+ setStep("deposit");
3851
+ }
3852
+ } catch (err) {
3853
+ setError(err instanceof Error ? err.message : "Failed to register passkey");
3854
+ } finally {
3855
+ setRegisteringPasskey(false);
3856
+ }
3857
+ }, [getAccessToken, user, apiBaseUrl, accounts.length]);
3858
+ const handleSkipPasskey = useCallback(() => {
3859
+ if (accounts.length === 0) {
3860
+ setStep("wallet-picker");
3861
+ } else {
3862
+ setStep("deposit");
3863
+ }
3864
+ }, [accounts.length]);
3865
+ const handleSetupOneTap = useCallback(async (limit) => {
3866
+ setOneTapLimit(limit);
3867
+ setStep("setup-status");
3868
+ setSetupComplete(false);
3869
+ setSetupStepLabel("Approving tokens");
3870
+ setError(null);
3871
+ try {
3872
+ const token = await getAccessToken();
3873
+ if (!token) throw new Error("Not authenticated");
3874
+ if (!sourceId) {
3875
+ throw new Error("No wallet selected for setup.");
3876
+ }
3877
+ const setupAmount = depositAmount ?? MIN_SEND_AMOUNT_USD;
3878
+ const t = await createTransfer(apiBaseUrl, token, {
3879
+ credentialId: activeCredentialId ?? "",
3880
+ merchantAuthorization,
3881
+ sourceType,
3882
+ sourceId,
3883
+ destination,
3884
+ amount: setupAmount
3885
+ });
3886
+ if (t.authorizationSessions && t.authorizationSessions.length > 0) {
3887
+ const shouldUseConnector = shouldUseWalletConnector({
3888
+ useWalletConnector,
3889
+ userAgent: typeof navigator === "undefined" ? void 0 : navigator.userAgent
3890
+ });
3891
+ if (!shouldUseConnector) {
3892
+ setMobileFlow(true);
3893
+ window.location.href = t.authorizationSessions[0].uri;
3894
+ } else {
3895
+ await authExecutor.executeSession(t);
3896
+ }
3897
+ }
3898
+ setSetupStepLabel(void 0);
3899
+ setSetupComplete(true);
3900
+ } catch (err) {
3901
+ const msg = err instanceof Error ? err.message : "Setup failed";
3902
+ setError(msg);
3903
+ onError?.(msg);
3904
+ }
3905
+ }, [
3906
+ getAccessToken,
3907
+ sourceId,
3908
+ sourceType,
3909
+ activeCredentialId,
3910
+ destination,
3911
+ apiBaseUrl,
3912
+ merchantAuthorization,
3913
+ useWalletConnector,
3914
+ authExecutor,
3915
+ onError,
3916
+ depositAmount
2701
3917
  ]);
2702
- const handleNewPayment = () => {
2703
- setStep("ready");
3918
+ const handleSelectProvider = useCallback((providerId) => {
3919
+ setSelectedProviderId(providerId);
3920
+ setSelectedAccountId(null);
3921
+ setConnectingNewAccount(true);
3922
+ setStep("setup");
3923
+ }, []);
3924
+ const handleNewPayment = useCallback(() => {
3925
+ setStep("deposit");
2704
3926
  setTransfer(null);
2705
3927
  setError(null);
2706
3928
  setAmount(depositAmount != null ? depositAmount.toString() : "");
@@ -2710,9 +3932,9 @@ function SwypePayment({
2710
3932
  mobileSigningTransferIdRef.current = null;
2711
3933
  setConnectingNewAccount(false);
2712
3934
  setSelectedWalletId(null);
2713
- setAdvancedSettings({ asset: null, chain: null });
3935
+ setSetupComplete(false);
2714
3936
  if (accounts.length > 0) setSelectedAccountId(accounts[0].id);
2715
- };
3937
+ }, [depositAmount, accounts]);
2716
3938
  const handleLogout = useCallback(async () => {
2717
3939
  try {
2718
3940
  await logout();
@@ -2727,1134 +3949,196 @@ function SwypePayment({
2727
3949
  setError(null);
2728
3950
  setTransfer(null);
2729
3951
  setCreatingTransfer(false);
2730
- setRegisteringPasskey(false);
2731
- setProviders([]);
2732
- setAccounts([]);
2733
- setChains([]);
2734
- setSelectedAccountId(null);
2735
- setSelectedWalletId(null);
2736
- setSelectedProviderId(null);
2737
- setConnectingNewAccount(false);
2738
- setAmount(depositAmount != null ? depositAmount.toString() : "");
2739
- setAdvancedSettings({ asset: null, chain: null });
2740
- setMobileFlow(false);
2741
- setSelectSourceChainName("");
2742
- setSelectSourceTokenSymbol("");
2743
- initializedSelectSourceActionRef.current = null;
2744
- processingStartedAtRef.current = null;
2745
- pollingTransferIdRef.current = null;
2746
- mobileSigningTransferIdRef.current = null;
2747
- resetHeadlessLogin();
2748
- }, [logout, polling, depositAmount, resetHeadlessLogin]);
2749
- const handleConnectNewAccount = (providerId) => {
2750
- setSelectedProviderId(providerId);
2751
- setSelectedAccountId(null);
2752
- setConnectingNewAccount(true);
2753
- };
2754
- const cardStyle = {
2755
- background: tokens.bgCard,
2756
- borderRadius: tokens.radiusLg,
2757
- border: `1px solid ${tokens.border}`,
2758
- padding: "30px 24px 24px",
2759
- maxWidth: 420,
2760
- width: "100%",
2761
- boxShadow: tokens.shadowLg,
2762
- fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
2763
- color: tokens.text
2764
- };
2765
- const headingStyle = {
2766
- fontSize: "2rem",
2767
- fontWeight: 700,
2768
- margin: "0 0 18px 0",
2769
- letterSpacing: "-0.02em",
2770
- color: tokens.text,
2771
- textAlign: "center"
2772
- };
2773
- const btnPrimary = {
2774
- width: "100%",
2775
- padding: "15px 18px",
2776
- background: `linear-gradient(180deg, ${tokens.accent}, ${tokens.accentHover})`,
2777
- color: tokens.accentText,
2778
- border: "none",
2779
- borderRadius: "999px",
2780
- fontSize: "1.03rem",
2781
- fontWeight: 700,
2782
- cursor: "pointer",
2783
- transition: "filter 0.15s ease, transform 0.15s ease",
2784
- fontFamily: "inherit",
2785
- boxShadow: "0 8px 18px rgba(40, 182, 122, 0.28)"
2786
- };
2787
- const btnDisabled = {
2788
- ...btnPrimary,
2789
- opacity: 0.5,
2790
- cursor: "not-allowed"
2791
- };
2792
- ({
2793
- ...btnPrimary,
2794
- background: tokens.bgCard,
2795
- color: tokens.textSecondary,
2796
- border: `1px solid ${tokens.border}`});
2797
- const textFieldStyle = {
2798
- width: "100%",
2799
- padding: "15px 16px",
2800
- borderRadius: "16px",
2801
- border: `1px solid ${tokens.border}`,
2802
- background: tokens.bgInput,
2803
- color: tokens.text,
2804
- fontSize: "0.98rem",
2805
- fontFamily: "inherit",
2806
- outline: "none",
2807
- boxSizing: "border-box"
2808
- };
2809
- const authCaptionStyle = {
2810
- fontSize: "0.84rem",
2811
- color: tokens.textSecondary,
2812
- margin: 0,
2813
- lineHeight: 1.5
2814
- };
2815
- const authTertiaryButtonStyle = {
2816
- background: "transparent",
2817
- border: "none",
2818
- color: tokens.textMuted,
2819
- cursor: "pointer",
2820
- fontFamily: "inherit",
2821
- fontSize: "0.84rem",
2822
- padding: 0
2823
- };
2824
- const errorStyle = {
2825
- background: tokens.errorBg,
2826
- border: `1px solid ${tokens.error}66`,
2827
- borderRadius: tokens.radiusLg,
2828
- padding: "11px 14px",
2829
- color: tokens.error,
2830
- fontSize: "0.86rem",
2831
- marginBottom: "14px",
2832
- lineHeight: 1.5
2833
- };
2834
- const stepBadge = (label) => /* @__PURE__ */ jsxs(
2835
- "div",
2836
- {
2837
- style: {
2838
- display: "flex",
2839
- alignItems: "center",
2840
- justifyContent: "center",
2841
- gap: "10px",
2842
- marginBottom: "20px"
2843
- },
2844
- children: [
2845
- /* @__PURE__ */ jsx(
2846
- "div",
2847
- {
2848
- style: {
2849
- width: 28,
2850
- height: 7,
2851
- borderRadius: 999,
2852
- background: tokens.accent,
2853
- opacity: 0.95
2854
- }
2855
- }
2856
- ),
2857
- /* @__PURE__ */ jsx(
2858
- "div",
2859
- {
2860
- style: {
2861
- width: 8,
2862
- height: 8,
2863
- borderRadius: 999,
2864
- background: tokens.border
2865
- }
2866
- }
2867
- ),
2868
- /* @__PURE__ */ jsx(
2869
- "span",
2870
- {
2871
- style: {
2872
- fontSize: "0.75rem",
2873
- textTransform: "uppercase",
2874
- letterSpacing: "0.06em",
2875
- color: tokens.textMuted,
2876
- fontWeight: 600
2877
- },
2878
- children: label
2879
- }
2880
- )
2881
- ]
2882
- }
2883
- );
2884
- const placeholderProviders = ["A", "B", "C", "D", "E"];
2885
- const displayedSelectSourceChoices = selectSourceChoices.length > 0 ? selectSourceChoices : [
2886
- {
2887
- chainName: "Base",
2888
- balance: 0,
2889
- tokens: [{ tokenSymbol: "USDC", balance: 0 }]
2890
- }
2891
- ];
2892
- const selectedChainChoice = displayedSelectSourceChoices.find(
2893
- (choice) => choice.chainName === selectSourceChainName
2894
- ) ?? displayedSelectSourceChoices[0];
2895
- const selectSourceTokenChoices = selectedChainChoice?.tokens ?? [];
2896
- const resolvedSelectSourceChainName = selectedChainChoice?.chainName ?? selectSourceChainName;
2897
- const resolvedSelectSourceTokenSymbol = selectSourceTokenChoices.find(
2898
- (token) => token.tokenSymbol === selectSourceTokenSymbol
2899
- )?.tokenSymbol ?? selectSourceTokenChoices[0]?.tokenSymbol ?? "";
2900
- const canConfirmSelectSource = !!resolvedSelectSourceChainName && !!resolvedSelectSourceTokenSymbol;
2901
- const handleSelectSourceChainChange = (chainName) => {
2902
- setSelectSourceChainName(chainName);
2903
- const nextChain = displayedSelectSourceChoices.find(
2904
- (choice) => choice.chainName === chainName
2905
- );
2906
- if (!nextChain || nextChain.tokens.length === 0) {
2907
- setSelectSourceTokenSymbol("");
2908
- return;
2909
- }
2910
- const recommendedTokenForChain = selectSourceRecommended?.chainName === chainName ? selectSourceRecommended.tokenSymbol : null;
2911
- const hasRecommendedToken = !!recommendedTokenForChain && nextChain.tokens.some((token) => token.tokenSymbol === recommendedTokenForChain);
2912
- setSelectSourceTokenSymbol(
2913
- hasRecommendedToken && recommendedTokenForChain ? recommendedTokenForChain : nextChain.tokens[0].tokenSymbol
2914
- );
2915
- };
3952
+ setRegisteringPasskey(false);
3953
+ setProviders([]);
3954
+ setAccounts([]);
3955
+ setChains([]);
3956
+ setSelectedAccountId(null);
3957
+ setSelectedWalletId(null);
3958
+ setSelectedProviderId(null);
3959
+ setConnectingNewAccount(false);
3960
+ setAmount(depositAmount != null ? depositAmount.toString() : "");
3961
+ setMobileFlow(false);
3962
+ setSetupComplete(false);
3963
+ resetHeadlessLogin();
3964
+ }, [logout, polling, depositAmount, resetHeadlessLogin]);
2916
3965
  if (!ready) {
2917
- return /* @__PURE__ */ jsx("div", { style: cardStyle, children: /* @__PURE__ */ jsx("div", { style: { textAlign: "center", padding: "24px 0" }, children: /* @__PURE__ */ jsx(Spinner, { label: "Initializing..." }) }) });
3966
+ return /* @__PURE__ */ jsx(ScreenLayout, { children: /* @__PURE__ */ jsx("div", { style: { textAlign: "center", padding: "48px 0", flex: 1, display: "flex", alignItems: "center", justifyContent: "center" }, children: /* @__PURE__ */ jsx(Spinner, { label: "Initializing..." }) }) });
2918
3967
  }
2919
3968
  if (step === "login" && !authenticated) {
2920
- const isAwaitingOtp = verificationTarget !== null;
2921
- const isSendingCode = activeOtpStatus === "sending-code";
2922
- const isSubmittingCode = activeOtpStatus === "submitting-code";
2923
- const continueDisabled = authInput.trim().length === 0 || isSendingCode || isSubmittingCode;
2924
- const verifyDisabled = otpCode.trim().length !== 6 || isSubmittingCode;
2925
- return /* @__PURE__ */ jsx("div", { style: cardStyle, children: /* @__PURE__ */ jsxs("div", { style: { textAlign: "center" }, children: [
2926
- /* @__PURE__ */ jsx(
2927
- "div",
2928
- {
2929
- style: {
2930
- width: 56,
2931
- height: 56,
2932
- borderRadius: 14,
2933
- background: tokens.accent,
2934
- color: tokens.accentText,
2935
- display: "flex",
2936
- alignItems: "center",
2937
- justifyContent: "center",
2938
- fontWeight: 700,
2939
- fontSize: "1.35rem",
2940
- margin: "0 auto 24px",
2941
- boxShadow: "0 10px 20px rgba(40, 182, 122, 0.22)"
2942
- },
2943
- children: "S"
2944
- }
2945
- ),
2946
- /* @__PURE__ */ jsx(
2947
- "h2",
2948
- {
2949
- style: {
2950
- ...headingStyle,
2951
- fontSize: "2.05rem",
2952
- lineHeight: 1.15,
2953
- marginBottom: "10px",
2954
- whiteSpace: "pre-line"
2955
- },
2956
- children: isAwaitingOtp ? "Enter your code." : "One-time setup.\nOne-tap deposits after."
2957
- }
2958
- ),
2959
- /* @__PURE__ */ jsx(
2960
- "p",
2961
- {
2962
- style: {
2963
- ...authCaptionStyle,
2964
- margin: "0 0 26px 0",
2965
- whiteSpace: "pre-line"
2966
- },
2967
- children: isAwaitingOtp ? `We sent a 6-digit code to ${maskAuthIdentifier(verificationTarget)}.` : "Protected by Face ID."
2968
- }
2969
- ),
2970
- error && /* @__PURE__ */ jsx("div", { style: errorStyle, children: error }),
2971
- isAwaitingOtp ? /* @__PURE__ */ jsxs(Fragment, { children: [
2972
- /* @__PURE__ */ jsx(
2973
- "input",
2974
- {
2975
- id: "swype-login-code",
2976
- type: "text",
2977
- inputMode: "numeric",
2978
- autoComplete: "one-time-code",
2979
- placeholder: "Verification code",
2980
- value: otpCode,
2981
- onChange: (event) => {
2982
- setOtpCode(event.target.value.replace(/\D/g, "").slice(0, 6));
2983
- },
2984
- style: {
2985
- ...textFieldStyle,
2986
- textAlign: "center",
2987
- letterSpacing: "0.24em",
2988
- marginBottom: "14px"
2989
- }
2990
- }
2991
- ),
2992
- /* @__PURE__ */ jsx(
2993
- "button",
2994
- {
2995
- style: verifyDisabled ? btnDisabled : btnPrimary,
2996
- disabled: verifyDisabled,
2997
- onClick: handleVerifyLoginCode,
2998
- children: isSubmittingCode ? "Verifying..." : "Continue"
2999
- }
3000
- ),
3001
- /* @__PURE__ */ jsxs(
3002
- "div",
3003
- {
3004
- style: {
3005
- display: "flex",
3006
- justifyContent: "space-between",
3007
- gap: "12px",
3008
- marginTop: "14px"
3009
- },
3010
- children: [
3011
- /* @__PURE__ */ jsx("button", { type: "button", style: authTertiaryButtonStyle, onClick: handleEditIdentifier, children: "Use a different email or phone" }),
3012
- /* @__PURE__ */ jsx(
3013
- "button",
3014
- {
3015
- type: "button",
3016
- style: authTertiaryButtonStyle,
3017
- onClick: handleResendLoginCode,
3018
- disabled: isSendingCode || isSubmittingCode,
3019
- children: isSendingCode ? "Sending..." : "Resend code"
3020
- }
3021
- )
3022
- ]
3023
- }
3024
- )
3025
- ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
3026
- /* @__PURE__ */ jsx(
3027
- "input",
3028
- {
3029
- id: "swype-login-identifier",
3030
- type: "text",
3031
- inputMode: "text",
3032
- autoComplete: "username",
3033
- placeholder: "Email or phone number",
3034
- value: authInput,
3035
- onChange: (event) => setAuthInput(event.target.value),
3036
- style: { ...textFieldStyle, marginBottom: "14px" }
3037
- }
3038
- ),
3039
- /* @__PURE__ */ jsx(
3040
- "button",
3041
- {
3042
- style: continueDisabled ? btnDisabled : btnPrimary,
3043
- disabled: continueDisabled,
3044
- onClick: handleSendLoginCode,
3045
- children: isSendingCode ? "Sending code..." : "Continue"
3046
- }
3047
- ),
3048
- /* @__PURE__ */ jsxs(
3049
- "div",
3050
- {
3051
- style: {
3052
- display: "flex",
3053
- alignItems: "center",
3054
- gap: "10px",
3055
- margin: "22px 0 14px",
3056
- color: tokens.textMuted,
3057
- fontSize: "0.82rem"
3058
- },
3059
- children: [
3060
- /* @__PURE__ */ jsx("div", { style: { flex: 1, height: 1, background: tokens.border } }),
3061
- /* @__PURE__ */ jsx("span", { children: "works with" }),
3062
- /* @__PURE__ */ jsx("div", { style: { flex: 1, height: 1, background: tokens.border } })
3063
- ]
3064
- }
3065
- ),
3066
- /* @__PURE__ */ jsx(
3067
- "div",
3068
- {
3069
- "aria-label": "Works with placeholder providers",
3070
- style: {
3071
- display: "flex",
3072
- justifyContent: "center",
3073
- gap: "12px",
3074
- marginBottom: "18px"
3075
- },
3076
- children: placeholderProviders.map((providerLabel) => /* @__PURE__ */ jsx(
3077
- "div",
3078
- {
3079
- style: {
3080
- width: 34,
3081
- height: 34,
3082
- borderRadius: 999,
3083
- border: `1px solid ${tokens.border}`,
3084
- background: tokens.bgInput,
3085
- color: tokens.textMuted,
3086
- display: "flex",
3087
- alignItems: "center",
3088
- justifyContent: "center",
3089
- fontSize: "0.78rem",
3090
- fontWeight: 600
3091
- },
3092
- children: providerLabel
3093
- },
3094
- providerLabel
3095
- ))
3096
- }
3097
- ),
3098
- /* @__PURE__ */ jsx("p", { style: { ...authCaptionStyle, color: tokens.textMuted }, children: "Powered by Swype. Non-custodial." })
3099
- ] })
3100
- ] }) });
3969
+ return /* @__PURE__ */ jsx(
3970
+ LoginScreen,
3971
+ {
3972
+ authInput,
3973
+ onAuthInputChange: setAuthInput,
3974
+ onSubmit: handleSendLoginCode,
3975
+ sending: activeOtpStatus === "sending-code",
3976
+ error,
3977
+ onBack
3978
+ }
3979
+ );
3101
3980
  }
3102
- if (step === "register-passkey") {
3103
- const handleRegisterPasskey = async () => {
3104
- setRegisteringPasskey(true);
3105
- setError(null);
3106
- try {
3107
- const token = await getAccessToken();
3108
- if (!token) throw new Error("Not authenticated");
3109
- const passkeyDisplayName = user?.email?.address ?? user?.google?.name ?? user?.id ?? "Swype User";
3110
- const { credentialId, publicKey } = await createPasskeyCredential({
3111
- userId: user?.id ?? "unknown",
3112
- displayName: passkeyDisplayName
3113
- });
3114
- await registerPasskey(apiBaseUrl, token, credentialId, publicKey);
3115
- setActiveCredentialId(credentialId);
3116
- window.localStorage.setItem(ACTIVE_CREDENTIAL_STORAGE_KEY, credentialId);
3117
- if (depositAmount != null && depositAmount > 0) {
3118
- setStep("ready");
3119
- } else {
3120
- setStep("enter-amount");
3121
- }
3122
- } catch (err) {
3123
- const msg = err instanceof Error ? err.message : "Failed to register passkey";
3124
- setError(msg);
3125
- } finally {
3126
- setRegisteringPasskey(false);
3981
+ if (step === "otp-verify" && !authenticated) {
3982
+ return /* @__PURE__ */ jsx(
3983
+ OtpVerifyScreen,
3984
+ {
3985
+ maskedIdentifier: verificationTarget ? maskAuthIdentifier(verificationTarget) : "",
3986
+ otpCode,
3987
+ onOtpChange: (code) => {
3988
+ setOtpCode(code);
3989
+ setError(null);
3990
+ },
3991
+ onVerify: handleVerifyLoginCode,
3992
+ onResend: handleResendLoginCode,
3993
+ onBack: () => {
3994
+ setVerificationTarget(null);
3995
+ setOtpCode("");
3996
+ setError(null);
3997
+ setStep("login");
3998
+ },
3999
+ verifying: activeOtpStatus === "submitting-code",
4000
+ error
3127
4001
  }
3128
- };
3129
- return /* @__PURE__ */ jsx("div", { style: cardStyle, children: /* @__PURE__ */ jsxs("div", { style: { textAlign: "center" }, children: [
3130
- /* @__PURE__ */ jsxs(
3131
- "svg",
3132
- {
3133
- width: "48",
3134
- height: "48",
3135
- viewBox: "0 0 48 48",
3136
- fill: "none",
3137
- style: { margin: "0 auto 16px" },
3138
- children: [
3139
- /* @__PURE__ */ jsx("rect", { width: "48", height: "48", rx: "12", fill: tokens.accent + "20" }),
3140
- /* @__PURE__ */ jsx(
3141
- "path",
3142
- {
3143
- d: "M24 16c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm0 10c-4.42 0-8 1.79-8 4v2h16v-2c0-2.21-3.58-4-8-4z",
3144
- fill: tokens.accent
3145
- }
3146
- )
3147
- ]
3148
- }
3149
- ),
3150
- /* @__PURE__ */ jsx("h2", { style: { ...headingStyle, marginBottom: "8px" }, children: "Set Up Passkey" }),
3151
- /* @__PURE__ */ jsx(
3152
- "p",
3153
- {
3154
- style: {
3155
- fontSize: "0.875rem",
3156
- color: tokens.textSecondary,
3157
- margin: "0 0 24px 0",
3158
- lineHeight: 1.5
3159
- },
3160
- children: "Create a passkey for secure, one-touch payments. This only needs to be done once."
3161
- }
3162
- ),
3163
- error && /* @__PURE__ */ jsx("div", { style: errorStyle, children: error }),
3164
- /* @__PURE__ */ jsx(
3165
- "button",
3166
- {
3167
- style: registeringPasskey ? btnDisabled : btnPrimary,
3168
- disabled: registeringPasskey,
3169
- onClick: handleRegisterPasskey,
3170
- children: registeringPasskey ? "Creating passkey..." : "Create Passkey"
3171
- }
3172
- )
3173
- ] }) });
4002
+ );
3174
4003
  }
3175
- if (step === "enter-amount") {
3176
- const parsedAmount = parseFloat(amount);
3177
- const canContinue = !isNaN(parsedAmount) && parsedAmount >= MIN_SEND_AMOUNT_USD;
3178
- let maxSourceBalance = null;
3179
- for (const acct of accounts) {
3180
- for (const wallet of acct.wallets) {
3181
- for (const source of wallet.sources) {
3182
- const bal = source.balance.available.amount;
3183
- if (maxSourceBalance === null || bal > maxSourceBalance) {
3184
- maxSourceBalance = bal;
3185
- }
3186
- }
4004
+ if (step === "create-passkey") {
4005
+ return /* @__PURE__ */ jsx(
4006
+ CreatePasskeyScreen,
4007
+ {
4008
+ onCreatePasskey: handleRegisterPasskey,
4009
+ onSkip: handleSkipPasskey,
4010
+ onBack: () => setStep("login"),
4011
+ creating: registeringPasskey,
4012
+ error
4013
+ }
4014
+ );
4015
+ }
4016
+ if (step === "wallet-picker") {
4017
+ return /* @__PURE__ */ jsx(
4018
+ WalletPickerScreen,
4019
+ {
4020
+ providers,
4021
+ onSelectProvider: handleSelectProvider,
4022
+ onBack: () => setStep("create-passkey")
4023
+ }
4024
+ );
4025
+ }
4026
+ if (step === "setup") {
4027
+ return /* @__PURE__ */ jsx(
4028
+ SetupScreen,
4029
+ {
4030
+ availableBalance: maxSourceBalance,
4031
+ tokenCount,
4032
+ sourceName,
4033
+ onSetupOneTap: handleSetupOneTap,
4034
+ onBack: () => setStep("wallet-picker"),
4035
+ onLogout: handleLogout,
4036
+ loading: loadingData,
4037
+ error
4038
+ }
4039
+ );
4040
+ }
4041
+ if (step === "setup-status") {
4042
+ return /* @__PURE__ */ jsx(
4043
+ SetupStatusScreen,
4044
+ {
4045
+ complete: setupComplete,
4046
+ limit: oneTapLimit,
4047
+ tokensApproved: tokenCount,
4048
+ currentStepLabel: setupStepLabel,
4049
+ merchantName,
4050
+ onContinue: () => setStep("deposit"),
4051
+ onLogout: handleLogout,
4052
+ error
3187
4053
  }
4054
+ );
4055
+ }
4056
+ if (step === "deposit") {
4057
+ if (loadingData) {
4058
+ return /* @__PURE__ */ jsx(ScreenLayout, { children: /* @__PURE__ */ jsx("div", { style: { textAlign: "center", padding: "48px 0", flex: 1, display: "flex", alignItems: "center", justifyContent: "center" }, children: /* @__PURE__ */ jsx(Spinner, { label: "Loading..." }) }) });
3188
4059
  }
3189
- return /* @__PURE__ */ jsxs("div", { style: cardStyle, children: [
3190
- stepBadge("Enter amount"),
3191
- /* @__PURE__ */ jsx("h2", { style: headingStyle, children: "How much?" }),
3192
- error && /* @__PURE__ */ jsx("div", { style: errorStyle, children: error }),
3193
- /* @__PURE__ */ jsxs(
3194
- "div",
3195
- {
3196
- style: {
3197
- display: "flex",
3198
- alignItems: "center",
3199
- gap: "8px",
3200
- background: tokens.bgInput,
3201
- border: `1px solid ${tokens.border}`,
3202
- borderRadius: tokens.radiusLg,
3203
- padding: "6px 14px 6px 8px",
3204
- marginBottom: "8px"
3205
- },
3206
- children: [
3207
- /* @__PURE__ */ jsx(
3208
- "span",
3209
- {
3210
- style: {
3211
- fontSize: "1.5rem",
3212
- fontWeight: 600,
3213
- color: tokens.textMuted,
3214
- paddingLeft: "10px",
3215
- userSelect: "none"
3216
- },
3217
- children: "$"
3218
- }
3219
- ),
3220
- /* @__PURE__ */ jsx(
3221
- "input",
3222
- {
3223
- type: "number",
3224
- min: MIN_SEND_AMOUNT_USD.toFixed(2),
3225
- step: "0.01",
3226
- value: amount,
3227
- onChange: (e) => setAmount(e.target.value),
3228
- placeholder: "0.00",
3229
- style: {
3230
- flex: 1,
3231
- background: "transparent",
3232
- border: "none",
3233
- outline: "none",
3234
- color: tokens.text,
3235
- fontSize: "1.5rem",
3236
- fontWeight: 600,
3237
- fontFamily: "inherit",
3238
- padding: "10px 0"
3239
- },
3240
- autoFocus: true
3241
- }
3242
- ),
3243
- /* @__PURE__ */ jsx(
3244
- "span",
3245
- {
3246
- style: {
3247
- fontSize: "0.825rem",
3248
- fontWeight: 600,
3249
- color: tokens.textMuted,
3250
- background: tokens.bgCard,
3251
- padding: "6px 12px",
3252
- border: `1px solid ${tokens.border}`,
3253
- borderRadius: "999px"
3254
- },
3255
- children: "USD"
3256
- }
3257
- )
3258
- ]
3259
- }
3260
- ),
3261
- /* @__PURE__ */ jsx(
3262
- "div",
3263
- {
3264
- style: {
3265
- fontSize: "0.8rem",
3266
- color: tokens.textMuted,
3267
- marginBottom: "20px",
3268
- paddingLeft: "2px"
3269
- },
3270
- children: loadingData ? /* @__PURE__ */ jsx("span", { children: "Loading balance..." }) : maxSourceBalance !== null && maxSourceBalance > 0 ? /* @__PURE__ */ jsxs("span", { children: [
3271
- "Available: ",
3272
- /* @__PURE__ */ jsxs("span", { style: { fontWeight: 600, color: tokens.textSecondary }, children: [
3273
- "$",
3274
- maxSourceBalance.toFixed(2)
3275
- ] })
3276
- ] }) : null
3277
- }
3278
- ),
3279
- /* @__PURE__ */ jsx(
3280
- "button",
3281
- {
3282
- style: canContinue ? btnPrimary : btnDisabled,
3283
- disabled: !canContinue,
3284
- onClick: () => {
3285
- setError(null);
3286
- setStep("ready");
3287
- },
3288
- children: "Continue"
3289
- }
3290
- )
3291
- ] });
3292
- }
3293
- if (step === "ready") {
3294
- const parsedAmount = parseFloat(amount);
3295
- const canPay = !isNaN(parsedAmount) && parsedAmount >= MIN_SEND_AMOUNT_USD && !!sourceId && !loadingData;
3296
- const noAccounts = !loadingData && accounts.length === 0;
3297
- return /* @__PURE__ */ jsxs("div", { style: cardStyle, children: [
3298
- /* @__PURE__ */ jsxs("div", { style: { position: "relative" }, children: [
3299
- stepBadge("Review & pay"),
3300
- /* @__PURE__ */ jsx(
3301
- "button",
3302
- {
3303
- type: "button",
3304
- onClick: handleLogout,
3305
- style: {
3306
- position: "absolute",
3307
- top: 0,
3308
- right: 0,
3309
- background: "transparent",
3310
- border: "none",
3311
- color: tokens.textMuted,
3312
- cursor: "pointer",
3313
- fontSize: "0.75rem",
3314
- fontWeight: 600,
3315
- letterSpacing: "0.04em",
3316
- textTransform: "uppercase",
3317
- fontFamily: "inherit",
3318
- padding: 0
3319
- },
3320
- children: "Logout"
3321
- }
3322
- )
3323
- ] }),
3324
- error && /* @__PURE__ */ jsx("div", { style: errorStyle, children: error }),
3325
- loadingData ? /* @__PURE__ */ jsx("div", { style: { padding: "24px 0", textAlign: "center" }, children: /* @__PURE__ */ jsx(Spinner, { label: "Loading..." }) }) : /* @__PURE__ */ jsxs(Fragment, { children: [
3326
- /* @__PURE__ */ jsxs(
3327
- "div",
3328
- {
3329
- style: {
3330
- textAlign: "center",
3331
- marginBottom: "20px"
3332
- },
3333
- children: [
3334
- /* @__PURE__ */ jsxs(
3335
- "div",
3336
- {
3337
- style: {
3338
- fontSize: "2rem",
3339
- fontWeight: 700,
3340
- color: tokens.text,
3341
- lineHeight: 1.2
3342
- },
3343
- children: [
3344
- "$",
3345
- parsedAmount > 0 ? parsedAmount.toFixed(2) : "0.00"
3346
- ]
3347
- }
3348
- ),
3349
- /* @__PURE__ */ jsx(
3350
- "button",
3351
- {
3352
- onClick: () => setStep("enter-amount"),
3353
- style: {
3354
- background: "transparent",
3355
- border: "none",
3356
- cursor: "pointer",
3357
- color: tokens.textMuted,
3358
- fontSize: "0.75rem",
3359
- fontFamily: "inherit",
3360
- outline: "none",
3361
- padding: "4px 8px",
3362
- marginTop: "4px"
3363
- },
3364
- children: "Change amount"
3365
- }
3366
- )
3367
- ]
3368
- }
3369
- ),
3370
- /* @__PURE__ */ jsx(
3371
- "div",
3372
- {
3373
- style: {
3374
- fontSize: "0.825rem",
3375
- color: tokens.textSecondary,
3376
- marginBottom: "16px",
3377
- padding: "12px 14px",
3378
- background: tokens.bgInput,
3379
- borderRadius: tokens.radiusLg,
3380
- border: `1px solid ${tokens.border}`,
3381
- lineHeight: 1.7
3382
- },
3383
- children: /* @__PURE__ */ jsx(
3384
- "div",
3385
- {
3386
- style: {
3387
- display: "flex",
3388
- justifyContent: "space-between",
3389
- alignItems: "center"
3390
- },
3391
- children: noAccounts ? /* @__PURE__ */ jsx(Fragment, {}) : /* @__PURE__ */ jsxs("div", { children: [
3392
- /* @__PURE__ */ jsx("span", { children: "From" }),
3393
- /* @__PURE__ */ jsx(
3394
- AccountDropdown,
3395
- {
3396
- accounts,
3397
- selectedAccountId,
3398
- selectedWalletId,
3399
- onSelect: (id) => {
3400
- setSelectedAccountId(id);
3401
- setSelectedWalletId(null);
3402
- setConnectingNewAccount(false);
3403
- setSelectedProviderId(null);
3404
- },
3405
- onWalletSelect: (accountId, walletId) => {
3406
- setSelectedAccountId(accountId);
3407
- setSelectedWalletId(walletId);
3408
- setConnectingNewAccount(false);
3409
- setSelectedProviderId(null);
3410
- }
3411
- }
3412
- )
3413
- ] })
3414
- }
3415
- )
3416
- }
3417
- ),
3418
- noAccounts && /* @__PURE__ */ jsxs("div", { style: { marginBottom: "16px" }, children: [
3419
- /* @__PURE__ */ jsx(
3420
- "label",
3421
- {
3422
- style: {
3423
- display: "block",
3424
- fontSize: "0.8rem",
3425
- color: tokens.textMuted,
3426
- marginBottom: "8px",
3427
- fontWeight: 500,
3428
- textTransform: "uppercase",
3429
- letterSpacing: "0.05em"
3430
- },
3431
- children: "Connect a wallet"
3432
- }
3433
- ),
3434
- /* @__PURE__ */ jsx(
3435
- "div",
3436
- {
3437
- style: {
3438
- display: "flex",
3439
- flexDirection: "column",
3440
- gap: "8px"
3441
- },
3442
- children: providers.map((p) => /* @__PURE__ */ jsx(
3443
- ProviderCard,
3444
- {
3445
- provider: p,
3446
- selected: selectedProviderId === p.id,
3447
- onClick: () => {
3448
- setSelectedProviderId(p.id);
3449
- setSelectedAccountId(null);
3450
- setConnectingNewAccount(false);
3451
- }
3452
- },
3453
- p.id
3454
- ))
3455
- }
3456
- )
3457
- ] }),
3458
- /* @__PURE__ */ jsxs(
3459
- "button",
3460
- {
3461
- style: canPay ? btnPrimary : btnDisabled,
3462
- disabled: !canPay,
3463
- onClick: handlePay,
3464
- children: [
3465
- "Pay $",
3466
- parsedAmount > 0 ? parsedAmount.toFixed(2) : "0.00"
3467
- ]
3468
- }
3469
- ),
3470
- !noAccounts && /* @__PURE__ */ jsx(
3471
- AdvancedSettings,
3472
- {
3473
- settings: advancedSettings,
3474
- onChange: setAdvancedSettings,
3475
- chains,
3476
- providers,
3477
- onConnectNewAccount: handleConnectNewAccount,
3478
- connectingNewAccount
3479
- }
3480
- )
3481
- ] })
3482
- ] });
4060
+ const parsedAmt = depositAmount != null ? depositAmount : 5;
4061
+ return /* @__PURE__ */ jsx(
4062
+ DepositScreen,
4063
+ {
4064
+ merchantName,
4065
+ sourceName,
4066
+ sourceAddress,
4067
+ sourceVerified,
4068
+ availableBalance: maxSourceBalance,
4069
+ remainingLimit: oneTapLimit,
4070
+ tokenCount,
4071
+ initialAmount: parsedAmt,
4072
+ estimatedFeePct: 0.6,
4073
+ estimatedFeeUsd: parsedAmt * 6e-3,
4074
+ processing: creatingTransfer,
4075
+ error,
4076
+ onDeposit: handlePay,
4077
+ onChangeSource: () => setStep("wallet-picker"),
4078
+ onSwitchWallet: () => setStep("wallet-picker"),
4079
+ onBack: onBack ?? (() => handleLogout()),
4080
+ onLogout: handleLogout
4081
+ }
4082
+ );
3483
4083
  }
3484
4084
  if (step === "processing") {
3485
- if (pendingSelectSourceAction) {
3486
- const chainValue = resolvedSelectSourceChainName;
3487
- const tokenValue = resolvedSelectSourceTokenSymbol;
3488
- return /* @__PURE__ */ jsxs("div", { style: cardStyle, children: [
3489
- stepBadge("Select source"),
3490
- /* @__PURE__ */ jsxs("div", { style: { textAlign: "center", marginBottom: "16px" }, children: [
3491
- /* @__PURE__ */ jsx("h2", { style: { ...headingStyle, marginBottom: "8px" }, children: "Select payment source" }),
3492
- /* @__PURE__ */ jsx(
3493
- "p",
3494
- {
3495
- style: {
3496
- fontSize: "0.85rem",
3497
- color: tokens.textSecondary,
3498
- margin: 0,
3499
- lineHeight: 1.5
3500
- },
3501
- children: "Confirm the chain and token to use for this transfer."
3502
- }
3503
- )
3504
- ] }),
3505
- /* @__PURE__ */ jsxs(
3506
- "div",
3507
- {
3508
- style: {
3509
- fontSize: "0.825rem",
3510
- color: tokens.textSecondary,
3511
- marginBottom: "16px",
3512
- padding: "14px",
3513
- background: tokens.bgInput,
3514
- borderRadius: tokens.radius,
3515
- border: `1px solid ${tokens.border}`
3516
- },
3517
- children: [
3518
- /* @__PURE__ */ jsx(
3519
- "label",
3520
- {
3521
- htmlFor: "swype-select-source-chain",
3522
- style: {
3523
- display: "block",
3524
- fontSize: "0.75rem",
3525
- fontWeight: 600,
3526
- marginBottom: "6px",
3527
- color: tokens.textMuted,
3528
- textTransform: "uppercase",
3529
- letterSpacing: "0.04em"
3530
- },
3531
- children: "Chain"
3532
- }
3533
- ),
3534
- /* @__PURE__ */ jsx(
3535
- "select",
3536
- {
3537
- id: "swype-select-source-chain",
3538
- value: chainValue,
3539
- onChange: (event) => handleSelectSourceChainChange(event.target.value),
3540
- style: {
3541
- width: "100%",
3542
- marginBottom: "12px",
3543
- padding: "10px 12px",
3544
- borderRadius: tokens.radiusLg,
3545
- border: `1px solid ${tokens.border}`,
3546
- background: tokens.bgInput,
3547
- color: tokens.text,
3548
- fontFamily: "inherit",
3549
- fontSize: "0.875rem",
3550
- outline: "none"
3551
- },
3552
- children: displayedSelectSourceChoices.map((chainChoice) => /* @__PURE__ */ jsxs("option", { value: chainChoice.chainName, children: [
3553
- chainChoice.chainName,
3554
- " ($",
3555
- chainChoice.balance.toFixed(2),
3556
- ")"
3557
- ] }, chainChoice.chainName))
3558
- }
3559
- ),
3560
- /* @__PURE__ */ jsx(
3561
- "label",
3562
- {
3563
- htmlFor: "swype-select-source-token",
3564
- style: {
3565
- display: "block",
3566
- fontSize: "0.75rem",
3567
- fontWeight: 600,
3568
- marginBottom: "6px",
3569
- color: tokens.textMuted,
3570
- textTransform: "uppercase",
3571
- letterSpacing: "0.04em"
3572
- },
3573
- children: "Token"
3574
- }
3575
- ),
3576
- /* @__PURE__ */ jsx(
3577
- "select",
3578
- {
3579
- id: "swype-select-source-token",
3580
- value: tokenValue,
3581
- onChange: (event) => setSelectSourceTokenSymbol(event.target.value),
3582
- style: {
3583
- width: "100%",
3584
- padding: "10px 12px",
3585
- borderRadius: tokens.radiusLg,
3586
- border: `1px solid ${tokens.border}`,
3587
- background: tokens.bgInput,
3588
- color: tokens.text,
3589
- fontFamily: "inherit",
3590
- fontSize: "0.875rem",
3591
- outline: "none"
3592
- },
3593
- children: selectSourceTokenChoices.map((tokenChoice) => /* @__PURE__ */ jsxs("option", { value: tokenChoice.tokenSymbol, children: [
3594
- tokenChoice.tokenSymbol,
3595
- " ($",
3596
- tokenChoice.balance.toFixed(2),
3597
- ")"
3598
- ] }, tokenChoice.tokenSymbol))
3599
- }
3600
- )
3601
- ]
3602
- }
3603
- ),
3604
- /* @__PURE__ */ jsx(
3605
- "button",
3606
- {
3607
- style: canConfirmSelectSource ? btnPrimary : btnDisabled,
3608
- disabled: !canConfirmSelectSource,
3609
- onClick: () => {
3610
- if (!canConfirmSelectSource) return;
3611
- authExecutor.resolveSelectSource({
3612
- chainName: resolvedSelectSourceChainName,
3613
- tokenSymbol: resolvedSelectSourceTokenSymbol
3614
- });
3615
- },
3616
- children: "Confirm source"
3617
- }
3618
- )
3619
- ] });
3620
- }
3621
- if (transferSigning.signing && transferSigning.signPayload) {
3622
- const payload = transferSigning.signPayload;
3623
- return /* @__PURE__ */ jsx("div", { style: cardStyle, children: /* @__PURE__ */ jsxs("div", { style: { textAlign: "center", padding: "16px 0" }, children: [
3624
- /* @__PURE__ */ jsxs("svg", { width: "48", height: "48", viewBox: "0 0 48 48", fill: "none", style: { margin: "0 auto 16px" }, children: [
3625
- /* @__PURE__ */ jsx("rect", { width: "48", height: "48", rx: "12", fill: tokens.accent + "20" }),
3626
- /* @__PURE__ */ jsx("path", { d: "M24 14v8M20 18h8M24 26v2M24 32v2", stroke: tokens.accent, strokeWidth: "2", strokeLinecap: "round" })
3627
- ] }),
3628
- /* @__PURE__ */ jsx("h2", { style: { ...headingStyle, marginBottom: "8px" }, children: "Authorize Transfer" }),
3629
- /* @__PURE__ */ jsx("p", { style: { fontSize: "0.85rem", color: tokens.textSecondary, margin: "0 0 16px 0", lineHeight: 1.5 }, children: "Use your passkey to confirm this payment." }),
3630
- /* @__PURE__ */ jsxs("div", { style: { fontSize: "0.825rem", color: tokens.textSecondary, padding: "12px 14px", background: tokens.bgInput, borderRadius: tokens.radiusLg, border: `1px solid ${tokens.border}`, textAlign: "left", lineHeight: 1.7, marginBottom: "16px" }, children: [
3631
- payload.amount && payload.tokenSymbol && /* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between" }, children: [
3632
- /* @__PURE__ */ jsx("span", { children: "Amount" }),
3633
- /* @__PURE__ */ jsxs("span", { style: { fontWeight: 600, color: tokens.text }, children: [
3634
- payload.amount,
3635
- " ",
3636
- payload.tokenSymbol
3637
- ] })
3638
- ] }),
3639
- payload.bridgeRelayAddress && /* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between" }, children: [
3640
- /* @__PURE__ */ jsx("span", { children: "Bridge relay" }),
3641
- /* @__PURE__ */ jsxs("span", { style: { fontFamily: '"SF Mono", "Fira Code", monospace', fontSize: "0.75rem" }, children: [
3642
- payload.bridgeRelayAddress.slice(0, 6),
3643
- "...",
3644
- payload.bridgeRelayAddress.slice(-4)
3645
- ] })
3646
- ] }),
3647
- payload.estimatedFeeUsd && /* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between" }, children: [
3648
- /* @__PURE__ */ jsx("span", { children: "Est. fee" }),
3649
- /* @__PURE__ */ jsxs("span", { style: { fontWeight: 600 }, children: [
3650
- "$",
3651
- payload.estimatedFeeUsd
3652
- ] })
3653
- ] })
3654
- ] }),
3655
- /* @__PURE__ */ jsx(Spinner, { label: "Waiting for passkey..." })
3656
- ] }) });
3657
- }
3658
4085
  const currentActionType = authExecutor.currentAction?.type;
3659
- const getRegistrationMessage = () => {
3660
- switch (currentActionType) {
3661
- case "CREATE_SMART_ACCOUNT":
3662
- return {
3663
- label: "Creating your smart account...",
3664
- description: "Setting up your smart account for gasless payments."
3665
- };
3666
- case "APPROVE_PERMIT2":
3667
- return {
3668
- label: "Approving token access...",
3669
- description: "Approve the prompt in your wallet to allow secure token transfers."
3670
- };
3671
- case "SIGN_PERMIT2":
3672
- return {
3673
- label: "Signing transfer permission...",
3674
- description: "Sign the permit to allow your smart account to transfer tokens on your behalf."
3675
- };
3676
- default:
3677
- return { label: "", description: "" };
3678
- }
3679
- };
3680
- const regMsg = getRegistrationMessage();
3681
- getDisplayTransferStatus(polling.transfer, transfer);
3682
- getTransferIdSuffix(polling.transfer, transfer);
3683
- const statusLabel = creatingTransfer ? "Creating Transfer" : mobileFlow ? "Waiting for Authorization" : authExecutor.executing && regMsg.label ? regMsg.label : authExecutor.executing ? "Authorizing" : transferSigning.signing ? "Sending transfer" : polling.isPolling ? "Transfer Sent" : "Please wait...";
3684
- return /* @__PURE__ */ jsx("div", { style: cardStyle, children: /* @__PURE__ */ jsxs("div", { style: { textAlign: "center", padding: "16px 0" }, children: [
4086
+ const statusLabel = creatingTransfer ? "Creating Transfer" : mobileFlow ? "Waiting for Authorization" : authExecutor.executing ? currentActionType?.replace(/_/g, " ") ?? "Authorizing" : transferSigning.signing ? "Sending transfer" : polling.isPolling ? "Transfer Sent" : "Please wait...";
4087
+ return /* @__PURE__ */ jsx(ScreenLayout, { children: /* @__PURE__ */ jsxs("div", { style: { textAlign: "center", padding: "48px 0", flex: 1, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center" }, children: [
3685
4088
  /* @__PURE__ */ jsx(Spinner, { size: 48 }),
3686
- /* @__PURE__ */ jsx(
3687
- "h2",
3688
- {
3689
- style: {
3690
- ...headingStyle,
3691
- marginTop: "20px",
3692
- marginBottom: "8px"
3693
- },
3694
- children: statusLabel
3695
- }
3696
- ),
3697
- polling.error && /* @__PURE__ */ jsxs(
3698
- "p",
3699
- {
3700
- style: {
3701
- marginTop: "8px",
3702
- marginBottom: 0,
3703
- fontSize: "0.75rem",
3704
- color: tokens.textMuted
3705
- },
3706
- children: [
3707
- "Last polling error: ",
3708
- polling.error
3709
- ]
3710
- }
3711
- ),
3712
- !mobileFlow && authExecutor.results.length > 0 && /* @__PURE__ */ jsx("div", { style: { marginTop: "20px", textAlign: "left" }, children: authExecutor.results.map((r) => /* @__PURE__ */ jsxs(
3713
- "div",
3714
- {
3715
- style: {
3716
- display: "flex",
3717
- alignItems: "center",
3718
- gap: "8px",
3719
- padding: "6px 0",
3720
- fontSize: "0.8rem",
3721
- color: r.status === "success" ? tokens.success : tokens.error
3722
- },
3723
- children: [
3724
- /* @__PURE__ */ jsx("span", { children: r.status === "success" ? "\u2713" : "\u2717" }),
3725
- /* @__PURE__ */ jsx("span", { children: r.type.replace(/_/g, " ") })
3726
- ]
3727
- },
3728
- r.actionId
3729
- )) }),
3730
- (error || authExecutor.error || transferSigning.error || polling.error) && /* @__PURE__ */ jsx(
3731
- "div",
3732
- {
3733
- style: { ...errorStyle, marginTop: "16px", textAlign: "left" },
3734
- children: error || authExecutor.error || transferSigning.error || polling.error
3735
- }
3736
- )
4089
+ /* @__PURE__ */ jsx("h2", { style: { fontSize: "1.4rem", fontWeight: 700, color: tokens.text, marginTop: 20, marginBottom: 8 }, children: statusLabel }),
4090
+ (error || authExecutor.error || transferSigning.error || polling.error) && /* @__PURE__ */ jsx("div", { style: {
4091
+ background: tokens.errorBg,
4092
+ border: `1px solid ${tokens.error}66`,
4093
+ borderRadius: 16,
4094
+ padding: "11px 14px",
4095
+ color: tokens.error,
4096
+ fontSize: "0.84rem",
4097
+ marginTop: 16,
4098
+ lineHeight: 1.5,
4099
+ textAlign: "left",
4100
+ maxWidth: 340
4101
+ }, children: error || authExecutor.error || transferSigning.error || polling.error })
3737
4102
  ] }) });
3738
4103
  }
3739
- if (step === "complete") {
3740
- const succeeded = transfer?.status === "COMPLETED";
3741
- return /* @__PURE__ */ jsx("div", { style: cardStyle, children: /* @__PURE__ */ jsxs("div", { style: { textAlign: "center" }, children: [
3742
- /* @__PURE__ */ jsx(
3743
- "div",
3744
- {
3745
- style: {
3746
- width: 56,
3747
- height: 56,
3748
- borderRadius: "50%",
3749
- background: succeeded ? tokens.success + "20" : tokens.error + "20",
3750
- display: "flex",
3751
- alignItems: "center",
3752
- justifyContent: "center",
3753
- margin: "0 auto 16px"
3754
- },
3755
- children: succeeded ? /* @__PURE__ */ jsx("svg", { width: "28", height: "28", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ jsx(
3756
- "path",
3757
- {
3758
- d: "M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41L9 16.17z",
3759
- fill: tokens.success
3760
- }
3761
- ) }) : /* @__PURE__ */ jsx("svg", { width: "28", height: "28", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ jsx(
3762
- "path",
3763
- {
3764
- d: "M18.3 5.71L12 12.01 5.7 5.71 4.29 7.12l6.3 6.3-6.3 6.29 1.41 1.41 6.3-6.29 6.29 6.29 1.41-1.41-6.29-6.29 6.29-6.3-1.41-1.41z",
3765
- fill: tokens.error
3766
- }
3767
- ) })
3768
- }
3769
- ),
3770
- /* @__PURE__ */ jsx(
3771
- "h2",
3772
- {
3773
- style: {
3774
- ...headingStyle,
3775
- marginBottom: "8px",
3776
- color: succeeded ? tokens.success : tokens.error
3777
- },
3778
- children: succeeded ? "Payment Complete" : "Payment Failed"
3779
- }
3780
- ),
3781
- transfer && /* @__PURE__ */ jsxs(
3782
- "div",
3783
- {
3784
- style: {
3785
- fontSize: "0.825rem",
3786
- color: tokens.textSecondary,
3787
- margin: "0 0 24px 0",
3788
- padding: "14px",
3789
- background: tokens.bgInput,
3790
- borderRadius: tokens.radiusLg,
3791
- border: `1px solid ${tokens.border}`,
3792
- textAlign: "left",
3793
- lineHeight: 1.8
3794
- },
3795
- children: [
3796
- /* @__PURE__ */ jsxs(
3797
- "div",
3798
- {
3799
- style: { display: "flex", justifyContent: "space-between" },
3800
- children: [
3801
- /* @__PURE__ */ jsx("span", { children: "Amount" }),
3802
- /* @__PURE__ */ jsxs("span", { style: { fontWeight: 600, color: tokens.text }, children: [
3803
- "$",
3804
- transfer.amount?.amount?.toFixed(2),
3805
- " ",
3806
- transfer.amount?.currency
3807
- ] })
3808
- ]
3809
- }
3810
- ),
3811
- /* @__PURE__ */ jsxs(
3812
- "div",
3813
- {
3814
- style: { display: "flex", justifyContent: "space-between" },
3815
- children: [
3816
- /* @__PURE__ */ jsx("span", { children: "Status" }),
3817
- /* @__PURE__ */ jsx(
3818
- "span",
3819
- {
3820
- style: {
3821
- fontWeight: 600,
3822
- color: succeeded ? tokens.success : tokens.error
3823
- },
3824
- children: transfer.status
3825
- }
3826
- )
3827
- ]
3828
- }
3829
- ),
3830
- /* @__PURE__ */ jsxs(
3831
- "div",
3832
- {
3833
- style: { display: "flex", justifyContent: "space-between" },
3834
- children: [
3835
- /* @__PURE__ */ jsx("span", { children: "Transfer ID" }),
3836
- /* @__PURE__ */ jsxs(
3837
- "span",
3838
- {
3839
- style: {
3840
- fontFamily: '"SF Mono", "Fira Code", monospace',
3841
- fontSize: "0.75rem"
3842
- },
3843
- children: [
3844
- transfer.id.slice(0, 8),
3845
- "..."
3846
- ]
3847
- }
3848
- )
3849
- ]
3850
- }
3851
- )
3852
- ]
3853
- }
3854
- ),
3855
- error && /* @__PURE__ */ jsx("div", { style: { ...errorStyle, textAlign: "left" }, children: error }),
3856
- /* @__PURE__ */ jsx("button", { style: btnPrimary, onClick: handleNewPayment, children: succeeded ? "Make Another Payment" : "Try Again" })
3857
- ] }) });
4104
+ if (step === "success") {
4105
+ transfer?.status === "COMPLETED";
4106
+ const displayAmount = transfer?.amount?.amount ?? 0;
4107
+ const displayCurrency = transfer?.amount?.currency ?? "USD";
4108
+ return /* @__PURE__ */ jsx(
4109
+ SuccessScreen,
4110
+ {
4111
+ amount: displayAmount,
4112
+ currency: displayCurrency,
4113
+ merchantName,
4114
+ sourceName,
4115
+ remainingLimit: oneTapLimit > displayAmount ? oneTapLimit - displayAmount : 0,
4116
+ onDone: handleNewPayment,
4117
+ onLogout: handleLogout
4118
+ }
4119
+ );
4120
+ }
4121
+ if (step === "low-balance") {
4122
+ return /* @__PURE__ */ jsx(
4123
+ DepositScreen,
4124
+ {
4125
+ merchantName,
4126
+ sourceName,
4127
+ sourceAddress,
4128
+ sourceVerified,
4129
+ availableBalance: 0,
4130
+ remainingLimit: oneTapLimit,
4131
+ tokenCount,
4132
+ initialAmount: depositAmount ?? 5,
4133
+ processing: false,
4134
+ error,
4135
+ onDeposit: handlePay,
4136
+ onChangeSource: () => setStep("wallet-picker"),
4137
+ onSwitchWallet: () => setStep("wallet-picker"),
4138
+ onBack: onBack ?? (() => handleLogout()),
4139
+ onLogout: handleLogout
4140
+ }
4141
+ );
3858
4142
  }
3859
4143
  return null;
3860
4144
  }