@swype-org/react-sdk 0.1.63 → 0.1.67
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 +284 -216
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +284 -216
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -654,6 +654,24 @@ function normalizeSignature(sig) {
|
|
|
654
654
|
);
|
|
655
655
|
}
|
|
656
656
|
|
|
657
|
+
// src/transferPolling.ts
|
|
658
|
+
async function pollTransferTick(params) {
|
|
659
|
+
const fetchTransfer2 = params.fetchTransfer ?? fetchTransfer;
|
|
660
|
+
const token = await params.getAccessToken();
|
|
661
|
+
if (!token) {
|
|
662
|
+
return { kind: "retry" };
|
|
663
|
+
}
|
|
664
|
+
try {
|
|
665
|
+
const transfer = await fetchTransfer2(params.apiBaseUrl, token, params.transferId);
|
|
666
|
+
return { kind: "success", transfer };
|
|
667
|
+
} catch (err) {
|
|
668
|
+
return {
|
|
669
|
+
kind: "error",
|
|
670
|
+
message: err instanceof Error ? err.message : "Polling error"
|
|
671
|
+
};
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
|
|
657
675
|
// src/passkey-delegation.ts
|
|
658
676
|
var PasskeyIframeBlockedError = class extends Error {
|
|
659
677
|
constructor(message = "Passkey creation is not supported in this browser context.") {
|
|
@@ -956,20 +974,22 @@ function useTransferPolling(intervalMs = 3e3) {
|
|
|
956
974
|
}, []);
|
|
957
975
|
const poll = useCallback(async () => {
|
|
958
976
|
if (!transferIdRef.current) return;
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
}
|
|
972
|
-
|
|
977
|
+
const result = await pollTransferTick({
|
|
978
|
+
apiBaseUrl,
|
|
979
|
+
transferId: transferIdRef.current,
|
|
980
|
+
getAccessToken
|
|
981
|
+
});
|
|
982
|
+
if (result.kind === "retry") {
|
|
983
|
+
return;
|
|
984
|
+
}
|
|
985
|
+
if (result.kind === "error") {
|
|
986
|
+
setError(result.message);
|
|
987
|
+
stopPolling();
|
|
988
|
+
return;
|
|
989
|
+
}
|
|
990
|
+
setError(null);
|
|
991
|
+
setTransfer(result.transfer);
|
|
992
|
+
if (result.transfer.status === "COMPLETED" || result.transfer.status === "FAILED") {
|
|
973
993
|
stopPolling();
|
|
974
994
|
}
|
|
975
995
|
}, [apiBaseUrl, getAccessToken, stopPolling]);
|
|
@@ -1580,6 +1600,35 @@ function isMobileUserAgent(userAgent) {
|
|
|
1580
1600
|
function shouldUseWalletConnector(options) {
|
|
1581
1601
|
return options.useWalletConnector ?? !isMobileUserAgent(options.userAgent);
|
|
1582
1602
|
}
|
|
1603
|
+
|
|
1604
|
+
// src/mobileFlow.ts
|
|
1605
|
+
function hasActiveWallet(accounts) {
|
|
1606
|
+
return accounts.some((account) => account.wallets.some((wallet) => wallet.status === "ACTIVE"));
|
|
1607
|
+
}
|
|
1608
|
+
function resolvePostAuthStep(state) {
|
|
1609
|
+
if (!state.hasPasskey) {
|
|
1610
|
+
return { step: "create-passkey", clearPersistedFlow: false };
|
|
1611
|
+
}
|
|
1612
|
+
if (state.persistedMobileFlow) {
|
|
1613
|
+
return { step: "open-wallet", clearPersistedFlow: false };
|
|
1614
|
+
}
|
|
1615
|
+
if ((state.accounts.length === 0 || !hasActiveWallet(state.accounts)) && !state.connectingNewAccount) {
|
|
1616
|
+
return { step: "wallet-picker", clearPersistedFlow: false };
|
|
1617
|
+
}
|
|
1618
|
+
return { step: "deposit", clearPersistedFlow: false };
|
|
1619
|
+
}
|
|
1620
|
+
function resolveRestoredMobileFlow(transferStatus, isSetup) {
|
|
1621
|
+
if (transferStatus === "AUTHORIZED") {
|
|
1622
|
+
return isSetup ? { kind: "resume-setup-deposit", step: "deposit", clearPersistedFlow: true } : { kind: "resume-confirm-sign", step: "confirm-sign", clearPersistedFlow: true };
|
|
1623
|
+
}
|
|
1624
|
+
if (transferStatus === "COMPLETED") {
|
|
1625
|
+
return { kind: "resume-success", step: "success", clearPersistedFlow: true };
|
|
1626
|
+
}
|
|
1627
|
+
if (transferStatus === "FAILED") {
|
|
1628
|
+
return { kind: "resume-failed", step: "success", clearPersistedFlow: true };
|
|
1629
|
+
}
|
|
1630
|
+
return { kind: "resume-open-wallet", step: "open-wallet", clearPersistedFlow: false };
|
|
1631
|
+
}
|
|
1583
1632
|
var FOOTER_CSS = `
|
|
1584
1633
|
.swype-screen-footer {
|
|
1585
1634
|
padding-bottom: max(24px, env(safe-area-inset-bottom, 24px));
|
|
@@ -1908,137 +1957,6 @@ var inputStyle = (tokens, filled) => ({
|
|
|
1908
1957
|
caretColor: tokens.borderFocus,
|
|
1909
1958
|
transition: "border-color 0.15s ease"
|
|
1910
1959
|
});
|
|
1911
|
-
function LimitSlider({
|
|
1912
|
-
value,
|
|
1913
|
-
min,
|
|
1914
|
-
max,
|
|
1915
|
-
step = 1,
|
|
1916
|
-
onChange,
|
|
1917
|
-
ticks,
|
|
1918
|
-
disabled
|
|
1919
|
-
}) {
|
|
1920
|
-
const { tokens } = useSwypeConfig();
|
|
1921
|
-
const pct = (value - min) / (max - min) * 100;
|
|
1922
|
-
const handleChange = useCallback(
|
|
1923
|
-
(e) => onChange(Number(e.target.value)),
|
|
1924
|
-
[onChange]
|
|
1925
|
-
);
|
|
1926
|
-
return /* @__PURE__ */ jsxs("div", { className: "swype-slider-wrap", style: wrapperStyle, children: [
|
|
1927
|
-
/* @__PURE__ */ jsxs("div", { style: trackContainerStyle, children: [
|
|
1928
|
-
/* @__PURE__ */ jsx("div", { style: trackBgStyle(tokens.border) }),
|
|
1929
|
-
/* @__PURE__ */ jsx("div", { style: trackFillStyle(tokens.accent, pct) }),
|
|
1930
|
-
/* @__PURE__ */ jsx(
|
|
1931
|
-
"input",
|
|
1932
|
-
{
|
|
1933
|
-
type: "range",
|
|
1934
|
-
min,
|
|
1935
|
-
max,
|
|
1936
|
-
step,
|
|
1937
|
-
value,
|
|
1938
|
-
onChange: handleChange,
|
|
1939
|
-
disabled,
|
|
1940
|
-
style: rangeInputStyle
|
|
1941
|
-
}
|
|
1942
|
-
)
|
|
1943
|
-
] }),
|
|
1944
|
-
ticks && ticks.length > 0 && /* @__PURE__ */ jsx("div", { style: ticksStyle, children: ticks.map((tick, i) => {
|
|
1945
|
-
const pctPos = (tick - min) / (max - min) * 100;
|
|
1946
|
-
const isFirst = i === 0;
|
|
1947
|
-
const isLast = i === ticks.length - 1;
|
|
1948
|
-
const label = tick % 1 === 0 ? `$${tick}` : `$${tick.toFixed(2)}`;
|
|
1949
|
-
return /* @__PURE__ */ jsx(
|
|
1950
|
-
"span",
|
|
1951
|
-
{
|
|
1952
|
-
style: tickLabelStyle(tokens.textMuted, pctPos, isFirst, isLast),
|
|
1953
|
-
children: label
|
|
1954
|
-
},
|
|
1955
|
-
tick
|
|
1956
|
-
);
|
|
1957
|
-
}) }),
|
|
1958
|
-
/* @__PURE__ */ jsx("style", { children: sliderThumbCss(tokens.accent) })
|
|
1959
|
-
] });
|
|
1960
|
-
}
|
|
1961
|
-
var wrapperStyle = { width: "100%" };
|
|
1962
|
-
var trackContainerStyle = {
|
|
1963
|
-
position: "relative",
|
|
1964
|
-
height: 28,
|
|
1965
|
-
display: "flex",
|
|
1966
|
-
alignItems: "center"
|
|
1967
|
-
};
|
|
1968
|
-
var trackBgStyle = (color) => ({
|
|
1969
|
-
position: "absolute",
|
|
1970
|
-
left: 0,
|
|
1971
|
-
right: 0,
|
|
1972
|
-
height: 4,
|
|
1973
|
-
borderRadius: 2,
|
|
1974
|
-
background: color
|
|
1975
|
-
});
|
|
1976
|
-
var trackFillStyle = (color, pct) => ({
|
|
1977
|
-
position: "absolute",
|
|
1978
|
-
left: 0,
|
|
1979
|
-
width: `${pct}%`,
|
|
1980
|
-
height: 4,
|
|
1981
|
-
borderRadius: 2,
|
|
1982
|
-
background: color
|
|
1983
|
-
});
|
|
1984
|
-
var rangeInputStyle = {
|
|
1985
|
-
position: "absolute",
|
|
1986
|
-
left: 0,
|
|
1987
|
-
right: 0,
|
|
1988
|
-
width: "100%",
|
|
1989
|
-
height: 28,
|
|
1990
|
-
margin: 0,
|
|
1991
|
-
cursor: "pointer",
|
|
1992
|
-
zIndex: 2,
|
|
1993
|
-
WebkitAppearance: "none",
|
|
1994
|
-
appearance: "none",
|
|
1995
|
-
background: "transparent"
|
|
1996
|
-
};
|
|
1997
|
-
var ticksStyle = {
|
|
1998
|
-
position: "relative",
|
|
1999
|
-
height: 18,
|
|
2000
|
-
marginTop: 6
|
|
2001
|
-
};
|
|
2002
|
-
var tickLabelStyle = (color, pct, isFirst, isLast) => ({
|
|
2003
|
-
position: "absolute",
|
|
2004
|
-
left: `${pct}%`,
|
|
2005
|
-
transform: isFirst ? "none" : isLast ? "translateX(-100%)" : "translateX(-50%)",
|
|
2006
|
-
fontSize: "0.72rem",
|
|
2007
|
-
fontWeight: 500,
|
|
2008
|
-
color,
|
|
2009
|
-
whiteSpace: "nowrap"
|
|
2010
|
-
});
|
|
2011
|
-
var sliderThumbCss = (accent) => `
|
|
2012
|
-
.swype-slider-wrap input[type="range"]::-webkit-slider-runnable-track {
|
|
2013
|
-
height: 4px;
|
|
2014
|
-
background: transparent;
|
|
2015
|
-
}
|
|
2016
|
-
.swype-slider-wrap input[type="range"]::-webkit-slider-thumb {
|
|
2017
|
-
-webkit-appearance: none;
|
|
2018
|
-
width: 20px;
|
|
2019
|
-
height: 20px;
|
|
2020
|
-
border-radius: 50%;
|
|
2021
|
-
background: ${accent};
|
|
2022
|
-
border: 3px solid #fff;
|
|
2023
|
-
box-shadow: 0 2px 6px rgba(0,0,0,0.15);
|
|
2024
|
-
cursor: pointer;
|
|
2025
|
-
margin-top: -8px;
|
|
2026
|
-
}
|
|
2027
|
-
.swype-slider-wrap input[type="range"]::-moz-range-track {
|
|
2028
|
-
height: 4px;
|
|
2029
|
-
background: transparent;
|
|
2030
|
-
border: none;
|
|
2031
|
-
}
|
|
2032
|
-
.swype-slider-wrap input[type="range"]::-moz-range-thumb {
|
|
2033
|
-
width: 14px;
|
|
2034
|
-
height: 14px;
|
|
2035
|
-
border-radius: 50%;
|
|
2036
|
-
background: ${accent};
|
|
2037
|
-
border: 3px solid #fff;
|
|
2038
|
-
box-shadow: 0 2px 6px rgba(0,0,0,0.15);
|
|
2039
|
-
cursor: pointer;
|
|
2040
|
-
}
|
|
2041
|
-
`;
|
|
2042
1960
|
|
|
2043
1961
|
// src/assets/logos.ts
|
|
2044
1962
|
function svgToDataUri(svg) {
|
|
@@ -3000,18 +2918,6 @@ var dividerTextStyle = (color) => ({
|
|
|
3000
2918
|
});
|
|
3001
2919
|
var DEFAULT_MAX = 500;
|
|
3002
2920
|
var ABSOLUTE_MIN = 1;
|
|
3003
|
-
function buildTicks(min, max) {
|
|
3004
|
-
if (max <= min) return [min];
|
|
3005
|
-
const range = max - min;
|
|
3006
|
-
const candidates = [1, 2, 5, 10, 25, 50, 100, 250];
|
|
3007
|
-
const step = candidates.find((s) => range / s <= 5) ?? Math.ceil(range / 4);
|
|
3008
|
-
const ticks = [];
|
|
3009
|
-
for (let v = min; v <= max; v += step) {
|
|
3010
|
-
ticks.push(Math.round(v * 100) / 100);
|
|
3011
|
-
}
|
|
3012
|
-
if (ticks[ticks.length - 1] !== max) ticks.push(max);
|
|
3013
|
-
return ticks;
|
|
3014
|
-
}
|
|
3015
2921
|
function SetupScreen({
|
|
3016
2922
|
availableBalance,
|
|
3017
2923
|
tokenCount,
|
|
@@ -3027,9 +2933,22 @@ function SetupScreen({
|
|
|
3027
2933
|
const { tokens } = useSwypeConfig();
|
|
3028
2934
|
const effectiveMax = Math.floor(Math.min(DEFAULT_MAX, availableBalance > 0 ? availableBalance : DEFAULT_MAX) * 100) / 100;
|
|
3029
2935
|
const effectiveMin = Math.min(ABSOLUTE_MIN, effectiveMax);
|
|
3030
|
-
const
|
|
3031
|
-
const
|
|
3032
|
-
const [
|
|
2936
|
+
const [limit, setLimit] = useState(() => effectiveMax);
|
|
2937
|
+
const [editing, setEditing] = useState(false);
|
|
2938
|
+
const [inputValue, setInputValue] = useState("");
|
|
2939
|
+
const inputRef = useRef(null);
|
|
2940
|
+
const startEditing = useCallback(() => {
|
|
2941
|
+
setInputValue(limit.toFixed(2));
|
|
2942
|
+
setEditing(true);
|
|
2943
|
+
requestAnimationFrame(() => inputRef.current?.select());
|
|
2944
|
+
}, [limit]);
|
|
2945
|
+
const commitEdit = useCallback(() => {
|
|
2946
|
+
const parsed = parseFloat(inputValue);
|
|
2947
|
+
if (!isNaN(parsed)) {
|
|
2948
|
+
setLimit(Math.min(effectiveMax, Math.max(effectiveMin, Math.round(parsed * 100) / 100)));
|
|
2949
|
+
}
|
|
2950
|
+
setEditing(false);
|
|
2951
|
+
}, [inputValue, effectiveMax, effectiveMin]);
|
|
3033
2952
|
return /* @__PURE__ */ jsxs(
|
|
3034
2953
|
ScreenLayout,
|
|
3035
2954
|
{
|
|
@@ -3085,19 +3004,33 @@ function SetupScreen({
|
|
|
3085
3004
|
] }),
|
|
3086
3005
|
/* @__PURE__ */ jsxs("div", { style: limitSectionStyle, children: [
|
|
3087
3006
|
/* @__PURE__ */ jsx("div", { style: limitLabelStyle(tokens.textMuted), children: "Your One-Tap limit" }),
|
|
3088
|
-
/* @__PURE__ */ jsxs("div", { style: limitValueStyle(tokens.text), children: [
|
|
3007
|
+
editing ? /* @__PURE__ */ jsxs("div", { style: limitValueStyle(tokens.text), children: [
|
|
3089
3008
|
"$",
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3009
|
+
/* @__PURE__ */ jsx(
|
|
3010
|
+
"input",
|
|
3011
|
+
{
|
|
3012
|
+
ref: inputRef,
|
|
3013
|
+
type: "text",
|
|
3014
|
+
inputMode: "decimal",
|
|
3015
|
+
pattern: "[0-9]*",
|
|
3016
|
+
value: inputValue,
|
|
3017
|
+
onChange: (e) => setInputValue(e.target.value),
|
|
3018
|
+
onBlur: commitEdit,
|
|
3019
|
+
onKeyDown: (e) => {
|
|
3020
|
+
if (e.key === "Enter") commitEdit();
|
|
3021
|
+
},
|
|
3022
|
+
style: limitInputStyle(tokens.text)
|
|
3023
|
+
}
|
|
3024
|
+
)
|
|
3025
|
+
] }) : /* @__PURE__ */ jsxs(
|
|
3026
|
+
"div",
|
|
3094
3027
|
{
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3028
|
+
style: { ...limitValueStyle(tokens.text), cursor: "pointer" },
|
|
3029
|
+
onClick: startEditing,
|
|
3030
|
+
children: [
|
|
3031
|
+
"$",
|
|
3032
|
+
limit.toFixed(2)
|
|
3033
|
+
]
|
|
3101
3034
|
}
|
|
3102
3035
|
)
|
|
3103
3036
|
] }),
|
|
@@ -3204,6 +3137,19 @@ var limitValueStyle = (color) => ({
|
|
|
3204
3137
|
color,
|
|
3205
3138
|
marginBottom: 12
|
|
3206
3139
|
});
|
|
3140
|
+
var limitInputStyle = (color) => ({
|
|
3141
|
+
fontSize: "2.2rem",
|
|
3142
|
+
fontWeight: 700,
|
|
3143
|
+
color,
|
|
3144
|
+
background: "transparent",
|
|
3145
|
+
border: "none",
|
|
3146
|
+
borderBottom: "2px solid currentColor",
|
|
3147
|
+
outline: "none",
|
|
3148
|
+
textAlign: "center",
|
|
3149
|
+
width: "5ch",
|
|
3150
|
+
fontFamily: "inherit",
|
|
3151
|
+
padding: 0
|
|
3152
|
+
});
|
|
3207
3153
|
var bannerWrapStyle = { marginBottom: 16 };
|
|
3208
3154
|
var linkStyle = (color) => ({
|
|
3209
3155
|
background: "transparent",
|
|
@@ -4109,6 +4055,8 @@ function OpenWalletScreen({
|
|
|
4109
4055
|
walletName,
|
|
4110
4056
|
deeplinkUri,
|
|
4111
4057
|
loading,
|
|
4058
|
+
error,
|
|
4059
|
+
onRetryStatus,
|
|
4112
4060
|
onLogout
|
|
4113
4061
|
}) {
|
|
4114
4062
|
const { tokens } = useSwypeConfig();
|
|
@@ -4129,12 +4077,14 @@ function OpenWalletScreen({
|
|
|
4129
4077
|
return /* @__PURE__ */ jsxs(
|
|
4130
4078
|
ScreenLayout,
|
|
4131
4079
|
{
|
|
4132
|
-
footer: /* @__PURE__ */ jsxs(
|
|
4080
|
+
footer: /* @__PURE__ */ jsxs("div", { style: footerContentStyle, children: [
|
|
4081
|
+
error && /* @__PURE__ */ jsx(InfoBanner, { children: error }),
|
|
4133
4082
|
!loading && /* @__PURE__ */ jsxs(PrimaryButton, { onClick: handleOpen, children: [
|
|
4134
4083
|
"Open ",
|
|
4135
4084
|
displayName
|
|
4136
4085
|
] }),
|
|
4137
|
-
/* @__PURE__ */ jsx(
|
|
4086
|
+
error && onRetryStatus && /* @__PURE__ */ jsx(OutlineButton, { onClick: onRetryStatus, children: "Retry status check" }),
|
|
4087
|
+
/* @__PURE__ */ 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" })
|
|
4138
4088
|
] }),
|
|
4139
4089
|
children: [
|
|
4140
4090
|
/* @__PURE__ */ jsx(ScreenHeader, { right: /* @__PURE__ */ jsx(SettingsMenu, { onLogout }) }),
|
|
@@ -4160,6 +4110,11 @@ var contentStyle6 = {
|
|
|
4160
4110
|
textAlign: "center",
|
|
4161
4111
|
padding: "0 24px"
|
|
4162
4112
|
};
|
|
4113
|
+
var footerContentStyle = {
|
|
4114
|
+
display: "flex",
|
|
4115
|
+
flexDirection: "column",
|
|
4116
|
+
gap: 12
|
|
4117
|
+
};
|
|
4163
4118
|
var logoStyle = {
|
|
4164
4119
|
width: 56,
|
|
4165
4120
|
height: 56,
|
|
@@ -4538,6 +4493,55 @@ function SwypePaymentInner({
|
|
|
4538
4493
|
setConnectingNewAccount(false);
|
|
4539
4494
|
}
|
|
4540
4495
|
}, [getAccessToken, activeCredentialId, apiBaseUrl, depositAmount]);
|
|
4496
|
+
const enterPersistedMobileFlow = useCallback((persisted, errorMessage) => {
|
|
4497
|
+
setMobileFlow(true);
|
|
4498
|
+
setDeeplinkUri(persisted.deeplinkUri);
|
|
4499
|
+
setSelectedProviderId(persisted.providerId);
|
|
4500
|
+
pollingTransferIdRef.current = persisted.transferId;
|
|
4501
|
+
mobileSetupFlowRef.current = persisted.isSetup;
|
|
4502
|
+
setError(errorMessage ?? null);
|
|
4503
|
+
setStep("open-wallet");
|
|
4504
|
+
polling.startPolling(persisted.transferId);
|
|
4505
|
+
}, [polling]);
|
|
4506
|
+
const handleAuthorizedMobileReturn = useCallback(async (authorizedTransfer, isSetup) => {
|
|
4507
|
+
setTransfer(authorizedTransfer);
|
|
4508
|
+
polling.stopPolling();
|
|
4509
|
+
if (isSetup) {
|
|
4510
|
+
mobileSetupFlowRef.current = false;
|
|
4511
|
+
clearMobileFlowState();
|
|
4512
|
+
try {
|
|
4513
|
+
await reloadAccounts();
|
|
4514
|
+
setError(null);
|
|
4515
|
+
setDeeplinkUri(null);
|
|
4516
|
+
setMobileFlow(false);
|
|
4517
|
+
setStep("deposit");
|
|
4518
|
+
} catch (err) {
|
|
4519
|
+
setError(
|
|
4520
|
+
err instanceof Error ? err.message : "Wallet authorized, but we could not refresh your account yet."
|
|
4521
|
+
);
|
|
4522
|
+
setStep("open-wallet");
|
|
4523
|
+
}
|
|
4524
|
+
return;
|
|
4525
|
+
}
|
|
4526
|
+
mobileSetupFlowRef.current = false;
|
|
4527
|
+
clearMobileFlowState();
|
|
4528
|
+
setError(null);
|
|
4529
|
+
setDeeplinkUri(null);
|
|
4530
|
+
setMobileFlow(false);
|
|
4531
|
+
setStep("confirm-sign");
|
|
4532
|
+
}, [polling.stopPolling, reloadAccounts]);
|
|
4533
|
+
const handleRetryMobileStatus = useCallback(() => {
|
|
4534
|
+
setError(null);
|
|
4535
|
+
const currentTransfer = polling.transfer ?? transfer;
|
|
4536
|
+
if (currentTransfer?.status === "AUTHORIZED") {
|
|
4537
|
+
void handleAuthorizedMobileReturn(currentTransfer, mobileSetupFlowRef.current);
|
|
4538
|
+
return;
|
|
4539
|
+
}
|
|
4540
|
+
const transferIdToResume = pollingTransferIdRef.current ?? currentTransfer?.id;
|
|
4541
|
+
if (transferIdToResume) {
|
|
4542
|
+
polling.startPolling(transferIdToResume);
|
|
4543
|
+
}
|
|
4544
|
+
}, [handleAuthorizedMobileReturn, polling, transfer]);
|
|
4541
4545
|
useEffect(() => {
|
|
4542
4546
|
if (depositAmount != null) {
|
|
4543
4547
|
setAmount(depositAmount.toString());
|
|
@@ -4623,19 +4627,70 @@ function SwypePaymentInner({
|
|
|
4623
4627
|
let cancelled = false;
|
|
4624
4628
|
setError(null);
|
|
4625
4629
|
resetHeadlessLogin();
|
|
4626
|
-
const restoreOrDeposit = () => {
|
|
4630
|
+
const restoreOrDeposit = async (credId, token) => {
|
|
4627
4631
|
const persisted = loadMobileFlowState();
|
|
4628
|
-
|
|
4629
|
-
|
|
4630
|
-
|
|
4631
|
-
|
|
4632
|
-
|
|
4633
|
-
|
|
4634
|
-
|
|
4635
|
-
|
|
4636
|
-
|
|
4637
|
-
|
|
4632
|
+
let accts = [];
|
|
4633
|
+
try {
|
|
4634
|
+
accts = await fetchAccounts(apiBaseUrl, token, credId);
|
|
4635
|
+
if (cancelled) return;
|
|
4636
|
+
} catch {
|
|
4637
|
+
}
|
|
4638
|
+
const resolved = resolvePostAuthStep({
|
|
4639
|
+
hasPasskey: true,
|
|
4640
|
+
accounts: accts,
|
|
4641
|
+
persistedMobileFlow: persisted,
|
|
4642
|
+
connectingNewAccount: false
|
|
4643
|
+
});
|
|
4644
|
+
if (resolved.clearPersistedFlow) {
|
|
4645
|
+
clearMobileFlowState();
|
|
4646
|
+
}
|
|
4647
|
+
if (resolved.step === "open-wallet" && persisted) {
|
|
4648
|
+
try {
|
|
4649
|
+
const existingTransfer = await fetchTransfer(apiBaseUrl, token, persisted.transferId);
|
|
4650
|
+
if (cancelled) return;
|
|
4651
|
+
const mobileResolution = resolveRestoredMobileFlow(
|
|
4652
|
+
existingTransfer.status,
|
|
4653
|
+
persisted.isSetup
|
|
4654
|
+
);
|
|
4655
|
+
if (mobileResolution.kind === "resume-setup-deposit") {
|
|
4656
|
+
await handleAuthorizedMobileReturn(existingTransfer, true);
|
|
4657
|
+
return;
|
|
4658
|
+
}
|
|
4659
|
+
if (mobileResolution.kind === "resume-confirm-sign") {
|
|
4660
|
+
await handleAuthorizedMobileReturn(existingTransfer, false);
|
|
4661
|
+
return;
|
|
4662
|
+
}
|
|
4663
|
+
if (mobileResolution.kind === "resume-success") {
|
|
4664
|
+
clearMobileFlowState();
|
|
4665
|
+
setMobileFlow(false);
|
|
4666
|
+
setDeeplinkUri(null);
|
|
4667
|
+
setTransfer(existingTransfer);
|
|
4668
|
+
setError(null);
|
|
4669
|
+
setStep("success");
|
|
4670
|
+
onComplete?.(existingTransfer);
|
|
4671
|
+
return;
|
|
4672
|
+
}
|
|
4673
|
+
if (mobileResolution.kind === "resume-failed") {
|
|
4674
|
+
clearMobileFlowState();
|
|
4675
|
+
setMobileFlow(false);
|
|
4676
|
+
setDeeplinkUri(null);
|
|
4677
|
+
setTransfer(existingTransfer);
|
|
4678
|
+
setError("Transfer failed.");
|
|
4679
|
+
setStep("success");
|
|
4680
|
+
return;
|
|
4681
|
+
}
|
|
4682
|
+
} catch (err) {
|
|
4683
|
+
if (cancelled) return;
|
|
4684
|
+
enterPersistedMobileFlow(
|
|
4685
|
+
persisted,
|
|
4686
|
+
err instanceof Error ? err.message : "Unable to refresh wallet authorization status."
|
|
4687
|
+
);
|
|
4688
|
+
return;
|
|
4689
|
+
}
|
|
4690
|
+
enterPersistedMobileFlow(persisted);
|
|
4691
|
+
return;
|
|
4638
4692
|
}
|
|
4693
|
+
setStep(resolved.step);
|
|
4639
4694
|
};
|
|
4640
4695
|
const checkPasskey = async () => {
|
|
4641
4696
|
try {
|
|
@@ -4652,7 +4707,7 @@ function SwypePaymentInner({
|
|
|
4652
4707
|
return;
|
|
4653
4708
|
}
|
|
4654
4709
|
if (activeCredentialId && allPasskeys.some((p) => p.credentialId === activeCredentialId)) {
|
|
4655
|
-
restoreOrDeposit();
|
|
4710
|
+
await restoreOrDeposit(activeCredentialId, token);
|
|
4656
4711
|
return;
|
|
4657
4712
|
}
|
|
4658
4713
|
if (cancelled) return;
|
|
@@ -4662,7 +4717,7 @@ function SwypePaymentInner({
|
|
|
4662
4717
|
if (matched) {
|
|
4663
4718
|
setActiveCredentialId(matched);
|
|
4664
4719
|
window.localStorage.setItem(ACTIVE_CREDENTIAL_STORAGE_KEY, matched);
|
|
4665
|
-
restoreOrDeposit();
|
|
4720
|
+
await restoreOrDeposit(matched, token);
|
|
4666
4721
|
return;
|
|
4667
4722
|
}
|
|
4668
4723
|
setStep("create-passkey");
|
|
@@ -4674,7 +4729,18 @@ function SwypePaymentInner({
|
|
|
4674
4729
|
return () => {
|
|
4675
4730
|
cancelled = true;
|
|
4676
4731
|
};
|
|
4677
|
-
}, [
|
|
4732
|
+
}, [
|
|
4733
|
+
ready,
|
|
4734
|
+
authenticated,
|
|
4735
|
+
step,
|
|
4736
|
+
apiBaseUrl,
|
|
4737
|
+
getAccessToken,
|
|
4738
|
+
activeCredentialId,
|
|
4739
|
+
resetHeadlessLogin,
|
|
4740
|
+
enterPersistedMobileFlow,
|
|
4741
|
+
handleAuthorizedMobileReturn,
|
|
4742
|
+
onComplete
|
|
4743
|
+
]);
|
|
4678
4744
|
const loadingDataRef = useRef(false);
|
|
4679
4745
|
useEffect(() => {
|
|
4680
4746
|
if (!authenticated) return;
|
|
@@ -4706,11 +4772,22 @@ function SwypePaymentInner({
|
|
|
4706
4772
|
} else if (prov.length > 0 && !connectingNewAccount) {
|
|
4707
4773
|
setSelectedProviderId(prov[0].id);
|
|
4708
4774
|
}
|
|
4709
|
-
const
|
|
4710
|
-
|
|
4711
|
-
|
|
4712
|
-
|
|
4713
|
-
|
|
4775
|
+
const persisted = loadMobileFlowState();
|
|
4776
|
+
const resolved = resolvePostAuthStep({
|
|
4777
|
+
hasPasskey: !!activeCredentialId,
|
|
4778
|
+
accounts: accts,
|
|
4779
|
+
persistedMobileFlow: persisted,
|
|
4780
|
+
mobileSetupInProgress: mobileSetupFlowRef.current,
|
|
4781
|
+
connectingNewAccount
|
|
4782
|
+
});
|
|
4783
|
+
if (resolved.clearPersistedFlow) {
|
|
4784
|
+
clearMobileFlowState();
|
|
4785
|
+
setMobileFlow(false);
|
|
4786
|
+
setDeeplinkUri(null);
|
|
4787
|
+
}
|
|
4788
|
+
const correctableSteps = ["deposit", "wallet-picker", "open-wallet"];
|
|
4789
|
+
if (correctableSteps.includes(step)) {
|
|
4790
|
+
setStep(resolved.step);
|
|
4714
4791
|
}
|
|
4715
4792
|
} catch (err) {
|
|
4716
4793
|
if (!cancelled) {
|
|
@@ -4773,22 +4850,8 @@ function SwypePaymentInner({
|
|
|
4773
4850
|
if (!mobileFlow) return;
|
|
4774
4851
|
const polledTransfer = polling.transfer;
|
|
4775
4852
|
if (!polledTransfer || polledTransfer.status !== "AUTHORIZED") return;
|
|
4776
|
-
|
|
4777
|
-
|
|
4778
|
-
clearMobileFlowState();
|
|
4779
|
-
setDeeplinkUri(null);
|
|
4780
|
-
polling.stopPolling();
|
|
4781
|
-
setTransfer(polledTransfer);
|
|
4782
|
-
reloadAccounts().catch(() => {
|
|
4783
|
-
}).then(() => {
|
|
4784
|
-
setMobileFlow(false);
|
|
4785
|
-
setStep("deposit");
|
|
4786
|
-
});
|
|
4787
|
-
return;
|
|
4788
|
-
}
|
|
4789
|
-
setTransfer(polledTransfer);
|
|
4790
|
-
setStep("confirm-sign");
|
|
4791
|
-
}, [mobileFlow, polling.transfer, polling.stopPolling, transferSigning, onError, reloadAccounts]);
|
|
4853
|
+
void handleAuthorizedMobileReturn(polledTransfer, mobileSetupFlowRef.current);
|
|
4854
|
+
}, [mobileFlow, polling.transfer, handleAuthorizedMobileReturn]);
|
|
4792
4855
|
useEffect(() => {
|
|
4793
4856
|
if (!mobileFlow) return;
|
|
4794
4857
|
const transferIdToResume = pollingTransferIdRef.current ?? transfer?.id;
|
|
@@ -5021,15 +5084,18 @@ function SwypePaymentInner({
|
|
|
5021
5084
|
setActiveCredentialId(credentialId);
|
|
5022
5085
|
window.localStorage.setItem(ACTIVE_CREDENTIAL_STORAGE_KEY, credentialId);
|
|
5023
5086
|
setPasskeyPopupNeeded(false);
|
|
5024
|
-
const
|
|
5025
|
-
|
|
5026
|
-
|
|
5027
|
-
|
|
5028
|
-
|
|
5029
|
-
|
|
5030
|
-
|
|
5087
|
+
const resolved = resolvePostAuthStep({
|
|
5088
|
+
hasPasskey: true,
|
|
5089
|
+
accounts,
|
|
5090
|
+
persistedMobileFlow: loadMobileFlowState(),
|
|
5091
|
+
mobileSetupInProgress: mobileSetupFlowRef.current,
|
|
5092
|
+
connectingNewAccount
|
|
5093
|
+
});
|
|
5094
|
+
if (resolved.clearPersistedFlow) {
|
|
5095
|
+
clearMobileFlowState();
|
|
5031
5096
|
}
|
|
5032
|
-
|
|
5097
|
+
setStep(resolved.step);
|
|
5098
|
+
}, [getAccessToken, apiBaseUrl, accounts, connectingNewAccount]);
|
|
5033
5099
|
const handleRegisterPasskey = useCallback(async () => {
|
|
5034
5100
|
setRegisteringPasskey(true);
|
|
5035
5101
|
setError(null);
|
|
@@ -5227,6 +5293,8 @@ function SwypePaymentInner({
|
|
|
5227
5293
|
walletName: providerName,
|
|
5228
5294
|
deeplinkUri: deeplinkUri ?? "",
|
|
5229
5295
|
loading: creatingTransfer || !deeplinkUri,
|
|
5296
|
+
error: error || polling.error,
|
|
5297
|
+
onRetryStatus: handleRetryMobileStatus,
|
|
5230
5298
|
onLogout: handleLogout
|
|
5231
5299
|
}
|
|
5232
5300
|
);
|