@swype-org/react-sdk 0.1.35 → 0.1.36

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.d.cts CHANGED
@@ -1,4 +1,5 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ReactNode } from 'react';
2
3
 
3
4
  /** Wallet provider (e.g. MetaMask) */
4
5
  interface Provider {
@@ -490,4 +491,95 @@ interface UseTransferSigningOptions {
490
491
  */
491
492
  declare function useTransferSigning(pollIntervalMs?: number, options?: UseTransferSigningOptions): UseTransferSigningResult;
492
493
 
493
- export { type Account, type ActionExecutionResult, type AdvancedSettings, type Amount, type AuthorizationAction, type AuthorizationSession, type AuthorizationSessionDetail, type Chain, type Destination, type ErrorResponse, type ListResponse, type MerchantAuthorization, type MerchantPublicKey, type PaymentStep, type Provider, type SourceOption, type SourceSelection, type SourceType, SwypePayment, type SwypePaymentProps, SwypeProvider, type SwypeProviderProps, type ThemeMode, type ThemeTokens, type TokenBalance, type Transfer, type TransferDestination, type UserConfig, type Wallet, type WalletSource, type WalletToken, createPasskeyCredential, darkTheme, deviceHasPasskey, findDevicePasskey, getTheme, lightTheme, api as swypeApi, useAuthorizationExecutor, useSwypeConfig, useSwypeDepositAmount, useTransferPolling, useTransferSigning };
494
+ interface ScreenLayoutProps {
495
+ children: ReactNode;
496
+ /** Content pinned to the bottom of the screen (buttons, footer) */
497
+ footer?: ReactNode;
498
+ }
499
+ declare function ScreenLayout({ children, footer }: ScreenLayoutProps): react_jsx_runtime.JSX.Element;
500
+
501
+ interface ScreenHeaderProps {
502
+ /** Center title text */
503
+ title?: string;
504
+ /** Right-aligned element (avatar, close button, etc.) */
505
+ right?: ReactNode;
506
+ /** Called when back arrow is pressed. Omit to hide the back arrow. */
507
+ onBack?: () => void;
508
+ /** Optional secondary label next to the title (e.g. "Simple") */
509
+ badge?: string;
510
+ }
511
+ declare function ScreenHeader({ title, right, onBack, badge }: ScreenHeaderProps): react_jsx_runtime.JSX.Element;
512
+
513
+ declare function PoweredByFooter(): react_jsx_runtime.JSX.Element;
514
+
515
+ interface PrimaryButtonProps {
516
+ children: ReactNode;
517
+ onClick?: () => void;
518
+ disabled?: boolean;
519
+ loading?: boolean;
520
+ /** Optional icon element rendered left of the label */
521
+ icon?: ReactNode;
522
+ }
523
+ declare function PrimaryButton({ children, onClick, disabled, loading, icon }: PrimaryButtonProps): react_jsx_runtime.JSX.Element;
524
+
525
+ interface OutlineButtonProps {
526
+ children: ReactNode;
527
+ onClick?: () => void;
528
+ disabled?: boolean;
529
+ }
530
+ declare function OutlineButton({ children, onClick, disabled }: OutlineButtonProps): react_jsx_runtime.JSX.Element;
531
+
532
+ type IconCircleVariant = 'accent' | 'success' | 'error';
533
+ interface IconCircleProps {
534
+ children: ReactNode;
535
+ variant?: IconCircleVariant;
536
+ size?: number;
537
+ }
538
+ declare function IconCircle({ children, variant, size }: IconCircleProps): react_jsx_runtime.JSX.Element;
539
+
540
+ interface StepItem {
541
+ label: string;
542
+ /** Optional sublabel (e.g. "$100 limit · 2 tokens approved") */
543
+ detail?: string;
544
+ status: 'pending' | 'active' | 'complete';
545
+ }
546
+ interface StepListProps {
547
+ steps: StepItem[];
548
+ }
549
+ declare function StepList({ steps }: StepListProps): react_jsx_runtime.JSX.Element;
550
+
551
+ interface SettingsMenuProps {
552
+ onLogout: () => void;
553
+ }
554
+ declare function SettingsMenu({ onLogout }: SettingsMenuProps): react_jsx_runtime.JSX.Element;
555
+
556
+ interface SpinnerProps {
557
+ size?: number;
558
+ label?: string;
559
+ }
560
+ declare function Spinner({ size, label }: SpinnerProps): react_jsx_runtime.JSX.Element;
561
+
562
+ interface ChainChoice {
563
+ chainName: string;
564
+ balance: number;
565
+ tokens: {
566
+ tokenSymbol: string;
567
+ balance: number;
568
+ }[];
569
+ }
570
+ interface SelectSourceScreenProps {
571
+ choices: ChainChoice[];
572
+ selectedChainName: string;
573
+ selectedTokenSymbol: string;
574
+ recommended: {
575
+ chainName: string;
576
+ tokenSymbol: string;
577
+ } | null;
578
+ onChainChange: (chainName: string) => void;
579
+ onTokenChange: (tokenSymbol: string) => void;
580
+ onConfirm: () => void;
581
+ onLogout: () => void;
582
+ }
583
+ declare function SelectSourceScreen({ choices, selectedChainName, selectedTokenSymbol, recommended, onChainChange, onTokenChange, onConfirm, onLogout, }: SelectSourceScreenProps): react_jsx_runtime.JSX.Element;
584
+
585
+ export { type Account, type ActionExecutionResult, type AdvancedSettings, type Amount, type AuthorizationAction, type AuthorizationSession, type AuthorizationSessionDetail, type Chain, type Destination, type ErrorResponse, IconCircle, type ListResponse, type MerchantAuthorization, type MerchantPublicKey, OutlineButton, type PaymentStep, PoweredByFooter, PrimaryButton, type Provider, ScreenHeader, ScreenLayout, SelectSourceScreen, SettingsMenu, type SourceOption, type SourceSelection, type SourceType, Spinner, type StepItem, StepList, SwypePayment, type SwypePaymentProps, SwypeProvider, type SwypeProviderProps, type ThemeMode, type ThemeTokens, type TokenBalance, type Transfer, type TransferDestination, type UserConfig, type Wallet, type WalletSource, type WalletToken, createPasskeyCredential, darkTheme, deviceHasPasskey, findDevicePasskey, getTheme, lightTheme, api as swypeApi, useAuthorizationExecutor, useSwypeConfig, useSwypeDepositAmount, useTransferPolling, useTransferSigning };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ReactNode } from 'react';
2
3
 
3
4
  /** Wallet provider (e.g. MetaMask) */
4
5
  interface Provider {
@@ -490,4 +491,95 @@ interface UseTransferSigningOptions {
490
491
  */
491
492
  declare function useTransferSigning(pollIntervalMs?: number, options?: UseTransferSigningOptions): UseTransferSigningResult;
492
493
 
493
- export { type Account, type ActionExecutionResult, type AdvancedSettings, type Amount, type AuthorizationAction, type AuthorizationSession, type AuthorizationSessionDetail, type Chain, type Destination, type ErrorResponse, type ListResponse, type MerchantAuthorization, type MerchantPublicKey, type PaymentStep, type Provider, type SourceOption, type SourceSelection, type SourceType, SwypePayment, type SwypePaymentProps, SwypeProvider, type SwypeProviderProps, type ThemeMode, type ThemeTokens, type TokenBalance, type Transfer, type TransferDestination, type UserConfig, type Wallet, type WalletSource, type WalletToken, createPasskeyCredential, darkTheme, deviceHasPasskey, findDevicePasskey, getTheme, lightTheme, api as swypeApi, useAuthorizationExecutor, useSwypeConfig, useSwypeDepositAmount, useTransferPolling, useTransferSigning };
494
+ interface ScreenLayoutProps {
495
+ children: ReactNode;
496
+ /** Content pinned to the bottom of the screen (buttons, footer) */
497
+ footer?: ReactNode;
498
+ }
499
+ declare function ScreenLayout({ children, footer }: ScreenLayoutProps): react_jsx_runtime.JSX.Element;
500
+
501
+ interface ScreenHeaderProps {
502
+ /** Center title text */
503
+ title?: string;
504
+ /** Right-aligned element (avatar, close button, etc.) */
505
+ right?: ReactNode;
506
+ /** Called when back arrow is pressed. Omit to hide the back arrow. */
507
+ onBack?: () => void;
508
+ /** Optional secondary label next to the title (e.g. "Simple") */
509
+ badge?: string;
510
+ }
511
+ declare function ScreenHeader({ title, right, onBack, badge }: ScreenHeaderProps): react_jsx_runtime.JSX.Element;
512
+
513
+ declare function PoweredByFooter(): react_jsx_runtime.JSX.Element;
514
+
515
+ interface PrimaryButtonProps {
516
+ children: ReactNode;
517
+ onClick?: () => void;
518
+ disabled?: boolean;
519
+ loading?: boolean;
520
+ /** Optional icon element rendered left of the label */
521
+ icon?: ReactNode;
522
+ }
523
+ declare function PrimaryButton({ children, onClick, disabled, loading, icon }: PrimaryButtonProps): react_jsx_runtime.JSX.Element;
524
+
525
+ interface OutlineButtonProps {
526
+ children: ReactNode;
527
+ onClick?: () => void;
528
+ disabled?: boolean;
529
+ }
530
+ declare function OutlineButton({ children, onClick, disabled }: OutlineButtonProps): react_jsx_runtime.JSX.Element;
531
+
532
+ type IconCircleVariant = 'accent' | 'success' | 'error';
533
+ interface IconCircleProps {
534
+ children: ReactNode;
535
+ variant?: IconCircleVariant;
536
+ size?: number;
537
+ }
538
+ declare function IconCircle({ children, variant, size }: IconCircleProps): react_jsx_runtime.JSX.Element;
539
+
540
+ interface StepItem {
541
+ label: string;
542
+ /** Optional sublabel (e.g. "$100 limit · 2 tokens approved") */
543
+ detail?: string;
544
+ status: 'pending' | 'active' | 'complete';
545
+ }
546
+ interface StepListProps {
547
+ steps: StepItem[];
548
+ }
549
+ declare function StepList({ steps }: StepListProps): react_jsx_runtime.JSX.Element;
550
+
551
+ interface SettingsMenuProps {
552
+ onLogout: () => void;
553
+ }
554
+ declare function SettingsMenu({ onLogout }: SettingsMenuProps): react_jsx_runtime.JSX.Element;
555
+
556
+ interface SpinnerProps {
557
+ size?: number;
558
+ label?: string;
559
+ }
560
+ declare function Spinner({ size, label }: SpinnerProps): react_jsx_runtime.JSX.Element;
561
+
562
+ interface ChainChoice {
563
+ chainName: string;
564
+ balance: number;
565
+ tokens: {
566
+ tokenSymbol: string;
567
+ balance: number;
568
+ }[];
569
+ }
570
+ interface SelectSourceScreenProps {
571
+ choices: ChainChoice[];
572
+ selectedChainName: string;
573
+ selectedTokenSymbol: string;
574
+ recommended: {
575
+ chainName: string;
576
+ tokenSymbol: string;
577
+ } | null;
578
+ onChainChange: (chainName: string) => void;
579
+ onTokenChange: (tokenSymbol: string) => void;
580
+ onConfirm: () => void;
581
+ onLogout: () => void;
582
+ }
583
+ declare function SelectSourceScreen({ choices, selectedChainName, selectedTokenSymbol, recommended, onChainChange, onTokenChange, onConfirm, onLogout, }: SelectSourceScreenProps): react_jsx_runtime.JSX.Element;
584
+
585
+ export { type Account, type ActionExecutionResult, type AdvancedSettings, type Amount, type AuthorizationAction, type AuthorizationSession, type AuthorizationSessionDetail, type Chain, type Destination, type ErrorResponse, IconCircle, type ListResponse, type MerchantAuthorization, type MerchantPublicKey, OutlineButton, type PaymentStep, PoweredByFooter, PrimaryButton, type Provider, ScreenHeader, ScreenLayout, SelectSourceScreen, SettingsMenu, type SourceOption, type SourceSelection, type SourceType, Spinner, type StepItem, StepList, SwypePayment, type SwypePaymentProps, SwypeProvider, type SwypeProviderProps, type ThemeMode, type ThemeTokens, type TokenBalance, type Transfer, type TransferDestination, type UserConfig, type Wallet, type WalletSource, type WalletToken, createPasskeyCredential, darkTheme, deviceHasPasskey, findDevicePasskey, getTheme, lightTheme, api as swypeApi, useAuthorizationExecutor, useSwypeConfig, useSwypeDepositAmount, useTransferPolling, useTransferSigning };
package/dist/index.js CHANGED
@@ -2,6 +2,7 @@ import { createContext, useRef, useState, useCallback, useMemo, useContext, useE
2
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
+ import { injected } from 'wagmi/connectors';
5
6
  import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
6
7
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
7
8
  import { recoverTypedDataAddress, decodeAbiParameters, walletActions, createClient, custom } from 'viem';
@@ -74,6 +75,7 @@ function getTheme(mode) {
74
75
  var SWYPE_PRIVY_APP_ID = "cmlil87uv004n0ck0blwumwek";
75
76
  var wagmiConfig = createConfig({
76
77
  chains: [mainnet, arbitrum, base],
78
+ connectors: [injected()],
77
79
  transports: {
78
80
  [mainnet.id]: http(),
79
81
  [arbitrum.id]: http(),
@@ -2560,13 +2562,20 @@ var WALLET_EMOJIS = {
2560
2562
  ora: "\u2666\uFE0F",
2561
2563
  phantom: "\u{1F47B}"
2562
2564
  };
2565
+ function truncateAddress(address) {
2566
+ if (address.length <= 10) return address;
2567
+ return `${address.slice(0, 6)}...${address.slice(-4)}`;
2568
+ }
2563
2569
  function WalletPickerScreen({
2564
2570
  providers,
2571
+ pendingConnections,
2565
2572
  onSelectProvider,
2573
+ onContinueConnection,
2566
2574
  onBack
2567
2575
  }) {
2568
2576
  const { tokens } = useSwypeConfig();
2569
2577
  const [hoveredId, setHoveredId] = useState(null);
2578
+ const hasPending = pendingConnections != null && pendingConnections.length > 0;
2570
2579
  const displayProviders = providers.length > 0 ? providers : [
2571
2580
  { id: "metamask", name: "MetaMask" },
2572
2581
  { id: "rabby", name: "Rabby" },
@@ -2582,8 +2591,44 @@ function WalletPickerScreen({
2582
2591
  ] }),
2583
2592
  children: [
2584
2593
  /* @__PURE__ */ jsx(ScreenHeader, { title: "Set up Swype", onBack }),
2585
- /* @__PURE__ */ jsx("h2", { style: headingStyle4(tokens.text), children: "Where are your stablecoins?" }),
2586
- /* @__PURE__ */ jsx("p", { style: subtitleStyle4(tokens.textSecondary), children: "Select the wallet you want to deposit from" }),
2594
+ hasPending && /* @__PURE__ */ jsxs(Fragment, { children: [
2595
+ /* @__PURE__ */ jsx("h2", { style: headingStyle4(tokens.text), children: "Continue where you left off" }),
2596
+ /* @__PURE__ */ jsx("p", { style: subtitleStyle4(tokens.textSecondary), children: "You have a wallet that still needs setup" }),
2597
+ /* @__PURE__ */ jsx("div", { style: pendingListStyle, children: pendingConnections.map((acct) => {
2598
+ const wallet = acct.wallets[0];
2599
+ const address = wallet ? truncateAddress(wallet.name) : void 0;
2600
+ const isHovered = hoveredId === `pending-${acct.id}`;
2601
+ return /* @__PURE__ */ jsxs(
2602
+ "button",
2603
+ {
2604
+ onClick: () => onContinueConnection?.(acct.id),
2605
+ onMouseEnter: () => setHoveredId(`pending-${acct.id}`),
2606
+ onMouseLeave: () => setHoveredId(null),
2607
+ style: pendingCardStyle(tokens, isHovered),
2608
+ children: [
2609
+ /* @__PURE__ */ jsxs("div", { style: pendingCardContentStyle, children: [
2610
+ /* @__PURE__ */ jsx("div", { style: pendingIconStyle, children: /* @__PURE__ */ jsx("span", { style: emojiStyle, children: WALLET_EMOJIS[acct.name.toLowerCase()] ?? acct.name.charAt(0) }) }),
2611
+ /* @__PURE__ */ jsxs("div", { style: pendingInfoStyle, children: [
2612
+ /* @__PURE__ */ jsx("span", { style: pendingNameStyle(tokens.text), children: acct.name }),
2613
+ address && /* @__PURE__ */ jsx("span", { style: pendingAddressStyle(tokens.textMuted), children: address })
2614
+ ] }),
2615
+ /* @__PURE__ */ jsx("span", { style: pendingBadgeStyle(tokens), children: "Setup incomplete" })
2616
+ ] }),
2617
+ /* @__PURE__ */ jsxs("div", { style: continueRowStyle(tokens), children: [
2618
+ "Continue setup",
2619
+ /* @__PURE__ */ jsx("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ jsx("path", { d: "M8.59 16.59L13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.41z", fill: "currentColor" }) })
2620
+ ] })
2621
+ ]
2622
+ },
2623
+ acct.id
2624
+ );
2625
+ }) }),
2626
+ /* @__PURE__ */ jsx("div", { style: dividerStyle2(tokens.border), children: /* @__PURE__ */ jsx("span", { style: dividerTextStyle(tokens.textMuted), children: "Or connect a new wallet" }) })
2627
+ ] }),
2628
+ !hasPending && /* @__PURE__ */ jsxs(Fragment, { children: [
2629
+ /* @__PURE__ */ jsx("h2", { style: headingStyle4(tokens.text), children: "Where are your stablecoins?" }),
2630
+ /* @__PURE__ */ jsx("p", { style: subtitleStyle4(tokens.textSecondary), children: "Select the wallet you want to deposit from" })
2631
+ ] }),
2587
2632
  /* @__PURE__ */ jsxs("div", { style: gridStyle, children: [
2588
2633
  displayProviders.map((p) => {
2589
2634
  const emoji = WALLET_EMOJIS[p.name.toLowerCase()] ?? p.name.charAt(0);
@@ -2687,6 +2732,86 @@ var hintStyle2 = (color) => ({
2687
2732
  color,
2688
2733
  margin: "0 0 4px"
2689
2734
  });
2735
+ var pendingListStyle = {
2736
+ display: "flex",
2737
+ flexDirection: "column",
2738
+ gap: 10,
2739
+ marginBottom: 20
2740
+ };
2741
+ var pendingCardStyle = (tokens, hovered) => ({
2742
+ display: "flex",
2743
+ flexDirection: "column",
2744
+ gap: 0,
2745
+ padding: 0,
2746
+ background: hovered ? tokens.bgHover : tokens.bgInput,
2747
+ border: `1.5px solid ${tokens.warning}44`,
2748
+ borderRadius: 16,
2749
+ cursor: "pointer",
2750
+ fontFamily: "inherit",
2751
+ transition: "background 0.15s ease",
2752
+ outline: "none",
2753
+ overflow: "hidden",
2754
+ textAlign: "left"
2755
+ });
2756
+ var pendingCardContentStyle = {
2757
+ display: "flex",
2758
+ alignItems: "center",
2759
+ gap: 12,
2760
+ padding: "14px 16px"
2761
+ };
2762
+ var pendingIconStyle = {
2763
+ flexShrink: 0
2764
+ };
2765
+ var pendingInfoStyle = {
2766
+ display: "flex",
2767
+ flexDirection: "column",
2768
+ gap: 2,
2769
+ flex: 1,
2770
+ minWidth: 0
2771
+ };
2772
+ var pendingNameStyle = (color) => ({
2773
+ fontSize: "0.92rem",
2774
+ fontWeight: 600,
2775
+ color
2776
+ });
2777
+ var pendingAddressStyle = (color) => ({
2778
+ fontSize: "0.78rem",
2779
+ color,
2780
+ fontFamily: "monospace"
2781
+ });
2782
+ var pendingBadgeStyle = (tokens) => ({
2783
+ fontSize: "0.72rem",
2784
+ fontWeight: 600,
2785
+ color: tokens.warningText ?? tokens.warning,
2786
+ background: tokens.warningBg ?? `${tokens.warning}1a`,
2787
+ padding: "3px 8px",
2788
+ borderRadius: 6,
2789
+ whiteSpace: "nowrap",
2790
+ flexShrink: 0
2791
+ });
2792
+ var continueRowStyle = (tokens) => ({
2793
+ display: "flex",
2794
+ alignItems: "center",
2795
+ justifyContent: "center",
2796
+ gap: 4,
2797
+ padding: "10px 16px",
2798
+ fontSize: "0.84rem",
2799
+ fontWeight: 600,
2800
+ color: tokens.accent,
2801
+ background: `${tokens.accent}0d`,
2802
+ borderTop: `1px solid ${tokens.accent}22`
2803
+ });
2804
+ var dividerStyle2 = (borderColor) => ({
2805
+ display: "flex",
2806
+ alignItems: "center",
2807
+ gap: 12,
2808
+ margin: "4px 0 16px"
2809
+ });
2810
+ var dividerTextStyle = (color) => ({
2811
+ fontSize: "0.82rem",
2812
+ color,
2813
+ whiteSpace: "nowrap"
2814
+ });
2690
2815
  var DEFAULT_MAX = 500;
2691
2816
  var ABSOLUTE_MIN = 1;
2692
2817
  function buildTicks(min, max) {
@@ -3774,6 +3899,7 @@ function SwypePayment({
3774
3899
  const [setupComplete, setSetupComplete] = useState(false);
3775
3900
  const [setupStepLabel, setSetupStepLabel] = useState(void 0);
3776
3901
  const [mobileFlow, setMobileFlow] = useState(false);
3902
+ const [mobileSetupFlow, setMobileSetupFlow] = useState(false);
3777
3903
  const pollingTransferIdRef = useRef(null);
3778
3904
  const mobileSigningTransferIdRef = useRef(null);
3779
3905
  const processingStartedAtRef = useRef(null);
@@ -3786,6 +3912,23 @@ function SwypePayment({
3786
3912
  const transferSigning = useTransferSigning();
3787
3913
  const sourceType = connectingNewAccount ? "providerId" : selectedWalletId ? "walletId" : selectedAccountId ? "accountId" : "providerId";
3788
3914
  const sourceId = connectingNewAccount ? selectedProviderId ?? "" : selectedWalletId ? selectedWalletId : selectedAccountId ? selectedAccountId : selectedProviderId ?? "";
3915
+ const reloadAccounts = useCallback(async () => {
3916
+ const token = await getAccessToken();
3917
+ if (!token || !activeCredentialId) return;
3918
+ const [accts, prov] = await Promise.all([
3919
+ fetchAccounts(apiBaseUrl, token, activeCredentialId),
3920
+ fetchProviders(apiBaseUrl, token)
3921
+ ]);
3922
+ setAccounts(accts);
3923
+ setProviders(prov);
3924
+ const parsedAmt = depositAmount != null ? depositAmount : 0;
3925
+ const defaults = computeSmartDefaults(accts, parsedAmt);
3926
+ if (defaults) {
3927
+ setSelectedAccountId(defaults.accountId);
3928
+ setSelectedWalletId(defaults.walletId);
3929
+ setConnectingNewAccount(false);
3930
+ }
3931
+ }, [getAccessToken, activeCredentialId, apiBaseUrl, depositAmount]);
3789
3932
  useEffect(() => {
3790
3933
  if (depositAmount != null) {
3791
3934
  setAmount(depositAmount.toString());
@@ -3935,7 +4078,10 @@ function SwypePayment({
3935
4078
  } else if (prov.length > 0) {
3936
4079
  setSelectedProviderId(prov[0].id);
3937
4080
  }
3938
- if (accts.length === 0 && step === "deposit") {
4081
+ const hasActiveWallet = accts.some(
4082
+ (a) => a.wallets.some((w) => w.status === "ACTIVE")
4083
+ );
4084
+ if ((accts.length === 0 || !hasActiveWallet) && step === "deposit") {
3939
4085
  setStep("wallet-picker");
3940
4086
  }
3941
4087
  } catch (err) {
@@ -3994,7 +4140,24 @@ function SwypePayment({
3994
4140
  return () => window.clearTimeout(timeoutId);
3995
4141
  }, [step, polling.transfer, transfer, polling.stopPolling, onError]);
3996
4142
  useEffect(() => {
3997
- if (!mobileFlow) return;
4143
+ if (!mobileSetupFlow) return;
4144
+ const polledTransfer = polling.transfer;
4145
+ if (!polledTransfer) return;
4146
+ if (polledTransfer.status !== "AUTHORIZED" && polledTransfer.status !== "COMPLETED") return;
4147
+ polling.stopPolling();
4148
+ setMobileFlow(false);
4149
+ setMobileSetupFlow(false);
4150
+ const finishSetup = async () => {
4151
+ try {
4152
+ await reloadAccounts();
4153
+ } catch {
4154
+ }
4155
+ setStep("deposit");
4156
+ };
4157
+ void finishSetup();
4158
+ }, [mobileSetupFlow, polling, reloadAccounts]);
4159
+ useEffect(() => {
4160
+ if (!mobileFlow || mobileSetupFlow) return;
3998
4161
  const polledTransfer = polling.transfer;
3999
4162
  if (!polledTransfer || polledTransfer.status !== "AUTHORIZED") return;
4000
4163
  if (transferSigning.signing) return;
@@ -4012,7 +4175,7 @@ function SwypePayment({
4012
4175
  }
4013
4176
  };
4014
4177
  void sign();
4015
- }, [mobileFlow, polling.transfer, transferSigning, onError]);
4178
+ }, [mobileFlow, mobileSetupFlow, polling.transfer, transferSigning, onError]);
4016
4179
  useEffect(() => {
4017
4180
  if (!mobileFlow) return;
4018
4181
  const transferIdToResume = pollingTransferIdRef.current ?? transfer?.id;
@@ -4097,6 +4260,12 @@ function SwypePayment({
4097
4260
  },
4098
4261
  [selectSourceChoices, selectSourceRecommended]
4099
4262
  );
4263
+ const pendingConnections = useMemo(
4264
+ () => accounts.filter(
4265
+ (a) => a.wallets.length > 0 && !a.wallets.some((w) => w.status === "ACTIVE")
4266
+ ),
4267
+ [accounts]
4268
+ );
4100
4269
  const selectedAccount = accounts.find((a) => a.id === selectedAccountId);
4101
4270
  const selectedWallet = selectedAccount?.wallets.find((w) => w.id === selectedWalletId);
4102
4271
  const sourceName = selectedAccount?.name ?? selectedWallet?.chain.name ?? "Wallet";
@@ -4240,7 +4409,10 @@ function SwypePayment({
4240
4409
  await registerPasskey(apiBaseUrl, token, credentialId, publicKey);
4241
4410
  setActiveCredentialId(credentialId);
4242
4411
  window.localStorage.setItem(ACTIVE_CREDENTIAL_STORAGE_KEY, credentialId);
4243
- if (accounts.length === 0) {
4412
+ const hasActiveWallet = accounts.some(
4413
+ (a) => a.wallets.some((w) => w.status === "ACTIVE")
4414
+ );
4415
+ if (accounts.length === 0 || !hasActiveWallet) {
4244
4416
  setStep("wallet-picker");
4245
4417
  } else {
4246
4418
  setStep("deposit");
@@ -4250,14 +4422,17 @@ function SwypePayment({
4250
4422
  } finally {
4251
4423
  setRegisteringPasskey(false);
4252
4424
  }
4253
- }, [getAccessToken, user, apiBaseUrl, accounts.length]);
4425
+ }, [getAccessToken, user, apiBaseUrl, accounts]);
4254
4426
  const handleSkipPasskey = useCallback(() => {
4255
- if (accounts.length === 0) {
4427
+ const hasActiveWallet = accounts.some(
4428
+ (a) => a.wallets.some((w) => w.status === "ACTIVE")
4429
+ );
4430
+ if (accounts.length === 0 || !hasActiveWallet) {
4256
4431
  setStep("wallet-picker");
4257
4432
  } else {
4258
4433
  setStep("deposit");
4259
4434
  }
4260
- }, [accounts.length]);
4435
+ }, [accounts]);
4261
4436
  const handleSetupOneTap = useCallback(async (limit) => {
4262
4437
  setOneTapLimit(limit);
4263
4438
  setStep("setup-status");
@@ -4270,6 +4445,7 @@ function SwypePayment({
4270
4445
  if (!sourceId) {
4271
4446
  throw new Error("No wallet selected for setup.");
4272
4447
  }
4448
+ await updateUserConfig(apiBaseUrl, token, { defaultAllowance: limit });
4273
4449
  const setupAmount = depositAmount ?? MIN_SEND_AMOUNT_USD;
4274
4450
  const t = await createTransfer(apiBaseUrl, token, {
4275
4451
  id: idempotencyKey,
@@ -4287,11 +4463,16 @@ function SwypePayment({
4287
4463
  });
4288
4464
  if (!shouldUseConnector) {
4289
4465
  setMobileFlow(true);
4466
+ setMobileSetupFlow(true);
4467
+ pollingTransferIdRef.current = t.id;
4468
+ polling.startPolling(t.id);
4290
4469
  window.location.href = t.authorizationSessions[0].uri;
4470
+ return;
4291
4471
  } else {
4292
4472
  await authExecutor.executeSession(t);
4293
4473
  }
4294
4474
  }
4475
+ await reloadAccounts();
4295
4476
  setSetupStepLabel(void 0);
4296
4477
  setSetupComplete(true);
4297
4478
  } catch (err) {
@@ -4310,8 +4491,10 @@ function SwypePayment({
4310
4491
  merchantAuthorization,
4311
4492
  useWalletConnector,
4312
4493
  authExecutor,
4494
+ polling,
4313
4495
  onError,
4314
- depositAmount
4496
+ depositAmount,
4497
+ reloadAccounts
4315
4498
  ]);
4316
4499
  const handleSelectProvider = useCallback((providerId) => {
4317
4500
  setSelectedProviderId(providerId);
@@ -4319,12 +4502,23 @@ function SwypePayment({
4319
4502
  setConnectingNewAccount(true);
4320
4503
  setStep("setup");
4321
4504
  }, []);
4505
+ const handleContinueConnection = useCallback(
4506
+ (accountId) => {
4507
+ const acct = accounts.find((a) => a.id === accountId);
4508
+ setSelectedAccountId(accountId);
4509
+ setSelectedWalletId(acct?.wallets[0]?.id ?? null);
4510
+ setConnectingNewAccount(false);
4511
+ setStep("setup");
4512
+ },
4513
+ [accounts]
4514
+ );
4322
4515
  const handleNewPayment = useCallback(() => {
4323
4516
  setStep("deposit");
4324
4517
  setTransfer(null);
4325
4518
  setError(null);
4326
4519
  setAmount(depositAmount != null ? depositAmount.toString() : "");
4327
4520
  setMobileFlow(false);
4521
+ setMobileSetupFlow(false);
4328
4522
  processingStartedAtRef.current = null;
4329
4523
  pollingTransferIdRef.current = null;
4330
4524
  mobileSigningTransferIdRef.current = null;
@@ -4357,6 +4551,7 @@ function SwypePayment({
4357
4551
  setConnectingNewAccount(false);
4358
4552
  setAmount(depositAmount != null ? depositAmount.toString() : "");
4359
4553
  setMobileFlow(false);
4554
+ setMobileSetupFlow(false);
4360
4555
  setSetupComplete(false);
4361
4556
  resetHeadlessLogin();
4362
4557
  }, [logout, polling, depositAmount, resetHeadlessLogin]);
@@ -4420,7 +4615,9 @@ function SwypePayment({
4420
4615
  WalletPickerScreen,
4421
4616
  {
4422
4617
  providers,
4618
+ pendingConnections,
4423
4619
  onSelectProvider: handleSelectProvider,
4620
+ onContinueConnection: handleContinueConnection,
4424
4621
  onBack: () => setStep("create-passkey")
4425
4622
  }
4426
4623
  );
@@ -4559,6 +4756,6 @@ function SwypePayment({
4559
4756
  return null;
4560
4757
  }
4561
4758
 
4562
- export { SwypePayment, SwypeProvider, createPasskeyCredential, darkTheme, deviceHasPasskey, findDevicePasskey, getTheme, lightTheme, api_exports as swypeApi, useAuthorizationExecutor, useSwypeConfig, useSwypeDepositAmount, useTransferPolling, useTransferSigning };
4759
+ export { IconCircle, OutlineButton, PoweredByFooter, PrimaryButton, ScreenHeader, ScreenLayout, SelectSourceScreen, SettingsMenu, Spinner, StepList, SwypePayment, SwypeProvider, createPasskeyCredential, darkTheme, deviceHasPasskey, findDevicePasskey, getTheme, lightTheme, api_exports as swypeApi, useAuthorizationExecutor, useSwypeConfig, useSwypeDepositAmount, useTransferPolling, useTransferSigning };
4563
4760
  //# sourceMappingURL=index.js.map
4564
4761
  //# sourceMappingURL=index.js.map