@pollar/react 0.3.9 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -12,6 +12,97 @@ var LOGO_POLLAR = "https://pollar.xyz/assets/logo_pollar.png";
12
12
  var LOGO_GITHUB = "https://pollar.xyz/assets/GitHub_Invertocat_White.png";
13
13
  var LOGO_FREIGHTER = "https://pollar.xyz/assets/logo_freighter.png";
14
14
  var LOGO_ALBEDO = "https://pollar.xyz/assets/logo_albedo.svg";
15
+ var ModalErrorBoundary = class extends react.Component {
16
+ constructor() {
17
+ super(...arguments);
18
+ this.state = { crashed: false };
19
+ }
20
+ static getDerivedStateFromError() {
21
+ return { crashed: true };
22
+ }
23
+ componentDidCatch(error) {
24
+ console.error("[Pollar] Modal crashed:", error);
25
+ }
26
+ render() {
27
+ if (this.state.crashed) {
28
+ this.props.onClose();
29
+ return null;
30
+ }
31
+ return this.props.children;
32
+ }
33
+ };
34
+ var PollarModalFooter = () => {
35
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-footer", children: [
36
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-footer-protected", children: "Protected by" }),
37
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-footer-brand", children: [
38
+ /* @__PURE__ */ jsxRuntime.jsx("img", { src: LOGO_POLLAR, alt: "Pollar", className: "pollar-footer-logo" }),
39
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-footer-name", children: "Pollar" }),
40
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "pollar-footer-version", children: [
41
+ "v",
42
+ "0.4.1"
43
+ ] })
44
+ ] })
45
+ ] });
46
+ };
47
+ var LOGIN_CODE_MESSAGES = {
48
+ NONE: { text: "" },
49
+ LOGOUT: { text: "Logged out" },
50
+ CREATE_SESSION_START: { text: "Starting session\u2026" },
51
+ CREATE_SESSION_ERROR: { text: "Failed to start session" },
52
+ CREATE_SESSION_SUCCESS: { text: "Session ready" },
53
+ EMAIL_AUTH_START: { text: "Sending code\u2026" },
54
+ EMAIL_AUTH_START_ERROR: { text: "Failed to send code" },
55
+ EMAIL_AUTH_START_SUCCESS: { text: "Code sent \u2014 check your inbox" },
56
+ EMAIL_AUTH_CODE_ERROR: { text: "Invalid code \u2014 try again" },
57
+ EMAIL_AUTH_CODE_SUCCESS: { text: "Code verified!" },
58
+ WALLET_AUTH_START: { text: "Connecting wallet\u2026" },
59
+ WALLET_AUTH_FREIGHTER_NOT_INSTALLED: { text: "Freighter is not installed" },
60
+ WALLET_AUTH_ALBEDO_NOT_INSTALLED: { text: "Albedo is not installed" },
61
+ WALLET_AUTH_CONNECTED: { text: "Wallet connected" },
62
+ WALLET_AUTH_LOGIN_START: { text: "Signing in with wallet\u2026" },
63
+ WALLET_AUTH_LOGIN_START_SUCCESS: { text: "Wallet signed in" },
64
+ WALLET_AUTH_LOGIN_START_ERROR: { text: "Failed to sign in with wallet" },
65
+ WALLET_AUTH_ERROR: { text: "Unknow wallet error" },
66
+ STREAM_POLL_START: { text: "Waiting for authentication\u2026" },
67
+ STREAM_POLL_EVENT: { text: "Waiting for authentication\u2026" },
68
+ STREAM_POLL_READY: { text: "Authenticated!" },
69
+ FETCH_SESSION_START: { text: "Loading session\u2026" },
70
+ FETCH_SESSION_SUCCESS: { text: "Welcome back!" },
71
+ FETCH_SESSION_ERROR: { text: "Failed to load session" },
72
+ RESTORED_SESSION_SUCCESS: { text: "Session restored" },
73
+ RESTORED_SESSION_ERROR: { text: "Failed to restore session" },
74
+ SESSION_STORED: { text: "Session saved" },
75
+ ERROR_UNKNOWN: { text: "Something went wrong" },
76
+ ABORTED: { text: "Login cancelled" },
77
+ // transaction
78
+ BUILD_TRANSACTION_START: { text: "Building transaction\u2026" },
79
+ BUILD_TRANSACTION_SUCCESS: { text: "Transaction built, ready to sign and send" },
80
+ BUILD_TRANSACTION_ERROR: { text: "Failed to build transaction" },
81
+ BUILD_TRANSACTION_ERROR_NO_WALLET: { text: "No wallet connected" },
82
+ SIGN_SEND_TRANSACTION_START: { text: "Signing and sending transaction\u2026" },
83
+ SIGN_SEND_TRANSACTION_SUCCESS: { text: "Transaction signed" },
84
+ SIGN_SEND_TRANSACTION_ERROR: { text: "Signing rejected" }
85
+ };
86
+ function ModalStatusBanner({ code, status, onCancel, onRetry }) {
87
+ if (!code) {
88
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-status" });
89
+ }
90
+ const { text } = LOGIN_CODE_MESSAGES[code] || { text: "" };
91
+ const isLoading = status === "LOADING";
92
+ const icon = status === "ERROR" ? /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", "aria-hidden": true, children: [
93
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "7", cy: "7", r: "7", fill: "currentColor" }),
94
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M4.5 4.5l5 5M9.5 4.5l-5 5", stroke: "white", strokeWidth: "1.5", strokeLinecap: "round" })
95
+ ] }) : status === "SUCCESS" ? /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", "aria-hidden": true, children: [
96
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "7", cy: "7", r: "7", fill: "currentColor" }),
97
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M3.5 7l2.5 2.5 4.5-5", stroke: "white", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })
98
+ ] }) : status === "LOADING" ? /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "7", cy: "7", r: "5.5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeDasharray: "22 10" }) }) : null;
99
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-status", "data-kind": status, children: [
100
+ icon,
101
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: text }),
102
+ isLoading && onCancel && /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-status-cancel", onClick: onCancel, children: "Cancel" }),
103
+ status === core.StateStatus.ERROR && onRetry && /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-status-cancel", onClick: onRetry, children: "Retry" })
104
+ ] });
105
+ }
15
106
  function EmailCodeInput({ email, onSubmit }) {
16
107
  const [digits, setDigits] = react.useState(["", "", "", "", "", ""]);
17
108
  const inputRefs = react.useRef([]);
@@ -118,51 +209,6 @@ var GoogleButton = ({ disabled, onClick }) => {
118
209
  ] })
119
210
  ] });
120
211
  };
121
- var LOGIN_CODE_MESSAGES = {
122
- LOGOUT: { text: "Logged out" },
123
- CREATE_SESSION_START: { text: "Starting session\u2026" },
124
- CREATE_SESSION_ERROR: { text: "Failed to start session" },
125
- CREATE_SESSION_SUCCESS: { text: "Session ready" },
126
- EMAIL_AUTH_START: { text: "Sending code\u2026" },
127
- EMAIL_AUTH_START_ERROR: { text: "Failed to send code" },
128
- EMAIL_AUTH_START_SUCCESS: { text: "Code sent \u2014 check your inbox" },
129
- EMAIL_AUTH_CODE_ERROR: { text: "Invalid code \u2014 try again" },
130
- EMAIL_AUTH_CODE_SUCCESS: { text: "Code verified!" },
131
- WALLET_AUTH_START: { text: "Connecting wallet\u2026" },
132
- WALLET_AUTH_FREIGHTER_NOT_INSTALLED: { text: "Freighter is not installed" },
133
- WALLET_AUTH_ALBEDO_NOT_INSTALLED: { text: "Albedo is not installed" },
134
- WALLET_AUTH_CONNECTED: { text: "Wallet connected" },
135
- WALLET_AUTH_LOGIN_START: { text: "Signing in with wallet\u2026" },
136
- WALLET_AUTH_LOGIN_START_SUCCESS: { text: "Wallet signed in" },
137
- WALLET_AUTH_LOGIN_START_ERROR: { text: "Failed to sign in with wallet" },
138
- WALLET_AUTH_ERROR: { text: "Unknow wallet error" },
139
- STREAM_POLL_START: { text: "Waiting for authentication\u2026" },
140
- STREAM_POLL_EVENT: { text: "Waiting for authentication\u2026" },
141
- STREAM_POLL_READY: { text: "Authenticated!" },
142
- FETCH_SESSION_START: { text: "Loading session\u2026" },
143
- FETCH_SESSION_SUCCESS: { text: "Welcome back!" },
144
- FETCH_SESSION_ERROR: { text: "Failed to load session" },
145
- ERROR_UNKNOWN: { text: "Something went wrong" },
146
- ABORTED: { text: "Login cancelled" }
147
- };
148
- function LoginStatusBanner({ code, status, onCancel, onRetry }) {
149
- if (!code) return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-status" });
150
- const { text } = LOGIN_CODE_MESSAGES[code] || { text: "" };
151
- const isLoading = status === core.StateStatus.LOADING;
152
- const icon = status === core.StateStatus.ERROR ? /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", "aria-hidden": true, children: [
153
- /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "7", cy: "7", r: "7", fill: "currentColor" }),
154
- /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M4.5 4.5l5 5M9.5 4.5l-5 5", stroke: "white", strokeWidth: "1.5", strokeLinecap: "round" })
155
- ] }) : status === core.StateStatus.SUCCESS ? /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", "aria-hidden": true, children: [
156
- /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "7", cy: "7", r: "7", fill: "currentColor" }),
157
- /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M3.5 7l2.5 2.5 4.5-5", stroke: "white", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })
158
- ] }) : status === core.StateStatus.LOADING ? /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "7", cy: "7", r: "5.5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeDasharray: "22 10" }) }) : null;
159
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-status", "data-kind": status, children: [
160
- icon,
161
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: text }),
162
- isLoading && onCancel && /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-status-cancel", onClick: onCancel, children: "Cancel" }),
163
- status === core.StateStatus.ERROR && /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-status-cancel", onClick: onRetry, children: "Retry" })
164
- ] });
165
- }
166
212
  function LoginModalTemplate({
167
213
  theme,
168
214
  accentColor,
@@ -245,22 +291,12 @@ function LoginModalTemplate({
245
291
  ] })
246
292
  ] })
247
293
  ] }),
248
- /* @__PURE__ */ jsxRuntime.jsx(LoginStatusBanner, { code: loginStateCode, status, onCancel: () => cancelLoginRef.current?.(), onRetry }),
249
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-footer", children: [
250
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-footer-protected", children: "Protected by" }),
251
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-footer-brand", children: [
252
- /* @__PURE__ */ jsxRuntime.jsx("img", { src: LOGO_POLLAR, alt: "Pollar", className: "pollar-footer-logo" }),
253
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-footer-name", children: "Pollar" }),
254
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "pollar-footer-version", children: [
255
- "v",
256
- "0.3.9"
257
- ] })
258
- ] })
259
- ] })
294
+ /* @__PURE__ */ jsxRuntime.jsx(ModalStatusBanner, { code: loginStateCode, status, onCancel: () => cancelLoginRef.current?.(), onRetry }),
295
+ /* @__PURE__ */ jsxRuntime.jsx(PollarModalFooter, {})
260
296
  ] });
261
297
  }
262
298
  function isLoginCode(code) {
263
- return Object.values(core.STATE_VAR_CODES[core.PollarStateVar.LOGIN]).includes(code);
299
+ return Object.values(core.STATE_VAR_CODES[core.PollarStateVar.AUTHENTICATION]).includes(code);
264
300
  }
265
301
  function LoginModal({ onClose }) {
266
302
  const [email, setEmail] = react.useState("");
@@ -272,20 +308,20 @@ function LoginModal({ onClose }) {
272
308
  const [clientSessionId, setClientSessionId] = react.useState(null);
273
309
  react.useEffect(() => {
274
310
  return getClient().onStateChange((stateEntry) => {
275
- if (stateEntry.var === core.PollarStateVar.LOGIN && isLoginCode(stateEntry.code)) {
311
+ if (stateEntry.var === core.PollarStateVar.AUTHENTICATION && isLoginCode(stateEntry.code)) {
276
312
  setLoginStateCode(stateEntry.code);
277
313
  setStatus(stateEntry.status);
278
- if (stateEntry.code === core.STATE_VAR_CODES[core.PollarStateVar.LOGIN].STREAM_POLL_START) {
314
+ if (stateEntry.code === core.STATE_VAR_CODES[core.PollarStateVar.AUTHENTICATION].STREAM_POLL_START) {
279
315
  const data = stateEntry.data;
280
316
  setClientSessionId(data.clientSessionId);
281
317
  }
282
- if (stateEntry.code === core.STATE_VAR_CODES[core.PollarStateVar.LOGIN].STREAM_POLL_EVENT) {
318
+ if (stateEntry.code === core.STATE_VAR_CODES[core.PollarStateVar.AUTHENTICATION].STREAM_POLL_EVENT) {
283
319
  const data = stateEntry.data;
284
320
  if (data?.status === "AWAITING_EMAIL") {
285
321
  setAwaitingEmailCode(true);
286
322
  }
287
323
  }
288
- if (stateEntry.code === core.STATE_VAR_CODES[core.PollarStateVar.LOGIN].FETCH_SESSION_SUCCESS) {
324
+ if (stateEntry.code === core.STATE_VAR_CODES[core.PollarStateVar.AUTHENTICATION].FETCH_SESSION_SUCCESS) {
289
325
  setAwaitingEmailCode(false);
290
326
  setTimeout(onClose, 1e3);
291
327
  }
@@ -355,6 +391,203 @@ function LoginModal({ onClose }) {
355
391
  }
356
392
  ) });
357
393
  }
394
+ function TransactionModalTemplate({
395
+ theme,
396
+ accentColor,
397
+ transactionStateCode,
398
+ status,
399
+ buildResult,
400
+ submitResult,
401
+ onClose,
402
+ onSignAndSend,
403
+ onRetrySignAndSend
404
+ }) {
405
+ const isDark = theme === "dark";
406
+ const cssVars = {
407
+ "--pollar-accent": accentColor,
408
+ "--pollar-buttons-border-radius": "8px",
409
+ "--pollar-buttons-height": "44px",
410
+ "--pollar-bg": isDark ? "#1a1a1a" : "#ffffff",
411
+ "--pollar-border": isDark ? "#374151" : "#e5e7eb",
412
+ "--pollar-text": isDark ? "#ffffff" : "#111827",
413
+ "--pollar-muted": isDark ? "#9ca3af" : "#6b7280",
414
+ "--pollar-input-bg": isDark ? "#374151" : "rgba(0,0,0,0.04)",
415
+ "--pollar-error-text": isDark ? "#f87171" : "#dc2626",
416
+ "--pollar-success-text": isDark ? "#4ade80" : "#16a34a"
417
+ };
418
+ const [showXdr, setShowXdr] = react.useState(false);
419
+ const [copied, setCopied] = react.useState(false);
420
+ function handleCopyHash() {
421
+ if (!submitResult) return;
422
+ navigator.clipboard.writeText(submitResult.hash).then(() => {
423
+ setCopied(true);
424
+ setTimeout(() => setCopied(false), 2e3);
425
+ });
426
+ }
427
+ const explorerNetwork = buildResult?.summary.network?.toLowerCase().includes("testnet") ? "testnet" : "public";
428
+ const explorerUrl = submitResult ? `https://stellar.expert/explorer/${explorerNetwork}/tx/${submitResult.hash}` : null;
429
+ transactionStateCode.includes("ERROR");
430
+ transactionStateCode.includes("SUCCESS");
431
+ const isBuilt = buildResult && transactionStateCode === "BUILD_TRANSACTION_SUCCESS";
432
+ const isDone = submitResult && transactionStateCode === "SIGN_SEND_TRANSACTION_START";
433
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-tx-modal", "data-theme": theme, style: cssVars, onClick: (e) => e.stopPropagation(), children: [
434
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-tx-header", children: [
435
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "pollar-tx-title", children: "Transaction" }),
436
+ /* @__PURE__ */ jsxRuntime.jsx("button", { className: "pollar-tx-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" }) }) })
437
+ ] }),
438
+ isBuilt && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
439
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-tx-summary", children: [
440
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-tx-summary-title", children: "Details" }),
441
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "pollar-tx-summary-lines", children: buildResult.summary.lines.map((line, i) => /* @__PURE__ */ jsxRuntime.jsx("li", { className: "pollar-tx-summary-line", children: line }, i)) })
442
+ ] }),
443
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-tx-meta", children: [
444
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-tx-meta-item", children: [
445
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-tx-meta-label", children: "Network" }),
446
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-tx-meta-value", children: buildResult.summary.network })
447
+ ] }),
448
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-tx-meta-item", children: [
449
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-tx-meta-label", children: "Fee" }),
450
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-tx-meta-value", children: buildResult.summary.fee })
451
+ ] })
452
+ ] }),
453
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-tx-xdr", children: [
454
+ /* @__PURE__ */ jsxRuntime.jsxs("button", { className: "pollar-tx-xdr-toggle", onClick: () => setShowXdr((v) => !v), children: [
455
+ /* @__PURE__ */ jsxRuntime.jsx(
456
+ "svg",
457
+ {
458
+ width: "12",
459
+ height: "12",
460
+ viewBox: "0 0 12 12",
461
+ fill: "none",
462
+ "aria-hidden": true,
463
+ style: { transform: showXdr ? "rotate(90deg)" : "rotate(0deg)", transition: "transform 150ms" },
464
+ children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M4 2l4 4-4 4", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })
465
+ }
466
+ ),
467
+ "Raw transaction (XDR)"
468
+ ] }),
469
+ showXdr && /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "pollar-tx-xdr-content", children: buildResult.unsignedXdr })
470
+ ] })
471
+ ] }),
472
+ submitResult && transactionStateCode === "SIGN_SEND_TRANSACTION_SUCCESS" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-tx-result", children: [
473
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-tx-result-label", children: "Transaction hash" }),
474
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-tx-result-hash", children: submitResult.hash }),
475
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-tx-result-actions", children: [
476
+ /* @__PURE__ */ jsxRuntime.jsx("button", { className: "pollar-tx-result-btn", onClick: handleCopyHash, children: copied ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
477
+ /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "13", height: "13", viewBox: "0 0 14 14", fill: "none", "aria-hidden": true, children: [
478
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "7", cy: "7", r: "7", fill: "currentColor" }),
479
+ /* @__PURE__ */ jsxRuntime.jsx(
480
+ "path",
481
+ {
482
+ d: "M3.5 7l2.5 2.5 4.5-5",
483
+ stroke: "white",
484
+ strokeWidth: "1.5",
485
+ strokeLinecap: "round",
486
+ strokeLinejoin: "round"
487
+ }
488
+ )
489
+ ] }),
490
+ "Copied!"
491
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
492
+ /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "13", height: "13", viewBox: "0 0 13 13", fill: "none", "aria-hidden": true, children: [
493
+ /* @__PURE__ */ jsxRuntime.jsx("rect", { x: "4", y: "4", width: "8", height: "8", rx: "1.5", stroke: "currentColor", strokeWidth: "1.5" }),
494
+ /* @__PURE__ */ jsxRuntime.jsx(
495
+ "path",
496
+ {
497
+ d: "M3 9H2a1 1 0 01-1-1V2a1 1 0 011-1h6a1 1 0 011 1v1",
498
+ stroke: "currentColor",
499
+ strokeWidth: "1.5",
500
+ strokeLinecap: "round"
501
+ }
502
+ )
503
+ ] }),
504
+ "Copy hash"
505
+ ] }) }),
506
+ explorerUrl && /* @__PURE__ */ jsxRuntime.jsxs("a", { className: "pollar-tx-result-btn", href: explorerUrl, target: "_blank", rel: "noopener noreferrer", children: [
507
+ /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "13", height: "13", viewBox: "0 0 13 13", fill: "none", "aria-hidden": true, children: [
508
+ /* @__PURE__ */ jsxRuntime.jsx(
509
+ "path",
510
+ {
511
+ d: "M5 2H2a1 1 0 00-1 1v8a1 1 0 001 1h8a1 1 0 001-1V8",
512
+ stroke: "currentColor",
513
+ strokeWidth: "1.5",
514
+ strokeLinecap: "round"
515
+ }
516
+ ),
517
+ /* @__PURE__ */ jsxRuntime.jsx(
518
+ "path",
519
+ {
520
+ d: "M8 1h4m0 0v4m0-4L6 7",
521
+ stroke: "currentColor",
522
+ strokeWidth: "1.5",
523
+ strokeLinecap: "round",
524
+ strokeLinejoin: "round"
525
+ }
526
+ )
527
+ ] }),
528
+ "View on Explorer"
529
+ ] })
530
+ ] })
531
+ ] }),
532
+ isBuilt && /* @__PURE__ */ jsxRuntime.jsx("button", { className: "pollar-tx-sign-btn", onClick: onSignAndSend, children: "Sign & Send" }),
533
+ isDone && /* @__PURE__ */ jsxRuntime.jsx("button", { className: "pollar-tx-sign-btn", onClick: onClose, children: "Done" }),
534
+ /* @__PURE__ */ jsxRuntime.jsx(
535
+ ModalStatusBanner,
536
+ {
537
+ code: transactionStateCode,
538
+ status
539
+ }
540
+ ),
541
+ /* @__PURE__ */ jsxRuntime.jsx(PollarModalFooter, {})
542
+ ] });
543
+ }
544
+ var isTxBuildResponseContent = (data) => {
545
+ if (!data || typeof data !== "object") return false;
546
+ const d = data;
547
+ return typeof d.unsignedXdr === "string" && typeof d.networkPassphrase === "string" && typeof d.estimatedFee === "string" && d.summary !== null && typeof d.summary === "object";
548
+ };
549
+ var isTxSignSendResponseContent = (data) => {
550
+ if (!data || typeof data !== "object") return false;
551
+ const d = data;
552
+ return typeof d.hash === "string" && (d.status === "PENDING" || d.status === "SUCCESS" || d.status === "FAILED");
553
+ };
554
+ function TransactionModal({ onClose }) {
555
+ const {
556
+ getClient,
557
+ styles,
558
+ state: { transaction }
559
+ } = usePollar();
560
+ const { theme = "light", accentColor = "#005DB4" } = styles;
561
+ let buildResult = null;
562
+ const transactionStateCode = transaction.code;
563
+ const content = transaction.data?.content;
564
+ if (isTxBuildResponseContent(content)) {
565
+ buildResult = content;
566
+ }
567
+ let submitResult = null;
568
+ if (isTxSignSendResponseContent(content)) {
569
+ submitResult = content;
570
+ }
571
+ async function handleSignAndSend() {
572
+ if (buildResult) {
573
+ await getClient().submitTx(buildResult.unsignedXdr);
574
+ }
575
+ }
576
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-overlay", onClick: onClose, children: /* @__PURE__ */ jsxRuntime.jsx(
577
+ TransactionModalTemplate,
578
+ {
579
+ theme,
580
+ accentColor,
581
+ transactionStateCode,
582
+ status: transaction.status,
583
+ buildResult,
584
+ submitResult,
585
+ onClose,
586
+ onSignAndSend: handleSignAndSend,
587
+ onRetrySignAndSend: handleSignAndSend
588
+ }
589
+ ) });
590
+ }
358
591
  var emptyResponse = {
359
592
  application: {
360
593
  name: ""
@@ -363,7 +596,7 @@ var emptyResponse = {
363
596
  };
364
597
  async function fetchRemoteConfig(api) {
365
598
  try {
366
- const { data, error } = await api.GET(`/config`);
599
+ const { data, error } = await api.GET(`/applications/config`);
367
600
  if (!data || error) {
368
601
  return emptyResponse;
369
602
  }
@@ -378,16 +611,23 @@ function PollarProvider({ config, styles: propStyles, children }) {
378
611
  const [stellarClient] = react.useState(() => new core.StellarClient(config.stellarNetwork || "testnet"));
379
612
  const [sessionState, setSessionState] = react.useState(null);
380
613
  const [state, setState] = react.useState({
381
- [core.PollarStateVar.LOGIN]: {
382
- var: core.PollarStateVar.LOGIN,
383
- code: core.STATE_VAR_CODES[core.PollarStateVar.LOGIN].NONE,
614
+ network: {
615
+ var: "network",
616
+ code: core.STATE_VAR_CODES.network.NONE,
617
+ status: core.StateStatus.NONE,
618
+ level: "info",
619
+ ts: 0
620
+ },
621
+ authentication: {
622
+ var: "authentication",
623
+ code: core.STATE_VAR_CODES.authentication.NONE,
384
624
  status: core.StateStatus.NONE,
385
625
  level: "info",
386
626
  ts: 0
387
627
  },
388
- [core.PollarStateVar.WALLET_ADDRESS]: {
389
- var: core.PollarStateVar.WALLET_ADDRESS,
390
- code: core.STATE_VAR_CODES[core.PollarStateVar.WALLET_ADDRESS].NONE,
628
+ transaction: {
629
+ var: "transaction",
630
+ code: core.STATE_VAR_CODES.transaction.NONE,
391
631
  status: core.StateStatus.NONE,
392
632
  level: "info",
393
633
  ts: 0
@@ -406,8 +646,8 @@ function PollarProvider({ config, styles: propStyles, children }) {
406
646
  }
407
647
  return prevState;
408
648
  });
409
- if (stateEntry.var === core.PollarStateVar.WALLET_ADDRESS) {
410
- if (stateEntry.code === core.STATE_VAR_CODES[core.PollarStateVar.WALLET_ADDRESS].UPDATED_ADDRESS && core.isValidSession(stateEntry.data)) {
649
+ if (stateEntry.var === "authentication") {
650
+ if ((stateEntry.code === core.STATE_VAR_CODES.authentication.SESSION_STORED || core.STATE_VAR_CODES.authentication.RESTORED_SESSION_SUCCESS) && core.isValidSession(stateEntry.data)) {
411
651
  setSessionState((prevState) => {
412
652
  if (JSON.stringify(prevState) !== JSON.stringify(stateEntry.data)) {
413
653
  return stateEntry.data;
@@ -415,9 +655,9 @@ function PollarProvider({ config, styles: propStyles, children }) {
415
655
  return prevState;
416
656
  });
417
657
  }
418
- }
419
- if (stateEntry.var === core.PollarStateVar.WALLET_ADDRESS && stateEntry.code === core.STATE_VAR_CODES[core.PollarStateVar.WALLET_ADDRESS].REMOVED_ADDRESS || stateEntry.var === core.PollarStateVar.LOGIN && stateEntry.code === core.STATE_VAR_CODES[core.PollarStateVar.LOGIN].LOGOUT) {
420
- setSessionState(null);
658
+ if (stateEntry.code === core.STATE_VAR_CODES.authentication.LOGOUT) {
659
+ setSessionState(null);
660
+ }
421
661
  }
422
662
  });
423
663
  }, [pollarClient]);
@@ -433,31 +673,43 @@ function PollarProvider({ config, styles: propStyles, children }) {
433
673
  setStyles(propStyles ?? {});
434
674
  });
435
675
  }, [pollarClient]);
436
- const [modalOpen, setModalOpen] = react.useState(false);
676
+ const [loginModalOpen, setLoginModalOpen] = react.useState(false);
677
+ const [transactionModalOpen, setTransactionModalOpen] = react.useState(false);
437
678
  const contextValue = react.useMemo(
438
679
  () => ({
439
680
  walletAddress: sessionState?.wallet?.publicKey || "",
440
681
  getClient: () => pollarClient,
441
- openLoginModal: () => setModalOpen(true),
442
- isAuthenticated: pollarClient.isAuthenticated(),
682
+ // client
683
+ state,
443
684
  login: (options) => pollarClient.login(options),
444
685
  logout: () => pollarClient.logout(),
686
+ isAuthenticated: pollarClient.isAuthenticated(),
687
+ buildTx: (operation, params, options) => pollarClient.buildTx(operation, params, options),
688
+ submitTx: (signedXdr) => pollarClient.submitTx(signedXdr),
689
+ // react
690
+ sendTransaction: (operation, params, options) => {
691
+ void pollarClient.buildTx(operation, params, options);
692
+ setTransactionModalOpen(true);
693
+ },
694
+ openTransactionModal: () => setTransactionModalOpen(true),
695
+ openLoginModal: () => setLoginModalOpen(true),
445
696
  config: remoteConfig,
446
- state,
447
697
  styles,
698
+ // stellar
448
699
  async getBalance(publicKey) {
449
700
  const pk = publicKey || sessionState?.wallet?.publicKey;
450
701
  if (pk) {
451
- return stellarClient.getBalances(pk);
702
+ return await stellarClient.getBalances(pk);
452
703
  }
453
- return null;
704
+ return { success: false, errorCode: "NO_WALLET_FOUND", balances: [] };
454
705
  }
455
706
  }),
456
707
  [sessionState, remoteConfig, styles, pollarClient, state]
457
708
  );
458
709
  return /* @__PURE__ */ jsxRuntime.jsxs(PollarContext.Provider, { value: contextValue, children: [
459
710
  children,
460
- modalOpen && /* @__PURE__ */ jsxRuntime.jsx(LoginModal, { onClose: () => setModalOpen(false) })
711
+ loginModalOpen && /* @__PURE__ */ jsxRuntime.jsx(ModalErrorBoundary, { onClose: () => setLoginModalOpen(false), children: /* @__PURE__ */ jsxRuntime.jsx(LoginModal, { onClose: () => setLoginModalOpen(false) }) }),
712
+ transactionModalOpen && /* @__PURE__ */ jsxRuntime.jsx(ModalErrorBoundary, { onClose: () => setTransactionModalOpen(false), children: /* @__PURE__ */ jsxRuntime.jsx(TransactionModal, { onClose: () => setTransactionModalOpen(false) }) })
461
713
  ] });
462
714
  }
463
715
  function usePollar() {