@pollar/react 0.11.3 → 0.11.4-rc.1
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/LICENSE +202 -0
- package/NOTICE +4 -0
- package/README.md +68 -25
- package/dist/index.css +1375 -217
- package/dist/index.css.map +1 -1
- package/dist/index.d.mts +163 -33
- package/dist/index.d.ts +163 -33
- package/dist/index.js +2081 -570
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2079 -572
- package/dist/index.mjs.map +1 -1
- package/package.json +7 -6
package/dist/index.js
CHANGED
|
@@ -1027,19 +1027,77 @@ var ModalErrorBoundary = class extends react.Component {
|
|
|
1027
1027
|
return this.props.children;
|
|
1028
1028
|
}
|
|
1029
1029
|
};
|
|
1030
|
-
var PollarModalFooter = () => {
|
|
1030
|
+
var PollarModalFooter = ({ shield = false }) => {
|
|
1031
1031
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-footer", children: [
|
|
1032
1032
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-footer-protected", children: "Protected by" }),
|
|
1033
1033
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-footer-brand", children: [
|
|
1034
|
-
/* @__PURE__ */ jsxRuntime.
|
|
1034
|
+
shield ? /* @__PURE__ */ jsxRuntime.jsxs("svg", { className: "pollar-footer-shield", width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", "aria-hidden": true, children: [
|
|
1035
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 3.2 19 6v5.3c0 4.4-2.9 7.8-7 9.5-4.1-1.7-7-5.1-7-9.5V6l7-2.8Z", fill: "var(--pollar-accent)" }),
|
|
1036
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "m8.5 12 2.2 2.2 4.8-5", stroke: "white", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round" })
|
|
1037
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx("img", { src: LOGO_POLLAR, alt: "Pollar", className: "pollar-footer-logo" }),
|
|
1035
1038
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-footer-name", children: "Pollar" }),
|
|
1036
1039
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "pollar-footer-version", children: [
|
|
1037
1040
|
"v",
|
|
1038
|
-
"0.11.
|
|
1041
|
+
"0.11.4-rc.1"
|
|
1039
1042
|
] })
|
|
1040
1043
|
] })
|
|
1041
1044
|
] });
|
|
1042
1045
|
};
|
|
1046
|
+
function RefreshIcon({ spinning = false, className = "" }) {
|
|
1047
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1048
|
+
"svg",
|
|
1049
|
+
{
|
|
1050
|
+
className: `${spinning ? "pollar-modal-refresh-icon pollar-spinning" : "pollar-modal-refresh-icon"}${className ? ` ${className}` : ""}`,
|
|
1051
|
+
width: "17",
|
|
1052
|
+
height: "17",
|
|
1053
|
+
viewBox: "0 0 17 17",
|
|
1054
|
+
fill: "none",
|
|
1055
|
+
"aria-hidden": true,
|
|
1056
|
+
children: [
|
|
1057
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1058
|
+
"path",
|
|
1059
|
+
{
|
|
1060
|
+
d: "M2.125 8.5C2.125 6.80924 2.79665 5.18774 3.99219 3.99219C5.18774 2.79665 6.80924 2.125 8.5 2.125C10.2822 2.1317 11.9928 2.82712 13.2742 4.06583L14.875 5.66667",
|
|
1061
|
+
stroke: "currentColor",
|
|
1062
|
+
strokeWidth: "2",
|
|
1063
|
+
strokeLinecap: "round",
|
|
1064
|
+
strokeLinejoin: "round"
|
|
1065
|
+
}
|
|
1066
|
+
),
|
|
1067
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1068
|
+
"path",
|
|
1069
|
+
{
|
|
1070
|
+
d: "M14.8747 2.125V5.66667H11.333",
|
|
1071
|
+
stroke: "currentColor",
|
|
1072
|
+
strokeWidth: "2",
|
|
1073
|
+
strokeLinecap: "round",
|
|
1074
|
+
strokeLinejoin: "round"
|
|
1075
|
+
}
|
|
1076
|
+
),
|
|
1077
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1078
|
+
"path",
|
|
1079
|
+
{
|
|
1080
|
+
d: "M14.875 8.5C14.875 10.1908 14.2033 11.8123 13.0078 13.0078C11.8123 14.2033 10.1908 14.875 8.5 14.875C6.7178 14.8683 5.00719 14.1729 3.72583 12.9342L2.125 11.3333",
|
|
1081
|
+
stroke: "currentColor",
|
|
1082
|
+
strokeWidth: "2",
|
|
1083
|
+
strokeLinecap: "round",
|
|
1084
|
+
strokeLinejoin: "round"
|
|
1085
|
+
}
|
|
1086
|
+
),
|
|
1087
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1088
|
+
"path",
|
|
1089
|
+
{
|
|
1090
|
+
d: "M2.125 14.875V11.3333H5.66667",
|
|
1091
|
+
stroke: "currentColor",
|
|
1092
|
+
strokeWidth: "2",
|
|
1093
|
+
strokeLinecap: "round",
|
|
1094
|
+
strokeLinejoin: "round"
|
|
1095
|
+
}
|
|
1096
|
+
)
|
|
1097
|
+
]
|
|
1098
|
+
}
|
|
1099
|
+
);
|
|
1100
|
+
}
|
|
1043
1101
|
function CopyButton({ value, label = "Copy", className }) {
|
|
1044
1102
|
const [copied, setCopied] = react.useState(false);
|
|
1045
1103
|
const timerRef = react.useRef(null);
|
|
@@ -1827,9 +1885,10 @@ var STATUS_CONFIG = {
|
|
|
1827
1885
|
none: { label: "Not started", color: "#6b7280", dot: false },
|
|
1828
1886
|
pending: { label: "Pending review", color: "#f59e0b", dot: true },
|
|
1829
1887
|
approved: { label: "Verified", color: "#10b981", dot: false },
|
|
1830
|
-
rejected: { label: "Rejected", color: "#ef4444", dot: false }
|
|
1888
|
+
rejected: { label: "Rejected", color: "#ef4444", dot: false },
|
|
1889
|
+
expired: { label: "Expired", color: "#6b7280", dot: false }
|
|
1831
1890
|
};
|
|
1832
|
-
function KycStatus({ status, className }) {
|
|
1891
|
+
function KycStatus({ status, label, className }) {
|
|
1833
1892
|
const config = STATUS_CONFIG[status] ?? STATUS_CONFIG.none;
|
|
1834
1893
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1835
1894
|
"span",
|
|
@@ -1838,11 +1897,42 @@ function KycStatus({ status, className }) {
|
|
|
1838
1897
|
style: { "--pollar-kyc-color": config.color },
|
|
1839
1898
|
children: [
|
|
1840
1899
|
config.dot && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-kyc-badge-dot" }),
|
|
1841
|
-
config.label
|
|
1900
|
+
label ?? config.label
|
|
1842
1901
|
]
|
|
1843
1902
|
}
|
|
1844
1903
|
);
|
|
1845
1904
|
}
|
|
1905
|
+
|
|
1906
|
+
// src/components/kyc-modal/kyc-messages.ts
|
|
1907
|
+
function kycErrorMessage(error, phase) {
|
|
1908
|
+
const code = error?.code;
|
|
1909
|
+
switch (code) {
|
|
1910
|
+
case "SDK_KYC_NOT_CONFIGURED":
|
|
1911
|
+
return "Identity verification is not available for this app yet.";
|
|
1912
|
+
case "SDK_KYC_PROVIDER_ERROR":
|
|
1913
|
+
return "The verification service is not responding right now. Please try again in a moment.";
|
|
1914
|
+
case "SDK_KYC_SESSION_EXPIRED":
|
|
1915
|
+
return "Your previous verification session expired. Select the provider to start a new one.";
|
|
1916
|
+
case "SDK_KYC_PROVIDER_NOT_FOUND":
|
|
1917
|
+
case "SDK_KYC_PROVIDER_NOT_ENABLED":
|
|
1918
|
+
return "This verification option is no longer available. Refresh to see the current options.";
|
|
1919
|
+
case "SDK_RAMPS_PROVIDER_NOT_CONFIGURED":
|
|
1920
|
+
return "This route is not set up for identity verification yet.";
|
|
1921
|
+
case "VALIDATION_ERROR":
|
|
1922
|
+
return "This verification option is not available for your country.";
|
|
1923
|
+
default:
|
|
1924
|
+
return phase === "load" ? "Could not load verification options. Please refresh to try again." : "Could not start verification. Please try again.";
|
|
1925
|
+
}
|
|
1926
|
+
}
|
|
1927
|
+
function kycReviewMessage(reviewReason) {
|
|
1928
|
+
if (reviewReason === "DUPLICATE_DOCUMENT") {
|
|
1929
|
+
return "This document is already linked to another account, so our team is reviewing it. You can check again later.";
|
|
1930
|
+
}
|
|
1931
|
+
return "Your verification is still being reviewed. You can check again shortly.";
|
|
1932
|
+
}
|
|
1933
|
+
function kycProcessingMessage() {
|
|
1934
|
+
return "Your verification was approved. We are finishing setting it up; check again in a minute.";
|
|
1935
|
+
}
|
|
1846
1936
|
function KycModalTemplate({
|
|
1847
1937
|
theme,
|
|
1848
1938
|
accentColor,
|
|
@@ -1852,151 +1942,274 @@ function KycModalTemplate({
|
|
|
1852
1942
|
selectedProvider,
|
|
1853
1943
|
session,
|
|
1854
1944
|
kycStatus,
|
|
1945
|
+
reviewReason,
|
|
1946
|
+
processing = false,
|
|
1855
1947
|
isLoading,
|
|
1948
|
+
error,
|
|
1856
1949
|
onSelectProvider,
|
|
1857
1950
|
onDoneVerifying,
|
|
1951
|
+
onStartAgain,
|
|
1858
1952
|
onRefresh,
|
|
1859
1953
|
onClose
|
|
1860
1954
|
}) {
|
|
1861
1955
|
const cssVars = buildModalCssVars(theme, accentColor, styleOverrides, "hero");
|
|
1862
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
"
|
|
1956
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1957
|
+
"div",
|
|
1958
|
+
{
|
|
1959
|
+
className: `pollar-modal-card pollar-kyc-modal ${step === "verifying" ? "pollar-kyc-modal--verifying" : ""}`,
|
|
1960
|
+
role: "dialog",
|
|
1961
|
+
"aria-modal": "true",
|
|
1962
|
+
"aria-label": "Identity verification",
|
|
1963
|
+
style: cssVars,
|
|
1964
|
+
onClick: (e) => e.stopPropagation(),
|
|
1965
|
+
children: [
|
|
1966
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-modal-header", children: [
|
|
1967
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-kyc-header-text", children: [
|
|
1968
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "pollar-modal-title", children: "Identity verification" }),
|
|
1969
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "pollar-kyc-subtitle", children: [
|
|
1970
|
+
step === "select_provider" && "Choose your verification provider",
|
|
1971
|
+
step === "verifying" && `Complete the steps below with ${selectedProvider?.name}`,
|
|
1972
|
+
step === "polling" && "Waiting for verification result",
|
|
1973
|
+
step === "done" && (kycStatus === "approved" ? "You\u2019re ready to continue" : "Your verification status")
|
|
1974
|
+
] })
|
|
1975
|
+
] }),
|
|
1976
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-modal-header-actions", children: [
|
|
1977
|
+
step === "select_provider" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1978
|
+
"button",
|
|
1885
1979
|
{
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
"
|
|
1980
|
+
type: "button",
|
|
1981
|
+
className: "pollar-modal-close",
|
|
1982
|
+
onClick: onRefresh,
|
|
1983
|
+
disabled: isLoading,
|
|
1984
|
+
"aria-label": "Refresh",
|
|
1985
|
+
title: "Refresh providers",
|
|
1892
1986
|
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1893
|
-
"
|
|
1987
|
+
"svg",
|
|
1894
1988
|
{
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1989
|
+
className: isLoading ? "pollar-modal-refresh-icon pollar-spinning" : "pollar-modal-refresh-icon",
|
|
1990
|
+
width: "16",
|
|
1991
|
+
height: "16",
|
|
1992
|
+
viewBox: "0 0 16 16",
|
|
1993
|
+
fill: "none",
|
|
1994
|
+
"aria-hidden": true,
|
|
1995
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1996
|
+
"path",
|
|
1997
|
+
{
|
|
1998
|
+
d: "M13.5 8a5.5 5.5 0 1 1-1.6-3.9M13.5 2v3h-3",
|
|
1999
|
+
stroke: "currentColor",
|
|
2000
|
+
strokeWidth: "1.6",
|
|
2001
|
+
strokeLinecap: "round",
|
|
2002
|
+
strokeLinejoin: "round"
|
|
2003
|
+
}
|
|
2004
|
+
)
|
|
1900
2005
|
}
|
|
1901
2006
|
)
|
|
1902
2007
|
}
|
|
1903
|
-
)
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
2008
|
+
),
|
|
2009
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-modal-close", onClick: onClose, "aria-label": "Close", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M2 2l12 12M14 2L2 14", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) }) })
|
|
2010
|
+
] })
|
|
2011
|
+
] }),
|
|
2012
|
+
error && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-kyc-error", role: "alert", children: error }),
|
|
2013
|
+
step === "select_provider" && (isLoading && providers.length === 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-loading-block", children: [
|
|
2014
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-spinner" }),
|
|
2015
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Loading providers\u2026" })
|
|
2016
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-kyc-providers", children: [
|
|
2017
|
+
providers.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("p", { style: { color: "var(--pollar-muted)", textAlign: "center" }, children: "No providers available for your country." }),
|
|
2018
|
+
providers.map((p) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2019
|
+
"button",
|
|
2020
|
+
{
|
|
2021
|
+
type: "button",
|
|
2022
|
+
className: "pollar-kyc-provider-btn",
|
|
2023
|
+
disabled: isLoading,
|
|
2024
|
+
onClick: () => onSelectProvider(p),
|
|
2025
|
+
children: [
|
|
2026
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-kyc-provider-name", children: p.name }),
|
|
2027
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-kyc-provider-flow", children: isLoading && selectedProvider?.id === p.id ? "Opening\u2026" : p.flow === "redirect" ? "Continue in a new tab" : "Continue here" })
|
|
2028
|
+
]
|
|
2029
|
+
},
|
|
2030
|
+
p.id
|
|
2031
|
+
))
|
|
2032
|
+
] })),
|
|
2033
|
+
step === "verifying" && selectedProvider && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2034
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-kyc-session-bar", children: [
|
|
2035
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "pollar-kyc-session-label", children: [
|
|
2036
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-kyc-session-dot" }),
|
|
2037
|
+
"Verification in progress"
|
|
2038
|
+
] }),
|
|
2039
|
+
session?.kycUrl && /* @__PURE__ */ jsxRuntime.jsx("a", { href: session.kycUrl, target: "_blank", rel: "noopener noreferrer", children: "Open in new tab \u2197" })
|
|
2040
|
+
] }),
|
|
2041
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-kyc-iframe-wrap", children: session?.kycUrl && selectedProvider.flow === "redirect" ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-kyc-iframe-mock", children: [
|
|
2042
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { children: "Complete verification in a separate tab, then return here to check your status." }),
|
|
2043
|
+
/* @__PURE__ */ jsxRuntime.jsx("a", { className: "pollar-btn-primary", href: session.kycUrl, target: "_blank", rel: "noopener noreferrer", children: "Open verification" })
|
|
2044
|
+
] }) : session?.kycUrl ? /* @__PURE__ */ jsxRuntime.jsx("iframe", { className: "pollar-kyc-iframe", src: session.kycUrl, title: "KYC verification", allow: "camera; microphone" }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-kyc-iframe-mock", children: /* @__PURE__ */ jsxRuntime.jsx("span", { children: selectedProvider.flow === "form" ? "The identity verification form will appear here." : "Identity verification will open here." }) }) }),
|
|
2045
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-kyc-footer", children: [
|
|
2046
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { children: "Finished the steps? Check your status to continue." }),
|
|
2047
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-modal-actions", children: [
|
|
2048
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-btn-secondary", onClick: onClose, children: "Close" }),
|
|
2049
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-btn-primary", onClick: onDoneVerifying, children: "Check status" })
|
|
2050
|
+
] })
|
|
2051
|
+
] })
|
|
2052
|
+
] }),
|
|
2053
|
+
step === "polling" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-kyc-polling", children: [
|
|
2054
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-spinner" }),
|
|
2055
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-kyc-polling-text", children: "Checking verification status\u2026" })
|
|
2056
|
+
] }),
|
|
2057
|
+
step === "done" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-kyc-result", children: [
|
|
2058
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: `pollar-kyc-result-icon pollar-kyc-result-icon--${kycStatus}`, "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2059
|
+
"svg",
|
|
2060
|
+
{
|
|
2061
|
+
width: "28",
|
|
2062
|
+
height: "28",
|
|
2063
|
+
viewBox: "0 0 24 24",
|
|
2064
|
+
fill: "none",
|
|
2065
|
+
stroke: "currentColor",
|
|
2066
|
+
strokeWidth: "1.5",
|
|
2067
|
+
strokeLinecap: "round",
|
|
2068
|
+
strokeLinejoin: "round",
|
|
2069
|
+
children: kycStatus === "approved" ? /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m5 12 4 4L19 6" }) : kycStatus === "rejected" ? /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m7 7 10 10M17 7 7 17" }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2070
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "8" }),
|
|
2071
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 7v5l3 2" })
|
|
2072
|
+
] })
|
|
2073
|
+
}
|
|
2074
|
+
) }),
|
|
2075
|
+
/* @__PURE__ */ jsxRuntime.jsx(KycStatus, { status: kycStatus, ...processing ? { label: "Approved" } : {} }),
|
|
2076
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-kyc-result-text", children: kycStatus === "approved" ? "Your identity has been verified successfully." : kycStatus === "rejected" ? "Your verification was not approved. Contact support for the next steps." : kycStatus === "expired" ? "Your verification expired. Start again to verify your identity." : processing ? kycProcessingMessage() : kycReviewMessage(reviewReason) }),
|
|
2077
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-modal-actions", children: [
|
|
2078
|
+
kycStatus === "expired" && onStartAgain && /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-btn-secondary", onClick: onStartAgain, disabled: isLoading, children: "Start again" }),
|
|
2079
|
+
kycStatus !== "approved" && kycStatus !== "rejected" && kycStatus !== "expired" && /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-btn-secondary", onClick: onDoneVerifying, children: "Check again" }),
|
|
2080
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-btn-primary", onClick: onClose, children: "Close" })
|
|
2081
|
+
] })
|
|
2082
|
+
] })
|
|
2083
|
+
]
|
|
2084
|
+
}
|
|
2085
|
+
);
|
|
1950
2086
|
}
|
|
1951
|
-
function
|
|
2087
|
+
function newIdempotencyKey() {
|
|
2088
|
+
const c = globalThis.crypto;
|
|
2089
|
+
if (c && typeof c.randomUUID === "function") return c.randomUUID();
|
|
2090
|
+
return `kyc-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 12)}`;
|
|
2091
|
+
}
|
|
2092
|
+
function KycModal({ onClose, country = "MX", level = "basic", onApproved, corridorId, providerId }) {
|
|
1952
2093
|
const { getClient, styles } = usePollar();
|
|
1953
2094
|
const [step, setStep] = react.useState("select_provider");
|
|
1954
2095
|
const [providers, setProviders] = react.useState([]);
|
|
1955
2096
|
const [selectedProvider, setSelectedProvider] = react.useState(null);
|
|
1956
2097
|
const [session, setSession] = react.useState(null);
|
|
1957
2098
|
const [kycStatus, setKycStatus] = react.useState("none");
|
|
2099
|
+
const [reviewReason, setReviewReason] = react.useState(null);
|
|
2100
|
+
const [processing, setProcessing] = react.useState(false);
|
|
1958
2101
|
const [isLoading, setIsLoading] = react.useState(false);
|
|
2102
|
+
const [error, setError] = react.useState(null);
|
|
2103
|
+
const idempotencyKeys = react.useRef({});
|
|
2104
|
+
const autoOpened = react.useRef(false);
|
|
1959
2105
|
const client = getClient();
|
|
1960
2106
|
const { theme, accentColor, styleOverrides, overlayStyle } = modalChrome(styles);
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
}
|
|
1968
|
-
|
|
2107
|
+
function finish(status, reason = null, isProcessing = false) {
|
|
2108
|
+
setKycStatus(status);
|
|
2109
|
+
setReviewReason(reason);
|
|
2110
|
+
setProcessing(isProcessing);
|
|
2111
|
+
setStep("done");
|
|
2112
|
+
if (status === "approved") onApproved?.();
|
|
2113
|
+
}
|
|
2114
|
+
function finishWith(read) {
|
|
2115
|
+
if (read.status === "pending" && read.decisionStatus === "approved") finish("pending", null, true);
|
|
2116
|
+
else if (read.decisionStatus === "manual_review") finish("pending", read.reviewReason ?? null);
|
|
2117
|
+
else finish(read.decisionStatus === "expired" ? "expired" : read.status);
|
|
2118
|
+
}
|
|
2119
|
+
function readStatus(providerId2) {
|
|
2120
|
+
return corridorId ? client.getKycStatus(void 0, corridorId) : client.getKycStatus(providerId2);
|
|
2121
|
+
}
|
|
2122
|
+
const starting = react.useRef(false);
|
|
2123
|
+
async function handleSelectProvider(provider, listed = true) {
|
|
2124
|
+
var _a, _b;
|
|
2125
|
+
if (starting.current) return;
|
|
2126
|
+
starting.current = true;
|
|
1969
2127
|
setSelectedProvider(provider);
|
|
2128
|
+
setError(null);
|
|
1970
2129
|
setIsLoading(true);
|
|
2130
|
+
const key = (_a = idempotencyKeys.current)[_b = provider.id] ?? (_a[_b] = newIdempotencyKey());
|
|
1971
2131
|
try {
|
|
1972
|
-
const result = await client.resolveKyc(
|
|
2132
|
+
const result = await client.resolveKyc(
|
|
2133
|
+
provider.id,
|
|
2134
|
+
provider.levels?.[0] ?? level,
|
|
2135
|
+
listed ? country : void 0,
|
|
2136
|
+
corridorId,
|
|
2137
|
+
key
|
|
2138
|
+
);
|
|
1973
2139
|
if (result.alreadyApproved) {
|
|
1974
|
-
|
|
1975
|
-
setStep("done");
|
|
1976
|
-
onApproved?.();
|
|
2140
|
+
finish("approved");
|
|
1977
2141
|
return;
|
|
1978
2142
|
}
|
|
1979
2143
|
setSession(result);
|
|
1980
2144
|
setStep("verifying");
|
|
1981
|
-
} catch {
|
|
2145
|
+
} catch (e) {
|
|
2146
|
+
const code = core.isPollarApiError(e) ? e.code : void 0;
|
|
2147
|
+
if (code === "SDK_KYC_ALREADY_APPROVED") {
|
|
2148
|
+
finish("approved");
|
|
2149
|
+
return;
|
|
2150
|
+
}
|
|
2151
|
+
if (code === "SDK_KYC_UNDER_REVIEW") {
|
|
2152
|
+
await readStatus(provider.id).then(finishWith, () => finish("pending"));
|
|
2153
|
+
return;
|
|
2154
|
+
}
|
|
2155
|
+
if (code === "SDK_KYC_SESSION_EXPIRED") delete idempotencyKeys.current[provider.id];
|
|
2156
|
+
setError(kycErrorMessage(e, "start"));
|
|
1982
2157
|
setStep("select_provider");
|
|
1983
2158
|
} finally {
|
|
2159
|
+
starting.current = false;
|
|
1984
2160
|
setIsLoading(false);
|
|
1985
2161
|
}
|
|
1986
2162
|
}
|
|
2163
|
+
const loadProviders = react.useCallback(() => {
|
|
2164
|
+
setIsLoading(true);
|
|
2165
|
+
setError(null);
|
|
2166
|
+
return getClient().getKycProviders(country, corridorId).then((result) => {
|
|
2167
|
+
setProviders(result.providers);
|
|
2168
|
+
return result.providers;
|
|
2169
|
+
}).catch((e) => {
|
|
2170
|
+
setProviders([]);
|
|
2171
|
+
setError(kycErrorMessage(e, "load"));
|
|
2172
|
+
return [];
|
|
2173
|
+
}).finally(() => setIsLoading(false));
|
|
2174
|
+
}, [getClient, country, corridorId]);
|
|
2175
|
+
react.useEffect(() => {
|
|
2176
|
+
void loadProviders().then((list) => {
|
|
2177
|
+
if (!providerId || autoOpened.current) return;
|
|
2178
|
+
autoOpened.current = true;
|
|
2179
|
+
const target = list.find((p) => p.id === providerId);
|
|
2180
|
+
if (target) void handleSelectProvider(target);
|
|
2181
|
+
else
|
|
2182
|
+
void handleSelectProvider(
|
|
2183
|
+
{ id: providerId, name: "Identity verification", flow: "iframe", levels: [level] },
|
|
2184
|
+
false
|
|
2185
|
+
);
|
|
2186
|
+
});
|
|
2187
|
+
}, [loadProviders, providerId]);
|
|
1987
2188
|
async function handleDoneVerifying() {
|
|
1988
2189
|
if (!selectedProvider) return;
|
|
2190
|
+
setError(null);
|
|
1989
2191
|
setStep("polling");
|
|
1990
2192
|
try {
|
|
1991
|
-
const
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
2193
|
+
const read = await client.pollKycDecision(selectedProvider.id, {
|
|
2194
|
+
intervalMs: 3e3,
|
|
2195
|
+
timeoutMs: 12e4,
|
|
2196
|
+
...corridorId ? { corridorId } : {}
|
|
2197
|
+
});
|
|
2198
|
+
finishWith(read);
|
|
1995
2199
|
} catch {
|
|
1996
|
-
|
|
1997
|
-
setStep("
|
|
2200
|
+
setError("We could not confirm your result yet. Check again shortly; this does not mean your verification was rejected.");
|
|
2201
|
+
setStep("verifying");
|
|
1998
2202
|
}
|
|
1999
2203
|
}
|
|
2204
|
+
function handleStartAgain() {
|
|
2205
|
+
if (selectedProvider) delete idempotencyKeys.current[selectedProvider.id];
|
|
2206
|
+
setSession(null);
|
|
2207
|
+
setKycStatus("none");
|
|
2208
|
+
setReviewReason(null);
|
|
2209
|
+
setProcessing(false);
|
|
2210
|
+
if (selectedProvider) void handleSelectProvider(selectedProvider);
|
|
2211
|
+
else setStep("select_provider");
|
|
2212
|
+
}
|
|
2000
2213
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-overlay", style: overlayStyle, onClick: onClose, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2001
2214
|
KycModalTemplate,
|
|
2002
2215
|
{
|
|
@@ -2008,91 +2221,477 @@ function KycModal({ onClose, country = "MX", level = "basic", onApproved }) {
|
|
|
2008
2221
|
selectedProvider,
|
|
2009
2222
|
session,
|
|
2010
2223
|
kycStatus,
|
|
2224
|
+
reviewReason,
|
|
2225
|
+
processing,
|
|
2011
2226
|
isLoading,
|
|
2227
|
+
error,
|
|
2012
2228
|
onSelectProvider: handleSelectProvider,
|
|
2013
2229
|
onDoneVerifying: handleDoneVerifying,
|
|
2230
|
+
onStartAgain: handleStartAgain,
|
|
2014
2231
|
onRefresh: () => void loadProviders(),
|
|
2015
2232
|
onClose
|
|
2016
2233
|
}
|
|
2017
2234
|
) });
|
|
2018
2235
|
}
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2236
|
+
|
|
2237
|
+
// src/components/requirement-form-modal/form-fields.ts
|
|
2238
|
+
function formLanguage() {
|
|
2239
|
+
const language = typeof navigator !== "undefined" ? navigator.language : "";
|
|
2240
|
+
return language.toLowerCase().startsWith("es") ? "es" : "en";
|
|
2241
|
+
}
|
|
2242
|
+
function localized(text, language) {
|
|
2243
|
+
return (language === "es" ? text?.es || text?.en : text?.en || text?.es) ?? "";
|
|
2244
|
+
}
|
|
2245
|
+
function initialValues(fields, answers) {
|
|
2246
|
+
const values = {};
|
|
2247
|
+
for (const field of fields) {
|
|
2248
|
+
const answer = answers[field.key];
|
|
2249
|
+
if (field.type === "checkbox") values[field.key] = answer === true;
|
|
2250
|
+
else if (field.type === "multiselect") values[field.key] = Array.isArray(answer) ? answer : [];
|
|
2251
|
+
else values[field.key] = answer === void 0 || answer === null ? "" : String(answer);
|
|
2024
2252
|
}
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2253
|
+
return values;
|
|
2254
|
+
}
|
|
2255
|
+
var DATE = /^\d{4}-\d{2}-\d{2}$/;
|
|
2256
|
+
function localFieldErrors(fields, values) {
|
|
2257
|
+
const errors = {};
|
|
2258
|
+
for (const field of fields) {
|
|
2259
|
+
const value = values[field.key];
|
|
2260
|
+
if (typeof value !== "string" || !value.trim()) continue;
|
|
2261
|
+
if (field.type === "number" && !Number.isFinite(Number(value))) errors[field.key] = "invalid_type";
|
|
2262
|
+
if (field.type === "date" && (!DATE.test(value.trim()) || Number.isNaN(Date.parse(`${value.trim()}T00:00:00Z`)))) {
|
|
2263
|
+
errors[field.key] = "invalid_format";
|
|
2264
|
+
}
|
|
2031
2265
|
}
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2266
|
+
return errors;
|
|
2267
|
+
}
|
|
2268
|
+
function answersOf(fields, values) {
|
|
2269
|
+
const answers = {};
|
|
2270
|
+
for (const field of fields) {
|
|
2271
|
+
const value = values[field.key];
|
|
2272
|
+
if (field.type === "checkbox") {
|
|
2273
|
+
answers[field.key] = value === true;
|
|
2274
|
+
} else if (field.type === "multiselect") {
|
|
2275
|
+
if (Array.isArray(value) && value.length) answers[field.key] = value;
|
|
2276
|
+
} else if (typeof value === "string" && value.trim()) {
|
|
2277
|
+
answers[field.key] = field.type === "number" ? Number(value) : value.trim();
|
|
2035
2278
|
}
|
|
2036
2279
|
}
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2280
|
+
return answers;
|
|
2281
|
+
}
|
|
2282
|
+
var MESSAGES = {
|
|
2283
|
+
en: {
|
|
2284
|
+
required: "This field is required.",
|
|
2285
|
+
invalid_type: "This value is not valid.",
|
|
2286
|
+
invalid_option: "Choose one of the options.",
|
|
2287
|
+
too_long: "This is too long.",
|
|
2288
|
+
too_small: "This value is too small.",
|
|
2289
|
+
too_large: "This value is too large.",
|
|
2290
|
+
pattern: "This does not have the expected format.",
|
|
2291
|
+
invalid_format: "This does not have the expected format."
|
|
2292
|
+
},
|
|
2293
|
+
es: {
|
|
2294
|
+
required: "Este campo es obligatorio.",
|
|
2295
|
+
invalid_type: "Este valor no es v\xE1lido.",
|
|
2296
|
+
invalid_option: "Elige una de las opciones.",
|
|
2297
|
+
too_long: "Es demasiado largo.",
|
|
2298
|
+
too_small: "Este valor es demasiado bajo.",
|
|
2299
|
+
too_large: "Este valor es demasiado alto.",
|
|
2300
|
+
pattern: "No tiene el formato esperado.",
|
|
2301
|
+
invalid_format: "No tiene el formato esperado."
|
|
2044
2302
|
}
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
email ? /* @__PURE__ */ jsxRuntime.jsx("strong", { children: email }) : "your email"
|
|
2049
|
-
] }),
|
|
2050
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-code-inputs", children: digits.map((digit, i) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2051
|
-
"input",
|
|
2052
|
-
{
|
|
2053
|
-
ref: (el) => {
|
|
2054
|
-
inputRefs.current[i] = el;
|
|
2055
|
-
},
|
|
2056
|
-
type: "text",
|
|
2057
|
-
inputMode: "numeric",
|
|
2058
|
-
maxLength: 2,
|
|
2059
|
-
value: digit,
|
|
2060
|
-
className: "pollar-code-input",
|
|
2061
|
-
onChange: (e) => handleChange(i, e.target.value),
|
|
2062
|
-
onKeyDown: (e) => handleKeyDown(i, e),
|
|
2063
|
-
onPaste: handlePaste
|
|
2064
|
-
},
|
|
2065
|
-
i
|
|
2066
|
-
)) })
|
|
2067
|
-
] });
|
|
2303
|
+
};
|
|
2304
|
+
function fieldErrorMessage(code, language) {
|
|
2305
|
+
return MESSAGES[language][code] ?? MESSAGES[language].invalid_type;
|
|
2068
2306
|
}
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2307
|
+
function fieldErrorsOf(error) {
|
|
2308
|
+
if (!error || typeof error !== "object") return null;
|
|
2309
|
+
const { code, body } = error;
|
|
2310
|
+
if (code !== "KYC_FORM_INVALID_ANSWERS" || !Array.isArray(body?.errors)) return null;
|
|
2311
|
+
const errors = {};
|
|
2312
|
+
for (const item of body.errors) {
|
|
2313
|
+
if (typeof item.key === "string" && typeof item.code === "string") errors[item.key] = item.code;
|
|
2314
|
+
}
|
|
2315
|
+
return Object.keys(errors).length ? errors : null;
|
|
2316
|
+
}
|
|
2317
|
+
var COPY = {
|
|
2318
|
+
en: {
|
|
2319
|
+
title: "A few more details",
|
|
2320
|
+
loading: "Loading the form\u2026",
|
|
2321
|
+
submit: "Continue",
|
|
2322
|
+
submitting: "Saving\u2026",
|
|
2323
|
+
close: "Close",
|
|
2324
|
+
loadError: "Could not load the form. Please try again.",
|
|
2325
|
+
submitError: "Could not save your answers. Please try again.",
|
|
2326
|
+
step: "Step {n} of {total}"
|
|
2327
|
+
},
|
|
2328
|
+
es: {
|
|
2329
|
+
title: "Unos datos m\xE1s",
|
|
2330
|
+
loading: "Cargando el formulario\u2026",
|
|
2331
|
+
submit: "Continuar",
|
|
2332
|
+
submitting: "Guardando\u2026",
|
|
2333
|
+
close: "Cerrar",
|
|
2334
|
+
loadError: "No se pudo cargar el formulario. Intenta de nuevo.",
|
|
2335
|
+
submitError: "No se pudieron guardar tus respuestas. Intenta de nuevo.",
|
|
2336
|
+
step: "Paso {n} de {total}"
|
|
2337
|
+
}
|
|
2081
2338
|
};
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2339
|
+
function FieldInput({
|
|
2340
|
+
field,
|
|
2341
|
+
value,
|
|
2342
|
+
language,
|
|
2343
|
+
disabled,
|
|
2344
|
+
onChange
|
|
2345
|
+
}) {
|
|
2346
|
+
const id = `pollar-form-${field.key}`;
|
|
2347
|
+
const text = typeof value === "string" ? value : "";
|
|
2348
|
+
switch (field.type) {
|
|
2349
|
+
case "select":
|
|
2350
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("select", { id, className: "pollar-input", value: text, disabled, onChange: (e) => onChange(e.target.value), children: [
|
|
2351
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "" }),
|
|
2352
|
+
(field.options ?? []).map((option) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: option.value, children: localized(option.label, language) }, option.value))
|
|
2353
|
+
] });
|
|
2354
|
+
case "multiselect": {
|
|
2355
|
+
const selected = Array.isArray(value) ? value : [];
|
|
2356
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-form-choices", children: (field.options ?? []).map((option) => /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "pollar-form-choice", children: [
|
|
2087
2357
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2088
|
-
"
|
|
2358
|
+
"input",
|
|
2089
2359
|
{
|
|
2090
|
-
|
|
2091
|
-
|
|
2360
|
+
type: "checkbox",
|
|
2361
|
+
checked: selected.includes(option.value),
|
|
2362
|
+
disabled,
|
|
2363
|
+
onChange: (e) => onChange(e.target.checked ? [...selected, option.value] : selected.filter((item) => item !== option.value))
|
|
2092
2364
|
}
|
|
2093
2365
|
),
|
|
2094
|
-
|
|
2095
|
-
|
|
2366
|
+
localized(option.label, language)
|
|
2367
|
+
] }, option.value)) });
|
|
2368
|
+
}
|
|
2369
|
+
case "textarea":
|
|
2370
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2371
|
+
"textarea",
|
|
2372
|
+
{
|
|
2373
|
+
id,
|
|
2374
|
+
className: "pollar-input pollar-form-textarea",
|
|
2375
|
+
value: text,
|
|
2376
|
+
disabled,
|
|
2377
|
+
maxLength: field.validation?.maxLength,
|
|
2378
|
+
onChange: (e) => onChange(e.target.value)
|
|
2379
|
+
}
|
|
2380
|
+
);
|
|
2381
|
+
default:
|
|
2382
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2383
|
+
"input",
|
|
2384
|
+
{
|
|
2385
|
+
id,
|
|
2386
|
+
className: "pollar-input",
|
|
2387
|
+
type: field.type === "phone" ? "tel" : field.type === "text" ? "text" : field.type,
|
|
2388
|
+
inputMode: field.type === "number" ? "decimal" : void 0,
|
|
2389
|
+
value: text,
|
|
2390
|
+
disabled,
|
|
2391
|
+
min: field.validation?.min,
|
|
2392
|
+
max: field.validation?.max,
|
|
2393
|
+
maxLength: field.validation?.maxLength,
|
|
2394
|
+
onChange: (e) => onChange(e.target.value)
|
|
2395
|
+
}
|
|
2396
|
+
);
|
|
2397
|
+
}
|
|
2398
|
+
}
|
|
2399
|
+
function RequirementFormModal({ formId, progress, onClose, onSubmitted }) {
|
|
2400
|
+
const { getClient, styles } = usePollar();
|
|
2401
|
+
const client = getClient();
|
|
2402
|
+
const { theme, accentColor, styleOverrides, overlayStyle } = modalChrome(styles);
|
|
2403
|
+
const cssVars = buildModalCssVars(theme, accentColor, styleOverrides, "hero");
|
|
2404
|
+
const language = react.useMemo(formLanguage, []);
|
|
2405
|
+
const copy = COPY[language];
|
|
2406
|
+
const [form, setForm] = react.useState(null);
|
|
2407
|
+
const [values, setValues] = react.useState({});
|
|
2408
|
+
const [fieldErrors, setFieldErrors] = react.useState({});
|
|
2409
|
+
const [error, setError] = react.useState(null);
|
|
2410
|
+
const [submitting, setSubmitting] = react.useState(false);
|
|
2411
|
+
const mounted = react.useRef(true);
|
|
2412
|
+
react.useEffect(() => {
|
|
2413
|
+
mounted.current = true;
|
|
2414
|
+
return () => {
|
|
2415
|
+
mounted.current = false;
|
|
2416
|
+
};
|
|
2417
|
+
}, []);
|
|
2418
|
+
react.useEffect(() => {
|
|
2419
|
+
client.getRequirementForm(formId).then((loaded) => {
|
|
2420
|
+
if (!mounted.current) return;
|
|
2421
|
+
setForm(loaded);
|
|
2422
|
+
setValues(initialValues(loaded.fields, loaded.answers));
|
|
2423
|
+
}).catch(() => mounted.current && setError(copy.loadError));
|
|
2424
|
+
}, [formId]);
|
|
2425
|
+
async function submit() {
|
|
2426
|
+
if (!form) return;
|
|
2427
|
+
setError(null);
|
|
2428
|
+
const local = localFieldErrors(form.fields, values);
|
|
2429
|
+
if (Object.keys(local).length) return setFieldErrors(local);
|
|
2430
|
+
setSubmitting(true);
|
|
2431
|
+
setFieldErrors({});
|
|
2432
|
+
try {
|
|
2433
|
+
await client.submitRequirementForm(form.formId, answersOf(form.fields, values));
|
|
2434
|
+
if (mounted.current) onSubmitted();
|
|
2435
|
+
} catch (e) {
|
|
2436
|
+
if (!mounted.current) return;
|
|
2437
|
+
const byField = fieldErrorsOf(e);
|
|
2438
|
+
if (byField) setFieldErrors(byField);
|
|
2439
|
+
else setError(copy.submitError);
|
|
2440
|
+
} finally {
|
|
2441
|
+
if (mounted.current) setSubmitting(false);
|
|
2442
|
+
}
|
|
2443
|
+
}
|
|
2444
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-overlay", style: overlayStyle, onClick: onClose, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2445
|
+
"div",
|
|
2446
|
+
{
|
|
2447
|
+
className: "pollar-modal-card pollar-form-modal",
|
|
2448
|
+
role: "dialog",
|
|
2449
|
+
"aria-modal": "true",
|
|
2450
|
+
"aria-label": form?.name ?? copy.title,
|
|
2451
|
+
style: cssVars,
|
|
2452
|
+
onClick: (e) => e.stopPropagation(),
|
|
2453
|
+
children: [
|
|
2454
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-modal-header", children: [
|
|
2455
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-form-header-text", children: [
|
|
2456
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "pollar-modal-title", children: form?.name ?? copy.title }),
|
|
2457
|
+
progress && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-form-subtitle", children: copy.step.replace("{n}", String(progress.position)).replace("{total}", String(progress.total)) })
|
|
2458
|
+
] }),
|
|
2459
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-modal-close", onClick: onClose, "aria-label": copy.close, children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M2 2l12 12M14 2L2 14", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) }) })
|
|
2460
|
+
] }),
|
|
2461
|
+
error && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-form-error", role: "alert", children: error }),
|
|
2462
|
+
!form && !error && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-loading-block", children: [
|
|
2463
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-spinner" }),
|
|
2464
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: copy.loading })
|
|
2465
|
+
] }),
|
|
2466
|
+
form && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2467
|
+
"form",
|
|
2468
|
+
{
|
|
2469
|
+
className: "pollar-form-body",
|
|
2470
|
+
onSubmit: (e) => {
|
|
2471
|
+
e.preventDefault();
|
|
2472
|
+
void submit();
|
|
2473
|
+
},
|
|
2474
|
+
children: [
|
|
2475
|
+
form.description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-form-description", children: form.description }),
|
|
2476
|
+
form.fields.map((field) => {
|
|
2477
|
+
const fieldError = fieldErrors[field.key];
|
|
2478
|
+
const help = localized(field.help, language);
|
|
2479
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-form-field", children: [
|
|
2480
|
+
field.type === "checkbox" ? /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "pollar-form-choice", children: [
|
|
2481
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2482
|
+
"input",
|
|
2483
|
+
{
|
|
2484
|
+
type: "checkbox",
|
|
2485
|
+
checked: values[field.key] === true,
|
|
2486
|
+
disabled: submitting,
|
|
2487
|
+
onChange: (e) => setValues((v) => ({ ...v, [field.key]: e.target.checked }))
|
|
2488
|
+
}
|
|
2489
|
+
),
|
|
2490
|
+
localized(field.label, language),
|
|
2491
|
+
field.required && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-form-required", children: " *" })
|
|
2492
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2493
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { htmlFor: `pollar-form-${field.key}`, className: "pollar-form-label", children: [
|
|
2494
|
+
localized(field.label, language),
|
|
2495
|
+
field.required && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-form-required", children: " *" })
|
|
2496
|
+
] }),
|
|
2497
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2498
|
+
FieldInput,
|
|
2499
|
+
{
|
|
2500
|
+
field,
|
|
2501
|
+
value: values[field.key] ?? "",
|
|
2502
|
+
language,
|
|
2503
|
+
disabled: submitting,
|
|
2504
|
+
onChange: (value) => setValues((v) => ({ ...v, [field.key]: value }))
|
|
2505
|
+
}
|
|
2506
|
+
)
|
|
2507
|
+
] }),
|
|
2508
|
+
help && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-form-help", children: help }),
|
|
2509
|
+
fieldError && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-form-field-error", role: "alert", children: fieldErrorMessage(fieldError, language) })
|
|
2510
|
+
] }, field.key);
|
|
2511
|
+
}),
|
|
2512
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-modal-actions", children: [
|
|
2513
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-btn-secondary", onClick: onClose, disabled: submitting, children: copy.close }),
|
|
2514
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "submit", className: "pollar-btn-primary", disabled: submitting, children: submitting ? copy.submitting : copy.submit })
|
|
2515
|
+
] })
|
|
2516
|
+
]
|
|
2517
|
+
}
|
|
2518
|
+
)
|
|
2519
|
+
]
|
|
2520
|
+
}
|
|
2521
|
+
) });
|
|
2522
|
+
}
|
|
2523
|
+
function AppKycFlow({ onClose, country, level, onApproved }) {
|
|
2524
|
+
const { getClient } = usePollar();
|
|
2525
|
+
const client = getClient();
|
|
2526
|
+
const [state, setState] = react.useState({ kind: "loading" });
|
|
2527
|
+
const kycStepDone = react.useRef(false);
|
|
2528
|
+
const firstRead = react.useRef(true);
|
|
2529
|
+
const loading = react.useRef(false);
|
|
2530
|
+
const mounted = react.useRef(true);
|
|
2531
|
+
react.useEffect(() => {
|
|
2532
|
+
mounted.current = true;
|
|
2533
|
+
return () => {
|
|
2534
|
+
mounted.current = false;
|
|
2535
|
+
};
|
|
2536
|
+
}, []);
|
|
2537
|
+
async function approvedOption(steps) {
|
|
2538
|
+
for (const step2 of steps) {
|
|
2539
|
+
if (step2.type !== "KYC") continue;
|
|
2540
|
+
for (const optionId of step2.optionIds) {
|
|
2541
|
+
const status = await client.getKycStatus(optionId).catch(() => null);
|
|
2542
|
+
if (status?.status === "approved") return optionId;
|
|
2543
|
+
}
|
|
2544
|
+
}
|
|
2545
|
+
return null;
|
|
2546
|
+
}
|
|
2547
|
+
const load = react.useCallback(async () => {
|
|
2548
|
+
if (loading.current) return;
|
|
2549
|
+
loading.current = true;
|
|
2550
|
+
kycStepDone.current = false;
|
|
2551
|
+
try {
|
|
2552
|
+
const requirements = await client.getAppRequirements();
|
|
2553
|
+
if (!mounted.current) return;
|
|
2554
|
+
if (!requirements.total) return setState({ kind: "options" });
|
|
2555
|
+
const first = firstRead.current;
|
|
2556
|
+
firstRead.current = false;
|
|
2557
|
+
if (requirements.next) return setState({ kind: "step", step: requirements.next });
|
|
2558
|
+
onApproved?.();
|
|
2559
|
+
const providerId = first ? await approvedOption(requirements.steps) : null;
|
|
2560
|
+
if (!mounted.current) return;
|
|
2561
|
+
if (providerId) setState({ kind: "done", providerId });
|
|
2562
|
+
else onClose();
|
|
2563
|
+
} catch {
|
|
2564
|
+
if (mounted.current) setState({ kind: "options" });
|
|
2565
|
+
} finally {
|
|
2566
|
+
loading.current = false;
|
|
2567
|
+
}
|
|
2568
|
+
}, []);
|
|
2569
|
+
react.useEffect(() => {
|
|
2570
|
+
void load();
|
|
2571
|
+
}, [load]);
|
|
2572
|
+
if (state.kind === "loading") return null;
|
|
2573
|
+
if (state.kind === "options") {
|
|
2574
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2575
|
+
KycModal,
|
|
2576
|
+
{
|
|
2577
|
+
onClose,
|
|
2578
|
+
...country !== void 0 && { country },
|
|
2579
|
+
...level !== void 0 && { level },
|
|
2580
|
+
...onApproved !== void 0 && { onApproved }
|
|
2581
|
+
}
|
|
2582
|
+
);
|
|
2583
|
+
}
|
|
2584
|
+
if (state.kind === "done") {
|
|
2585
|
+
return /* @__PURE__ */ jsxRuntime.jsx(KycModal, { onClose, providerId: state.providerId, ...country !== void 0 && { country } });
|
|
2586
|
+
}
|
|
2587
|
+
const { step } = state;
|
|
2588
|
+
const progress = { position: step.completed + 1, total: step.total };
|
|
2589
|
+
if (step.type === "FORM") {
|
|
2590
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2591
|
+
RequirementFormModal,
|
|
2592
|
+
{
|
|
2593
|
+
formId: step.optionId,
|
|
2594
|
+
progress,
|
|
2595
|
+
onClose,
|
|
2596
|
+
onSubmitted: () => void load()
|
|
2597
|
+
},
|
|
2598
|
+
step.optionId
|
|
2599
|
+
);
|
|
2600
|
+
}
|
|
2601
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2602
|
+
KycModal,
|
|
2603
|
+
{
|
|
2604
|
+
providerId: step.optionId,
|
|
2605
|
+
...country !== void 0 && { country },
|
|
2606
|
+
...level !== void 0 && { level },
|
|
2607
|
+
onApproved: () => {
|
|
2608
|
+
kycStepDone.current = true;
|
|
2609
|
+
},
|
|
2610
|
+
onClose: () => {
|
|
2611
|
+
if (kycStepDone.current) void load();
|
|
2612
|
+
else onClose();
|
|
2613
|
+
}
|
|
2614
|
+
},
|
|
2615
|
+
step.optionId
|
|
2616
|
+
);
|
|
2617
|
+
}
|
|
2618
|
+
function EmailCodeInput({ email, onSubmit }) {
|
|
2619
|
+
const [digits, setDigits] = react.useState(["", "", "", "", "", ""]);
|
|
2620
|
+
const inputRefs = react.useRef([]);
|
|
2621
|
+
function submit(next) {
|
|
2622
|
+
if (next.every(Boolean)) onSubmit(next.join(""));
|
|
2623
|
+
}
|
|
2624
|
+
function handleChange(index, value) {
|
|
2625
|
+
const cleaned = value.replace(/\D/g, "").slice(-1);
|
|
2626
|
+
const next = digits.map((d, i) => i === index ? cleaned : d);
|
|
2627
|
+
setDigits(next);
|
|
2628
|
+
if (cleaned && index < 5) inputRefs.current[index + 1]?.focus();
|
|
2629
|
+
submit(next);
|
|
2630
|
+
}
|
|
2631
|
+
function handleKeyDown(index, e) {
|
|
2632
|
+
if (e.key === "Backspace" && !digits[index] && index > 0) {
|
|
2633
|
+
inputRefs.current[index - 1]?.focus();
|
|
2634
|
+
}
|
|
2635
|
+
}
|
|
2636
|
+
function handlePaste(e) {
|
|
2637
|
+
e.preventDefault();
|
|
2638
|
+
const text = e.clipboardData.getData("text").replace(/\D/g, "").slice(0, 6);
|
|
2639
|
+
const next = Array.from({ length: 6 }, (_, i) => text[i] ?? "");
|
|
2640
|
+
setDigits(next);
|
|
2641
|
+
inputRefs.current[Math.min(text.length - 1, 5)]?.focus();
|
|
2642
|
+
submit(next);
|
|
2643
|
+
}
|
|
2644
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-code-section", children: [
|
|
2645
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "pollar-code-label", children: [
|
|
2646
|
+
"Enter the 6-digit code sent to ",
|
|
2647
|
+
email ? /* @__PURE__ */ jsxRuntime.jsx("strong", { children: email }) : "your email"
|
|
2648
|
+
] }),
|
|
2649
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-code-inputs", children: digits.map((digit, i) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2650
|
+
"input",
|
|
2651
|
+
{
|
|
2652
|
+
ref: (el) => {
|
|
2653
|
+
inputRefs.current[i] = el;
|
|
2654
|
+
},
|
|
2655
|
+
type: "text",
|
|
2656
|
+
inputMode: "numeric",
|
|
2657
|
+
maxLength: 2,
|
|
2658
|
+
value: digit,
|
|
2659
|
+
className: "pollar-code-input",
|
|
2660
|
+
onChange: (e) => handleChange(i, e.target.value),
|
|
2661
|
+
onKeyDown: (e) => handleKeyDown(i, e),
|
|
2662
|
+
onPaste: handlePaste
|
|
2663
|
+
},
|
|
2664
|
+
i
|
|
2665
|
+
)) })
|
|
2666
|
+
] });
|
|
2667
|
+
}
|
|
2668
|
+
var GithubButton = ({ disabled, onClick }) => {
|
|
2669
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("button", { className: "pollar-github-button", disabled, onClick, children: [
|
|
2670
|
+
/* @__PURE__ */ jsxRuntime.jsx("svg", { className: "pollar-github-button-icon", viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2671
|
+
"path",
|
|
2672
|
+
{
|
|
2673
|
+
fillRule: "evenodd",
|
|
2674
|
+
d: "M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z",
|
|
2675
|
+
clipRule: "evenodd"
|
|
2676
|
+
}
|
|
2677
|
+
) }),
|
|
2678
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-github-button-contents", children: "GitHub" })
|
|
2679
|
+
] });
|
|
2680
|
+
};
|
|
2681
|
+
var GoogleButton = ({ disabled, onClick }) => {
|
|
2682
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("button", { className: "pollar-gsi-material-button", disabled, onClick, children: [
|
|
2683
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-gsi-material-button-state" }),
|
|
2684
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-gsi-material-button-content-wrapper", children: [
|
|
2685
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-gsi-material-button-icon", children: /* @__PURE__ */ jsxRuntime.jsxs("svg", { version: "1.1", xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 48 48", style: { display: "block" }, children: [
|
|
2686
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2687
|
+
"path",
|
|
2688
|
+
{
|
|
2689
|
+
fill: "#EA4335",
|
|
2690
|
+
d: "M24 9.5c3.54 0 6.71 1.22 9.21 3.6l6.85-6.85C35.9 2.38 30.47 0 24 0 14.62 0 6.51 5.38 2.56 13.22l7.98 6.19C12.43 13.72 17.74 9.5 24 9.5z"
|
|
2691
|
+
}
|
|
2692
|
+
),
|
|
2693
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2694
|
+
"path",
|
|
2096
2695
|
{
|
|
2097
2696
|
fill: "#4285F4",
|
|
2098
2697
|
d: "M46.98 24.55c0-1.57-.15-3.09-.38-4.55H24v9.02h12.94c-.58 2.96-2.26 5.48-4.78 7.18l7.73 6c4.51-4.18 7.09-10.36 7.09-17.65z"
|
|
@@ -2732,6 +3331,53 @@ function LoginModal({ onClose }) {
|
|
|
2732
3331
|
}
|
|
2733
3332
|
) });
|
|
2734
3333
|
}
|
|
3334
|
+
|
|
3335
|
+
// src/components/ramp-widget/ramp-kyc.ts
|
|
3336
|
+
var nonEmpty = (value) => typeof value === "string" && !!value.trim();
|
|
3337
|
+
function requiredRampKyc(error) {
|
|
3338
|
+
if (!error || typeof error !== "object") return null;
|
|
3339
|
+
const { code, body } = error;
|
|
3340
|
+
if (code !== "SDK_RAMPS_KYC_REQUIRED" || !body || typeof body !== "object") return null;
|
|
3341
|
+
const { rampProviderId, corridorId, requirementType, optionId, kycProviderId } = body;
|
|
3342
|
+
if (!nonEmpty(rampProviderId) || !nonEmpty(corridorId)) return null;
|
|
3343
|
+
if ((requirementType === "FORM" || requirementType === "REGISTRY_CHECK" || requirementType === "PROVIDER_REGISTRATION") && nonEmpty(optionId)) {
|
|
3344
|
+
return { rampProviderId, corridorId, type: requirementType, optionId };
|
|
3345
|
+
}
|
|
3346
|
+
const kyc = nonEmpty(optionId) && requirementType === "KYC" ? optionId : kycProviderId;
|
|
3347
|
+
return nonEmpty(kyc) ? { rampProviderId, corridorId, type: "KYC", optionId: kyc } : null;
|
|
3348
|
+
}
|
|
3349
|
+
function pendingFromQuote(requirement) {
|
|
3350
|
+
return {
|
|
3351
|
+
rampProviderId: requirement.rampProviderId,
|
|
3352
|
+
corridorId: requirement.corridorId,
|
|
3353
|
+
type: requirement.type,
|
|
3354
|
+
optionId: requirement.optionId,
|
|
3355
|
+
progress: { position: requirement.completed + 1, total: requirement.total }
|
|
3356
|
+
};
|
|
3357
|
+
}
|
|
3358
|
+
function lockedRouteCopy(requirement) {
|
|
3359
|
+
if (requirement.type === "FORM") return { message: "Answer a few questions to see this route", action: "Continue" };
|
|
3360
|
+
if (requirement.type === "PROVIDER_REGISTRATION") {
|
|
3361
|
+
return { message: "Register with the provider to see this route", action: "Continue" };
|
|
3362
|
+
}
|
|
3363
|
+
if (requirement.type === "REGISTRY_CHECK") {
|
|
3364
|
+
return requirement.status === "pending" ? { message: "Your details are under review", action: null } : { message: "Confirm your details to see this route", action: "Confirm" };
|
|
3365
|
+
}
|
|
3366
|
+
switch (requirement.status) {
|
|
3367
|
+
case "expired":
|
|
3368
|
+
return { message: "Your verification expired", action: "Verify again" };
|
|
3369
|
+
case "pending":
|
|
3370
|
+
if (!requirement.reviewReason) return { message: "Verification in progress", action: "Continue" };
|
|
3371
|
+
return {
|
|
3372
|
+
message: requirement.reviewReason === "DUPLICATE_DOCUMENT" ? kycReviewMessage(requirement.reviewReason) : "Your verification is under review",
|
|
3373
|
+
action: null
|
|
3374
|
+
};
|
|
3375
|
+
case "rejected":
|
|
3376
|
+
return { message: "Verification was not approved", action: null };
|
|
3377
|
+
default:
|
|
3378
|
+
return { message: "Verify your identity to see this route", action: "Verify" };
|
|
3379
|
+
}
|
|
3380
|
+
}
|
|
2735
3381
|
var RAIL_LABELS = {
|
|
2736
3382
|
SPEI: "SPEI (Mexico)",
|
|
2737
3383
|
PIX: "PIX (Brazil)",
|
|
@@ -2772,6 +3418,34 @@ function RouteDisplay({ quote, busy = false, disabled = false, onSelect }) {
|
|
|
2772
3418
|
}
|
|
2773
3419
|
);
|
|
2774
3420
|
}
|
|
3421
|
+
function LockedRouteDisplay({ requirement, disabled = false, onVerify }) {
|
|
3422
|
+
const { message, action } = lockedRouteCopy(requirement);
|
|
3423
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3424
|
+
"div",
|
|
3425
|
+
{
|
|
3426
|
+
className: "pollar-ramp-route-card",
|
|
3427
|
+
"data-locked": true,
|
|
3428
|
+
"data-kyc-status": requirement.status,
|
|
3429
|
+
"data-disabled": disabled || void 0,
|
|
3430
|
+
children: [
|
|
3431
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-ramp-route-left", children: [
|
|
3432
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-ramp-route-provider", children: requirement.provider }),
|
|
3433
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-ramp-route-meta", children: message })
|
|
3434
|
+
] }),
|
|
3435
|
+
action && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-ramp-route-right", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3436
|
+
"button",
|
|
3437
|
+
{
|
|
3438
|
+
type: "button",
|
|
3439
|
+
className: "pollar-btn-secondary pollar-ramp-route-verify",
|
|
3440
|
+
disabled,
|
|
3441
|
+
onClick: () => onVerify(requirement),
|
|
3442
|
+
children: action
|
|
3443
|
+
}
|
|
3444
|
+
) })
|
|
3445
|
+
]
|
|
3446
|
+
}
|
|
3447
|
+
);
|
|
3448
|
+
}
|
|
2775
3449
|
var EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
2776
3450
|
function isFieldValid(spec, raw) {
|
|
2777
3451
|
const value = (raw ?? "").trim();
|
|
@@ -2779,6 +3453,9 @@ function isFieldValid(spec, raw) {
|
|
|
2779
3453
|
if (spec.type === "email") return EMAIL_RE.test(value);
|
|
2780
3454
|
return true;
|
|
2781
3455
|
}
|
|
3456
|
+
function scannableImageSrc(image) {
|
|
3457
|
+
return image.encoding === "base64" ? `data:${image.mediaType};base64,${image.data}` : `data:${image.mediaType};charset=utf-8,${encodeURIComponent(image.data)}`;
|
|
3458
|
+
}
|
|
2782
3459
|
function listOf(items) {
|
|
2783
3460
|
const last = items[items.length - 1];
|
|
2784
3461
|
if (last === void 0) return "a few details";
|
|
@@ -2829,12 +3506,14 @@ function RampWidgetTemplate({
|
|
|
2829
3506
|
countriesLoading,
|
|
2830
3507
|
refreshing,
|
|
2831
3508
|
quotes,
|
|
3509
|
+
kycRequired,
|
|
2832
3510
|
isLoading,
|
|
2833
3511
|
provider,
|
|
2834
3512
|
txStatus,
|
|
2835
3513
|
kycUrl,
|
|
2836
3514
|
tosUrl,
|
|
2837
3515
|
kycBlocking,
|
|
3516
|
+
onboardingStatus,
|
|
2838
3517
|
kycJustApproved,
|
|
2839
3518
|
stellarTxHash,
|
|
2840
3519
|
explorerUrl,
|
|
@@ -2842,12 +3521,14 @@ function RampWidgetTemplate({
|
|
|
2842
3521
|
canComplete,
|
|
2843
3522
|
completing,
|
|
2844
3523
|
errorMsg,
|
|
3524
|
+
noticeMsg,
|
|
2845
3525
|
onDirectionChange,
|
|
2846
3526
|
onAmountChange,
|
|
2847
3527
|
onFieldChange,
|
|
2848
3528
|
onCountryChange,
|
|
2849
3529
|
onFindRoute,
|
|
2850
3530
|
onSelectQuote,
|
|
3531
|
+
onVerifyRoute,
|
|
2851
3532
|
onContactContinue,
|
|
2852
3533
|
onOpenKyc,
|
|
2853
3534
|
onOpenTos,
|
|
@@ -3004,16 +3685,28 @@ function RampWidgetTemplate({
|
|
|
3004
3685
|
] }, i))
|
|
3005
3686
|
] }),
|
|
3006
3687
|
step === "select_route" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3007
|
-
/* @__PURE__ */ jsxRuntime.jsx("
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3688
|
+
noticeMsg && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-ramp-payment-note", children: noticeMsg }),
|
|
3689
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-ramp-route-list", children: [
|
|
3690
|
+
quotes.map((q, i) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
3691
|
+
RouteDisplay,
|
|
3692
|
+
{
|
|
3693
|
+
quote: q,
|
|
3694
|
+
busy: startingQuoteId != null && q.quoteId === startingQuoteId,
|
|
3695
|
+
disabled: startingQuoteId != null && q.quoteId !== startingQuoteId,
|
|
3696
|
+
onSelect: onSelectQuote
|
|
3697
|
+
},
|
|
3698
|
+
i
|
|
3699
|
+
)),
|
|
3700
|
+
kycRequired.map((r) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
3701
|
+
LockedRouteDisplay,
|
|
3702
|
+
{
|
|
3703
|
+
requirement: r,
|
|
3704
|
+
disabled: startingQuoteId != null,
|
|
3705
|
+
onVerify: onVerifyRoute
|
|
3706
|
+
},
|
|
3707
|
+
`${r.rampProviderId}:${r.corridorId}`
|
|
3708
|
+
))
|
|
3709
|
+
] }),
|
|
3017
3710
|
errorMsg && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-ramp-payment-note", style: { color: "var(--pollar-error-text)" }, children: errorMsg }),
|
|
3018
3711
|
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: errorMsg ? "pollar-btn-primary" : "pollar-btn-secondary", onClick: onBack, children: "Back" })
|
|
3019
3712
|
] }),
|
|
@@ -3133,7 +3826,7 @@ function RampWidgetTemplate({
|
|
|
3133
3826
|
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
3134
3827
|
"img",
|
|
3135
3828
|
{
|
|
3136
|
-
src:
|
|
3829
|
+
src: scannableImageSrc(depositInstructions.scannable.image),
|
|
3137
3830
|
alt: "Payment QR",
|
|
3138
3831
|
style: { width: "100%", maxWidth: 220, height: "auto", display: "block", margin: "0 auto" }
|
|
3139
3832
|
}
|
|
@@ -3167,15 +3860,24 @@ function RampWidgetTemplate({
|
|
|
3167
3860
|
"Continue at ",
|
|
3168
3861
|
provider
|
|
3169
3862
|
] }),
|
|
3170
|
-
kycBlocking && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "pollar-ramp-payment-note", children: [
|
|
3863
|
+
kycBlocking && onboardingStatus === "awaiting_provider" && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "pollar-ramp-payment-note", children: [
|
|
3864
|
+
provider,
|
|
3865
|
+
" is still setting up your account for this payment method. Your verification is complete and there is nothing left for you to do \u2014 nothing has been sent, and this will update on its own once ",
|
|
3866
|
+
provider,
|
|
3867
|
+
" is ready."
|
|
3868
|
+
] }),
|
|
3869
|
+
kycBlocking && onboardingStatus !== "awaiting_provider" && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "pollar-ramp-payment-note", children: [
|
|
3171
3870
|
provider,
|
|
3172
3871
|
" needs to verify your identity before this payout. Nothing has been sent yet \u2014 complete verification with ",
|
|
3173
3872
|
provider,
|
|
3174
3873
|
", and this will update on its own."
|
|
3175
3874
|
] }),
|
|
3176
|
-
kycJustApproved && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3177
|
-
|
|
3178
|
-
|
|
3875
|
+
kycJustApproved && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3876
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "pollar-ramp-payment-note", children: [
|
|
3877
|
+
provider,
|
|
3878
|
+
" approved your verification. Request a new quote to continue \u2014 the previous one was consumed."
|
|
3879
|
+
] }),
|
|
3880
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-btn-primary", onClick: onRetry, children: "Request a new quote" })
|
|
3179
3881
|
] }),
|
|
3180
3882
|
canComplete && /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-btn-primary", disabled: completing, onClick: onCompleteWithdraw, children: completing ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3181
3883
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-spinner pollar-spinner-sm" }),
|
|
@@ -3193,6 +3895,374 @@ function RampWidgetTemplate({
|
|
|
3193
3895
|
] })
|
|
3194
3896
|
] });
|
|
3195
3897
|
}
|
|
3898
|
+
|
|
3899
|
+
// src/components/registry-check-modal/registry-copy.ts
|
|
3900
|
+
var REGISTRY_COPY = {
|
|
3901
|
+
en: {
|
|
3902
|
+
title: "Confirm your details",
|
|
3903
|
+
intro: "We check these details with SEGIP, Bolivia's civil registry. They come from your verified document: you can only adjust how your surnames are split and your ID complement.",
|
|
3904
|
+
givenNames: "Names",
|
|
3905
|
+
surname1: "First surname",
|
|
3906
|
+
surname2: "Second surname",
|
|
3907
|
+
birthdate: "Date of birth",
|
|
3908
|
+
documentNumber: "ID number",
|
|
3909
|
+
complement: "Complement (if your ID has one)",
|
|
3910
|
+
submit: "Confirm",
|
|
3911
|
+
submitting: "Checking\u2026",
|
|
3912
|
+
close: "Close",
|
|
3913
|
+
approved: "Your details were confirmed.",
|
|
3914
|
+
review: "Your details are being reviewed. You can continue once they are confirmed.",
|
|
3915
|
+
notApplicable: "This check is only for Bolivian ID cards (CI). Your verified document is not one, so this route is not available.",
|
|
3916
|
+
identityRequired: "Verify your identity first.",
|
|
3917
|
+
nameMismatch: "Both surnames together must read as on your document: {full}.",
|
|
3918
|
+
loadError: "Could not load your details. Please try again.",
|
|
3919
|
+
submitError: "Could not check your details. Please try again.",
|
|
3920
|
+
step: "Step {n} of {total}"
|
|
3921
|
+
},
|
|
3922
|
+
es: {
|
|
3923
|
+
title: "Confirma tus datos",
|
|
3924
|
+
intro: "Validamos estos datos con el SEGIP, el registro civil de Bolivia. Vienen de tu documento verificado: solo puedes ajustar c\xF3mo se separan tus apellidos y el complemento de tu CI.",
|
|
3925
|
+
givenNames: "Nombres",
|
|
3926
|
+
surname1: "Primer apellido",
|
|
3927
|
+
surname2: "Segundo apellido",
|
|
3928
|
+
birthdate: "Fecha de nacimiento",
|
|
3929
|
+
documentNumber: "N\xFAmero de CI",
|
|
3930
|
+
complement: "Complemento (si tu CI lo tiene)",
|
|
3931
|
+
submit: "Confirmar",
|
|
3932
|
+
submitting: "Validando\u2026",
|
|
3933
|
+
close: "Cerrar",
|
|
3934
|
+
approved: "Tus datos fueron confirmados.",
|
|
3935
|
+
review: "Tus datos est\xE1n en revisi\xF3n. Podr\xE1s continuar cuando se confirmen.",
|
|
3936
|
+
notApplicable: "Esta validaci\xF3n es solo para c\xE9dulas bolivianas (CI). Tu documento verificado no lo es, as\xED que esta ruta no est\xE1 disponible.",
|
|
3937
|
+
identityRequired: "Primero verifica tu identidad.",
|
|
3938
|
+
nameMismatch: "Los dos apellidos juntos deben leerse como en tu documento: {full}.",
|
|
3939
|
+
loadError: "No se pudieron cargar tus datos. Intenta de nuevo.",
|
|
3940
|
+
submitError: "No se pudieron validar tus datos. Intenta de nuevo.",
|
|
3941
|
+
step: "Paso {n} de {total}"
|
|
3942
|
+
}
|
|
3943
|
+
};
|
|
3944
|
+
var REGISTRATION_COPY = {
|
|
3945
|
+
en: {
|
|
3946
|
+
title: "Register with the payment provider",
|
|
3947
|
+
intro: "To use this route, the provider registers you as its customer. These details will be sent to it:",
|
|
3948
|
+
consent: "I agree to share these details with the provider.",
|
|
3949
|
+
submit: "Register",
|
|
3950
|
+
submitting: "Registering\u2026",
|
|
3951
|
+
close: "Close",
|
|
3952
|
+
notReady: "Complete the previous steps first.",
|
|
3953
|
+
missing: "Some details are missing: {fields}.",
|
|
3954
|
+
loadError: "Could not load the registration. Please try again.",
|
|
3955
|
+
submitError: "Could not register you. Please try again.",
|
|
3956
|
+
step: "Step {n} of {total}"
|
|
3957
|
+
},
|
|
3958
|
+
es: {
|
|
3959
|
+
title: "Registro con el proveedor de pagos",
|
|
3960
|
+
intro: "Para usar esta ruta, el proveedor te registra como su cliente. Se le enviar\xE1n estos datos:",
|
|
3961
|
+
consent: "Acepto compartir estos datos con el proveedor.",
|
|
3962
|
+
submit: "Registrarme",
|
|
3963
|
+
submitting: "Registrando\u2026",
|
|
3964
|
+
close: "Cerrar",
|
|
3965
|
+
notReady: "Primero completa los pasos anteriores.",
|
|
3966
|
+
missing: "Faltan algunos datos: {fields}.",
|
|
3967
|
+
loadError: "No se pudo cargar el registro. Intenta de nuevo.",
|
|
3968
|
+
submitError: "No se pudo completar el registro. Intenta de nuevo.",
|
|
3969
|
+
step: "Paso {n} de {total}"
|
|
3970
|
+
}
|
|
3971
|
+
};
|
|
3972
|
+
var SHARED_FIELD_LABELS = {
|
|
3973
|
+
en: {
|
|
3974
|
+
name: "Names",
|
|
3975
|
+
lastname: "Surnames",
|
|
3976
|
+
document_type: "Document type",
|
|
3977
|
+
document_number: "Document number",
|
|
3978
|
+
country: "Country",
|
|
3979
|
+
state_of_residence: "Department of residence",
|
|
3980
|
+
economic_activity: "Economic activity",
|
|
3981
|
+
source_of_funds: "Source of funds",
|
|
3982
|
+
destination_of_funds: "Use of funds",
|
|
3983
|
+
income_level: "Income level",
|
|
3984
|
+
doc_provider_id: "SEGIP validation"
|
|
3985
|
+
},
|
|
3986
|
+
es: {
|
|
3987
|
+
name: "Nombres",
|
|
3988
|
+
lastname: "Apellidos",
|
|
3989
|
+
document_type: "Tipo de documento",
|
|
3990
|
+
document_number: "N\xFAmero de documento",
|
|
3991
|
+
country: "Pa\xEDs",
|
|
3992
|
+
state_of_residence: "Departamento de residencia",
|
|
3993
|
+
economic_activity: "Actividad econ\xF3mica",
|
|
3994
|
+
source_of_funds: "Origen de los fondos",
|
|
3995
|
+
destination_of_funds: "Destino de los fondos",
|
|
3996
|
+
income_level: "Nivel de ingresos",
|
|
3997
|
+
doc_provider_id: "Validaci\xF3n SEGIP"
|
|
3998
|
+
}
|
|
3999
|
+
};
|
|
4000
|
+
var errorCode = (error) => error && typeof error === "object" && typeof error.code === "string" ? error.code : null;
|
|
4001
|
+
function missingFieldsOf(error) {
|
|
4002
|
+
const body = error && typeof error === "object" ? error.body : void 0;
|
|
4003
|
+
return Array.isArray(body?.missing) ? body.missing.filter((item) => typeof item === "string") : [];
|
|
4004
|
+
}
|
|
4005
|
+
function RegistryCheckModal({ optionId, progress, onClose, onApproved }) {
|
|
4006
|
+
const { getClient, styles } = usePollar();
|
|
4007
|
+
const client = getClient();
|
|
4008
|
+
const { theme, accentColor, styleOverrides, overlayStyle } = modalChrome(styles);
|
|
4009
|
+
const cssVars = buildModalCssVars(theme, accentColor, styleOverrides, "hero");
|
|
4010
|
+
const language = react.useMemo(formLanguage, []);
|
|
4011
|
+
const copy = REGISTRY_COPY[language];
|
|
4012
|
+
const [check, setCheck] = react.useState(null);
|
|
4013
|
+
const [surname1, setSurname1] = react.useState("");
|
|
4014
|
+
const [surname2, setSurname2] = react.useState("");
|
|
4015
|
+
const [complement, setComplement] = react.useState("");
|
|
4016
|
+
const [error, setError] = react.useState(null);
|
|
4017
|
+
const [review, setReview] = react.useState(false);
|
|
4018
|
+
const [submitting, setSubmitting] = react.useState(false);
|
|
4019
|
+
const mounted = react.useRef(true);
|
|
4020
|
+
react.useEffect(() => {
|
|
4021
|
+
mounted.current = true;
|
|
4022
|
+
return () => {
|
|
4023
|
+
mounted.current = false;
|
|
4024
|
+
};
|
|
4025
|
+
}, []);
|
|
4026
|
+
react.useEffect(() => {
|
|
4027
|
+
client.getRegistryCheck(optionId).then((loaded) => {
|
|
4028
|
+
if (!mounted.current) return;
|
|
4029
|
+
if (loaded.status === "approved") return onApproved();
|
|
4030
|
+
setCheck(loaded);
|
|
4031
|
+
if (loaded.status === "pending") setReview(true);
|
|
4032
|
+
if (loaded.prefill.applies) {
|
|
4033
|
+
setSurname1(loaded.prefill.surname1);
|
|
4034
|
+
setSurname2(loaded.prefill.surname2 ?? "");
|
|
4035
|
+
setComplement(loaded.prefill.complementNumber ?? "");
|
|
4036
|
+
}
|
|
4037
|
+
}).catch((e) => {
|
|
4038
|
+
if (!mounted.current) return;
|
|
4039
|
+
setError(errorCode(e) === "KYC_REGISTRY_IDENTITY_REQUIRED" ? copy.identityRequired : copy.loadError);
|
|
4040
|
+
});
|
|
4041
|
+
}, [optionId]);
|
|
4042
|
+
const prefill = check?.prefill.applies ? check.prefill : null;
|
|
4043
|
+
async function submit() {
|
|
4044
|
+
if (!prefill) return;
|
|
4045
|
+
setSubmitting(true);
|
|
4046
|
+
setError(null);
|
|
4047
|
+
try {
|
|
4048
|
+
const result = await client.submitRegistryCheck(optionId, {
|
|
4049
|
+
surname1: surname1.trim(),
|
|
4050
|
+
...surname2.trim() ? { surname2: surname2.trim() } : {},
|
|
4051
|
+
...complement.trim() ? { complementNumber: complement.trim() } : {}
|
|
4052
|
+
});
|
|
4053
|
+
if (!mounted.current) return;
|
|
4054
|
+
if (result.status === "approved") onApproved();
|
|
4055
|
+
else setReview(true);
|
|
4056
|
+
} catch (e) {
|
|
4057
|
+
if (!mounted.current) return;
|
|
4058
|
+
const code = errorCode(e);
|
|
4059
|
+
if (code === "SDK_KYC_ALREADY_APPROVED") return onApproved();
|
|
4060
|
+
if (code === "KYC_REGISTRY_NAME_MISMATCH") {
|
|
4061
|
+
setError(copy.nameMismatch.replace("{full}", [prefill.surname1, prefill.surname2].filter(Boolean).join(" ")));
|
|
4062
|
+
} else if (code === "SDK_KYC_UNDER_REVIEW") setReview(true);
|
|
4063
|
+
else setError(copy.submitError);
|
|
4064
|
+
} finally {
|
|
4065
|
+
if (mounted.current) setSubmitting(false);
|
|
4066
|
+
}
|
|
4067
|
+
}
|
|
4068
|
+
const readOnly = (label, value) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-form-field", children: [
|
|
4069
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-form-label", children: label }),
|
|
4070
|
+
/* @__PURE__ */ jsxRuntime.jsx("input", { className: "pollar-input", value, readOnly: true, disabled: true })
|
|
4071
|
+
] });
|
|
4072
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-overlay", style: overlayStyle, onClick: onClose, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4073
|
+
"div",
|
|
4074
|
+
{
|
|
4075
|
+
className: "pollar-modal-card pollar-form-modal",
|
|
4076
|
+
role: "dialog",
|
|
4077
|
+
"aria-modal": "true",
|
|
4078
|
+
"aria-label": copy.title,
|
|
4079
|
+
style: cssVars,
|
|
4080
|
+
onClick: (e) => e.stopPropagation(),
|
|
4081
|
+
children: [
|
|
4082
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-modal-header", children: [
|
|
4083
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-form-header-text", children: [
|
|
4084
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "pollar-modal-title", children: copy.title }),
|
|
4085
|
+
progress && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-form-subtitle", children: copy.step.replace("{n}", String(progress.position)).replace("{total}", String(progress.total)) })
|
|
4086
|
+
] }),
|
|
4087
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-modal-close", onClick: onClose, "aria-label": copy.close, children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M2 2l12 12M14 2L2 14", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) }) })
|
|
4088
|
+
] }),
|
|
4089
|
+
error && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-form-error", role: "alert", children: error }),
|
|
4090
|
+
!check && !error && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-loading-block", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-spinner" }) }),
|
|
4091
|
+
check && (review || !prefill) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-form-body", children: [
|
|
4092
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-form-error", role: "status", children: review ? copy.review : copy.notApplicable }),
|
|
4093
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-actions", children: /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-btn-secondary", onClick: onClose, children: copy.close }) })
|
|
4094
|
+
] }),
|
|
4095
|
+
prefill && !review && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4096
|
+
"form",
|
|
4097
|
+
{
|
|
4098
|
+
className: "pollar-form-body",
|
|
4099
|
+
onSubmit: (e) => {
|
|
4100
|
+
e.preventDefault();
|
|
4101
|
+
void submit();
|
|
4102
|
+
},
|
|
4103
|
+
children: [
|
|
4104
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-form-description", children: copy.intro }),
|
|
4105
|
+
readOnly(copy.givenNames, prefill.givenNames),
|
|
4106
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-form-field", children: [
|
|
4107
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { htmlFor: "pollar-registry-surname1", className: "pollar-form-label", children: [
|
|
4108
|
+
copy.surname1,
|
|
4109
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-form-required", children: " *" })
|
|
4110
|
+
] }),
|
|
4111
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4112
|
+
"input",
|
|
4113
|
+
{
|
|
4114
|
+
id: "pollar-registry-surname1",
|
|
4115
|
+
className: "pollar-input",
|
|
4116
|
+
value: surname1,
|
|
4117
|
+
required: true,
|
|
4118
|
+
disabled: submitting,
|
|
4119
|
+
onChange: (e) => setSurname1(e.target.value)
|
|
4120
|
+
}
|
|
4121
|
+
)
|
|
4122
|
+
] }),
|
|
4123
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-form-field", children: [
|
|
4124
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "pollar-registry-surname2", className: "pollar-form-label", children: copy.surname2 }),
|
|
4125
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4126
|
+
"input",
|
|
4127
|
+
{
|
|
4128
|
+
id: "pollar-registry-surname2",
|
|
4129
|
+
className: "pollar-input",
|
|
4130
|
+
value: surname2,
|
|
4131
|
+
disabled: submitting,
|
|
4132
|
+
onChange: (e) => setSurname2(e.target.value)
|
|
4133
|
+
}
|
|
4134
|
+
)
|
|
4135
|
+
] }),
|
|
4136
|
+
readOnly(copy.birthdate, prefill.birthdate),
|
|
4137
|
+
readOnly(copy.documentNumber, prefill.documentNumber),
|
|
4138
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-form-field", children: [
|
|
4139
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "pollar-registry-complement", className: "pollar-form-label", children: copy.complement }),
|
|
4140
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4141
|
+
"input",
|
|
4142
|
+
{
|
|
4143
|
+
id: "pollar-registry-complement",
|
|
4144
|
+
className: "pollar-input",
|
|
4145
|
+
value: complement,
|
|
4146
|
+
maxLength: 3,
|
|
4147
|
+
disabled: submitting,
|
|
4148
|
+
onChange: (e) => setComplement(e.target.value.toUpperCase().replace(/[^0-9A-Z]/g, ""))
|
|
4149
|
+
}
|
|
4150
|
+
)
|
|
4151
|
+
] }),
|
|
4152
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-modal-actions", children: [
|
|
4153
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-btn-secondary", onClick: onClose, disabled: submitting, children: copy.close }),
|
|
4154
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "submit", className: "pollar-btn-primary", disabled: submitting || !surname1.trim(), children: submitting ? copy.submitting : copy.submit })
|
|
4155
|
+
] })
|
|
4156
|
+
]
|
|
4157
|
+
}
|
|
4158
|
+
)
|
|
4159
|
+
]
|
|
4160
|
+
}
|
|
4161
|
+
) });
|
|
4162
|
+
}
|
|
4163
|
+
function ProviderRegistrationModal({ corridorId, progress, onClose, onRegistered }) {
|
|
4164
|
+
const { getClient, styles } = usePollar();
|
|
4165
|
+
const client = getClient();
|
|
4166
|
+
const { theme, accentColor, styleOverrides, overlayStyle } = modalChrome(styles);
|
|
4167
|
+
const cssVars = buildModalCssVars(theme, accentColor, styleOverrides, "hero");
|
|
4168
|
+
const language = react.useMemo(formLanguage, []);
|
|
4169
|
+
const copy = REGISTRATION_COPY[language];
|
|
4170
|
+
const labels = SHARED_FIELD_LABELS[language];
|
|
4171
|
+
const [registration, setRegistration] = react.useState(null);
|
|
4172
|
+
const [consent, setConsent] = react.useState(false);
|
|
4173
|
+
const [error, setError] = react.useState(null);
|
|
4174
|
+
const [submitting, setSubmitting] = react.useState(false);
|
|
4175
|
+
const mounted = react.useRef(true);
|
|
4176
|
+
react.useEffect(() => {
|
|
4177
|
+
mounted.current = true;
|
|
4178
|
+
return () => {
|
|
4179
|
+
mounted.current = false;
|
|
4180
|
+
};
|
|
4181
|
+
}, []);
|
|
4182
|
+
react.useEffect(() => {
|
|
4183
|
+
client.getProviderRegistration(corridorId).then((loaded) => {
|
|
4184
|
+
if (!mounted.current) return;
|
|
4185
|
+
if (loaded.status === "registered") onRegistered();
|
|
4186
|
+
else setRegistration(loaded);
|
|
4187
|
+
}).catch(() => mounted.current && setError(copy.loadError));
|
|
4188
|
+
}, [corridorId]);
|
|
4189
|
+
async function submit() {
|
|
4190
|
+
setSubmitting(true);
|
|
4191
|
+
setError(null);
|
|
4192
|
+
try {
|
|
4193
|
+
await client.submitProviderRegistration(corridorId);
|
|
4194
|
+
if (mounted.current) onRegistered();
|
|
4195
|
+
} catch (e) {
|
|
4196
|
+
if (!mounted.current) return;
|
|
4197
|
+
const code = errorCode(e);
|
|
4198
|
+
if (code === "KYC_REGISTRATION_MISSING_DATA") {
|
|
4199
|
+
setError(
|
|
4200
|
+
copy.missing.replace(
|
|
4201
|
+
"{fields}",
|
|
4202
|
+
missingFieldsOf(e).map((key) => labels[key] ?? key).join(", ")
|
|
4203
|
+
)
|
|
4204
|
+
);
|
|
4205
|
+
} else if (code === "KYC_REGISTRATION_STEPS_PENDING") setError(copy.notReady);
|
|
4206
|
+
else setError(copy.submitError);
|
|
4207
|
+
} finally {
|
|
4208
|
+
if (mounted.current) setSubmitting(false);
|
|
4209
|
+
}
|
|
4210
|
+
}
|
|
4211
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-overlay", style: overlayStyle, onClick: onClose, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4212
|
+
"div",
|
|
4213
|
+
{
|
|
4214
|
+
className: "pollar-modal-card pollar-form-modal",
|
|
4215
|
+
role: "dialog",
|
|
4216
|
+
"aria-modal": "true",
|
|
4217
|
+
"aria-label": copy.title,
|
|
4218
|
+
style: cssVars,
|
|
4219
|
+
onClick: (e) => e.stopPropagation(),
|
|
4220
|
+
children: [
|
|
4221
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-modal-header", children: [
|
|
4222
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-form-header-text", children: [
|
|
4223
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "pollar-modal-title", children: copy.title }),
|
|
4224
|
+
progress && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-form-subtitle", children: copy.step.replace("{n}", String(progress.position)).replace("{total}", String(progress.total)) })
|
|
4225
|
+
] }),
|
|
4226
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-modal-close", onClick: onClose, "aria-label": copy.close, children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M2 2l12 12M14 2L2 14", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) }) })
|
|
4227
|
+
] }),
|
|
4228
|
+
error && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-form-error", role: "alert", children: error }),
|
|
4229
|
+
!registration && !error && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-loading-block", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-spinner" }) }),
|
|
4230
|
+
registration && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4231
|
+
"form",
|
|
4232
|
+
{
|
|
4233
|
+
className: "pollar-form-body",
|
|
4234
|
+
onSubmit: (e) => {
|
|
4235
|
+
e.preventDefault();
|
|
4236
|
+
void submit();
|
|
4237
|
+
},
|
|
4238
|
+
children: [
|
|
4239
|
+
registration.ready ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
4240
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-form-description", children: copy.intro }),
|
|
4241
|
+
/* @__PURE__ */ jsxRuntime.jsx("ul", { className: "pollar-form-description", children: registration.fields.map((key) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: labels[key] ?? key }, key)) }),
|
|
4242
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { className: "pollar-form-choice", children: [
|
|
4243
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4244
|
+
"input",
|
|
4245
|
+
{
|
|
4246
|
+
type: "checkbox",
|
|
4247
|
+
checked: consent,
|
|
4248
|
+
disabled: submitting,
|
|
4249
|
+
onChange: (e) => setConsent(e.target.checked)
|
|
4250
|
+
}
|
|
4251
|
+
),
|
|
4252
|
+
copy.consent
|
|
4253
|
+
] })
|
|
4254
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-form-error", role: "status", children: copy.notReady }),
|
|
4255
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-modal-actions", children: [
|
|
4256
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-btn-secondary", onClick: onClose, disabled: submitting, children: copy.close }),
|
|
4257
|
+
registration.ready && /* @__PURE__ */ jsxRuntime.jsx("button", { type: "submit", className: "pollar-btn-primary", disabled: submitting || !consent, children: submitting ? copy.submitting : copy.submit })
|
|
4258
|
+
] })
|
|
4259
|
+
]
|
|
4260
|
+
}
|
|
4261
|
+
)
|
|
4262
|
+
]
|
|
4263
|
+
}
|
|
4264
|
+
) });
|
|
4265
|
+
}
|
|
3196
4266
|
var TERMINAL = ["completed", "failed"];
|
|
3197
4267
|
function requiredFieldsOf(quote) {
|
|
3198
4268
|
return quote.requiredFields ?? [];
|
|
@@ -3225,7 +4295,12 @@ var RAMP_ERROR_MESSAGES = {
|
|
|
3225
4295
|
SDK_RAMPS_WALLET_UNSUPPORTED: "This wallet type cannot be used for this ramp.",
|
|
3226
4296
|
SDK_RAMPS_PROVIDER_NOT_CONFIGURED: "This ramp provider is not configured for this app yet.",
|
|
3227
4297
|
SDK_RAMPS_ANCHOR_ERROR: "The provider rejected the request. Please try again in a moment.",
|
|
3228
|
-
SDK_RAMPS_BRIDGE_ERROR: "The provider rejected the request. Please try again in a moment."
|
|
4298
|
+
SDK_RAMPS_BRIDGE_ERROR: "The provider rejected the request. Please try again in a moment.",
|
|
4299
|
+
SDK_RAMPS_ETHERFUSE_ERROR: "The provider rejected the request. Please try again in a moment.",
|
|
4300
|
+
SDK_RAMPS_INSUFFICIENT_BALANCE: "This wallet does not hold enough to cover that amount. Try a smaller one.",
|
|
4301
|
+
// Nothing moved on-chain, so the balance is untouched. Almost always no XLM
|
|
4302
|
+
// for the network fee on a wallet the app does not sponsor.
|
|
4303
|
+
SDK_RAMPS_ONCHAIN_SUBMIT_FAILED: "The network rejected the transaction, so nothing was sent. The wallet may need XLM for the fee."
|
|
3229
4304
|
};
|
|
3230
4305
|
function rampErrorMessage(e, fallback) {
|
|
3231
4306
|
const body = e?.body;
|
|
@@ -3255,14 +4330,25 @@ function RampWidget({ onClose }) {
|
|
|
3255
4330
|
const [countriesLoading, setCountriesLoading] = react.useState(true);
|
|
3256
4331
|
const [refreshing, setRefreshing] = react.useState(false);
|
|
3257
4332
|
const [quotes, setQuotes] = react.useState([]);
|
|
4333
|
+
const [requirementsRequired, setRequirementsRequired] = react.useState([]);
|
|
3258
4334
|
const [selectedQuote, setSelectedQuote] = react.useState(null);
|
|
3259
4335
|
const [isLoading, setIsLoading] = react.useState(false);
|
|
4336
|
+
const [pendingKyc, setPendingKyc] = react.useState(null);
|
|
4337
|
+
const [noticeMsg, setNoticeMsg] = react.useState(null);
|
|
4338
|
+
const kycAttempt = react.useRef(null);
|
|
4339
|
+
react.useEffect(
|
|
4340
|
+
() => () => {
|
|
4341
|
+
kycAttempt.current = null;
|
|
4342
|
+
},
|
|
4343
|
+
[]
|
|
4344
|
+
);
|
|
3260
4345
|
const [txId, setTxId] = react.useState(null);
|
|
3261
4346
|
const [provider, setProvider] = react.useState("");
|
|
3262
4347
|
const [kycUrl, setKycUrl] = react.useState(null);
|
|
3263
4348
|
const [tosUrl, setTosUrl] = react.useState(null);
|
|
3264
4349
|
const [kycPending, setKycPending] = react.useState(false);
|
|
3265
4350
|
const [kycApproved, setKycApproved] = react.useState(false);
|
|
4351
|
+
const [onboardingStatus, setOnboardingStatus] = react.useState(void 0);
|
|
3266
4352
|
const [txStatus, setTxStatus] = react.useState(null);
|
|
3267
4353
|
const [stellarTxHash, setStellarTxHash] = react.useState(null);
|
|
3268
4354
|
const [depositInstructions, setDepositInstructions] = react.useState(null);
|
|
@@ -3293,6 +4379,7 @@ function RampWidget({ onClose }) {
|
|
|
3293
4379
|
}, [step, txId, txStatus, client]);
|
|
3294
4380
|
react.useEffect(() => {
|
|
3295
4381
|
if (step !== "status" || !kycPending || kycApproved) return;
|
|
4382
|
+
if (onboardingStatus === "awaiting_provider") return;
|
|
3296
4383
|
let active = true;
|
|
3297
4384
|
const check = async () => {
|
|
3298
4385
|
try {
|
|
@@ -3307,7 +4394,7 @@ function RampWidget({ onClose }) {
|
|
|
3307
4394
|
active = false;
|
|
3308
4395
|
clearInterval(id);
|
|
3309
4396
|
};
|
|
3310
|
-
}, [step, kycPending, kycApproved, client]);
|
|
4397
|
+
}, [step, kycPending, kycApproved, onboardingStatus, client]);
|
|
3311
4398
|
async function loadCountries(resetSelection) {
|
|
3312
4399
|
setCountriesLoading(true);
|
|
3313
4400
|
try {
|
|
@@ -3341,6 +4428,7 @@ function RampWidget({ onClose }) {
|
|
|
3341
4428
|
if (step === "select_route") {
|
|
3342
4429
|
const result = await client.getRampsQuote({ country, amount: Number(amount), currency, direction });
|
|
3343
4430
|
setQuotes(result.quotes ?? []);
|
|
4431
|
+
setRequirementsRequired(result.requirementsRequired ?? []);
|
|
3344
4432
|
} else if (step === "status" && txId) {
|
|
3345
4433
|
const tx = await client.getRampTransaction(txId);
|
|
3346
4434
|
setTxStatus(tx.status);
|
|
@@ -3356,6 +4444,7 @@ function RampWidget({ onClose }) {
|
|
|
3356
4444
|
function resetToInput({ keepMessage = false } = {}) {
|
|
3357
4445
|
setStep("input");
|
|
3358
4446
|
setQuotes([]);
|
|
4447
|
+
setRequirementsRequired([]);
|
|
3359
4448
|
setSelectedQuote(null);
|
|
3360
4449
|
setFieldValues({});
|
|
3361
4450
|
setTxId(null);
|
|
@@ -3365,6 +4454,9 @@ function RampWidget({ onClose }) {
|
|
|
3365
4454
|
setTxStatus(null);
|
|
3366
4455
|
setStellarTxHash(null);
|
|
3367
4456
|
setDepositInstructions(null);
|
|
4457
|
+
setKycPending(false);
|
|
4458
|
+
setKycApproved(false);
|
|
4459
|
+
setNoticeMsg(null);
|
|
3368
4460
|
if (!keepMessage) setErrorMsg(null);
|
|
3369
4461
|
}
|
|
3370
4462
|
async function resumeWithSignature(id, ps) {
|
|
@@ -3389,6 +4481,7 @@ function RampWidget({ onClose }) {
|
|
|
3389
4481
|
}
|
|
3390
4482
|
setKycUrl(result.kycUrl ?? null);
|
|
3391
4483
|
setTosUrl(result.tosUrl ?? null);
|
|
4484
|
+
setOnboardingStatus(result.onboardingStatus);
|
|
3392
4485
|
setKycPending(result.kycRequired === true);
|
|
3393
4486
|
if (result.kycRequired) setKycApproved(false);
|
|
3394
4487
|
setTxStatus(result.status);
|
|
@@ -3396,19 +4489,28 @@ function RampWidget({ onClose }) {
|
|
|
3396
4489
|
setDepositInstructions(result.depositInstructions ?? null);
|
|
3397
4490
|
setStep("status");
|
|
3398
4491
|
}
|
|
4492
|
+
async function loadQuotes() {
|
|
4493
|
+
const result = await client.getRampsQuote({ country, amount: Number(amount), currency, direction });
|
|
4494
|
+
const list = result.quotes ?? [];
|
|
4495
|
+
const locked = result.requirementsRequired ?? [];
|
|
4496
|
+
if (list.length === 0 && locked.length === 0) {
|
|
4497
|
+
const down = (result.unavailable ?? []).map((u) => u.provider);
|
|
4498
|
+
setErrorMsg(
|
|
4499
|
+
down.length > 0 ? `${down.join(", ")} ${down.length === 1 ? "is" : "are"} temporarily unavailable. Please try again later.` : `No ramp providers available for ${country} yet.`
|
|
4500
|
+
);
|
|
4501
|
+
setStep("error");
|
|
4502
|
+
return false;
|
|
4503
|
+
}
|
|
4504
|
+
setQuotes(list);
|
|
4505
|
+
setRequirementsRequired(locked);
|
|
4506
|
+
return true;
|
|
4507
|
+
}
|
|
3399
4508
|
async function handleFindRoute() {
|
|
3400
4509
|
setStep("loading_quote");
|
|
3401
4510
|
setIsLoading(true);
|
|
3402
4511
|
setErrorMsg(null);
|
|
3403
4512
|
try {
|
|
3404
|
-
|
|
3405
|
-
const list = result.quotes ?? [];
|
|
3406
|
-
if (list.length === 0) {
|
|
3407
|
-
setErrorMsg(`No ramp providers available for ${country} yet.`);
|
|
3408
|
-
setStep("error");
|
|
3409
|
-
return;
|
|
3410
|
-
}
|
|
3411
|
-
setQuotes(list);
|
|
4513
|
+
if (!await loadQuotes()) return;
|
|
3412
4514
|
setStep("select_route");
|
|
3413
4515
|
} catch (e) {
|
|
3414
4516
|
setErrorMsg(rampErrorMessage(e, "Failed to fetch quotes."));
|
|
@@ -3420,6 +4522,7 @@ function RampWidget({ onClose }) {
|
|
|
3420
4522
|
function handleSelectQuote(quote) {
|
|
3421
4523
|
setSelectedQuote(quote);
|
|
3422
4524
|
setErrorMsg(null);
|
|
4525
|
+
setNoticeMsg(null);
|
|
3423
4526
|
const broken = brokenLimitOf(Number(amount), quote);
|
|
3424
4527
|
if (broken) {
|
|
3425
4528
|
setErrorMsg(limitMessage(broken.limit, broken.value, currency));
|
|
@@ -3455,12 +4558,47 @@ function RampWidget({ onClose }) {
|
|
|
3455
4558
|
const result = direction === "onramp" ? await client.createOnRamp(base) : await client.createOffRamp(base);
|
|
3456
4559
|
await applyResult(result);
|
|
3457
4560
|
} catch (e) {
|
|
4561
|
+
const requirement = requiredRampKyc(e);
|
|
4562
|
+
if (requirement) {
|
|
4563
|
+
setStep(requiredFieldsOf(quote).length ? "contact" : "select_route");
|
|
4564
|
+
setErrorMsg(
|
|
4565
|
+
requirement.type === "KYC" ? "Identity verification is required before continuing." : "A few more details are required before continuing."
|
|
4566
|
+
);
|
|
4567
|
+
kycAttempt.current = requirement;
|
|
4568
|
+
setPendingKyc(requirement);
|
|
4569
|
+
return;
|
|
4570
|
+
}
|
|
3458
4571
|
setErrorMsg(rampErrorMessage(e, "Failed to start the ramp."));
|
|
3459
4572
|
setStep("error");
|
|
3460
4573
|
} finally {
|
|
3461
4574
|
setIsLoading(false);
|
|
3462
4575
|
}
|
|
3463
4576
|
}
|
|
4577
|
+
async function requoteAfterKyc(completed = "KYC") {
|
|
4578
|
+
setStep("loading_quote");
|
|
4579
|
+
setIsLoading(true);
|
|
4580
|
+
setErrorMsg(null);
|
|
4581
|
+
setSelectedQuote(null);
|
|
4582
|
+
try {
|
|
4583
|
+
if (!await loadQuotes()) return;
|
|
4584
|
+
setNoticeMsg(
|
|
4585
|
+
completed === "KYC" ? "Your identity is verified. Prices may have changed, so choose a route to continue." : "Thanks, your details are saved. Prices may have changed, so choose a route to continue."
|
|
4586
|
+
);
|
|
4587
|
+
setStep("select_route");
|
|
4588
|
+
} catch (e) {
|
|
4589
|
+
setErrorMsg(rampErrorMessage(e, "Failed to fetch quotes."));
|
|
4590
|
+
setStep("error");
|
|
4591
|
+
} finally {
|
|
4592
|
+
setIsLoading(false);
|
|
4593
|
+
}
|
|
4594
|
+
}
|
|
4595
|
+
function handleVerifyRoute(requirement) {
|
|
4596
|
+
const attempt = pendingFromQuote(requirement);
|
|
4597
|
+
setErrorMsg(null);
|
|
4598
|
+
setNoticeMsg(null);
|
|
4599
|
+
kycAttempt.current = attempt;
|
|
4600
|
+
setPendingKyc(attempt);
|
|
4601
|
+
}
|
|
3464
4602
|
function handleOpenKyc() {
|
|
3465
4603
|
if (kycUrl) window.open(kycUrl, "_blank", "noopener,noreferrer");
|
|
3466
4604
|
}
|
|
@@ -3489,9 +4627,61 @@ function RampWidget({ onClose }) {
|
|
|
3489
4627
|
}
|
|
3490
4628
|
}
|
|
3491
4629
|
const kycBlocking = kycPending && !kycApproved;
|
|
3492
|
-
const canComplete = direction === "offramp" && step === "status" && txStatus !== "completed" && !stellarTxHash && !
|
|
4630
|
+
const canComplete = direction === "offramp" && step === "status" && txStatus !== "completed" && !stellarTxHash && !kycPending;
|
|
3493
4631
|
const flowSteps = flowStepsOf(quotes, selectedQuote);
|
|
3494
4632
|
const flowStepIndex = flowSteps.indexOf(STEP_LABEL[step] ?? "");
|
|
4633
|
+
if (pendingKyc?.type === "FORM") {
|
|
4634
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
4635
|
+
RequirementFormModal,
|
|
4636
|
+
{
|
|
4637
|
+
formId: pendingKyc.optionId,
|
|
4638
|
+
...pendingKyc.progress ? { progress: pendingKyc.progress } : {},
|
|
4639
|
+
onClose: () => {
|
|
4640
|
+
kycAttempt.current = null;
|
|
4641
|
+
setPendingKyc(null);
|
|
4642
|
+
},
|
|
4643
|
+
onSubmitted: () => {
|
|
4644
|
+
if (kycAttempt.current !== pendingKyc) return;
|
|
4645
|
+
kycAttempt.current = null;
|
|
4646
|
+
setPendingKyc(null);
|
|
4647
|
+
void requoteAfterKyc("FORM");
|
|
4648
|
+
}
|
|
4649
|
+
}
|
|
4650
|
+
);
|
|
4651
|
+
}
|
|
4652
|
+
if (pendingKyc?.type === "REGISTRY_CHECK" || pendingKyc?.type === "PROVIDER_REGISTRATION") {
|
|
4653
|
+
const close = () => {
|
|
4654
|
+
kycAttempt.current = null;
|
|
4655
|
+
setPendingKyc(null);
|
|
4656
|
+
};
|
|
4657
|
+
const done = () => {
|
|
4658
|
+
if (kycAttempt.current !== pendingKyc) return;
|
|
4659
|
+
close();
|
|
4660
|
+
void requoteAfterKyc(pendingKyc.type);
|
|
4661
|
+
};
|
|
4662
|
+
const progress = pendingKyc.progress ? { progress: pendingKyc.progress } : {};
|
|
4663
|
+
return pendingKyc.type === "REGISTRY_CHECK" ? /* @__PURE__ */ jsxRuntime.jsx(RegistryCheckModal, { optionId: pendingKyc.optionId, ...progress, onClose: close, onApproved: done }) : /* @__PURE__ */ jsxRuntime.jsx(ProviderRegistrationModal, { corridorId: pendingKyc.corridorId, ...progress, onClose: close, onRegistered: done });
|
|
4664
|
+
}
|
|
4665
|
+
if (pendingKyc) {
|
|
4666
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
4667
|
+
KycModal,
|
|
4668
|
+
{
|
|
4669
|
+
country,
|
|
4670
|
+
corridorId: pendingKyc.corridorId,
|
|
4671
|
+
providerId: pendingKyc.optionId,
|
|
4672
|
+
onClose: () => {
|
|
4673
|
+
kycAttempt.current = null;
|
|
4674
|
+
setPendingKyc(null);
|
|
4675
|
+
},
|
|
4676
|
+
onApproved: () => {
|
|
4677
|
+
if (kycAttempt.current !== pendingKyc) return;
|
|
4678
|
+
kycAttempt.current = null;
|
|
4679
|
+
setPendingKyc(null);
|
|
4680
|
+
void requoteAfterKyc();
|
|
4681
|
+
}
|
|
4682
|
+
}
|
|
4683
|
+
);
|
|
4684
|
+
}
|
|
3495
4685
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-overlay", style: overlayStyle, onClick: onClose, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3496
4686
|
RampWidgetTemplate,
|
|
3497
4687
|
{
|
|
@@ -3512,12 +4702,14 @@ function RampWidget({ onClose }) {
|
|
|
3512
4702
|
countriesLoading,
|
|
3513
4703
|
refreshing,
|
|
3514
4704
|
quotes,
|
|
4705
|
+
kycRequired: requirementsRequired,
|
|
3515
4706
|
isLoading,
|
|
3516
4707
|
provider,
|
|
3517
4708
|
txStatus,
|
|
3518
4709
|
kycUrl,
|
|
3519
4710
|
tosUrl,
|
|
3520
4711
|
kycBlocking,
|
|
4712
|
+
onboardingStatus: onboardingStatus ?? null,
|
|
3521
4713
|
kycJustApproved: kycPending && kycApproved,
|
|
3522
4714
|
stellarTxHash,
|
|
3523
4715
|
explorerUrl: stellarTxHash ? `https://stellar.expert/explorer/${network === "mainnet" ? "public" : "testnet"}/tx/${stellarTxHash}` : null,
|
|
@@ -3525,6 +4717,7 @@ function RampWidget({ onClose }) {
|
|
|
3525
4717
|
canComplete,
|
|
3526
4718
|
completing,
|
|
3527
4719
|
errorMsg,
|
|
4720
|
+
noticeMsg,
|
|
3528
4721
|
onDirectionChange: setDirection,
|
|
3529
4722
|
onAmountChange: (next) => {
|
|
3530
4723
|
setAmount(next);
|
|
@@ -3534,6 +4727,7 @@ function RampWidget({ onClose }) {
|
|
|
3534
4727
|
onCountryChange: handleCountryChange,
|
|
3535
4728
|
onFindRoute: handleFindRoute,
|
|
3536
4729
|
onSelectQuote: handleSelectQuote,
|
|
4730
|
+
onVerifyRoute: handleVerifyRoute,
|
|
3537
4731
|
onContactContinue: handleContactContinue,
|
|
3538
4732
|
onOpenKyc: handleOpenKyc,
|
|
3539
4733
|
onOpenTos: handleOpenTos,
|
|
@@ -3546,6 +4740,18 @@ function RampWidget({ onClose }) {
|
|
|
3546
4740
|
) });
|
|
3547
4741
|
}
|
|
3548
4742
|
|
|
4743
|
+
// src/lib/wallet-provisioning.ts
|
|
4744
|
+
function walletNotReadyReason(wallet, chain) {
|
|
4745
|
+
if (chain !== "STELLAR") return null;
|
|
4746
|
+
if (wallet?.provisioning === "CREATING") {
|
|
4747
|
+
return "Your wallet is still being prepared on the network. This usually takes a few seconds.";
|
|
4748
|
+
}
|
|
4749
|
+
if (wallet?.provisioning === "FAILED") {
|
|
4750
|
+
return "Your wallet could not be created on the network. Sign in again to retry.";
|
|
4751
|
+
}
|
|
4752
|
+
return null;
|
|
4753
|
+
}
|
|
4754
|
+
|
|
3549
4755
|
// src/lib/qr-code/index.tsx
|
|
3550
4756
|
var import_ErrorCorrectLevel = __toESM(require_ErrorCorrectLevel());
|
|
3551
4757
|
var import_QRCode = __toESM(require_QRCode());
|
|
@@ -3588,6 +4794,31 @@ var QRCode = react.forwardRef(function QRCode2({ bgColor = "#FFFFFF", fgColor =
|
|
|
3588
4794
|
}
|
|
3589
4795
|
);
|
|
3590
4796
|
});
|
|
4797
|
+
function PollarLogo(props) {
|
|
4798
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "45", height: "48", viewBox: "0 0 45 48", fill: "none", xmlns: "http://www.w3.org/2000/svg", ...props, children: [
|
|
4799
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4800
|
+
"path",
|
|
4801
|
+
{
|
|
4802
|
+
d: "M27.2476 11.7526L23.3926 10.0529L24.6679 9.14844L26.8168 9.19868L27.7248 10.3873L27.2476 11.7526Z",
|
|
4803
|
+
fill: "#005DB4"
|
|
4804
|
+
}
|
|
4805
|
+
),
|
|
4806
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4807
|
+
"path",
|
|
4808
|
+
{
|
|
4809
|
+
d: "M27.2307 33.2204L35.6034 28.6687L35.5931 25.9484L35.5707 20.0746L37.96 20.0989C37.96 20.0989 35.8728 18.3558 34.958 17.571C34.0431 16.7861 29.1016 12.8772 29.1016 12.8772L29.7315 11.2883L29.723 9.3148L27.3303 7.45046L23.7464 7.40887C23.7464 7.40887 20.5179 8.96827 20.4115 9.12248C20.2227 9.12248 15.4579 9.17619 14.5568 9.17619C12.3907 10.5103 8.21642 13.1527 8.21642 13.1527L8.22672 15.1002L2.54028 18.4858L5.60406 18.8704L5.99368 19.9568L4.93466 21.7276C4.93466 21.7276 3.61131 22.4796 3.43624 22.5264C3.76248 23.1143 4.12596 23.6803 4.52444 24.2209C4.72869 24.4773 5.01362 24.5259 5.26421 24.5969C5.66242 24.7078 6.09152 24.6991 6.50517 24.7563C6.71629 24.784 6.92226 24.8585 7.13509 24.8863C7.34792 24.914 10.6966 25.4061 11.1566 25.4424C11.5767 25.519 11.9895 25.6315 12.3907 25.7786C13.1476 26.1719 13.8685 26.6449 14.622 27.0226C15.4236 27.4298 16.1668 27.9184 16.9426 28.3689C17.5519 28.7258 18.7397 29.5281 18.7397 29.5281L19.4366 30.3372C19.4366 30.3372 17.7819 30.4135 17.219 30.5261C16.9117 30.5885 16.6302 30.63 16.4534 31.0286C16.2286 31.5345 6.69054 47.5703 6.43136 48C6.36442 47.9134 6.38845 28.6687 6.38845 28.6687L8.60776 27.2513L3.81385 26.0662L0.53552 20.818L0 18.3662L6.45368 14.414L6.36957 0H28.8304C28.8304 0 30.5468 0.223514 31.0618 0.377721C31.5767 0.531928 31.98 0.609898 33.7205 1.8938C35.3373 3.30592 39.7502 7.82125 42.3214 10.4098C42.6028 10.694 43.4422 11.7735 43.6087 12.47C43.7752 13.1665 44 14.2442 44 15.0586C43.9708 19.1148 44.0172 23.2853 43.9571 27.3397C43.9382 28.615 43.516 29.8226 42.8449 30.9506C42.5531 31.4427 41.3276 32.8201 40.3595 33.8233C39.9109 34.2848 39.3577 34.6291 38.7478 34.8266L27.2307 38.5847V33.2204Z",
|
|
4810
|
+
fill: "#005DB4"
|
|
4811
|
+
}
|
|
4812
|
+
),
|
|
4813
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4814
|
+
"path",
|
|
4815
|
+
{
|
|
4816
|
+
d: "M14.2192 17.0897C13.6705 17.1694 11.7754 15.6937 11.7754 15.6937L13.4741 14.3999H16.5112L18.0217 15.7182C18.0217 15.7182 16.6853 15.708 16.2399 15.708C15.6669 16.3927 14.7679 17.0181 14.2152 17.0999",
|
|
4817
|
+
fill: "#005DB4"
|
|
4818
|
+
}
|
|
4819
|
+
)
|
|
4820
|
+
] });
|
|
4821
|
+
}
|
|
3591
4822
|
var CHAIN_NAME = {
|
|
3592
4823
|
STELLAR: "Stellar",
|
|
3593
4824
|
POLYGON: "Polygon",
|
|
@@ -3602,10 +4833,10 @@ function ReceiveModalTemplate({
|
|
|
3602
4833
|
selectedChain,
|
|
3603
4834
|
onSelectChain,
|
|
3604
4835
|
copied,
|
|
4836
|
+
notReadyReason,
|
|
3605
4837
|
onCopy,
|
|
3606
4838
|
onClose
|
|
3607
4839
|
}) {
|
|
3608
|
-
const isDark = theme === "dark";
|
|
3609
4840
|
const cssVars = buildModalCssVars(theme, accentColor, styleOverrides);
|
|
3610
4841
|
const chainName = selectedChain ? CHAIN_NAME[selectedChain] ?? selectedChain : "wallet";
|
|
3611
4842
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -3620,18 +4851,32 @@ function ReceiveModalTemplate({
|
|
|
3620
4851
|
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "pollar-modal-title", children: "Receive" }),
|
|
3621
4852
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-header-actions", children: /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-modal-close", onClick: onClose, "aria-label": "Close", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M2 2l12 12M14 2L2 14", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) }) }) })
|
|
3622
4853
|
] }),
|
|
3623
|
-
/* @__PURE__ */ jsxRuntime.jsx(ChainSelect, { value: selectedChain, options: chains, onChange: onSelectChain }),
|
|
4854
|
+
chains && onSelectChain && /* @__PURE__ */ jsxRuntime.jsx(ChainSelect, { value: selectedChain, options: chains, onChange: onSelectChain }),
|
|
3624
4855
|
walletAddress ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3625
|
-
/* @__PURE__ */ jsxRuntime.
|
|
3626
|
-
|
|
3627
|
-
|
|
3628
|
-
|
|
3629
|
-
|
|
3630
|
-
|
|
3631
|
-
|
|
4856
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-receive-qr", children: [
|
|
4857
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-receive-network-badge", children: [
|
|
4858
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-receive-network-dot", "aria-hidden": true }),
|
|
4859
|
+
chainName,
|
|
4860
|
+
" network"
|
|
4861
|
+
] }),
|
|
4862
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-receive-qr-frame", children: [
|
|
4863
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4864
|
+
QRCode,
|
|
4865
|
+
{
|
|
4866
|
+
value: walletAddress,
|
|
4867
|
+
size: 220,
|
|
4868
|
+
level: "H",
|
|
4869
|
+
fgColor: "#111827",
|
|
4870
|
+
bgColor: "#ffffff",
|
|
4871
|
+
title: `${chainName} wallet QR code`
|
|
4872
|
+
}
|
|
4873
|
+
),
|
|
4874
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-receive-qr-mark", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx(PollarLogo, { width: "22", height: "24" }) })
|
|
4875
|
+
] })
|
|
3632
4876
|
] }),
|
|
3633
|
-
/* @__PURE__ */ jsxRuntime.
|
|
3634
|
-
|
|
4877
|
+
notReadyReason && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-receive-notice", children: notReadyReason }),
|
|
4878
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-receive-address-actions", children: [
|
|
4879
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-receive-address-row", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-receive-address", children: walletAddress }) }),
|
|
3635
4880
|
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-receive-copy-btn", onClick: onCopy, "aria-label": "Copy address", children: copied ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3636
4881
|
/* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "13", height: "13", viewBox: "0 0 14 14", fill: "none", "aria-hidden": true, children: [
|
|
3637
4882
|
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "7", cy: "7", r: "7", fill: "currentColor" }),
|
|
@@ -3646,7 +4891,7 @@ function ReceiveModalTemplate({
|
|
|
3646
4891
|
}
|
|
3647
4892
|
)
|
|
3648
4893
|
] }),
|
|
3649
|
-
"Copied
|
|
4894
|
+
"Copied"
|
|
3650
4895
|
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3651
4896
|
/* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "13", height: "13", viewBox: "0 0 13 13", fill: "none", "aria-hidden": true, children: [
|
|
3652
4897
|
/* @__PURE__ */ jsxRuntime.jsx("rect", { x: "4", y: "4", width: "8", height: "8", rx: "1.5", stroke: "currentColor", strokeWidth: "1.5" }),
|
|
@@ -3660,17 +4905,28 @@ function ReceiveModalTemplate({
|
|
|
3660
4905
|
}
|
|
3661
4906
|
)
|
|
3662
4907
|
] }),
|
|
3663
|
-
"Copy
|
|
4908
|
+
"Copy"
|
|
3664
4909
|
] }) })
|
|
4910
|
+
] }),
|
|
4911
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "pollar-receive-warning", children: [
|
|
4912
|
+
/* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", "aria-hidden": true, children: [
|
|
4913
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "7", cy: "7", r: "5.5", stroke: "currentColor", strokeWidth: "1.25" }),
|
|
4914
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M7 6.25V9.25M7 4.5V4.75", stroke: "currentColor", strokeWidth: "1.25", strokeLinecap: "round" })
|
|
4915
|
+
] }),
|
|
4916
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
4917
|
+
"Only send ",
|
|
4918
|
+
chainName,
|
|
4919
|
+
" assets to this address"
|
|
4920
|
+
] })
|
|
3665
4921
|
] })
|
|
3666
4922
|
] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-empty", children: "No wallet connected." }),
|
|
3667
|
-
/* @__PURE__ */ jsxRuntime.jsx(PollarModalFooter, {})
|
|
4923
|
+
/* @__PURE__ */ jsxRuntime.jsx(PollarModalFooter, { shield: true })
|
|
3668
4924
|
]
|
|
3669
4925
|
}
|
|
3670
4926
|
);
|
|
3671
4927
|
}
|
|
3672
4928
|
function ReceiveModal({ onClose }) {
|
|
3673
|
-
const { wallets, styles } = usePollar();
|
|
4929
|
+
const { wallet, wallets, styles } = usePollar();
|
|
3674
4930
|
const { theme, accentColor, styleOverrides, overlayStyle } = modalChrome(styles);
|
|
3675
4931
|
const [copied, setCopied] = react.useState(false);
|
|
3676
4932
|
const copyTimerRef = react.useRef(null);
|
|
@@ -3680,6 +4936,7 @@ function ReceiveModal({ onClose }) {
|
|
|
3680
4936
|
if (selectedChain === null && chains.length > 0) setSelectedChain(chains[0]);
|
|
3681
4937
|
}, [chains, selectedChain]);
|
|
3682
4938
|
const walletAddress = addressForChain(wallets, selectedChain);
|
|
4939
|
+
const notReadyReason = walletNotReadyReason(wallet, selectedChain);
|
|
3683
4940
|
react.useEffect(
|
|
3684
4941
|
() => () => {
|
|
3685
4942
|
if (copyTimerRef.current !== null) clearTimeout(copyTimerRef.current);
|
|
@@ -3710,53 +4967,13 @@ function ReceiveModal({ onClose }) {
|
|
|
3710
4967
|
setCopied(false);
|
|
3711
4968
|
setSelectedChain(chain);
|
|
3712
4969
|
},
|
|
4970
|
+
notReadyReason,
|
|
3713
4971
|
copied,
|
|
3714
4972
|
onCopy: handleCopy,
|
|
3715
4973
|
onClose
|
|
3716
4974
|
}
|
|
3717
4975
|
) });
|
|
3718
4976
|
}
|
|
3719
|
-
function formatAmount2(value) {
|
|
3720
|
-
const n = parseFloat(value);
|
|
3721
|
-
return isNaN(n) ? value : n.toLocaleString(void 0, { maximumFractionDigits: 7 });
|
|
3722
|
-
}
|
|
3723
|
-
var optionLabel = (o) => o.available !== void 0 ? `${o.code} \u2014 ${formatAmount2(o.available)} available` : o.code;
|
|
3724
|
-
function AssetSelect({
|
|
3725
|
-
label,
|
|
3726
|
-
value,
|
|
3727
|
-
options,
|
|
3728
|
-
onChange,
|
|
3729
|
-
loading = false,
|
|
3730
|
-
loadingLabel,
|
|
3731
|
-
disabled = false,
|
|
3732
|
-
appGroupLabel = "App assets",
|
|
3733
|
-
otherGroupLabel = "Other assets",
|
|
3734
|
-
children
|
|
3735
|
-
}) {
|
|
3736
|
-
const appAssets = options.filter((o) => o.enabledInApp);
|
|
3737
|
-
const otherAssets = options.filter((o) => !o.enabledInApp);
|
|
3738
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-send-field", children: [
|
|
3739
|
-
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "pollar-send-label", children: label }),
|
|
3740
|
-
loading ? loadingLabel ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-input pollar-select-loading", children: [
|
|
3741
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-spinner pollar-spinner-sm" }),
|
|
3742
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { children: loadingLabel })
|
|
3743
|
-
] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-send-skeleton" }) : /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3744
|
-
"select",
|
|
3745
|
-
{
|
|
3746
|
-
className: "pollar-input pollar-send-select",
|
|
3747
|
-
value,
|
|
3748
|
-
disabled,
|
|
3749
|
-
onChange: (e) => onChange(e.target.value),
|
|
3750
|
-
children: [
|
|
3751
|
-
value === "" && /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", disabled: true, hidden: true }),
|
|
3752
|
-
appAssets.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("optgroup", { label: appGroupLabel, children: appAssets.map((o) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: o.key, children: optionLabel(o) }, o.key)) }),
|
|
3753
|
-
otherAssets.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("optgroup", { label: otherGroupLabel, children: otherAssets.map((o) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: o.key, children: optionLabel(o) }, o.key)) })
|
|
3754
|
-
]
|
|
3755
|
-
}
|
|
3756
|
-
),
|
|
3757
|
-
!loading && children
|
|
3758
|
-
] });
|
|
3759
|
-
}
|
|
3760
4977
|
var STATUS_MESSAGES = {
|
|
3761
4978
|
idle: "",
|
|
3762
4979
|
building: "Building transaction\u2026",
|
|
@@ -3962,6 +5179,97 @@ function formatBalance(balance) {
|
|
|
3962
5179
|
function assetKey3(record) {
|
|
3963
5180
|
return `${record.code}:${record.issuer ?? "native"}`;
|
|
3964
5181
|
}
|
|
5182
|
+
function chainLabel(chain) {
|
|
5183
|
+
if (chain === "STELLAR") return "Stellar";
|
|
5184
|
+
if (chain === "SOLANA") return "Solana";
|
|
5185
|
+
if (chain === "POLYGON") return "Polygon";
|
|
5186
|
+
return "network";
|
|
5187
|
+
}
|
|
5188
|
+
function AssetIcon({ code }) {
|
|
5189
|
+
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-send-asset-icon", "aria-hidden": true, children: code.slice(0, 2).toUpperCase() });
|
|
5190
|
+
}
|
|
5191
|
+
function SendAssetSelector({ assets, selectedAsset, loading, onSelectAsset }) {
|
|
5192
|
+
const [open, setOpen] = react.useState(false);
|
|
5193
|
+
const triggerRef = react.useRef(null);
|
|
5194
|
+
react.useEffect(() => {
|
|
5195
|
+
if (!open) return;
|
|
5196
|
+
const closeOnOutsideClick = (event) => {
|
|
5197
|
+
if (!(event.target instanceof Node) || !triggerRef.current?.parentElement?.contains(event.target)) setOpen(false);
|
|
5198
|
+
};
|
|
5199
|
+
document.addEventListener("mousedown", closeOnOutsideClick);
|
|
5200
|
+
return () => document.removeEventListener("mousedown", closeOnOutsideClick);
|
|
5201
|
+
}, [open]);
|
|
5202
|
+
function handleTriggerKeyDown(event) {
|
|
5203
|
+
if (event.key === "ArrowDown" || event.key === "Enter" || event.key === " ") {
|
|
5204
|
+
event.preventDefault();
|
|
5205
|
+
setOpen(true);
|
|
5206
|
+
}
|
|
5207
|
+
}
|
|
5208
|
+
if (loading) {
|
|
5209
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-send-field", children: [
|
|
5210
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-send-label", children: "Asset" }),
|
|
5211
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-send-asset-selector pollar-send-asset-selector-loading", "aria-label": "Loading assets", children: [
|
|
5212
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-spinner pollar-spinner-sm" }),
|
|
5213
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Loading assets\u2026" })
|
|
5214
|
+
] })
|
|
5215
|
+
] });
|
|
5216
|
+
}
|
|
5217
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-send-field", children: [
|
|
5218
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "pollar-send-label", id: "pollar-send-asset-label", children: "Asset" }),
|
|
5219
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-send-asset-picker", children: [
|
|
5220
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
5221
|
+
"button",
|
|
5222
|
+
{
|
|
5223
|
+
ref: triggerRef,
|
|
5224
|
+
type: "button",
|
|
5225
|
+
className: "pollar-send-asset-selector",
|
|
5226
|
+
"aria-labelledby": "pollar-send-asset-label",
|
|
5227
|
+
"aria-haspopup": "listbox",
|
|
5228
|
+
"aria-expanded": open,
|
|
5229
|
+
disabled: !selectedAsset,
|
|
5230
|
+
onClick: () => setOpen((value) => !value),
|
|
5231
|
+
onKeyDown: handleTriggerKeyDown,
|
|
5232
|
+
children: [
|
|
5233
|
+
selectedAsset ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
5234
|
+
/* @__PURE__ */ jsxRuntime.jsx(AssetIcon, { code: selectedAsset.code }),
|
|
5235
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "pollar-send-asset-copy", children: [
|
|
5236
|
+
/* @__PURE__ */ jsxRuntime.jsx("strong", { children: selectedAsset.code }),
|
|
5237
|
+
/* @__PURE__ */ jsxRuntime.jsx("small", { children: selectedAsset.available === null ? "Balance unavailable" : `${formatBalance(selectedAsset.available)} available` })
|
|
5238
|
+
] })
|
|
5239
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-send-asset-copy", children: /* @__PURE__ */ jsxRuntime.jsx("strong", { children: "No assets available" }) }),
|
|
5240
|
+
/* @__PURE__ */ jsxRuntime.jsx("svg", { className: "pollar-send-chevron", width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m4 6 4 4 4-4", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) })
|
|
5241
|
+
]
|
|
5242
|
+
}
|
|
5243
|
+
),
|
|
5244
|
+
open && assets.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-send-asset-menu", role: "listbox", "aria-label": "Assets", children: assets.map((asset) => {
|
|
5245
|
+
const key = assetKey3(asset);
|
|
5246
|
+
const selected = selectedAsset ? key === assetKey3(selectedAsset) : false;
|
|
5247
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5248
|
+
"button",
|
|
5249
|
+
{
|
|
5250
|
+
type: "button",
|
|
5251
|
+
role: "option",
|
|
5252
|
+
"aria-selected": selected,
|
|
5253
|
+
className: `pollar-send-asset-option${selected ? " is-selected" : ""}`,
|
|
5254
|
+
onClick: () => {
|
|
5255
|
+
onSelectAsset(asset);
|
|
5256
|
+
setOpen(false);
|
|
5257
|
+
triggerRef.current?.focus();
|
|
5258
|
+
},
|
|
5259
|
+
children: [
|
|
5260
|
+
/* @__PURE__ */ jsxRuntime.jsx(AssetIcon, { code: asset.code }),
|
|
5261
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "pollar-send-asset-copy", children: [
|
|
5262
|
+
/* @__PURE__ */ jsxRuntime.jsx("strong", { children: asset.code }),
|
|
5263
|
+
/* @__PURE__ */ jsxRuntime.jsx("small", { children: asset.available === null ? "Balance unavailable" : `${formatBalance(asset.available)} available` })
|
|
5264
|
+
] })
|
|
5265
|
+
]
|
|
5266
|
+
},
|
|
5267
|
+
key
|
|
5268
|
+
);
|
|
5269
|
+
}) })
|
|
5270
|
+
] })
|
|
5271
|
+
] });
|
|
5272
|
+
}
|
|
3965
5273
|
function SendModalTemplate({
|
|
3966
5274
|
theme,
|
|
3967
5275
|
accentColor,
|
|
@@ -3970,10 +5278,10 @@ function SendModalTemplate({
|
|
|
3970
5278
|
txTitle,
|
|
3971
5279
|
assets,
|
|
3972
5280
|
selectedAsset,
|
|
3973
|
-
chains,
|
|
3974
5281
|
selectedChain,
|
|
3975
|
-
walletAddress,
|
|
3976
5282
|
canSendOnChain,
|
|
5283
|
+
notReadyReason,
|
|
5284
|
+
chains,
|
|
3977
5285
|
onSelectChain,
|
|
3978
5286
|
amount,
|
|
3979
5287
|
destination,
|
|
@@ -3991,6 +5299,8 @@ function SendModalTemplate({
|
|
|
3991
5299
|
onRefresh,
|
|
3992
5300
|
onSelectAsset,
|
|
3993
5301
|
onAmountChange,
|
|
5302
|
+
onMax,
|
|
5303
|
+
onPaste,
|
|
3994
5304
|
onDestinationChange,
|
|
3995
5305
|
onSubmit,
|
|
3996
5306
|
onSignAndSend,
|
|
@@ -4000,8 +5310,9 @@ function SendModalTemplate({
|
|
|
4000
5310
|
onDone
|
|
4001
5311
|
}) {
|
|
4002
5312
|
const cssVars = buildModalCssVars(theme, accentColor, styleOverrides);
|
|
4003
|
-
const
|
|
4004
|
-
const
|
|
5313
|
+
const parsedAmount = amount ? Number(amount) : 0;
|
|
5314
|
+
const availableAmount = selectedAsset?.available === null || selectedAsset?.available === void 0 ? 0 : Number(selectedAsset.available);
|
|
5315
|
+
const canSubmit = canSendOnChain && !notReadyReason && !!selectedAsset && Number.isFinite(parsedAmount) && parsedAmount > 0 && parsedAmount <= availableAmount && !!destination.trim() && !isLoadingBalance;
|
|
4005
5316
|
const title = step === "form" ? "Send" : txTitle;
|
|
4006
5317
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4007
5318
|
"div",
|
|
@@ -4014,7 +5325,14 @@ function SendModalTemplate({
|
|
|
4014
5325
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-modal-header", children: [
|
|
4015
5326
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-send-header-left", children: [
|
|
4016
5327
|
showBack && /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-modal-close", onClick: onBack, "aria-label": "Back", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M10 3L5 8l5 5", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }) }),
|
|
4017
|
-
/* @__PURE__ */ jsxRuntime.
|
|
5328
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-send-title-copy", children: [
|
|
5329
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "pollar-modal-title", children: title }),
|
|
5330
|
+
step === "form" && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "pollar-send-subtitle", children: [
|
|
5331
|
+
"Transfer assets to another ",
|
|
5332
|
+
chainLabel(selectedChain),
|
|
5333
|
+
" wallet"
|
|
5334
|
+
] })
|
|
5335
|
+
] })
|
|
4018
5336
|
] }),
|
|
4019
5337
|
!isInProgress && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-modal-header-actions", children: [
|
|
4020
5338
|
step === "form" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -4026,58 +5344,23 @@ function SendModalTemplate({
|
|
|
4026
5344
|
disabled: isLoadingBalance,
|
|
4027
5345
|
"aria-label": "Refresh",
|
|
4028
5346
|
title: "Refresh balances",
|
|
4029
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4030
|
-
"svg",
|
|
4031
|
-
{
|
|
4032
|
-
className: isLoadingBalance ? "pollar-modal-refresh-icon pollar-spinning" : "pollar-modal-refresh-icon",
|
|
4033
|
-
width: "16",
|
|
4034
|
-
height: "16",
|
|
4035
|
-
viewBox: "0 0 16 16",
|
|
4036
|
-
fill: "none",
|
|
4037
|
-
"aria-hidden": true,
|
|
4038
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4039
|
-
"path",
|
|
4040
|
-
{
|
|
4041
|
-
d: "M13.5 8a5.5 5.5 0 1 1-1.6-3.9M13.5 2v3h-3",
|
|
4042
|
-
stroke: "currentColor",
|
|
4043
|
-
strokeWidth: "1.6",
|
|
4044
|
-
strokeLinecap: "round",
|
|
4045
|
-
strokeLinejoin: "round"
|
|
4046
|
-
}
|
|
4047
|
-
)
|
|
4048
|
-
}
|
|
4049
|
-
)
|
|
5347
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(RefreshIcon, { spinning: isLoadingBalance })
|
|
4050
5348
|
}
|
|
4051
5349
|
),
|
|
4052
5350
|
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-modal-close", onClick: onClose, "aria-label": "Close", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M2 2l12 12M14 2L2 14", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) }) })
|
|
4053
5351
|
] })
|
|
4054
5352
|
] }),
|
|
4055
5353
|
step === "form" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
4056
|
-
/* @__PURE__ */ jsxRuntime.jsx(ChainSelect, { value: selectedChain, options: chains, onChange: onSelectChain, disabled: isLoadingBalance }),
|
|
4057
|
-
walletAddress && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-address-row", children: [
|
|
4058
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-address", children: cropAddress(walletAddress) }),
|
|
4059
|
-
/* @__PURE__ */ jsxRuntime.jsx(CopyButton, { value: walletAddress, label: "Copy wallet address" })
|
|
4060
|
-
] }),
|
|
5354
|
+
chains && onSelectChain && /* @__PURE__ */ jsxRuntime.jsx(ChainSelect, { value: selectedChain, options: chains, onChange: onSelectChain, disabled: isLoadingBalance }),
|
|
4061
5355
|
!canSendOnChain && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-empty", children: "Sending is not available on this network yet." }),
|
|
5356
|
+
canSendOnChain && notReadyReason && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-empty", children: notReadyReason }),
|
|
4062
5357
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4063
|
-
|
|
5358
|
+
SendAssetSelector,
|
|
4064
5359
|
{
|
|
4065
|
-
|
|
4066
|
-
|
|
5360
|
+
assets,
|
|
5361
|
+
selectedAsset,
|
|
4067
5362
|
loading: isLoadingBalance,
|
|
4068
|
-
|
|
4069
|
-
options: assets.map((a) => ({
|
|
4070
|
-
key: assetKey3(a),
|
|
4071
|
-
code: a.code,
|
|
4072
|
-
// Unreadable (null) drops the "- X available" suffix instead of
|
|
4073
|
-
// claiming a zero balance.
|
|
4074
|
-
available: a.available ?? void 0,
|
|
4075
|
-
enabledInApp: a.enabledInApp
|
|
4076
|
-
})),
|
|
4077
|
-
onChange: (key) => {
|
|
4078
|
-
const found = assets.find((a) => assetKey3(a) === key);
|
|
4079
|
-
if (found) onSelectAsset(found);
|
|
4080
|
-
}
|
|
5363
|
+
onSelectAsset
|
|
4081
5364
|
}
|
|
4082
5365
|
),
|
|
4083
5366
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-send-field", children: [
|
|
@@ -4090,30 +5373,50 @@ function SendModalTemplate({
|
|
|
4090
5373
|
selectedAsset.code
|
|
4091
5374
|
] })
|
|
4092
5375
|
] }),
|
|
4093
|
-
/* @__PURE__ */ jsxRuntime.
|
|
4094
|
-
|
|
4095
|
-
|
|
4096
|
-
|
|
4097
|
-
|
|
4098
|
-
|
|
4099
|
-
|
|
4100
|
-
|
|
4101
|
-
|
|
4102
|
-
|
|
4103
|
-
|
|
5376
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-send-input-shell", children: [
|
|
5377
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5378
|
+
"input",
|
|
5379
|
+
{
|
|
5380
|
+
className: "pollar-input pollar-send-amount-input",
|
|
5381
|
+
type: "text",
|
|
5382
|
+
inputMode: "decimal",
|
|
5383
|
+
placeholder: "0.00",
|
|
5384
|
+
value: amount,
|
|
5385
|
+
onChange: (e) => onAmountChange(e.target.value),
|
|
5386
|
+
"aria-label": "Amount"
|
|
5387
|
+
}
|
|
5388
|
+
),
|
|
5389
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-send-input-suffix", children: [
|
|
5390
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5391
|
+
"button",
|
|
5392
|
+
{
|
|
5393
|
+
type: "button",
|
|
5394
|
+
className: "pollar-send-inline-action",
|
|
5395
|
+
onClick: onMax,
|
|
5396
|
+
disabled: !selectedAsset?.available,
|
|
5397
|
+
children: "Max"
|
|
5398
|
+
}
|
|
5399
|
+
),
|
|
5400
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: selectedAsset?.code ?? "" })
|
|
5401
|
+
] })
|
|
5402
|
+
] })
|
|
4104
5403
|
] }),
|
|
4105
5404
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-send-field", children: [
|
|
4106
|
-
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "pollar-send-label", children: "Destination wallet" }),
|
|
4107
|
-
/* @__PURE__ */ jsxRuntime.
|
|
4108
|
-
|
|
4109
|
-
|
|
4110
|
-
|
|
4111
|
-
|
|
4112
|
-
|
|
4113
|
-
|
|
4114
|
-
|
|
4115
|
-
|
|
4116
|
-
|
|
5405
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "pollar-send-label", children: "Destination wallet" }),
|
|
5406
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-send-input-shell", children: [
|
|
5407
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5408
|
+
"input",
|
|
5409
|
+
{
|
|
5410
|
+
className: "pollar-input pollar-send-destination-input",
|
|
5411
|
+
type: "text",
|
|
5412
|
+
placeholder: "G\u2026",
|
|
5413
|
+
value: destination,
|
|
5414
|
+
onChange: (e) => onDestinationChange(e.target.value),
|
|
5415
|
+
"aria-label": "Destination wallet"
|
|
5416
|
+
}
|
|
5417
|
+
),
|
|
5418
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-send-inline-action", onClick: onPaste, children: "Paste" })
|
|
5419
|
+
] })
|
|
4117
5420
|
] }),
|
|
4118
5421
|
formError && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-error", children: formError }),
|
|
4119
5422
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-actions", children: /* @__PURE__ */ jsxRuntime.jsx("button", { className: "pollar-btn-primary", onClick: onSubmit, disabled: !canSubmit, children: "Continue" }) })
|
|
@@ -4154,7 +5457,6 @@ function SendModal({ onClose }) {
|
|
|
4154
5457
|
signAndSubmitTx,
|
|
4155
5458
|
tx: transaction,
|
|
4156
5459
|
wallet,
|
|
4157
|
-
wallets,
|
|
4158
5460
|
network,
|
|
4159
5461
|
styles
|
|
4160
5462
|
} = usePollar();
|
|
@@ -4173,8 +5475,8 @@ function SendModal({ onClose }) {
|
|
|
4173
5475
|
react.useEffect(() => {
|
|
4174
5476
|
if (selectedChain === null && chains.length > 0) setSelectedChain(chains[0]);
|
|
4175
5477
|
}, [chains, selectedChain]);
|
|
4176
|
-
const walletAddress = addressForChain(wallets, selectedChain);
|
|
4177
5478
|
const canSendOnChain = selectedChain === "STELLAR" || selectedChain === "SOLANA";
|
|
5479
|
+
const notReadyReason = walletNotReadyReason(wallet, selectedChain);
|
|
4178
5480
|
const isBaseUnitChain = selectedChain === "SOLANA";
|
|
4179
5481
|
react.useEffect(() => {
|
|
4180
5482
|
void refreshWalletBalance();
|
|
@@ -4221,6 +5523,10 @@ function SendModal({ onClose }) {
|
|
|
4221
5523
|
setFormError("Sending is not available on this network yet.");
|
|
4222
5524
|
return;
|
|
4223
5525
|
}
|
|
5526
|
+
if (notReadyReason) {
|
|
5527
|
+
setFormError(notReadyReason);
|
|
5528
|
+
return;
|
|
5529
|
+
}
|
|
4224
5530
|
if (!selectedAsset) {
|
|
4225
5531
|
setFormError("Select an asset");
|
|
4226
5532
|
return;
|
|
@@ -4271,6 +5577,29 @@ function SendModal({ onClose }) {
|
|
|
4271
5577
|
void signAndSubmitTx(transaction.buildData.unsignedXdr);
|
|
4272
5578
|
}
|
|
4273
5579
|
}
|
|
5580
|
+
function handleMax() {
|
|
5581
|
+
if (selectedAsset?.available !== null && selectedAsset?.available !== void 0) {
|
|
5582
|
+
setAmount(selectedAsset.available);
|
|
5583
|
+
setFormError("");
|
|
5584
|
+
}
|
|
5585
|
+
}
|
|
5586
|
+
async function handlePaste() {
|
|
5587
|
+
if (!navigator.clipboard?.readText) {
|
|
5588
|
+
setFormError("Clipboard access is not available. Paste the address manually.");
|
|
5589
|
+
return;
|
|
5590
|
+
}
|
|
5591
|
+
try {
|
|
5592
|
+
const value = (await navigator.clipboard.readText()).trim();
|
|
5593
|
+
if (!value) {
|
|
5594
|
+
setFormError("The clipboard is empty.");
|
|
5595
|
+
return;
|
|
5596
|
+
}
|
|
5597
|
+
setDestination(value);
|
|
5598
|
+
setFormError("");
|
|
5599
|
+
} catch {
|
|
5600
|
+
setFormError("Could not read the clipboard. Paste the address manually.");
|
|
5601
|
+
}
|
|
5602
|
+
}
|
|
4274
5603
|
function handleCopyHash() {
|
|
4275
5604
|
if (!hash) return;
|
|
4276
5605
|
navigator.clipboard.writeText(hash).then(() => {
|
|
@@ -4304,8 +5633,8 @@ function SendModal({ onClose }) {
|
|
|
4304
5633
|
selectedAsset,
|
|
4305
5634
|
chains,
|
|
4306
5635
|
selectedChain,
|
|
4307
|
-
walletAddress,
|
|
4308
5636
|
canSendOnChain,
|
|
5637
|
+
notReadyReason,
|
|
4309
5638
|
onSelectChain: setSelectedChain,
|
|
4310
5639
|
amount,
|
|
4311
5640
|
destination,
|
|
@@ -4323,6 +5652,8 @@ function SendModal({ onClose }) {
|
|
|
4323
5652
|
onRefresh: () => void refreshWalletBalance(),
|
|
4324
5653
|
onSelectAsset: setSelectedAsset,
|
|
4325
5654
|
onAmountChange: setAmount,
|
|
5655
|
+
onMax: handleMax,
|
|
5656
|
+
onPaste: handlePaste,
|
|
4326
5657
|
onDestinationChange: setDestination,
|
|
4327
5658
|
onSubmit: () => void handleSubmit(),
|
|
4328
5659
|
onSignAndSend: handleSignAndSend,
|
|
@@ -4337,15 +5668,77 @@ function assetOptionKey(o) {
|
|
|
4337
5668
|
return `${o.code}:${o.issuer ?? "native"}`;
|
|
4338
5669
|
}
|
|
4339
5670
|
var PROVIDER_LABELS = {
|
|
4340
|
-
auto: "Best price
|
|
5671
|
+
auto: "Best price",
|
|
4341
5672
|
aquarius: "Aquarius",
|
|
4342
5673
|
soroswap: "Soroswap",
|
|
4343
5674
|
sdex: "Stellar DEX"
|
|
4344
5675
|
};
|
|
4345
|
-
function
|
|
5676
|
+
function formatAmount2(value) {
|
|
5677
|
+
if (value === void 0) return "\u2014";
|
|
4346
5678
|
const n = parseFloat(value);
|
|
4347
5679
|
return isNaN(n) ? value : n.toLocaleString(void 0, { maximumFractionDigits: 7 });
|
|
4348
5680
|
}
|
|
5681
|
+
function formatRate(numerator, denominator) {
|
|
5682
|
+
const parse = (value) => {
|
|
5683
|
+
const trimmed = value.trim();
|
|
5684
|
+
if (!/^\d+(\.\d+)?$/.test(trimmed)) return null;
|
|
5685
|
+
const [whole2 = "0", fraction2 = ""] = trimmed.split(".");
|
|
5686
|
+
return { digits: BigInt(`${whole2}${fraction2}`), scale: fraction2.length };
|
|
5687
|
+
};
|
|
5688
|
+
const top = parse(numerator);
|
|
5689
|
+
const bottom = parse(denominator);
|
|
5690
|
+
if (!top || !bottom || bottom.digits === 0n || top.digits === 0n) return null;
|
|
5691
|
+
const precision = 8;
|
|
5692
|
+
const scaledNumerator = top.digits * 10n ** BigInt(bottom.scale + precision);
|
|
5693
|
+
const scaledDenominator = bottom.digits * 10n ** BigInt(top.scale);
|
|
5694
|
+
const scaled = scaledNumerator / scaledDenominator;
|
|
5695
|
+
const whole = scaled / 10n ** BigInt(precision);
|
|
5696
|
+
const fraction = (scaled % 10n ** BigInt(precision)).toString().padStart(precision, "0").replace(/0+$/, "");
|
|
5697
|
+
return fraction ? `${whole}.${fraction}` : whole.toString();
|
|
5698
|
+
}
|
|
5699
|
+
function AssetIcon2({ code }) {
|
|
5700
|
+
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-swap-asset-icon", "aria-hidden": true, children: code.slice(0, 2).toUpperCase() });
|
|
5701
|
+
}
|
|
5702
|
+
function AssetPill({
|
|
5703
|
+
label,
|
|
5704
|
+
value,
|
|
5705
|
+
options,
|
|
5706
|
+
disabled,
|
|
5707
|
+
onChange
|
|
5708
|
+
}) {
|
|
5709
|
+
const selected = options.find((option) => assetOptionKey(option) === value);
|
|
5710
|
+
const appAssets = options.filter((option) => option.enabledInApp);
|
|
5711
|
+
const otherAssets = options.filter((option) => !option.enabledInApp);
|
|
5712
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "pollar-swap-asset-pill-wrap", children: [
|
|
5713
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: label }),
|
|
5714
|
+
/* @__PURE__ */ jsxRuntime.jsx(AssetIcon2, { code: selected?.code ?? "\u2014" }),
|
|
5715
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
5716
|
+
"select",
|
|
5717
|
+
{
|
|
5718
|
+
className: "pollar-swap-asset-pill",
|
|
5719
|
+
"aria-label": label,
|
|
5720
|
+
value,
|
|
5721
|
+
disabled,
|
|
5722
|
+
onChange: (event) => onChange(event.target.value),
|
|
5723
|
+
children: [
|
|
5724
|
+
value === "" && /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", disabled: true, hidden: true }),
|
|
5725
|
+
appAssets.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("optgroup", { label: "App assets", children: appAssets.map((option) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: assetOptionKey(option), children: option.code }, assetOptionKey(option))) }),
|
|
5726
|
+
otherAssets.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("optgroup", { label: "Other assets", children: otherAssets.map((option) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: assetOptionKey(option), children: option.code }, assetOptionKey(option))) })
|
|
5727
|
+
]
|
|
5728
|
+
}
|
|
5729
|
+
),
|
|
5730
|
+
/* @__PURE__ */ jsxRuntime.jsx("svg", { className: "pollar-swap-chevron", width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
5731
|
+
"path",
|
|
5732
|
+
{
|
|
5733
|
+
d: "m3.5 5.25 3.5 3.5 3.5-3.5",
|
|
5734
|
+
stroke: "currentColor",
|
|
5735
|
+
strokeWidth: "1.5",
|
|
5736
|
+
strokeLinecap: "round",
|
|
5737
|
+
strokeLinejoin: "round"
|
|
5738
|
+
}
|
|
5739
|
+
) })
|
|
5740
|
+
] });
|
|
5741
|
+
}
|
|
4349
5742
|
function SwapModalTemplate({
|
|
4350
5743
|
theme,
|
|
4351
5744
|
accentColor,
|
|
@@ -4381,6 +5774,8 @@ function SwapModalTemplate({
|
|
|
4381
5774
|
onSelectSell,
|
|
4382
5775
|
onSelectBuy,
|
|
4383
5776
|
onAddCustomToken,
|
|
5777
|
+
onReverse,
|
|
5778
|
+
onMax,
|
|
4384
5779
|
onAmountChange,
|
|
4385
5780
|
onProviderChange,
|
|
4386
5781
|
onSwap,
|
|
@@ -4407,19 +5802,29 @@ function SwapModalTemplate({
|
|
|
4407
5802
|
const cssVars = buildModalCssVars(theme, accentColor, styleOverrides);
|
|
4408
5803
|
const sellKey = selectedSell ? assetOptionKey(selectedSell) : "";
|
|
4409
5804
|
const buyKey = selectedBuy ? assetOptionKey(selectedBuy) : "";
|
|
4410
|
-
const
|
|
5805
|
+
const sameAsset = !!selectedSell && !!selectedBuy && sellKey === buyKey;
|
|
5806
|
+
const canSwap = !smartUnsupported && !sameAsset && !!selectedSell && !!selectedBuy && !!amount && !!quote && !quoteLoading && !isLoadingData;
|
|
5807
|
+
const rate = quote && amount ? formatRate(quote.amountOut, amount) : null;
|
|
4411
5808
|
const title = step === "form" ? "Swap" : txTitle;
|
|
5809
|
+
const selectSell = (key) => {
|
|
5810
|
+
const found = sellOptions.find((option) => assetOptionKey(option) === key);
|
|
5811
|
+
if (found) onSelectSell(found);
|
|
5812
|
+
};
|
|
5813
|
+
const selectBuy = (key) => {
|
|
5814
|
+
const found = buyOptions.find((option) => assetOptionKey(option) === key);
|
|
5815
|
+
if (found) onSelectBuy(found);
|
|
5816
|
+
};
|
|
4412
5817
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4413
5818
|
"div",
|
|
4414
5819
|
{
|
|
4415
|
-
className: "pollar-modal-card pollar-
|
|
5820
|
+
className: "pollar-modal-card pollar-swap-modal",
|
|
4416
5821
|
"data-theme": theme,
|
|
4417
5822
|
style: cssVars,
|
|
4418
|
-
onClick: (
|
|
5823
|
+
onClick: (event) => event.stopPropagation(),
|
|
4419
5824
|
children: [
|
|
4420
5825
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-modal-header", children: [
|
|
4421
5826
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-send-header-left", children: [
|
|
4422
|
-
showBack && /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-modal-close", onClick: onBack, "aria-label": "Back", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M10
|
|
5827
|
+
showBack && /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-modal-close", onClick: onBack, "aria-label": "Back", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M10 3 5 8l5 5", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }) }),
|
|
4423
5828
|
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "pollar-modal-title", children: title })
|
|
4424
5829
|
] }),
|
|
4425
5830
|
!isInProgress && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-modal-header-actions", children: [
|
|
@@ -4432,16 +5837,7 @@ function SwapModalTemplate({
|
|
|
4432
5837
|
disabled: configLoading || isLoadingData,
|
|
4433
5838
|
"aria-label": "Refresh",
|
|
4434
5839
|
title: "Refresh balances and options",
|
|
4435
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4436
|
-
"path",
|
|
4437
|
-
{
|
|
4438
|
-
d: "M13.5 8a5.5 5.5 0 1 1-1.6-3.9M13.5 2.5v3h-3",
|
|
4439
|
-
stroke: "currentColor",
|
|
4440
|
-
strokeWidth: "1.6",
|
|
4441
|
-
strokeLinecap: "round",
|
|
4442
|
-
strokeLinejoin: "round"
|
|
4443
|
-
}
|
|
4444
|
-
) })
|
|
5840
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(RefreshIcon, { spinning: configLoading || isLoadingData })
|
|
4445
5841
|
}
|
|
4446
5842
|
),
|
|
4447
5843
|
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-modal-close", onClick: onClose, "aria-label": "Close", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M2 2l12 12M14 2L2 14", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) }) })
|
|
@@ -4450,174 +5846,205 @@ function SwapModalTemplate({
|
|
|
4450
5846
|
step === "form" && !configLoading && swapUnavailable && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-error", children: "Swap is not available for this app." }),
|
|
4451
5847
|
step === "form" && !swapUnavailable && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
4452
5848
|
smartUnsupported && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-error", children: "Swaps are not yet available for smart (passkey) wallets." }),
|
|
4453
|
-
/* @__PURE__ */ jsxRuntime.
|
|
4454
|
-
|
|
4455
|
-
|
|
4456
|
-
|
|
4457
|
-
|
|
4458
|
-
|
|
4459
|
-
|
|
4460
|
-
|
|
4461
|
-
|
|
4462
|
-
|
|
4463
|
-
code: o.code,
|
|
4464
|
-
available: o.available,
|
|
4465
|
-
enabledInApp: o.enabledInApp
|
|
4466
|
-
})),
|
|
4467
|
-
onChange: (key) => {
|
|
4468
|
-
const found = sellOptions.find((o) => assetOptionKey(o) === key);
|
|
4469
|
-
if (found) onSelectSell(found);
|
|
4470
|
-
}
|
|
4471
|
-
}
|
|
4472
|
-
),
|
|
4473
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-send-field", children: [
|
|
4474
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-send-label-row", children: [
|
|
4475
|
-
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "pollar-send-label", children: "Amount" }),
|
|
4476
|
-
selectedSell?.available !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "pollar-send-hint", children: [
|
|
4477
|
-
"Available: ",
|
|
4478
|
-
formatAmount3(selectedSell.available),
|
|
4479
|
-
" ",
|
|
4480
|
-
selectedSell.code
|
|
4481
|
-
] })
|
|
4482
|
-
] }),
|
|
4483
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4484
|
-
"input",
|
|
4485
|
-
{
|
|
4486
|
-
className: "pollar-input",
|
|
4487
|
-
type: "text",
|
|
4488
|
-
inputMode: "decimal",
|
|
4489
|
-
placeholder: "0.00",
|
|
4490
|
-
value: amount,
|
|
4491
|
-
disabled: configLoading,
|
|
4492
|
-
onChange: (e) => onAmountChange(e.target.value)
|
|
4493
|
-
}
|
|
4494
|
-
)
|
|
4495
|
-
] }),
|
|
4496
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4497
|
-
AssetSelect,
|
|
4498
|
-
{
|
|
4499
|
-
label: "You receive",
|
|
4500
|
-
value: buyKey,
|
|
4501
|
-
loading: isLoadingData || configLoading,
|
|
4502
|
-
loadingLabel: "Loading assets\u2026",
|
|
4503
|
-
disabled: configLoading,
|
|
4504
|
-
options: buyOptions.map((o) => ({
|
|
4505
|
-
key: assetOptionKey(o),
|
|
4506
|
-
code: o.code,
|
|
4507
|
-
enabledInApp: o.enabledInApp
|
|
4508
|
-
})),
|
|
4509
|
-
onChange: (key) => {
|
|
4510
|
-
const found = buyOptions.find((o) => assetOptionKey(o) === key);
|
|
4511
|
-
if (found) onSelectBuy(found);
|
|
4512
|
-
},
|
|
4513
|
-
children: customOpen ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-swap-custom", children: [
|
|
4514
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4515
|
-
"input",
|
|
4516
|
-
{
|
|
4517
|
-
className: "pollar-input",
|
|
4518
|
-
type: "text",
|
|
4519
|
-
placeholder: "Code (e.g. USDC)",
|
|
4520
|
-
value: customCode,
|
|
4521
|
-
onChange: (e) => setCustomCode(e.target.value)
|
|
4522
|
-
}
|
|
4523
|
-
),
|
|
5849
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-swap-panels", children: [
|
|
5850
|
+
/* @__PURE__ */ jsxRuntime.jsxs("section", { className: "pollar-swap-panel", "aria-labelledby": "pollar-swap-pay-label", children: [
|
|
5851
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-swap-panel-heading", children: [
|
|
5852
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { id: "pollar-swap-pay-label", className: "pollar-swap-panel-label", children: "You pay" }),
|
|
5853
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "pollar-swap-balance", children: [
|
|
5854
|
+
"Balance: ",
|
|
5855
|
+
formatAmount2(selectedSell?.available)
|
|
5856
|
+
] })
|
|
5857
|
+
] }),
|
|
5858
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-swap-panel-main", children: [
|
|
4524
5859
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4525
5860
|
"input",
|
|
4526
5861
|
{
|
|
4527
|
-
className: "pollar-
|
|
5862
|
+
className: "pollar-swap-amount",
|
|
4528
5863
|
type: "text",
|
|
4529
|
-
|
|
4530
|
-
|
|
4531
|
-
|
|
5864
|
+
inputMode: "decimal",
|
|
5865
|
+
"aria-label": "Amount to pay",
|
|
5866
|
+
placeholder: "0.00",
|
|
5867
|
+
value: amount,
|
|
5868
|
+
disabled: configLoading || isLoadingData,
|
|
5869
|
+
onChange: (event) => onAmountChange(event.target.value)
|
|
4532
5870
|
}
|
|
4533
5871
|
),
|
|
4534
|
-
|
|
4535
|
-
|
|
4536
|
-
|
|
5872
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-swap-panel-selector", children: [
|
|
5873
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5874
|
+
AssetPill,
|
|
5875
|
+
{
|
|
5876
|
+
label: "Asset to pay",
|
|
5877
|
+
value: sellKey,
|
|
5878
|
+
options: sellOptions,
|
|
5879
|
+
disabled: configLoading || isLoadingData,
|
|
5880
|
+
onChange: selectSell
|
|
5881
|
+
}
|
|
5882
|
+
),
|
|
4537
5883
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4538
5884
|
"button",
|
|
4539
5885
|
{
|
|
4540
5886
|
type: "button",
|
|
4541
|
-
className: "pollar-swap-
|
|
4542
|
-
onClick:
|
|
4543
|
-
|
|
4544
|
-
|
|
4545
|
-
},
|
|
4546
|
-
children: "Cancel"
|
|
5887
|
+
className: "pollar-swap-max",
|
|
5888
|
+
onClick: onMax,
|
|
5889
|
+
disabled: !selectedSell?.available || configLoading || isLoadingData,
|
|
5890
|
+
children: "Max"
|
|
4547
5891
|
}
|
|
4548
5892
|
)
|
|
4549
5893
|
] })
|
|
4550
|
-
] })
|
|
5894
|
+
] })
|
|
5895
|
+
] }),
|
|
5896
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5897
|
+
"button",
|
|
5898
|
+
{
|
|
5899
|
+
type: "button",
|
|
5900
|
+
className: "pollar-swap-reverse",
|
|
5901
|
+
onClick: onReverse,
|
|
5902
|
+
disabled: !selectedSell || !selectedBuy,
|
|
5903
|
+
"aria-label": "Swap pay and receive assets",
|
|
5904
|
+
title: "Swap pay and receive assets",
|
|
5905
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "17", height: "17", viewBox: "0 0 17 17", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
5906
|
+
"path",
|
|
5907
|
+
{
|
|
5908
|
+
d: "M5 3v10M5 3 2.5 5.5M5 3l2.5 2.5M12 14V4M12 14l2.5-2.5M12 14 9.5 11.5",
|
|
5909
|
+
stroke: "currentColor",
|
|
5910
|
+
strokeWidth: "1.6",
|
|
5911
|
+
strokeLinecap: "round",
|
|
5912
|
+
strokeLinejoin: "round"
|
|
5913
|
+
}
|
|
5914
|
+
) })
|
|
5915
|
+
}
|
|
5916
|
+
),
|
|
5917
|
+
/* @__PURE__ */ jsxRuntime.jsxs("section", { className: "pollar-swap-panel", "aria-labelledby": "pollar-swap-receive-label", children: [
|
|
5918
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-swap-panel-heading", children: [
|
|
5919
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { id: "pollar-swap-receive-label", className: "pollar-swap-panel-label", children: "You receive" }),
|
|
5920
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "pollar-swap-balance", children: [
|
|
5921
|
+
"Balance: ",
|
|
5922
|
+
formatAmount2(selectedBuy?.available)
|
|
5923
|
+
] })
|
|
5924
|
+
] }),
|
|
5925
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-swap-panel-main", children: [
|
|
5926
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: `pollar-swap-output${quoteLoading ? " is-loading" : ""}`, "aria-live": "polite", children: quoteLoading ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-spinner pollar-spinner-sm" }) : formatAmount2(quote?.amountOut) }),
|
|
5927
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-swap-panel-selector", children: [
|
|
5928
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5929
|
+
AssetPill,
|
|
5930
|
+
{
|
|
5931
|
+
label: "Asset to receive",
|
|
5932
|
+
value: buyKey,
|
|
5933
|
+
options: buyOptions,
|
|
5934
|
+
disabled: configLoading || isLoadingData,
|
|
5935
|
+
onChange: selectBuy
|
|
5936
|
+
}
|
|
5937
|
+
),
|
|
5938
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-swap-panel-note", children: "Quoted amount" })
|
|
5939
|
+
] })
|
|
5940
|
+
] })
|
|
5941
|
+
] })
|
|
5942
|
+
] }),
|
|
5943
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-swap-custom-area", children: customOpen ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-swap-custom", children: [
|
|
5944
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5945
|
+
"input",
|
|
5946
|
+
{
|
|
5947
|
+
className: "pollar-input",
|
|
5948
|
+
type: "text",
|
|
5949
|
+
placeholder: "Code (e.g. USDC)",
|
|
5950
|
+
value: customCode,
|
|
5951
|
+
onChange: (e) => setCustomCode(e.target.value)
|
|
5952
|
+
}
|
|
5953
|
+
),
|
|
5954
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5955
|
+
"input",
|
|
5956
|
+
{
|
|
5957
|
+
className: "pollar-input",
|
|
5958
|
+
type: "text",
|
|
5959
|
+
placeholder: "Issuer (G...)",
|
|
5960
|
+
value: customIssuer,
|
|
5961
|
+
onChange: (e) => setCustomIssuer(e.target.value)
|
|
5962
|
+
}
|
|
5963
|
+
),
|
|
5964
|
+
customError && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-error", children: customError }),
|
|
5965
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-swap-custom-actions", children: [
|
|
5966
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-btn-primary", onClick: submitCustomToken, children: "Add token" }),
|
|
5967
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4551
5968
|
"button",
|
|
4552
5969
|
{
|
|
4553
5970
|
type: "button",
|
|
4554
|
-
className: "pollar-swap-custom-
|
|
4555
|
-
|
|
4556
|
-
|
|
4557
|
-
|
|
5971
|
+
className: "pollar-swap-custom-cancel",
|
|
5972
|
+
onClick: () => {
|
|
5973
|
+
setCustomOpen(false);
|
|
5974
|
+
setCustomError("");
|
|
5975
|
+
},
|
|
5976
|
+
children: "Cancel"
|
|
4558
5977
|
}
|
|
4559
5978
|
)
|
|
5979
|
+
] })
|
|
5980
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
5981
|
+
"button",
|
|
5982
|
+
{
|
|
5983
|
+
type: "button",
|
|
5984
|
+
className: "pollar-swap-custom-toggle",
|
|
5985
|
+
disabled: configLoading,
|
|
5986
|
+
onClick: () => setCustomOpen(true),
|
|
5987
|
+
children: "+ Add a token by code / issuer"
|
|
4560
5988
|
}
|
|
4561
|
-
),
|
|
4562
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-
|
|
4563
|
-
/* @__PURE__ */ jsxRuntime.jsx("
|
|
4564
|
-
|
|
5989
|
+
) }),
|
|
5990
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-swap-rate-row", children: [
|
|
5991
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-swap-rate", "aria-live": "polite", children: rate && selectedSell && selectedBuy ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
5992
|
+
"1 ",
|
|
5993
|
+
selectedSell.code,
|
|
5994
|
+
" \u2248 ",
|
|
5995
|
+
rate,
|
|
5996
|
+
" ",
|
|
5997
|
+
selectedBuy.code
|
|
5998
|
+
] }) : quoteLoading ? "Updating rate\u2026" : "Exchange rate unavailable" }),
|
|
5999
|
+
configLoading ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-swap-route-pill", children: [
|
|
4565
6000
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-spinner pollar-spinner-sm" }),
|
|
4566
|
-
|
|
4567
|
-
] }) : /* @__PURE__ */ jsxRuntime.
|
|
4568
|
-
"
|
|
4569
|
-
|
|
4570
|
-
|
|
4571
|
-
|
|
4572
|
-
|
|
4573
|
-
|
|
4574
|
-
|
|
4575
|
-
|
|
4576
|
-
|
|
4577
|
-
|
|
4578
|
-
|
|
4579
|
-
|
|
4580
|
-
|
|
6001
|
+
" Loading"
|
|
6002
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "pollar-swap-route-wrap", children: [
|
|
6003
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Route" }),
|
|
6004
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6005
|
+
"select",
|
|
6006
|
+
{
|
|
6007
|
+
className: "pollar-swap-route-pill",
|
|
6008
|
+
"aria-label": "Route",
|
|
6009
|
+
value: provider,
|
|
6010
|
+
disabled: providers.length === 0,
|
|
6011
|
+
onChange: (event) => onProviderChange(event.target.value),
|
|
6012
|
+
children: providers.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("option", { value: provider, children: PROVIDER_LABELS[provider] }) : providers.map((p) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: p, children: PROVIDER_LABELS[p] }, p))
|
|
6013
|
+
}
|
|
6014
|
+
)
|
|
6015
|
+
] })
|
|
4581
6016
|
] }),
|
|
4582
6017
|
!quoteLoading && quoteError && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-error", children: quoteError }),
|
|
4583
|
-
!quoteLoading && !quoteError && quote && selectedBuy && /* @__PURE__ */ jsxRuntime.
|
|
4584
|
-
|
|
4585
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-send-hint", children: "You receive" }),
|
|
4586
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
4587
|
-
"~ ",
|
|
4588
|
-
formatAmount3(quote.amountOut),
|
|
4589
|
-
" ",
|
|
4590
|
-
selectedBuy.code
|
|
4591
|
-
] })
|
|
4592
|
-
] }),
|
|
6018
|
+
!quoteLoading && !quoteError && !quote && selectedSell && selectedBuy && !!amount && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-send-hint", children: "No route found for this pair." }),
|
|
6019
|
+
quote && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-swap-quote", children: [
|
|
4593
6020
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-swap-quote-row", children: [
|
|
4594
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", {
|
|
4595
|
-
/* @__PURE__ */ jsxRuntime.jsxs("
|
|
4596
|
-
|
|
6021
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Minimum received" }),
|
|
6022
|
+
/* @__PURE__ */ jsxRuntime.jsxs("strong", { children: [
|
|
6023
|
+
formatAmount2(quote.minReceived),
|
|
4597
6024
|
" ",
|
|
4598
|
-
selectedBuy
|
|
6025
|
+
selectedBuy?.code
|
|
4599
6026
|
] })
|
|
4600
6027
|
] }),
|
|
4601
6028
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-swap-quote-row", children: [
|
|
4602
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", {
|
|
4603
|
-
/* @__PURE__ */ jsxRuntime.jsxs("
|
|
6029
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Price impact" }),
|
|
6030
|
+
/* @__PURE__ */ jsxRuntime.jsxs("strong", { children: [
|
|
4604
6031
|
quote.priceImpactPct,
|
|
4605
6032
|
"%"
|
|
4606
6033
|
] })
|
|
4607
6034
|
] }),
|
|
4608
6035
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-swap-quote-row", children: [
|
|
4609
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", {
|
|
4610
|
-
/* @__PURE__ */ jsxRuntime.jsx("
|
|
6036
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Route" }),
|
|
6037
|
+
/* @__PURE__ */ jsxRuntime.jsx("strong", { children: PROVIDER_LABELS[quote.provider] })
|
|
4611
6038
|
] })
|
|
4612
6039
|
] }),
|
|
4613
|
-
!quoteLoading && !quoteError && !quote && selectedSell && selectedBuy && !!amount && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-send-hint", children: "No route found for this pair." }),
|
|
4614
6040
|
buyNeedsTrustline && selectedBuy && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-swap-trustline-notice", children: [
|
|
4615
6041
|
"To receive ",
|
|
4616
6042
|
selectedBuy.code,
|
|
4617
6043
|
" your wallet needs a trustline. Swapping will create it first (~0.5 XLM reserve, refundable if you later remove it)."
|
|
4618
6044
|
] }),
|
|
6045
|
+
sameAsset && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-error", children: "Choose two different assets to swap." }),
|
|
4619
6046
|
formError && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-error", children: formError }),
|
|
4620
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-actions", children: /* @__PURE__ */ jsxRuntime.jsx("button", { className: "pollar-btn-primary", onClick: onSwap, disabled: !canSwap, children: buyNeedsTrustline ? "Create trustline & swap" : "Swap" }) })
|
|
6047
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-actions", children: /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-btn-primary", onClick: onSwap, disabled: !canSwap, children: buyNeedsTrustline ? "Create trustline & swap" : "Swap" }) })
|
|
4621
6048
|
] }),
|
|
4622
6049
|
step === "tx" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
4623
6050
|
TxStatusView,
|
|
@@ -4635,7 +6062,7 @@ function SwapModalTemplate({
|
|
|
4635
6062
|
onDone
|
|
4636
6063
|
}
|
|
4637
6064
|
),
|
|
4638
|
-
/* @__PURE__ */ jsxRuntime.jsx(PollarModalFooter, {})
|
|
6065
|
+
/* @__PURE__ */ jsxRuntime.jsx(PollarModalFooter, { shield: true })
|
|
4639
6066
|
]
|
|
4640
6067
|
}
|
|
4641
6068
|
);
|
|
@@ -4716,6 +6143,7 @@ function SwapModal({ onClose }) {
|
|
|
4716
6143
|
const balances = walletBalance.step === "loaded" ? walletBalance.data.balances : [];
|
|
4717
6144
|
const assetRecords = enabledAssets.step === "loaded" ? enabledAssets.data.assets : [];
|
|
4718
6145
|
const isLoadingData = walletBalance.step === "loading" || enabledAssets.step === "loading";
|
|
6146
|
+
const availableFor = (code, issuer) => balances.find((b) => b.code === code && (b.issuer ?? "") === (issuer ?? ""))?.available ?? void 0;
|
|
4719
6147
|
const sellOptions = balances.filter(
|
|
4720
6148
|
(b) => (b.chain === void 0 || b.chain === "STELLAR") && (b.type === "native" || (b.type === "credit_alphanum4" || b.type === "credit_alphanum12") && !b.trustlineRemoved)
|
|
4721
6149
|
).map((b) => ({
|
|
@@ -4733,6 +6161,7 @@ function SwapModal({ onClose }) {
|
|
|
4733
6161
|
ref: toRef(a),
|
|
4734
6162
|
code: a.code,
|
|
4735
6163
|
issuer: a.issuer,
|
|
6164
|
+
available: availableFor(a.code, a.issuer),
|
|
4736
6165
|
enabledInApp: a.enabledInApp
|
|
4737
6166
|
}));
|
|
4738
6167
|
const enabledKeys = new Set(enabledBuy.map(optKey));
|
|
@@ -4740,11 +6169,14 @@ function SwapModal({ onClose }) {
|
|
|
4740
6169
|
ref: catalogRef(tk.code, tk.issuer),
|
|
4741
6170
|
code: tk.code,
|
|
4742
6171
|
issuer: tk.issuer,
|
|
6172
|
+
available: availableFor(tk.code, tk.issuer),
|
|
4743
6173
|
enabledInApp: false
|
|
4744
6174
|
})).filter((o) => !enabledKeys.has(optKey(o)));
|
|
4745
6175
|
const knownKeys = /* @__PURE__ */ new Set([...enabledKeys, ...catalogBuy.map(optKey)]);
|
|
4746
|
-
const customBuy = customTokens.filter((o) => !knownKeys.has(optKey(o)));
|
|
4747
|
-
const buyOptions = [...enabledBuy, ...catalogBuy, ...customBuy].filter(
|
|
6176
|
+
const customBuy = customTokens.filter((o) => !knownKeys.has(optKey(o))).map((o) => ({ ...o, available: availableFor(o.code, o.issuer) }));
|
|
6177
|
+
const buyOptions = [...enabledBuy, ...catalogBuy, ...customBuy].filter(
|
|
6178
|
+
(o) => optKey(o) !== buyKeyOfSell || optKey(o) === (selectedBuy ? optKey(selectedBuy) : "")
|
|
6179
|
+
);
|
|
4748
6180
|
react.useEffect(() => {
|
|
4749
6181
|
if (sellOptions.length === 0) return;
|
|
4750
6182
|
if (!selectedSell || !sellOptions.some((o) => optKey(o) === optKey(selectedSell))) {
|
|
@@ -4855,6 +6287,15 @@ function SwapModal({ onClose }) {
|
|
|
4855
6287
|
async function handleRetry() {
|
|
4856
6288
|
if (transaction.step === "error" && quote) await swap(quote);
|
|
4857
6289
|
}
|
|
6290
|
+
function handleMax() {
|
|
6291
|
+
if (selectedSell?.available !== void 0) setAmount(selectedSell.available);
|
|
6292
|
+
}
|
|
6293
|
+
function handleReverse() {
|
|
6294
|
+
if (!selectedSell || !selectedBuy) return;
|
|
6295
|
+
const previousSell = selectedSell;
|
|
6296
|
+
setSelectedSell(selectedBuy);
|
|
6297
|
+
setSelectedBuy(previousSell);
|
|
6298
|
+
}
|
|
4858
6299
|
function handleCopyHash() {
|
|
4859
6300
|
if (!hash) return;
|
|
4860
6301
|
navigator.clipboard.writeText(hash).then(() => {
|
|
@@ -4907,6 +6348,8 @@ function SwapModal({ onClose }) {
|
|
|
4907
6348
|
onRefresh: handleRefresh,
|
|
4908
6349
|
onSelectSell: setSelectedSell,
|
|
4909
6350
|
onSelectBuy: setSelectedBuy,
|
|
6351
|
+
onReverse: handleReverse,
|
|
6352
|
+
onMax: handleMax,
|
|
4910
6353
|
onAddCustomToken: addCustomToken,
|
|
4911
6354
|
onAmountChange: setAmount,
|
|
4912
6355
|
onProviderChange: setProvider,
|
|
@@ -4931,7 +6374,7 @@ var IN_FLIGHT_STEPS2 = [
|
|
|
4931
6374
|
"signing-submitting",
|
|
4932
6375
|
"building-signing-submitting"
|
|
4933
6376
|
];
|
|
4934
|
-
function
|
|
6377
|
+
function formatAmount3(value) {
|
|
4935
6378
|
const n = parseFloat(value);
|
|
4936
6379
|
return isNaN(n) ? value : n.toLocaleString(void 0, { maximumFractionDigits: 7 });
|
|
4937
6380
|
}
|
|
@@ -5245,7 +6688,7 @@ function EarnModal({ onClose }) {
|
|
|
5245
6688
|
tab === "deposit" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-swap-quote-row", children: [
|
|
5246
6689
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-send-hint", children: "In your wallet" }),
|
|
5247
6690
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
5248
|
-
walletAvailable != null ?
|
|
6691
|
+
walletAvailable != null ? formatAmount3(walletAvailable) : "\u2026",
|
|
5249
6692
|
" ",
|
|
5250
6693
|
assetCode
|
|
5251
6694
|
] })
|
|
@@ -5253,7 +6696,7 @@ function EarnModal({ onClose }) {
|
|
|
5253
6696
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-swap-quote-row", children: [
|
|
5254
6697
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-send-hint", children: "Your position" }),
|
|
5255
6698
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
5256
|
-
position ?
|
|
6699
|
+
position ? formatAmount3(position.balance) : "\u2026",
|
|
5257
6700
|
" ",
|
|
5258
6701
|
assetCode
|
|
5259
6702
|
] })
|
|
@@ -5271,13 +6714,13 @@ function EarnModal({ onClose }) {
|
|
|
5271
6714
|
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "pollar-send-label", children: tab === "deposit" ? "Amount" : "Withdraw amount" }),
|
|
5272
6715
|
tab === "deposit" && walletAvailable != null && /* @__PURE__ */ jsxRuntime.jsxs("button", { type: "button", className: "pollar-swap-custom-toggle", onClick: () => setAmount(walletAvailable), children: [
|
|
5273
6716
|
"Max: ",
|
|
5274
|
-
|
|
6717
|
+
formatAmount3(walletAvailable),
|
|
5275
6718
|
" ",
|
|
5276
6719
|
amountUnitLabel
|
|
5277
6720
|
] }),
|
|
5278
6721
|
tab === "withdraw" && position && /* @__PURE__ */ jsxRuntime.jsxs("button", { type: "button", className: "pollar-swap-custom-toggle", onClick: () => setAmount(position.withdrawable), children: [
|
|
5279
6722
|
"Max: ",
|
|
5280
|
-
|
|
6723
|
+
formatAmount3(position.withdrawable),
|
|
5281
6724
|
" ",
|
|
5282
6725
|
amountUnitLabel
|
|
5283
6726
|
] })
|
|
@@ -5327,10 +6770,15 @@ function EarnModal({ onClose }) {
|
|
|
5327
6770
|
) });
|
|
5328
6771
|
}
|
|
5329
6772
|
function describeDevice(s) {
|
|
5330
|
-
if (s.deviceLabel) return s.deviceLabel;
|
|
6773
|
+
if (s.deviceLabel) return normalizeDeviceLabel(s.deviceLabel);
|
|
5331
6774
|
if (!s.userAgent) return "Unknown device";
|
|
5332
6775
|
return parseUserAgent(s.userAgent);
|
|
5333
6776
|
}
|
|
6777
|
+
function normalizeDeviceLabel(label) {
|
|
6778
|
+
const parts = label.replace(/\s+/g, " ").split(/ (?:[—–-]|·) /);
|
|
6779
|
+
if (parts.length === 2 && parts[1] !== void 0) return `${parts[0]} \xB7 ${parts[1].toLowerCase()}`;
|
|
6780
|
+
return label;
|
|
6781
|
+
}
|
|
5334
6782
|
function detectBrowser(ua) {
|
|
5335
6783
|
if (/Edg\//.test(ua)) return "Edge";
|
|
5336
6784
|
if (/OPR\//.test(ua)) return "Opera";
|
|
@@ -5350,7 +6798,7 @@ function detectOS(ua) {
|
|
|
5350
6798
|
function parseUserAgent(ua) {
|
|
5351
6799
|
const browser = detectBrowser(ua);
|
|
5352
6800
|
const os = detectOS(ua);
|
|
5353
|
-
if (browser && os) return `${os} \
|
|
6801
|
+
if (browser && os) return `${os} \xB7 ${browser.toLowerCase()}`;
|
|
5354
6802
|
if (os) return os;
|
|
5355
6803
|
if (browser) return browser;
|
|
5356
6804
|
return ua.slice(0, 48);
|
|
@@ -5374,6 +6822,37 @@ function shortIp(hash) {
|
|
|
5374
6822
|
if (!hash) return "";
|
|
5375
6823
|
return hash.slice(0, 8);
|
|
5376
6824
|
}
|
|
6825
|
+
function deviceKind(session) {
|
|
6826
|
+
const value = `${session.deviceLabel ?? ""} ${session.userAgent ?? ""}`.toLowerCase();
|
|
6827
|
+
if (/ipad|tablet/.test(value)) return "tablet";
|
|
6828
|
+
if (/android|iphone|ipod|mobile|phone/.test(value)) return "phone";
|
|
6829
|
+
return "desktop";
|
|
6830
|
+
}
|
|
6831
|
+
function DeviceIcon({ kind, size = "small" }) {
|
|
6832
|
+
const dimensions = size === "large" ? 30 : 18;
|
|
6833
|
+
if (kind === "phone") {
|
|
6834
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: dimensions, height: dimensions, viewBox: "0 0 24 24", fill: "none", "aria-hidden": true, children: [
|
|
6835
|
+
/* @__PURE__ */ jsxRuntime.jsx("rect", { x: "7", y: "2.5", width: "10", height: "19", rx: "2.5", stroke: "currentColor", strokeWidth: "1.8" }),
|
|
6836
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M10.5 5h3M11 18.5h2", stroke: "currentColor", strokeWidth: "1.6", strokeLinecap: "round" })
|
|
6837
|
+
] });
|
|
6838
|
+
}
|
|
6839
|
+
if (kind === "tablet") {
|
|
6840
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: dimensions, height: dimensions, viewBox: "0 0 24 24", fill: "none", "aria-hidden": true, children: [
|
|
6841
|
+
/* @__PURE__ */ jsxRuntime.jsx("rect", { x: "4.5", y: "2.5", width: "15", height: "19", rx: "2", stroke: "currentColor", strokeWidth: "1.8" }),
|
|
6842
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M11 18.5h2", stroke: "currentColor", strokeWidth: "1.6", strokeLinecap: "round" })
|
|
6843
|
+
] });
|
|
6844
|
+
}
|
|
6845
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: dimensions, height: dimensions, viewBox: "0 0 24 24", fill: "none", "aria-hidden": true, children: [
|
|
6846
|
+
/* @__PURE__ */ jsxRuntime.jsx("rect", { x: "3", y: "3.5", width: "18", height: "12", rx: "1.8", stroke: "currentColor", strokeWidth: "1.8" }),
|
|
6847
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M8 20.5h8M12 15.5v5", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round" })
|
|
6848
|
+
] });
|
|
6849
|
+
}
|
|
6850
|
+
function CheckIcon() {
|
|
6851
|
+
return /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m2.5 6.2 2.1 2.1L9.6 3.6", stroke: "currentColor", strokeWidth: "1.7", strokeLinecap: "round", strokeLinejoin: "round" }) });
|
|
6852
|
+
}
|
|
6853
|
+
function CloseIcon() {
|
|
6854
|
+
return /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m3 3 8 8M11 3l-8 8", stroke: "currentColor", strokeWidth: "1.7", strokeLinecap: "round" }) });
|
|
6855
|
+
}
|
|
5377
6856
|
function SessionsModalTemplate({
|
|
5378
6857
|
theme,
|
|
5379
6858
|
accentColor,
|
|
@@ -5381,6 +6860,7 @@ function SessionsModalTemplate({
|
|
|
5381
6860
|
state,
|
|
5382
6861
|
revokingFamilyId,
|
|
5383
6862
|
signingOutEverywhere,
|
|
6863
|
+
revokeError,
|
|
5384
6864
|
onRefresh,
|
|
5385
6865
|
onRevoke,
|
|
5386
6866
|
onLogoutEverywhere,
|
|
@@ -5389,7 +6869,9 @@ function SessionsModalTemplate({
|
|
|
5389
6869
|
const cssVars = buildModalCssVars(theme, accentColor, styleOverrides);
|
|
5390
6870
|
const isLoading = state.step === "loading";
|
|
5391
6871
|
const sessions = state.step === "loaded" ? state.sessions : [];
|
|
5392
|
-
const
|
|
6872
|
+
const currentSession = sessions.find((s) => s.current);
|
|
6873
|
+
const otherSessions = sessions.filter((s) => !s.current);
|
|
6874
|
+
const otherCount = otherSessions.length;
|
|
5393
6875
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5394
6876
|
"div",
|
|
5395
6877
|
{
|
|
@@ -5410,30 +6892,10 @@ function SessionsModalTemplate({
|
|
|
5410
6892
|
disabled: isLoading,
|
|
5411
6893
|
"aria-label": "Refresh",
|
|
5412
6894
|
title: "Refresh",
|
|
5413
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
5414
|
-
"svg",
|
|
5415
|
-
{
|
|
5416
|
-
className: isLoading ? "pollar-modal-refresh-icon pollar-spinning" : "pollar-modal-refresh-icon",
|
|
5417
|
-
width: "16",
|
|
5418
|
-
height: "16",
|
|
5419
|
-
viewBox: "0 0 16 16",
|
|
5420
|
-
fill: "none",
|
|
5421
|
-
"aria-hidden": true,
|
|
5422
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
5423
|
-
"path",
|
|
5424
|
-
{
|
|
5425
|
-
d: "M13.5 8a5.5 5.5 0 1 1-1.6-3.9M13.5 2v3h-3",
|
|
5426
|
-
stroke: "currentColor",
|
|
5427
|
-
strokeWidth: "1.6",
|
|
5428
|
-
strokeLinecap: "round",
|
|
5429
|
-
strokeLinejoin: "round"
|
|
5430
|
-
}
|
|
5431
|
-
)
|
|
5432
|
-
}
|
|
5433
|
-
)
|
|
6895
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(RefreshIcon, { spinning: isLoading })
|
|
5434
6896
|
}
|
|
5435
6897
|
),
|
|
5436
|
-
/* @__PURE__ */ jsxRuntime.jsx("button", { className: "pollar-modal-close", onClick: onClose, "aria-label": "Close",
|
|
6898
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-modal-close", onClick: onClose, "aria-label": "Close", title: "Close", children: /* @__PURE__ */ jsxRuntime.jsx(CloseIcon, {}) })
|
|
5437
6899
|
] })
|
|
5438
6900
|
] }),
|
|
5439
6901
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-sessions-list", children: [
|
|
@@ -5443,40 +6905,54 @@ function SessionsModalTemplate({
|
|
|
5443
6905
|
] }),
|
|
5444
6906
|
state.step === "error" && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-empty", children: state.message }),
|
|
5445
6907
|
state.step === "loaded" && sessions.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-empty", children: "No active sessions." }),
|
|
5446
|
-
|
|
5447
|
-
|
|
5448
|
-
|
|
5449
|
-
/* @__PURE__ */ jsxRuntime.
|
|
5450
|
-
|
|
5451
|
-
|
|
5452
|
-
|
|
5453
|
-
|
|
5454
|
-
|
|
5455
|
-
|
|
5456
|
-
|
|
5457
|
-
|
|
5458
|
-
|
|
5459
|
-
|
|
5460
|
-
|
|
5461
|
-
"ip ",
|
|
5462
|
-
shortIp(s.ipHash)
|
|
5463
|
-
] })
|
|
6908
|
+
state.step === "loaded" && currentSession && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-sessions-current-card", children: [
|
|
6909
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-sessions-current-icon-wrap", children: [
|
|
6910
|
+
/* @__PURE__ */ jsxRuntime.jsx(DeviceIcon, { kind: deviceKind(currentSession), size: "large" }),
|
|
6911
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-sessions-current-check", children: /* @__PURE__ */ jsxRuntime.jsx(CheckIcon, {}) })
|
|
6912
|
+
] }),
|
|
6913
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-sessions-current-label", children: "This device" }),
|
|
6914
|
+
/* @__PURE__ */ jsxRuntime.jsx("strong", { className: "pollar-sessions-current-device", children: describeDevice(currentSession) }),
|
|
6915
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-sessions-current-status", children: [
|
|
6916
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-sessions-status-dot" }),
|
|
6917
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Active now" }),
|
|
6918
|
+
currentSession.ipHash && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
6919
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "\xB7" }),
|
|
6920
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { title: `ip-hash ${currentSession.ipHash}`, children: [
|
|
6921
|
+
"IP ",
|
|
6922
|
+
shortIp(currentSession.ipHash)
|
|
5464
6923
|
] })
|
|
5465
|
-
] })
|
|
5466
|
-
|
|
5467
|
-
|
|
5468
|
-
|
|
5469
|
-
|
|
5470
|
-
|
|
5471
|
-
|
|
5472
|
-
|
|
5473
|
-
|
|
5474
|
-
|
|
5475
|
-
|
|
5476
|
-
|
|
5477
|
-
|
|
5478
|
-
|
|
5479
|
-
|
|
6924
|
+
] })
|
|
6925
|
+
] })
|
|
6926
|
+
] }),
|
|
6927
|
+
state.step === "loaded" && otherSessions.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "pollar-sessions-other-section", "aria-labelledby": "pollar-other-devices-heading", children: [
|
|
6928
|
+
/* @__PURE__ */ jsxRuntime.jsxs("h3", { id: "pollar-other-devices-heading", className: "pollar-sessions-section-title", children: [
|
|
6929
|
+
"Other devices ",
|
|
6930
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: otherCount })
|
|
6931
|
+
] }),
|
|
6932
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-sessions-grid", children: otherSessions.map((s) => {
|
|
6933
|
+
const isRevoking = revokingFamilyId === s.familyId;
|
|
6934
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-sessions-item", children: [
|
|
6935
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-sessions-item-top", children: [
|
|
6936
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-sessions-item-icon", children: /* @__PURE__ */ jsxRuntime.jsx(DeviceIcon, { kind: deviceKind(s) }) }),
|
|
6937
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6938
|
+
"button",
|
|
6939
|
+
{
|
|
6940
|
+
type: "button",
|
|
6941
|
+
className: "pollar-sessions-item-revoke",
|
|
6942
|
+
onClick: () => onRevoke(s.familyId),
|
|
6943
|
+
disabled: isRevoking || signingOutEverywhere,
|
|
6944
|
+
"aria-label": `Sign out ${describeDevice(s)}`,
|
|
6945
|
+
title: isRevoking ? "Signing out\u2026" : "Sign out this device",
|
|
6946
|
+
children: isRevoking ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-spinner pollar-spinner-sm" }) : /* @__PURE__ */ jsxRuntime.jsx(CloseIcon, {})
|
|
6947
|
+
}
|
|
6948
|
+
)
|
|
6949
|
+
] }),
|
|
6950
|
+
/* @__PURE__ */ jsxRuntime.jsx("strong", { className: "pollar-sessions-item-device", children: describeDevice(s) }),
|
|
6951
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-sessions-item-meta", children: formatRelative(s.lastUsedAt ?? s.createdAt) })
|
|
6952
|
+
] }, s.familyId);
|
|
6953
|
+
}) })
|
|
6954
|
+
] }),
|
|
6955
|
+
revokeError && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-sessions-action-error", role: "alert", children: revokeError })
|
|
5480
6956
|
] }),
|
|
5481
6957
|
state.step === "loaded" && sessions.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-sessions-actions", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
5482
6958
|
"button",
|
|
@@ -5501,6 +6977,7 @@ function SessionsModal({ onClose }) {
|
|
|
5501
6977
|
const { theme, accentColor, styleOverrides, overlayStyle } = modalChrome(styles);
|
|
5502
6978
|
const [revokingFamilyId, setRevokingFamilyId] = react.useState(null);
|
|
5503
6979
|
const [signingOutEverywhere, setSigningOutEverywhere] = react.useState(false);
|
|
6980
|
+
const [revokeError, setRevokeError] = react.useState(null);
|
|
5504
6981
|
const load = react.useCallback(() => {
|
|
5505
6982
|
void getClient().fetchSessions();
|
|
5506
6983
|
}, [getClient]);
|
|
@@ -5517,9 +6994,11 @@ function SessionsModal({ onClose }) {
|
|
|
5517
6994
|
const handleRevoke = react.useCallback(
|
|
5518
6995
|
async (familyId) => {
|
|
5519
6996
|
setRevokingFamilyId(familyId);
|
|
6997
|
+
setRevokeError(null);
|
|
5520
6998
|
try {
|
|
5521
6999
|
await getClient().revokeSession(familyId);
|
|
5522
7000
|
} catch {
|
|
7001
|
+
setRevokeError("Could not sign out that device. Please try again.");
|
|
5523
7002
|
} finally {
|
|
5524
7003
|
setRevokingFamilyId(null);
|
|
5525
7004
|
load();
|
|
@@ -5545,6 +7024,7 @@ function SessionsModal({ onClose }) {
|
|
|
5545
7024
|
state: sessions,
|
|
5546
7025
|
revokingFamilyId,
|
|
5547
7026
|
signingOutEverywhere,
|
|
7027
|
+
revokeError,
|
|
5548
7028
|
onRefresh: () => load(),
|
|
5549
7029
|
onRevoke: (familyId) => void handleRevoke(familyId),
|
|
5550
7030
|
onLogoutEverywhere: () => void handleLogoutEverywhere(),
|
|
@@ -5939,14 +7419,32 @@ function faucetFor(record) {
|
|
|
5939
7419
|
if (record.code === "USDC") return { url: "https://faucet.circle.com/", label: "Get test USDC" };
|
|
5940
7420
|
return null;
|
|
5941
7421
|
}
|
|
5942
|
-
function
|
|
7422
|
+
function assetMetadataFor(record, metadata) {
|
|
7423
|
+
return metadata.find(
|
|
7424
|
+
(asset) => resolveChain(asset.chain) === resolveChain(record.chain) && asset.code === record.code && (asset.issuer ?? "") === (record.issuer ?? "")
|
|
7425
|
+
);
|
|
7426
|
+
}
|
|
7427
|
+
function AssetIcon3({ code }) {
|
|
7428
|
+
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-bal-asset-icon", "aria-hidden": true, children: code.slice(0, 2).toUpperCase() });
|
|
7429
|
+
}
|
|
7430
|
+
function BalanceItem({
|
|
7431
|
+
record,
|
|
7432
|
+
faucet,
|
|
7433
|
+
metadata
|
|
7434
|
+
}) {
|
|
5943
7435
|
const balanceDiffers = record.balance !== record.available;
|
|
7436
|
+
const secondary = metadata?.name ?? (record.issuer ? cropAddress(record.issuer) : "Native asset");
|
|
5944
7437
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-bal-item", children: [
|
|
5945
7438
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-bal-asset-info", children: [
|
|
5946
|
-
/* @__PURE__ */ jsxRuntime.
|
|
5947
|
-
|
|
5948
|
-
/* @__PURE__ */ jsxRuntime.
|
|
5949
|
-
|
|
7439
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "pollar-bal-asset-leading", children: [
|
|
7440
|
+
/* @__PURE__ */ jsxRuntime.jsx(AssetIcon3, { code: record.code }),
|
|
7441
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "pollar-bal-asset-copy", children: [
|
|
7442
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-bal-asset", children: record.code }),
|
|
7443
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "pollar-bal-asset-secondary", children: [
|
|
7444
|
+
secondary,
|
|
7445
|
+
record.issuer && /* @__PURE__ */ jsxRuntime.jsx(CopyButton, { value: record.issuer, label: "Copy issuer address", className: "pollar-copy-btn-sm" })
|
|
7446
|
+
] })
|
|
7447
|
+
] })
|
|
5950
7448
|
] }),
|
|
5951
7449
|
faucet && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "pollar-bal-faucet-hint", children: [
|
|
5952
7450
|
"Need more?",
|
|
@@ -5970,6 +7468,7 @@ function WalletBalanceModalTemplate({
|
|
|
5970
7468
|
styleOverrides,
|
|
5971
7469
|
walletBalance,
|
|
5972
7470
|
walletAddress,
|
|
7471
|
+
assetMetadata = [],
|
|
5973
7472
|
chains,
|
|
5974
7473
|
selectedChain,
|
|
5975
7474
|
network,
|
|
@@ -5996,33 +7495,13 @@ function WalletBalanceModalTemplate({
|
|
|
5996
7495
|
disabled: isLoading,
|
|
5997
7496
|
"aria-label": "Refresh",
|
|
5998
7497
|
title: "Refresh",
|
|
5999
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
6000
|
-
"svg",
|
|
6001
|
-
{
|
|
6002
|
-
className: isLoading ? "pollar-modal-refresh-icon pollar-spinning" : "pollar-modal-refresh-icon",
|
|
6003
|
-
width: "16",
|
|
6004
|
-
height: "16",
|
|
6005
|
-
viewBox: "0 0 16 16",
|
|
6006
|
-
fill: "none",
|
|
6007
|
-
"aria-hidden": true,
|
|
6008
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
6009
|
-
"path",
|
|
6010
|
-
{
|
|
6011
|
-
d: "M13.5 8a5.5 5.5 0 1 1-1.6-3.9M13.5 2v3h-3",
|
|
6012
|
-
stroke: "currentColor",
|
|
6013
|
-
strokeWidth: "1.6",
|
|
6014
|
-
strokeLinecap: "round",
|
|
6015
|
-
strokeLinejoin: "round"
|
|
6016
|
-
}
|
|
6017
|
-
)
|
|
6018
|
-
}
|
|
6019
|
-
)
|
|
7498
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(RefreshIcon, { spinning: isLoading })
|
|
6020
7499
|
}
|
|
6021
7500
|
),
|
|
6022
|
-
/* @__PURE__ */ jsxRuntime.jsx("button", { className: "pollar-modal-close", onClick: onClose, "aria-label": "Close", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M2 2l12 12M14 2L2 14", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) }) })
|
|
7501
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-modal-close", onClick: onClose, "aria-label": "Close", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M2 2l12 12M14 2L2 14", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) }) })
|
|
6023
7502
|
] })
|
|
6024
7503
|
] }),
|
|
6025
|
-
/* @__PURE__ */ jsxRuntime.jsx(ChainSelect, { value: selectedChain, options: chains, onChange: onSelectChain, disabled: isLoading }),
|
|
7504
|
+
chains && onSelectChain && /* @__PURE__ */ jsxRuntime.jsx(ChainSelect, { value: selectedChain, options: chains, onChange: onSelectChain, disabled: isLoading }),
|
|
6026
7505
|
walletAddress && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-address-row", children: [
|
|
6027
7506
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-address", children: cropAddress(walletAddress) }),
|
|
6028
7507
|
/* @__PURE__ */ jsxRuntime.jsx(CopyButton, { value: walletAddress, label: "Copy wallet address" })
|
|
@@ -6042,6 +7521,7 @@ function WalletBalanceModalTemplate({
|
|
|
6042
7521
|
BalanceItem,
|
|
6043
7522
|
{
|
|
6044
7523
|
record: b,
|
|
7524
|
+
metadata: assetMetadataFor(b, assetMetadata),
|
|
6045
7525
|
faucet: showFaucets ? faucetFor(b) : null
|
|
6046
7526
|
},
|
|
6047
7527
|
(b.chain ?? "") + b.code + (b.issuer ?? "")
|
|
@@ -6050,7 +7530,7 @@ function WalletBalanceModalTemplate({
|
|
|
6050
7530
|
] });
|
|
6051
7531
|
}
|
|
6052
7532
|
function WalletBalanceModal({ onClose }) {
|
|
6053
|
-
const { walletBalance, refreshWalletBalance, wallets, network, styles } = usePollar();
|
|
7533
|
+
const { walletBalance, refreshWalletBalance, wallets, network, styles, enabledAssets } = usePollar();
|
|
6054
7534
|
const { theme, accentColor, styleOverrides, overlayStyle } = modalChrome(styles);
|
|
6055
7535
|
const { chains } = useChains();
|
|
6056
7536
|
const [selectedChain, setSelectedChain] = react.useState(null);
|
|
@@ -6069,6 +7549,7 @@ function WalletBalanceModal({ onClose }) {
|
|
|
6069
7549
|
styleOverrides,
|
|
6070
7550
|
walletBalance,
|
|
6071
7551
|
walletAddress,
|
|
7552
|
+
assetMetadata: enabledAssets.step === "loaded" ? enabledAssets.data.assets : [],
|
|
6072
7553
|
chains,
|
|
6073
7554
|
selectedChain,
|
|
6074
7555
|
network,
|
|
@@ -6138,7 +7619,11 @@ var DEFAULT_APP_CONFIG = {
|
|
|
6138
7619
|
function sessionsEqual(a, b) {
|
|
6139
7620
|
if (a === b) return true;
|
|
6140
7621
|
if (!a || !b) return false;
|
|
6141
|
-
return a.clientSessionId === b.clientSessionId && a.userId === b.userId && a.status === b.status && a.token?.accessToken === b.token?.accessToken && a.token?.refreshToken === b.token?.refreshToken && a.token?.expiresAt === b.token?.expiresAt && a.wallet?.address === b.wallet?.address
|
|
7622
|
+
return a.clientSessionId === b.clientSessionId && a.userId === b.userId && a.status === b.status && a.token?.accessToken === b.token?.accessToken && a.token?.refreshToken === b.token?.refreshToken && a.token?.expiresAt === b.token?.expiresAt && a.wallet?.address === b.wallet?.address && // The wallet's on-chain account can move from CREATING to READY without any
|
|
7623
|
+
// other field changing. Leaving it out of the comparison is what would make
|
|
7624
|
+
// the whole provisioning UI dead: the short-circuit below would swallow the
|
|
7625
|
+
// one emission that says the wait is over.
|
|
7626
|
+
a.wallet?.provisioning === b.wallet?.provisioning;
|
|
6142
7627
|
}
|
|
6143
7628
|
var PollarContext = react.createContext(null);
|
|
6144
7629
|
var clientByConfig = /* @__PURE__ */ new WeakMap();
|
|
@@ -6304,6 +7789,7 @@ function PollarProvider({
|
|
|
6304
7789
|
const [sessionsModalOpen, setSessionsModalOpen] = react.useState(false);
|
|
6305
7790
|
const [distributionRulesModalOpen, setDistributionRulesModalOpen] = react.useState(false);
|
|
6306
7791
|
const walletAddress = sessionState?.wallet?.address || "";
|
|
7792
|
+
const walletProvisioning = sessionState?.wallet?.provisioning;
|
|
6307
7793
|
const getClient = react.useCallback(() => pollarClient, [pollarClient]);
|
|
6308
7794
|
const refreshWalletBalance = react.useCallback(() => pollarClient.refreshBalance(), [pollarClient, walletAddress]);
|
|
6309
7795
|
const refreshAssets = react.useCallback(() => pollarClient.refreshAssets(), [pollarClient, walletAddress]);
|
|
@@ -6395,6 +7881,7 @@ function PollarProvider({
|
|
|
6395
7881
|
};
|
|
6396
7882
|
}, [
|
|
6397
7883
|
walletAddress,
|
|
7884
|
+
walletProvisioning,
|
|
6398
7885
|
verified,
|
|
6399
7886
|
pollarClient,
|
|
6400
7887
|
getClient,
|
|
@@ -6415,11 +7902,24 @@ function PollarProvider({
|
|
|
6415
7902
|
children,
|
|
6416
7903
|
loginModalOpen && /* @__PURE__ */ jsxRuntime.jsx(ModalErrorBoundary, { onClose: () => setLoginModalOpen(false), children: /* @__PURE__ */ jsxRuntime.jsx(LoginModal, { onClose: () => setLoginModalOpen(false) }) }),
|
|
6417
7904
|
transactionModalOpen && /* @__PURE__ */ jsxRuntime.jsx(ModalErrorBoundary, { onClose: () => setTransactionModalOpen(false), children: /* @__PURE__ */ jsxRuntime.jsx(TransactionModal, { onClose: () => setTransactionModalOpen(false) }) }),
|
|
6418
|
-
kycModalOpen && /* @__PURE__ */ jsxRuntime.jsx(ModalErrorBoundary, { onClose: () => setKycModalOpen(false), children:
|
|
7905
|
+
kycModalOpen && /* @__PURE__ */ jsxRuntime.jsx(ModalErrorBoundary, { onClose: () => setKycModalOpen(false), children: kycModalOptions.corridorId === void 0 && kycModalOptions.providerId === void 0 ? (
|
|
7906
|
+
// The app's own KYC: its configured steps, in order.
|
|
7907
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7908
|
+
AppKycFlow,
|
|
7909
|
+
{
|
|
7910
|
+
onClose: () => setKycModalOpen(false),
|
|
7911
|
+
...kycModalOptions.country !== void 0 && { country: kycModalOptions.country },
|
|
7912
|
+
...kycModalOptions.level !== void 0 && { level: kycModalOptions.level },
|
|
7913
|
+
...kycModalOptions.onApproved !== void 0 && { onApproved: kycModalOptions.onApproved }
|
|
7914
|
+
}
|
|
7915
|
+
)
|
|
7916
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
6419
7917
|
KycModal,
|
|
6420
7918
|
{
|
|
6421
7919
|
onClose: () => setKycModalOpen(false),
|
|
6422
7920
|
...kycModalOptions.country !== void 0 && { country: kycModalOptions.country },
|
|
7921
|
+
...kycModalOptions.corridorId !== void 0 && { corridorId: kycModalOptions.corridorId },
|
|
7922
|
+
...kycModalOptions.providerId !== void 0 && { providerId: kycModalOptions.providerId },
|
|
6423
7923
|
...kycModalOptions.level !== void 0 && { level: kycModalOptions.level },
|
|
6424
7924
|
...kycModalOptions.onApproved !== void 0 && { onApproved: kycModalOptions.onApproved }
|
|
6425
7925
|
}
|
|
@@ -6481,6 +7981,7 @@ function WalletButtonTemplate({
|
|
|
6481
7981
|
wrapperRef,
|
|
6482
7982
|
isInProgress,
|
|
6483
7983
|
showCreateAccount,
|
|
7984
|
+
notReadyReason,
|
|
6484
7985
|
creatingAccount,
|
|
6485
7986
|
onToggleOpen,
|
|
6486
7987
|
onCreateAccount,
|
|
@@ -6545,6 +8046,10 @@ function WalletButtonTemplate({
|
|
|
6545
8046
|
}
|
|
6546
8047
|
),
|
|
6547
8048
|
open && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-wallet-dropdown", style: { backgroundColor: dropdownBg, borderColor: dropdownBorder }, children: [
|
|
8049
|
+
notReadyReason && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
8050
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-wallet-dropdown-notice", style: { color: itemColor }, role: "status", children: notReadyReason }),
|
|
8051
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-wallet-dropdown-divider" })
|
|
8052
|
+
] }),
|
|
6548
8053
|
showCreateAccount && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
6549
8054
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
6550
8055
|
"button",
|
|
@@ -6814,7 +8319,7 @@ function WalletButton() {
|
|
|
6814
8319
|
openDistributionRulesModal,
|
|
6815
8320
|
tx: transaction
|
|
6816
8321
|
} = usePollar();
|
|
6817
|
-
const { primaryAddress } = useChains();
|
|
8322
|
+
const { primaryChain, primaryAddress } = useChains();
|
|
6818
8323
|
const walletAddress = primaryAddress || (wallet?.address ?? "");
|
|
6819
8324
|
const [open, setOpen] = react.useState(false);
|
|
6820
8325
|
const [copied, setCopied] = react.useState(false);
|
|
@@ -6824,6 +8329,7 @@ function WalletButton() {
|
|
|
6824
8329
|
const copyTimerRef = react.useRef(null);
|
|
6825
8330
|
const isInProgress = transaction.step === "building" || transaction.step === "signing";
|
|
6826
8331
|
const canCreateAccount = !created && wallet?.custody === "external" && wallet.existsOnStellar === false && wallet.fundingMode === "IMMEDIATE";
|
|
8332
|
+
const notReadyReason = walletNotReadyReason(wallet, primaryChain);
|
|
6827
8333
|
const { theme = "light", accentColor = "#005DB4" } = styles;
|
|
6828
8334
|
const isDark = theme === "dark";
|
|
6829
8335
|
const dropdownBg = isDark ? "#18181b" : "#fff";
|
|
@@ -6917,6 +8423,7 @@ function WalletButton() {
|
|
|
6917
8423
|
wrapperRef,
|
|
6918
8424
|
isInProgress,
|
|
6919
8425
|
showCreateAccount: canCreateAccount,
|
|
8426
|
+
notReadyReason,
|
|
6920
8427
|
creatingAccount: creating,
|
|
6921
8428
|
onToggleOpen: () => setOpen((v) => !v),
|
|
6922
8429
|
onCreateAccount: handleCreateAccount,
|
|
@@ -6946,10 +8453,13 @@ exports.KycModalTemplate = KycModalTemplate;
|
|
|
6946
8453
|
exports.KycStatus = KycStatus;
|
|
6947
8454
|
exports.LoginModalTemplate = LoginModalTemplate;
|
|
6948
8455
|
exports.PollarProvider = PollarProvider;
|
|
8456
|
+
exports.ProviderRegistrationModal = ProviderRegistrationModal;
|
|
6949
8457
|
exports.RampWidget = RampWidget;
|
|
6950
8458
|
exports.RampWidgetTemplate = RampWidgetTemplate;
|
|
6951
8459
|
exports.ReceiveModal = ReceiveModal;
|
|
6952
8460
|
exports.ReceiveModalTemplate = ReceiveModalTemplate;
|
|
8461
|
+
exports.RegistryCheckModal = RegistryCheckModal;
|
|
8462
|
+
exports.RequirementFormModal = RequirementFormModal;
|
|
6953
8463
|
exports.RouteDisplay = RouteDisplay;
|
|
6954
8464
|
exports.SendModal = SendModal;
|
|
6955
8465
|
exports.SendModalTemplate = SendModalTemplate;
|
|
@@ -6975,5 +8485,6 @@ exports.readableTextOn = readableTextOn;
|
|
|
6975
8485
|
exports.resolveChain = resolveChain;
|
|
6976
8486
|
exports.useChains = useChains;
|
|
6977
8487
|
exports.usePollar = usePollar;
|
|
8488
|
+
exports.walletNotReadyReason = walletNotReadyReason;
|
|
6978
8489
|
//# sourceMappingURL=index.js.map
|
|
6979
8490
|
//# sourceMappingURL=index.js.map
|