@pollar/react 0.11.3 → 0.11.4-rc.1

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