@swype-org/react-sdk 0.1.64 → 0.1.68

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.cjs CHANGED
@@ -657,6 +657,24 @@ function normalizeSignature(sig) {
657
657
  );
658
658
  }
659
659
 
660
+ // src/transferPolling.ts
661
+ async function pollTransferTick(params) {
662
+ const fetchTransfer2 = params.fetchTransfer ?? fetchTransfer;
663
+ const token = await params.getAccessToken();
664
+ if (!token) {
665
+ return { kind: "retry" };
666
+ }
667
+ try {
668
+ const transfer = await fetchTransfer2(params.apiBaseUrl, token, params.transferId);
669
+ return { kind: "success", transfer };
670
+ } catch (err) {
671
+ return {
672
+ kind: "error",
673
+ message: err instanceof Error ? err.message : "Polling error"
674
+ };
675
+ }
676
+ }
677
+
660
678
  // src/passkey-delegation.ts
661
679
  var PasskeyIframeBlockedError = class extends Error {
662
680
  constructor(message = "Passkey creation is not supported in this browser context.") {
@@ -959,20 +977,22 @@ function useTransferPolling(intervalMs = 3e3) {
959
977
  }, []);
960
978
  const poll = react.useCallback(async () => {
961
979
  if (!transferIdRef.current) return;
962
- try {
963
- const token = await getAccessToken();
964
- if (!token) {
965
- setError("Could not get access token");
966
- stopPolling();
967
- return;
968
- }
969
- const t = await fetchTransfer(apiBaseUrl, token, transferIdRef.current);
970
- setTransfer(t);
971
- if (t.status === "COMPLETED" || t.status === "FAILED") {
972
- stopPolling();
973
- }
974
- } catch (err) {
975
- setError(err instanceof Error ? err.message : "Polling error");
980
+ const result = await pollTransferTick({
981
+ apiBaseUrl,
982
+ transferId: transferIdRef.current,
983
+ getAccessToken
984
+ });
985
+ if (result.kind === "retry") {
986
+ return;
987
+ }
988
+ if (result.kind === "error") {
989
+ setError(result.message);
990
+ stopPolling();
991
+ return;
992
+ }
993
+ setError(null);
994
+ setTransfer(result.transfer);
995
+ if (result.transfer.status === "COMPLETED" || result.transfer.status === "FAILED") {
976
996
  stopPolling();
977
997
  }
978
998
  }, [apiBaseUrl, getAccessToken, stopPolling]);
@@ -1583,6 +1603,41 @@ function isMobileUserAgent(userAgent) {
1583
1603
  function shouldUseWalletConnector(options) {
1584
1604
  return options.useWalletConnector ?? !isMobileUserAgent(options.userAgent);
1585
1605
  }
1606
+
1607
+ // src/mobileFlow.ts
1608
+ function hasActiveWallet(accounts) {
1609
+ return accounts.some((account) => account.wallets.some((wallet) => wallet.status === "ACTIVE"));
1610
+ }
1611
+ function resolvePostAuthStep(state) {
1612
+ if (!state.hasPasskey) {
1613
+ return { step: "create-passkey", clearPersistedFlow: false };
1614
+ }
1615
+ if (state.persistedMobileFlow) {
1616
+ if (state.persistedMobileFlow.isSetup && hasActiveWallet(state.accounts)) {
1617
+ return { step: "deposit", clearPersistedFlow: true };
1618
+ }
1619
+ return { step: "open-wallet", clearPersistedFlow: false };
1620
+ }
1621
+ if ((state.accounts.length === 0 || !hasActiveWallet(state.accounts)) && !state.connectingNewAccount) {
1622
+ return { step: "wallet-picker", clearPersistedFlow: false };
1623
+ }
1624
+ return { step: "deposit", clearPersistedFlow: false };
1625
+ }
1626
+ function resolveRestoredMobileFlow(transferStatus, isSetup) {
1627
+ if (transferStatus === "AUTHORIZED") {
1628
+ return isSetup ? { kind: "resume-setup-deposit", step: "deposit", clearPersistedFlow: true } : { kind: "resume-confirm-sign", step: "confirm-sign", clearPersistedFlow: true };
1629
+ }
1630
+ if (transferStatus === "COMPLETED") {
1631
+ return { kind: "resume-success", step: "success", clearPersistedFlow: true };
1632
+ }
1633
+ if (transferStatus === "FAILED") {
1634
+ return { kind: "resume-failed", step: "success", clearPersistedFlow: true };
1635
+ }
1636
+ if (isSetup) {
1637
+ return { kind: "resume-stale-setup", step: "wallet-picker", clearPersistedFlow: true };
1638
+ }
1639
+ return { kind: "resume-open-wallet", step: "open-wallet", clearPersistedFlow: false };
1640
+ }
1586
1641
  var FOOTER_CSS = `
1587
1642
  .swype-screen-footer {
1588
1643
  padding-bottom: max(24px, env(safe-area-inset-bottom, 24px));
@@ -1911,137 +1966,6 @@ var inputStyle = (tokens, filled) => ({
1911
1966
  caretColor: tokens.borderFocus,
1912
1967
  transition: "border-color 0.15s ease"
1913
1968
  });
1914
- function LimitSlider({
1915
- value,
1916
- min,
1917
- max,
1918
- step = 1,
1919
- onChange,
1920
- ticks,
1921
- disabled
1922
- }) {
1923
- const { tokens } = useSwypeConfig();
1924
- const pct = (value - min) / (max - min) * 100;
1925
- const handleChange = react.useCallback(
1926
- (e) => onChange(Number(e.target.value)),
1927
- [onChange]
1928
- );
1929
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "swype-slider-wrap", style: wrapperStyle, children: [
1930
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: trackContainerStyle, children: [
1931
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: trackBgStyle(tokens.border) }),
1932
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: trackFillStyle(tokens.accent, pct) }),
1933
- /* @__PURE__ */ jsxRuntime.jsx(
1934
- "input",
1935
- {
1936
- type: "range",
1937
- min,
1938
- max,
1939
- step,
1940
- value,
1941
- onChange: handleChange,
1942
- disabled,
1943
- style: rangeInputStyle
1944
- }
1945
- )
1946
- ] }),
1947
- ticks && ticks.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { style: ticksStyle, children: ticks.map((tick, i) => {
1948
- const pctPos = (tick - min) / (max - min) * 100;
1949
- const isFirst = i === 0;
1950
- const isLast = i === ticks.length - 1;
1951
- const label = tick % 1 === 0 ? `$${tick}` : `$${tick.toFixed(2)}`;
1952
- return /* @__PURE__ */ jsxRuntime.jsx(
1953
- "span",
1954
- {
1955
- style: tickLabelStyle(tokens.textMuted, pctPos, isFirst, isLast),
1956
- children: label
1957
- },
1958
- tick
1959
- );
1960
- }) }),
1961
- /* @__PURE__ */ jsxRuntime.jsx("style", { children: sliderThumbCss(tokens.accent) })
1962
- ] });
1963
- }
1964
- var wrapperStyle = { width: "100%" };
1965
- var trackContainerStyle = {
1966
- position: "relative",
1967
- height: 28,
1968
- display: "flex",
1969
- alignItems: "center"
1970
- };
1971
- var trackBgStyle = (color) => ({
1972
- position: "absolute",
1973
- left: 0,
1974
- right: 0,
1975
- height: 4,
1976
- borderRadius: 2,
1977
- background: color
1978
- });
1979
- var trackFillStyle = (color, pct) => ({
1980
- position: "absolute",
1981
- left: 0,
1982
- width: `${pct}%`,
1983
- height: 4,
1984
- borderRadius: 2,
1985
- background: color
1986
- });
1987
- var rangeInputStyle = {
1988
- position: "absolute",
1989
- left: 0,
1990
- right: 0,
1991
- width: "100%",
1992
- height: 28,
1993
- margin: 0,
1994
- cursor: "pointer",
1995
- zIndex: 2,
1996
- WebkitAppearance: "none",
1997
- appearance: "none",
1998
- background: "transparent"
1999
- };
2000
- var ticksStyle = {
2001
- position: "relative",
2002
- height: 18,
2003
- marginTop: 6
2004
- };
2005
- var tickLabelStyle = (color, pct, isFirst, isLast) => ({
2006
- position: "absolute",
2007
- left: `${pct}%`,
2008
- transform: isFirst ? "none" : isLast ? "translateX(-100%)" : "translateX(-50%)",
2009
- fontSize: "0.72rem",
2010
- fontWeight: 500,
2011
- color,
2012
- whiteSpace: "nowrap"
2013
- });
2014
- var sliderThumbCss = (accent) => `
2015
- .swype-slider-wrap input[type="range"]::-webkit-slider-runnable-track {
2016
- height: 4px;
2017
- background: transparent;
2018
- }
2019
- .swype-slider-wrap input[type="range"]::-webkit-slider-thumb {
2020
- -webkit-appearance: none;
2021
- width: 20px;
2022
- height: 20px;
2023
- border-radius: 50%;
2024
- background: ${accent};
2025
- border: 3px solid #fff;
2026
- box-shadow: 0 2px 6px rgba(0,0,0,0.15);
2027
- cursor: pointer;
2028
- margin-top: -8px;
2029
- }
2030
- .swype-slider-wrap input[type="range"]::-moz-range-track {
2031
- height: 4px;
2032
- background: transparent;
2033
- border: none;
2034
- }
2035
- .swype-slider-wrap input[type="range"]::-moz-range-thumb {
2036
- width: 14px;
2037
- height: 14px;
2038
- border-radius: 50%;
2039
- background: ${accent};
2040
- border: 3px solid #fff;
2041
- box-shadow: 0 2px 6px rgba(0,0,0,0.15);
2042
- cursor: pointer;
2043
- }
2044
- `;
2045
1969
 
2046
1970
  // src/assets/logos.ts
2047
1971
  function svgToDataUri(svg) {
@@ -3003,18 +2927,6 @@ var dividerTextStyle = (color) => ({
3003
2927
  });
3004
2928
  var DEFAULT_MAX = 500;
3005
2929
  var ABSOLUTE_MIN = 1;
3006
- function buildTicks(min, max) {
3007
- if (max <= min) return [min];
3008
- const range = max - min;
3009
- const candidates = [1, 2, 5, 10, 25, 50, 100, 250];
3010
- const step = candidates.find((s) => range / s <= 5) ?? Math.ceil(range / 4);
3011
- const ticks = [];
3012
- for (let v = min; v <= max; v += step) {
3013
- ticks.push(Math.round(v * 100) / 100);
3014
- }
3015
- if (ticks[ticks.length - 1] !== max) ticks.push(max);
3016
- return ticks;
3017
- }
3018
2930
  function SetupScreen({
3019
2931
  availableBalance,
3020
2932
  tokenCount,
@@ -3030,9 +2942,22 @@ function SetupScreen({
3030
2942
  const { tokens } = useSwypeConfig();
3031
2943
  const effectiveMax = Math.floor(Math.min(DEFAULT_MAX, availableBalance > 0 ? availableBalance : DEFAULT_MAX) * 100) / 100;
3032
2944
  const effectiveMin = Math.min(ABSOLUTE_MIN, effectiveMax);
3033
- const sliderStep = effectiveMax <= 10 ? 0.5 : effectiveMax <= 50 ? 1 : 5;
3034
- const ticks = buildTicks(effectiveMin, effectiveMax);
3035
- const [limit, setLimit] = react.useState(() => Math.min(100, effectiveMax));
2945
+ const [limit, setLimit] = react.useState(() => effectiveMax);
2946
+ const [editing, setEditing] = react.useState(false);
2947
+ const [inputValue, setInputValue] = react.useState("");
2948
+ const inputRef = react.useRef(null);
2949
+ const startEditing = react.useCallback(() => {
2950
+ setInputValue(limit.toFixed(2));
2951
+ setEditing(true);
2952
+ requestAnimationFrame(() => inputRef.current?.select());
2953
+ }, [limit]);
2954
+ const commitEdit = react.useCallback(() => {
2955
+ const parsed = parseFloat(inputValue);
2956
+ if (!isNaN(parsed)) {
2957
+ setLimit(Math.min(effectiveMax, Math.max(effectiveMin, Math.round(parsed * 100) / 100)));
2958
+ }
2959
+ setEditing(false);
2960
+ }, [inputValue, effectiveMax, effectiveMin]);
3036
2961
  return /* @__PURE__ */ jsxRuntime.jsxs(
3037
2962
  ScreenLayout,
3038
2963
  {
@@ -3088,19 +3013,33 @@ function SetupScreen({
3088
3013
  ] }),
3089
3014
  /* @__PURE__ */ jsxRuntime.jsxs("div", { style: limitSectionStyle, children: [
3090
3015
  /* @__PURE__ */ jsxRuntime.jsx("div", { style: limitLabelStyle(tokens.textMuted), children: "Your One-Tap limit" }),
3091
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: limitValueStyle(tokens.text), children: [
3016
+ editing ? /* @__PURE__ */ jsxRuntime.jsxs("div", { style: limitValueStyle(tokens.text), children: [
3092
3017
  "$",
3093
- limit.toFixed(2)
3094
- ] }),
3095
- /* @__PURE__ */ jsxRuntime.jsx(
3096
- LimitSlider,
3018
+ /* @__PURE__ */ jsxRuntime.jsx(
3019
+ "input",
3020
+ {
3021
+ ref: inputRef,
3022
+ type: "text",
3023
+ inputMode: "decimal",
3024
+ pattern: "[0-9]*",
3025
+ value: inputValue,
3026
+ onChange: (e) => setInputValue(e.target.value),
3027
+ onBlur: commitEdit,
3028
+ onKeyDown: (e) => {
3029
+ if (e.key === "Enter") commitEdit();
3030
+ },
3031
+ style: limitInputStyle(tokens.text)
3032
+ }
3033
+ )
3034
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(
3035
+ "div",
3097
3036
  {
3098
- value: limit,
3099
- min: effectiveMin,
3100
- max: effectiveMax,
3101
- step: sliderStep,
3102
- ticks,
3103
- onChange: setLimit
3037
+ style: { ...limitValueStyle(tokens.text), cursor: "pointer" },
3038
+ onClick: startEditing,
3039
+ children: [
3040
+ "$",
3041
+ limit.toFixed(2)
3042
+ ]
3104
3043
  }
3105
3044
  )
3106
3045
  ] }),
@@ -3207,6 +3146,19 @@ var limitValueStyle = (color) => ({
3207
3146
  color,
3208
3147
  marginBottom: 12
3209
3148
  });
3149
+ var limitInputStyle = (color) => ({
3150
+ fontSize: "2.2rem",
3151
+ fontWeight: 700,
3152
+ color,
3153
+ background: "transparent",
3154
+ border: "none",
3155
+ borderBottom: "2px solid currentColor",
3156
+ outline: "none",
3157
+ textAlign: "center",
3158
+ width: "5ch",
3159
+ fontFamily: "inherit",
3160
+ padding: 0
3161
+ });
3210
3162
  var bannerWrapStyle = { marginBottom: 16 };
3211
3163
  var linkStyle = (color) => ({
3212
3164
  background: "transparent",
@@ -4112,6 +4064,8 @@ function OpenWalletScreen({
4112
4064
  walletName,
4113
4065
  deeplinkUri,
4114
4066
  loading,
4067
+ error,
4068
+ onRetryStatus,
4115
4069
  onLogout
4116
4070
  }) {
4117
4071
  const { tokens } = useSwypeConfig();
@@ -4132,12 +4086,14 @@ function OpenWalletScreen({
4132
4086
  return /* @__PURE__ */ jsxRuntime.jsxs(
4133
4087
  ScreenLayout,
4134
4088
  {
4135
- footer: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4089
+ footer: /* @__PURE__ */ jsxRuntime.jsxs("div", { style: footerContentStyle, children: [
4090
+ error && /* @__PURE__ */ jsxRuntime.jsx(InfoBanner, { children: error }),
4136
4091
  !loading && /* @__PURE__ */ jsxRuntime.jsxs(PrimaryButton, { onClick: handleOpen, children: [
4137
4092
  "Open ",
4138
4093
  displayName
4139
4094
  ] }),
4140
- /* @__PURE__ */ jsxRuntime.jsx("p", { style: hintStyle3(tokens.textMuted), children: loading ? "Preparing authorization..." : "If your wallet didn't open automatically, tap the button above" })
4095
+ error && onRetryStatus && /* @__PURE__ */ jsxRuntime.jsx(OutlineButton, { onClick: onRetryStatus, children: "Retry status check" }),
4096
+ /* @__PURE__ */ jsxRuntime.jsx("p", { style: hintStyle3(tokens.textMuted), children: loading ? "Preparing authorization..." : error ? "Retry the status check after returning to the browser, or reopen your wallet if needed." : "If your wallet didn't open automatically, tap the button above" })
4141
4097
  ] }),
4142
4098
  children: [
4143
4099
  /* @__PURE__ */ jsxRuntime.jsx(ScreenHeader, { right: /* @__PURE__ */ jsxRuntime.jsx(SettingsMenu, { onLogout }) }),
@@ -4163,6 +4119,11 @@ var contentStyle6 = {
4163
4119
  textAlign: "center",
4164
4120
  padding: "0 24px"
4165
4121
  };
4122
+ var footerContentStyle = {
4123
+ display: "flex",
4124
+ flexDirection: "column",
4125
+ gap: 12
4126
+ };
4166
4127
  var logoStyle = {
4167
4128
  width: 56,
4168
4129
  height: 56,
@@ -4452,24 +4413,6 @@ function buildSelectSourceChoices(options) {
4452
4413
  }
4453
4414
  return chainChoices;
4454
4415
  }
4455
- function resolvePostAuthStep(state) {
4456
- if (!state.hasPasskey) {
4457
- return { step: "create-passkey", clearPersistedFlow: false };
4458
- }
4459
- const hasActiveWallet = state.accounts.some(
4460
- (a) => a.wallets.some((w) => w.status === "ACTIVE")
4461
- );
4462
- if (state.persistedMobileFlow) {
4463
- if (hasActiveWallet && !state.mobileSetupInProgress) {
4464
- return { step: "deposit", clearPersistedFlow: true };
4465
- }
4466
- return { step: "open-wallet", clearPersistedFlow: false };
4467
- }
4468
- if ((state.accounts.length === 0 || !hasActiveWallet) && !state.connectingNewAccount) {
4469
- return { step: "wallet-picker", clearPersistedFlow: false };
4470
- }
4471
- return { step: "deposit", clearPersistedFlow: false };
4472
- }
4473
4416
  function SwypePayment(props) {
4474
4417
  const resetKey = react.useRef(0);
4475
4418
  const handleBoundaryReset = react.useCallback(() => {
@@ -4559,6 +4502,55 @@ function SwypePaymentInner({
4559
4502
  setConnectingNewAccount(false);
4560
4503
  }
4561
4504
  }, [getAccessToken, activeCredentialId, apiBaseUrl, depositAmount]);
4505
+ const enterPersistedMobileFlow = react.useCallback((persisted, errorMessage) => {
4506
+ setMobileFlow(true);
4507
+ setDeeplinkUri(persisted.deeplinkUri);
4508
+ setSelectedProviderId(persisted.providerId);
4509
+ pollingTransferIdRef.current = persisted.transferId;
4510
+ mobileSetupFlowRef.current = persisted.isSetup;
4511
+ setError(errorMessage ?? null);
4512
+ setStep("open-wallet");
4513
+ polling.startPolling(persisted.transferId);
4514
+ }, [polling]);
4515
+ const handleAuthorizedMobileReturn = react.useCallback(async (authorizedTransfer, isSetup) => {
4516
+ setTransfer(authorizedTransfer);
4517
+ polling.stopPolling();
4518
+ if (isSetup) {
4519
+ mobileSetupFlowRef.current = false;
4520
+ clearMobileFlowState();
4521
+ try {
4522
+ await reloadAccounts();
4523
+ setError(null);
4524
+ setDeeplinkUri(null);
4525
+ setMobileFlow(false);
4526
+ setStep("deposit");
4527
+ } catch (err) {
4528
+ setError(
4529
+ err instanceof Error ? err.message : "Wallet authorized, but we could not refresh your account yet."
4530
+ );
4531
+ setStep("open-wallet");
4532
+ }
4533
+ return;
4534
+ }
4535
+ mobileSetupFlowRef.current = false;
4536
+ clearMobileFlowState();
4537
+ setError(null);
4538
+ setDeeplinkUri(null);
4539
+ setMobileFlow(false);
4540
+ setStep("confirm-sign");
4541
+ }, [polling.stopPolling, reloadAccounts]);
4542
+ const handleRetryMobileStatus = react.useCallback(() => {
4543
+ setError(null);
4544
+ const currentTransfer = polling.transfer ?? transfer;
4545
+ if (currentTransfer?.status === "AUTHORIZED") {
4546
+ void handleAuthorizedMobileReturn(currentTransfer, mobileSetupFlowRef.current);
4547
+ return;
4548
+ }
4549
+ const transferIdToResume = pollingTransferIdRef.current ?? currentTransfer?.id;
4550
+ if (transferIdToResume) {
4551
+ polling.startPolling(transferIdToResume);
4552
+ }
4553
+ }, [handleAuthorizedMobileReturn, polling, transfer]);
4562
4554
  react.useEffect(() => {
4563
4555
  if (depositAmount != null) {
4564
4556
  setAmount(depositAmount.toString());
@@ -4656,7 +4648,6 @@ function SwypePaymentInner({
4656
4648
  hasPasskey: true,
4657
4649
  accounts: accts,
4658
4650
  persistedMobileFlow: persisted,
4659
- mobileSetupInProgress: false,
4660
4651
  connectingNewAccount: false
4661
4652
  });
4662
4653
  if (resolved.clearPersistedFlow) {
@@ -4666,23 +4657,52 @@ function SwypePaymentInner({
4666
4657
  try {
4667
4658
  const existingTransfer = await fetchTransfer(apiBaseUrl, token, persisted.transferId);
4668
4659
  if (cancelled) return;
4669
- const terminalStatuses = ["AUTHORIZED", "COMPLETED", "FAILED"];
4670
- if (terminalStatuses.includes(existingTransfer.status)) {
4660
+ const mobileResolution = resolveRestoredMobileFlow(
4661
+ existingTransfer.status,
4662
+ persisted.isSetup
4663
+ );
4664
+ if (mobileResolution.kind === "resume-setup-deposit") {
4665
+ await handleAuthorizedMobileReturn(existingTransfer, true);
4666
+ return;
4667
+ }
4668
+ if (mobileResolution.kind === "resume-confirm-sign") {
4669
+ await handleAuthorizedMobileReturn(existingTransfer, false);
4670
+ return;
4671
+ }
4672
+ if (mobileResolution.kind === "resume-success") {
4671
4673
  clearMobileFlowState();
4672
- setStep("deposit");
4674
+ setMobileFlow(false);
4675
+ setDeeplinkUri(null);
4676
+ setTransfer(existingTransfer);
4677
+ setError(null);
4678
+ setStep("success");
4679
+ onComplete?.(existingTransfer);
4673
4680
  return;
4674
4681
  }
4675
- } catch {
4676
- clearMobileFlowState();
4677
- setStep("deposit");
4682
+ if (mobileResolution.kind === "resume-failed") {
4683
+ clearMobileFlowState();
4684
+ setMobileFlow(false);
4685
+ setDeeplinkUri(null);
4686
+ setTransfer(existingTransfer);
4687
+ setError("Transfer failed.");
4688
+ setStep("success");
4689
+ return;
4690
+ }
4691
+ if (mobileResolution.kind === "resume-stale-setup") {
4692
+ clearMobileFlowState();
4693
+ if (!cancelled) setStep("wallet-picker");
4694
+ return;
4695
+ }
4696
+ } catch (err) {
4697
+ if (cancelled) return;
4698
+ enterPersistedMobileFlow(
4699
+ persisted,
4700
+ err instanceof Error ? err.message : "Unable to refresh wallet authorization status."
4701
+ );
4678
4702
  return;
4679
4703
  }
4680
- setMobileFlow(true);
4681
- setDeeplinkUri(persisted.deeplinkUri);
4682
- setSelectedProviderId(persisted.providerId);
4683
- pollingTransferIdRef.current = persisted.transferId;
4684
- mobileSetupFlowRef.current = persisted.isSetup;
4685
- polling.startPolling(persisted.transferId);
4704
+ enterPersistedMobileFlow(persisted);
4705
+ return;
4686
4706
  }
4687
4707
  setStep(resolved.step);
4688
4708
  };
@@ -4723,7 +4743,18 @@ function SwypePaymentInner({
4723
4743
  return () => {
4724
4744
  cancelled = true;
4725
4745
  };
4726
- }, [ready, authenticated, step, apiBaseUrl, getAccessToken, activeCredentialId, resetHeadlessLogin]);
4746
+ }, [
4747
+ ready,
4748
+ authenticated,
4749
+ step,
4750
+ apiBaseUrl,
4751
+ getAccessToken,
4752
+ activeCredentialId,
4753
+ resetHeadlessLogin,
4754
+ enterPersistedMobileFlow,
4755
+ handleAuthorizedMobileReturn,
4756
+ onComplete
4757
+ ]);
4727
4758
  const loadingDataRef = react.useRef(false);
4728
4759
  react.useEffect(() => {
4729
4760
  if (!authenticated) return;
@@ -4833,22 +4864,8 @@ function SwypePaymentInner({
4833
4864
  if (!mobileFlow) return;
4834
4865
  const polledTransfer = polling.transfer;
4835
4866
  if (!polledTransfer || polledTransfer.status !== "AUTHORIZED") return;
4836
- if (mobileSetupFlowRef.current) {
4837
- mobileSetupFlowRef.current = false;
4838
- clearMobileFlowState();
4839
- setDeeplinkUri(null);
4840
- polling.stopPolling();
4841
- setTransfer(polledTransfer);
4842
- reloadAccounts().catch(() => {
4843
- }).then(() => {
4844
- setMobileFlow(false);
4845
- setStep("deposit");
4846
- });
4847
- return;
4848
- }
4849
- setTransfer(polledTransfer);
4850
- setStep("confirm-sign");
4851
- }, [mobileFlow, polling.transfer, polling.stopPolling, transferSigning, onError, reloadAccounts]);
4867
+ void handleAuthorizedMobileReturn(polledTransfer, mobileSetupFlowRef.current);
4868
+ }, [mobileFlow, polling.transfer, handleAuthorizedMobileReturn]);
4852
4869
  react.useEffect(() => {
4853
4870
  if (!mobileFlow) return;
4854
4871
  const transferIdToResume = pollingTransferIdRef.current ?? transfer?.id;
@@ -5290,6 +5307,8 @@ function SwypePaymentInner({
5290
5307
  walletName: providerName,
5291
5308
  deeplinkUri: deeplinkUri ?? "",
5292
5309
  loading: creatingTransfer || !deeplinkUri,
5310
+ error: error || polling.error,
5311
+ onRetryStatus: handleRetryMobileStatus,
5293
5312
  onLogout: handleLogout
5294
5313
  }
5295
5314
  );