@pollar/react 0.4.5 → 0.5.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.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  'use client';
2
- import { PollarClient, StellarClient, StateStatus, STATE_VAR_CODES, AUTH_ERROR_CODES, WalletType } from '@pollar/core';
2
+ import { AUTH_ERROR_CODES, WalletType, PollarClient } from '@pollar/core';
3
3
  import { createContext, useState, useEffect, useMemo, useContext, useRef, Component } from 'react';
4
4
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
5
5
 
@@ -7,7 +7,6 @@ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
7
7
 
8
8
  // src/constants.ts
9
9
  var LOGO_POLLAR = "https://pollar.xyz/assets/logo_pollar.png";
10
- var LOGO_GITHUB = "https://pollar.xyz/assets/GitHub_Invertocat_White.png";
11
10
  var LOGO_FREIGHTER = "https://pollar.xyz/assets/logo_freighter.png";
12
11
  var LOGO_ALBEDO = "https://pollar.xyz/assets/logo_albedo.svg";
13
12
  var ModalErrorBoundary = class extends Component {
@@ -37,40 +36,180 @@ var PollarModalFooter = () => {
37
36
  /* @__PURE__ */ jsx("span", { className: "pollar-footer-name", children: "Pollar" }),
38
37
  /* @__PURE__ */ jsxs("span", { className: "pollar-footer-version", children: [
39
38
  "v",
40
- "0.4.4"
39
+ "0.5.2"
41
40
  ] })
42
41
  ] })
43
42
  ] });
44
43
  };
45
- var TRANSACTION_CODE_MESSAGES = {
46
- NONE: "",
47
- BUILD_TRANSACTION_START: "Building transaction\u2026",
48
- BUILD_TRANSACTION_SUCCESS: "Transaction built, ready to sign and send",
49
- BUILD_TRANSACTION_ERROR: "Failed to build transaction",
50
- BUILD_TRANSACTION_ERROR_NO_WALLET: "No wallet connected",
51
- SIGN_SEND_TRANSACTION_START: "Signing and sending transaction\u2026",
52
- SIGN_SEND_TRANSACTION_SUCCESS: "Transaction signed",
53
- SIGN_SEND_TRANSACTION_ERROR: "Signing rejected"
54
- };
55
44
  function ModalStatusBanner({ message, status, onCancel, onRetry }) {
56
- if (!message && status === StateStatus.NONE) {
45
+ if (!message && status === "NONE") {
57
46
  return /* @__PURE__ */ jsx("div", { className: "pollar-status" });
58
47
  }
59
- const isLoading = status === StateStatus.LOADING;
48
+ const isLoading = status === "LOADING";
60
49
  const icon = status === "ERROR" ? /* @__PURE__ */ jsxs("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", "aria-hidden": true, children: [
61
50
  /* @__PURE__ */ jsx("circle", { cx: "7", cy: "7", r: "7", fill: "currentColor" }),
62
51
  /* @__PURE__ */ jsx("path", { d: "M4.5 4.5l5 5M9.5 4.5l-5 5", stroke: "white", strokeWidth: "1.5", strokeLinecap: "round" })
63
52
  ] }) : status === "SUCCESS" ? /* @__PURE__ */ jsxs("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", "aria-hidden": true, children: [
64
53
  /* @__PURE__ */ jsx("circle", { cx: "7", cy: "7", r: "7", fill: "currentColor" }),
65
54
  /* @__PURE__ */ jsx("path", { d: "M3.5 7l2.5 2.5 4.5-5", stroke: "white", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })
66
- ] }) : status === "LOADING" ? /* @__PURE__ */ jsx("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsx("circle", { cx: "7", cy: "7", r: "5.5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeDasharray: "22 10" }) }) : null;
55
+ ] }) : status === "LOADING" ? /* @__PURE__ */ jsx(Fragment, {}) : null;
67
56
  return /* @__PURE__ */ jsxs("div", { className: "pollar-status", "data-kind": status, children: [
68
57
  icon,
69
58
  /* @__PURE__ */ jsx("span", { children: message }),
70
59
  isLoading && onCancel && /* @__PURE__ */ jsx("button", { type: "button", className: "pollar-status-cancel", onClick: onCancel, children: "Cancel" }),
71
- status === StateStatus.ERROR && onRetry && /* @__PURE__ */ jsx("button", { type: "button", className: "pollar-status-cancel", onClick: onRetry, children: "Retry" })
60
+ status === "ERROR" && onRetry && /* @__PURE__ */ jsx("button", { type: "button", className: "pollar-status-cancel", onClick: onRetry, children: "Retry" })
72
61
  ] });
73
62
  }
63
+ var STATUS_CONFIG = {
64
+ none: { label: "Not started", color: "#6b7280", dot: false },
65
+ pending: { label: "Pending review", color: "#f59e0b", dot: true },
66
+ approved: { label: "Verified", color: "#10b981", dot: false },
67
+ rejected: { label: "Rejected", color: "#ef4444", dot: false }
68
+ };
69
+ function KycStatus({ status, className }) {
70
+ const config = STATUS_CONFIG[status] ?? STATUS_CONFIG.none;
71
+ return /* @__PURE__ */ jsxs(
72
+ "span",
73
+ {
74
+ className: `pollar-kyc-badge${className ? ` ${className}` : ""}`,
75
+ style: { "--pollar-kyc-color": config.color },
76
+ children: [
77
+ config.dot && /* @__PURE__ */ jsx("span", { className: "pollar-kyc-badge-dot" }),
78
+ config.label
79
+ ]
80
+ }
81
+ );
82
+ }
83
+ function KycModalTemplate({
84
+ theme,
85
+ accentColor,
86
+ step,
87
+ providers,
88
+ selectedProvider,
89
+ session,
90
+ kycStatus,
91
+ isLoading,
92
+ onSelectProvider,
93
+ onDoneVerifying,
94
+ onClose
95
+ }) {
96
+ const isDark = theme === "dark";
97
+ const cssVars = {
98
+ "--pollar-accent": accentColor,
99
+ "--pollar-buttons-border-radius": "6px",
100
+ "--pollar-buttons-height": "44px",
101
+ "--pollar-bg": isDark ? "#1a1a1a" : "#ffffff",
102
+ "--pollar-border": isDark ? "#374151" : "#e5e7eb",
103
+ "--pollar-text": isDark ? "#ffffff" : "#111827",
104
+ "--pollar-muted": isDark ? "#9ca3af" : "#6b7280",
105
+ "--pollar-input-bg": isDark ? "#374151" : "#f9fafb"
106
+ };
107
+ return /* @__PURE__ */ jsxs("div", { className: "pollar-kyc-modal", style: cssVars, onClick: (e) => e.stopPropagation(), children: [
108
+ /* @__PURE__ */ jsxs("div", { className: "pollar-kyc-header", children: [
109
+ /* @__PURE__ */ jsx("h2", { className: "pollar-kyc-title", children: "Identity verification" }),
110
+ /* @__PURE__ */ jsxs("p", { className: "pollar-kyc-subtitle", children: [
111
+ step === "select_provider" && "Choose your verification provider",
112
+ step === "verifying" && `Verifying with ${selectedProvider?.name}`,
113
+ step === "polling" && "Waiting for verification result",
114
+ step === "done" && "Verification complete"
115
+ ] })
116
+ ] }),
117
+ step === "select_provider" && /* @__PURE__ */ jsxs("div", { className: "pollar-kyc-providers", children: [
118
+ providers.length === 0 && /* @__PURE__ */ jsx("p", { style: { color: "var(--pollar-muted)", textAlign: "center" }, children: "No providers available for your country." }),
119
+ providers.map((p) => /* @__PURE__ */ jsxs("button", { type: "button", className: "pollar-kyc-provider-btn", disabled: isLoading, onClick: () => onSelectProvider(p), children: [
120
+ /* @__PURE__ */ jsx("span", { className: "pollar-kyc-provider-name", children: p.name }),
121
+ /* @__PURE__ */ jsx("span", { className: "pollar-kyc-provider-flow", children: p.flow })
122
+ ] }, p.id))
123
+ ] }),
124
+ step === "verifying" && selectedProvider && /* @__PURE__ */ jsxs(Fragment, { children: [
125
+ /* @__PURE__ */ jsx("div", { className: "pollar-kyc-iframe-wrap", children: session?.kycUrl ? /* @__PURE__ */ jsx("iframe", { className: "pollar-kyc-iframe", src: session.kycUrl, title: "KYC verification", allow: "camera; microphone" }) : /* @__PURE__ */ jsxs("div", { className: "pollar-kyc-iframe-mock", children: [
126
+ /* @__PURE__ */ jsx("span", { children: "\u{1F512}" }),
127
+ /* @__PURE__ */ jsx("span", { children: selectedProvider.flow === "form" ? "Form-based KYC \u2014 fields will render here once backend is connected" : "KYC iframe will load here once backend is connected" }),
128
+ /* @__PURE__ */ jsxs("code", { style: { fontSize: "0.7rem", opacity: 0.6 }, children: [
129
+ "provider: ",
130
+ selectedProvider.id
131
+ ] })
132
+ ] }) }),
133
+ /* @__PURE__ */ jsxs("div", { className: "pollar-modal-actions", children: [
134
+ /* @__PURE__ */ jsx("button", { type: "button", className: "pollar-btn-secondary", onClick: onClose, children: "Cancel" }),
135
+ /* @__PURE__ */ jsx("button", { type: "button", className: "pollar-btn-primary", onClick: onDoneVerifying, children: "I've completed verification" })
136
+ ] })
137
+ ] }),
138
+ step === "polling" && /* @__PURE__ */ jsxs("div", { className: "pollar-kyc-polling", children: [
139
+ /* @__PURE__ */ jsx("div", { className: "pollar-spinner" }),
140
+ /* @__PURE__ */ jsx("p", { className: "pollar-kyc-polling-text", children: "Checking verification status\u2026" })
141
+ ] }),
142
+ step === "done" && /* @__PURE__ */ jsxs("div", { className: "pollar-kyc-result", children: [
143
+ /* @__PURE__ */ jsx("span", { className: "pollar-kyc-result-icon", children: kycStatus === "approved" ? "\u2705" : "\u274C" }),
144
+ /* @__PURE__ */ jsx(KycStatus, { status: kycStatus }),
145
+ /* @__PURE__ */ jsx("p", { className: "pollar-kyc-result-text", children: kycStatus === "approved" ? "Your identity has been verified successfully." : "Verification was not approved. Please try again." }),
146
+ /* @__PURE__ */ jsx("div", { className: "pollar-modal-actions", children: /* @__PURE__ */ jsx("button", { type: "button", className: "pollar-btn-primary", onClick: onClose, children: "Close" }) })
147
+ ] })
148
+ ] });
149
+ }
150
+ function KycModal({ onClose, country = "MX", level = "basic", onApproved }) {
151
+ const { getClient, styles } = usePollar();
152
+ const [step, setStep] = useState("select_provider");
153
+ const [providers, setProviders] = useState([]);
154
+ const [selectedProvider, setSelectedProvider] = useState(null);
155
+ const [session, setSession] = useState(null);
156
+ const [kycStatus, setKycStatus] = useState("none");
157
+ const [isLoading, setIsLoading] = useState(false);
158
+ const client = getClient();
159
+ const { theme = "light", accentColor = "#005DB4" } = styles;
160
+ useEffect(() => {
161
+ setIsLoading(true);
162
+ client.getKycProviders(country).then((result) => setProviders(result.providers)).catch(() => setProviders([])).finally(() => setIsLoading(false));
163
+ }, [country]);
164
+ async function handleSelectProvider(provider) {
165
+ setSelectedProvider(provider);
166
+ setIsLoading(true);
167
+ try {
168
+ const result = await client.resolveKyc(provider.id, level);
169
+ if (result.alreadyApproved) {
170
+ setKycStatus("approved");
171
+ setStep("done");
172
+ onApproved?.();
173
+ return;
174
+ }
175
+ setSession(result);
176
+ setStep("verifying");
177
+ } catch {
178
+ setStep("select_provider");
179
+ } finally {
180
+ setIsLoading(false);
181
+ }
182
+ }
183
+ async function handleDoneVerifying() {
184
+ if (!selectedProvider) return;
185
+ setStep("polling");
186
+ try {
187
+ const finalStatus = await client.pollKycStatus(selectedProvider.id, { intervalMs: 3e3, timeoutMs: 12e4 });
188
+ setKycStatus(finalStatus);
189
+ setStep("done");
190
+ if (finalStatus === "approved") onApproved?.();
191
+ } catch {
192
+ setKycStatus("rejected");
193
+ setStep("done");
194
+ }
195
+ }
196
+ return /* @__PURE__ */ jsx("div", { className: "pollar-overlay", onClick: onClose, children: /* @__PURE__ */ jsx(
197
+ KycModalTemplate,
198
+ {
199
+ theme,
200
+ accentColor,
201
+ step,
202
+ providers,
203
+ selectedProvider,
204
+ session,
205
+ kycStatus,
206
+ isLoading,
207
+ onSelectProvider: handleSelectProvider,
208
+ onDoneVerifying: handleDoneVerifying,
209
+ onClose
210
+ }
211
+ ) });
212
+ }
74
213
  function EmailCodeInput({ email, onSubmit }) {
75
214
  const [digits, setDigits] = useState(["", "", "", "", "", ""]);
76
215
  const inputRefs = useRef([]);
@@ -124,8 +263,8 @@ function EmailCodeInput({ email, onSubmit }) {
124
263
  }
125
264
  var GithubButton = ({ disabled, onClick }) => {
126
265
  return /* @__PURE__ */ jsxs("button", { className: "github-button", disabled, onClick, children: [
127
- /* @__PURE__ */ jsx("img", { src: LOGO_GITHUB, alt: "GitHub", className: "github-button-icon" }),
128
- /* @__PURE__ */ jsx("span", { className: "github-button-contents", children: "Continue with GitHub" })
266
+ /* @__PURE__ */ jsx("svg", { className: "github-button-icon", viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": true, children: /* @__PURE__ */ jsx("path", { fillRule: "evenodd", 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", clipRule: "evenodd" }) }),
267
+ /* @__PURE__ */ jsx("span", { className: "github-button-contents", children: "GitHub" })
129
268
  ] });
130
269
  };
131
270
  var GoogleButton = ({ disabled, onClick }) => {
@@ -172,8 +311,8 @@ var GoogleButton = ({ disabled, onClick }) => {
172
311
  ]
173
312
  }
174
313
  ) }),
175
- /* @__PURE__ */ jsx("span", { className: "gsi-material-button-contents", children: "Continue with Google" }),
176
- /* @__PURE__ */ jsx("span", { style: { display: "none" }, children: "Continue with Google" })
314
+ /* @__PURE__ */ jsx("span", { className: "gsi-material-button-contents", children: "Google" }),
315
+ /* @__PURE__ */ jsx("span", { style: { display: "none" }, children: "Google" })
177
316
  ] })
178
317
  ] });
179
318
  };
@@ -204,10 +343,10 @@ function authStateToStatus(step) {
204
343
  ];
205
344
  const success = ["authenticated", "entering_code"];
206
345
  const error = ["error", "wallet_not_installed"];
207
- if (loading.includes(step)) return StateStatus.LOADING;
208
- if (success.includes(step)) return StateStatus.SUCCESS;
209
- if (error.includes(step)) return StateStatus.ERROR;
210
- return StateStatus.NONE;
346
+ if (loading.includes(step)) return "LOADING";
347
+ if (success.includes(step)) return "SUCCESS";
348
+ if (error.includes(step)) return "ERROR";
349
+ return "NONE";
211
350
  }
212
351
  function LoginModalTemplate({
213
352
  theme,
@@ -230,6 +369,7 @@ function LoginModalTemplate({
230
369
  onCancel,
231
370
  onRetry
232
371
  }) {
372
+ const [showWalletPicker, setShowWalletPicker] = useState(false);
233
373
  const isDark = theme === "dark";
234
374
  const enabledSocial = Object.entries(providers).filter(([, enabled]) => enabled);
235
375
  const cssVars = {
@@ -246,20 +386,52 @@ function LoginModalTemplate({
246
386
  "--pollar-error-text": isDark ? "#f87171" : "#dc2626"
247
387
  };
248
388
  const status = authStateToStatus(authState.step);
249
- const isLoading = status === StateStatus.LOADING;
389
+ const isLoading = status === "LOADING";
250
390
  const isEmailCodeError = authState.step === "error" && (authState.errorCode === AUTH_ERROR_CODES.EMAIL_CODE_EXPIRED || authState.errorCode === AUTH_ERROR_CODES.EMAIL_CODE_INVALID);
251
391
  const awaitingEmailCode = authState.step === "entering_code" || authState.step === "verifying_email_code" || isEmailCodeError;
252
392
  const statusMessage = authState.step === "error" ? authState.message : AUTH_STATE_MESSAGES[authState.step];
393
+ const BackButton = ({ onClick }) => /* @__PURE__ */ jsx("button", { type: "button", className: "pollar-back-btn", onClick, "aria-label": "Back", children: /* @__PURE__ */ jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M15 19l-7-7 7-7" }) }) });
253
394
  return /* @__PURE__ */ jsxs("div", { className: "pollar-modal", style: cssVars, onClick: (e) => e.stopPropagation(), children: [
395
+ /* @__PURE__ */ jsx("button", { type: "button", className: "pollar-close-btn", onClick: onCancel, "aria-label": "Close", children: /* @__PURE__ */ jsx("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M18 6L6 18M6 6l12 12" }) }) }),
254
396
  /* @__PURE__ */ jsxs("div", { className: "pollar-header", children: [
255
397
  /* @__PURE__ */ jsx("div", { className: "pollar-logo-wrap", children: /* @__PURE__ */ jsx("img", { src: logoUrl ?? LOGO_POLLAR, alt: "Logo", className: "pollar-logo" }) }),
256
398
  /* @__PURE__ */ jsx("h2", { className: "pollar-title", children: appName }),
257
399
  /* @__PURE__ */ jsx("p", { className: "pollar-subtitle", children: "Log in or sign up" })
258
400
  ] }),
259
401
  awaitingEmailCode ? /* @__PURE__ */ jsxs(Fragment, { children: [
260
- /* @__PURE__ */ jsx("button", { type: "button", className: "pollar-back-btn", onClick: onBack, children: "\u2190 Back" }),
402
+ /* @__PURE__ */ jsx(BackButton, { onClick: onBack }),
261
403
  /* @__PURE__ */ jsx(EmailCodeInput, { email, onSubmit: onCodeSubmit ?? (() => {
262
404
  }) }, codeInputKey)
405
+ ] }) : showWalletPicker ? /* @__PURE__ */ jsxs(Fragment, { children: [
406
+ /* @__PURE__ */ jsx(BackButton, { onClick: () => setShowWalletPicker(false) }),
407
+ /* @__PURE__ */ jsxs("div", { className: "pollar-wallet-list", children: [
408
+ /* @__PURE__ */ jsxs(
409
+ "button",
410
+ {
411
+ type: "button",
412
+ disabled: isLoading,
413
+ className: "pollar-wallet-list-btn",
414
+ onClick: onFreighterConnect,
415
+ children: [
416
+ /* @__PURE__ */ jsx("img", { src: LOGO_FREIGHTER, alt: "Freighter", className: "pollar-wallet-list-icon" }),
417
+ /* @__PURE__ */ jsx("span", { className: "pollar-wallet-list-name", children: "Freighter" })
418
+ ]
419
+ }
420
+ ),
421
+ /* @__PURE__ */ jsxs(
422
+ "button",
423
+ {
424
+ type: "button",
425
+ disabled: isLoading,
426
+ className: "pollar-wallet-list-btn",
427
+ onClick: onAlbedoConnect,
428
+ children: [
429
+ /* @__PURE__ */ jsx("img", { src: LOGO_ALBEDO, alt: "Albedo", className: "pollar-wallet-list-icon" }),
430
+ /* @__PURE__ */ jsx("span", { className: "pollar-wallet-list-name", children: "Albedo" })
431
+ ]
432
+ }
433
+ )
434
+ ] })
263
435
  ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
264
436
  emailEnabled && /* @__PURE__ */ jsxs("div", { className: "pollar-email-section", children: [
265
437
  /* @__PURE__ */ jsx(
@@ -284,17 +456,19 @@ function LoginModalTemplate({
284
456
  enabledSocial.some(([key]) => key === "google") && /* @__PURE__ */ jsx(GoogleButton, { disabled: isLoading, onClick: () => onSocialLogin?.("google") }),
285
457
  enabledSocial.some(([key]) => key === "github") && /* @__PURE__ */ jsx(GithubButton, { disabled: isLoading, onClick: () => onSocialLogin?.("github") })
286
458
  ] }),
287
- embeddedWallets && /* @__PURE__ */ jsxs("div", { className: "pollar-wallet-section", children: [
288
- /* @__PURE__ */ jsx("p", { className: "pollar-wallet-label", children: "Continue with a wallet" }),
289
- /* @__PURE__ */ jsxs("button", { type: "button", disabled: isLoading, className: "pollar-wallet-btn", onClick: onFreighterConnect, children: [
290
- /* @__PURE__ */ jsx("img", { src: LOGO_FREIGHTER, alt: "Freighter", className: "pollar-wallet-icon" }),
291
- "Freighter"
292
- ] }),
293
- /* @__PURE__ */ jsxs("button", { type: "button", disabled: isLoading, className: "pollar-wallet-btn", onClick: onAlbedoConnect, children: [
294
- /* @__PURE__ */ jsx("img", { src: LOGO_ALBEDO, alt: "Albedo", className: "pollar-wallet-icon" }),
295
- "Albedo"
296
- ] })
297
- ] })
459
+ embeddedWallets && /* @__PURE__ */ jsx("div", { className: "pollar-wallet-section", children: /* @__PURE__ */ jsxs(
460
+ "button",
461
+ {
462
+ type: "button",
463
+ disabled: isLoading,
464
+ className: "pollar-wallet-entry-btn",
465
+ onClick: () => setShowWalletPicker(true),
466
+ children: [
467
+ /* @__PURE__ */ jsx("svg", { width: "18", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z" }) }),
468
+ "Wallet"
469
+ ]
470
+ }
471
+ ) })
298
472
  ] }),
299
473
  /* @__PURE__ */ jsx(
300
474
  ModalStatusBanner,
@@ -341,7 +515,7 @@ function LoginModal({ onClose }) {
341
515
  getClient().beginEmailLogin();
342
516
  }
343
517
  function handleSocialLogin(provider) {
344
- getClient().loginOAuth(provider);
518
+ getClient().login({ provider });
345
519
  }
346
520
  function handleWalletConnect(type) {
347
521
  getClient().loginWallet(type);
@@ -385,21 +559,336 @@ function LoginModal({ onClose }) {
385
559
  codeInputKey,
386
560
  onCodeSubmit: handleVerifyCode,
387
561
  onBack: handleBack,
388
- onCancel: () => getClient().cancelLogin(),
562
+ onCancel: handleClose,
389
563
  onRetry: handleRetry
390
564
  }
391
565
  ) });
392
566
  }
567
+ var RAIL_LABELS = {
568
+ SPEI: "SPEI (Mexico)",
569
+ PIX: "PIX (Brazil)",
570
+ PSE: "PSE (Colombia)",
571
+ ACH: "ACH (US)"
572
+ };
573
+ function RouteDisplay({ quote, onSelect }) {
574
+ return /* @__PURE__ */ jsxs(
575
+ "div",
576
+ {
577
+ className: "pollar-ramp-route-card",
578
+ "data-recommended": quote.recommended,
579
+ role: "button",
580
+ tabIndex: 0,
581
+ onClick: () => onSelect(quote),
582
+ onKeyDown: (e) => e.key === "Enter" && onSelect(quote),
583
+ children: [
584
+ /* @__PURE__ */ jsxs("div", { className: "pollar-ramp-route-left", children: [
585
+ /* @__PURE__ */ jsx("span", { className: "pollar-ramp-route-provider", children: quote.provider }),
586
+ /* @__PURE__ */ jsxs("span", { className: "pollar-ramp-route-meta", children: [
587
+ RAIL_LABELS[quote.rail] ?? quote.rail,
588
+ " \xB7 ",
589
+ quote.protocol,
590
+ " \xB7 ",
591
+ quote.estimatedTime
592
+ ] })
593
+ ] }),
594
+ /* @__PURE__ */ jsxs("div", { className: "pollar-ramp-route-right", children: [
595
+ /* @__PURE__ */ jsxs("span", { className: "pollar-ramp-route-fee", children: [
596
+ quote.fee,
597
+ "% fee"
598
+ ] }),
599
+ quote.recommended && /* @__PURE__ */ jsx("span", { className: "pollar-ramp-route-badge", children: "Best rate" })
600
+ ] })
601
+ ]
602
+ }
603
+ );
604
+ }
605
+ var LOADING_STEPS = ["Detecting your country\u2026", "Consulting providers\u2026", "Route found!"];
606
+ var COUNTRY_CURRENCIES = {
607
+ MX: "MXN",
608
+ BR: "BRL",
609
+ CO: "COP",
610
+ CL: "CLP",
611
+ PE: "PEN",
612
+ AR: "ARS"
613
+ };
614
+ function RampWidgetTemplate({
615
+ theme,
616
+ accentColor,
617
+ step,
618
+ direction,
619
+ amount,
620
+ currency,
621
+ country,
622
+ quotes,
623
+ paymentInstructions,
624
+ isLoading,
625
+ onDirectionChange,
626
+ onAmountChange,
627
+ onCurrencyChange,
628
+ onCountryChange,
629
+ onFindRoute,
630
+ onSelectQuote,
631
+ onCopy,
632
+ onClose
633
+ }) {
634
+ const isDark = theme === "dark";
635
+ const cssVars = {
636
+ "--pollar-accent": accentColor,
637
+ "--pollar-buttons-border-radius": "6px",
638
+ "--pollar-buttons-height": "44px",
639
+ "--pollar-bg": isDark ? "#1a1a1a" : "#ffffff",
640
+ "--pollar-border": isDark ? "#374151" : "#e5e7eb",
641
+ "--pollar-text": isDark ? "#ffffff" : "#111827",
642
+ "--pollar-muted": isDark ? "#9ca3af" : "#6b7280",
643
+ "--pollar-input-bg": isDark ? "#374151" : "#f9fafb"
644
+ };
645
+ const stepTitle = {
646
+ input: direction === "onramp" ? "Buy crypto" : "Sell crypto",
647
+ loading_quote: "Finding best route",
648
+ select_route: "Select provider",
649
+ payment_instructions: "Payment instructions"
650
+ };
651
+ const stepSubtitle = {
652
+ input: direction === "onramp" ? "Enter the amount you want to deposit" : "Enter the amount you want to withdraw",
653
+ loading_quote: "Comparing providers in real time\u2026",
654
+ select_route: "All prices include fees",
655
+ payment_instructions: "Send the exact amount to complete your transaction"
656
+ };
657
+ return /* @__PURE__ */ jsxs("div", { className: "pollar-ramp-modal", style: cssVars, onClick: (e) => e.stopPropagation(), children: [
658
+ /* @__PURE__ */ jsxs("div", { className: "pollar-ramp-header", children: [
659
+ /* @__PURE__ */ jsx("h2", { className: "pollar-ramp-title", children: stepTitle[step] }),
660
+ /* @__PURE__ */ jsx("p", { className: "pollar-ramp-subtitle", children: stepSubtitle[step] })
661
+ ] }),
662
+ step === "input" && /* @__PURE__ */ jsxs(Fragment, { children: [
663
+ /* @__PURE__ */ jsxs("div", { className: "pollar-ramp-tabs", children: [
664
+ /* @__PURE__ */ jsx("button", { type: "button", className: "pollar-ramp-tab", "data-active": direction === "onramp", onClick: () => onDirectionChange("onramp"), children: "Buy" }),
665
+ /* @__PURE__ */ jsx("button", { type: "button", className: "pollar-ramp-tab", "data-active": direction === "offramp", onClick: () => onDirectionChange("offramp"), children: "Sell" })
666
+ ] }),
667
+ /* @__PURE__ */ jsxs("div", { className: "pollar-ramp-input-row", children: [
668
+ /* @__PURE__ */ jsxs("div", { className: "pollar-ramp-field", children: [
669
+ /* @__PURE__ */ jsx("label", { className: "pollar-ramp-label", children: "Amount" }),
670
+ /* @__PURE__ */ jsx(
671
+ "input",
672
+ {
673
+ type: "number",
674
+ className: "pollar-ramp-input",
675
+ placeholder: "0.00",
676
+ value: amount,
677
+ min: "0",
678
+ onChange: (e) => onAmountChange(e.target.value)
679
+ }
680
+ )
681
+ ] }),
682
+ /* @__PURE__ */ jsxs("div", { className: "pollar-ramp-field", style: { maxWidth: 90 }, children: [
683
+ /* @__PURE__ */ jsx("label", { className: "pollar-ramp-label", children: "Currency" }),
684
+ /* @__PURE__ */ jsx(
685
+ "input",
686
+ {
687
+ type: "text",
688
+ className: "pollar-ramp-input",
689
+ placeholder: "MXN",
690
+ value: currency,
691
+ maxLength: 5,
692
+ onChange: (e) => onCurrencyChange(e.target.value.toUpperCase())
693
+ }
694
+ )
695
+ ] })
696
+ ] }),
697
+ /* @__PURE__ */ jsxs("div", { className: "pollar-ramp-field", children: [
698
+ /* @__PURE__ */ jsx("label", { className: "pollar-ramp-label", children: "Country" }),
699
+ /* @__PURE__ */ jsxs(
700
+ "select",
701
+ {
702
+ className: "pollar-ramp-input",
703
+ value: country,
704
+ onChange: (e) => {
705
+ const c = e.target.value;
706
+ onCountryChange(c);
707
+ if (COUNTRY_CURRENCIES[c]) onCurrencyChange(COUNTRY_CURRENCIES[c]);
708
+ },
709
+ children: [
710
+ /* @__PURE__ */ jsx("option", { value: "MX", children: "\u{1F1F2}\u{1F1FD} Mexico" }),
711
+ /* @__PURE__ */ jsx("option", { value: "BR", children: "\u{1F1E7}\u{1F1F7} Brazil" }),
712
+ /* @__PURE__ */ jsx("option", { value: "CO", children: "\u{1F1E8}\u{1F1F4} Colombia" }),
713
+ /* @__PURE__ */ jsx("option", { value: "CL", children: "\u{1F1E8}\u{1F1F1} Chile" }),
714
+ /* @__PURE__ */ jsx("option", { value: "PE", children: "\u{1F1F5}\u{1F1EA} Peru" }),
715
+ /* @__PURE__ */ jsx("option", { value: "AR", children: "\u{1F1E6}\u{1F1F7} Argentina" })
716
+ ]
717
+ }
718
+ )
719
+ ] }),
720
+ /* @__PURE__ */ jsxs("div", { className: "pollar-modal-actions", children: [
721
+ /* @__PURE__ */ jsx("button", { type: "button", className: "pollar-btn-secondary", onClick: onClose, children: "Cancel" }),
722
+ /* @__PURE__ */ jsx("button", { type: "button", className: "pollar-btn-primary", disabled: !amount || isLoading, onClick: onFindRoute, children: "Find best route" })
723
+ ] })
724
+ ] }),
725
+ step === "loading_quote" && /* @__PURE__ */ jsx("div", { className: "pollar-ramp-loading", children: LOADING_STEPS.map((text, i) => /* @__PURE__ */ jsxs("div", { className: "pollar-ramp-loading-row", children: [
726
+ /* @__PURE__ */ jsx("div", { className: "pollar-ramp-loading-dot" }),
727
+ /* @__PURE__ */ jsx("span", { children: text })
728
+ ] }, i)) }),
729
+ step === "select_route" && /* @__PURE__ */ jsxs(Fragment, { children: [
730
+ /* @__PURE__ */ jsx("div", { className: "pollar-ramp-route-list", children: quotes.map((q, i) => /* @__PURE__ */ jsx(RouteDisplay, { quote: q, onSelect: onSelectQuote }, i)) }),
731
+ /* @__PURE__ */ jsx("button", { type: "button", className: "pollar-btn-secondary", onClick: onClose, children: "Cancel" })
732
+ ] }),
733
+ step === "payment_instructions" && paymentInstructions && /* @__PURE__ */ jsxs("div", { className: "pollar-ramp-payment", children: [
734
+ /* @__PURE__ */ jsx("p", { className: "pollar-ramp-payment-title", children: paymentInstructions.type }),
735
+ /* @__PURE__ */ jsxs("div", { className: "pollar-ramp-payment-field", children: [
736
+ /* @__PURE__ */ jsx("span", { className: "pollar-ramp-payment-label", children: paymentInstructions.type === "CLABE" ? "CLABE number" : paymentInstructions.type === "PIX" ? "PIX key" : "Account number" }),
737
+ /* @__PURE__ */ jsxs("div", { className: "pollar-ramp-payment-value", children: [
738
+ /* @__PURE__ */ jsx("code", { children: paymentInstructions.value }),
739
+ /* @__PURE__ */ jsx("button", { type: "button", className: "pollar-ramp-copy-btn", onClick: () => onCopy(paymentInstructions.value), children: "Copy" })
740
+ ] })
741
+ ] }),
742
+ /* @__PURE__ */ jsxs("div", { className: "pollar-ramp-payment-field", children: [
743
+ /* @__PURE__ */ jsx("span", { className: "pollar-ramp-payment-label", children: "Amount to send" }),
744
+ /* @__PURE__ */ jsxs("div", { className: "pollar-ramp-payment-value", children: [
745
+ /* @__PURE__ */ jsxs("code", { children: [
746
+ paymentInstructions.amount.toLocaleString(),
747
+ " ",
748
+ paymentInstructions.currency
749
+ ] }),
750
+ /* @__PURE__ */ jsx(
751
+ "button",
752
+ {
753
+ type: "button",
754
+ className: "pollar-ramp-copy-btn",
755
+ onClick: () => onCopy(`${paymentInstructions.amount} ${paymentInstructions.currency}`),
756
+ children: "Copy"
757
+ }
758
+ )
759
+ ] })
760
+ ] }),
761
+ paymentInstructions.expiresAt && /* @__PURE__ */ jsxs("p", { className: "pollar-ramp-payment-note", children: [
762
+ "Instructions expire at ",
763
+ new Date(paymentInstructions.expiresAt).toLocaleTimeString()
764
+ ] }),
765
+ /* @__PURE__ */ jsx("button", { type: "button", className: "pollar-btn-primary", onClick: onClose, children: "Done" })
766
+ ] })
767
+ ] });
768
+ }
769
+ var MOCK_DEFAULT_QUOTES = [
770
+ { quoteId: "meld-default", provider: "Meld", fee: 1.2, feeCurrency: "USD", rate: 1, rail: "ACH", protocol: "REST", estimatedTime: "~20 min", recommended: true }
771
+ ];
772
+ var MOCK_QUOTES = {
773
+ MX: [
774
+ { quoteId: "etherfuse-mx", provider: "Etherfuse", fee: 0.5, feeCurrency: "MXN", rate: 17.2, rail: "SPEI", protocol: "SEP-24", estimatedTime: "~10 min", recommended: true },
775
+ { quoteId: "alfredpay-mx", provider: "AlfredPay", fee: 0.8, feeCurrency: "MXN", rate: 17.1, rail: "SPEI", protocol: "REST", estimatedTime: "~15 min", recommended: false }
776
+ ],
777
+ BR: [{ quoteId: "abroad-br", provider: "Abroad", fee: 0.6, feeCurrency: "BRL", rate: 5.1, rail: "PIX", protocol: "REST", estimatedTime: "~5 min", recommended: true }],
778
+ CO: [
779
+ { quoteId: "abroad-co", provider: "Abroad", fee: 0.7, feeCurrency: "COP", rate: 4100, rail: "PSE", protocol: "REST", estimatedTime: "~10 min", recommended: true },
780
+ { quoteId: "koywe-co", provider: "Koywe", fee: 0.9, feeCurrency: "COP", rate: 4095, rail: "PSE", protocol: "REST", estimatedTime: "~15 min", recommended: false }
781
+ ],
782
+ DEFAULT: MOCK_DEFAULT_QUOTES
783
+ };
784
+ var MOCK_PAYMENT = {
785
+ type: "CLABE",
786
+ value: "646180157088723456",
787
+ amount: 1e3,
788
+ currency: "MXN",
789
+ expiresAt: new Date(Date.now() + 30 * 60 * 1e3).toISOString()
790
+ };
791
+ function RampWidget({ onClose }) {
792
+ const { getClient, walletAddress, styles } = usePollar();
793
+ const [step, setStep] = useState("input");
794
+ const [direction, setDirection] = useState("onramp");
795
+ const [amount, setAmount] = useState("");
796
+ const [currency, setCurrency] = useState("MXN");
797
+ const [country, setCountry] = useState("MX");
798
+ const [quotes, setQuotes] = useState([]);
799
+ const [paymentInstructions, setPaymentInstructions] = useState(null);
800
+ const [isLoading, setIsLoading] = useState(false);
801
+ const client = getClient();
802
+ const { theme = "light", accentColor = "#005DB4" } = styles;
803
+ async function handleFindRoute() {
804
+ setStep("loading_quote");
805
+ setIsLoading(true);
806
+ try {
807
+ const result = await client.getRampsQuote({
808
+ country,
809
+ amount: Number(amount),
810
+ currency,
811
+ direction
812
+ });
813
+ if (result.quotes) setQuotes(result.quotes);
814
+ } catch {
815
+ await new Promise((r) => setTimeout(r, 1500));
816
+ setQuotes(MOCK_QUOTES[country] ?? MOCK_DEFAULT_QUOTES);
817
+ } finally {
818
+ setIsLoading(false);
819
+ setStep("select_route");
820
+ }
821
+ }
822
+ async function handleSelectQuote(quote) {
823
+ if (!walletAddress) return;
824
+ setIsLoading(true);
825
+ const body = {
826
+ quoteId: `${quote.provider}-${Date.now()}`,
827
+ amount: Number(amount),
828
+ currency,
829
+ country,
830
+ walletAddress
831
+ };
832
+ try {
833
+ const result = await client.createOnRamp(body);
834
+ setPaymentInstructions(result.paymentInstructions);
835
+ } catch {
836
+ await new Promise((r) => setTimeout(r, 800));
837
+ setPaymentInstructions({ ...MOCK_PAYMENT, currency });
838
+ } finally {
839
+ setIsLoading(false);
840
+ setStep("payment_instructions");
841
+ }
842
+ }
843
+ function handleCopy(value) {
844
+ navigator.clipboard.writeText(value).catch(() => {
845
+ });
846
+ }
847
+ return /* @__PURE__ */ jsx("div", { className: "pollar-overlay", onClick: onClose, children: /* @__PURE__ */ jsx(
848
+ RampWidgetTemplate,
849
+ {
850
+ theme,
851
+ accentColor,
852
+ step,
853
+ direction,
854
+ amount,
855
+ currency,
856
+ country,
857
+ quotes,
858
+ paymentInstructions,
859
+ isLoading,
860
+ onDirectionChange: setDirection,
861
+ onAmountChange: setAmount,
862
+ onCurrencyChange: setCurrency,
863
+ onCountryChange: setCountry,
864
+ onFindRoute: handleFindRoute,
865
+ onSelectQuote: handleSelectQuote,
866
+ onCopy: handleCopy,
867
+ onClose
868
+ }
869
+ ) });
870
+ }
871
+ var STATUS_MESSAGES = {
872
+ idle: "",
873
+ building: "Building transaction\u2026",
874
+ built: "Ready to sign and send",
875
+ signing: "Signing and sending transaction\u2026",
876
+ success: "Transaction sent successfully",
877
+ error: "Transaction failed"
878
+ };
393
879
  function TransactionModalTemplate({
394
880
  theme,
395
881
  accentColor,
396
- transactionStateCode,
397
- status,
398
- buildResult,
399
- submitResult,
882
+ transaction,
883
+ showXdr,
884
+ copied,
885
+ explorerUrl,
886
+ walletType,
400
887
  onClose,
401
888
  onSignAndSend,
402
- onRetrySignAndSend
889
+ onToggleXdr,
890
+ onCopyHash,
891
+ onRetry
403
892
  }) {
404
893
  const isDark = theme === "dark";
405
894
  const cssVars = {
@@ -414,43 +903,48 @@ function TransactionModalTemplate({
414
903
  "--pollar-error-text": isDark ? "#f87171" : "#dc2626",
415
904
  "--pollar-success-text": isDark ? "#4ade80" : "#16a34a"
416
905
  };
417
- const [showXdr, setShowXdr] = useState(false);
418
- const [copied, setCopied] = useState(false);
419
- function handleCopyHash() {
420
- if (!submitResult) return;
421
- navigator.clipboard.writeText(submitResult.hash).then(() => {
422
- setCopied(true);
423
- setTimeout(() => setCopied(false), 2e3);
424
- });
425
- }
426
- const explorerNetwork = buildResult?.summary.network?.toLowerCase().includes("testnet") ? "testnet" : "public";
427
- const explorerUrl = submitResult ? `https://stellar.expert/explorer/${explorerNetwork}/tx/${submitResult.hash}` : null;
428
- transactionStateCode.includes("ERROR");
429
- transactionStateCode.includes("SUCCESS");
430
- const isBuilt = buildResult && transactionStateCode === "BUILD_TRANSACTION_SUCCESS";
431
- const isDone = submitResult && transactionStateCode === "SIGN_SEND_TRANSACTION_START";
906
+ const buildData = "buildData" in transaction ? transaction.buildData : null;
907
+ const hash = transaction.step === "success" ? transaction.hash : null;
908
+ const errorDetails = transaction.step === "error" ? transaction.details ?? null : null;
909
+ const isBuilt = transaction.step === "built";
910
+ const isSigning = transaction.step === "signing";
911
+ const isSuccess = transaction.step === "success";
912
+ const isError = transaction.step === "error";
913
+ const showDetails = buildData !== null && (isBuilt || isSigning || isSuccess);
432
914
  return /* @__PURE__ */ jsxs("div", { className: "pollar-tx-modal", "data-theme": theme, style: cssVars, onClick: (e) => e.stopPropagation(), children: [
433
- /* @__PURE__ */ jsxs("div", { className: "pollar-tx-header", children: [
434
- /* @__PURE__ */ jsx("h2", { className: "pollar-tx-title", children: "Transaction" }),
435
- /* @__PURE__ */ jsx("button", { className: "pollar-tx-close", onClick: onClose, "aria-label": "Close", children: /* @__PURE__ */ jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsx("path", { d: "M2 2l12 12M14 2L2 14", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) }) })
436
- ] }),
437
- isBuilt && /* @__PURE__ */ jsxs(Fragment, { children: [
915
+ /* @__PURE__ */ jsx("div", { className: "pollar-modal-header", children: /* @__PURE__ */ jsx("h2", { className: "pollar-modal-title", children: "Transaction" }) }),
916
+ /* @__PURE__ */ jsx("button", { type: "button", className: "pollar-close-btn", onClick: onClose, "aria-label": "Close", children: /* @__PURE__ */ jsx(
917
+ "svg",
918
+ {
919
+ width: "18",
920
+ height: "18",
921
+ viewBox: "0 0 24 24",
922
+ fill: "none",
923
+ stroke: "currentColor",
924
+ strokeWidth: "2.5",
925
+ strokeLinecap: "round",
926
+ strokeLinejoin: "round",
927
+ "aria-hidden": true,
928
+ children: /* @__PURE__ */ jsx("path", { d: "M18 6L6 18M6 6l12 12" })
929
+ }
930
+ ) }),
931
+ showDetails && buildData && /* @__PURE__ */ jsxs(Fragment, { children: [
438
932
  /* @__PURE__ */ jsxs("div", { className: "pollar-tx-summary", children: [
439
933
  /* @__PURE__ */ jsx("p", { className: "pollar-tx-summary-title", children: "Details" }),
440
- /* @__PURE__ */ jsx("ul", { className: "pollar-tx-summary-lines", children: buildResult.summary.lines.map((line, i) => /* @__PURE__ */ jsx("li", { className: "pollar-tx-summary-line", children: line }, i)) })
934
+ /* @__PURE__ */ jsx("ul", { className: "pollar-tx-summary-lines", children: buildData.summary.lines.map((line, i) => /* @__PURE__ */ jsx("li", { className: "pollar-tx-summary-line", children: line }, i)) })
441
935
  ] }),
442
936
  /* @__PURE__ */ jsxs("div", { className: "pollar-tx-meta", children: [
443
937
  /* @__PURE__ */ jsxs("div", { className: "pollar-tx-meta-item", children: [
444
938
  /* @__PURE__ */ jsx("span", { className: "pollar-tx-meta-label", children: "Network" }),
445
- /* @__PURE__ */ jsx("span", { className: "pollar-tx-meta-value", children: buildResult.summary.network })
939
+ /* @__PURE__ */ jsx("span", { className: "pollar-tx-meta-value", children: buildData.summary.network })
446
940
  ] }),
447
941
  /* @__PURE__ */ jsxs("div", { className: "pollar-tx-meta-item", children: [
448
942
  /* @__PURE__ */ jsx("span", { className: "pollar-tx-meta-label", children: "Fee" }),
449
- /* @__PURE__ */ jsx("span", { className: "pollar-tx-meta-value", children: buildResult.summary.fee })
943
+ /* @__PURE__ */ jsx("span", { className: "pollar-tx-meta-value", children: buildData.summary.fee })
450
944
  ] })
451
945
  ] }),
452
946
  /* @__PURE__ */ jsxs("div", { className: "pollar-tx-xdr", children: [
453
- /* @__PURE__ */ jsxs("button", { className: "pollar-tx-xdr-toggle", onClick: () => setShowXdr((v) => !v), children: [
947
+ /* @__PURE__ */ jsxs("button", { className: "pollar-tx-xdr-toggle", onClick: onToggleXdr, children: [
454
948
  /* @__PURE__ */ jsx(
455
949
  "svg",
456
950
  {
@@ -465,14 +959,61 @@ function TransactionModalTemplate({
465
959
  ),
466
960
  "Raw transaction (XDR)"
467
961
  ] }),
468
- showXdr && /* @__PURE__ */ jsx("pre", { className: "pollar-tx-xdr-content", children: buildResult.unsignedXdr })
962
+ showXdr && /* @__PURE__ */ jsx("pre", { className: "pollar-tx-xdr-content", children: buildData.unsignedXdr })
469
963
  ] })
470
964
  ] }),
471
- submitResult && transactionStateCode === "SIGN_SEND_TRANSACTION_SUCCESS" && /* @__PURE__ */ jsxs("div", { className: "pollar-tx-result", children: [
965
+ isError && errorDetails && /* @__PURE__ */ jsxs("div", { className: "pollar-tx-error-details", children: [
966
+ /* @__PURE__ */ jsx("p", { className: "pollar-tx-error-details-label", children: "Error details" }),
967
+ /* @__PURE__ */ jsx("pre", { className: "pollar-tx-error-details-content", children: errorDetails })
968
+ ] }),
969
+ isBuilt && /* @__PURE__ */ jsx("button", { className: "pollar-btn-primary pollar-tx-sign-btn", onClick: onSignAndSend, children: "Sign & Send" }),
970
+ (isSigning || isSuccess || isError) && /* @__PURE__ */ jsxs("div", { className: "pollar-tx-wallet-spinner", children: [
971
+ /* @__PURE__ */ jsxs("div", { className: "pollar-tx-spinner-ring", children: [
972
+ /* @__PURE__ */ jsxs(
973
+ "svg",
974
+ {
975
+ viewBox: "0 0 88 88",
976
+ width: "88",
977
+ height: "88",
978
+ className: `pollar-tx-spinner-svg${isSigning ? " pollar-tx-spinner-rotating" : ""}`,
979
+ "aria-hidden": true,
980
+ children: [
981
+ /* @__PURE__ */ jsx("circle", { cx: "44", cy: "44", r: "36", fill: "none", stroke: "var(--pollar-border)", strokeWidth: "3" }),
982
+ /* @__PURE__ */ jsx(
983
+ "circle",
984
+ {
985
+ cx: "44",
986
+ cy: "44",
987
+ r: "36",
988
+ fill: "none",
989
+ stroke: isSuccess ? "var(--pollar-success-text)" : isError ? "var(--pollar-error-text)" : "var(--pollar-accent)",
990
+ strokeWidth: "3",
991
+ strokeLinecap: "round",
992
+ strokeDasharray: isSigning ? "169.6 56.6" : "999 0",
993
+ transform: "rotate(-90 44 44)",
994
+ style: { transition: isSigning ? "none" : "stroke 400ms, stroke-dasharray 400ms" }
995
+ }
996
+ )
997
+ ]
998
+ }
999
+ ),
1000
+ /* @__PURE__ */ jsx("div", { className: "pollar-tx-wallet-icon", children: /* @__PURE__ */ jsx(
1001
+ "img",
1002
+ {
1003
+ src: walletType === WalletType.FREIGHTER ? LOGO_FREIGHTER : walletType === WalletType.ALBEDO ? LOGO_ALBEDO : LOGO_POLLAR,
1004
+ alt: walletType === WalletType.FREIGHTER ? "Freighter" : walletType === WalletType.ALBEDO ? "Albedo" : "Pollar",
1005
+ className: "pollar-tx-wallet-img"
1006
+ }
1007
+ ) })
1008
+ ] }),
1009
+ isSigning && /* @__PURE__ */ jsx("p", { className: "pollar-tx-spinner-label", children: walletType === WalletType.FREIGHTER ? "Waiting for Freighter\u2026" : walletType === WalletType.ALBEDO ? "Waiting for Albedo\u2026" : "Signing and sending\u2026" }),
1010
+ isError && onRetry && "buildData" in transaction && transaction.buildData && /* @__PURE__ */ jsx("button", { className: "pollar-btn-secondary pollar-tx-retry-btn", onClick: onRetry, children: "Try again" })
1011
+ ] }),
1012
+ isSuccess && hash && /* @__PURE__ */ jsxs("div", { className: "pollar-tx-result", children: [
472
1013
  /* @__PURE__ */ jsx("span", { className: "pollar-tx-result-label", children: "Transaction hash" }),
473
- /* @__PURE__ */ jsx("span", { className: "pollar-tx-result-hash", children: submitResult.hash }),
1014
+ /* @__PURE__ */ jsx("span", { className: "pollar-tx-result-hash", children: hash }),
474
1015
  /* @__PURE__ */ jsxs("div", { className: "pollar-tx-result-actions", children: [
475
- /* @__PURE__ */ jsx("button", { className: "pollar-tx-result-btn", onClick: handleCopyHash, children: copied ? /* @__PURE__ */ jsxs(Fragment, { children: [
1016
+ /* @__PURE__ */ jsx("button", { className: "pollar-tx-result-btn", onClick: onCopyHash, children: copied ? /* @__PURE__ */ jsxs(Fragment, { children: [
476
1017
  /* @__PURE__ */ jsxs("svg", { width: "13", height: "13", viewBox: "0 0 14 14", fill: "none", "aria-hidden": true, children: [
477
1018
  /* @__PURE__ */ jsx("circle", { cx: "7", cy: "7", r: "7", fill: "currentColor" }),
478
1019
  /* @__PURE__ */ jsx(
@@ -528,48 +1069,41 @@ function TransactionModalTemplate({
528
1069
  ] })
529
1070
  ] })
530
1071
  ] }),
531
- isBuilt && /* @__PURE__ */ jsx("button", { className: "pollar-tx-sign-btn", onClick: onSignAndSend, children: "Sign & Send" }),
532
- isDone && /* @__PURE__ */ jsx("button", { className: "pollar-tx-sign-btn", onClick: onClose, children: "Done" }),
1072
+ isSuccess && /* @__PURE__ */ jsx("button", { className: "pollar-btn-primary pollar-tx-sign-btn", onClick: onClose, children: "Done" }),
533
1073
  /* @__PURE__ */ jsx(
534
1074
  ModalStatusBanner,
535
1075
  {
536
- message: TRANSACTION_CODE_MESSAGES[transactionStateCode] ?? "",
537
- status
1076
+ message: STATUS_MESSAGES[transaction.step],
1077
+ status: isError ? "ERROR" : isSigning || transaction.step === "building" ? "LOADING" : isSuccess ? "SUCCESS" : "NONE"
538
1078
  }
539
1079
  ),
540
1080
  /* @__PURE__ */ jsx(PollarModalFooter, {})
541
1081
  ] });
542
1082
  }
543
- var isTxBuildResponseContent = (data) => {
544
- if (!data || typeof data !== "object") return false;
545
- const d = data;
546
- return typeof d.unsignedXdr === "string" && typeof d.networkPassphrase === "string" && typeof d.estimatedFee === "string" && d.summary !== null && typeof d.summary === "object";
547
- };
548
- var isTxSignSendResponseContent = (data) => {
549
- if (!data || typeof data !== "object") return false;
550
- const d = data;
551
- return typeof d.hash === "string" && (d.status === "PENDING" || d.status === "SUCCESS" || d.status === "FAILED");
552
- };
553
1083
  function TransactionModal({ onClose }) {
554
- const {
555
- getClient,
556
- styles,
557
- state: { transaction }
558
- } = usePollar();
1084
+ const { getClient, styles, transaction, network, walletType } = usePollar();
559
1085
  const { theme = "light", accentColor = "#005DB4" } = styles;
560
- let buildResult = null;
561
- const transactionStateCode = transaction.code;
562
- const content = transaction.data?.content;
563
- if (isTxBuildResponseContent(content)) {
564
- buildResult = content;
1086
+ const [showXdr, setShowXdr] = useState(false);
1087
+ const [copied, setCopied] = useState(false);
1088
+ const hash = transaction.step === "success" ? transaction.hash : null;
1089
+ const buildData = "buildData" in transaction ? transaction.buildData : null;
1090
+ const explorerNetwork = buildData?.summary.network?.toLowerCase().includes("testnet") ? "testnet" : "public";
1091
+ const explorerUrl = hash ? `https://stellar.expert/explorer/${explorerNetwork}/tx/${hash}` : null;
1092
+ function handleSignAndSend() {
1093
+ if (transaction.step === "built") {
1094
+ void getClient().signAndSubmitTx(transaction.buildData.unsignedXdr);
1095
+ }
565
1096
  }
566
- let submitResult = null;
567
- if (isTxSignSendResponseContent(content)) {
568
- submitResult = content;
1097
+ function handleCopyHash() {
1098
+ if (!hash) return;
1099
+ navigator.clipboard.writeText(hash).then(() => {
1100
+ setCopied(true);
1101
+ setTimeout(() => setCopied(false), 2e3);
1102
+ });
569
1103
  }
570
- async function handleSignAndSend() {
571
- if (buildResult) {
572
- await getClient().submitTx(buildResult.unsignedXdr);
1104
+ async function handleRetry() {
1105
+ if (transaction.step === "error" && transaction.buildData) {
1106
+ await getClient().signAndSubmitTx(transaction.buildData.unsignedXdr);
573
1107
  }
574
1108
  }
575
1109
  return /* @__PURE__ */ jsx("div", { className: "pollar-overlay", onClick: onClose, children: /* @__PURE__ */ jsx(
@@ -577,13 +1111,243 @@ function TransactionModal({ onClose }) {
577
1111
  {
578
1112
  theme,
579
1113
  accentColor,
580
- transactionStateCode,
581
- status: transaction.status,
582
- buildResult,
583
- submitResult,
1114
+ transaction,
1115
+ showXdr,
1116
+ copied,
1117
+ explorerUrl,
1118
+ walletType,
584
1119
  onClose,
585
1120
  onSignAndSend: handleSignAndSend,
586
- onRetrySignAndSend: handleSignAndSend
1121
+ onToggleXdr: () => setShowXdr((v) => !v),
1122
+ onCopyHash: handleCopyHash,
1123
+ onRetry: handleRetry
1124
+ }
1125
+ ) });
1126
+ }
1127
+ var PAGE_SIZE = 10;
1128
+ function StatusBadge({ status }) {
1129
+ return /* @__PURE__ */ jsx("span", { className: "pollar-hist-item-badge", "data-status": status, children: status });
1130
+ }
1131
+ function formatDate(iso) {
1132
+ return new Date(iso).toLocaleDateString(void 0, { month: "short", day: "numeric", year: "numeric" });
1133
+ }
1134
+ function TxHistoryModalTemplate({
1135
+ theme,
1136
+ accentColor,
1137
+ txHistory,
1138
+ offset,
1139
+ onRefresh,
1140
+ onPrev,
1141
+ onNext,
1142
+ onClose
1143
+ }) {
1144
+ const isDark = theme === "dark";
1145
+ const cssVars = {
1146
+ "--pollar-accent": accentColor,
1147
+ "--pollar-buttons-border-radius": "8px",
1148
+ "--pollar-buttons-height": "44px",
1149
+ "--pollar-bg": isDark ? "#1a1a1a" : "#ffffff",
1150
+ "--pollar-border": isDark ? "#374151" : "#e5e7eb",
1151
+ "--pollar-text": isDark ? "#ffffff" : "#111827",
1152
+ "--pollar-muted": isDark ? "#9ca3af" : "#6b7280",
1153
+ "--pollar-input-bg": isDark ? "#374151" : "rgba(0,0,0,0.04)",
1154
+ "--pollar-error-text": isDark ? "#f87171" : "#dc2626",
1155
+ "--pollar-success-text": isDark ? "#4ade80" : "#16a34a"
1156
+ };
1157
+ const isLoading = txHistory.step === "loading";
1158
+ const records = txHistory.step === "loaded" ? txHistory.data.records : [];
1159
+ const total = txHistory.step === "loaded" ? txHistory.data.total : 0;
1160
+ const hasPrev = offset > 0;
1161
+ const hasNext = offset + PAGE_SIZE < total;
1162
+ const showPagination = txHistory.step === "loaded" && total > PAGE_SIZE;
1163
+ return /* @__PURE__ */ jsxs("div", { className: "pollar-hist-modal", "data-theme": theme, style: cssVars, onClick: (e) => e.stopPropagation(), children: [
1164
+ /* @__PURE__ */ jsxs("div", { className: "pollar-modal-header", children: [
1165
+ /* @__PURE__ */ jsx("h2", { className: "pollar-modal-title", children: "Transaction History" }),
1166
+ /* @__PURE__ */ jsxs("div", { className: "pollar-modal-header-actions", children: [
1167
+ /* @__PURE__ */ jsxs("button", { className: "pollar-modal-refresh-btn", onClick: onRefresh, disabled: isLoading, children: [
1168
+ /* @__PURE__ */ jsxs(
1169
+ "svg",
1170
+ {
1171
+ className: `pollar-modal-refresh-icon${isLoading ? " spinning" : ""}`,
1172
+ width: "13",
1173
+ height: "13",
1174
+ viewBox: "0 0 13 13",
1175
+ fill: "none",
1176
+ "aria-hidden": true,
1177
+ children: [
1178
+ /* @__PURE__ */ jsx(
1179
+ "path",
1180
+ {
1181
+ d: "M11.5 6.5a5 5 0 11-1.5-3.536",
1182
+ stroke: "currentColor",
1183
+ strokeWidth: "1.5",
1184
+ strokeLinecap: "round"
1185
+ }
1186
+ ),
1187
+ /* @__PURE__ */ jsx("path", { d: "M10 1v3h-3", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })
1188
+ ]
1189
+ }
1190
+ ),
1191
+ "Refresh"
1192
+ ] }),
1193
+ /* @__PURE__ */ jsx("button", { className: "pollar-modal-close", onClick: onClose, "aria-label": "Close", children: /* @__PURE__ */ jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsx("path", { d: "M2 2l12 12M14 2L2 14", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) }) })
1194
+ ] })
1195
+ ] }),
1196
+ /* @__PURE__ */ jsxs("div", { className: "pollar-hist-list", children: [
1197
+ txHistory.step === "idle" && /* @__PURE__ */ jsx("div", { className: "pollar-modal-empty", children: "Click Refresh to load transactions." }),
1198
+ isLoading && /* @__PURE__ */ jsx("div", { className: "pollar-modal-empty", children: "Loading\u2026" }),
1199
+ txHistory.step === "error" && /* @__PURE__ */ jsx("div", { className: "pollar-modal-empty", children: txHistory.message }),
1200
+ txHistory.step === "loaded" && records.length === 0 && /* @__PURE__ */ jsx("div", { className: "pollar-modal-empty", children: "No transactions yet." }),
1201
+ records.map((record) => /* @__PURE__ */ jsxs("div", { className: "pollar-hist-item", children: [
1202
+ /* @__PURE__ */ jsx("span", { className: "pollar-hist-item-summary", children: record.summary }),
1203
+ /* @__PURE__ */ jsx(StatusBadge, { status: record.status }),
1204
+ /* @__PURE__ */ jsxs("span", { className: "pollar-hist-item-meta", children: [
1205
+ /* @__PURE__ */ jsx("span", { children: record.operation }),
1206
+ record.feeXlm && /* @__PURE__ */ jsxs("span", { children: [
1207
+ "\xB7 ",
1208
+ record.feeXlm,
1209
+ " XLM"
1210
+ ] }),
1211
+ /* @__PURE__ */ jsxs("span", { children: [
1212
+ "\xB7 ",
1213
+ formatDate(record.createdAt)
1214
+ ] })
1215
+ ] })
1216
+ ] }, record.id))
1217
+ ] }),
1218
+ showPagination && /* @__PURE__ */ jsxs("div", { className: "pollar-hist-pagination", children: [
1219
+ /* @__PURE__ */ jsxs("span", { className: "pollar-hist-pagination-info", children: [
1220
+ offset + 1,
1221
+ "\u2013",
1222
+ Math.min(offset + PAGE_SIZE, total),
1223
+ " of ",
1224
+ total
1225
+ ] }),
1226
+ /* @__PURE__ */ jsxs("div", { className: "pollar-hist-pagination-btns", children: [
1227
+ /* @__PURE__ */ jsx("button", { className: "pollar-hist-page-btn", onClick: onPrev, disabled: !hasPrev, children: "\u2190 Prev" }),
1228
+ /* @__PURE__ */ jsx("button", { className: "pollar-hist-page-btn", onClick: onNext, disabled: !hasNext, children: "Next \u2192" })
1229
+ ] })
1230
+ ] }),
1231
+ /* @__PURE__ */ jsx(PollarModalFooter, {})
1232
+ ] });
1233
+ }
1234
+ var PAGE_SIZE2 = 10;
1235
+ function TxHistoryModal({ onClose }) {
1236
+ const { getClient, styles, txHistory } = usePollar();
1237
+ const { theme = "light", accentColor = "#005DB4" } = styles;
1238
+ const [offset, setOffset] = useState(0);
1239
+ function load(nextOffset) {
1240
+ setOffset(nextOffset);
1241
+ void getClient().fetchTxHistory({ limit: PAGE_SIZE2, offset: nextOffset });
1242
+ }
1243
+ return /* @__PURE__ */ jsx("div", { className: "pollar-overlay", onClick: onClose, children: /* @__PURE__ */ jsx(
1244
+ TxHistoryModalTemplate,
1245
+ {
1246
+ theme,
1247
+ accentColor,
1248
+ txHistory,
1249
+ offset,
1250
+ onRefresh: () => load(offset),
1251
+ onPrev: () => load(Math.max(0, offset - PAGE_SIZE2)),
1252
+ onNext: () => load(offset + PAGE_SIZE2),
1253
+ onClose
1254
+ }
1255
+ ) });
1256
+ }
1257
+ function formatBalance(balance) {
1258
+ const n = parseFloat(balance);
1259
+ return isNaN(n) ? balance : n.toLocaleString(void 0, { maximumFractionDigits: 7 });
1260
+ }
1261
+ function cropAddress(address) {
1262
+ if (address.length <= 16) return address;
1263
+ return `${address.slice(0, 8)}...${address.slice(-8)}`;
1264
+ }
1265
+ function BalanceItem({ record }) {
1266
+ const balanceDiffers = record.balance !== record.available;
1267
+ return /* @__PURE__ */ jsxs("div", { className: "pollar-bal-item", children: [
1268
+ /* @__PURE__ */ jsx("span", { className: "pollar-bal-asset", children: record.code }),
1269
+ /* @__PURE__ */ jsxs("div", { className: "pollar-bal-amounts", children: [
1270
+ /* @__PURE__ */ jsx("span", { className: "pollar-bal-amount", children: formatBalance(record.balance) }),
1271
+ balanceDiffers && /* @__PURE__ */ jsxs("span", { className: "pollar-bal-available", children: [
1272
+ formatBalance(record.available),
1273
+ " available"
1274
+ ] })
1275
+ ] })
1276
+ ] });
1277
+ }
1278
+ function WalletBalanceModalTemplate({
1279
+ theme,
1280
+ accentColor,
1281
+ walletBalance,
1282
+ walletAddress,
1283
+ onRefresh,
1284
+ onClose
1285
+ }) {
1286
+ const isDark = theme === "dark";
1287
+ const cssVars = {
1288
+ "--pollar-accent": accentColor,
1289
+ "--pollar-bg": isDark ? "#1a1a1a" : "#ffffff",
1290
+ "--pollar-border": isDark ? "#374151" : "#e5e7eb",
1291
+ "--pollar-text": isDark ? "#ffffff" : "#111827",
1292
+ "--pollar-muted": isDark ? "#9ca3af" : "#6b7280",
1293
+ "--pollar-input-bg": isDark ? "#374151" : "rgba(0,0,0,0.04)",
1294
+ "--pollar-error-text": isDark ? "#f87171" : "#dc2626"
1295
+ };
1296
+ const isLoading = walletBalance.step === "loading";
1297
+ const data = walletBalance.step === "loaded" ? walletBalance.data : null;
1298
+ return /* @__PURE__ */ jsxs("div", { className: "pollar-bal-modal", "data-theme": theme, style: cssVars, onClick: (e) => e.stopPropagation(), children: [
1299
+ /* @__PURE__ */ jsxs("div", { className: "pollar-modal-header", children: [
1300
+ /* @__PURE__ */ jsx("h2", { className: "pollar-modal-title", children: "Wallet Balance" }),
1301
+ /* @__PURE__ */ jsxs("div", { className: "pollar-modal-header-actions", children: [
1302
+ /* @__PURE__ */ jsxs("button", { className: "pollar-modal-refresh-btn", onClick: onRefresh, disabled: isLoading, children: [
1303
+ /* @__PURE__ */ jsxs(
1304
+ "svg",
1305
+ {
1306
+ className: `pollar-modal-refresh-icon${isLoading ? " spinning" : ""}`,
1307
+ width: "13",
1308
+ height: "13",
1309
+ viewBox: "0 0 13 13",
1310
+ fill: "none",
1311
+ "aria-hidden": true,
1312
+ children: [
1313
+ /* @__PURE__ */ jsx("path", { d: "M11.5 6.5a5 5 0 11-1.5-3.536", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" }),
1314
+ /* @__PURE__ */ jsx("path", { d: "M10 1v3h-3", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })
1315
+ ]
1316
+ }
1317
+ ),
1318
+ "Refresh"
1319
+ ] }),
1320
+ /* @__PURE__ */ jsx("button", { className: "pollar-modal-close", onClick: onClose, "aria-label": "Close", children: /* @__PURE__ */ jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsx("path", { d: "M2 2l12 12M14 2L2 14", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) }) })
1321
+ ] })
1322
+ ] }),
1323
+ walletAddress && /* @__PURE__ */ jsx("div", { className: "pollar-bal-address", children: cropAddress(walletAddress) }),
1324
+ isLoading && /* @__PURE__ */ jsx("div", { className: "pollar-modal-empty", children: "Loading\u2026" }),
1325
+ walletBalance.step === "error" && /* @__PURE__ */ jsx("div", { className: "pollar-modal-error", children: walletBalance.message }),
1326
+ data && !data.exists && /* @__PURE__ */ jsxs("div", { className: "pollar-modal-empty", children: [
1327
+ "Account not found on ",
1328
+ data.network,
1329
+ "."
1330
+ ] }),
1331
+ data?.exists && data.balances.length === 0 && /* @__PURE__ */ jsx("div", { className: "pollar-modal-empty", children: "No balances found." }),
1332
+ data?.exists && data.balances.length > 0 && /* @__PURE__ */ jsx("div", { className: "pollar-bal-list", children: data.balances.map((b) => /* @__PURE__ */ jsx(BalanceItem, { record: b }, b.code + (b.issuer ?? ""))) }),
1333
+ /* @__PURE__ */ jsx(PollarModalFooter, {})
1334
+ ] });
1335
+ }
1336
+ function WalletBalanceModal({ onClose }) {
1337
+ const { walletBalance, refreshBalance, walletAddress, styles } = usePollar();
1338
+ const { theme = "light", accentColor = "#005DB4" } = styles;
1339
+ useEffect(() => {
1340
+ void refreshBalance();
1341
+ }, []);
1342
+ return /* @__PURE__ */ jsx("div", { className: "pollar-overlay", onClick: onClose, children: /* @__PURE__ */ jsx(
1343
+ WalletBalanceModalTemplate,
1344
+ {
1345
+ theme,
1346
+ accentColor,
1347
+ walletBalance,
1348
+ walletAddress,
1349
+ onRefresh: () => refreshBalance(),
1350
+ onClose
587
1351
  }
588
1352
  ) });
589
1353
  }
@@ -593,48 +1357,32 @@ var emptyResponse = {
593
1357
  },
594
1358
  styles: {}
595
1359
  };
596
- async function fetchRemoteConfig(api) {
597
- try {
598
- const { data, error } = await api.GET(`/applications/config`);
599
- if (!data || error) {
600
- return emptyResponse;
601
- }
602
- return data.content;
603
- } catch {
604
- return emptyResponse;
605
- }
1360
+ async function fetchRemoteConfig(client) {
1361
+ const content = await client.getAppConfig();
1362
+ return content ?? emptyResponse;
606
1363
  }
607
1364
  var PollarContext = createContext(null);
608
1365
  function PollarProvider({ config, styles: propStyles, children }) {
609
1366
  const [pollarClient] = useState(() => new PollarClient(config));
610
- const [stellarClient] = useState(() => new StellarClient(config.stellarNetwork || "testnet"));
1367
+ const [networkState, setNetworkState] = useState(() => pollarClient.getNetworkState());
611
1368
  const [sessionState, setSessionState] = useState(null);
612
- const [state, setState] = useState({
613
- network: {
614
- var: "network",
615
- code: STATE_VAR_CODES.network.NONE,
616
- status: StateStatus.NONE,
617
- level: "info",
618
- ts: 0
619
- },
620
- transaction: {
621
- var: "transaction",
622
- code: STATE_VAR_CODES.transaction.NONE,
623
- status: StateStatus.NONE,
624
- level: "info",
625
- ts: 0
626
- }
627
- });
1369
+ const [transaction, setTransaction] = useState({ step: "idle" });
1370
+ const [txHistory, setTxHistory] = useState({ step: "idle" });
1371
+ const [walletBalance, setWalletBalance] = useState({ step: "idle" });
628
1372
  const [remoteConfig, setRemoteConfig] = useState(emptyResponse);
629
1373
  const [styles, setStyles] = useState(propStyles ?? {});
630
1374
  useEffect(() => {
631
- return pollarClient.onStateChange((stateEntry) => {
632
- setState((prevState) => {
633
- if (JSON.stringify(prevState[stateEntry.var]) !== JSON.stringify(stateEntry)) {
634
- return { ...prevState, [stateEntry.var]: stateEntry };
635
- }
636
- return prevState;
637
- });
1375
+ return pollarClient.onTransactionStateChange(setTransaction);
1376
+ }, [pollarClient]);
1377
+ useEffect(() => {
1378
+ return pollarClient.onTxHistoryStateChange(setTxHistory);
1379
+ }, [pollarClient]);
1380
+ useEffect(() => {
1381
+ return pollarClient.onWalletBalanceStateChange(setWalletBalance);
1382
+ }, [pollarClient]);
1383
+ useEffect(() => {
1384
+ return pollarClient.onNetworkStateChange((state) => {
1385
+ setNetworkState(state);
638
1386
  });
639
1387
  }, [pollarClient]);
640
1388
  useEffect(() => {
@@ -647,7 +1395,7 @@ function PollarProvider({ config, styles: propStyles, children }) {
647
1395
  });
648
1396
  }, [pollarClient]);
649
1397
  useEffect(() => {
650
- fetchRemoteConfig(pollarClient.getApi()).then((fetched) => {
1398
+ fetchRemoteConfig(pollarClient).then((fetched) => {
651
1399
  setRemoteConfig(fetched);
652
1400
  setStyles({
653
1401
  ...fetched.styles,
@@ -658,40 +1406,64 @@ function PollarProvider({ config, styles: propStyles, children }) {
658
1406
  setStyles(propStyles ?? {});
659
1407
  });
660
1408
  }, [pollarClient]);
1409
+ useEffect(() => {
1410
+ if (transaction.step !== "idle") {
1411
+ setTransactionModalOpen(true);
1412
+ }
1413
+ }, [transaction.step]);
661
1414
  const [loginModalOpen, setLoginModalOpen] = useState(false);
662
1415
  const [transactionModalOpen, setTransactionModalOpen] = useState(false);
1416
+ const [kycModalOpen, setKycModalOpen] = useState(false);
1417
+ const [kycModalOptions, setKycModalOptions] = useState({});
1418
+ const [rampWidgetOpen, setRampWidgetOpen] = useState(false);
1419
+ const [txHistoryModalOpen, setTxHistoryModalOpen] = useState(false);
1420
+ const [walletBalanceModalOpen, setWalletBalanceModalOpen] = useState(false);
663
1421
  const contextValue = useMemo(
664
1422
  () => ({
665
- walletAddress: sessionState?.wallet?.publicKey || "",
1423
+ walletAddress: sessionState?.data?.providers?.wallet?.address || sessionState?.wallet?.publicKey || "",
666
1424
  getClient: () => pollarClient,
667
- state,
1425
+ transaction,
668
1426
  login: (options) => pollarClient.login(options),
669
1427
  logout: () => pollarClient.logout(),
670
- isAuthenticated: pollarClient.isAuthenticated(),
1428
+ isAuthenticated: !!sessionState?.wallet?.publicKey,
671
1429
  buildTx: (operation, params, options) => pollarClient.buildTx(operation, params, options),
672
- submitTx: (signedXdr) => pollarClient.submitTx(signedXdr),
673
- sendTransaction: (operation, params, options) => {
674
- void pollarClient.buildTx(operation, params, options);
675
- setTransactionModalOpen(true);
676
- },
1430
+ signAndSubmitTx: (unsignedXdr) => pollarClient.signAndSubmitTx(unsignedXdr),
1431
+ walletType: pollarClient.getWalletType(),
677
1432
  openTransactionModal: () => setTransactionModalOpen(true),
678
1433
  openLoginModal: () => setLoginModalOpen(true),
1434
+ openKycModal: (options = {}) => {
1435
+ setKycModalOptions(options);
1436
+ setKycModalOpen(true);
1437
+ },
1438
+ openRampWidget: () => setRampWidgetOpen(true),
1439
+ txHistory,
1440
+ openTxHistoryModal: () => setTxHistoryModalOpen(true),
1441
+ openWalletBalanceModal: () => setWalletBalanceModalOpen(true),
1442
+ walletBalance,
1443
+ refreshBalance: (publicKey) => pollarClient.refreshBalance(publicKey),
1444
+ network: networkState.step === "connected" ? networkState.network : "testnet",
1445
+ setNetwork: (network) => pollarClient.setNetwork(network),
679
1446
  config: remoteConfig,
680
- styles,
681
- async getBalance(publicKey) {
682
- const pk = publicKey || sessionState?.wallet?.publicKey;
683
- if (pk) {
684
- return await stellarClient.getBalances(pk);
685
- }
686
- return { success: false, errorCode: "NO_WALLET_FOUND", balances: [] };
687
- }
1447
+ styles
688
1448
  }),
689
- [sessionState, remoteConfig, styles, pollarClient, state]
1449
+ [sessionState, remoteConfig, styles, pollarClient, transaction, txHistory, networkState, walletBalance]
690
1450
  );
691
1451
  return /* @__PURE__ */ jsxs(PollarContext.Provider, { value: contextValue, children: [
692
1452
  children,
693
1453
  loginModalOpen && /* @__PURE__ */ jsx(ModalErrorBoundary, { onClose: () => setLoginModalOpen(false), children: /* @__PURE__ */ jsx(LoginModal, { onClose: () => setLoginModalOpen(false) }) }),
694
- transactionModalOpen && /* @__PURE__ */ jsx(ModalErrorBoundary, { onClose: () => setTransactionModalOpen(false), children: /* @__PURE__ */ jsx(TransactionModal, { onClose: () => setTransactionModalOpen(false) }) })
1454
+ transactionModalOpen && /* @__PURE__ */ jsx(ModalErrorBoundary, { onClose: () => setTransactionModalOpen(false), children: /* @__PURE__ */ jsx(TransactionModal, { onClose: () => setTransactionModalOpen(false) }) }),
1455
+ kycModalOpen && /* @__PURE__ */ jsx(ModalErrorBoundary, { onClose: () => setKycModalOpen(false), children: /* @__PURE__ */ jsx(
1456
+ KycModal,
1457
+ {
1458
+ onClose: () => setKycModalOpen(false),
1459
+ ...kycModalOptions.country !== void 0 && { country: kycModalOptions.country },
1460
+ ...kycModalOptions.level !== void 0 && { level: kycModalOptions.level },
1461
+ ...kycModalOptions.onApproved !== void 0 && { onApproved: kycModalOptions.onApproved }
1462
+ }
1463
+ ) }),
1464
+ rampWidgetOpen && /* @__PURE__ */ jsx(ModalErrorBoundary, { onClose: () => setRampWidgetOpen(false), children: /* @__PURE__ */ jsx(RampWidget, { onClose: () => setRampWidgetOpen(false) }) }),
1465
+ txHistoryModalOpen && /* @__PURE__ */ jsx(ModalErrorBoundary, { onClose: () => setTxHistoryModalOpen(false), children: /* @__PURE__ */ jsx(TxHistoryModal, { onClose: () => setTxHistoryModalOpen(false) }) }),
1466
+ walletBalanceModalOpen && /* @__PURE__ */ jsx(ModalErrorBoundary, { onClose: () => setWalletBalanceModalOpen(false), children: /* @__PURE__ */ jsx(WalletBalanceModal, { onClose: () => setWalletBalanceModalOpen(false) }) })
695
1467
  ] });
696
1468
  }
697
1469
  function usePollar() {
@@ -701,50 +1473,37 @@ function usePollar() {
701
1473
  }
702
1474
  return ctx;
703
1475
  }
1476
+ function ButtonLogo() {
1477
+ return /* @__PURE__ */ jsx("img", { src: LOGO_POLLAR, alt: "Pollar", width: 22, height: 22, className: "wallet-btn-logo" });
1478
+ }
704
1479
  function cropWallet(address) {
705
1480
  if (address.length <= 12) return address;
706
1481
  return `${address.slice(0, 6)}...${address.slice(-4)}`;
707
1482
  }
708
- function ButtonLogo() {
709
- return /* @__PURE__ */ jsx("img", { src: LOGO_POLLAR, alt: "Pollar", width: 22, height: 22, className: "wallet-btn-logo" });
710
- }
711
- function WalletButton() {
712
- const { getClient, walletAddress, styles, openLoginModal } = usePollar();
713
- const [open, setOpen] = useState(false);
714
- const [copied, setCopied] = useState(false);
715
- const wrapperRef = useRef(null);
716
- const { theme = "light", accentColor = "#005DB4" } = styles;
717
- const isDark = theme === "dark";
718
- const dropdownBg = isDark ? "#18181b" : "#fff";
719
- const dropdownBorder = isDark ? "#3f3f46" : "#e4e4e7";
720
- const itemColor = isDark ? "#fafafa" : "#18181b";
721
- useEffect(() => {
722
- function handleClickOutside(e) {
723
- if (wrapperRef.current && !wrapperRef.current.contains(e.target)) {
724
- setOpen(false);
725
- }
726
- }
727
- document.addEventListener("mousedown", handleClickOutside);
728
- return () => document.removeEventListener("mousedown", handleClickOutside);
729
- }, []);
730
- async function handleCopy() {
731
- if (!walletAddress) return;
732
- await navigator.clipboard.writeText(walletAddress);
733
- setCopied(true);
734
- setTimeout(() => setCopied(false), 1500);
735
- }
736
- function handleLogout() {
737
- setOpen(false);
738
- getClient().logout();
739
- }
1483
+ function WalletButtonTemplate({
1484
+ walletAddress,
1485
+ accentColor,
1486
+ open,
1487
+ copied,
1488
+ dropdownBg,
1489
+ dropdownBorder,
1490
+ itemColor,
1491
+ wrapperRef,
1492
+ onToggleOpen,
1493
+ onCopy,
1494
+ onWalletBalance,
1495
+ onTxHistory,
1496
+ onLogout,
1497
+ onLogin
1498
+ }) {
740
1499
  if (!walletAddress) {
741
- return /* @__PURE__ */ jsxs("button", { type: "button", className: "wallet-login-btn", style: { backgroundColor: accentColor }, onClick: openLoginModal, children: [
1500
+ return /* @__PURE__ */ jsxs("button", { type: "button", className: "wallet-login-btn", style: { backgroundColor: accentColor }, onClick: onLogin, children: [
742
1501
  /* @__PURE__ */ jsx(ButtonLogo, {}),
743
1502
  "Login with Pollar"
744
1503
  ] });
745
1504
  }
746
1505
  return /* @__PURE__ */ jsxs("div", { className: "wallet-wrapper", ref: wrapperRef, children: [
747
- /* @__PURE__ */ jsxs("button", { className: "wallet-btn", style: { backgroundColor: accentColor }, onClick: () => setOpen((v) => !v), children: [
1506
+ /* @__PURE__ */ jsxs("button", { className: "wallet-btn", style: { backgroundColor: accentColor }, onClick: onToggleOpen, children: [
748
1507
  cropWallet(walletAddress),
749
1508
  /* @__PURE__ */ jsx(
750
1509
  "svg",
@@ -761,7 +1520,7 @@ function WalletButton() {
761
1520
  )
762
1521
  ] }),
763
1522
  open && /* @__PURE__ */ jsxs("div", { className: "wallet-dropdown", style: { backgroundColor: dropdownBg, borderColor: dropdownBorder }, children: [
764
- /* @__PURE__ */ jsxs("button", { className: "wallet-dropdown-item", style: { color: itemColor }, onClick: handleCopy, children: [
1523
+ /* @__PURE__ */ jsxs("button", { className: "wallet-dropdown-item", style: { color: itemColor }, onClick: onCopy, children: [
765
1524
  /* @__PURE__ */ jsxs(
766
1525
  "svg",
767
1526
  {
@@ -781,7 +1540,67 @@ function WalletButton() {
781
1540
  ),
782
1541
  copied ? "Copied!" : "Copy address"
783
1542
  ] }),
784
- /* @__PURE__ */ jsxs("button", { className: "wallet-dropdown-item danger", onClick: handleLogout, children: [
1543
+ /* @__PURE__ */ jsxs(
1544
+ "button",
1545
+ {
1546
+ className: "wallet-dropdown-item",
1547
+ style: { color: itemColor },
1548
+ onClick: onWalletBalance,
1549
+ children: [
1550
+ /* @__PURE__ */ jsxs(
1551
+ "svg",
1552
+ {
1553
+ width: "14",
1554
+ height: "14",
1555
+ viewBox: "0 0 24 24",
1556
+ fill: "none",
1557
+ stroke: "currentColor",
1558
+ strokeWidth: "2",
1559
+ strokeLinecap: "round",
1560
+ strokeLinejoin: "round",
1561
+ children: [
1562
+ /* @__PURE__ */ jsx("rect", { x: "1", y: "4", width: "22", height: "16", rx: "2", ry: "2" }),
1563
+ /* @__PURE__ */ jsx("circle", { cx: "16", cy: "12", r: "2" }),
1564
+ /* @__PURE__ */ jsx("path", { d: "M22 8H12" })
1565
+ ]
1566
+ }
1567
+ ),
1568
+ "Wallet balance"
1569
+ ]
1570
+ }
1571
+ ),
1572
+ /* @__PURE__ */ jsxs(
1573
+ "button",
1574
+ {
1575
+ className: "wallet-dropdown-item",
1576
+ style: { color: itemColor },
1577
+ onClick: onTxHistory,
1578
+ children: [
1579
+ /* @__PURE__ */ jsxs(
1580
+ "svg",
1581
+ {
1582
+ width: "14",
1583
+ height: "14",
1584
+ viewBox: "0 0 24 24",
1585
+ fill: "none",
1586
+ stroke: "currentColor",
1587
+ strokeWidth: "2",
1588
+ strokeLinecap: "round",
1589
+ strokeLinejoin: "round",
1590
+ children: [
1591
+ /* @__PURE__ */ jsx("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" }),
1592
+ /* @__PURE__ */ jsx("polyline", { points: "14,2 14,8 20,8" }),
1593
+ /* @__PURE__ */ jsx("line", { x1: "16", y1: "13", x2: "8", y2: "13" }),
1594
+ /* @__PURE__ */ jsx("line", { x1: "16", y1: "17", x2: "8", y2: "17" }),
1595
+ /* @__PURE__ */ jsx("polyline", { points: "10,9 9,9 8,9" })
1596
+ ]
1597
+ }
1598
+ ),
1599
+ "Transaction history"
1600
+ ]
1601
+ }
1602
+ ),
1603
+ /* @__PURE__ */ jsxs("button", { className: "wallet-dropdown-item danger", onClick: onLogout, children: [
785
1604
  /* @__PURE__ */ jsxs(
786
1605
  "svg",
787
1606
  {
@@ -805,7 +1624,64 @@ function WalletButton() {
805
1624
  ] })
806
1625
  ] });
807
1626
  }
1627
+ function WalletButton() {
1628
+ const { getClient, walletAddress, styles, openLoginModal, openTxHistoryModal, openWalletBalanceModal } = usePollar();
1629
+ const [open, setOpen] = useState(false);
1630
+ const [copied, setCopied] = useState(false);
1631
+ const wrapperRef = useRef(null);
1632
+ const { theme = "light", accentColor = "#005DB4" } = styles;
1633
+ const isDark = theme === "dark";
1634
+ const dropdownBg = isDark ? "#18181b" : "#fff";
1635
+ const dropdownBorder = isDark ? "#3f3f46" : "#e4e4e7";
1636
+ const itemColor = isDark ? "#fafafa" : "#18181b";
1637
+ useEffect(() => {
1638
+ function handleClickOutside(e) {
1639
+ if (wrapperRef.current && !wrapperRef.current.contains(e.target)) {
1640
+ setOpen(false);
1641
+ }
1642
+ }
1643
+ document.addEventListener("mousedown", handleClickOutside);
1644
+ return () => document.removeEventListener("mousedown", handleClickOutside);
1645
+ }, []);
1646
+ async function handleCopy() {
1647
+ if (!walletAddress) return;
1648
+ await navigator.clipboard.writeText(walletAddress);
1649
+ setCopied(true);
1650
+ setTimeout(() => setCopied(false), 1500);
1651
+ }
1652
+ function handleLogout() {
1653
+ setOpen(false);
1654
+ getClient().logout();
1655
+ }
1656
+ function handleWalletBalance() {
1657
+ setOpen(false);
1658
+ openWalletBalanceModal();
1659
+ }
1660
+ function handleTxHistory() {
1661
+ setOpen(false);
1662
+ openTxHistoryModal();
1663
+ }
1664
+ return /* @__PURE__ */ jsx(
1665
+ WalletButtonTemplate,
1666
+ {
1667
+ walletAddress: walletAddress ?? null,
1668
+ accentColor,
1669
+ open,
1670
+ copied,
1671
+ dropdownBg,
1672
+ dropdownBorder,
1673
+ itemColor,
1674
+ wrapperRef,
1675
+ onToggleOpen: () => setOpen((v) => !v),
1676
+ onCopy: handleCopy,
1677
+ onWalletBalance: handleWalletBalance,
1678
+ onTxHistory: handleTxHistory,
1679
+ onLogout: handleLogout,
1680
+ onLogin: openLoginModal
1681
+ }
1682
+ );
1683
+ }
808
1684
 
809
- export { PollarProvider, WalletButton, usePollar };
1685
+ export { KycModal, KycModalTemplate, KycStatus, LoginModalTemplate, PollarProvider, RampWidget, RampWidgetTemplate, RouteDisplay, TransactionModalTemplate, TxHistoryModalTemplate, WalletBalanceModal, WalletBalanceModalTemplate, WalletButton, usePollar };
810
1686
  //# sourceMappingURL=index.mjs.map
811
1687
  //# sourceMappingURL=index.mjs.map