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