@pollar/react 0.11.3 → 0.11.4-rc.2

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