@pollar/react 0.11.3 → 0.11.4-rc.2
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 +2090 -570
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2088 -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.2"
|
|
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,383 @@ 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
|
+
rejected: "The registry did not confirm: {fields}. Check how they are written and try again.",
|
|
3917
|
+
loadError: "Could not load your details. Please try again.",
|
|
3918
|
+
submitError: "Could not check your details. Please try again.",
|
|
3919
|
+
step: "Step {n} of {total}"
|
|
3920
|
+
},
|
|
3921
|
+
es: {
|
|
3922
|
+
title: "Confirma tus datos",
|
|
3923
|
+
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.",
|
|
3924
|
+
givenNames: "Nombres",
|
|
3925
|
+
surname1: "Primer apellido",
|
|
3926
|
+
surname2: "Segundo apellido",
|
|
3927
|
+
birthdate: "Fecha de nacimiento",
|
|
3928
|
+
documentNumber: "N\xFAmero de CI",
|
|
3929
|
+
complement: "Complemento (si tu CI lo tiene)",
|
|
3930
|
+
submit: "Confirmar",
|
|
3931
|
+
submitting: "Validando\u2026",
|
|
3932
|
+
close: "Cerrar",
|
|
3933
|
+
approved: "Tus datos fueron confirmados.",
|
|
3934
|
+
review: "Tus datos est\xE1n en revisi\xF3n. Podr\xE1s continuar cuando se confirmen.",
|
|
3935
|
+
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.",
|
|
3936
|
+
identityRequired: "Primero verifica tu identidad.",
|
|
3937
|
+
nameMismatch: "Los dos apellidos juntos deben leerse como en tu documento: {full}.",
|
|
3938
|
+
rejected: "El registro no confirm\xF3: {fields}. Revisa c\xF3mo est\xE1n escritos e intenta de nuevo.",
|
|
3939
|
+
loadError: "No se pudieron cargar tus datos. Intenta de nuevo.",
|
|
3940
|
+
submitError: "No se pudieron validar tus datos. Intenta de nuevo.",
|
|
3941
|
+
step: "Paso {n} de {total}"
|
|
3942
|
+
}
|
|
3943
|
+
};
|
|
3944
|
+
var REGISTRATION_COPY = {
|
|
3945
|
+
en: {
|
|
3946
|
+
title: "Register with the payment provider",
|
|
3947
|
+
intro: "To use this route, the provider registers you as its customer. These details will be sent to it:",
|
|
3948
|
+
consent: "I agree to share these details with the provider.",
|
|
3949
|
+
submit: "Register",
|
|
3950
|
+
submitting: "Registering\u2026",
|
|
3951
|
+
close: "Close",
|
|
3952
|
+
notReady: "Complete the previous steps first.",
|
|
3953
|
+
missing: "Some details are missing: {fields}.",
|
|
3954
|
+
loadError: "Could not load the registration. Please try again.",
|
|
3955
|
+
submitError: "Could not register you. Please try again.",
|
|
3956
|
+
step: "Step {n} of {total}"
|
|
3957
|
+
},
|
|
3958
|
+
es: {
|
|
3959
|
+
title: "Registro con el proveedor de pagos",
|
|
3960
|
+
intro: "Para usar esta ruta, el proveedor te registra como su cliente. Se le enviar\xE1n estos datos:",
|
|
3961
|
+
consent: "Acepto compartir estos datos con el proveedor.",
|
|
3962
|
+
submit: "Registrarme",
|
|
3963
|
+
submitting: "Registrando\u2026",
|
|
3964
|
+
close: "Cerrar",
|
|
3965
|
+
notReady: "Primero completa los pasos anteriores.",
|
|
3966
|
+
missing: "Faltan algunos datos: {fields}.",
|
|
3967
|
+
loadError: "No se pudo cargar el registro. Intenta de nuevo.",
|
|
3968
|
+
submitError: "No se pudo completar el registro. Intenta de nuevo.",
|
|
3969
|
+
step: "Paso {n} de {total}"
|
|
3970
|
+
}
|
|
3971
|
+
};
|
|
3972
|
+
var SHARED_FIELD_LABELS = {
|
|
3973
|
+
en: {
|
|
3974
|
+
name: "Names",
|
|
3975
|
+
lastname: "Surnames",
|
|
3976
|
+
document_type: "Document type",
|
|
3977
|
+
document_number: "Document number",
|
|
3978
|
+
country: "Country",
|
|
3979
|
+
state_of_residence: "Department of residence",
|
|
3980
|
+
economic_activity: "Economic activity",
|
|
3981
|
+
source_of_funds: "Source of funds",
|
|
3982
|
+
destination_of_funds: "Use of funds",
|
|
3983
|
+
income_level: "Income level",
|
|
3984
|
+
doc_provider_id: "SEGIP validation"
|
|
3985
|
+
},
|
|
3986
|
+
es: {
|
|
3987
|
+
name: "Nombres",
|
|
3988
|
+
lastname: "Apellidos",
|
|
3989
|
+
document_type: "Tipo de documento",
|
|
3990
|
+
document_number: "N\xFAmero de documento",
|
|
3991
|
+
country: "Pa\xEDs",
|
|
3992
|
+
state_of_residence: "Departamento de residencia",
|
|
3993
|
+
economic_activity: "Actividad econ\xF3mica",
|
|
3994
|
+
source_of_funds: "Origen de los fondos",
|
|
3995
|
+
destination_of_funds: "Destino de los fondos",
|
|
3996
|
+
income_level: "Nivel de ingresos",
|
|
3997
|
+
doc_provider_id: "Validaci\xF3n SEGIP"
|
|
3998
|
+
}
|
|
3999
|
+
};
|
|
4000
|
+
var errorCode = (error) => error && typeof error === "object" && typeof error.code === "string" ? error.code : null;
|
|
4001
|
+
function missingFieldsOf(error) {
|
|
4002
|
+
const body = error && typeof error === "object" ? error.body : void 0;
|
|
4003
|
+
return Array.isArray(body?.missing) ? body.missing.filter((item) => typeof item === "string") : [];
|
|
4004
|
+
}
|
|
4005
|
+
function RegistryCheckModal({ optionId, progress, onClose, onApproved }) {
|
|
4006
|
+
const { getClient, styles } = usePollar();
|
|
4007
|
+
const client = getClient();
|
|
4008
|
+
const { theme, accentColor, styleOverrides, overlayStyle } = modalChrome(styles);
|
|
4009
|
+
const cssVars = buildModalCssVars(theme, accentColor, styleOverrides, "hero");
|
|
4010
|
+
const language = useMemo(formLanguage, []);
|
|
4011
|
+
const copy = REGISTRY_COPY[language];
|
|
4012
|
+
const [check, setCheck] = useState(null);
|
|
4013
|
+
const [surname1, setSurname1] = useState("");
|
|
4014
|
+
const [surname2, setSurname2] = useState("");
|
|
4015
|
+
const [complement, setComplement] = useState("");
|
|
4016
|
+
const [error, setError] = useState(null);
|
|
4017
|
+
const [review, setReview] = useState(false);
|
|
4018
|
+
const [submitting, setSubmitting] = useState(false);
|
|
4019
|
+
const mounted = useRef(true);
|
|
4020
|
+
useEffect(() => {
|
|
4021
|
+
mounted.current = true;
|
|
4022
|
+
return () => {
|
|
4023
|
+
mounted.current = false;
|
|
4024
|
+
};
|
|
4025
|
+
}, []);
|
|
4026
|
+
useEffect(() => {
|
|
4027
|
+
client.getRegistryCheck(optionId).then((loaded) => {
|
|
4028
|
+
if (!mounted.current) return;
|
|
4029
|
+
if (loaded.status === "approved") return onApproved();
|
|
4030
|
+
setCheck(loaded);
|
|
4031
|
+
if (loaded.status === "pending") setReview(true);
|
|
4032
|
+
if (loaded.status === "rejected") setError(rejectedMessage(loaded.rejectedFields));
|
|
4033
|
+
if (loaded.prefill.applies) {
|
|
4034
|
+
setSurname1(loaded.prefill.surname1);
|
|
4035
|
+
setSurname2(loaded.prefill.surname2 ?? "");
|
|
4036
|
+
setComplement(loaded.prefill.complementNumber ?? "");
|
|
4037
|
+
}
|
|
4038
|
+
}).catch((e) => {
|
|
4039
|
+
if (!mounted.current) return;
|
|
4040
|
+
setError(errorCode(e) === "KYC_REGISTRY_IDENTITY_REQUIRED" ? copy.identityRequired : copy.loadError);
|
|
4041
|
+
});
|
|
4042
|
+
}, [optionId]);
|
|
4043
|
+
const prefill = check?.prefill.applies ? check.prefill : null;
|
|
4044
|
+
function rejectedMessage(fields) {
|
|
4045
|
+
const labels = { surname1: copy.surname1, surname2: copy.surname2, complementNumber: copy.complement };
|
|
4046
|
+
const named = (fields ?? []).map((field) => labels[field] ?? field);
|
|
4047
|
+
return copy.rejected.replace("{fields}", named.length ? named.join(", ") : copy.surname2);
|
|
4048
|
+
}
|
|
4049
|
+
async function submit() {
|
|
4050
|
+
if (!prefill) return;
|
|
4051
|
+
setSubmitting(true);
|
|
4052
|
+
setError(null);
|
|
4053
|
+
try {
|
|
4054
|
+
const result = await client.submitRegistryCheck(optionId, {
|
|
4055
|
+
surname1: surname1.trim(),
|
|
4056
|
+
...surname2.trim() ? { surname2: surname2.trim() } : {},
|
|
4057
|
+
...complement.trim() ? { complementNumber: complement.trim() } : {}
|
|
4058
|
+
});
|
|
4059
|
+
if (!mounted.current) return;
|
|
4060
|
+
if (result.status === "approved") onApproved();
|
|
4061
|
+
else if (result.status === "rejected") setError(rejectedMessage(result.rejectedFields));
|
|
4062
|
+
else setReview(true);
|
|
4063
|
+
} catch (e) {
|
|
4064
|
+
if (!mounted.current) return;
|
|
4065
|
+
const code = errorCode(e);
|
|
4066
|
+
if (code === "SDK_KYC_ALREADY_APPROVED") return onApproved();
|
|
4067
|
+
if (code === "KYC_REGISTRY_NAME_MISMATCH") {
|
|
4068
|
+
setError(copy.nameMismatch.replace("{full}", [prefill.surname1, prefill.surname2].filter(Boolean).join(" ")));
|
|
4069
|
+
} else if (code === "SDK_KYC_UNDER_REVIEW") setReview(true);
|
|
4070
|
+
else setError(copy.submitError);
|
|
4071
|
+
} finally {
|
|
4072
|
+
if (mounted.current) setSubmitting(false);
|
|
4073
|
+
}
|
|
4074
|
+
}
|
|
4075
|
+
const readOnly = (label, value) => /* @__PURE__ */ jsxs("div", { className: "pollar-form-field", children: [
|
|
4076
|
+
/* @__PURE__ */ jsx("span", { className: "pollar-form-label", children: label }),
|
|
4077
|
+
/* @__PURE__ */ jsx("input", { className: "pollar-input", value, readOnly: true, disabled: true })
|
|
4078
|
+
] });
|
|
4079
|
+
return /* @__PURE__ */ jsx("div", { className: "pollar-overlay", style: overlayStyle, onClick: onClose, children: /* @__PURE__ */ jsxs(
|
|
4080
|
+
"div",
|
|
4081
|
+
{
|
|
4082
|
+
className: "pollar-modal-card pollar-form-modal",
|
|
4083
|
+
role: "dialog",
|
|
4084
|
+
"aria-modal": "true",
|
|
4085
|
+
"aria-label": copy.title,
|
|
4086
|
+
style: cssVars,
|
|
4087
|
+
onClick: (e) => e.stopPropagation(),
|
|
4088
|
+
children: [
|
|
4089
|
+
/* @__PURE__ */ jsxs("div", { className: "pollar-modal-header", children: [
|
|
4090
|
+
/* @__PURE__ */ jsxs("div", { className: "pollar-form-header-text", children: [
|
|
4091
|
+
/* @__PURE__ */ jsx("h2", { className: "pollar-modal-title", children: copy.title }),
|
|
4092
|
+
progress && /* @__PURE__ */ jsx("p", { className: "pollar-form-subtitle", children: copy.step.replace("{n}", String(progress.position)).replace("{total}", String(progress.total)) })
|
|
4093
|
+
] }),
|
|
4094
|
+
/* @__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" }) }) })
|
|
4095
|
+
] }),
|
|
4096
|
+
error && /* @__PURE__ */ jsx("p", { className: "pollar-form-error", role: "alert", children: error }),
|
|
4097
|
+
!check && !error && /* @__PURE__ */ jsx("div", { className: "pollar-loading-block", children: /* @__PURE__ */ jsx("div", { className: "pollar-spinner" }) }),
|
|
4098
|
+
check && (review || !prefill) && /* @__PURE__ */ jsxs("div", { className: "pollar-form-body", children: [
|
|
4099
|
+
/* @__PURE__ */ jsx("p", { className: "pollar-form-error", role: "status", children: review ? copy.review : copy.notApplicable }),
|
|
4100
|
+
/* @__PURE__ */ jsx("div", { className: "pollar-modal-actions", children: /* @__PURE__ */ jsx("button", { type: "button", className: "pollar-btn-secondary", onClick: onClose, children: copy.close }) })
|
|
4101
|
+
] }),
|
|
4102
|
+
prefill && !review && /* @__PURE__ */ jsxs(
|
|
4103
|
+
"form",
|
|
4104
|
+
{
|
|
4105
|
+
className: "pollar-form-body",
|
|
4106
|
+
onSubmit: (e) => {
|
|
4107
|
+
e.preventDefault();
|
|
4108
|
+
void submit();
|
|
4109
|
+
},
|
|
4110
|
+
children: [
|
|
4111
|
+
/* @__PURE__ */ jsx("p", { className: "pollar-form-description", children: copy.intro }),
|
|
4112
|
+
readOnly(copy.givenNames, prefill.givenNames),
|
|
4113
|
+
/* @__PURE__ */ jsxs("div", { className: "pollar-form-field", children: [
|
|
4114
|
+
/* @__PURE__ */ jsxs("label", { htmlFor: "pollar-registry-surname1", className: "pollar-form-label", children: [
|
|
4115
|
+
copy.surname1,
|
|
4116
|
+
/* @__PURE__ */ jsx("span", { className: "pollar-form-required", children: " *" })
|
|
4117
|
+
] }),
|
|
4118
|
+
/* @__PURE__ */ jsx(
|
|
4119
|
+
"input",
|
|
4120
|
+
{
|
|
4121
|
+
id: "pollar-registry-surname1",
|
|
4122
|
+
className: "pollar-input",
|
|
4123
|
+
value: surname1,
|
|
4124
|
+
required: true,
|
|
4125
|
+
disabled: submitting,
|
|
4126
|
+
onChange: (e) => setSurname1(e.target.value)
|
|
4127
|
+
}
|
|
4128
|
+
)
|
|
4129
|
+
] }),
|
|
4130
|
+
/* @__PURE__ */ jsxs("div", { className: "pollar-form-field", children: [
|
|
4131
|
+
/* @__PURE__ */ jsx("label", { htmlFor: "pollar-registry-surname2", className: "pollar-form-label", children: copy.surname2 }),
|
|
4132
|
+
/* @__PURE__ */ jsx(
|
|
4133
|
+
"input",
|
|
4134
|
+
{
|
|
4135
|
+
id: "pollar-registry-surname2",
|
|
4136
|
+
className: "pollar-input",
|
|
4137
|
+
value: surname2,
|
|
4138
|
+
disabled: submitting,
|
|
4139
|
+
onChange: (e) => setSurname2(e.target.value)
|
|
4140
|
+
}
|
|
4141
|
+
)
|
|
4142
|
+
] }),
|
|
4143
|
+
readOnly(copy.birthdate, prefill.birthdate),
|
|
4144
|
+
readOnly(copy.documentNumber, prefill.documentNumber),
|
|
4145
|
+
/* @__PURE__ */ jsxs("div", { className: "pollar-form-field", children: [
|
|
4146
|
+
/* @__PURE__ */ jsx("label", { htmlFor: "pollar-registry-complement", className: "pollar-form-label", children: copy.complement }),
|
|
4147
|
+
/* @__PURE__ */ jsx(
|
|
4148
|
+
"input",
|
|
4149
|
+
{
|
|
4150
|
+
id: "pollar-registry-complement",
|
|
4151
|
+
className: "pollar-input",
|
|
4152
|
+
value: complement,
|
|
4153
|
+
maxLength: 3,
|
|
4154
|
+
disabled: submitting,
|
|
4155
|
+
onChange: (e) => setComplement(e.target.value.toUpperCase().replace(/[^0-9A-Z]/g, ""))
|
|
4156
|
+
}
|
|
4157
|
+
)
|
|
4158
|
+
] }),
|
|
4159
|
+
/* @__PURE__ */ jsxs("div", { className: "pollar-modal-actions", children: [
|
|
4160
|
+
/* @__PURE__ */ jsx("button", { type: "button", className: "pollar-btn-secondary", onClick: onClose, disabled: submitting, children: copy.close }),
|
|
4161
|
+
/* @__PURE__ */ jsx("button", { type: "submit", className: "pollar-btn-primary", disabled: submitting || !surname1.trim(), children: submitting ? copy.submitting : copy.submit })
|
|
4162
|
+
] })
|
|
4163
|
+
]
|
|
4164
|
+
}
|
|
4165
|
+
)
|
|
4166
|
+
]
|
|
4167
|
+
}
|
|
4168
|
+
) });
|
|
4169
|
+
}
|
|
4170
|
+
function ProviderRegistrationModal({ corridorId, progress, onClose, onRegistered }) {
|
|
4171
|
+
const { getClient, styles } = usePollar();
|
|
4172
|
+
const client = getClient();
|
|
4173
|
+
const { theme, accentColor, styleOverrides, overlayStyle } = modalChrome(styles);
|
|
4174
|
+
const cssVars = buildModalCssVars(theme, accentColor, styleOverrides, "hero");
|
|
4175
|
+
const language = useMemo(formLanguage, []);
|
|
4176
|
+
const copy = REGISTRATION_COPY[language];
|
|
4177
|
+
const labels = SHARED_FIELD_LABELS[language];
|
|
4178
|
+
const [registration, setRegistration] = useState(null);
|
|
4179
|
+
const [consent, setConsent] = useState(false);
|
|
4180
|
+
const [error, setError] = useState(null);
|
|
4181
|
+
const [submitting, setSubmitting] = useState(false);
|
|
4182
|
+
const mounted = useRef(true);
|
|
4183
|
+
useEffect(() => {
|
|
4184
|
+
mounted.current = true;
|
|
4185
|
+
return () => {
|
|
4186
|
+
mounted.current = false;
|
|
4187
|
+
};
|
|
4188
|
+
}, []);
|
|
4189
|
+
useEffect(() => {
|
|
4190
|
+
client.getProviderRegistration(corridorId).then((loaded) => {
|
|
4191
|
+
if (!mounted.current) return;
|
|
4192
|
+
if (loaded.status === "registered") onRegistered();
|
|
4193
|
+
else setRegistration(loaded);
|
|
4194
|
+
}).catch(() => mounted.current && setError(copy.loadError));
|
|
4195
|
+
}, [corridorId]);
|
|
4196
|
+
async function submit() {
|
|
4197
|
+
setSubmitting(true);
|
|
4198
|
+
setError(null);
|
|
4199
|
+
try {
|
|
4200
|
+
await client.submitProviderRegistration(corridorId);
|
|
4201
|
+
if (mounted.current) onRegistered();
|
|
4202
|
+
} catch (e) {
|
|
4203
|
+
if (!mounted.current) return;
|
|
4204
|
+
const code = errorCode(e);
|
|
4205
|
+
if (code === "KYC_REGISTRATION_MISSING_DATA") {
|
|
4206
|
+
setError(
|
|
4207
|
+
copy.missing.replace(
|
|
4208
|
+
"{fields}",
|
|
4209
|
+
missingFieldsOf(e).map((key) => labels[key] ?? key).join(", ")
|
|
4210
|
+
)
|
|
4211
|
+
);
|
|
4212
|
+
} else if (code === "KYC_REGISTRATION_STEPS_PENDING") setError(copy.notReady);
|
|
4213
|
+
else setError(copy.submitError);
|
|
4214
|
+
} finally {
|
|
4215
|
+
if (mounted.current) setSubmitting(false);
|
|
4216
|
+
}
|
|
4217
|
+
}
|
|
4218
|
+
return /* @__PURE__ */ jsx("div", { className: "pollar-overlay", style: overlayStyle, onClick: onClose, children: /* @__PURE__ */ jsxs(
|
|
4219
|
+
"div",
|
|
4220
|
+
{
|
|
4221
|
+
className: "pollar-modal-card pollar-form-modal",
|
|
4222
|
+
role: "dialog",
|
|
4223
|
+
"aria-modal": "true",
|
|
4224
|
+
"aria-label": copy.title,
|
|
4225
|
+
style: cssVars,
|
|
4226
|
+
onClick: (e) => e.stopPropagation(),
|
|
4227
|
+
children: [
|
|
4228
|
+
/* @__PURE__ */ jsxs("div", { className: "pollar-modal-header", children: [
|
|
4229
|
+
/* @__PURE__ */ jsxs("div", { className: "pollar-form-header-text", children: [
|
|
4230
|
+
/* @__PURE__ */ jsx("h2", { className: "pollar-modal-title", children: copy.title }),
|
|
4231
|
+
progress && /* @__PURE__ */ jsx("p", { className: "pollar-form-subtitle", children: copy.step.replace("{n}", String(progress.position)).replace("{total}", String(progress.total)) })
|
|
4232
|
+
] }),
|
|
4233
|
+
/* @__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" }) }) })
|
|
4234
|
+
] }),
|
|
4235
|
+
error && /* @__PURE__ */ jsx("p", { className: "pollar-form-error", role: "alert", children: error }),
|
|
4236
|
+
!registration && !error && /* @__PURE__ */ jsx("div", { className: "pollar-loading-block", children: /* @__PURE__ */ jsx("div", { className: "pollar-spinner" }) }),
|
|
4237
|
+
registration && /* @__PURE__ */ jsxs(
|
|
4238
|
+
"form",
|
|
4239
|
+
{
|
|
4240
|
+
className: "pollar-form-body",
|
|
4241
|
+
onSubmit: (e) => {
|
|
4242
|
+
e.preventDefault();
|
|
4243
|
+
void submit();
|
|
4244
|
+
},
|
|
4245
|
+
children: [
|
|
4246
|
+
registration.ready ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4247
|
+
/* @__PURE__ */ jsx("p", { className: "pollar-form-description", children: copy.intro }),
|
|
4248
|
+
/* @__PURE__ */ jsx("ul", { className: "pollar-form-description", children: registration.fields.map((key) => /* @__PURE__ */ jsx("li", { children: labels[key] ?? key }, key)) }),
|
|
4249
|
+
/* @__PURE__ */ jsxs("label", { className: "pollar-form-choice", children: [
|
|
4250
|
+
/* @__PURE__ */ jsx(
|
|
4251
|
+
"input",
|
|
4252
|
+
{
|
|
4253
|
+
type: "checkbox",
|
|
4254
|
+
checked: consent,
|
|
4255
|
+
disabled: submitting,
|
|
4256
|
+
onChange: (e) => setConsent(e.target.checked)
|
|
4257
|
+
}
|
|
4258
|
+
),
|
|
4259
|
+
copy.consent
|
|
4260
|
+
] })
|
|
4261
|
+
] }) : /* @__PURE__ */ jsx("p", { className: "pollar-form-error", role: "status", children: copy.notReady }),
|
|
4262
|
+
/* @__PURE__ */ jsxs("div", { className: "pollar-modal-actions", children: [
|
|
4263
|
+
/* @__PURE__ */ jsx("button", { type: "button", className: "pollar-btn-secondary", onClick: onClose, disabled: submitting, children: copy.close }),
|
|
4264
|
+
registration.ready && /* @__PURE__ */ jsx("button", { type: "submit", className: "pollar-btn-primary", disabled: submitting || !consent, children: submitting ? copy.submitting : copy.submit })
|
|
4265
|
+
] })
|
|
4266
|
+
]
|
|
4267
|
+
}
|
|
4268
|
+
)
|
|
4269
|
+
]
|
|
4270
|
+
}
|
|
4271
|
+
) });
|
|
4272
|
+
}
|
|
3194
4273
|
var TERMINAL = ["completed", "failed"];
|
|
3195
4274
|
function requiredFieldsOf(quote) {
|
|
3196
4275
|
return quote.requiredFields ?? [];
|
|
@@ -3223,7 +4302,12 @@ var RAMP_ERROR_MESSAGES = {
|
|
|
3223
4302
|
SDK_RAMPS_WALLET_UNSUPPORTED: "This wallet type cannot be used for this ramp.",
|
|
3224
4303
|
SDK_RAMPS_PROVIDER_NOT_CONFIGURED: "This ramp provider is not configured for this app yet.",
|
|
3225
4304
|
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."
|
|
4305
|
+
SDK_RAMPS_BRIDGE_ERROR: "The provider rejected the request. Please try again in a moment.",
|
|
4306
|
+
SDK_RAMPS_ETHERFUSE_ERROR: "The provider rejected the request. Please try again in a moment.",
|
|
4307
|
+
SDK_RAMPS_INSUFFICIENT_BALANCE: "This wallet does not hold enough to cover that amount. Try a smaller one.",
|
|
4308
|
+
// Nothing moved on-chain, so the balance is untouched. Almost always no XLM
|
|
4309
|
+
// for the network fee on a wallet the app does not sponsor.
|
|
4310
|
+
SDK_RAMPS_ONCHAIN_SUBMIT_FAILED: "The network rejected the transaction, so nothing was sent. The wallet may need XLM for the fee."
|
|
3227
4311
|
};
|
|
3228
4312
|
function rampErrorMessage(e, fallback) {
|
|
3229
4313
|
const body = e?.body;
|
|
@@ -3253,14 +4337,25 @@ function RampWidget({ onClose }) {
|
|
|
3253
4337
|
const [countriesLoading, setCountriesLoading] = useState(true);
|
|
3254
4338
|
const [refreshing, setRefreshing] = useState(false);
|
|
3255
4339
|
const [quotes, setQuotes] = useState([]);
|
|
4340
|
+
const [requirementsRequired, setRequirementsRequired] = useState([]);
|
|
3256
4341
|
const [selectedQuote, setSelectedQuote] = useState(null);
|
|
3257
4342
|
const [isLoading, setIsLoading] = useState(false);
|
|
4343
|
+
const [pendingKyc, setPendingKyc] = useState(null);
|
|
4344
|
+
const [noticeMsg, setNoticeMsg] = useState(null);
|
|
4345
|
+
const kycAttempt = useRef(null);
|
|
4346
|
+
useEffect(
|
|
4347
|
+
() => () => {
|
|
4348
|
+
kycAttempt.current = null;
|
|
4349
|
+
},
|
|
4350
|
+
[]
|
|
4351
|
+
);
|
|
3258
4352
|
const [txId, setTxId] = useState(null);
|
|
3259
4353
|
const [provider, setProvider] = useState("");
|
|
3260
4354
|
const [kycUrl, setKycUrl] = useState(null);
|
|
3261
4355
|
const [tosUrl, setTosUrl] = useState(null);
|
|
3262
4356
|
const [kycPending, setKycPending] = useState(false);
|
|
3263
4357
|
const [kycApproved, setKycApproved] = useState(false);
|
|
4358
|
+
const [onboardingStatus, setOnboardingStatus] = useState(void 0);
|
|
3264
4359
|
const [txStatus, setTxStatus] = useState(null);
|
|
3265
4360
|
const [stellarTxHash, setStellarTxHash] = useState(null);
|
|
3266
4361
|
const [depositInstructions, setDepositInstructions] = useState(null);
|
|
@@ -3291,6 +4386,7 @@ function RampWidget({ onClose }) {
|
|
|
3291
4386
|
}, [step, txId, txStatus, client]);
|
|
3292
4387
|
useEffect(() => {
|
|
3293
4388
|
if (step !== "status" || !kycPending || kycApproved) return;
|
|
4389
|
+
if (onboardingStatus === "awaiting_provider") return;
|
|
3294
4390
|
let active = true;
|
|
3295
4391
|
const check = async () => {
|
|
3296
4392
|
try {
|
|
@@ -3305,7 +4401,7 @@ function RampWidget({ onClose }) {
|
|
|
3305
4401
|
active = false;
|
|
3306
4402
|
clearInterval(id);
|
|
3307
4403
|
};
|
|
3308
|
-
}, [step, kycPending, kycApproved, client]);
|
|
4404
|
+
}, [step, kycPending, kycApproved, onboardingStatus, client]);
|
|
3309
4405
|
async function loadCountries(resetSelection) {
|
|
3310
4406
|
setCountriesLoading(true);
|
|
3311
4407
|
try {
|
|
@@ -3339,6 +4435,7 @@ function RampWidget({ onClose }) {
|
|
|
3339
4435
|
if (step === "select_route") {
|
|
3340
4436
|
const result = await client.getRampsQuote({ country, amount: Number(amount), currency, direction });
|
|
3341
4437
|
setQuotes(result.quotes ?? []);
|
|
4438
|
+
setRequirementsRequired(result.requirementsRequired ?? []);
|
|
3342
4439
|
} else if (step === "status" && txId) {
|
|
3343
4440
|
const tx = await client.getRampTransaction(txId);
|
|
3344
4441
|
setTxStatus(tx.status);
|
|
@@ -3354,6 +4451,7 @@ function RampWidget({ onClose }) {
|
|
|
3354
4451
|
function resetToInput({ keepMessage = false } = {}) {
|
|
3355
4452
|
setStep("input");
|
|
3356
4453
|
setQuotes([]);
|
|
4454
|
+
setRequirementsRequired([]);
|
|
3357
4455
|
setSelectedQuote(null);
|
|
3358
4456
|
setFieldValues({});
|
|
3359
4457
|
setTxId(null);
|
|
@@ -3363,6 +4461,9 @@ function RampWidget({ onClose }) {
|
|
|
3363
4461
|
setTxStatus(null);
|
|
3364
4462
|
setStellarTxHash(null);
|
|
3365
4463
|
setDepositInstructions(null);
|
|
4464
|
+
setKycPending(false);
|
|
4465
|
+
setKycApproved(false);
|
|
4466
|
+
setNoticeMsg(null);
|
|
3366
4467
|
if (!keepMessage) setErrorMsg(null);
|
|
3367
4468
|
}
|
|
3368
4469
|
async function resumeWithSignature(id, ps) {
|
|
@@ -3387,6 +4488,7 @@ function RampWidget({ onClose }) {
|
|
|
3387
4488
|
}
|
|
3388
4489
|
setKycUrl(result.kycUrl ?? null);
|
|
3389
4490
|
setTosUrl(result.tosUrl ?? null);
|
|
4491
|
+
setOnboardingStatus(result.onboardingStatus);
|
|
3390
4492
|
setKycPending(result.kycRequired === true);
|
|
3391
4493
|
if (result.kycRequired) setKycApproved(false);
|
|
3392
4494
|
setTxStatus(result.status);
|
|
@@ -3394,19 +4496,28 @@ function RampWidget({ onClose }) {
|
|
|
3394
4496
|
setDepositInstructions(result.depositInstructions ?? null);
|
|
3395
4497
|
setStep("status");
|
|
3396
4498
|
}
|
|
4499
|
+
async function loadQuotes() {
|
|
4500
|
+
const result = await client.getRampsQuote({ country, amount: Number(amount), currency, direction });
|
|
4501
|
+
const list = result.quotes ?? [];
|
|
4502
|
+
const locked = result.requirementsRequired ?? [];
|
|
4503
|
+
if (list.length === 0 && locked.length === 0) {
|
|
4504
|
+
const down = (result.unavailable ?? []).map((u) => u.provider);
|
|
4505
|
+
setErrorMsg(
|
|
4506
|
+
down.length > 0 ? `${down.join(", ")} ${down.length === 1 ? "is" : "are"} temporarily unavailable. Please try again later.` : `No ramp providers available for ${country} yet.`
|
|
4507
|
+
);
|
|
4508
|
+
setStep("error");
|
|
4509
|
+
return false;
|
|
4510
|
+
}
|
|
4511
|
+
setQuotes(list);
|
|
4512
|
+
setRequirementsRequired(locked);
|
|
4513
|
+
return true;
|
|
4514
|
+
}
|
|
3397
4515
|
async function handleFindRoute() {
|
|
3398
4516
|
setStep("loading_quote");
|
|
3399
4517
|
setIsLoading(true);
|
|
3400
4518
|
setErrorMsg(null);
|
|
3401
4519
|
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);
|
|
4520
|
+
if (!await loadQuotes()) return;
|
|
3410
4521
|
setStep("select_route");
|
|
3411
4522
|
} catch (e) {
|
|
3412
4523
|
setErrorMsg(rampErrorMessage(e, "Failed to fetch quotes."));
|
|
@@ -3418,6 +4529,7 @@ function RampWidget({ onClose }) {
|
|
|
3418
4529
|
function handleSelectQuote(quote) {
|
|
3419
4530
|
setSelectedQuote(quote);
|
|
3420
4531
|
setErrorMsg(null);
|
|
4532
|
+
setNoticeMsg(null);
|
|
3421
4533
|
const broken = brokenLimitOf(Number(amount), quote);
|
|
3422
4534
|
if (broken) {
|
|
3423
4535
|
setErrorMsg(limitMessage(broken.limit, broken.value, currency));
|
|
@@ -3453,12 +4565,47 @@ function RampWidget({ onClose }) {
|
|
|
3453
4565
|
const result = direction === "onramp" ? await client.createOnRamp(base) : await client.createOffRamp(base);
|
|
3454
4566
|
await applyResult(result);
|
|
3455
4567
|
} catch (e) {
|
|
4568
|
+
const requirement = requiredRampKyc(e);
|
|
4569
|
+
if (requirement) {
|
|
4570
|
+
setStep(requiredFieldsOf(quote).length ? "contact" : "select_route");
|
|
4571
|
+
setErrorMsg(
|
|
4572
|
+
requirement.type === "KYC" ? "Identity verification is required before continuing." : "A few more details are required before continuing."
|
|
4573
|
+
);
|
|
4574
|
+
kycAttempt.current = requirement;
|
|
4575
|
+
setPendingKyc(requirement);
|
|
4576
|
+
return;
|
|
4577
|
+
}
|
|
3456
4578
|
setErrorMsg(rampErrorMessage(e, "Failed to start the ramp."));
|
|
3457
4579
|
setStep("error");
|
|
3458
4580
|
} finally {
|
|
3459
4581
|
setIsLoading(false);
|
|
3460
4582
|
}
|
|
3461
4583
|
}
|
|
4584
|
+
async function requoteAfterKyc(completed = "KYC") {
|
|
4585
|
+
setStep("loading_quote");
|
|
4586
|
+
setIsLoading(true);
|
|
4587
|
+
setErrorMsg(null);
|
|
4588
|
+
setSelectedQuote(null);
|
|
4589
|
+
try {
|
|
4590
|
+
if (!await loadQuotes()) return;
|
|
4591
|
+
setNoticeMsg(
|
|
4592
|
+
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."
|
|
4593
|
+
);
|
|
4594
|
+
setStep("select_route");
|
|
4595
|
+
} catch (e) {
|
|
4596
|
+
setErrorMsg(rampErrorMessage(e, "Failed to fetch quotes."));
|
|
4597
|
+
setStep("error");
|
|
4598
|
+
} finally {
|
|
4599
|
+
setIsLoading(false);
|
|
4600
|
+
}
|
|
4601
|
+
}
|
|
4602
|
+
function handleVerifyRoute(requirement) {
|
|
4603
|
+
const attempt = pendingFromQuote(requirement);
|
|
4604
|
+
setErrorMsg(null);
|
|
4605
|
+
setNoticeMsg(null);
|
|
4606
|
+
kycAttempt.current = attempt;
|
|
4607
|
+
setPendingKyc(attempt);
|
|
4608
|
+
}
|
|
3462
4609
|
function handleOpenKyc() {
|
|
3463
4610
|
if (kycUrl) window.open(kycUrl, "_blank", "noopener,noreferrer");
|
|
3464
4611
|
}
|
|
@@ -3487,9 +4634,61 @@ function RampWidget({ onClose }) {
|
|
|
3487
4634
|
}
|
|
3488
4635
|
}
|
|
3489
4636
|
const kycBlocking = kycPending && !kycApproved;
|
|
3490
|
-
const canComplete = direction === "offramp" && step === "status" && txStatus !== "completed" && !stellarTxHash && !
|
|
4637
|
+
const canComplete = direction === "offramp" && step === "status" && txStatus !== "completed" && !stellarTxHash && !kycPending;
|
|
3491
4638
|
const flowSteps = flowStepsOf(quotes, selectedQuote);
|
|
3492
4639
|
const flowStepIndex = flowSteps.indexOf(STEP_LABEL[step] ?? "");
|
|
4640
|
+
if (pendingKyc?.type === "FORM") {
|
|
4641
|
+
return /* @__PURE__ */ jsx(
|
|
4642
|
+
RequirementFormModal,
|
|
4643
|
+
{
|
|
4644
|
+
formId: pendingKyc.optionId,
|
|
4645
|
+
...pendingKyc.progress ? { progress: pendingKyc.progress } : {},
|
|
4646
|
+
onClose: () => {
|
|
4647
|
+
kycAttempt.current = null;
|
|
4648
|
+
setPendingKyc(null);
|
|
4649
|
+
},
|
|
4650
|
+
onSubmitted: () => {
|
|
4651
|
+
if (kycAttempt.current !== pendingKyc) return;
|
|
4652
|
+
kycAttempt.current = null;
|
|
4653
|
+
setPendingKyc(null);
|
|
4654
|
+
void requoteAfterKyc("FORM");
|
|
4655
|
+
}
|
|
4656
|
+
}
|
|
4657
|
+
);
|
|
4658
|
+
}
|
|
4659
|
+
if (pendingKyc?.type === "REGISTRY_CHECK" || pendingKyc?.type === "PROVIDER_REGISTRATION") {
|
|
4660
|
+
const close = () => {
|
|
4661
|
+
kycAttempt.current = null;
|
|
4662
|
+
setPendingKyc(null);
|
|
4663
|
+
};
|
|
4664
|
+
const done = () => {
|
|
4665
|
+
if (kycAttempt.current !== pendingKyc) return;
|
|
4666
|
+
close();
|
|
4667
|
+
void requoteAfterKyc(pendingKyc.type);
|
|
4668
|
+
};
|
|
4669
|
+
const progress = pendingKyc.progress ? { progress: pendingKyc.progress } : {};
|
|
4670
|
+
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 });
|
|
4671
|
+
}
|
|
4672
|
+
if (pendingKyc) {
|
|
4673
|
+
return /* @__PURE__ */ jsx(
|
|
4674
|
+
KycModal,
|
|
4675
|
+
{
|
|
4676
|
+
country,
|
|
4677
|
+
corridorId: pendingKyc.corridorId,
|
|
4678
|
+
providerId: pendingKyc.optionId,
|
|
4679
|
+
onClose: () => {
|
|
4680
|
+
kycAttempt.current = null;
|
|
4681
|
+
setPendingKyc(null);
|
|
4682
|
+
},
|
|
4683
|
+
onApproved: () => {
|
|
4684
|
+
if (kycAttempt.current !== pendingKyc) return;
|
|
4685
|
+
kycAttempt.current = null;
|
|
4686
|
+
setPendingKyc(null);
|
|
4687
|
+
void requoteAfterKyc();
|
|
4688
|
+
}
|
|
4689
|
+
}
|
|
4690
|
+
);
|
|
4691
|
+
}
|
|
3493
4692
|
return /* @__PURE__ */ jsx("div", { className: "pollar-overlay", style: overlayStyle, onClick: onClose, children: /* @__PURE__ */ jsx(
|
|
3494
4693
|
RampWidgetTemplate,
|
|
3495
4694
|
{
|
|
@@ -3510,12 +4709,14 @@ function RampWidget({ onClose }) {
|
|
|
3510
4709
|
countriesLoading,
|
|
3511
4710
|
refreshing,
|
|
3512
4711
|
quotes,
|
|
4712
|
+
kycRequired: requirementsRequired,
|
|
3513
4713
|
isLoading,
|
|
3514
4714
|
provider,
|
|
3515
4715
|
txStatus,
|
|
3516
4716
|
kycUrl,
|
|
3517
4717
|
tosUrl,
|
|
3518
4718
|
kycBlocking,
|
|
4719
|
+
onboardingStatus: onboardingStatus ?? null,
|
|
3519
4720
|
kycJustApproved: kycPending && kycApproved,
|
|
3520
4721
|
stellarTxHash,
|
|
3521
4722
|
explorerUrl: stellarTxHash ? `https://stellar.expert/explorer/${network === "mainnet" ? "public" : "testnet"}/tx/${stellarTxHash}` : null,
|
|
@@ -3523,6 +4724,7 @@ function RampWidget({ onClose }) {
|
|
|
3523
4724
|
canComplete,
|
|
3524
4725
|
completing,
|
|
3525
4726
|
errorMsg,
|
|
4727
|
+
noticeMsg,
|
|
3526
4728
|
onDirectionChange: setDirection,
|
|
3527
4729
|
onAmountChange: (next) => {
|
|
3528
4730
|
setAmount(next);
|
|
@@ -3532,6 +4734,7 @@ function RampWidget({ onClose }) {
|
|
|
3532
4734
|
onCountryChange: handleCountryChange,
|
|
3533
4735
|
onFindRoute: handleFindRoute,
|
|
3534
4736
|
onSelectQuote: handleSelectQuote,
|
|
4737
|
+
onVerifyRoute: handleVerifyRoute,
|
|
3535
4738
|
onContactContinue: handleContactContinue,
|
|
3536
4739
|
onOpenKyc: handleOpenKyc,
|
|
3537
4740
|
onOpenTos: handleOpenTos,
|
|
@@ -3544,6 +4747,18 @@ function RampWidget({ onClose }) {
|
|
|
3544
4747
|
) });
|
|
3545
4748
|
}
|
|
3546
4749
|
|
|
4750
|
+
// src/lib/wallet-provisioning.ts
|
|
4751
|
+
function walletNotReadyReason(wallet, chain) {
|
|
4752
|
+
if (chain !== "STELLAR") return null;
|
|
4753
|
+
if (wallet?.provisioning === "CREATING") {
|
|
4754
|
+
return "Your wallet is still being prepared on the network. This usually takes a few seconds.";
|
|
4755
|
+
}
|
|
4756
|
+
if (wallet?.provisioning === "FAILED") {
|
|
4757
|
+
return "Your wallet could not be created on the network. Sign in again to retry.";
|
|
4758
|
+
}
|
|
4759
|
+
return null;
|
|
4760
|
+
}
|
|
4761
|
+
|
|
3547
4762
|
// src/lib/qr-code/index.tsx
|
|
3548
4763
|
var import_ErrorCorrectLevel = __toESM(require_ErrorCorrectLevel());
|
|
3549
4764
|
var import_QRCode = __toESM(require_QRCode());
|
|
@@ -3586,6 +4801,31 @@ var QRCode = forwardRef(function QRCode2({ bgColor = "#FFFFFF", fgColor = "#0000
|
|
|
3586
4801
|
}
|
|
3587
4802
|
);
|
|
3588
4803
|
});
|
|
4804
|
+
function PollarLogo(props) {
|
|
4805
|
+
return /* @__PURE__ */ jsxs("svg", { width: "45", height: "48", viewBox: "0 0 45 48", fill: "none", xmlns: "http://www.w3.org/2000/svg", ...props, children: [
|
|
4806
|
+
/* @__PURE__ */ jsx(
|
|
4807
|
+
"path",
|
|
4808
|
+
{
|
|
4809
|
+
d: "M27.2476 11.7526L23.3926 10.0529L24.6679 9.14844L26.8168 9.19868L27.7248 10.3873L27.2476 11.7526Z",
|
|
4810
|
+
fill: "#005DB4"
|
|
4811
|
+
}
|
|
4812
|
+
),
|
|
4813
|
+
/* @__PURE__ */ jsx(
|
|
4814
|
+
"path",
|
|
4815
|
+
{
|
|
4816
|
+
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",
|
|
4817
|
+
fill: "#005DB4"
|
|
4818
|
+
}
|
|
4819
|
+
),
|
|
4820
|
+
/* @__PURE__ */ jsx(
|
|
4821
|
+
"path",
|
|
4822
|
+
{
|
|
4823
|
+
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",
|
|
4824
|
+
fill: "#005DB4"
|
|
4825
|
+
}
|
|
4826
|
+
)
|
|
4827
|
+
] });
|
|
4828
|
+
}
|
|
3589
4829
|
var CHAIN_NAME = {
|
|
3590
4830
|
STELLAR: "Stellar",
|
|
3591
4831
|
POLYGON: "Polygon",
|
|
@@ -3600,10 +4840,10 @@ function ReceiveModalTemplate({
|
|
|
3600
4840
|
selectedChain,
|
|
3601
4841
|
onSelectChain,
|
|
3602
4842
|
copied,
|
|
4843
|
+
notReadyReason,
|
|
3603
4844
|
onCopy,
|
|
3604
4845
|
onClose
|
|
3605
4846
|
}) {
|
|
3606
|
-
const isDark = theme === "dark";
|
|
3607
4847
|
const cssVars = buildModalCssVars(theme, accentColor, styleOverrides);
|
|
3608
4848
|
const chainName = selectedChain ? CHAIN_NAME[selectedChain] ?? selectedChain : "wallet";
|
|
3609
4849
|
return /* @__PURE__ */ jsxs(
|
|
@@ -3618,18 +4858,32 @@ function ReceiveModalTemplate({
|
|
|
3618
4858
|
/* @__PURE__ */ jsx("h2", { className: "pollar-modal-title", children: "Receive" }),
|
|
3619
4859
|
/* @__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
4860
|
] }),
|
|
3621
|
-
/* @__PURE__ */ jsx(ChainSelect, { value: selectedChain, options: chains, onChange: onSelectChain }),
|
|
4861
|
+
chains && onSelectChain && /* @__PURE__ */ jsx(ChainSelect, { value: selectedChain, options: chains, onChange: onSelectChain }),
|
|
3622
4862
|
walletAddress ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3623
|
-
/* @__PURE__ */
|
|
3624
|
-
|
|
3625
|
-
|
|
3626
|
-
|
|
3627
|
-
|
|
3628
|
-
|
|
3629
|
-
|
|
4863
|
+
/* @__PURE__ */ jsxs("div", { className: "pollar-receive-qr", children: [
|
|
4864
|
+
/* @__PURE__ */ jsxs("div", { className: "pollar-receive-network-badge", children: [
|
|
4865
|
+
/* @__PURE__ */ jsx("span", { className: "pollar-receive-network-dot", "aria-hidden": true }),
|
|
4866
|
+
chainName,
|
|
4867
|
+
" network"
|
|
4868
|
+
] }),
|
|
4869
|
+
/* @__PURE__ */ jsxs("div", { className: "pollar-receive-qr-frame", children: [
|
|
4870
|
+
/* @__PURE__ */ jsx(
|
|
4871
|
+
QRCode,
|
|
4872
|
+
{
|
|
4873
|
+
value: walletAddress,
|
|
4874
|
+
size: 220,
|
|
4875
|
+
level: "H",
|
|
4876
|
+
fgColor: "#111827",
|
|
4877
|
+
bgColor: "#ffffff",
|
|
4878
|
+
title: `${chainName} wallet QR code`
|
|
4879
|
+
}
|
|
4880
|
+
),
|
|
4881
|
+
/* @__PURE__ */ jsx("span", { className: "pollar-receive-qr-mark", "aria-hidden": true, children: /* @__PURE__ */ jsx(PollarLogo, { width: "22", height: "24" }) })
|
|
4882
|
+
] })
|
|
3630
4883
|
] }),
|
|
3631
|
-
/* @__PURE__ */
|
|
3632
|
-
|
|
4884
|
+
notReadyReason && /* @__PURE__ */ jsx("div", { className: "pollar-receive-notice", children: notReadyReason }),
|
|
4885
|
+
/* @__PURE__ */ jsxs("div", { className: "pollar-receive-address-actions", children: [
|
|
4886
|
+
/* @__PURE__ */ jsx("div", { className: "pollar-receive-address-row", children: /* @__PURE__ */ jsx("span", { className: "pollar-receive-address", children: walletAddress }) }),
|
|
3633
4887
|
/* @__PURE__ */ jsx("button", { type: "button", className: "pollar-receive-copy-btn", onClick: onCopy, "aria-label": "Copy address", children: copied ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3634
4888
|
/* @__PURE__ */ jsxs("svg", { width: "13", height: "13", viewBox: "0 0 14 14", fill: "none", "aria-hidden": true, children: [
|
|
3635
4889
|
/* @__PURE__ */ jsx("circle", { cx: "7", cy: "7", r: "7", fill: "currentColor" }),
|
|
@@ -3644,7 +4898,7 @@ function ReceiveModalTemplate({
|
|
|
3644
4898
|
}
|
|
3645
4899
|
)
|
|
3646
4900
|
] }),
|
|
3647
|
-
"Copied
|
|
4901
|
+
"Copied"
|
|
3648
4902
|
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3649
4903
|
/* @__PURE__ */ jsxs("svg", { width: "13", height: "13", viewBox: "0 0 13 13", fill: "none", "aria-hidden": true, children: [
|
|
3650
4904
|
/* @__PURE__ */ jsx("rect", { x: "4", y: "4", width: "8", height: "8", rx: "1.5", stroke: "currentColor", strokeWidth: "1.5" }),
|
|
@@ -3658,17 +4912,28 @@ function ReceiveModalTemplate({
|
|
|
3658
4912
|
}
|
|
3659
4913
|
)
|
|
3660
4914
|
] }),
|
|
3661
|
-
"Copy
|
|
4915
|
+
"Copy"
|
|
3662
4916
|
] }) })
|
|
4917
|
+
] }),
|
|
4918
|
+
/* @__PURE__ */ jsxs("p", { className: "pollar-receive-warning", children: [
|
|
4919
|
+
/* @__PURE__ */ jsxs("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", "aria-hidden": true, children: [
|
|
4920
|
+
/* @__PURE__ */ jsx("circle", { cx: "7", cy: "7", r: "5.5", stroke: "currentColor", strokeWidth: "1.25" }),
|
|
4921
|
+
/* @__PURE__ */ jsx("path", { d: "M7 6.25V9.25M7 4.5V4.75", stroke: "currentColor", strokeWidth: "1.25", strokeLinecap: "round" })
|
|
4922
|
+
] }),
|
|
4923
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
4924
|
+
"Only send ",
|
|
4925
|
+
chainName,
|
|
4926
|
+
" assets to this address"
|
|
4927
|
+
] })
|
|
3663
4928
|
] })
|
|
3664
4929
|
] }) : /* @__PURE__ */ jsx("div", { className: "pollar-modal-empty", children: "No wallet connected." }),
|
|
3665
|
-
/* @__PURE__ */ jsx(PollarModalFooter, {})
|
|
4930
|
+
/* @__PURE__ */ jsx(PollarModalFooter, { shield: true })
|
|
3666
4931
|
]
|
|
3667
4932
|
}
|
|
3668
4933
|
);
|
|
3669
4934
|
}
|
|
3670
4935
|
function ReceiveModal({ onClose }) {
|
|
3671
|
-
const { wallets, styles } = usePollar();
|
|
4936
|
+
const { wallet, wallets, styles } = usePollar();
|
|
3672
4937
|
const { theme, accentColor, styleOverrides, overlayStyle } = modalChrome(styles);
|
|
3673
4938
|
const [copied, setCopied] = useState(false);
|
|
3674
4939
|
const copyTimerRef = useRef(null);
|
|
@@ -3678,6 +4943,7 @@ function ReceiveModal({ onClose }) {
|
|
|
3678
4943
|
if (selectedChain === null && chains.length > 0) setSelectedChain(chains[0]);
|
|
3679
4944
|
}, [chains, selectedChain]);
|
|
3680
4945
|
const walletAddress = addressForChain(wallets, selectedChain);
|
|
4946
|
+
const notReadyReason = walletNotReadyReason(wallet, selectedChain);
|
|
3681
4947
|
useEffect(
|
|
3682
4948
|
() => () => {
|
|
3683
4949
|
if (copyTimerRef.current !== null) clearTimeout(copyTimerRef.current);
|
|
@@ -3708,53 +4974,13 @@ function ReceiveModal({ onClose }) {
|
|
|
3708
4974
|
setCopied(false);
|
|
3709
4975
|
setSelectedChain(chain);
|
|
3710
4976
|
},
|
|
4977
|
+
notReadyReason,
|
|
3711
4978
|
copied,
|
|
3712
4979
|
onCopy: handleCopy,
|
|
3713
4980
|
onClose
|
|
3714
4981
|
}
|
|
3715
4982
|
) });
|
|
3716
4983
|
}
|
|
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
4984
|
var STATUS_MESSAGES = {
|
|
3759
4985
|
idle: "",
|
|
3760
4986
|
building: "Building transaction\u2026",
|
|
@@ -3960,6 +5186,97 @@ function formatBalance(balance) {
|
|
|
3960
5186
|
function assetKey3(record) {
|
|
3961
5187
|
return `${record.code}:${record.issuer ?? "native"}`;
|
|
3962
5188
|
}
|
|
5189
|
+
function chainLabel(chain) {
|
|
5190
|
+
if (chain === "STELLAR") return "Stellar";
|
|
5191
|
+
if (chain === "SOLANA") return "Solana";
|
|
5192
|
+
if (chain === "POLYGON") return "Polygon";
|
|
5193
|
+
return "network";
|
|
5194
|
+
}
|
|
5195
|
+
function AssetIcon({ code }) {
|
|
5196
|
+
return /* @__PURE__ */ jsx("span", { className: "pollar-send-asset-icon", "aria-hidden": true, children: code.slice(0, 2).toUpperCase() });
|
|
5197
|
+
}
|
|
5198
|
+
function SendAssetSelector({ assets, selectedAsset, loading, onSelectAsset }) {
|
|
5199
|
+
const [open, setOpen] = useState(false);
|
|
5200
|
+
const triggerRef = useRef(null);
|
|
5201
|
+
useEffect(() => {
|
|
5202
|
+
if (!open) return;
|
|
5203
|
+
const closeOnOutsideClick = (event) => {
|
|
5204
|
+
if (!(event.target instanceof Node) || !triggerRef.current?.parentElement?.contains(event.target)) setOpen(false);
|
|
5205
|
+
};
|
|
5206
|
+
document.addEventListener("mousedown", closeOnOutsideClick);
|
|
5207
|
+
return () => document.removeEventListener("mousedown", closeOnOutsideClick);
|
|
5208
|
+
}, [open]);
|
|
5209
|
+
function handleTriggerKeyDown(event) {
|
|
5210
|
+
if (event.key === "ArrowDown" || event.key === "Enter" || event.key === " ") {
|
|
5211
|
+
event.preventDefault();
|
|
5212
|
+
setOpen(true);
|
|
5213
|
+
}
|
|
5214
|
+
}
|
|
5215
|
+
if (loading) {
|
|
5216
|
+
return /* @__PURE__ */ jsxs("div", { className: "pollar-send-field", children: [
|
|
5217
|
+
/* @__PURE__ */ jsx("span", { className: "pollar-send-label", children: "Asset" }),
|
|
5218
|
+
/* @__PURE__ */ jsxs("div", { className: "pollar-send-asset-selector pollar-send-asset-selector-loading", "aria-label": "Loading assets", children: [
|
|
5219
|
+
/* @__PURE__ */ jsx("span", { className: "pollar-spinner pollar-spinner-sm" }),
|
|
5220
|
+
/* @__PURE__ */ jsx("span", { children: "Loading assets\u2026" })
|
|
5221
|
+
] })
|
|
5222
|
+
] });
|
|
5223
|
+
}
|
|
5224
|
+
return /* @__PURE__ */ jsxs("div", { className: "pollar-send-field", children: [
|
|
5225
|
+
/* @__PURE__ */ jsx("label", { className: "pollar-send-label", id: "pollar-send-asset-label", children: "Asset" }),
|
|
5226
|
+
/* @__PURE__ */ jsxs("div", { className: "pollar-send-asset-picker", children: [
|
|
5227
|
+
/* @__PURE__ */ jsxs(
|
|
5228
|
+
"button",
|
|
5229
|
+
{
|
|
5230
|
+
ref: triggerRef,
|
|
5231
|
+
type: "button",
|
|
5232
|
+
className: "pollar-send-asset-selector",
|
|
5233
|
+
"aria-labelledby": "pollar-send-asset-label",
|
|
5234
|
+
"aria-haspopup": "listbox",
|
|
5235
|
+
"aria-expanded": open,
|
|
5236
|
+
disabled: !selectedAsset,
|
|
5237
|
+
onClick: () => setOpen((value) => !value),
|
|
5238
|
+
onKeyDown: handleTriggerKeyDown,
|
|
5239
|
+
children: [
|
|
5240
|
+
selectedAsset ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
5241
|
+
/* @__PURE__ */ jsx(AssetIcon, { code: selectedAsset.code }),
|
|
5242
|
+
/* @__PURE__ */ jsxs("span", { className: "pollar-send-asset-copy", children: [
|
|
5243
|
+
/* @__PURE__ */ jsx("strong", { children: selectedAsset.code }),
|
|
5244
|
+
/* @__PURE__ */ jsx("small", { children: selectedAsset.available === null ? "Balance unavailable" : `${formatBalance(selectedAsset.available)} available` })
|
|
5245
|
+
] })
|
|
5246
|
+
] }) : /* @__PURE__ */ jsx("span", { className: "pollar-send-asset-copy", children: /* @__PURE__ */ jsx("strong", { children: "No assets available" }) }),
|
|
5247
|
+
/* @__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" }) })
|
|
5248
|
+
]
|
|
5249
|
+
}
|
|
5250
|
+
),
|
|
5251
|
+
open && assets.length > 0 && /* @__PURE__ */ jsx("div", { className: "pollar-send-asset-menu", role: "listbox", "aria-label": "Assets", children: assets.map((asset) => {
|
|
5252
|
+
const key = assetKey3(asset);
|
|
5253
|
+
const selected = selectedAsset ? key === assetKey3(selectedAsset) : false;
|
|
5254
|
+
return /* @__PURE__ */ jsxs(
|
|
5255
|
+
"button",
|
|
5256
|
+
{
|
|
5257
|
+
type: "button",
|
|
5258
|
+
role: "option",
|
|
5259
|
+
"aria-selected": selected,
|
|
5260
|
+
className: `pollar-send-asset-option${selected ? " is-selected" : ""}`,
|
|
5261
|
+
onClick: () => {
|
|
5262
|
+
onSelectAsset(asset);
|
|
5263
|
+
setOpen(false);
|
|
5264
|
+
triggerRef.current?.focus();
|
|
5265
|
+
},
|
|
5266
|
+
children: [
|
|
5267
|
+
/* @__PURE__ */ jsx(AssetIcon, { code: asset.code }),
|
|
5268
|
+
/* @__PURE__ */ jsxs("span", { className: "pollar-send-asset-copy", children: [
|
|
5269
|
+
/* @__PURE__ */ jsx("strong", { children: asset.code }),
|
|
5270
|
+
/* @__PURE__ */ jsx("small", { children: asset.available === null ? "Balance unavailable" : `${formatBalance(asset.available)} available` })
|
|
5271
|
+
] })
|
|
5272
|
+
]
|
|
5273
|
+
},
|
|
5274
|
+
key
|
|
5275
|
+
);
|
|
5276
|
+
}) })
|
|
5277
|
+
] })
|
|
5278
|
+
] });
|
|
5279
|
+
}
|
|
3963
5280
|
function SendModalTemplate({
|
|
3964
5281
|
theme,
|
|
3965
5282
|
accentColor,
|
|
@@ -3968,10 +5285,10 @@ function SendModalTemplate({
|
|
|
3968
5285
|
txTitle,
|
|
3969
5286
|
assets,
|
|
3970
5287
|
selectedAsset,
|
|
3971
|
-
chains,
|
|
3972
5288
|
selectedChain,
|
|
3973
|
-
walletAddress,
|
|
3974
5289
|
canSendOnChain,
|
|
5290
|
+
notReadyReason,
|
|
5291
|
+
chains,
|
|
3975
5292
|
onSelectChain,
|
|
3976
5293
|
amount,
|
|
3977
5294
|
destination,
|
|
@@ -3989,6 +5306,8 @@ function SendModalTemplate({
|
|
|
3989
5306
|
onRefresh,
|
|
3990
5307
|
onSelectAsset,
|
|
3991
5308
|
onAmountChange,
|
|
5309
|
+
onMax,
|
|
5310
|
+
onPaste,
|
|
3992
5311
|
onDestinationChange,
|
|
3993
5312
|
onSubmit,
|
|
3994
5313
|
onSignAndSend,
|
|
@@ -3998,8 +5317,9 @@ function SendModalTemplate({
|
|
|
3998
5317
|
onDone
|
|
3999
5318
|
}) {
|
|
4000
5319
|
const cssVars = buildModalCssVars(theme, accentColor, styleOverrides);
|
|
4001
|
-
const
|
|
4002
|
-
const
|
|
5320
|
+
const parsedAmount = amount ? Number(amount) : 0;
|
|
5321
|
+
const availableAmount = selectedAsset?.available === null || selectedAsset?.available === void 0 ? 0 : Number(selectedAsset.available);
|
|
5322
|
+
const canSubmit = canSendOnChain && !notReadyReason && !!selectedAsset && Number.isFinite(parsedAmount) && parsedAmount > 0 && parsedAmount <= availableAmount && !!destination.trim() && !isLoadingBalance;
|
|
4003
5323
|
const title = step === "form" ? "Send" : txTitle;
|
|
4004
5324
|
return /* @__PURE__ */ jsxs(
|
|
4005
5325
|
"div",
|
|
@@ -4012,7 +5332,14 @@ function SendModalTemplate({
|
|
|
4012
5332
|
/* @__PURE__ */ jsxs("div", { className: "pollar-modal-header", children: [
|
|
4013
5333
|
/* @__PURE__ */ jsxs("div", { className: "pollar-send-header-left", children: [
|
|
4014
5334
|
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__ */
|
|
5335
|
+
/* @__PURE__ */ jsxs("div", { className: "pollar-send-title-copy", children: [
|
|
5336
|
+
/* @__PURE__ */ jsx("h2", { className: "pollar-modal-title", children: title }),
|
|
5337
|
+
step === "form" && /* @__PURE__ */ jsxs("p", { className: "pollar-send-subtitle", children: [
|
|
5338
|
+
"Transfer assets to another ",
|
|
5339
|
+
chainLabel(selectedChain),
|
|
5340
|
+
" wallet"
|
|
5341
|
+
] })
|
|
5342
|
+
] })
|
|
4016
5343
|
] }),
|
|
4017
5344
|
!isInProgress && /* @__PURE__ */ jsxs("div", { className: "pollar-modal-header-actions", children: [
|
|
4018
5345
|
step === "form" && /* @__PURE__ */ jsx(
|
|
@@ -4024,58 +5351,23 @@ function SendModalTemplate({
|
|
|
4024
5351
|
disabled: isLoadingBalance,
|
|
4025
5352
|
"aria-label": "Refresh",
|
|
4026
5353
|
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
|
-
)
|
|
5354
|
+
children: /* @__PURE__ */ jsx(RefreshIcon, { spinning: isLoadingBalance })
|
|
4048
5355
|
}
|
|
4049
5356
|
),
|
|
4050
5357
|
/* @__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
5358
|
] })
|
|
4052
5359
|
] }),
|
|
4053
5360
|
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
|
-
] }),
|
|
5361
|
+
chains && onSelectChain && /* @__PURE__ */ jsx(ChainSelect, { value: selectedChain, options: chains, onChange: onSelectChain, disabled: isLoadingBalance }),
|
|
4059
5362
|
!canSendOnChain && /* @__PURE__ */ jsx("div", { className: "pollar-modal-empty", children: "Sending is not available on this network yet." }),
|
|
5363
|
+
canSendOnChain && notReadyReason && /* @__PURE__ */ jsx("div", { className: "pollar-modal-empty", children: notReadyReason }),
|
|
4060
5364
|
/* @__PURE__ */ jsx(
|
|
4061
|
-
|
|
5365
|
+
SendAssetSelector,
|
|
4062
5366
|
{
|
|
4063
|
-
|
|
4064
|
-
|
|
5367
|
+
assets,
|
|
5368
|
+
selectedAsset,
|
|
4065
5369
|
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
|
-
}
|
|
5370
|
+
onSelectAsset
|
|
4079
5371
|
}
|
|
4080
5372
|
),
|
|
4081
5373
|
/* @__PURE__ */ jsxs("div", { className: "pollar-send-field", children: [
|
|
@@ -4088,30 +5380,50 @@ function SendModalTemplate({
|
|
|
4088
5380
|
selectedAsset.code
|
|
4089
5381
|
] })
|
|
4090
5382
|
] }),
|
|
4091
|
-
/* @__PURE__ */
|
|
4092
|
-
|
|
4093
|
-
|
|
4094
|
-
|
|
4095
|
-
|
|
4096
|
-
|
|
4097
|
-
|
|
4098
|
-
|
|
4099
|
-
|
|
4100
|
-
|
|
4101
|
-
|
|
5383
|
+
/* @__PURE__ */ jsxs("div", { className: "pollar-send-input-shell", children: [
|
|
5384
|
+
/* @__PURE__ */ jsx(
|
|
5385
|
+
"input",
|
|
5386
|
+
{
|
|
5387
|
+
className: "pollar-input pollar-send-amount-input",
|
|
5388
|
+
type: "text",
|
|
5389
|
+
inputMode: "decimal",
|
|
5390
|
+
placeholder: "0.00",
|
|
5391
|
+
value: amount,
|
|
5392
|
+
onChange: (e) => onAmountChange(e.target.value),
|
|
5393
|
+
"aria-label": "Amount"
|
|
5394
|
+
}
|
|
5395
|
+
),
|
|
5396
|
+
/* @__PURE__ */ jsxs("div", { className: "pollar-send-input-suffix", children: [
|
|
5397
|
+
/* @__PURE__ */ jsx(
|
|
5398
|
+
"button",
|
|
5399
|
+
{
|
|
5400
|
+
type: "button",
|
|
5401
|
+
className: "pollar-send-inline-action",
|
|
5402
|
+
onClick: onMax,
|
|
5403
|
+
disabled: !selectedAsset?.available,
|
|
5404
|
+
children: "Max"
|
|
5405
|
+
}
|
|
5406
|
+
),
|
|
5407
|
+
/* @__PURE__ */ jsx("span", { children: selectedAsset?.code ?? "" })
|
|
5408
|
+
] })
|
|
5409
|
+
] })
|
|
4102
5410
|
] }),
|
|
4103
5411
|
/* @__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
|
-
|
|
5412
|
+
/* @__PURE__ */ jsx("label", { className: "pollar-send-label", children: "Destination wallet" }),
|
|
5413
|
+
/* @__PURE__ */ jsxs("div", { className: "pollar-send-input-shell", children: [
|
|
5414
|
+
/* @__PURE__ */ jsx(
|
|
5415
|
+
"input",
|
|
5416
|
+
{
|
|
5417
|
+
className: "pollar-input pollar-send-destination-input",
|
|
5418
|
+
type: "text",
|
|
5419
|
+
placeholder: "G\u2026",
|
|
5420
|
+
value: destination,
|
|
5421
|
+
onChange: (e) => onDestinationChange(e.target.value),
|
|
5422
|
+
"aria-label": "Destination wallet"
|
|
5423
|
+
}
|
|
5424
|
+
),
|
|
5425
|
+
/* @__PURE__ */ jsx("button", { type: "button", className: "pollar-send-inline-action", onClick: onPaste, children: "Paste" })
|
|
5426
|
+
] })
|
|
4115
5427
|
] }),
|
|
4116
5428
|
formError && /* @__PURE__ */ jsx("div", { className: "pollar-modal-error", children: formError }),
|
|
4117
5429
|
/* @__PURE__ */ jsx("div", { className: "pollar-modal-actions", children: /* @__PURE__ */ jsx("button", { className: "pollar-btn-primary", onClick: onSubmit, disabled: !canSubmit, children: "Continue" }) })
|
|
@@ -4152,7 +5464,6 @@ function SendModal({ onClose }) {
|
|
|
4152
5464
|
signAndSubmitTx,
|
|
4153
5465
|
tx: transaction,
|
|
4154
5466
|
wallet,
|
|
4155
|
-
wallets,
|
|
4156
5467
|
network,
|
|
4157
5468
|
styles
|
|
4158
5469
|
} = usePollar();
|
|
@@ -4171,8 +5482,8 @@ function SendModal({ onClose }) {
|
|
|
4171
5482
|
useEffect(() => {
|
|
4172
5483
|
if (selectedChain === null && chains.length > 0) setSelectedChain(chains[0]);
|
|
4173
5484
|
}, [chains, selectedChain]);
|
|
4174
|
-
const walletAddress = addressForChain(wallets, selectedChain);
|
|
4175
5485
|
const canSendOnChain = selectedChain === "STELLAR" || selectedChain === "SOLANA";
|
|
5486
|
+
const notReadyReason = walletNotReadyReason(wallet, selectedChain);
|
|
4176
5487
|
const isBaseUnitChain = selectedChain === "SOLANA";
|
|
4177
5488
|
useEffect(() => {
|
|
4178
5489
|
void refreshWalletBalance();
|
|
@@ -4219,6 +5530,10 @@ function SendModal({ onClose }) {
|
|
|
4219
5530
|
setFormError("Sending is not available on this network yet.");
|
|
4220
5531
|
return;
|
|
4221
5532
|
}
|
|
5533
|
+
if (notReadyReason) {
|
|
5534
|
+
setFormError(notReadyReason);
|
|
5535
|
+
return;
|
|
5536
|
+
}
|
|
4222
5537
|
if (!selectedAsset) {
|
|
4223
5538
|
setFormError("Select an asset");
|
|
4224
5539
|
return;
|
|
@@ -4269,6 +5584,29 @@ function SendModal({ onClose }) {
|
|
|
4269
5584
|
void signAndSubmitTx(transaction.buildData.unsignedXdr);
|
|
4270
5585
|
}
|
|
4271
5586
|
}
|
|
5587
|
+
function handleMax() {
|
|
5588
|
+
if (selectedAsset?.available !== null && selectedAsset?.available !== void 0) {
|
|
5589
|
+
setAmount(selectedAsset.available);
|
|
5590
|
+
setFormError("");
|
|
5591
|
+
}
|
|
5592
|
+
}
|
|
5593
|
+
async function handlePaste() {
|
|
5594
|
+
if (!navigator.clipboard?.readText) {
|
|
5595
|
+
setFormError("Clipboard access is not available. Paste the address manually.");
|
|
5596
|
+
return;
|
|
5597
|
+
}
|
|
5598
|
+
try {
|
|
5599
|
+
const value = (await navigator.clipboard.readText()).trim();
|
|
5600
|
+
if (!value) {
|
|
5601
|
+
setFormError("The clipboard is empty.");
|
|
5602
|
+
return;
|
|
5603
|
+
}
|
|
5604
|
+
setDestination(value);
|
|
5605
|
+
setFormError("");
|
|
5606
|
+
} catch {
|
|
5607
|
+
setFormError("Could not read the clipboard. Paste the address manually.");
|
|
5608
|
+
}
|
|
5609
|
+
}
|
|
4272
5610
|
function handleCopyHash() {
|
|
4273
5611
|
if (!hash) return;
|
|
4274
5612
|
navigator.clipboard.writeText(hash).then(() => {
|
|
@@ -4302,8 +5640,8 @@ function SendModal({ onClose }) {
|
|
|
4302
5640
|
selectedAsset,
|
|
4303
5641
|
chains,
|
|
4304
5642
|
selectedChain,
|
|
4305
|
-
walletAddress,
|
|
4306
5643
|
canSendOnChain,
|
|
5644
|
+
notReadyReason,
|
|
4307
5645
|
onSelectChain: setSelectedChain,
|
|
4308
5646
|
amount,
|
|
4309
5647
|
destination,
|
|
@@ -4321,6 +5659,8 @@ function SendModal({ onClose }) {
|
|
|
4321
5659
|
onRefresh: () => void refreshWalletBalance(),
|
|
4322
5660
|
onSelectAsset: setSelectedAsset,
|
|
4323
5661
|
onAmountChange: setAmount,
|
|
5662
|
+
onMax: handleMax,
|
|
5663
|
+
onPaste: handlePaste,
|
|
4324
5664
|
onDestinationChange: setDestination,
|
|
4325
5665
|
onSubmit: () => void handleSubmit(),
|
|
4326
5666
|
onSignAndSend: handleSignAndSend,
|
|
@@ -4335,15 +5675,77 @@ function assetOptionKey(o) {
|
|
|
4335
5675
|
return `${o.code}:${o.issuer ?? "native"}`;
|
|
4336
5676
|
}
|
|
4337
5677
|
var PROVIDER_LABELS = {
|
|
4338
|
-
auto: "Best price
|
|
5678
|
+
auto: "Best price",
|
|
4339
5679
|
aquarius: "Aquarius",
|
|
4340
5680
|
soroswap: "Soroswap",
|
|
4341
5681
|
sdex: "Stellar DEX"
|
|
4342
5682
|
};
|
|
4343
|
-
function
|
|
5683
|
+
function formatAmount2(value) {
|
|
5684
|
+
if (value === void 0) return "\u2014";
|
|
4344
5685
|
const n = parseFloat(value);
|
|
4345
5686
|
return isNaN(n) ? value : n.toLocaleString(void 0, { maximumFractionDigits: 7 });
|
|
4346
5687
|
}
|
|
5688
|
+
function formatRate(numerator, denominator) {
|
|
5689
|
+
const parse = (value) => {
|
|
5690
|
+
const trimmed = value.trim();
|
|
5691
|
+
if (!/^\d+(\.\d+)?$/.test(trimmed)) return null;
|
|
5692
|
+
const [whole2 = "0", fraction2 = ""] = trimmed.split(".");
|
|
5693
|
+
return { digits: BigInt(`${whole2}${fraction2}`), scale: fraction2.length };
|
|
5694
|
+
};
|
|
5695
|
+
const top = parse(numerator);
|
|
5696
|
+
const bottom = parse(denominator);
|
|
5697
|
+
if (!top || !bottom || bottom.digits === 0n || top.digits === 0n) return null;
|
|
5698
|
+
const precision = 8;
|
|
5699
|
+
const scaledNumerator = top.digits * 10n ** BigInt(bottom.scale + precision);
|
|
5700
|
+
const scaledDenominator = bottom.digits * 10n ** BigInt(top.scale);
|
|
5701
|
+
const scaled = scaledNumerator / scaledDenominator;
|
|
5702
|
+
const whole = scaled / 10n ** BigInt(precision);
|
|
5703
|
+
const fraction = (scaled % 10n ** BigInt(precision)).toString().padStart(precision, "0").replace(/0+$/, "");
|
|
5704
|
+
return fraction ? `${whole}.${fraction}` : whole.toString();
|
|
5705
|
+
}
|
|
5706
|
+
function AssetIcon2({ code }) {
|
|
5707
|
+
return /* @__PURE__ */ jsx("span", { className: "pollar-swap-asset-icon", "aria-hidden": true, children: code.slice(0, 2).toUpperCase() });
|
|
5708
|
+
}
|
|
5709
|
+
function AssetPill({
|
|
5710
|
+
label,
|
|
5711
|
+
value,
|
|
5712
|
+
options,
|
|
5713
|
+
disabled,
|
|
5714
|
+
onChange
|
|
5715
|
+
}) {
|
|
5716
|
+
const selected = options.find((option) => assetOptionKey(option) === value);
|
|
5717
|
+
const appAssets = options.filter((option) => option.enabledInApp);
|
|
5718
|
+
const otherAssets = options.filter((option) => !option.enabledInApp);
|
|
5719
|
+
return /* @__PURE__ */ jsxs("label", { className: "pollar-swap-asset-pill-wrap", children: [
|
|
5720
|
+
/* @__PURE__ */ jsx("span", { className: "sr-only", children: label }),
|
|
5721
|
+
/* @__PURE__ */ jsx(AssetIcon2, { code: selected?.code ?? "\u2014" }),
|
|
5722
|
+
/* @__PURE__ */ jsxs(
|
|
5723
|
+
"select",
|
|
5724
|
+
{
|
|
5725
|
+
className: "pollar-swap-asset-pill",
|
|
5726
|
+
"aria-label": label,
|
|
5727
|
+
value,
|
|
5728
|
+
disabled,
|
|
5729
|
+
onChange: (event) => onChange(event.target.value),
|
|
5730
|
+
children: [
|
|
5731
|
+
value === "" && /* @__PURE__ */ jsx("option", { value: "", disabled: true, hidden: true }),
|
|
5732
|
+
appAssets.length > 0 && /* @__PURE__ */ jsx("optgroup", { label: "App assets", children: appAssets.map((option) => /* @__PURE__ */ jsx("option", { value: assetOptionKey(option), children: option.code }, assetOptionKey(option))) }),
|
|
5733
|
+
otherAssets.length > 0 && /* @__PURE__ */ jsx("optgroup", { label: "Other assets", children: otherAssets.map((option) => /* @__PURE__ */ jsx("option", { value: assetOptionKey(option), children: option.code }, assetOptionKey(option))) })
|
|
5734
|
+
]
|
|
5735
|
+
}
|
|
5736
|
+
),
|
|
5737
|
+
/* @__PURE__ */ jsx("svg", { className: "pollar-swap-chevron", width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsx(
|
|
5738
|
+
"path",
|
|
5739
|
+
{
|
|
5740
|
+
d: "m3.5 5.25 3.5 3.5 3.5-3.5",
|
|
5741
|
+
stroke: "currentColor",
|
|
5742
|
+
strokeWidth: "1.5",
|
|
5743
|
+
strokeLinecap: "round",
|
|
5744
|
+
strokeLinejoin: "round"
|
|
5745
|
+
}
|
|
5746
|
+
) })
|
|
5747
|
+
] });
|
|
5748
|
+
}
|
|
4347
5749
|
function SwapModalTemplate({
|
|
4348
5750
|
theme,
|
|
4349
5751
|
accentColor,
|
|
@@ -4379,6 +5781,8 @@ function SwapModalTemplate({
|
|
|
4379
5781
|
onSelectSell,
|
|
4380
5782
|
onSelectBuy,
|
|
4381
5783
|
onAddCustomToken,
|
|
5784
|
+
onReverse,
|
|
5785
|
+
onMax,
|
|
4382
5786
|
onAmountChange,
|
|
4383
5787
|
onProviderChange,
|
|
4384
5788
|
onSwap,
|
|
@@ -4405,19 +5809,29 @@ function SwapModalTemplate({
|
|
|
4405
5809
|
const cssVars = buildModalCssVars(theme, accentColor, styleOverrides);
|
|
4406
5810
|
const sellKey = selectedSell ? assetOptionKey(selectedSell) : "";
|
|
4407
5811
|
const buyKey = selectedBuy ? assetOptionKey(selectedBuy) : "";
|
|
4408
|
-
const
|
|
5812
|
+
const sameAsset = !!selectedSell && !!selectedBuy && sellKey === buyKey;
|
|
5813
|
+
const canSwap = !smartUnsupported && !sameAsset && !!selectedSell && !!selectedBuy && !!amount && !!quote && !quoteLoading && !isLoadingData;
|
|
5814
|
+
const rate = quote && amount ? formatRate(quote.amountOut, amount) : null;
|
|
4409
5815
|
const title = step === "form" ? "Swap" : txTitle;
|
|
5816
|
+
const selectSell = (key) => {
|
|
5817
|
+
const found = sellOptions.find((option) => assetOptionKey(option) === key);
|
|
5818
|
+
if (found) onSelectSell(found);
|
|
5819
|
+
};
|
|
5820
|
+
const selectBuy = (key) => {
|
|
5821
|
+
const found = buyOptions.find((option) => assetOptionKey(option) === key);
|
|
5822
|
+
if (found) onSelectBuy(found);
|
|
5823
|
+
};
|
|
4410
5824
|
return /* @__PURE__ */ jsxs(
|
|
4411
5825
|
"div",
|
|
4412
5826
|
{
|
|
4413
|
-
className: "pollar-modal-card pollar-
|
|
5827
|
+
className: "pollar-modal-card pollar-swap-modal",
|
|
4414
5828
|
"data-theme": theme,
|
|
4415
5829
|
style: cssVars,
|
|
4416
|
-
onClick: (
|
|
5830
|
+
onClick: (event) => event.stopPropagation(),
|
|
4417
5831
|
children: [
|
|
4418
5832
|
/* @__PURE__ */ jsxs("div", { className: "pollar-modal-header", children: [
|
|
4419
5833
|
/* @__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
|
|
5834
|
+
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
5835
|
/* @__PURE__ */ jsx("h2", { className: "pollar-modal-title", children: title })
|
|
4422
5836
|
] }),
|
|
4423
5837
|
!isInProgress && /* @__PURE__ */ jsxs("div", { className: "pollar-modal-header-actions", children: [
|
|
@@ -4430,16 +5844,7 @@ function SwapModalTemplate({
|
|
|
4430
5844
|
disabled: configLoading || isLoadingData,
|
|
4431
5845
|
"aria-label": "Refresh",
|
|
4432
5846
|
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
|
-
) })
|
|
5847
|
+
children: /* @__PURE__ */ jsx(RefreshIcon, { spinning: configLoading || isLoadingData })
|
|
4443
5848
|
}
|
|
4444
5849
|
),
|
|
4445
5850
|
/* @__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 +5853,205 @@ function SwapModalTemplate({
|
|
|
4448
5853
|
step === "form" && !configLoading && swapUnavailable && /* @__PURE__ */ jsx("div", { className: "pollar-modal-error", children: "Swap is not available for this app." }),
|
|
4449
5854
|
step === "form" && !swapUnavailable && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4450
5855
|
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
|
-
),
|
|
5856
|
+
/* @__PURE__ */ jsxs("div", { className: "pollar-swap-panels", children: [
|
|
5857
|
+
/* @__PURE__ */ jsxs("section", { className: "pollar-swap-panel", "aria-labelledby": "pollar-swap-pay-label", children: [
|
|
5858
|
+
/* @__PURE__ */ jsxs("div", { className: "pollar-swap-panel-heading", children: [
|
|
5859
|
+
/* @__PURE__ */ jsx("span", { id: "pollar-swap-pay-label", className: "pollar-swap-panel-label", children: "You pay" }),
|
|
5860
|
+
/* @__PURE__ */ jsxs("span", { className: "pollar-swap-balance", children: [
|
|
5861
|
+
"Balance: ",
|
|
5862
|
+
formatAmount2(selectedSell?.available)
|
|
5863
|
+
] })
|
|
5864
|
+
] }),
|
|
5865
|
+
/* @__PURE__ */ jsxs("div", { className: "pollar-swap-panel-main", children: [
|
|
4522
5866
|
/* @__PURE__ */ jsx(
|
|
4523
5867
|
"input",
|
|
4524
5868
|
{
|
|
4525
|
-
className: "pollar-
|
|
5869
|
+
className: "pollar-swap-amount",
|
|
4526
5870
|
type: "text",
|
|
4527
|
-
|
|
4528
|
-
|
|
4529
|
-
|
|
5871
|
+
inputMode: "decimal",
|
|
5872
|
+
"aria-label": "Amount to pay",
|
|
5873
|
+
placeholder: "0.00",
|
|
5874
|
+
value: amount,
|
|
5875
|
+
disabled: configLoading || isLoadingData,
|
|
5876
|
+
onChange: (event) => onAmountChange(event.target.value)
|
|
4530
5877
|
}
|
|
4531
5878
|
),
|
|
4532
|
-
|
|
4533
|
-
|
|
4534
|
-
|
|
5879
|
+
/* @__PURE__ */ jsxs("div", { className: "pollar-swap-panel-selector", children: [
|
|
5880
|
+
/* @__PURE__ */ jsx(
|
|
5881
|
+
AssetPill,
|
|
5882
|
+
{
|
|
5883
|
+
label: "Asset to pay",
|
|
5884
|
+
value: sellKey,
|
|
5885
|
+
options: sellOptions,
|
|
5886
|
+
disabled: configLoading || isLoadingData,
|
|
5887
|
+
onChange: selectSell
|
|
5888
|
+
}
|
|
5889
|
+
),
|
|
4535
5890
|
/* @__PURE__ */ jsx(
|
|
4536
5891
|
"button",
|
|
4537
5892
|
{
|
|
4538
5893
|
type: "button",
|
|
4539
|
-
className: "pollar-swap-
|
|
4540
|
-
onClick:
|
|
4541
|
-
|
|
4542
|
-
|
|
4543
|
-
},
|
|
4544
|
-
children: "Cancel"
|
|
5894
|
+
className: "pollar-swap-max",
|
|
5895
|
+
onClick: onMax,
|
|
5896
|
+
disabled: !selectedSell?.available || configLoading || isLoadingData,
|
|
5897
|
+
children: "Max"
|
|
4545
5898
|
}
|
|
4546
5899
|
)
|
|
4547
5900
|
] })
|
|
4548
|
-
] })
|
|
5901
|
+
] })
|
|
5902
|
+
] }),
|
|
5903
|
+
/* @__PURE__ */ jsx(
|
|
5904
|
+
"button",
|
|
5905
|
+
{
|
|
5906
|
+
type: "button",
|
|
5907
|
+
className: "pollar-swap-reverse",
|
|
5908
|
+
onClick: onReverse,
|
|
5909
|
+
disabled: !selectedSell || !selectedBuy,
|
|
5910
|
+
"aria-label": "Swap pay and receive assets",
|
|
5911
|
+
title: "Swap pay and receive assets",
|
|
5912
|
+
children: /* @__PURE__ */ jsx("svg", { width: "17", height: "17", viewBox: "0 0 17 17", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsx(
|
|
5913
|
+
"path",
|
|
5914
|
+
{
|
|
5915
|
+
d: "M5 3v10M5 3 2.5 5.5M5 3l2.5 2.5M12 14V4M12 14l2.5-2.5M12 14 9.5 11.5",
|
|
5916
|
+
stroke: "currentColor",
|
|
5917
|
+
strokeWidth: "1.6",
|
|
5918
|
+
strokeLinecap: "round",
|
|
5919
|
+
strokeLinejoin: "round"
|
|
5920
|
+
}
|
|
5921
|
+
) })
|
|
5922
|
+
}
|
|
5923
|
+
),
|
|
5924
|
+
/* @__PURE__ */ jsxs("section", { className: "pollar-swap-panel", "aria-labelledby": "pollar-swap-receive-label", children: [
|
|
5925
|
+
/* @__PURE__ */ jsxs("div", { className: "pollar-swap-panel-heading", children: [
|
|
5926
|
+
/* @__PURE__ */ jsx("span", { id: "pollar-swap-receive-label", className: "pollar-swap-panel-label", children: "You receive" }),
|
|
5927
|
+
/* @__PURE__ */ jsxs("span", { className: "pollar-swap-balance", children: [
|
|
5928
|
+
"Balance: ",
|
|
5929
|
+
formatAmount2(selectedBuy?.available)
|
|
5930
|
+
] })
|
|
5931
|
+
] }),
|
|
5932
|
+
/* @__PURE__ */ jsxs("div", { className: "pollar-swap-panel-main", children: [
|
|
5933
|
+
/* @__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) }),
|
|
5934
|
+
/* @__PURE__ */ jsxs("div", { className: "pollar-swap-panel-selector", children: [
|
|
5935
|
+
/* @__PURE__ */ jsx(
|
|
5936
|
+
AssetPill,
|
|
5937
|
+
{
|
|
5938
|
+
label: "Asset to receive",
|
|
5939
|
+
value: buyKey,
|
|
5940
|
+
options: buyOptions,
|
|
5941
|
+
disabled: configLoading || isLoadingData,
|
|
5942
|
+
onChange: selectBuy
|
|
5943
|
+
}
|
|
5944
|
+
),
|
|
5945
|
+
/* @__PURE__ */ jsx("span", { className: "pollar-swap-panel-note", children: "Quoted amount" })
|
|
5946
|
+
] })
|
|
5947
|
+
] })
|
|
5948
|
+
] })
|
|
5949
|
+
] }),
|
|
5950
|
+
/* @__PURE__ */ jsx("div", { className: "pollar-swap-custom-area", children: customOpen ? /* @__PURE__ */ jsxs("div", { className: "pollar-swap-custom", children: [
|
|
5951
|
+
/* @__PURE__ */ jsx(
|
|
5952
|
+
"input",
|
|
5953
|
+
{
|
|
5954
|
+
className: "pollar-input",
|
|
5955
|
+
type: "text",
|
|
5956
|
+
placeholder: "Code (e.g. USDC)",
|
|
5957
|
+
value: customCode,
|
|
5958
|
+
onChange: (e) => setCustomCode(e.target.value)
|
|
5959
|
+
}
|
|
5960
|
+
),
|
|
5961
|
+
/* @__PURE__ */ jsx(
|
|
5962
|
+
"input",
|
|
5963
|
+
{
|
|
5964
|
+
className: "pollar-input",
|
|
5965
|
+
type: "text",
|
|
5966
|
+
placeholder: "Issuer (G...)",
|
|
5967
|
+
value: customIssuer,
|
|
5968
|
+
onChange: (e) => setCustomIssuer(e.target.value)
|
|
5969
|
+
}
|
|
5970
|
+
),
|
|
5971
|
+
customError && /* @__PURE__ */ jsx("div", { className: "pollar-modal-error", children: customError }),
|
|
5972
|
+
/* @__PURE__ */ jsxs("div", { className: "pollar-swap-custom-actions", children: [
|
|
5973
|
+
/* @__PURE__ */ jsx("button", { type: "button", className: "pollar-btn-primary", onClick: submitCustomToken, children: "Add token" }),
|
|
5974
|
+
/* @__PURE__ */ jsx(
|
|
4549
5975
|
"button",
|
|
4550
5976
|
{
|
|
4551
5977
|
type: "button",
|
|
4552
|
-
className: "pollar-swap-custom-
|
|
4553
|
-
|
|
4554
|
-
|
|
4555
|
-
|
|
5978
|
+
className: "pollar-swap-custom-cancel",
|
|
5979
|
+
onClick: () => {
|
|
5980
|
+
setCustomOpen(false);
|
|
5981
|
+
setCustomError("");
|
|
5982
|
+
},
|
|
5983
|
+
children: "Cancel"
|
|
4556
5984
|
}
|
|
4557
5985
|
)
|
|
5986
|
+
] })
|
|
5987
|
+
] }) : /* @__PURE__ */ jsx(
|
|
5988
|
+
"button",
|
|
5989
|
+
{
|
|
5990
|
+
type: "button",
|
|
5991
|
+
className: "pollar-swap-custom-toggle",
|
|
5992
|
+
disabled: configLoading,
|
|
5993
|
+
onClick: () => setCustomOpen(true),
|
|
5994
|
+
children: "+ Add a token by code / issuer"
|
|
4558
5995
|
}
|
|
4559
|
-
),
|
|
4560
|
-
/* @__PURE__ */ jsxs("div", { className: "pollar-
|
|
4561
|
-
/* @__PURE__ */ jsx("
|
|
4562
|
-
|
|
5996
|
+
) }),
|
|
5997
|
+
/* @__PURE__ */ jsxs("div", { className: "pollar-swap-rate-row", children: [
|
|
5998
|
+
/* @__PURE__ */ jsx("div", { className: "pollar-swap-rate", "aria-live": "polite", children: rate && selectedSell && selectedBuy ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
5999
|
+
"1 ",
|
|
6000
|
+
selectedSell.code,
|
|
6001
|
+
" \u2248 ",
|
|
6002
|
+
rate,
|
|
6003
|
+
" ",
|
|
6004
|
+
selectedBuy.code
|
|
6005
|
+
] }) : quoteLoading ? "Updating rate\u2026" : "Exchange rate unavailable" }),
|
|
6006
|
+
configLoading ? /* @__PURE__ */ jsxs("div", { className: "pollar-swap-route-pill", children: [
|
|
4563
6007
|
/* @__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
|
-
|
|
6008
|
+
" Loading"
|
|
6009
|
+
] }) : /* @__PURE__ */ jsxs("label", { className: "pollar-swap-route-wrap", children: [
|
|
6010
|
+
/* @__PURE__ */ jsx("span", { className: "sr-only", children: "Route" }),
|
|
6011
|
+
/* @__PURE__ */ jsx(
|
|
6012
|
+
"select",
|
|
6013
|
+
{
|
|
6014
|
+
className: "pollar-swap-route-pill",
|
|
6015
|
+
"aria-label": "Route",
|
|
6016
|
+
value: provider,
|
|
6017
|
+
disabled: providers.length === 0,
|
|
6018
|
+
onChange: (event) => onProviderChange(event.target.value),
|
|
6019
|
+
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))
|
|
6020
|
+
}
|
|
6021
|
+
)
|
|
6022
|
+
] })
|
|
4579
6023
|
] }),
|
|
4580
6024
|
!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
|
-
] }),
|
|
6025
|
+
!quoteLoading && !quoteError && !quote && selectedSell && selectedBuy && !!amount && /* @__PURE__ */ jsx("div", { className: "pollar-send-hint", children: "No route found for this pair." }),
|
|
6026
|
+
quote && /* @__PURE__ */ jsxs("div", { className: "pollar-swap-quote", children: [
|
|
4591
6027
|
/* @__PURE__ */ jsxs("div", { className: "pollar-swap-quote-row", children: [
|
|
4592
|
-
/* @__PURE__ */ jsx("span", {
|
|
4593
|
-
/* @__PURE__ */ jsxs("
|
|
4594
|
-
|
|
6028
|
+
/* @__PURE__ */ jsx("span", { children: "Minimum received" }),
|
|
6029
|
+
/* @__PURE__ */ jsxs("strong", { children: [
|
|
6030
|
+
formatAmount2(quote.minReceived),
|
|
4595
6031
|
" ",
|
|
4596
|
-
selectedBuy
|
|
6032
|
+
selectedBuy?.code
|
|
4597
6033
|
] })
|
|
4598
6034
|
] }),
|
|
4599
6035
|
/* @__PURE__ */ jsxs("div", { className: "pollar-swap-quote-row", children: [
|
|
4600
|
-
/* @__PURE__ */ jsx("span", {
|
|
4601
|
-
/* @__PURE__ */ jsxs("
|
|
6036
|
+
/* @__PURE__ */ jsx("span", { children: "Price impact" }),
|
|
6037
|
+
/* @__PURE__ */ jsxs("strong", { children: [
|
|
4602
6038
|
quote.priceImpactPct,
|
|
4603
6039
|
"%"
|
|
4604
6040
|
] })
|
|
4605
6041
|
] }),
|
|
4606
6042
|
/* @__PURE__ */ jsxs("div", { className: "pollar-swap-quote-row", children: [
|
|
4607
|
-
/* @__PURE__ */ jsx("span", {
|
|
4608
|
-
/* @__PURE__ */ jsx("
|
|
6043
|
+
/* @__PURE__ */ jsx("span", { children: "Route" }),
|
|
6044
|
+
/* @__PURE__ */ jsx("strong", { children: PROVIDER_LABELS[quote.provider] })
|
|
4609
6045
|
] })
|
|
4610
6046
|
] }),
|
|
4611
|
-
!quoteLoading && !quoteError && !quote && selectedSell && selectedBuy && !!amount && /* @__PURE__ */ jsx("div", { className: "pollar-send-hint", children: "No route found for this pair." }),
|
|
4612
6047
|
buyNeedsTrustline && selectedBuy && /* @__PURE__ */ jsxs("div", { className: "pollar-swap-trustline-notice", children: [
|
|
4613
6048
|
"To receive ",
|
|
4614
6049
|
selectedBuy.code,
|
|
4615
6050
|
" your wallet needs a trustline. Swapping will create it first (~0.5 XLM reserve, refundable if you later remove it)."
|
|
4616
6051
|
] }),
|
|
6052
|
+
sameAsset && /* @__PURE__ */ jsx("div", { className: "pollar-modal-error", children: "Choose two different assets to swap." }),
|
|
4617
6053
|
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" }) })
|
|
6054
|
+
/* @__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
6055
|
] }),
|
|
4620
6056
|
step === "tx" && /* @__PURE__ */ jsx(
|
|
4621
6057
|
TxStatusView,
|
|
@@ -4633,7 +6069,7 @@ function SwapModalTemplate({
|
|
|
4633
6069
|
onDone
|
|
4634
6070
|
}
|
|
4635
6071
|
),
|
|
4636
|
-
/* @__PURE__ */ jsx(PollarModalFooter, {})
|
|
6072
|
+
/* @__PURE__ */ jsx(PollarModalFooter, { shield: true })
|
|
4637
6073
|
]
|
|
4638
6074
|
}
|
|
4639
6075
|
);
|
|
@@ -4714,6 +6150,7 @@ function SwapModal({ onClose }) {
|
|
|
4714
6150
|
const balances = walletBalance.step === "loaded" ? walletBalance.data.balances : [];
|
|
4715
6151
|
const assetRecords = enabledAssets.step === "loaded" ? enabledAssets.data.assets : [];
|
|
4716
6152
|
const isLoadingData = walletBalance.step === "loading" || enabledAssets.step === "loading";
|
|
6153
|
+
const availableFor = (code, issuer) => balances.find((b) => b.code === code && (b.issuer ?? "") === (issuer ?? ""))?.available ?? void 0;
|
|
4717
6154
|
const sellOptions = balances.filter(
|
|
4718
6155
|
(b) => (b.chain === void 0 || b.chain === "STELLAR") && (b.type === "native" || (b.type === "credit_alphanum4" || b.type === "credit_alphanum12") && !b.trustlineRemoved)
|
|
4719
6156
|
).map((b) => ({
|
|
@@ -4731,6 +6168,7 @@ function SwapModal({ onClose }) {
|
|
|
4731
6168
|
ref: toRef(a),
|
|
4732
6169
|
code: a.code,
|
|
4733
6170
|
issuer: a.issuer,
|
|
6171
|
+
available: availableFor(a.code, a.issuer),
|
|
4734
6172
|
enabledInApp: a.enabledInApp
|
|
4735
6173
|
}));
|
|
4736
6174
|
const enabledKeys = new Set(enabledBuy.map(optKey));
|
|
@@ -4738,11 +6176,14 @@ function SwapModal({ onClose }) {
|
|
|
4738
6176
|
ref: catalogRef(tk.code, tk.issuer),
|
|
4739
6177
|
code: tk.code,
|
|
4740
6178
|
issuer: tk.issuer,
|
|
6179
|
+
available: availableFor(tk.code, tk.issuer),
|
|
4741
6180
|
enabledInApp: false
|
|
4742
6181
|
})).filter((o) => !enabledKeys.has(optKey(o)));
|
|
4743
6182
|
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(
|
|
6183
|
+
const customBuy = customTokens.filter((o) => !knownKeys.has(optKey(o))).map((o) => ({ ...o, available: availableFor(o.code, o.issuer) }));
|
|
6184
|
+
const buyOptions = [...enabledBuy, ...catalogBuy, ...customBuy].filter(
|
|
6185
|
+
(o) => optKey(o) !== buyKeyOfSell || optKey(o) === (selectedBuy ? optKey(selectedBuy) : "")
|
|
6186
|
+
);
|
|
4746
6187
|
useEffect(() => {
|
|
4747
6188
|
if (sellOptions.length === 0) return;
|
|
4748
6189
|
if (!selectedSell || !sellOptions.some((o) => optKey(o) === optKey(selectedSell))) {
|
|
@@ -4853,6 +6294,15 @@ function SwapModal({ onClose }) {
|
|
|
4853
6294
|
async function handleRetry() {
|
|
4854
6295
|
if (transaction.step === "error" && quote) await swap(quote);
|
|
4855
6296
|
}
|
|
6297
|
+
function handleMax() {
|
|
6298
|
+
if (selectedSell?.available !== void 0) setAmount(selectedSell.available);
|
|
6299
|
+
}
|
|
6300
|
+
function handleReverse() {
|
|
6301
|
+
if (!selectedSell || !selectedBuy) return;
|
|
6302
|
+
const previousSell = selectedSell;
|
|
6303
|
+
setSelectedSell(selectedBuy);
|
|
6304
|
+
setSelectedBuy(previousSell);
|
|
6305
|
+
}
|
|
4856
6306
|
function handleCopyHash() {
|
|
4857
6307
|
if (!hash) return;
|
|
4858
6308
|
navigator.clipboard.writeText(hash).then(() => {
|
|
@@ -4905,6 +6355,8 @@ function SwapModal({ onClose }) {
|
|
|
4905
6355
|
onRefresh: handleRefresh,
|
|
4906
6356
|
onSelectSell: setSelectedSell,
|
|
4907
6357
|
onSelectBuy: setSelectedBuy,
|
|
6358
|
+
onReverse: handleReverse,
|
|
6359
|
+
onMax: handleMax,
|
|
4908
6360
|
onAddCustomToken: addCustomToken,
|
|
4909
6361
|
onAmountChange: setAmount,
|
|
4910
6362
|
onProviderChange: setProvider,
|
|
@@ -4929,7 +6381,7 @@ var IN_FLIGHT_STEPS2 = [
|
|
|
4929
6381
|
"signing-submitting",
|
|
4930
6382
|
"building-signing-submitting"
|
|
4931
6383
|
];
|
|
4932
|
-
function
|
|
6384
|
+
function formatAmount3(value) {
|
|
4933
6385
|
const n = parseFloat(value);
|
|
4934
6386
|
return isNaN(n) ? value : n.toLocaleString(void 0, { maximumFractionDigits: 7 });
|
|
4935
6387
|
}
|
|
@@ -5243,7 +6695,7 @@ function EarnModal({ onClose }) {
|
|
|
5243
6695
|
tab === "deposit" && /* @__PURE__ */ jsxs("div", { className: "pollar-swap-quote-row", children: [
|
|
5244
6696
|
/* @__PURE__ */ jsx("span", { className: "pollar-send-hint", children: "In your wallet" }),
|
|
5245
6697
|
/* @__PURE__ */ jsxs("span", { children: [
|
|
5246
|
-
walletAvailable != null ?
|
|
6698
|
+
walletAvailable != null ? formatAmount3(walletAvailable) : "\u2026",
|
|
5247
6699
|
" ",
|
|
5248
6700
|
assetCode
|
|
5249
6701
|
] })
|
|
@@ -5251,7 +6703,7 @@ function EarnModal({ onClose }) {
|
|
|
5251
6703
|
/* @__PURE__ */ jsxs("div", { className: "pollar-swap-quote-row", children: [
|
|
5252
6704
|
/* @__PURE__ */ jsx("span", { className: "pollar-send-hint", children: "Your position" }),
|
|
5253
6705
|
/* @__PURE__ */ jsxs("span", { children: [
|
|
5254
|
-
position ?
|
|
6706
|
+
position ? formatAmount3(position.balance) : "\u2026",
|
|
5255
6707
|
" ",
|
|
5256
6708
|
assetCode
|
|
5257
6709
|
] })
|
|
@@ -5269,13 +6721,13 @@ function EarnModal({ onClose }) {
|
|
|
5269
6721
|
/* @__PURE__ */ jsx("label", { className: "pollar-send-label", children: tab === "deposit" ? "Amount" : "Withdraw amount" }),
|
|
5270
6722
|
tab === "deposit" && walletAvailable != null && /* @__PURE__ */ jsxs("button", { type: "button", className: "pollar-swap-custom-toggle", onClick: () => setAmount(walletAvailable), children: [
|
|
5271
6723
|
"Max: ",
|
|
5272
|
-
|
|
6724
|
+
formatAmount3(walletAvailable),
|
|
5273
6725
|
" ",
|
|
5274
6726
|
amountUnitLabel
|
|
5275
6727
|
] }),
|
|
5276
6728
|
tab === "withdraw" && position && /* @__PURE__ */ jsxs("button", { type: "button", className: "pollar-swap-custom-toggle", onClick: () => setAmount(position.withdrawable), children: [
|
|
5277
6729
|
"Max: ",
|
|
5278
|
-
|
|
6730
|
+
formatAmount3(position.withdrawable),
|
|
5279
6731
|
" ",
|
|
5280
6732
|
amountUnitLabel
|
|
5281
6733
|
] })
|
|
@@ -5325,10 +6777,15 @@ function EarnModal({ onClose }) {
|
|
|
5325
6777
|
) });
|
|
5326
6778
|
}
|
|
5327
6779
|
function describeDevice(s) {
|
|
5328
|
-
if (s.deviceLabel) return s.deviceLabel;
|
|
6780
|
+
if (s.deviceLabel) return normalizeDeviceLabel(s.deviceLabel);
|
|
5329
6781
|
if (!s.userAgent) return "Unknown device";
|
|
5330
6782
|
return parseUserAgent(s.userAgent);
|
|
5331
6783
|
}
|
|
6784
|
+
function normalizeDeviceLabel(label) {
|
|
6785
|
+
const parts = label.replace(/\s+/g, " ").split(/ (?:[—–-]|·) /);
|
|
6786
|
+
if (parts.length === 2 && parts[1] !== void 0) return `${parts[0]} \xB7 ${parts[1].toLowerCase()}`;
|
|
6787
|
+
return label;
|
|
6788
|
+
}
|
|
5332
6789
|
function detectBrowser(ua) {
|
|
5333
6790
|
if (/Edg\//.test(ua)) return "Edge";
|
|
5334
6791
|
if (/OPR\//.test(ua)) return "Opera";
|
|
@@ -5348,7 +6805,7 @@ function detectOS(ua) {
|
|
|
5348
6805
|
function parseUserAgent(ua) {
|
|
5349
6806
|
const browser = detectBrowser(ua);
|
|
5350
6807
|
const os = detectOS(ua);
|
|
5351
|
-
if (browser && os) return `${os} \
|
|
6808
|
+
if (browser && os) return `${os} \xB7 ${browser.toLowerCase()}`;
|
|
5352
6809
|
if (os) return os;
|
|
5353
6810
|
if (browser) return browser;
|
|
5354
6811
|
return ua.slice(0, 48);
|
|
@@ -5372,6 +6829,37 @@ function shortIp(hash) {
|
|
|
5372
6829
|
if (!hash) return "";
|
|
5373
6830
|
return hash.slice(0, 8);
|
|
5374
6831
|
}
|
|
6832
|
+
function deviceKind(session) {
|
|
6833
|
+
const value = `${session.deviceLabel ?? ""} ${session.userAgent ?? ""}`.toLowerCase();
|
|
6834
|
+
if (/ipad|tablet/.test(value)) return "tablet";
|
|
6835
|
+
if (/android|iphone|ipod|mobile|phone/.test(value)) return "phone";
|
|
6836
|
+
return "desktop";
|
|
6837
|
+
}
|
|
6838
|
+
function DeviceIcon({ kind, size = "small" }) {
|
|
6839
|
+
const dimensions = size === "large" ? 30 : 18;
|
|
6840
|
+
if (kind === "phone") {
|
|
6841
|
+
return /* @__PURE__ */ jsxs("svg", { width: dimensions, height: dimensions, viewBox: "0 0 24 24", fill: "none", "aria-hidden": true, children: [
|
|
6842
|
+
/* @__PURE__ */ jsx("rect", { x: "7", y: "2.5", width: "10", height: "19", rx: "2.5", stroke: "currentColor", strokeWidth: "1.8" }),
|
|
6843
|
+
/* @__PURE__ */ jsx("path", { d: "M10.5 5h3M11 18.5h2", stroke: "currentColor", strokeWidth: "1.6", strokeLinecap: "round" })
|
|
6844
|
+
] });
|
|
6845
|
+
}
|
|
6846
|
+
if (kind === "tablet") {
|
|
6847
|
+
return /* @__PURE__ */ jsxs("svg", { width: dimensions, height: dimensions, viewBox: "0 0 24 24", fill: "none", "aria-hidden": true, children: [
|
|
6848
|
+
/* @__PURE__ */ jsx("rect", { x: "4.5", y: "2.5", width: "15", height: "19", rx: "2", stroke: "currentColor", strokeWidth: "1.8" }),
|
|
6849
|
+
/* @__PURE__ */ jsx("path", { d: "M11 18.5h2", stroke: "currentColor", strokeWidth: "1.6", strokeLinecap: "round" })
|
|
6850
|
+
] });
|
|
6851
|
+
}
|
|
6852
|
+
return /* @__PURE__ */ jsxs("svg", { width: dimensions, height: dimensions, viewBox: "0 0 24 24", fill: "none", "aria-hidden": true, children: [
|
|
6853
|
+
/* @__PURE__ */ jsx("rect", { x: "3", y: "3.5", width: "18", height: "12", rx: "1.8", stroke: "currentColor", strokeWidth: "1.8" }),
|
|
6854
|
+
/* @__PURE__ */ jsx("path", { d: "M8 20.5h8M12 15.5v5", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round" })
|
|
6855
|
+
] });
|
|
6856
|
+
}
|
|
6857
|
+
function CheckIcon() {
|
|
6858
|
+
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" }) });
|
|
6859
|
+
}
|
|
6860
|
+
function CloseIcon() {
|
|
6861
|
+
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" }) });
|
|
6862
|
+
}
|
|
5375
6863
|
function SessionsModalTemplate({
|
|
5376
6864
|
theme,
|
|
5377
6865
|
accentColor,
|
|
@@ -5379,6 +6867,7 @@ function SessionsModalTemplate({
|
|
|
5379
6867
|
state,
|
|
5380
6868
|
revokingFamilyId,
|
|
5381
6869
|
signingOutEverywhere,
|
|
6870
|
+
revokeError,
|
|
5382
6871
|
onRefresh,
|
|
5383
6872
|
onRevoke,
|
|
5384
6873
|
onLogoutEverywhere,
|
|
@@ -5387,7 +6876,9 @@ function SessionsModalTemplate({
|
|
|
5387
6876
|
const cssVars = buildModalCssVars(theme, accentColor, styleOverrides);
|
|
5388
6877
|
const isLoading = state.step === "loading";
|
|
5389
6878
|
const sessions = state.step === "loaded" ? state.sessions : [];
|
|
5390
|
-
const
|
|
6879
|
+
const currentSession = sessions.find((s) => s.current);
|
|
6880
|
+
const otherSessions = sessions.filter((s) => !s.current);
|
|
6881
|
+
const otherCount = otherSessions.length;
|
|
5391
6882
|
return /* @__PURE__ */ jsxs(
|
|
5392
6883
|
"div",
|
|
5393
6884
|
{
|
|
@@ -5408,30 +6899,10 @@ function SessionsModalTemplate({
|
|
|
5408
6899
|
disabled: isLoading,
|
|
5409
6900
|
"aria-label": "Refresh",
|
|
5410
6901
|
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
|
-
)
|
|
6902
|
+
children: /* @__PURE__ */ jsx(RefreshIcon, { spinning: isLoading })
|
|
5432
6903
|
}
|
|
5433
6904
|
),
|
|
5434
|
-
/* @__PURE__ */ jsx("button", { className: "pollar-modal-close", onClick: onClose, "aria-label": "Close",
|
|
6905
|
+
/* @__PURE__ */ jsx("button", { type: "button", className: "pollar-modal-close", onClick: onClose, "aria-label": "Close", title: "Close", children: /* @__PURE__ */ jsx(CloseIcon, {}) })
|
|
5435
6906
|
] })
|
|
5436
6907
|
] }),
|
|
5437
6908
|
/* @__PURE__ */ jsxs("div", { className: "pollar-sessions-list", children: [
|
|
@@ -5441,40 +6912,54 @@ function SessionsModalTemplate({
|
|
|
5441
6912
|
] }),
|
|
5442
6913
|
state.step === "error" && /* @__PURE__ */ jsx("div", { className: "pollar-modal-empty", children: state.message }),
|
|
5443
6914
|
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
|
-
] })
|
|
6915
|
+
state.step === "loaded" && currentSession && /* @__PURE__ */ jsxs("div", { className: "pollar-sessions-current-card", children: [
|
|
6916
|
+
/* @__PURE__ */ jsxs("div", { className: "pollar-sessions-current-icon-wrap", children: [
|
|
6917
|
+
/* @__PURE__ */ jsx(DeviceIcon, { kind: deviceKind(currentSession), size: "large" }),
|
|
6918
|
+
/* @__PURE__ */ jsx("span", { className: "pollar-sessions-current-check", children: /* @__PURE__ */ jsx(CheckIcon, {}) })
|
|
6919
|
+
] }),
|
|
6920
|
+
/* @__PURE__ */ jsx("span", { className: "pollar-sessions-current-label", children: "This device" }),
|
|
6921
|
+
/* @__PURE__ */ jsx("strong", { className: "pollar-sessions-current-device", children: describeDevice(currentSession) }),
|
|
6922
|
+
/* @__PURE__ */ jsxs("div", { className: "pollar-sessions-current-status", children: [
|
|
6923
|
+
/* @__PURE__ */ jsx("span", { className: "pollar-sessions-status-dot" }),
|
|
6924
|
+
/* @__PURE__ */ jsx("span", { children: "Active now" }),
|
|
6925
|
+
currentSession.ipHash && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
6926
|
+
/* @__PURE__ */ jsx("span", { children: "\xB7" }),
|
|
6927
|
+
/* @__PURE__ */ jsxs("span", { title: `ip-hash ${currentSession.ipHash}`, children: [
|
|
6928
|
+
"IP ",
|
|
6929
|
+
shortIp(currentSession.ipHash)
|
|
5462
6930
|
] })
|
|
5463
|
-
] })
|
|
5464
|
-
|
|
5465
|
-
|
|
5466
|
-
|
|
5467
|
-
|
|
5468
|
-
|
|
5469
|
-
|
|
5470
|
-
|
|
5471
|
-
|
|
5472
|
-
|
|
5473
|
-
|
|
5474
|
-
|
|
5475
|
-
|
|
5476
|
-
|
|
5477
|
-
|
|
6931
|
+
] })
|
|
6932
|
+
] })
|
|
6933
|
+
] }),
|
|
6934
|
+
state.step === "loaded" && otherSessions.length > 0 && /* @__PURE__ */ jsxs("section", { className: "pollar-sessions-other-section", "aria-labelledby": "pollar-other-devices-heading", children: [
|
|
6935
|
+
/* @__PURE__ */ jsxs("h3", { id: "pollar-other-devices-heading", className: "pollar-sessions-section-title", children: [
|
|
6936
|
+
"Other devices ",
|
|
6937
|
+
/* @__PURE__ */ jsx("span", { children: otherCount })
|
|
6938
|
+
] }),
|
|
6939
|
+
/* @__PURE__ */ jsx("div", { className: "pollar-sessions-grid", children: otherSessions.map((s) => {
|
|
6940
|
+
const isRevoking = revokingFamilyId === s.familyId;
|
|
6941
|
+
return /* @__PURE__ */ jsxs("div", { className: "pollar-sessions-item", children: [
|
|
6942
|
+
/* @__PURE__ */ jsxs("div", { className: "pollar-sessions-item-top", children: [
|
|
6943
|
+
/* @__PURE__ */ jsx("span", { className: "pollar-sessions-item-icon", children: /* @__PURE__ */ jsx(DeviceIcon, { kind: deviceKind(s) }) }),
|
|
6944
|
+
/* @__PURE__ */ jsx(
|
|
6945
|
+
"button",
|
|
6946
|
+
{
|
|
6947
|
+
type: "button",
|
|
6948
|
+
className: "pollar-sessions-item-revoke",
|
|
6949
|
+
onClick: () => onRevoke(s.familyId),
|
|
6950
|
+
disabled: isRevoking || signingOutEverywhere,
|
|
6951
|
+
"aria-label": `Sign out ${describeDevice(s)}`,
|
|
6952
|
+
title: isRevoking ? "Signing out\u2026" : "Sign out this device",
|
|
6953
|
+
children: isRevoking ? /* @__PURE__ */ jsx("span", { className: "pollar-spinner pollar-spinner-sm" }) : /* @__PURE__ */ jsx(CloseIcon, {})
|
|
6954
|
+
}
|
|
6955
|
+
)
|
|
6956
|
+
] }),
|
|
6957
|
+
/* @__PURE__ */ jsx("strong", { className: "pollar-sessions-item-device", children: describeDevice(s) }),
|
|
6958
|
+
/* @__PURE__ */ jsx("span", { className: "pollar-sessions-item-meta", children: formatRelative(s.lastUsedAt ?? s.createdAt) })
|
|
6959
|
+
] }, s.familyId);
|
|
6960
|
+
}) })
|
|
6961
|
+
] }),
|
|
6962
|
+
revokeError && /* @__PURE__ */ jsx("div", { className: "pollar-sessions-action-error", role: "alert", children: revokeError })
|
|
5478
6963
|
] }),
|
|
5479
6964
|
state.step === "loaded" && sessions.length > 0 && /* @__PURE__ */ jsx("div", { className: "pollar-sessions-actions", children: /* @__PURE__ */ jsx(
|
|
5480
6965
|
"button",
|
|
@@ -5499,6 +6984,7 @@ function SessionsModal({ onClose }) {
|
|
|
5499
6984
|
const { theme, accentColor, styleOverrides, overlayStyle } = modalChrome(styles);
|
|
5500
6985
|
const [revokingFamilyId, setRevokingFamilyId] = useState(null);
|
|
5501
6986
|
const [signingOutEverywhere, setSigningOutEverywhere] = useState(false);
|
|
6987
|
+
const [revokeError, setRevokeError] = useState(null);
|
|
5502
6988
|
const load = useCallback(() => {
|
|
5503
6989
|
void getClient().fetchSessions();
|
|
5504
6990
|
}, [getClient]);
|
|
@@ -5515,9 +7001,11 @@ function SessionsModal({ onClose }) {
|
|
|
5515
7001
|
const handleRevoke = useCallback(
|
|
5516
7002
|
async (familyId) => {
|
|
5517
7003
|
setRevokingFamilyId(familyId);
|
|
7004
|
+
setRevokeError(null);
|
|
5518
7005
|
try {
|
|
5519
7006
|
await getClient().revokeSession(familyId);
|
|
5520
7007
|
} catch {
|
|
7008
|
+
setRevokeError("Could not sign out that device. Please try again.");
|
|
5521
7009
|
} finally {
|
|
5522
7010
|
setRevokingFamilyId(null);
|
|
5523
7011
|
load();
|
|
@@ -5543,6 +7031,7 @@ function SessionsModal({ onClose }) {
|
|
|
5543
7031
|
state: sessions,
|
|
5544
7032
|
revokingFamilyId,
|
|
5545
7033
|
signingOutEverywhere,
|
|
7034
|
+
revokeError,
|
|
5546
7035
|
onRefresh: () => load(),
|
|
5547
7036
|
onRevoke: (familyId) => void handleRevoke(familyId),
|
|
5548
7037
|
onLogoutEverywhere: () => void handleLogoutEverywhere(),
|
|
@@ -5937,14 +7426,32 @@ function faucetFor(record) {
|
|
|
5937
7426
|
if (record.code === "USDC") return { url: "https://faucet.circle.com/", label: "Get test USDC" };
|
|
5938
7427
|
return null;
|
|
5939
7428
|
}
|
|
5940
|
-
function
|
|
7429
|
+
function assetMetadataFor(record, metadata) {
|
|
7430
|
+
return metadata.find(
|
|
7431
|
+
(asset) => resolveChain(asset.chain) === resolveChain(record.chain) && asset.code === record.code && (asset.issuer ?? "") === (record.issuer ?? "")
|
|
7432
|
+
);
|
|
7433
|
+
}
|
|
7434
|
+
function AssetIcon3({ code }) {
|
|
7435
|
+
return /* @__PURE__ */ jsx("span", { className: "pollar-bal-asset-icon", "aria-hidden": true, children: code.slice(0, 2).toUpperCase() });
|
|
7436
|
+
}
|
|
7437
|
+
function BalanceItem({
|
|
7438
|
+
record,
|
|
7439
|
+
faucet,
|
|
7440
|
+
metadata
|
|
7441
|
+
}) {
|
|
5941
7442
|
const balanceDiffers = record.balance !== record.available;
|
|
7443
|
+
const secondary = metadata?.name ?? (record.issuer ? cropAddress(record.issuer) : "Native asset");
|
|
5942
7444
|
return /* @__PURE__ */ jsxs("div", { className: "pollar-bal-item", children: [
|
|
5943
7445
|
/* @__PURE__ */ jsxs("div", { className: "pollar-bal-asset-info", children: [
|
|
5944
|
-
/* @__PURE__ */
|
|
5945
|
-
|
|
5946
|
-
/* @__PURE__ */
|
|
5947
|
-
|
|
7446
|
+
/* @__PURE__ */ jsxs("span", { className: "pollar-bal-asset-leading", children: [
|
|
7447
|
+
/* @__PURE__ */ jsx(AssetIcon3, { code: record.code }),
|
|
7448
|
+
/* @__PURE__ */ jsxs("span", { className: "pollar-bal-asset-copy", children: [
|
|
7449
|
+
/* @__PURE__ */ jsx("span", { className: "pollar-bal-asset", children: record.code }),
|
|
7450
|
+
/* @__PURE__ */ jsxs("span", { className: "pollar-bal-asset-secondary", children: [
|
|
7451
|
+
secondary,
|
|
7452
|
+
record.issuer && /* @__PURE__ */ jsx(CopyButton, { value: record.issuer, label: "Copy issuer address", className: "pollar-copy-btn-sm" })
|
|
7453
|
+
] })
|
|
7454
|
+
] })
|
|
5948
7455
|
] }),
|
|
5949
7456
|
faucet && /* @__PURE__ */ jsxs("span", { className: "pollar-bal-faucet-hint", children: [
|
|
5950
7457
|
"Need more?",
|
|
@@ -5968,6 +7475,7 @@ function WalletBalanceModalTemplate({
|
|
|
5968
7475
|
styleOverrides,
|
|
5969
7476
|
walletBalance,
|
|
5970
7477
|
walletAddress,
|
|
7478
|
+
assetMetadata = [],
|
|
5971
7479
|
chains,
|
|
5972
7480
|
selectedChain,
|
|
5973
7481
|
network,
|
|
@@ -5994,33 +7502,13 @@ function WalletBalanceModalTemplate({
|
|
|
5994
7502
|
disabled: isLoading,
|
|
5995
7503
|
"aria-label": "Refresh",
|
|
5996
7504
|
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
|
-
)
|
|
7505
|
+
children: /* @__PURE__ */ jsx(RefreshIcon, { spinning: isLoading })
|
|
6018
7506
|
}
|
|
6019
7507
|
),
|
|
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" }) }) })
|
|
7508
|
+
/* @__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
7509
|
] })
|
|
6022
7510
|
] }),
|
|
6023
|
-
/* @__PURE__ */ jsx(ChainSelect, { value: selectedChain, options: chains, onChange: onSelectChain, disabled: isLoading }),
|
|
7511
|
+
chains && onSelectChain && /* @__PURE__ */ jsx(ChainSelect, { value: selectedChain, options: chains, onChange: onSelectChain, disabled: isLoading }),
|
|
6024
7512
|
walletAddress && /* @__PURE__ */ jsxs("div", { className: "pollar-address-row", children: [
|
|
6025
7513
|
/* @__PURE__ */ jsx("span", { className: "pollar-address", children: cropAddress(walletAddress) }),
|
|
6026
7514
|
/* @__PURE__ */ jsx(CopyButton, { value: walletAddress, label: "Copy wallet address" })
|
|
@@ -6040,6 +7528,7 @@ function WalletBalanceModalTemplate({
|
|
|
6040
7528
|
BalanceItem,
|
|
6041
7529
|
{
|
|
6042
7530
|
record: b,
|
|
7531
|
+
metadata: assetMetadataFor(b, assetMetadata),
|
|
6043
7532
|
faucet: showFaucets ? faucetFor(b) : null
|
|
6044
7533
|
},
|
|
6045
7534
|
(b.chain ?? "") + b.code + (b.issuer ?? "")
|
|
@@ -6048,7 +7537,7 @@ function WalletBalanceModalTemplate({
|
|
|
6048
7537
|
] });
|
|
6049
7538
|
}
|
|
6050
7539
|
function WalletBalanceModal({ onClose }) {
|
|
6051
|
-
const { walletBalance, refreshWalletBalance, wallets, network, styles } = usePollar();
|
|
7540
|
+
const { walletBalance, refreshWalletBalance, wallets, network, styles, enabledAssets } = usePollar();
|
|
6052
7541
|
const { theme, accentColor, styleOverrides, overlayStyle } = modalChrome(styles);
|
|
6053
7542
|
const { chains } = useChains();
|
|
6054
7543
|
const [selectedChain, setSelectedChain] = useState(null);
|
|
@@ -6067,6 +7556,7 @@ function WalletBalanceModal({ onClose }) {
|
|
|
6067
7556
|
styleOverrides,
|
|
6068
7557
|
walletBalance,
|
|
6069
7558
|
walletAddress,
|
|
7559
|
+
assetMetadata: enabledAssets.step === "loaded" ? enabledAssets.data.assets : [],
|
|
6070
7560
|
chains,
|
|
6071
7561
|
selectedChain,
|
|
6072
7562
|
network,
|
|
@@ -6136,7 +7626,11 @@ var DEFAULT_APP_CONFIG = {
|
|
|
6136
7626
|
function sessionsEqual(a, b) {
|
|
6137
7627
|
if (a === b) return true;
|
|
6138
7628
|
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
|
|
7629
|
+
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
|
|
7630
|
+
// other field changing. Leaving it out of the comparison is what would make
|
|
7631
|
+
// the whole provisioning UI dead: the short-circuit below would swallow the
|
|
7632
|
+
// one emission that says the wait is over.
|
|
7633
|
+
a.wallet?.provisioning === b.wallet?.provisioning;
|
|
6140
7634
|
}
|
|
6141
7635
|
var PollarContext = createContext(null);
|
|
6142
7636
|
var clientByConfig = /* @__PURE__ */ new WeakMap();
|
|
@@ -6302,6 +7796,7 @@ function PollarProvider({
|
|
|
6302
7796
|
const [sessionsModalOpen, setSessionsModalOpen] = useState(false);
|
|
6303
7797
|
const [distributionRulesModalOpen, setDistributionRulesModalOpen] = useState(false);
|
|
6304
7798
|
const walletAddress = sessionState?.wallet?.address || "";
|
|
7799
|
+
const walletProvisioning = sessionState?.wallet?.provisioning;
|
|
6305
7800
|
const getClient = useCallback(() => pollarClient, [pollarClient]);
|
|
6306
7801
|
const refreshWalletBalance = useCallback(() => pollarClient.refreshBalance(), [pollarClient, walletAddress]);
|
|
6307
7802
|
const refreshAssets = useCallback(() => pollarClient.refreshAssets(), [pollarClient, walletAddress]);
|
|
@@ -6393,6 +7888,7 @@ function PollarProvider({
|
|
|
6393
7888
|
};
|
|
6394
7889
|
}, [
|
|
6395
7890
|
walletAddress,
|
|
7891
|
+
walletProvisioning,
|
|
6396
7892
|
verified,
|
|
6397
7893
|
pollarClient,
|
|
6398
7894
|
getClient,
|
|
@@ -6413,11 +7909,24 @@ function PollarProvider({
|
|
|
6413
7909
|
children,
|
|
6414
7910
|
loginModalOpen && /* @__PURE__ */ jsx(ModalErrorBoundary, { onClose: () => setLoginModalOpen(false), children: /* @__PURE__ */ jsx(LoginModal, { onClose: () => setLoginModalOpen(false) }) }),
|
|
6415
7911
|
transactionModalOpen && /* @__PURE__ */ jsx(ModalErrorBoundary, { onClose: () => setTransactionModalOpen(false), children: /* @__PURE__ */ jsx(TransactionModal, { onClose: () => setTransactionModalOpen(false) }) }),
|
|
6416
|
-
kycModalOpen && /* @__PURE__ */ jsx(ModalErrorBoundary, { onClose: () => setKycModalOpen(false), children:
|
|
7912
|
+
kycModalOpen && /* @__PURE__ */ jsx(ModalErrorBoundary, { onClose: () => setKycModalOpen(false), children: kycModalOptions.corridorId === void 0 && kycModalOptions.providerId === void 0 ? (
|
|
7913
|
+
// The app's own KYC: its configured steps, in order.
|
|
7914
|
+
/* @__PURE__ */ jsx(
|
|
7915
|
+
AppKycFlow,
|
|
7916
|
+
{
|
|
7917
|
+
onClose: () => setKycModalOpen(false),
|
|
7918
|
+
...kycModalOptions.country !== void 0 && { country: kycModalOptions.country },
|
|
7919
|
+
...kycModalOptions.level !== void 0 && { level: kycModalOptions.level },
|
|
7920
|
+
...kycModalOptions.onApproved !== void 0 && { onApproved: kycModalOptions.onApproved }
|
|
7921
|
+
}
|
|
7922
|
+
)
|
|
7923
|
+
) : /* @__PURE__ */ jsx(
|
|
6417
7924
|
KycModal,
|
|
6418
7925
|
{
|
|
6419
7926
|
onClose: () => setKycModalOpen(false),
|
|
6420
7927
|
...kycModalOptions.country !== void 0 && { country: kycModalOptions.country },
|
|
7928
|
+
...kycModalOptions.corridorId !== void 0 && { corridorId: kycModalOptions.corridorId },
|
|
7929
|
+
...kycModalOptions.providerId !== void 0 && { providerId: kycModalOptions.providerId },
|
|
6421
7930
|
...kycModalOptions.level !== void 0 && { level: kycModalOptions.level },
|
|
6422
7931
|
...kycModalOptions.onApproved !== void 0 && { onApproved: kycModalOptions.onApproved }
|
|
6423
7932
|
}
|
|
@@ -6479,6 +7988,7 @@ function WalletButtonTemplate({
|
|
|
6479
7988
|
wrapperRef,
|
|
6480
7989
|
isInProgress,
|
|
6481
7990
|
showCreateAccount,
|
|
7991
|
+
notReadyReason,
|
|
6482
7992
|
creatingAccount,
|
|
6483
7993
|
onToggleOpen,
|
|
6484
7994
|
onCreateAccount,
|
|
@@ -6543,6 +8053,10 @@ function WalletButtonTemplate({
|
|
|
6543
8053
|
}
|
|
6544
8054
|
),
|
|
6545
8055
|
open && /* @__PURE__ */ jsxs("div", { className: "pollar-wallet-dropdown", style: { backgroundColor: dropdownBg, borderColor: dropdownBorder }, children: [
|
|
8056
|
+
notReadyReason && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
8057
|
+
/* @__PURE__ */ jsx("div", { className: "pollar-wallet-dropdown-notice", style: { color: itemColor }, role: "status", children: notReadyReason }),
|
|
8058
|
+
/* @__PURE__ */ jsx("div", { className: "pollar-wallet-dropdown-divider" })
|
|
8059
|
+
] }),
|
|
6546
8060
|
showCreateAccount && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
6547
8061
|
/* @__PURE__ */ jsxs(
|
|
6548
8062
|
"button",
|
|
@@ -6812,7 +8326,7 @@ function WalletButton() {
|
|
|
6812
8326
|
openDistributionRulesModal,
|
|
6813
8327
|
tx: transaction
|
|
6814
8328
|
} = usePollar();
|
|
6815
|
-
const { primaryAddress } = useChains();
|
|
8329
|
+
const { primaryChain, primaryAddress } = useChains();
|
|
6816
8330
|
const walletAddress = primaryAddress || (wallet?.address ?? "");
|
|
6817
8331
|
const [open, setOpen] = useState(false);
|
|
6818
8332
|
const [copied, setCopied] = useState(false);
|
|
@@ -6822,6 +8336,7 @@ function WalletButton() {
|
|
|
6822
8336
|
const copyTimerRef = useRef(null);
|
|
6823
8337
|
const isInProgress = transaction.step === "building" || transaction.step === "signing";
|
|
6824
8338
|
const canCreateAccount = !created && wallet?.custody === "external" && wallet.existsOnStellar === false && wallet.fundingMode === "IMMEDIATE";
|
|
8339
|
+
const notReadyReason = walletNotReadyReason(wallet, primaryChain);
|
|
6825
8340
|
const { theme = "light", accentColor = "#005DB4" } = styles;
|
|
6826
8341
|
const isDark = theme === "dark";
|
|
6827
8342
|
const dropdownBg = isDark ? "#18181b" : "#fff";
|
|
@@ -6915,6 +8430,7 @@ function WalletButton() {
|
|
|
6915
8430
|
wrapperRef,
|
|
6916
8431
|
isInProgress,
|
|
6917
8432
|
showCreateAccount: canCreateAccount,
|
|
8433
|
+
notReadyReason,
|
|
6918
8434
|
creatingAccount: creating,
|
|
6919
8435
|
onToggleOpen: () => setOpen((v) => !v),
|
|
6920
8436
|
onCreateAccount: handleCreateAccount,
|
|
@@ -6933,6 +8449,6 @@ function WalletButton() {
|
|
|
6933
8449
|
);
|
|
6934
8450
|
}
|
|
6935
8451
|
|
|
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 };
|
|
8452
|
+
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
8453
|
//# sourceMappingURL=index.mjs.map
|
|
6938
8454
|
//# sourceMappingURL=index.mjs.map
|