@swype-org/react-sdk 0.1.69 → 0.1.71

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
@@ -1615,6 +1615,9 @@ function resolvePostAuthStep(state) {
1615
1615
  }
1616
1616
  return { step: "open-wallet", clearPersistedFlow: false };
1617
1617
  }
1618
+ if (state.mobileSetupInProgress && !hasActiveWallet(state.accounts)) {
1619
+ return { step: "open-wallet", clearPersistedFlow: false };
1620
+ }
1618
1621
  if ((state.accounts.length === 0 || !hasActiveWallet(state.accounts)) && !state.connectingNewAccount) {
1619
1622
  return { step: "wallet-picker", clearPersistedFlow: false };
1620
1623
  }
@@ -1630,11 +1633,31 @@ function resolveRestoredMobileFlow(transferStatus, isSetup) {
1630
1633
  if (transferStatus === "FAILED") {
1631
1634
  return { kind: "resume-failed", step: "success", clearPersistedFlow: true };
1632
1635
  }
1636
+ if (transferStatus === "SENDING" || transferStatus === "SENT") {
1637
+ return { kind: "resume-processing", step: "processing", clearPersistedFlow: true };
1638
+ }
1633
1639
  if (isSetup) {
1634
1640
  return { kind: "resume-stale-setup", step: "wallet-picker", clearPersistedFlow: true };
1635
1641
  }
1636
1642
  return { kind: "resume-open-wallet", step: "open-wallet", clearPersistedFlow: false };
1637
1643
  }
1644
+
1645
+ // src/dataLoading.ts
1646
+ function resolveDataLoadAction({
1647
+ authenticated,
1648
+ step,
1649
+ accountsCount,
1650
+ hasActiveCredential,
1651
+ loading
1652
+ }) {
1653
+ if (!authenticated || step === "login" || step === "otp-verify" || accountsCount > 0 || !hasActiveCredential) {
1654
+ return "reset";
1655
+ }
1656
+ if (loading) {
1657
+ return "wait";
1658
+ }
1659
+ return "load";
1660
+ }
1638
1661
  var FOOTER_CSS = `
1639
1662
  .swype-screen-footer {
1640
1663
  padding-bottom: max(24px, env(safe-area-inset-bottom, 24px));
@@ -3421,6 +3444,8 @@ var outlineBtnWrapStyle = {
3421
3444
  function SuccessScreen({
3422
3445
  amount,
3423
3446
  currency,
3447
+ succeeded,
3448
+ error,
3424
3449
  merchantName,
3425
3450
  sourceName,
3426
3451
  remainingLimit,
@@ -3431,7 +3456,8 @@ function SuccessScreen({
3431
3456
  autoCloseSeconds
3432
3457
  }) {
3433
3458
  const { tokens } = useSwypeConfig();
3434
- const [countdown, setCountdown] = useState(autoCloseSeconds ?? 0);
3459
+ const effectiveAutoClose = succeeded ? autoCloseSeconds : void 0;
3460
+ const [countdown, setCountdown] = useState(effectiveAutoClose ?? 0);
3435
3461
  const doneCalledRef = useRef(false);
3436
3462
  const handleDone = useCallback(() => {
3437
3463
  if (doneCalledRef.current) return;
@@ -3439,7 +3465,7 @@ function SuccessScreen({
3439
3465
  onDone();
3440
3466
  }, [onDone]);
3441
3467
  useEffect(() => {
3442
- if (!autoCloseSeconds || autoCloseSeconds <= 0) return;
3468
+ if (!effectiveAutoClose || effectiveAutoClose <= 0) return;
3443
3469
  const intervalId = window.setInterval(() => {
3444
3470
  setCountdown((prev) => {
3445
3471
  if (prev <= 1) {
@@ -3450,18 +3476,18 @@ function SuccessScreen({
3450
3476
  });
3451
3477
  }, 1e3);
3452
3478
  return () => window.clearInterval(intervalId);
3453
- }, [autoCloseSeconds]);
3479
+ }, [effectiveAutoClose]);
3454
3480
  useEffect(() => {
3455
- if (autoCloseSeconds && countdown === 0) {
3481
+ if (effectiveAutoClose && countdown === 0) {
3456
3482
  handleDone();
3457
3483
  }
3458
- }, [autoCloseSeconds, countdown, handleDone]);
3484
+ }, [effectiveAutoClose, countdown, handleDone]);
3459
3485
  return /* @__PURE__ */ jsxs(
3460
3486
  ScreenLayout,
3461
3487
  {
3462
3488
  footer: /* @__PURE__ */ jsxs(Fragment, { children: [
3463
- /* @__PURE__ */ jsx(PrimaryButton, { onClick: handleDone, children: "Done" }),
3464
- autoCloseSeconds != null && autoCloseSeconds > 0 && /* @__PURE__ */ jsxs("p", { style: countdownStyle(tokens.textMuted), children: [
3489
+ /* @__PURE__ */ jsx(PrimaryButton, { onClick: handleDone, children: succeeded ? "Done" : "Try again" }),
3490
+ effectiveAutoClose != null && effectiveAutoClose > 0 && /* @__PURE__ */ jsxs("p", { style: countdownStyle(tokens.textMuted), children: [
3465
3491
  "Returning to app in ",
3466
3492
  countdown,
3467
3493
  "s\u2026"
@@ -3477,26 +3503,32 @@ function SuccessScreen({
3477
3503
  }
3478
3504
  ),
3479
3505
  /* @__PURE__ */ jsxs("div", { style: contentStyle4, children: [
3480
- /* @__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 }) }) }),
3481
- /* @__PURE__ */ jsxs("h2", { style: headingStyle6(tokens.text), children: [
3482
- "$",
3483
- amount.toFixed(2),
3484
- " deposited"
3485
- ] }),
3486
- merchantName && /* @__PURE__ */ jsxs("p", { style: subtitleStyle6(tokens.textSecondary), children: [
3487
- "to ",
3488
- merchantName
3506
+ succeeded ? /* @__PURE__ */ jsxs(Fragment, { children: [
3507
+ /* @__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 }) }) }),
3508
+ /* @__PURE__ */ jsxs("h2", { style: headingStyle6(tokens.text), children: [
3509
+ "$",
3510
+ amount.toFixed(2),
3511
+ " deposited"
3512
+ ] }),
3513
+ merchantName && /* @__PURE__ */ jsxs("p", { style: subtitleStyle6(tokens.textSecondary), children: [
3514
+ "to ",
3515
+ merchantName
3516
+ ] })
3517
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
3518
+ /* @__PURE__ */ jsx(IconCircle, { variant: "error", size: 64, children: /* @__PURE__ */ jsx("svg", { width: "32", height: "32", viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ jsx("path", { d: "M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z", fill: tokens.error }) }) }),
3519
+ /* @__PURE__ */ jsx("h2", { style: headingStyle6(tokens.text), children: "Transfer failed" }),
3520
+ error && /* @__PURE__ */ jsx("p", { style: subtitleStyle6(tokens.error), children: error })
3489
3521
  ] }),
3490
3522
  /* @__PURE__ */ jsxs("div", { style: summaryCardStyle(tokens), children: [
3491
3523
  sourceName && /* @__PURE__ */ jsxs("div", { style: summaryRowStyle, children: [
3492
3524
  /* @__PURE__ */ jsx("span", { style: summaryLabelStyle(tokens.textMuted), children: "From" }),
3493
3525
  /* @__PURE__ */ jsx("span", { style: summaryValueStyle(tokens.text), children: sourceName })
3494
3526
  ] }),
3495
- /* @__PURE__ */ jsxs("div", { style: summaryRowStyle, children: [
3527
+ succeeded && /* @__PURE__ */ jsxs("div", { style: summaryRowStyle, children: [
3496
3528
  /* @__PURE__ */ jsx("span", { style: summaryLabelStyle(tokens.textMuted), children: "Time" }),
3497
3529
  /* @__PURE__ */ jsx("span", { style: summaryValueStyle(tokens.text), children: "just now" })
3498
3530
  ] }),
3499
- remainingLimit != null && /* @__PURE__ */ jsxs("div", { style: summaryRowStyle, children: [
3531
+ succeeded && remainingLimit != null && /* @__PURE__ */ jsxs("div", { style: summaryRowStyle, children: [
3500
3532
  /* @__PURE__ */ jsx("span", { style: summaryLabelStyle(tokens.textMuted), children: "Remaining limit" }),
3501
3533
  /* @__PURE__ */ jsxs("span", { style: { ...summaryValueStyle(tokens.text), color: tokens.accent }, children: [
3502
3534
  "$",
@@ -3504,7 +3536,7 @@ function SuccessScreen({
3504
3536
  ] })
3505
3537
  ] })
3506
3538
  ] }),
3507
- onIncreaseLimits && /* @__PURE__ */ jsxs("div", { style: upsellCardStyle(tokens), children: [
3539
+ succeeded && onIncreaseLimits && /* @__PURE__ */ jsxs("div", { style: upsellCardStyle(tokens), children: [
3508
3540
  /* @__PURE__ */ jsxs("div", { style: upsellHeaderStyle, children: [
3509
3541
  /* @__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" }) }),
3510
3542
  /* @__PURE__ */ jsx("strong", { children: "Want higher limits?" })
@@ -3986,12 +4018,11 @@ var radioDotStyle2 = (color) => ({
3986
4018
  borderRadius: "50%",
3987
4019
  background: color
3988
4020
  });
3989
- var STEP_LABELS = ["Creating transfer", "Verifying", "Sent", "Done"];
4021
+ var STEP_LABELS = ["Creating transfer", "Verifying", "Sent"];
3990
4022
  var PHASE_ACTIVE_INDEX = {
3991
4023
  creating: 0,
3992
4024
  verifying: 1,
3993
- sent: 2,
3994
- done: 4
4025
+ sent: 2
3995
4026
  };
3996
4027
  function buildSteps(phase) {
3997
4028
  const activeIdx = PHASE_ACTIVE_INDEX[phase];
@@ -4469,6 +4500,7 @@ function SwypePaymentInner({
4469
4500
  const [oneTapLimit, setOneTapLimit] = useState(100);
4470
4501
  const [mobileFlow, setMobileFlow] = useState(false);
4471
4502
  const [deeplinkUri, setDeeplinkUri] = useState(null);
4503
+ const loadingDataRef = useRef(false);
4472
4504
  const pollingTransferIdRef = useRef(null);
4473
4505
  const mobileSigningTransferIdRef = useRef(null);
4474
4506
  const mobileSetupFlowRef = useRef(false);
@@ -4499,6 +4531,10 @@ function SwypePaymentInner({
4499
4531
  setConnectingNewAccount(false);
4500
4532
  }
4501
4533
  }, [getAccessToken, activeCredentialId, apiBaseUrl, depositAmount]);
4534
+ const resetDataLoadingState = useCallback(() => {
4535
+ loadingDataRef.current = false;
4536
+ setLoadingData(false);
4537
+ }, []);
4502
4538
  const enterPersistedMobileFlow = useCallback((persisted, errorMessage) => {
4503
4539
  setMobileFlow(true);
4504
4540
  setDeeplinkUri(persisted.deeplinkUri);
@@ -4516,6 +4552,7 @@ function SwypePaymentInner({
4516
4552
  clearMobileFlowState();
4517
4553
  try {
4518
4554
  await reloadAccounts();
4555
+ resetDataLoadingState();
4519
4556
  setTransfer(null);
4520
4557
  setError(null);
4521
4558
  setDeeplinkUri(null);
@@ -4536,7 +4573,7 @@ function SwypePaymentInner({
4536
4573
  setDeeplinkUri(null);
4537
4574
  setMobileFlow(false);
4538
4575
  setStep("confirm-sign");
4539
- }, [polling.stopPolling, reloadAccounts]);
4576
+ }, [polling.stopPolling, reloadAccounts, resetDataLoadingState]);
4540
4577
  const handleRetryMobileStatus = useCallback(() => {
4541
4578
  setError(null);
4542
4579
  const currentTransfer = polling.transfer ?? transfer;
@@ -4646,6 +4683,7 @@ function SwypePaymentInner({
4646
4683
  hasPasskey: true,
4647
4684
  accounts: accts,
4648
4685
  persistedMobileFlow: persisted,
4686
+ mobileSetupInProgress: false,
4649
4687
  connectingNewAccount: false
4650
4688
  });
4651
4689
  if (resolved.clearPersistedFlow) {
@@ -4686,6 +4724,16 @@ function SwypePaymentInner({
4686
4724
  setStep("success");
4687
4725
  return;
4688
4726
  }
4727
+ if (mobileResolution.kind === "resume-processing") {
4728
+ clearMobileFlowState();
4729
+ setMobileFlow(false);
4730
+ setDeeplinkUri(null);
4731
+ setTransfer(existingTransfer);
4732
+ setError(null);
4733
+ setStep("processing");
4734
+ polling.startPolling(existingTransfer.id);
4735
+ return;
4736
+ }
4689
4737
  if (mobileResolution.kind === "resume-stale-setup") {
4690
4738
  clearMobileFlowState();
4691
4739
  if (!cancelled) setStep("wallet-picker");
@@ -4753,12 +4801,26 @@ function SwypePaymentInner({
4753
4801
  handleAuthorizedMobileReturn,
4754
4802
  onComplete
4755
4803
  ]);
4756
- const loadingDataRef = useRef(false);
4757
4804
  useEffect(() => {
4758
- if (!authenticated) return;
4759
- if (step === "login" || step === "otp-verify") return;
4760
- if (accounts.length > 0 || loadingDataRef.current) return;
4761
- if (!activeCredentialId) return;
4805
+ const loadAction = resolveDataLoadAction({
4806
+ authenticated,
4807
+ step,
4808
+ accountsCount: accounts.length,
4809
+ hasActiveCredential: !!activeCredentialId,
4810
+ loading: loadingDataRef.current
4811
+ });
4812
+ if (loadAction === "reset") {
4813
+ resetDataLoadingState();
4814
+ return;
4815
+ }
4816
+ if (loadAction === "wait") {
4817
+ return;
4818
+ }
4819
+ const credentialId = activeCredentialId;
4820
+ if (!credentialId) {
4821
+ resetDataLoadingState();
4822
+ return;
4823
+ }
4762
4824
  let cancelled = false;
4763
4825
  loadingDataRef.current = true;
4764
4826
  const load = async () => {
@@ -4769,7 +4831,7 @@ function SwypePaymentInner({
4769
4831
  if (!token) throw new Error("Not authenticated");
4770
4832
  const [prov, accts, chn] = await Promise.all([
4771
4833
  fetchProviders(apiBaseUrl, token),
4772
- fetchAccounts(apiBaseUrl, token, activeCredentialId),
4834
+ fetchAccounts(apiBaseUrl, token, credentialId),
4773
4835
  fetchChains(apiBaseUrl, token)
4774
4836
  ]);
4775
4837
  if (cancelled) return;
@@ -4807,8 +4869,7 @@ function SwypePaymentInner({
4807
4869
  }
4808
4870
  } finally {
4809
4871
  if (!cancelled) {
4810
- setLoadingData(false);
4811
- loadingDataRef.current = false;
4872
+ resetDataLoadingState();
4812
4873
  }
4813
4874
  }
4814
4875
  };
@@ -4817,7 +4878,7 @@ function SwypePaymentInner({
4817
4878
  cancelled = true;
4818
4879
  loadingDataRef.current = false;
4819
4880
  };
4820
- }, [authenticated, step, accounts.length, apiBaseUrl, getAccessToken, activeCredentialId, depositAmount, connectingNewAccount]);
4881
+ }, [authenticated, step, accounts.length, apiBaseUrl, getAccessToken, activeCredentialId, depositAmount, connectingNewAccount, resetDataLoadingState]);
4821
4882
  useEffect(() => {
4822
4883
  if (!polling.transfer) return;
4823
4884
  if (polling.transfer.status === "COMPLETED") {
@@ -5182,6 +5243,7 @@ function SwypePaymentInner({
5182
5243
  processingStartedAtRef.current = null;
5183
5244
  pollingTransferIdRef.current = null;
5184
5245
  mobileSigningTransferIdRef.current = null;
5246
+ preSelectSourceStepRef.current = null;
5185
5247
  setConnectingNewAccount(false);
5186
5248
  setSelectedWalletId(null);
5187
5249
  if (accounts.length > 0) setSelectedAccountId(accounts[0].id);
@@ -5212,6 +5274,7 @@ function SwypePaymentInner({
5212
5274
  setAmount(depositAmount != null ? depositAmount.toString() : "");
5213
5275
  setMobileFlow(false);
5214
5276
  setDeeplinkUri(null);
5277
+ preSelectSourceStepRef.current = null;
5215
5278
  resetHeadlessLogin();
5216
5279
  }, [logout, polling, depositAmount, resetHeadlessLogin]);
5217
5280
  const handleConfirmSign = useCallback(async () => {
@@ -5222,12 +5285,13 @@ function SwypePaymentInner({
5222
5285
  setTransfer(signedTransfer);
5223
5286
  clearMobileFlowState();
5224
5287
  setStep("processing");
5288
+ polling.startPolling(t.id);
5225
5289
  } catch (err) {
5226
5290
  const msg = err instanceof Error ? err.message : "Failed to sign transfer";
5227
5291
  setError(msg);
5228
5292
  onError?.(msg);
5229
5293
  }
5230
- }, [transfer, polling.transfer, transferSigning, onError]);
5294
+ }, [transfer, polling.transfer, polling.startPolling, transferSigning, onError]);
5231
5295
  if (!ready) {
5232
5296
  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..." }) }) });
5233
5297
  }
@@ -5352,7 +5416,7 @@ function SwypePaymentInner({
5352
5416
  }
5353
5417
  if (step === "processing") {
5354
5418
  const polledStatus = polling.transfer?.status;
5355
- const transferPhase = creatingTransfer ? "creating" : mobileFlow || authExecutor.executing || transferSigning.signing ? "verifying" : polledStatus === "SENDING" || polledStatus === "SENT" || polling.isPolling ? "sent" : "creating";
5419
+ const transferPhase = creatingTransfer ? "creating" : polledStatus === "SENDING" || polledStatus === "SENT" ? "sent" : "verifying";
5356
5420
  return /* @__PURE__ */ jsx(
5357
5421
  TransferStatusScreen,
5358
5422
  {
@@ -5383,7 +5447,7 @@ function SwypePaymentInner({
5383
5447
  );
5384
5448
  }
5385
5449
  if (step === "success") {
5386
- transfer?.status === "COMPLETED";
5450
+ const succeeded = transfer?.status === "COMPLETED";
5387
5451
  const displayAmount = transfer?.amount?.amount ?? 0;
5388
5452
  const displayCurrency = transfer?.amount?.currency ?? "USD";
5389
5453
  return /* @__PURE__ */ jsx(
@@ -5391,12 +5455,14 @@ function SwypePaymentInner({
5391
5455
  {
5392
5456
  amount: displayAmount,
5393
5457
  currency: displayCurrency,
5458
+ succeeded,
5459
+ error,
5394
5460
  merchantName,
5395
5461
  sourceName,
5396
- remainingLimit: (() => {
5462
+ remainingLimit: succeeded ? (() => {
5397
5463
  const limit = selectedAccount?.remainingAllowance ?? oneTapLimit;
5398
5464
  return limit > displayAmount ? limit - displayAmount : 0;
5399
- })(),
5465
+ })() : void 0,
5400
5466
  onDone: onDismiss ?? handleNewPayment,
5401
5467
  onLogout: handleLogout,
5402
5468
  autoCloseSeconds