@swype-org/react-sdk 0.1.31 → 0.1.33

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
@@ -1,5 +1,5 @@
1
1
  import { createContext, useRef, useState, useCallback, useMemo, useContext, useEffect } from 'react';
2
- import { PrivyProvider, usePrivy, useLoginWithEmail, useLoginWithSms } from '@privy-io/react-auth';
2
+ import { PrivyProvider, usePrivy, useLoginWithEmail, useLoginWithSms, useLoginWithOAuth } from '@privy-io/react-auth';
3
3
  import { createConfig, http, WagmiProvider, useConfig, useConnect, useSwitchChain } from 'wagmi';
4
4
  import { mainnet, arbitrum, base } from 'wagmi/chains';
5
5
  import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
@@ -1448,8 +1448,20 @@ function hasProcessingTimedOut(processingStartedAtMs, nowMs) {
1448
1448
  if (!processingStartedAtMs) return false;
1449
1449
  return nowMs - processingStartedAtMs >= PROCESSING_TIMEOUT_MS;
1450
1450
  }
1451
+ var STATUS_DISPLAY_LABELS = {
1452
+ CREATED: "created",
1453
+ AUTHORIZED: "authorized",
1454
+ SENDING: "sending",
1455
+ SENT: "confirming delivery",
1456
+ COMPLETED: "completed",
1457
+ FAILED: "failed"
1458
+ };
1459
+ function getStatusDisplayLabel(status) {
1460
+ return STATUS_DISPLAY_LABELS[status] ?? status;
1461
+ }
1451
1462
  function buildProcessingTimeoutMessage(status) {
1452
- return `Payment is taking longer than expected (status: ${status}). Please try again.`;
1463
+ const label = getStatusDisplayLabel(status);
1464
+ return `Payment is taking longer than expected (status: ${label}). Please try again.`;
1453
1465
  }
1454
1466
 
1455
1467
  // src/walletFlow.ts
@@ -1798,7 +1810,7 @@ function LimitSlider({
1798
1810
  (e) => onChange(Number(e.target.value)),
1799
1811
  [onChange]
1800
1812
  );
1801
- return /* @__PURE__ */ jsxs("div", { style: wrapperStyle, children: [
1813
+ return /* @__PURE__ */ jsxs("div", { className: "swype-slider-wrap", style: wrapperStyle, children: [
1802
1814
  /* @__PURE__ */ jsxs("div", { style: trackContainerStyle, children: [
1803
1815
  /* @__PURE__ */ jsx("div", { style: trackBgStyle(tokens.border) }),
1804
1816
  /* @__PURE__ */ jsx("div", { style: trackFillStyle(tokens.accent, pct) }),
@@ -1812,7 +1824,7 @@ function LimitSlider({
1812
1824
  value,
1813
1825
  onChange: handleChange,
1814
1826
  disabled,
1815
- style: rangeInputStyle(tokens.accent)
1827
+ style: rangeInputStyle
1816
1828
  }
1817
1829
  )
1818
1830
  ] }),
@@ -1846,17 +1858,19 @@ var trackFillStyle = (color, pct) => ({
1846
1858
  borderRadius: 2,
1847
1859
  background: color
1848
1860
  });
1849
- var rangeInputStyle = (_accent) => ({
1861
+ var rangeInputStyle = {
1850
1862
  position: "absolute",
1851
1863
  left: 0,
1852
1864
  right: 0,
1853
1865
  width: "100%",
1854
1866
  height: 28,
1855
1867
  margin: 0,
1856
- opacity: 0,
1857
1868
  cursor: "pointer",
1858
- zIndex: 2
1859
- });
1869
+ zIndex: 2,
1870
+ WebkitAppearance: "none",
1871
+ appearance: "none",
1872
+ background: "transparent"
1873
+ };
1860
1874
  var ticksStyle = {
1861
1875
  display: "flex",
1862
1876
  justifyContent: "space-between",
@@ -1868,10 +1882,8 @@ var tickLabelStyle = (color) => ({
1868
1882
  color
1869
1883
  });
1870
1884
  var sliderThumbCss = (accent) => `
1871
- .swype-slider-wrap input[type="range"] {
1872
- -webkit-appearance: none;
1873
- appearance: none;
1874
- opacity: 1 !important;
1885
+ .swype-slider-wrap input[type="range"]::-webkit-slider-runnable-track {
1886
+ height: 4px;
1875
1887
  background: transparent;
1876
1888
  }
1877
1889
  .swype-slider-wrap input[type="range"]::-webkit-slider-thumb {
@@ -1883,6 +1895,21 @@ var sliderThumbCss = (accent) => `
1883
1895
  border: 3px solid #fff;
1884
1896
  box-shadow: 0 2px 6px rgba(0,0,0,0.15);
1885
1897
  cursor: pointer;
1898
+ margin-top: -8px;
1899
+ }
1900
+ .swype-slider-wrap input[type="range"]::-moz-range-track {
1901
+ height: 4px;
1902
+ background: transparent;
1903
+ border: none;
1904
+ }
1905
+ .swype-slider-wrap input[type="range"]::-moz-range-thumb {
1906
+ width: 14px;
1907
+ height: 14px;
1908
+ border-radius: 50%;
1909
+ background: ${accent};
1910
+ border: 3px solid #fff;
1911
+ box-shadow: 0 2px 6px rgba(0,0,0,0.15);
1912
+ cursor: pointer;
1886
1913
  }
1887
1914
  `;
1888
1915
  function SourceCard({ name, address, verified, onChangeSource }) {
@@ -2013,40 +2040,137 @@ var detailStyle = (color) => ({
2013
2040
  fontSize: "0.75rem",
2014
2041
  color
2015
2042
  });
2043
+ function SettingsMenu({ onLogout }) {
2044
+ const { tokens } = useSwypeConfig();
2045
+ const [open, setOpen] = useState(false);
2046
+ const menuRef = useRef(null);
2047
+ const toggle = useCallback(() => setOpen((prev) => !prev), []);
2048
+ useEffect(() => {
2049
+ if (!open) return;
2050
+ const handleClickOutside = (e) => {
2051
+ if (menuRef.current && !menuRef.current.contains(e.target)) {
2052
+ setOpen(false);
2053
+ }
2054
+ };
2055
+ document.addEventListener("mousedown", handleClickOutside);
2056
+ return () => document.removeEventListener("mousedown", handleClickOutside);
2057
+ }, [open]);
2058
+ return /* @__PURE__ */ jsxs("div", { ref: menuRef, style: containerStyle7, children: [
2059
+ /* @__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: [
2060
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "5", r: "2", fill: "currentColor" }),
2061
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "2", fill: "currentColor" }),
2062
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "19", r: "2", fill: "currentColor" })
2063
+ ] }) }),
2064
+ open && /* @__PURE__ */ jsx("div", { style: dropdownStyle(tokens), children: /* @__PURE__ */ jsxs(
2065
+ "button",
2066
+ {
2067
+ type: "button",
2068
+ onClick: () => {
2069
+ setOpen(false);
2070
+ onLogout();
2071
+ },
2072
+ style: menuItemStyle(tokens),
2073
+ children: [
2074
+ /* @__PURE__ */ jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", style: { marginRight: 8, flexShrink: 0 }, children: [
2075
+ /* @__PURE__ */ jsx("path", { d: "M9 21H5a2 2 0 01-2-2V5a2 2 0 012-2h4", stroke: tokens.error, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }),
2076
+ /* @__PURE__ */ jsx("polyline", { points: "16 17 21 12 16 7", stroke: tokens.error, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }),
2077
+ /* @__PURE__ */ jsx("line", { x1: "21", y1: "12", x2: "9", y2: "12", stroke: tokens.error, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" })
2078
+ ] }),
2079
+ "Log out"
2080
+ ]
2081
+ }
2082
+ ) })
2083
+ ] });
2084
+ }
2085
+ var containerStyle7 = {
2086
+ position: "relative"
2087
+ };
2088
+ var triggerStyle = (color) => ({
2089
+ background: "transparent",
2090
+ border: "none",
2091
+ cursor: "pointer",
2092
+ padding: 4,
2093
+ color,
2094
+ display: "flex",
2095
+ alignItems: "center",
2096
+ justifyContent: "center"
2097
+ });
2098
+ var dropdownStyle = (tokens) => ({
2099
+ position: "absolute",
2100
+ right: 0,
2101
+ top: "100%",
2102
+ marginTop: 4,
2103
+ minWidth: 140,
2104
+ background: tokens.bgCard,
2105
+ border: `1px solid ${tokens.border}`,
2106
+ borderRadius: 12,
2107
+ boxShadow: tokens.shadow,
2108
+ zIndex: 100,
2109
+ overflow: "hidden"
2110
+ });
2111
+ var menuItemStyle = (tokens) => ({
2112
+ width: "100%",
2113
+ display: "flex",
2114
+ alignItems: "center",
2115
+ padding: "12px 16px",
2116
+ background: "transparent",
2117
+ border: "none",
2118
+ cursor: "pointer",
2119
+ fontFamily: "inherit",
2120
+ fontSize: "0.85rem",
2121
+ fontWeight: 500,
2122
+ color: tokens.error
2123
+ });
2016
2124
  function LoginScreen({
2017
2125
  authInput,
2018
2126
  onAuthInputChange,
2019
2127
  onSubmit,
2020
2128
  sending,
2021
2129
  error,
2022
- onBack
2130
+ onBack,
2131
+ merchantInitials,
2132
+ onSocialLogin
2023
2133
  }) {
2024
2134
  const { tokens } = useSwypeConfig();
2025
2135
  const disabled = authInput.trim().length === 0 || sending;
2026
- const walletLogos = ["MM", "R", "O", "P", "+"];
2027
2136
  return /* @__PURE__ */ jsxs(
2028
2137
  ScreenLayout,
2029
2138
  {
2030
2139
  footer: /* @__PURE__ */ jsxs(Fragment, { children: [
2031
2140
  /* @__PURE__ */ jsx(PrimaryButton, { onClick: onSubmit, disabled, loading: sending, children: "Continue" }),
2032
- /* @__PURE__ */ jsxs("div", { style: dividerStyle(tokens), children: [
2033
- /* @__PURE__ */ jsx("div", { style: dividerLineStyle(tokens.border) }),
2034
- /* @__PURE__ */ jsx("span", { children: "works with" }),
2035
- /* @__PURE__ */ jsx("div", { style: dividerLineStyle(tokens.border) })
2141
+ onSocialLogin && /* @__PURE__ */ jsxs(Fragment, { children: [
2142
+ /* @__PURE__ */ jsxs("div", { style: dividerStyle(tokens), children: [
2143
+ /* @__PURE__ */ jsx("div", { style: dividerLineStyle(tokens.border) }),
2144
+ /* @__PURE__ */ jsx("span", { children: "or continue with" }),
2145
+ /* @__PURE__ */ jsx("div", { style: dividerLineStyle(tokens.border) })
2146
+ ] }),
2147
+ /* @__PURE__ */ jsx("div", { style: socialRowStyle, children: ["google", "apple", "twitter"].map((provider) => /* @__PURE__ */ jsx(
2148
+ "button",
2149
+ {
2150
+ type: "button",
2151
+ onClick: () => onSocialLogin(provider),
2152
+ style: socialButtonStyle(tokens),
2153
+ children: socialLabel(provider)
2154
+ },
2155
+ provider
2156
+ )) })
2157
+ ] }),
2158
+ /* @__PURE__ */ jsxs("div", { style: walletSectionStyle, children: [
2159
+ /* @__PURE__ */ jsx("span", { style: walletLabelStyle(tokens.textMuted), children: "Works with" }),
2160
+ /* @__PURE__ */ jsx("div", { style: walletLogosStyle, children: walletIcons.map(({ key, emoji }) => /* @__PURE__ */ jsx("span", { style: walletEmojiStyle, children: emoji }, key)) })
2036
2161
  ] }),
2037
- /* @__PURE__ */ jsx("div", { style: logosRowStyle, children: walletLogos.map((label) => /* @__PURE__ */ jsx("div", { style: logoCircleStyle(tokens), children: label }, label)) }),
2038
2162
  /* @__PURE__ */ jsx(PoweredByFooter, {})
2039
2163
  ] }),
2040
2164
  children: [
2041
- /* @__PURE__ */ jsx(ScreenHeader, { onBack }),
2165
+ /* @__PURE__ */ jsx(
2166
+ ScreenHeader,
2167
+ {
2168
+ onBack,
2169
+ right: merchantInitials ? /* @__PURE__ */ jsx("div", { style: avatarStyle(tokens), children: merchantInitials }) : void 0
2170
+ }
2171
+ ),
2042
2172
  /* @__PURE__ */ jsxs("div", { style: contentStyle, children: [
2043
- /* @__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(
2044
- "path",
2045
- {
2046
- d: "M12 1L3 5v6c0 5.55 3.84 10.74 9 12 5.16-1.26 9-6.45 9-12V5l-9-4z",
2047
- fill: tokens.accent
2048
- }
2049
- ) }) }),
2173
+ /* @__PURE__ */ jsx("div", { style: iconBoxStyle(tokens.accent), children: /* @__PURE__ */ jsx("span", { style: iconLetterStyle, children: "S" }) }),
2050
2174
  /* @__PURE__ */ jsx("h2", { style: headingStyle(tokens.text), children: "One-time setup.\nOne-tap deposits after." }),
2051
2175
  /* @__PURE__ */ jsx("p", { style: subtitleStyle(tokens.textSecondary), children: "Protected by Face ID." }),
2052
2176
  error && /* @__PURE__ */ jsx("div", { style: errorStyle(tokens), children: error }),
@@ -2071,6 +2195,23 @@ function LoginScreen({
2071
2195
  }
2072
2196
  );
2073
2197
  }
2198
+ var walletIcons = [
2199
+ { key: "metamask", emoji: "\u{1F98A}" },
2200
+ { key: "rabby", emoji: "\u{1F430}" },
2201
+ { key: "phantom", emoji: "\u25C6" },
2202
+ { key: "rainbow", emoji: "\u{1F439}" },
2203
+ { key: "coinbase", emoji: "\u{1F535}" }
2204
+ ];
2205
+ function socialLabel(provider) {
2206
+ switch (provider) {
2207
+ case "google":
2208
+ return "Google";
2209
+ case "apple":
2210
+ return "Apple";
2211
+ case "twitter":
2212
+ return "X";
2213
+ }
2214
+ }
2074
2215
  var contentStyle = {
2075
2216
  textAlign: "center",
2076
2217
  flex: 1,
@@ -2079,10 +2220,25 @@ var contentStyle = {
2079
2220
  alignItems: "center",
2080
2221
  paddingTop: 24
2081
2222
  };
2223
+ var iconBoxStyle = (accent) => ({
2224
+ width: 56,
2225
+ height: 56,
2226
+ borderRadius: 16,
2227
+ background: accent,
2228
+ display: "flex",
2229
+ alignItems: "center",
2230
+ justifyContent: "center"
2231
+ });
2232
+ var iconLetterStyle = {
2233
+ color: "#fff",
2234
+ fontSize: "1.5rem",
2235
+ fontWeight: 700,
2236
+ lineHeight: 1
2237
+ };
2082
2238
  var headingStyle = (color) => ({
2083
- fontSize: "1.65rem",
2239
+ fontSize: "1.45rem",
2084
2240
  fontWeight: 700,
2085
- lineHeight: 1.2,
2241
+ lineHeight: 1.25,
2086
2242
  letterSpacing: "-0.02em",
2087
2243
  color,
2088
2244
  margin: "20px 0 8px",
@@ -2131,24 +2287,55 @@ var dividerLineStyle = (color) => ({
2131
2287
  height: 1,
2132
2288
  background: color
2133
2289
  });
2134
- var logosRowStyle = {
2290
+ var socialRowStyle = {
2291
+ display: "flex",
2292
+ gap: 10,
2293
+ marginBottom: 20
2294
+ };
2295
+ var socialButtonStyle = (tokens) => ({
2296
+ flex: 1,
2297
+ padding: "12px 0",
2298
+ borderRadius: 12,
2299
+ border: `1px solid ${tokens.border}`,
2300
+ background: "transparent",
2301
+ color: tokens.text,
2302
+ fontSize: "0.88rem",
2303
+ fontWeight: 600,
2304
+ fontFamily: "inherit",
2305
+ cursor: "pointer"
2306
+ });
2307
+ var walletSectionStyle = {
2308
+ textAlign: "center",
2309
+ marginBottom: 8,
2310
+ marginTop: 4
2311
+ };
2312
+ var walletLabelStyle = (color) => ({
2313
+ fontSize: "0.78rem",
2314
+ color,
2315
+ display: "block",
2316
+ marginBottom: 10
2317
+ });
2318
+ var walletLogosStyle = {
2135
2319
  display: "flex",
2136
2320
  justifyContent: "center",
2137
- gap: 12,
2138
- marginBottom: 8
2321
+ gap: 16
2139
2322
  };
2140
- var logoCircleStyle = (tokens) => ({
2141
- width: 34,
2142
- height: 34,
2143
- borderRadius: 999,
2323
+ var walletEmojiStyle = {
2324
+ fontSize: "1.4rem",
2325
+ lineHeight: 1
2326
+ };
2327
+ var avatarStyle = (tokens) => ({
2328
+ width: 28,
2329
+ height: 28,
2330
+ borderRadius: "50%",
2144
2331
  border: `1px solid ${tokens.border}`,
2145
- background: tokens.bgInput,
2146
- color: tokens.textMuted,
2147
2332
  display: "flex",
2148
2333
  alignItems: "center",
2149
2334
  justifyContent: "center",
2150
- fontSize: "0.72rem",
2151
- fontWeight: 600
2335
+ fontSize: "0.6rem",
2336
+ fontWeight: 700,
2337
+ color: tokens.textMuted,
2338
+ background: "transparent"
2152
2339
  });
2153
2340
  var RESEND_COOLDOWN_SECONDS = 30;
2154
2341
  function OtpVerifyScreen({
@@ -2500,21 +2687,36 @@ var hintStyle2 = (color) => ({
2500
2687
  color,
2501
2688
  margin: "0 0 4px"
2502
2689
  });
2503
- var DEFAULT_TICKS = [25, 100, 250, 500];
2504
- var DEFAULT_MIN = 25;
2505
2690
  var DEFAULT_MAX = 500;
2691
+ var ABSOLUTE_MIN = 1;
2692
+ function buildTicks(min, max) {
2693
+ if (max <= min) return [min];
2694
+ const range = max - min;
2695
+ const candidates = [1, 2, 5, 10, 25, 50, 100, 250];
2696
+ const step = candidates.find((s) => range / s <= 5) ?? Math.ceil(range / 4);
2697
+ const ticks = [];
2698
+ for (let v = min; v <= max; v += step) {
2699
+ ticks.push(Math.round(v * 100) / 100);
2700
+ }
2701
+ if (ticks[ticks.length - 1] !== max) ticks.push(max);
2702
+ return ticks;
2703
+ }
2506
2704
  function SetupScreen({
2507
2705
  availableBalance,
2508
2706
  tokenCount,
2509
2707
  sourceName,
2510
2708
  onSetupOneTap,
2511
2709
  onBack,
2710
+ onLogout,
2512
2711
  loading,
2513
2712
  error
2514
2713
  }) {
2515
2714
  const { tokens } = useSwypeConfig();
2516
- const [limit, setLimit] = useState(100);
2517
2715
  const effectiveMax = Math.min(DEFAULT_MAX, availableBalance > 0 ? availableBalance : DEFAULT_MAX);
2716
+ const effectiveMin = Math.min(ABSOLUTE_MIN, effectiveMax);
2717
+ const sliderStep = effectiveMax <= 10 ? 0.5 : effectiveMax <= 50 ? 1 : 5;
2718
+ const ticks = buildTicks(effectiveMin, effectiveMax);
2719
+ const [limit, setLimit] = useState(() => Math.min(100, effectiveMax));
2518
2720
  return /* @__PURE__ */ jsxs(
2519
2721
  ScreenLayout,
2520
2722
  {
@@ -2531,7 +2733,7 @@ function SetupScreen({
2531
2733
  /* @__PURE__ */ jsx(PoweredByFooter, {})
2532
2734
  ] }),
2533
2735
  children: [
2534
- /* @__PURE__ */ jsx(ScreenHeader, { title: "Swype Setup", badge: "Simple", onBack }),
2736
+ /* @__PURE__ */ jsx(ScreenHeader, { title: "Swype Setup", badge: "Simple", onBack, right: /* @__PURE__ */ jsx(SettingsMenu, { onLogout }) }),
2535
2737
  /* @__PURE__ */ jsx("h2", { style: headingStyle5(tokens.text), children: "Set up One-Tap deposits" }),
2536
2738
  /* @__PURE__ */ jsx("p", { style: subtitleStyle5(tokens.textSecondary), children: "Set your limit for instant deposits. Like a contactless card \u2014 you choose the max." }),
2537
2739
  error && /* @__PURE__ */ jsx("div", { style: errorBannerStyle3(tokens), children: error }),
@@ -2566,10 +2768,10 @@ function SetupScreen({
2566
2768
  LimitSlider,
2567
2769
  {
2568
2770
  value: limit,
2569
- min: DEFAULT_MIN,
2771
+ min: effectiveMin,
2570
2772
  max: effectiveMax,
2571
- step: 5,
2572
- ticks: DEFAULT_TICKS.filter((t) => t <= effectiveMax),
2773
+ step: sliderStep,
2774
+ ticks,
2573
2775
  onChange: setLimit
2574
2776
  }
2575
2777
  )
@@ -2689,6 +2891,7 @@ function SetupStatusScreen({
2689
2891
  currentStepLabel,
2690
2892
  merchantName,
2691
2893
  onContinue,
2894
+ onLogout,
2692
2895
  error
2693
2896
  }) {
2694
2897
  const { tokens } = useSwypeConfig();
@@ -2706,26 +2909,29 @@ function SetupStatusScreen({
2706
2909
  },
2707
2910
  { label: "Done", status: "pending" }
2708
2911
  ];
2709
- return /* @__PURE__ */ jsx(
2912
+ return /* @__PURE__ */ jsxs(
2710
2913
  ScreenLayout,
2711
2914
  {
2712
2915
  footer: complete ? /* @__PURE__ */ jsxs(Fragment, { children: [
2713
2916
  /* @__PURE__ */ jsx(PrimaryButton, { onClick: onContinue, children: merchantName ? `Return to ${merchantName}` : "Continue" }),
2714
2917
  /* @__PURE__ */ jsx("p", { style: swipeHintStyle(tokens.textMuted), children: "Swipe to deposit \u2014 no approvals needed." })
2715
2918
  ] }) : void 0,
2716
- children: /* @__PURE__ */ jsxs("div", { style: contentStyle4, children: [
2717
- complete ? /* @__PURE__ */ jsxs(Fragment, { children: [
2718
- /* @__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 }) }) }),
2719
- /* @__PURE__ */ jsx("h2", { style: headingStyle6(tokens.text), children: "You're all set!" })
2720
- ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
2721
- /* @__PURE__ */ jsx(Spinner, { size: 48 }),
2722
- /* @__PURE__ */ jsx("h2", { style: headingStyle6(tokens.text), children: "Setting up One-Tap..." })
2723
- ] }),
2724
- error && /* @__PURE__ */ jsx("div", { style: errorBannerStyle4(tokens), children: error }),
2725
- /* @__PURE__ */ jsx("div", { style: stepsWrapStyle, children: /* @__PURE__ */ jsx(StepList, { steps }) }),
2726
- !complete && /* @__PURE__ */ jsx("p", { style: waitHintStyle(tokens.textMuted), children: "Usually takes a few seconds" }),
2727
- complete && /* @__PURE__ */ jsx("p", { style: readyHintStyle(tokens.textSecondary), children: "You can now deposit instantly from any partner app." })
2728
- ] })
2919
+ children: [
2920
+ /* @__PURE__ */ jsx(ScreenHeader, { right: /* @__PURE__ */ jsx(SettingsMenu, { onLogout }) }),
2921
+ /* @__PURE__ */ jsxs("div", { style: contentStyle4, children: [
2922
+ complete ? /* @__PURE__ */ jsxs(Fragment, { children: [
2923
+ /* @__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 }) }) }),
2924
+ /* @__PURE__ */ jsx("h2", { style: headingStyle6(tokens.text), children: "You're all set!" })
2925
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
2926
+ /* @__PURE__ */ jsx(Spinner, { size: 48 }),
2927
+ /* @__PURE__ */ jsx("h2", { style: headingStyle6(tokens.text), children: "Setting up One-Tap..." })
2928
+ ] }),
2929
+ error && /* @__PURE__ */ jsx("div", { style: errorBannerStyle4(tokens), children: error }),
2930
+ /* @__PURE__ */ jsx("div", { style: stepsWrapStyle, children: /* @__PURE__ */ jsx(StepList, { steps }) }),
2931
+ !complete && /* @__PURE__ */ jsx("p", { style: waitHintStyle(tokens.textMuted), children: "Usually takes a few seconds" }),
2932
+ complete && /* @__PURE__ */ jsx("p", { style: readyHintStyle(tokens.textSecondary), children: "You can now deposit instantly from any partner app." })
2933
+ ] })
2934
+ ]
2729
2935
  }
2730
2936
  );
2731
2937
  }
@@ -2781,7 +2987,7 @@ var swipeHintStyle = (color) => ({
2781
2987
  color,
2782
2988
  margin: "12px 0 0"
2783
2989
  });
2784
- var MIN_DEPOSIT = 1;
2990
+ var MIN_DEPOSIT = 0.25;
2785
2991
  function DepositScreen({
2786
2992
  merchantName,
2787
2993
  sourceName,
@@ -2798,7 +3004,8 @@ function DepositScreen({
2798
3004
  onDeposit,
2799
3005
  onChangeSource,
2800
3006
  onSwitchWallet,
2801
- onBack
3007
+ onBack,
3008
+ onLogout
2802
3009
  }) {
2803
3010
  const { tokens } = useSwypeConfig();
2804
3011
  const [amount, setAmount] = useState(initialAmount);
@@ -2806,30 +3013,6 @@ function DepositScreen({
2806
3013
  const isLowBalance = availableBalance < MIN_DEPOSIT;
2807
3014
  const canDeposit = amount >= MIN_DEPOSIT && amount <= remainingLimit && !isLowBalance && !processing;
2808
3015
  const headerTitle = merchantName ? `Deposit to ${merchantName}` : "Deposit";
2809
- const trackRef = useRef(null);
2810
- const [swipeX, setSwipeX] = useState(0);
2811
- const [swiping, setSwiping] = useState(false);
2812
- const startXRef = useRef(0);
2813
- const handleTouchStart = useCallback((e) => {
2814
- if (!canDeposit) return;
2815
- startXRef.current = e.touches[0].clientX - swipeX;
2816
- setSwiping(true);
2817
- }, [canDeposit, swipeX]);
2818
- const handleTouchMove = useCallback((e) => {
2819
- if (!swiping || !trackRef.current) return;
2820
- const trackWidth = trackRef.current.offsetWidth - 52;
2821
- const x = Math.max(0, Math.min(e.touches[0].clientX - startXRef.current, trackWidth));
2822
- setSwipeX(x);
2823
- }, [swiping]);
2824
- const handleTouchEnd = useCallback(() => {
2825
- if (!trackRef.current) return;
2826
- const trackWidth = trackRef.current.offsetWidth - 52;
2827
- if (swipeX > trackWidth * 0.75) {
2828
- onDeposit(amount);
2829
- }
2830
- setSwipeX(0);
2831
- setSwiping(false);
2832
- }, [swipeX, amount, onDeposit]);
2833
3016
  if (isLowBalance) {
2834
3017
  return /* @__PURE__ */ jsxs(
2835
3018
  ScreenLayout,
@@ -2841,7 +3024,7 @@ function DepositScreen({
2841
3024
  /* @__PURE__ */ jsx(PoweredByFooter, {})
2842
3025
  ] }),
2843
3026
  children: [
2844
- /* @__PURE__ */ jsx(ScreenHeader, { title: headerTitle, onBack }),
3027
+ /* @__PURE__ */ jsx(ScreenHeader, { title: headerTitle, onBack, right: /* @__PURE__ */ jsx(SettingsMenu, { onLogout }) }),
2845
3028
  /* @__PURE__ */ jsx(
2846
3029
  SourceCard,
2847
3030
  {
@@ -2886,30 +3069,10 @@ function DepositScreen({
2886
3069
  ScreenLayout,
2887
3070
  {
2888
3071
  footer: /* @__PURE__ */ jsxs(Fragment, { children: [
2889
- /* @__PURE__ */ jsxs(
2890
- "div",
2891
- {
2892
- ref: trackRef,
2893
- style: swipeTrackStyle(tokens),
2894
- onTouchStart: handleTouchStart,
2895
- onTouchMove: handleTouchMove,
2896
- onTouchEnd: handleTouchEnd,
2897
- children: [
2898
- /* @__PURE__ */ jsx(
2899
- "div",
2900
- {
2901
- style: swipeThumbStyle(tokens, swipeX),
2902
- children: /* @__PURE__ */ jsx("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ jsx("path", { d: "M8 5l8 7-8 7", stroke: "#fff", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round" }) })
2903
- }
2904
- ),
2905
- /* @__PURE__ */ jsx("span", { style: swipeLabelStyle, children: processing ? "Processing..." : `Deposit $${amount.toFixed(2)}` })
2906
- ]
2907
- }
2908
- ),
2909
- /* @__PURE__ */ jsx("div", { style: desktopFallbackStyle, children: /* @__PURE__ */ jsxs(PrimaryButton, { onClick: () => onDeposit(amount), disabled: !canDeposit, loading: processing, children: [
3072
+ /* @__PURE__ */ jsxs(PrimaryButton, { onClick: () => onDeposit(amount), disabled: !canDeposit, loading: processing, children: [
2910
3073
  "Deposit $",
2911
3074
  amount.toFixed(2)
2912
- ] }) }),
3075
+ ] }),
2913
3076
  /* @__PURE__ */ jsx("p", { style: noApprovalStyle(tokens.textMuted), children: "No approval needed \xB7 within your One-Tap limit" }),
2914
3077
  /* @__PURE__ */ jsxs("p", { style: routeStyle(tokens.textMuted), children: [
2915
3078
  "From ",
@@ -2920,7 +3083,7 @@ function DepositScreen({
2920
3083
  /* @__PURE__ */ jsx(PoweredByFooter, {})
2921
3084
  ] }),
2922
3085
  children: [
2923
- /* @__PURE__ */ jsx(ScreenHeader, { title: headerTitle, badge: "Simple", onBack }),
3086
+ /* @__PURE__ */ jsx(ScreenHeader, { title: headerTitle, badge: "Simple", onBack, right: /* @__PURE__ */ jsx(SettingsMenu, { onLogout }) }),
2924
3087
  /* @__PURE__ */ jsx(
2925
3088
  SourceCard,
2926
3089
  {
@@ -2965,7 +3128,7 @@ function DepositScreen({
2965
3128
  min: MIN_DEPOSIT,
2966
3129
  max: sliderMax > MIN_DEPOSIT ? sliderMax : 20,
2967
3130
  step: 0.5,
2968
- ticks: [MIN_DEPOSIT, 5, 10, 20].filter((t) => t <= sliderMax || t <= 20),
3131
+ ticks: [MIN_DEPOSIT, 1, 5, 10, 20].filter((t) => t <= sliderMax || t <= 20),
2969
3132
  onChange: setAmount
2970
3133
  }
2971
3134
  ),
@@ -2977,13 +3140,13 @@ function DepositScreen({
2977
3140
  remainingLimit.toFixed(2)
2978
3141
  ] })
2979
3142
  ] }),
2980
- estimatedFeeUsd != null && estimatedFeePct != null && /* @__PURE__ */ jsxs("div", { style: detailRowStyle(tokens.textMuted), children: [
3143
+ estimatedFeeUsd != null && estimatedFeePct != null ? /* @__PURE__ */ jsxs("div", { style: detailRowStyle(tokens.textMuted), children: [
2981
3144
  "Fee: ~$",
2982
3145
  estimatedFeeUsd.toFixed(2),
2983
3146
  " (",
2984
3147
  estimatedFeePct.toFixed(1),
2985
3148
  "%)"
2986
- ] })
3149
+ ] }) : /* @__PURE__ */ jsx("div", { style: detailRowStyle(tokens.textMuted), children: "Fees calculated at time of transfer" })
2987
3150
  ] }),
2988
3151
  error && /* @__PURE__ */ jsx("div", { style: errorBannerStyle5(tokens), children: error })
2989
3152
  ]
@@ -3063,45 +3226,6 @@ var errorBannerStyle5 = (tokens) => ({
3063
3226
  marginTop: 8,
3064
3227
  lineHeight: 1.5
3065
3228
  });
3066
- var swipeTrackStyle = (tokens) => ({
3067
- position: "relative",
3068
- height: 56,
3069
- borderRadius: 999,
3070
- background: `linear-gradient(180deg, ${tokens.accent}, ${tokens.accent}dd)`,
3071
- overflow: "hidden",
3072
- display: "flex",
3073
- alignItems: "center",
3074
- touchAction: "none",
3075
- userSelect: "none"
3076
- });
3077
- var swipeThumbStyle = (tokens, x) => ({
3078
- position: "absolute",
3079
- left: 4 + x,
3080
- top: 4,
3081
- width: 48,
3082
- height: 48,
3083
- borderRadius: "50%",
3084
- background: `${tokens.accent}`,
3085
- border: "2px solid rgba(255,255,255,0.4)",
3086
- display: "flex",
3087
- alignItems: "center",
3088
- justifyContent: "center",
3089
- zIndex: 2,
3090
- transition: x === 0 ? "left 0.25s ease" : "none",
3091
- cursor: "grab"
3092
- });
3093
- var swipeLabelStyle = {
3094
- flex: 1,
3095
- textAlign: "center",
3096
- color: "#fff",
3097
- fontWeight: 700,
3098
- fontSize: "0.95rem",
3099
- zIndex: 1,
3100
- pointerEvents: "none"
3101
- };
3102
- var desktopFallbackStyle = {
3103
- marginTop: 8
3104
- };
3105
3229
  var noApprovalStyle = (color) => ({
3106
3230
  textAlign: "center",
3107
3231
  fontSize: "0.78rem",
@@ -3130,6 +3254,7 @@ function SuccessScreen({
3130
3254
  sourceName,
3131
3255
  remainingLimit,
3132
3256
  onDone,
3257
+ onLogout,
3133
3258
  onIncreaseLimits,
3134
3259
  onManageAccount
3135
3260
  }) {
@@ -3146,7 +3271,7 @@ function SuccessScreen({
3146
3271
  /* @__PURE__ */ jsx(
3147
3272
  ScreenHeader,
3148
3273
  {
3149
- right: /* @__PURE__ */ jsx("button", { type: "button", onClick: onDone, style: closeButtonStyle(tokens.textMuted), "aria-label": "Close", children: /* @__PURE__ */ jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ jsx("path", { d: "M18 6L6 18M6 6l12 12", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) }) })
3274
+ right: /* @__PURE__ */ jsx(SettingsMenu, { onLogout })
3150
3275
  }
3151
3276
  ),
3152
3277
  /* @__PURE__ */ jsxs("div", { style: contentStyle5, children: [
@@ -3262,15 +3387,6 @@ var upsellLinkStyle = (color) => ({
3262
3387
  fontFamily: "inherit",
3263
3388
  padding: 0
3264
3389
  });
3265
- var closeButtonStyle = (color) => ({
3266
- background: "transparent",
3267
- border: "none",
3268
- cursor: "pointer",
3269
- color,
3270
- padding: 4,
3271
- display: "flex",
3272
- alignItems: "center"
3273
- });
3274
3390
  var manageStyle = (color) => ({
3275
3391
  background: "transparent",
3276
3392
  border: "none",
@@ -3376,6 +3492,7 @@ function SwypePayment({
3376
3492
  loginWithCode: loginWithSmsCode,
3377
3493
  state: smsLoginState
3378
3494
  } = useLoginWithSms();
3495
+ const { initOAuth } = useLoginWithOAuth();
3379
3496
  const [step, setStep] = useState("login");
3380
3497
  const [error, setError] = useState(null);
3381
3498
  const [providers, setProviders] = useState([]);
@@ -3424,6 +3541,14 @@ function SwypePayment({
3424
3541
  setVerificationTarget(null);
3425
3542
  setOtpCode("");
3426
3543
  }, []);
3544
+ const handleSocialLogin = useCallback(async (provider) => {
3545
+ setError(null);
3546
+ try {
3547
+ await initOAuth({ provider });
3548
+ } catch (err) {
3549
+ setError(err instanceof Error ? err.message : "Social login failed");
3550
+ }
3551
+ }, [initOAuth]);
3427
3552
  const activeOtpStatus = verificationTarget?.kind === "email" ? emailLoginState.status : verificationTarget?.kind === "phone" ? smsLoginState.status : "initial";
3428
3553
  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;
3429
3554
  useEffect(() => {
@@ -3492,6 +3617,9 @@ function SwypePayment({
3492
3617
  if (!token || cancelled) return;
3493
3618
  const { config } = await fetchUserConfig(apiBaseUrl, token);
3494
3619
  if (cancelled) return;
3620
+ if (config.defaultAllowance != null) {
3621
+ setOneTapLimit(config.defaultAllowance);
3622
+ }
3495
3623
  const allPasskeys = config.passkeys ?? (config.passkey ? [config.passkey] : []);
3496
3624
  if (allPasskeys.length === 0) {
3497
3625
  setStep("create-passkey");
@@ -3849,13 +3977,15 @@ function SwypePayment({
3849
3977
  if (!sourceId) {
3850
3978
  throw new Error("No wallet selected for setup.");
3851
3979
  }
3980
+ const setupAmount = depositAmount ?? MIN_SEND_AMOUNT_USD;
3852
3981
  const t = await createTransfer(apiBaseUrl, token, {
3982
+ id: idempotencyKey,
3853
3983
  credentialId: activeCredentialId ?? "",
3854
3984
  merchantAuthorization,
3855
3985
  sourceType,
3856
3986
  sourceId,
3857
3987
  destination,
3858
- amount: 0
3988
+ amount: setupAmount
3859
3989
  });
3860
3990
  if (t.authorizationSessions && t.authorizationSessions.length > 0) {
3861
3991
  const shouldUseConnector = shouldUseWalletConnector({
@@ -3878,6 +4008,7 @@ function SwypePayment({
3878
4008
  }
3879
4009
  }, [
3880
4010
  getAccessToken,
4011
+ idempotencyKey,
3881
4012
  sourceId,
3882
4013
  sourceType,
3883
4014
  activeCredentialId,
@@ -3886,7 +4017,8 @@ function SwypePayment({
3886
4017
  merchantAuthorization,
3887
4018
  useWalletConnector,
3888
4019
  authExecutor,
3889
- onError
4020
+ onError,
4021
+ depositAmount
3890
4022
  ]);
3891
4023
  const handleSelectProvider = useCallback((providerId) => {
3892
4024
  setSelectedProviderId(providerId);
@@ -3947,7 +4079,9 @@ function SwypePayment({
3947
4079
  onSubmit: handleSendLoginCode,
3948
4080
  sending: activeOtpStatus === "sending-code",
3949
4081
  error,
3950
- onBack
4082
+ onBack,
4083
+ merchantInitials: merchantName ? merchantName.slice(0, 2).toUpperCase() : void 0,
4084
+ onSocialLogin: handleSocialLogin
3951
4085
  }
3952
4086
  );
3953
4087
  }
@@ -4005,6 +4139,7 @@ function SwypePayment({
4005
4139
  sourceName,
4006
4140
  onSetupOneTap: handleSetupOneTap,
4007
4141
  onBack: () => setStep("wallet-picker"),
4142
+ onLogout: handleLogout,
4008
4143
  loading: loadingData,
4009
4144
  error
4010
4145
  }
@@ -4020,6 +4155,7 @@ function SwypePayment({
4020
4155
  currentStepLabel: setupStepLabel,
4021
4156
  merchantName,
4022
4157
  onContinue: () => setStep("deposit"),
4158
+ onLogout: handleLogout,
4023
4159
  error
4024
4160
  }
4025
4161
  );
@@ -4040,20 +4176,20 @@ function SwypePayment({
4040
4176
  remainingLimit: oneTapLimit,
4041
4177
  tokenCount,
4042
4178
  initialAmount: parsedAmt,
4043
- estimatedFeePct: 0.6,
4044
- estimatedFeeUsd: parsedAmt * 6e-3,
4045
4179
  processing: creatingTransfer,
4046
4180
  error,
4047
4181
  onDeposit: handlePay,
4048
4182
  onChangeSource: () => setStep("wallet-picker"),
4049
4183
  onSwitchWallet: () => setStep("wallet-picker"),
4050
- onBack: onBack ?? (() => handleLogout())
4184
+ onBack: onBack ?? (() => handleLogout()),
4185
+ onLogout: handleLogout
4051
4186
  }
4052
4187
  );
4053
4188
  }
4054
4189
  if (step === "processing") {
4055
4190
  const currentActionType = authExecutor.currentAction?.type;
4056
- 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...";
4191
+ const polledStatus = polling.transfer?.status;
4192
+ const statusLabel = creatingTransfer ? "Creating Transfer" : mobileFlow ? "Waiting for Authorization" : authExecutor.executing ? currentActionType?.replace(/_/g, " ") ?? "Authorizing" : transferSigning.signing ? "Sending transfer" : polledStatus === "SENDING" ? "Sending transfer..." : polledStatus === "SENT" ? "Confirming delivery..." : polling.isPolling ? "Transfer Sent" : "Please wait...";
4057
4193
  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: [
4058
4194
  /* @__PURE__ */ jsx(Spinner, { size: 48 }),
4059
4195
  /* @__PURE__ */ jsx("h2", { style: { fontSize: "1.4rem", fontWeight: 700, color: tokens.text, marginTop: 20, marginBottom: 8 }, children: statusLabel }),
@@ -4083,7 +4219,8 @@ function SwypePayment({
4083
4219
  merchantName,
4084
4220
  sourceName,
4085
4221
  remainingLimit: oneTapLimit > displayAmount ? oneTapLimit - displayAmount : 0,
4086
- onDone: handleNewPayment
4222
+ onDone: handleNewPayment,
4223
+ onLogout: handleLogout
4087
4224
  }
4088
4225
  );
4089
4226
  }
@@ -4104,7 +4241,8 @@ function SwypePayment({
4104
4241
  onDeposit: handlePay,
4105
4242
  onChangeSource: () => setStep("wallet-picker"),
4106
4243
  onSwitchWallet: () => setStep("wallet-picker"),
4107
- onBack: onBack ?? (() => handleLogout())
4244
+ onBack: onBack ?? (() => handleLogout()),
4245
+ onLogout: handleLogout
4108
4246
  }
4109
4247
  );
4110
4248
  }