@microcosmmoney/portal-react 2.3.4 → 3.1.0

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.
Files changed (35) hide show
  1. package/dist/components/auction/auction-page.js +118 -25
  2. package/dist/components/dashboard/assets-summary.d.ts +2 -1
  3. package/dist/components/dashboard/assets-summary.js +11 -6
  4. package/dist/components/dashboard/dashboard-overview.d.ts +2 -1
  5. package/dist/components/dashboard/dashboard-overview.js +11 -2
  6. package/dist/components/dashboard/ecosystem-stats.d.ts +4 -1
  7. package/dist/components/dashboard/ecosystem-stats.js +12 -9
  8. package/dist/components/dashboard/lock-periods.d.ts +4 -1
  9. package/dist/components/dashboard/lock-periods.js +2 -2
  10. package/dist/components/dashboard/market-overview-bar.d.ts +4 -1
  11. package/dist/components/dashboard/market-overview-bar.js +9 -6
  12. package/dist/components/dashboard/mcc-token-stats.d.ts +4 -1
  13. package/dist/components/dashboard/mcc-token-stats.js +12 -9
  14. package/dist/components/dashboard/mcd-stats.d.ts +4 -1
  15. package/dist/components/dashboard/mcd-stats.js +14 -11
  16. package/dist/components/dashboard/mining-weight.d.ts +4 -1
  17. package/dist/components/dashboard/mining-weight.js +10 -7
  18. package/dist/components/dashboard/minting-stats.d.ts +4 -1
  19. package/dist/components/dashboard/minting-stats.js +6 -3
  20. package/dist/components/dashboard/my-mining.d.ts +2 -1
  21. package/dist/components/dashboard/my-mining.js +4 -2
  22. package/dist/components/dashboard/price-chart.d.ts +4 -1
  23. package/dist/components/dashboard/price-chart.js +6 -4
  24. package/dist/components/dashboard/quick-actions.d.ts +2 -1
  25. package/dist/components/dashboard/quick-actions.js +52 -37
  26. package/dist/components/fragment/fragment-page.js +53 -9
  27. package/dist/components/lending/lending-page.js +124 -22
  28. package/dist/components/mcd/mcd-page.js +139 -18
  29. package/dist/components/mining/mining-page.js +46 -15
  30. package/dist/components/organization/organization-page.js +90 -22
  31. package/dist/components/territory/territory-page.js +126 -29
  32. package/dist/components/voting/voting-page.js +10 -10
  33. package/dist/components/wallet/wallet-page.js +186 -23
  34. package/dist/index.d.ts +8 -0
  35. package/package.json +4 -4
@@ -6,16 +6,40 @@ exports.MicrocosmFragmentPage = MicrocosmFragmentPage;
6
6
  const jsx_runtime_1 = require("react/jsx-runtime");
7
7
  const react_1 = require("react");
8
8
  const auth_react_1 = require("@microcosmmoney/auth-react");
9
- const fmt = (num, decimals = 2) => num.toLocaleString('en-US', { minimumFractionDigits: decimals, maximumFractionDigits: decimals });
10
- const fmtMCC = (lamports) => fmt(lamports / 1000000000, 2);
11
- function Spinner() {
12
- return (0, jsx_runtime_1.jsx)("span", { className: "inline-block w-5 h-5 border-2 border-cyan-400 border-t-transparent rounded-full animate-spin" });
9
+ const formatNumber = (num, decimals = 2) => num.toLocaleString('en-US', { minimumFractionDigits: decimals, maximumFractionDigits: decimals });
10
+ const formatMCC = (lamports) => formatNumber(lamports / 1000000000, 2);
11
+ /* ── Inline SVG Icons (lucide style) ── */
12
+ function IconRefreshCw({ className }) {
13
+ return ((0, jsx_runtime_1.jsxs)("svg", { className: className, fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", viewBox: "0 0 24 24", children: [(0, jsx_runtime_1.jsx)("path", { d: "M21 2v6h-6" }), (0, jsx_runtime_1.jsx)("path", { d: "M3 12a9 9 0 0115.15-6.64L21 8" }), (0, jsx_runtime_1.jsx)("path", { d: "M3 22v-6h6" }), (0, jsx_runtime_1.jsx)("path", { d: "M21 12a9 9 0 01-15.15 6.64L3 16" })] }));
13
14
  }
15
+ function IconWallet({ className }) {
16
+ return ((0, jsx_runtime_1.jsxs)("svg", { className: className, fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", viewBox: "0 0 24 24", children: [(0, jsx_runtime_1.jsx)("path", { d: "M19 7V4a1 1 0 00-1-1H5a2 2 0 000 4h15a1 1 0 011 1v4h-3a2 2 0 000 4h3a1 1 0 001-1v-2a1 1 0 00-1-1" }), (0, jsx_runtime_1.jsx)("path", { d: "M3 5v14a2 2 0 002 2h15a1 1 0 001-1v-4" })] }));
17
+ }
18
+ function IconPuzzle({ className }) {
19
+ return ((0, jsx_runtime_1.jsx)("svg", { className: className, fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", viewBox: "0 0 24 24", children: (0, jsx_runtime_1.jsx)("path", { d: "M11 4a2 2 0 114 0v1a1 1 0 001 1h3a1 1 0 011 1v3a1 1 0 01-1 1h-1a2 2 0 100 4h1a1 1 0 011 1v3a1 1 0 01-1 1h-3a1 1 0 01-1-1v-1a2 2 0 10-4 0v1a1 1 0 01-1 1H7a1 1 0 01-1-1v-3a1 1 0 00-1-1H4a2 2 0 110-4h1a1 1 0 001-1V7a1 1 0 011-1h3a1 1 0 001-1V4z" }) }));
20
+ }
21
+ function IconImage({ className }) {
22
+ return ((0, jsx_runtime_1.jsxs)("svg", { className: className, fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", viewBox: "0 0 24 24", children: [(0, jsx_runtime_1.jsx)("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2", ry: "2" }), (0, jsx_runtime_1.jsx)("circle", { cx: "8.5", cy: "8.5", r: "1.5" }), (0, jsx_runtime_1.jsx)("path", { d: "M21 15l-5-5L5 21" })] }));
23
+ }
24
+ function IconShoppingCart({ className }) {
25
+ return ((0, jsx_runtime_1.jsxs)("svg", { className: className, fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", viewBox: "0 0 24 24", children: [(0, jsx_runtime_1.jsx)("circle", { cx: "9", cy: "21", r: "1" }), (0, jsx_runtime_1.jsx)("circle", { cx: "20", cy: "21", r: "1" }), (0, jsx_runtime_1.jsx)("path", { d: "M1 1h4l2.68 13.39a2 2 0 002 1.61h9.72a2 2 0 002-1.61L23 6H6" })] }));
26
+ }
27
+ function IconInfo({ className }) {
28
+ return ((0, jsx_runtime_1.jsxs)("svg", { className: className, fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", viewBox: "0 0 24 24", children: [(0, jsx_runtime_1.jsx)("circle", { cx: "12", cy: "12", r: "10" }), (0, jsx_runtime_1.jsx)("path", { d: "M12 16v-4" }), (0, jsx_runtime_1.jsx)("path", { d: "M12 8h.01" })] }));
29
+ }
30
+ function IconAlertTriangle({ className }) {
31
+ return ((0, jsx_runtime_1.jsxs)("svg", { className: className, fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", viewBox: "0 0 24 24", children: [(0, jsx_runtime_1.jsx)("path", { d: "M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z" }), (0, jsx_runtime_1.jsx)("path", { d: "M12 9v4" }), (0, jsx_runtime_1.jsx)("path", { d: "M12 17h.01" })] }));
32
+ }
33
+ function IconLoader({ className }) {
34
+ return ((0, jsx_runtime_1.jsxs)("svg", { className: className, fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", viewBox: "0 0 24 24", children: [(0, jsx_runtime_1.jsx)("path", { d: "M12 2v4" }), (0, jsx_runtime_1.jsx)("path", { d: "M12 18v4" }), (0, jsx_runtime_1.jsx)("path", { d: "M4.93 4.93l2.83 2.83" }), (0, jsx_runtime_1.jsx)("path", { d: "M16.24 16.24l2.83 2.83" }), (0, jsx_runtime_1.jsx)("path", { d: "M2 12h4" }), (0, jsx_runtime_1.jsx)("path", { d: "M18 12h4" }), (0, jsx_runtime_1.jsx)("path", { d: "M4.93 19.07l2.83-2.83" }), (0, jsx_runtime_1.jsx)("path", { d: "M16.24 7.76l2.83-2.83" })] }));
35
+ }
36
+ /* ── Modal ── */
14
37
  function Modal({ open, onClose, children }) {
15
38
  if (!open)
16
39
  return null;
17
40
  return ((0, jsx_runtime_1.jsxs)("div", { className: "fixed inset-0 z-50 flex items-center justify-center", onClick: onClose, children: [(0, jsx_runtime_1.jsx)("div", { className: "absolute inset-0 bg-black/60" }), (0, jsx_runtime_1.jsx)("div", { className: "relative bg-neutral-900 border border-neutral-700 rounded-lg p-6 max-w-md w-full mx-4 font-mono", onClick: e => e.stopPropagation(), children: children })] }));
18
41
  }
42
+ /* ── Main Component ── */
19
43
  function MicrocosmFragmentPage({ onNavigate }) {
20
44
  const { data: wallets } = (0, auth_react_1.useWallets)();
21
45
  const primaryWallet = wallets?.[0]?.wallet_address;
@@ -28,15 +52,23 @@ function MicrocosmFragmentPage({ onNavigate }) {
28
52
  const [refreshing, setRefreshing] = (0, react_1.useState)(false);
29
53
  const [actionError, setActionError] = (0, react_1.useState)(null);
30
54
  const [actionSuccess, setActionSuccess] = (0, react_1.useState)(null);
55
+ const [initialLoaded, setInitialLoaded] = (0, react_1.useState)(false);
31
56
  const loading = vLoading || hLoading;
57
+ (0, react_1.useEffect)(() => {
58
+ if (!loading && !initialLoaded) {
59
+ setInitialLoaded(true);
60
+ }
61
+ }, [loading, initialLoaded]);
32
62
  const handleRefresh = (0, react_1.useCallback)(async () => {
33
63
  setRefreshing(true);
34
64
  await Promise.all([refreshVaults(), refreshHoldings()]);
35
65
  setRefreshing(false);
36
66
  }, [refreshVaults, refreshHoldings]);
37
67
  const handleBuy = async () => {
38
- if (!selectedVault)
68
+ if (!selectedVault) {
69
+ setActionError('Please select a vault');
39
70
  return;
71
+ }
40
72
  const amount = parseInt(buyAmount);
41
73
  if (isNaN(amount) || amount <= 0) {
42
74
  setActionError('Please enter a valid amount');
@@ -55,8 +87,20 @@ function MicrocosmFragmentPage({ onNavigate }) {
55
87
  setActionError(err instanceof Error ? err.message : 'Purchase failed');
56
88
  }
57
89
  };
58
- return ((0, jsx_runtime_1.jsxs)("div", { className: "max-w-7xl mx-auto font-mono space-y-6", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h1", { className: "text-2xl font-bold text-white", children: "Fragment" }), (0, jsx_runtime_1.jsx)("p", { className: "text-neutral-400 text-sm mt-1", children: "NFT fractionalization protocol" })] }), (0, jsx_runtime_1.jsxs)("button", { onClick: handleRefresh, disabled: refreshing, className: "flex items-center gap-2 px-3 py-1.5 text-sm border border-neutral-700 rounded text-neutral-400 hover:bg-neutral-800 hover:text-neutral-300 disabled:opacity-50 bg-transparent", children: [(0, jsx_runtime_1.jsx)("svg", { className: `w-4 h-4 ${refreshing ? 'animate-spin' : ''}`, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: (0, jsx_runtime_1.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" }) }), "Refresh"] })] }), actionError && ((0, jsx_runtime_1.jsx)("div", { className: "p-3 bg-red-500/10 border border-red-500/30 rounded text-red-400 text-sm", children: actionError })), actionSuccess && ((0, jsx_runtime_1.jsx)("div", { className: "p-3 bg-cyan-400/10 border border-cyan-400/30 rounded text-cyan-400 text-sm", children: actionSuccess })), (0, jsx_runtime_1.jsx)("div", { className: "bg-neutral-900 border border-neutral-700 rounded-lg hover:border-cyan-400/50 transition-colors", children: (0, jsx_runtime_1.jsxs)("div", { className: "p-6", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2 text-neutral-400 text-sm mb-4", children: [(0, jsx_runtime_1.jsx)("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: (0, jsx_runtime_1.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, 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" }) }), (0, jsx_runtime_1.jsx)("span", { children: "MY_HOLDINGS" })] }), loading ? ((0, jsx_runtime_1.jsx)("div", { className: "flex items-center justify-center py-8", children: (0, jsx_runtime_1.jsx)(Spinner, {}) })) : holdings && holdings.length > 0 ? ((0, jsx_runtime_1.jsx)("div", { className: "space-y-3", children: holdings.map((h, i) => ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between p-4 bg-neutral-800 rounded border border-neutral-700", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-3", children: [(0, jsx_runtime_1.jsx)("div", { className: "p-2 bg-cyan-400/20 rounded border border-cyan-400/30", children: (0, jsx_runtime_1.jsx)("svg", { className: "h-5 w-5 text-cyan-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: (0, jsx_runtime_1.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M11 4a2 2 0 114 0v1a1 1 0 001 1h3a1 1 0 011 1v3a1 1 0 01-1 1h-1a2 2 0 100 4h1a1 1 0 011 1v3a1 1 0 01-1 1h-3a1 1 0 01-1-1v-1a2 2 0 10-4 0v1a1 1 0 01-1 1H7a1 1 0 01-1-1v-3a1 1 0 00-1-1H4a2 2 0 110-4h1a1 1 0 001-1V7a1 1 0 011-1h3a1 1 0 001-1V4z" }) }) }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsxs)("div", { className: "font-bold text-white font-mono", children: ["Vault #", h.vault_id] }), (0, jsx_runtime_1.jsxs)("div", { className: "text-xs text-neutral-400", children: [(h.percentage ?? 0).toFixed(2), "% ownership"] })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "text-right", children: [(0, jsx_runtime_1.jsx)("div", { className: "text-lg font-bold text-white font-mono", children: fmt(h.fragment_amount ?? 0, 0) }), (0, jsx_runtime_1.jsx)("div", { className: "text-xs text-neutral-400", children: "fragments" })] })] }, i))) })) : ((0, jsx_runtime_1.jsx)("div", { className: "text-center py-8 text-neutral-500 font-mono text-sm", children: "no fragment holdings" }))] }) }), (0, jsx_runtime_1.jsx)("div", { className: "bg-neutral-900 border border-neutral-700 rounded-lg hover:border-cyan-400/50 transition-colors", children: (0, jsx_runtime_1.jsxs)("div", { className: "p-6", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2 text-neutral-400 text-sm mb-4", children: [(0, jsx_runtime_1.jsx)("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: (0, jsx_runtime_1.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" }) }), (0, jsx_runtime_1.jsx)("span", { children: "FRAGMENT_VAULTS" })] }), loading ? ((0, jsx_runtime_1.jsx)("div", { className: "flex items-center justify-center py-8", children: (0, jsx_runtime_1.jsx)(Spinner, {}) })) : vaults && vaults.length > 0 ? ((0, jsx_runtime_1.jsx)("div", { className: "space-y-4", children: vaults.map((v) => {
59
- const soldPct = v.total_fragments > 0 ? (v.fragments_sold / v.total_fragments) * 100 : 0;
60
- return ((0, jsx_runtime_1.jsxs)("div", { className: "p-4 bg-neutral-800 rounded border border-neutral-700", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex justify-between items-start mb-4", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-3", children: [(0, jsx_runtime_1.jsx)("div", { className: "p-2 bg-cyan-400/20 rounded border border-cyan-400/30", children: (0, jsx_runtime_1.jsx)("svg", { className: "h-6 w-6 text-cyan-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: (0, jsx_runtime_1.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" }) }) }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsxs)("div", { className: "font-bold text-white", children: [v.nft_type ?? 'Territory', " NFT"] }), (0, jsx_runtime_1.jsxs)("div", { className: "text-xs text-neutral-400", children: [(v.nft_mint ?? '').slice(0, 8), "...", (v.nft_mint ?? '').slice(-4)] })] })] }), (0, jsx_runtime_1.jsx)("span", { className: `px-2 py-0.5 rounded text-xs ${v.is_active ? 'bg-white/20 text-white' : 'bg-neutral-700/50 text-neutral-400'}`, children: v.is_active ? 'OPEN' : 'CLOSED' })] }), (0, jsx_runtime_1.jsxs)("div", { className: "grid grid-cols-2 md:grid-cols-4 gap-4 mb-4", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("div", { className: "text-xs text-neutral-400 tracking-wider", children: "total_fragments" }), (0, jsx_runtime_1.jsx)("div", { className: "text-lg font-bold text-white font-mono", children: fmt(v.total_fragments ?? 0, 0) })] }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("div", { className: "text-xs text-neutral-400 tracking-wider", children: "price_per_fragment" }), (0, jsx_runtime_1.jsxs)("div", { className: "text-lg font-bold text-cyan-400 font-mono", children: [fmtMCC(v.price_per_fragment ?? 0), " MCC"] })] }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("div", { className: "text-xs text-neutral-400 tracking-wider", children: "sold" }), (0, jsx_runtime_1.jsx)("div", { className: "text-lg font-bold text-cyan-300 font-mono", children: fmt(v.fragments_sold ?? 0, 0) })] }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("div", { className: "text-xs text-neutral-400 tracking-wider", children: "available" }), (0, jsx_runtime_1.jsx)("div", { className: "text-lg font-bold text-white font-mono", children: fmt((v.total_fragments ?? 0) - (v.fragments_sold ?? 0), 0) })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "mb-4", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex justify-between items-center mb-2", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-xs text-neutral-400 tracking-wider", children: "sale_progress" }), (0, jsx_runtime_1.jsxs)("span", { className: "text-sm font-mono text-white", children: [soldPct.toFixed(1), "%"] })] }), (0, jsx_runtime_1.jsx)("div", { className: "w-full bg-neutral-700 rounded-full h-2", children: (0, jsx_runtime_1.jsx)("div", { className: "bg-cyan-400 h-2 rounded-full transition-all", style: { width: `${Math.min(soldPct, 100)}%` } }) })] }), v.is_active && (v.fragments_sold ?? 0) < (v.total_fragments ?? 0) && ((0, jsx_runtime_1.jsx)("div", { className: "flex justify-end", children: (0, jsx_runtime_1.jsx)("button", { onClick: () => { setSelectedVault(v); setBuyDialogOpen(true); setActionError(null); }, className: "px-4 py-2 text-sm bg-cyan-700 hover:bg-cyan-600 text-white rounded font-mono", children: "Buy Fragments" }) }))] }, v.vault_id));
61
- }) })) : ((0, jsx_runtime_1.jsx)("div", { className: "text-center py-8 text-neutral-500 font-mono text-sm", children: "no fragment vaults available" }))] }) }), (0, jsx_runtime_1.jsx)("div", { className: "bg-neutral-900 border border-neutral-700 rounded-lg hover:border-cyan-400/50 transition-colors", children: (0, jsx_runtime_1.jsxs)("div", { className: "p-6", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2 text-neutral-400 text-sm mb-4", children: [(0, jsx_runtime_1.jsx)("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: (0, jsx_runtime_1.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" }) }), (0, jsx_runtime_1.jsx)("span", { children: "PROTOCOL_INFO" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "space-y-4 text-sm", children: [(0, jsx_runtime_1.jsxs)("div", { className: "p-4 bg-neutral-800 rounded border border-neutral-700", children: [(0, jsx_runtime_1.jsx)("div", { className: "font-medium text-white mb-2", children: "What is Fragmentation?" }), (0, jsx_runtime_1.jsx)("p", { className: "text-neutral-400", children: "Fragment allows NFT owners to split Territory NFTs into tradeable fragments, enabling shared ownership and community buyout mechanics." })] }), (0, jsx_runtime_1.jsxs)("div", { className: "p-4 bg-neutral-800 rounded border border-neutral-700", children: [(0, jsx_runtime_1.jsx)("div", { className: "font-medium text-white mb-2", children: "Fragment Holder Rights" }), (0, jsx_runtime_1.jsxs)("ul", { className: "list-disc list-inside space-y-1 text-neutral-400", children: [(0, jsx_runtime_1.jsx)("li", { children: "Proportional ownership of the underlying NFT" }), (0, jsx_runtime_1.jsx)("li", { children: "Participate in buyout proposals" }), (0, jsx_runtime_1.jsx)("li", { children: "Trade fragments freely on the market" })] })] })] })] }) }), (0, jsx_runtime_1.jsx)(Modal, { open: buyDialogOpen, onClose: () => setBuyDialogOpen(false), children: (0, jsx_runtime_1.jsxs)("div", { className: "space-y-4", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-lg font-bold text-white", children: "Buy Fragments" }), (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-neutral-400 mt-1", children: selectedVault ? `Purchase fragments from ${selectedVault.nft_type ?? 'Territory'} NFT vault` : 'Select a vault' })] }), selectedVault && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("div", { className: "p-4 bg-neutral-800 rounded border border-neutral-700", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex justify-between items-center mb-2", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-neutral-400", children: "Unit Price" }), (0, jsx_runtime_1.jsxs)("span", { className: "text-cyan-400 font-bold font-mono", children: [fmtMCC(selectedVault.price_per_fragment ?? 0), " MCC"] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex justify-between items-center", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-neutral-400", children: "Available" }), (0, jsx_runtime_1.jsx)("span", { className: "text-white font-bold font-mono", children: fmt((selectedVault.total_fragments ?? 0) - (selectedVault.fragments_sold ?? 0), 0) })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "space-y-2", children: [(0, jsx_runtime_1.jsx)("label", { className: "text-xs text-neutral-400 tracking-wider", children: "purchase_amount" }), (0, jsx_runtime_1.jsx)("input", { type: "number", step: "1", min: "1", value: buyAmount, onChange: e => setBuyAmount(e.target.value), placeholder: "Enter amount", className: "w-full px-3 py-2 bg-neutral-800 border border-neutral-600 rounded text-white placeholder-neutral-400 outline-none focus:border-cyan-400" })] }), buyAmount && parseInt(buyAmount) > 0 && ((0, jsx_runtime_1.jsx)("div", { className: "p-4 bg-neutral-800 rounded border border-neutral-700", children: (0, jsx_runtime_1.jsxs)("div", { className: "flex justify-between items-center", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-neutral-400", children: "Total Price" }), (0, jsx_runtime_1.jsxs)("span", { className: "text-white font-bold font-mono", children: [fmtMCC((selectedVault.price_per_fragment ?? 0) * parseInt(buyAmount)), " MCC"] })] }) }))] })), (0, jsx_runtime_1.jsxs)("div", { className: "flex justify-end gap-3 pt-2", children: [(0, jsx_runtime_1.jsx)("button", { onClick: () => { setBuyDialogOpen(false); setBuyAmount(''); }, className: "px-4 py-2 text-sm border border-neutral-700 rounded text-neutral-400 hover:bg-neutral-800 bg-transparent", children: "Cancel" }), (0, jsx_runtime_1.jsx)("button", { onClick: handleBuy, disabled: actionLoading || !buyAmount, className: "px-4 py-2 text-sm bg-cyan-700 hover:bg-cyan-600 text-white rounded disabled:opacity-50", children: actionLoading ? 'Processing...' : 'Confirm Purchase' })] })] }) })] }));
90
+ /* ── Loading state (matches portal full-page spinner) ── */
91
+ if (!initialLoaded && loading) {
92
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "max-w-7xl mx-auto font-mono space-y-6", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h1", { className: "text-2xl font-bold text-white", children: "Fragment" }), (0, jsx_runtime_1.jsx)("p", { className: "text-neutral-400 text-sm mt-1", children: "NFT fractionalization protocol" })] }), (0, jsx_runtime_1.jsx)("div", { className: "flex items-center justify-center py-8", children: (0, jsx_runtime_1.jsx)(IconLoader, { className: "w-5 h-5 animate-spin text-cyan-400" }) })] }));
93
+ }
94
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "max-w-7xl mx-auto font-mono space-y-6", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h1", { className: "text-2xl font-bold text-white", children: "Fragment" }), (0, jsx_runtime_1.jsx)("p", { className: "text-neutral-400 text-sm mt-1", children: "NFT fractionalization protocol" })] }), (0, jsx_runtime_1.jsxs)("button", { onClick: handleRefresh, disabled: refreshing, className: "flex items-center gap-1 px-3 py-1.5 text-sm border border-neutral-700 rounded text-neutral-400 hover:bg-neutral-800 hover:text-neutral-300 disabled:opacity-50 bg-transparent", children: [(0, jsx_runtime_1.jsx)(IconRefreshCw, { className: `w-4 h-4 ${refreshing ? 'animate-spin' : ''}` }), "Refresh"] })] }), actionError && ((0, jsx_runtime_1.jsxs)("div", { className: "bg-red-500/10 border border-red-500/20 rounded-lg p-6", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2 text-red-500 mb-2", children: [(0, jsx_runtime_1.jsx)(IconAlertTriangle, { className: "w-5 h-5" }), (0, jsx_runtime_1.jsx)("span", { className: "font-medium", children: actionError })] }), (0, jsx_runtime_1.jsx)("p", { className: "text-neutral-400 text-sm", children: "Please check the details and try again." })] })), actionSuccess && ((0, jsx_runtime_1.jsx)("div", { className: "p-3 bg-cyan-400/10 border border-cyan-400/30 rounded text-cyan-400 text-sm", children: actionSuccess })), (0, jsx_runtime_1.jsx)("div", { className: "bg-neutral-900 border border-neutral-700 rounded-lg hover:border-cyan-400/50 transition-colors", children: (0, jsx_runtime_1.jsxs)("div", { className: "p-6", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2 text-neutral-400 text-sm mb-4", children: [(0, jsx_runtime_1.jsx)(IconWallet, { className: "w-4 h-4" }), (0, jsx_runtime_1.jsx)("span", { children: "MY_HOLDINGS" })] }), holdings && holdings.length > 0 ? ((0, jsx_runtime_1.jsx)("div", { className: "space-y-3", children: holdings.map((h, i) => ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between p-4 bg-neutral-800 rounded border border-neutral-700", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-3", children: [(0, jsx_runtime_1.jsx)("div", { className: "p-2 bg-cyan-400/20 rounded border border-cyan-400/30", children: (0, jsx_runtime_1.jsx)(IconPuzzle, { className: "h-5 w-5 text-cyan-400" }) }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsxs)("div", { className: "font-bold text-white font-mono", children: ["Vault #", h.vault_id] }), (0, jsx_runtime_1.jsxs)("div", { className: "text-xs text-neutral-400", children: [(h.percentage ?? 0).toFixed(2), "% ownership"] })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "text-right", children: [(0, jsx_runtime_1.jsx)("div", { className: "text-lg font-bold text-white font-mono", children: formatNumber(h.fragment_amount ?? 0, 0) }), (0, jsx_runtime_1.jsx)("div", { className: "text-xs text-neutral-400", children: "fragments" })] })] }, `${h.vault_id}-${h.wallet ?? i}`))) })) : ((0, jsx_runtime_1.jsxs)("div", { className: "text-center py-8 text-neutral-400", children: [(0, jsx_runtime_1.jsx)(IconPuzzle, { className: "w-12 h-12 mx-auto mb-2 opacity-50" }), (0, jsx_runtime_1.jsx)("p", { children: "No fragment holdings" }), (0, jsx_runtime_1.jsx)("p", { className: "text-sm mt-1", children: "Purchase fragments from available vaults below" })] }))] }) }), (0, jsx_runtime_1.jsx)("div", { className: "bg-neutral-900 border border-neutral-700 rounded-lg hover:border-cyan-400/50 transition-colors", children: (0, jsx_runtime_1.jsxs)("div", { className: "p-6", children: [(0, jsx_runtime_1.jsx)("div", { className: "flex items-center justify-between mb-4", children: (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2 text-neutral-400 text-sm", children: [(0, jsx_runtime_1.jsx)(IconImage, { className: "w-4 h-4" }), (0, jsx_runtime_1.jsx)("span", { children: "FRAGMENT_VAULTS" })] }) }), vaults && vaults.length > 0 ? ((0, jsx_runtime_1.jsx)("div", { className: "space-y-4", children: vaults.map((v) => {
95
+ const soldPercentage = v.total_fragments > 0
96
+ ? (v.fragments_sold / v.total_fragments) * 100
97
+ : 0;
98
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "p-4 bg-neutral-800 rounded border border-neutral-700", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex justify-between items-start mb-4", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-3", children: [(0, jsx_runtime_1.jsx)("div", { className: "p-2 bg-cyan-400/20 rounded border border-cyan-400/30", children: (0, jsx_runtime_1.jsx)(IconImage, { className: "h-6 w-6 text-cyan-400" }) }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsxs)("div", { className: "font-bold text-white", children: [v.nft_type ?? 'Territory', " NFT"] }), (0, jsx_runtime_1.jsxs)("div", { className: "text-xs text-neutral-400", children: [(v.nft_mint ?? '').slice(0, 8), "...", (v.nft_mint ?? '').slice(-4)] })] })] }), (0, jsx_runtime_1.jsx)("span", { className: `px-2 py-0.5 rounded text-xs ${v.is_active ? 'bg-white/20 text-white' : 'bg-neutral-700/50 text-neutral-400'}`, children: v.is_active ? 'OPEN' : 'CLOSED' })] }), (0, jsx_runtime_1.jsxs)("div", { className: "grid grid-cols-2 md:grid-cols-4 gap-4 mb-4", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("div", { className: "text-xs text-neutral-400 tracking-wider", children: "total_fragments" }), (0, jsx_runtime_1.jsx)("div", { className: "text-lg font-bold text-white font-mono", children: formatNumber(v.total_fragments ?? 0, 0) })] }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("div", { className: "text-xs text-neutral-400 tracking-wider", children: "price_per_fragment" }), (0, jsx_runtime_1.jsxs)("div", { className: "text-lg font-bold text-cyan-400 font-mono", children: [formatMCC(v.price_per_fragment ?? 0), " MCC"] })] }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("div", { className: "text-xs text-neutral-400 tracking-wider", children: "sold" }), (0, jsx_runtime_1.jsx)("div", { className: "text-lg font-bold text-cyan-300 font-mono", children: formatNumber(v.fragments_sold ?? 0, 0) })] }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("div", { className: "text-xs text-neutral-400 tracking-wider", children: "available" }), (0, jsx_runtime_1.jsx)("div", { className: "text-lg font-bold text-white font-mono", children: formatNumber((v.total_fragments ?? 0) - (v.fragments_sold ?? 0), 0) })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "mb-4", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex justify-between items-center mb-2", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-xs text-neutral-400 tracking-wider", children: "sale_progress" }), (0, jsx_runtime_1.jsxs)("span", { className: "text-sm font-mono text-white", children: [soldPercentage.toFixed(1), "%"] })] }), (0, jsx_runtime_1.jsx)("div", { className: "w-full bg-neutral-800 rounded-full h-2", children: (0, jsx_runtime_1.jsx)("div", { className: "bg-cyan-400 h-2 rounded-full transition-all", style: { width: `${Math.min(soldPercentage, 100)}%` } }) })] }), v.is_active && (v.fragments_sold ?? 0) < (v.total_fragments ?? 0) && ((0, jsx_runtime_1.jsx)("div", { className: "flex justify-end", children: (0, jsx_runtime_1.jsxs)("button", { onClick: () => {
99
+ setSelectedVault(v);
100
+ setBuyDialogOpen(true);
101
+ setActionError(null);
102
+ }, className: "flex items-center gap-1 px-4 py-2 text-sm bg-cyan-700 hover:bg-cyan-600 text-white rounded font-mono", children: [(0, jsx_runtime_1.jsx)(IconShoppingCart, { className: "w-4 h-4" }), "Buy Fragments"] }) }))] }, v.vault_id));
103
+ }) })) : ((0, jsx_runtime_1.jsxs)("div", { className: "text-center py-8 text-neutral-400", children: [(0, jsx_runtime_1.jsx)(IconImage, { className: "w-12 h-12 mx-auto mb-2 opacity-50" }), (0, jsx_runtime_1.jsx)("p", { children: "No fragment vaults available" }), (0, jsx_runtime_1.jsx)("p", { className: "text-sm mt-1", children: "Check back later for new NFT fragmentation opportunities" })] }))] }) }), (0, jsx_runtime_1.jsx)("div", { className: "bg-neutral-900 border border-neutral-700 rounded-lg hover:border-cyan-400/50 transition-colors", children: (0, jsx_runtime_1.jsxs)("div", { className: "p-6", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2 text-neutral-400 text-sm mb-4", children: [(0, jsx_runtime_1.jsx)(IconInfo, { className: "w-4 h-4" }), (0, jsx_runtime_1.jsx)("span", { children: "PROTOCOL_INFO" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "space-y-4 text-sm", children: [(0, jsx_runtime_1.jsxs)("div", { className: "p-4 bg-neutral-800 rounded border border-neutral-700", children: [(0, jsx_runtime_1.jsx)("div", { className: "font-medium text-white mb-2", children: "What is Fragmentation?" }), (0, jsx_runtime_1.jsx)("p", { className: "text-neutral-400", children: "Fragment allows NFT owners to split Territory NFTs into tradeable fragments, enabling shared ownership and community buyout mechanics." })] }), (0, jsx_runtime_1.jsxs)("div", { className: "p-4 bg-neutral-800 rounded border border-neutral-700", children: [(0, jsx_runtime_1.jsx)("div", { className: "font-medium text-white mb-2", children: "Fragment Holder Rights" }), (0, jsx_runtime_1.jsxs)("ul", { className: "list-disc list-inside space-y-1 text-neutral-400", children: [(0, jsx_runtime_1.jsx)("li", { children: "Proportional ownership of the underlying NFT" }), (0, jsx_runtime_1.jsx)("li", { children: "Participate in buyout proposals" }), (0, jsx_runtime_1.jsx)("li", { children: "Trade fragments freely on the market" })] })] })] })] }) }), (0, jsx_runtime_1.jsx)(Modal, { open: buyDialogOpen, onClose: () => setBuyDialogOpen(false), children: (0, jsx_runtime_1.jsxs)("div", { className: "space-y-4", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-lg font-bold text-white", children: "Buy Fragments" }), (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-neutral-400 mt-1", children: selectedVault
104
+ ? `Purchase fragments from ${selectedVault.nft_type ?? 'Territory'} NFT vault`
105
+ : 'Select a vault' })] }), selectedVault && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("div", { className: "p-4 bg-neutral-800 rounded border border-neutral-700", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex justify-between items-center mb-2", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-neutral-400", children: "Unit Price" }), (0, jsx_runtime_1.jsxs)("span", { className: "text-cyan-400 font-bold font-mono", children: [formatMCC(selectedVault.price_per_fragment ?? 0), " MCC"] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex justify-between items-center", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-neutral-400", children: "Available" }), (0, jsx_runtime_1.jsx)("span", { className: "text-white font-bold font-mono", children: formatNumber((selectedVault.total_fragments ?? 0) - (selectedVault.fragments_sold ?? 0), 0) })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "space-y-2", children: [(0, jsx_runtime_1.jsx)("label", { className: "text-xs text-neutral-400 tracking-wider", children: "purchase_amount" }), (0, jsx_runtime_1.jsx)("input", { type: "number", step: "1", min: "1", value: buyAmount, onChange: e => setBuyAmount(e.target.value), placeholder: "Enter amount", className: "w-full px-3 py-2 bg-neutral-800 border border-neutral-600 rounded text-white placeholder-neutral-400 outline-none focus:border-cyan-400" })] }), buyAmount && parseInt(buyAmount) > 0 && ((0, jsx_runtime_1.jsx)("div", { className: "p-4 bg-neutral-800 rounded border border-neutral-700", children: (0, jsx_runtime_1.jsxs)("div", { className: "flex justify-between items-center", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-neutral-400", children: "Total Price" }), (0, jsx_runtime_1.jsxs)("span", { className: "text-white font-bold font-mono", children: [formatMCC((selectedVault.price_per_fragment ?? 0) * parseInt(buyAmount)), " MCC"] })] }) }))] })), (0, jsx_runtime_1.jsxs)("div", { className: "flex justify-end gap-3 pt-2", children: [(0, jsx_runtime_1.jsx)("button", { onClick: () => { setBuyDialogOpen(false); setBuyAmount(''); }, className: "px-4 py-2 text-sm border border-neutral-700 rounded text-neutral-400 hover:bg-neutral-800 hover:text-neutral-300 bg-transparent", children: "Cancel" }), (0, jsx_runtime_1.jsx)("button", { onClick: handleBuy, disabled: actionLoading || !buyAmount, className: "flex items-center gap-2 px-4 py-2 text-sm bg-cyan-700 hover:bg-cyan-600 text-white rounded disabled:opacity-50", children: actionLoading ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(IconLoader, { className: "h-4 w-4 animate-spin" }), "Buying..."] })) : ('Confirm Purchase') })] })] }) })] }));
62
106
  }
@@ -6,17 +6,69 @@ exports.MicrocosmLendingPage = MicrocosmLendingPage;
6
6
  const jsx_runtime_1 = require("react/jsx-runtime");
7
7
  const react_1 = require("react");
8
8
  const auth_react_1 = require("@microcosmmoney/auth-react");
9
+ /* ── helpers ─────────────────────────────────────────────────── */
9
10
  const fmt = (num, decimals = 2) => num.toLocaleString('en-US', { minimumFractionDigits: decimals, maximumFractionDigits: decimals });
10
11
  const fmtMCC = (lamports) => fmt(lamports / 1000000000, 2);
12
+ const NFT_TYPE_MAP = {
13
+ Station: 'Station',
14
+ Matrix: 'Matrix',
15
+ Sector: 'Sector',
16
+ System: 'System',
17
+ };
11
18
  const COLLATERAL_TYPES = {
12
- Station: { value: 1000, label: 'Station' },
13
- Matrix: { value: 15000, label: 'Matrix' },
14
- Sector: { value: 200000, label: 'Sector' },
15
- System: { value: 2500000, label: 'System' },
19
+ Station: { value: 1000, label: 'Station', description: 'Space Station (1,000 users)' },
20
+ Matrix: { value: 15000, label: 'Matrix', description: 'Matrix (10 Stations)' },
21
+ Sector: { value: 200000, label: 'Sector', description: 'Sector (10 Matrices)' },
22
+ System: { value: 2500000, label: 'System', description: 'System (10 Sectors)' },
16
23
  };
17
- function Spinner() {
18
- return (0, jsx_runtime_1.jsx)("span", { className: "inline-block w-5 h-5 border-2 border-cyan-400 border-t-transparent rounded-full animate-spin" });
24
+ /* ── inline SVG icons (lucide-style) ─────────────────────────── */
25
+ function IconLandmark({ className }) {
26
+ return ((0, jsx_runtime_1.jsxs)("svg", { className: className, fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", viewBox: "0 0 24 24", children: [(0, jsx_runtime_1.jsx)("line", { x1: "3", y1: "22", x2: "21", y2: "22" }), (0, jsx_runtime_1.jsx)("line", { x1: "6", y1: "18", x2: "6", y2: "11" }), (0, jsx_runtime_1.jsx)("line", { x1: "10", y1: "18", x2: "10", y2: "11" }), (0, jsx_runtime_1.jsx)("line", { x1: "14", y1: "18", x2: "14", y2: "11" }), (0, jsx_runtime_1.jsx)("line", { x1: "18", y1: "18", x2: "18", y2: "11" }), (0, jsx_runtime_1.jsx)("polygon", { points: "12 2 20 7 4 7" })] }));
27
+ }
28
+ function IconWallet({ className }) {
29
+ return ((0, jsx_runtime_1.jsxs)("svg", { className: className, fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", viewBox: "0 0 24 24", children: [(0, jsx_runtime_1.jsx)("path", { d: "M21 12V7H5a2 2 0 010-4h14v4" }), (0, jsx_runtime_1.jsx)("path", { d: "M3 5v14a2 2 0 002 2h16v-5" }), (0, jsx_runtime_1.jsx)("path", { d: "M18 12a1 1 0 100 2 1 1 0 000-2z" })] }));
30
+ }
31
+ function IconTrendingUp({ className }) {
32
+ return ((0, jsx_runtime_1.jsxs)("svg", { className: className, fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", viewBox: "0 0 24 24", children: [(0, jsx_runtime_1.jsx)("polyline", { points: "23 6 13.5 15.5 8.5 10.5 1 18" }), (0, jsx_runtime_1.jsx)("polyline", { points: "17 6 23 6 23 12" })] }));
33
+ }
34
+ function IconPiggyBank({ className }) {
35
+ return ((0, jsx_runtime_1.jsxs)("svg", { className: className, fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", viewBox: "0 0 24 24", children: [(0, jsx_runtime_1.jsx)("path", { d: "M19 5c-1.5 0-2.8 1.4-3 2-3.5-1.5-11-.3-11 5 0 1.8 0 3 2 4.5V20h4v-2h3v2h4v-4c1-.5 1.7-1 2-2h2v-4h-2c0-1-.5-1.5-1-2" }), (0, jsx_runtime_1.jsx)("path", { d: "M2 9.5a.5.5 0 111 0 .5.5 0 01-1 0" }), (0, jsx_runtime_1.jsx)("path", { d: "M14 4a2 2 0 00-2 2" })] }));
36
+ }
37
+ function IconCreditCard({ className }) {
38
+ return ((0, jsx_runtime_1.jsxs)("svg", { className: className, fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", viewBox: "0 0 24 24", children: [(0, jsx_runtime_1.jsx)("rect", { x: "1", y: "4", width: "22", height: "16", rx: "2", ry: "2" }), (0, jsx_runtime_1.jsx)("line", { x1: "1", y1: "10", x2: "23", y2: "10" })] }));
39
+ }
40
+ function IconAlertTriangle({ className }) {
41
+ return ((0, jsx_runtime_1.jsxs)("svg", { className: className, fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", viewBox: "0 0 24 24", children: [(0, jsx_runtime_1.jsx)("path", { d: "M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z" }), (0, jsx_runtime_1.jsx)("line", { x1: "12", y1: "9", x2: "12", y2: "13" }), (0, jsx_runtime_1.jsx)("line", { x1: "12", y1: "17", x2: "12.01", y2: "17" })] }));
42
+ }
43
+ function IconClock({ className }) {
44
+ return ((0, jsx_runtime_1.jsxs)("svg", { className: className, fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", viewBox: "0 0 24 24", children: [(0, jsx_runtime_1.jsx)("circle", { cx: "12", cy: "12", r: "10" }), (0, jsx_runtime_1.jsx)("polyline", { points: "12 6 12 12 16 14" })] }));
45
+ }
46
+ function IconRefreshCw({ className }) {
47
+ return ((0, jsx_runtime_1.jsxs)("svg", { className: className, fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", viewBox: "0 0 24 24", children: [(0, jsx_runtime_1.jsx)("polyline", { points: "23 4 23 10 17 10" }), (0, jsx_runtime_1.jsx)("polyline", { points: "1 20 1 14 7 14" }), (0, jsx_runtime_1.jsx)("path", { d: "M3.51 9a9 9 0 0114.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0020.49 15" })] }));
48
+ }
49
+ function IconInfo({ className }) {
50
+ return ((0, jsx_runtime_1.jsxs)("svg", { className: className, fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", viewBox: "0 0 24 24", children: [(0, jsx_runtime_1.jsx)("circle", { cx: "12", cy: "12", r: "10" }), (0, jsx_runtime_1.jsx)("line", { x1: "12", y1: "16", x2: "12", y2: "12" }), (0, jsx_runtime_1.jsx)("line", { x1: "12", y1: "8", x2: "12.01", y2: "8" })] }));
51
+ }
52
+ function IconPlus({ className }) {
53
+ return ((0, jsx_runtime_1.jsxs)("svg", { className: className, fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", viewBox: "0 0 24 24", children: [(0, jsx_runtime_1.jsx)("line", { x1: "12", y1: "5", x2: "12", y2: "19" }), (0, jsx_runtime_1.jsx)("line", { x1: "5", y1: "12", x2: "19", y2: "12" })] }));
19
54
  }
55
+ function IconMinus({ className }) {
56
+ return ((0, jsx_runtime_1.jsx)("svg", { className: className, fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", viewBox: "0 0 24 24", children: (0, jsx_runtime_1.jsx)("line", { x1: "5", y1: "12", x2: "19", y2: "12" }) }));
57
+ }
58
+ function IconImage({ className }) {
59
+ return ((0, jsx_runtime_1.jsxs)("svg", { className: className, fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", viewBox: "0 0 24 24", children: [(0, jsx_runtime_1.jsx)("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2", ry: "2" }), (0, jsx_runtime_1.jsx)("circle", { cx: "8.5", cy: "8.5", r: "1.5" }), (0, jsx_runtime_1.jsx)("polyline", { points: "21 15 16 10 5 21" })] }));
60
+ }
61
+ function IconCheckCircle({ className }) {
62
+ return ((0, jsx_runtime_1.jsxs)("svg", { className: className, fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", viewBox: "0 0 24 24", children: [(0, jsx_runtime_1.jsx)("path", { d: "M22 11.08V12a10 10 0 11-5.93-9.14" }), (0, jsx_runtime_1.jsx)("polyline", { points: "22 4 12 14.01 9 11.01" })] }));
63
+ }
64
+ function IconLoader({ className }) {
65
+ return ((0, jsx_runtime_1.jsxs)("svg", { className: className, fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", viewBox: "0 0 24 24", children: [(0, jsx_runtime_1.jsx)("line", { x1: "12", y1: "2", x2: "12", y2: "6" }), (0, jsx_runtime_1.jsx)("line", { x1: "12", y1: "18", x2: "12", y2: "22" }), (0, jsx_runtime_1.jsx)("line", { x1: "4.93", y1: "4.93", x2: "7.76", y2: "7.76" }), (0, jsx_runtime_1.jsx)("line", { x1: "16.24", y1: "16.24", x2: "19.07", y2: "19.07" }), (0, jsx_runtime_1.jsx)("line", { x1: "2", y1: "12", x2: "6", y2: "12" }), (0, jsx_runtime_1.jsx)("line", { x1: "18", y1: "12", x2: "22", y2: "12" }), (0, jsx_runtime_1.jsx)("line", { x1: "4.93", y1: "19.07", x2: "7.76", y2: "16.24" }), (0, jsx_runtime_1.jsx)("line", { x1: "16.24", y1: "7.76", x2: "19.07", y2: "4.93" })] }));
66
+ }
67
+ /* ── cn helper ───────────────────────────────────────────────── */
68
+ function cn(...classes) {
69
+ return classes.filter(Boolean).join(' ');
70
+ }
71
+ /* ── Modal (inline, no shadcn) ───────────────────────────────── */
20
72
  function Modal({ open, onClose, children }) {
21
73
  if (!open)
22
74
  return null;
@@ -42,18 +94,39 @@ function MicrocosmLendingPage({ onNavigate }) {
42
94
  const [withdrawAmount, setWithdrawAmount] = (0, react_1.useState)('');
43
95
  const [selectedNFT, setSelectedNFT] = (0, react_1.useState)('');
44
96
  const [borrowAmount, setBorrowAmount] = (0, react_1.useState)('');
97
+ const [selectedLoan, setSelectedLoan] = (0, react_1.useState)(null);
45
98
  const [repayAmount, setRepayAmount] = (0, react_1.useState)('');
99
+ // Loans loaded from pool/stats data or nft-based lookup
100
+ const [userLoans, setUserLoans] = (0, react_1.useState)([]);
46
101
  const loading = poolLoading || statsLoading || lpLoading;
47
102
  const poolData = pool ?? stats;
103
+ const isSubmitting = actionLoading;
104
+ // Clear status messages after 5s
105
+ (0, react_1.useEffect)(() => {
106
+ if (actionSuccess) {
107
+ const t = setTimeout(() => setActionSuccess(null), 5000);
108
+ return () => clearTimeout(t);
109
+ }
110
+ }, [actionSuccess]);
111
+ (0, react_1.useEffect)(() => {
112
+ if (actionError) {
113
+ const t = setTimeout(() => setActionError(null), 8000);
114
+ return () => clearTimeout(t);
115
+ }
116
+ }, [actionError]);
117
+ // Derive available NFTs (exclude collateralized ones)
118
+ const collateralizedMints = new Set(userLoans.filter(l => l.status === 'Active').map(l => l.collateral_nft_mint));
119
+ const availableNFTs = (nfts ?? []).filter((nft) => !collateralizedMints.has(nft.mint));
48
120
  const handleRefresh = (0, react_1.useCallback)(async () => {
49
121
  setRefreshing(true);
50
122
  await Promise.all([refreshPool(), refreshStats(), refreshLP(), refreshOracle(), refreshNFTs()]);
51
123
  setRefreshing(false);
52
124
  }, [refreshPool, refreshStats, refreshLP, refreshOracle, refreshNFTs]);
125
+ /* ── Action handlers ─────────────────────────────────────── */
53
126
  const handleDeposit = async () => {
54
127
  const amount = parseFloat(depositAmount);
55
128
  if (isNaN(amount) || amount <= 0) {
56
- setActionError('Enter a valid amount');
129
+ setActionError('Enter a valid deposit amount');
57
130
  return;
58
131
  }
59
132
  try {
@@ -71,7 +144,7 @@ function MicrocosmLendingPage({ onNavigate }) {
71
144
  const handleWithdraw = async () => {
72
145
  const amount = parseFloat(withdrawAmount);
73
146
  if (isNaN(amount) || amount <= 0) {
74
- setActionError('Enter a valid amount');
147
+ setActionError('Enter a valid withdraw amount');
75
148
  return;
76
149
  }
77
150
  try {
@@ -88,20 +161,20 @@ function MicrocosmLendingPage({ onNavigate }) {
88
161
  };
89
162
  const handleBorrow = async () => {
90
163
  if (!selectedNFT) {
91
- setActionError('Select an NFT');
164
+ setActionError('Select an NFT as collateral');
92
165
  return;
93
166
  }
94
167
  const amount = parseFloat(borrowAmount);
95
168
  if (isNaN(amount) || amount <= 0) {
96
- setActionError('Enter a valid amount');
169
+ setActionError('Enter a valid borrow amount');
97
170
  return;
98
171
  }
99
- const nft = (nfts ?? []).find((n) => n.mint === selectedNFT);
172
+ const nft = availableNFTs.find((n) => n.mint === selectedNFT);
100
173
  if (!nft) {
101
174
  setActionError('NFT not found');
102
175
  return;
103
176
  }
104
- const nftType = nft.nft_type || 'Station';
177
+ const nftType = NFT_TYPE_MAP[nft.nft_type] || 'Station';
105
178
  const maxBorrow = COLLATERAL_TYPES[nftType]?.value ?? 1000;
106
179
  if (amount > maxBorrow) {
107
180
  setActionError(`Max borrow: ${fmt(maxBorrow)} MCC`);
@@ -110,7 +183,7 @@ function MicrocosmLendingPage({ onNavigate }) {
110
183
  try {
111
184
  setActionError(null);
112
185
  await borrow({ wallet: primaryWallet ?? '', amount: amount * 1000000000, nft_mint: nft.mint, duration_type: 1 });
113
- setActionSuccess(`Borrowed ${fmt(amount)} MCC`);
186
+ setActionSuccess(`Borrowed ${fmt(amount)} MCC against ${nft.name}`);
114
187
  setBorrowOpen(false);
115
188
  setSelectedNFT('');
116
189
  setBorrowAmount('');
@@ -121,16 +194,23 @@ function MicrocosmLendingPage({ onNavigate }) {
121
194
  }
122
195
  };
123
196
  const handleRepay = async () => {
197
+ if (!selectedLoan) {
198
+ setActionError('Select a loan to repay');
199
+ return;
200
+ }
124
201
  const amount = parseFloat(repayAmount);
125
202
  if (isNaN(amount) || amount <= 0) {
126
- setActionError('Enter a valid amount');
203
+ setActionError('Enter a valid repay amount');
127
204
  return;
128
205
  }
129
206
  try {
130
207
  setActionError(null);
131
- await repay({ wallet: primaryWallet ?? '', nft_mint: '', amount: amount * 1000000000 });
132
- setActionSuccess(`Repaid ${fmt(amount)} MCC`);
208
+ await repay({ wallet: primaryWallet ?? '', nft_mint: selectedLoan.collateral_nft_mint, amount: amount * 1000000000 });
209
+ const totalDebt = selectedLoan.total_owed / 1000000000;
210
+ const isFullRepay = amount >= totalDebt;
211
+ setActionSuccess(isFullRepay ? 'Loan fully repaid! NFT returned to wallet.' : `Repaid ${fmt(amount)} MCC`);
133
212
  setRepayOpen(false);
213
+ setSelectedLoan(null);
134
214
  setRepayAmount('');
135
215
  handleRefresh();
136
216
  }
@@ -138,10 +218,32 @@ function MicrocosmLendingPage({ onNavigate }) {
138
218
  setActionError(err instanceof Error ? err.message : 'Repay failed');
139
219
  }
140
220
  };
141
- return ((0, jsx_runtime_1.jsxs)("div", { className: "max-w-7xl mx-auto font-mono space-y-6", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h1", { className: "text-2xl font-bold text-white tracking-wider", children: "Lending" }), (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-neutral-400", children: "MCC collateralized lending protocol" })] }), (0, jsx_runtime_1.jsxs)("button", { onClick: handleRefresh, disabled: refreshing, className: "flex items-center gap-2 px-3 py-1.5 text-sm border border-neutral-700 rounded text-neutral-400 hover:bg-neutral-800 hover:text-neutral-300 disabled:opacity-50 bg-transparent", children: [(0, jsx_runtime_1.jsx)("svg", { className: `w-4 h-4 ${refreshing ? 'animate-spin' : ''}`, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: (0, jsx_runtime_1.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" }) }), "Refresh"] })] }), actionError && ((0, jsx_runtime_1.jsx)("div", { className: "p-3 bg-red-500/10 border border-red-500/30 rounded text-red-400 text-sm", children: actionError })), actionSuccess && ((0, jsx_runtime_1.jsx)("div", { className: "p-3 bg-cyan-400/10 border border-cyan-400/30 rounded text-cyan-400 text-sm", children: actionSuccess })), (0, jsx_runtime_1.jsx)("div", { className: "bg-neutral-900 border border-neutral-700 rounded-lg hover:border-cyan-400/50 transition-colors", children: (0, jsx_runtime_1.jsxs)("div", { className: "p-6", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-4 mb-6", children: [(0, jsx_runtime_1.jsx)("div", { className: "p-4 bg-cyan-400/20 rounded-xl border border-cyan-400/30", children: (0, jsx_runtime_1.jsx)("svg", { className: "h-8 w-8 text-white", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: (0, jsx_runtime_1.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M8 14v3m4-3v3m4-3v3M3 21h18M3 10h18M3 7l9-4 9 4M4 10h16v11H4V10z" }) }) }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("div", { className: "text-xs text-neutral-400 tracking-wider mb-1", children: "pool_name" }), (0, jsx_runtime_1.jsx)("div", { className: "text-2xl font-bold text-white", children: "MCC Lending Pool" })] })] }), loading ? ((0, jsx_runtime_1.jsx)("div", { className: "flex items-center justify-center py-8", children: (0, jsx_runtime_1.jsx)(Spinner, {}) })) : poolData ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("div", { className: "grid grid-cols-2 md:grid-cols-4 gap-4 mb-6", children: [(0, jsx_runtime_1.jsxs)("div", { className: "p-4 bg-neutral-800 rounded", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2 mb-2", children: [(0, jsx_runtime_1.jsx)("svg", { className: "h-4 w-4 text-white", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: (0, jsx_runtime_1.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M17 9V7a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2m2 4h10a2 2 0 002-2v-6a2 2 0 00-2-2H9a2 2 0 00-2 2v6a2 2 0 002 2zm7-5a2 2 0 11-4 0 2 2 0 014 0z" }) }), (0, jsx_runtime_1.jsx)("span", { className: "text-xs text-neutral-400 tracking-wider", children: "total_deposits" })] }), (0, jsx_runtime_1.jsx)("div", { className: "text-xl font-bold text-white font-mono", children: fmtMCC(poolData.total_deposits ?? 0) }), (0, jsx_runtime_1.jsx)("div", { className: "text-xs text-neutral-500 mt-1", children: "MCC" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "p-4 bg-neutral-800 rounded", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2 mb-2", children: [(0, jsx_runtime_1.jsx)("svg", { className: "h-4 w-4 text-cyan-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: (0, jsx_runtime_1.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, 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" }) }), (0, jsx_runtime_1.jsx)("span", { className: "text-xs text-neutral-400 tracking-wider", children: "total_borrowed" })] }), (0, jsx_runtime_1.jsx)("div", { className: "text-xl font-bold text-cyan-400 font-mono", children: fmtMCC(poolData.total_borrows ?? 0) }), (0, jsx_runtime_1.jsx)("div", { className: "text-xs text-neutral-500 mt-1", children: "MCC" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "p-4 bg-neutral-800 rounded", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2 mb-2", children: [(0, jsx_runtime_1.jsx)("svg", { className: "h-4 w-4 text-white", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: (0, jsx_runtime_1.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M13 7h8m0 0v8m0-8l-8 8-4-4-6 6" }) }), (0, jsx_runtime_1.jsx)("span", { className: "text-xs text-neutral-400 tracking-wider", children: "deposit_apr" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "text-xl font-bold text-white font-mono", children: [(poolData.supply_apr_percent ?? 0).toFixed(2), "%"] }), (0, jsx_runtime_1.jsx)("div", { className: "text-xs text-neutral-500 mt-1", children: "annualized" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "p-4 bg-neutral-800 rounded", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2 mb-2", children: [(0, jsx_runtime_1.jsx)("svg", { className: "h-4 w-4 text-cyan-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: (0, jsx_runtime_1.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M13 7h8m0 0v8m0-8l-8 8-4-4-6 6" }) }), (0, jsx_runtime_1.jsx)("span", { className: "text-xs text-neutral-400 tracking-wider", children: "borrow_apr" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "text-xl font-bold text-cyan-400 font-mono", children: [(poolData.borrow_apr_percent ?? 0).toFixed(2), "%"] }), (0, jsx_runtime_1.jsx)("div", { className: "text-xs text-neutral-500 mt-1", children: "annualized" })] })] }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex justify-between items-center mb-2", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-xs text-neutral-400 tracking-wider", children: "utilization_rate" }), (0, jsx_runtime_1.jsxs)("span", { className: "text-sm font-mono text-white", children: [(poolData.utilization_rate_percent ?? 0).toFixed(1), "%"] })] }), (0, jsx_runtime_1.jsx)("div", { className: "w-full bg-neutral-700 rounded-full h-2", children: (0, jsx_runtime_1.jsx)("div", { className: "bg-cyan-400 h-2 rounded-full transition-all", style: { width: `${Math.min(poolData.utilization_rate_percent ?? 0, 100)}%` } }) })] })] })) : ((0, jsx_runtime_1.jsx)("div", { className: "text-center py-8 text-neutral-500 font-mono text-sm", children: "pool data unavailable" }))] }) }), (0, jsx_runtime_1.jsx)("div", { className: "bg-neutral-900 border border-neutral-700 rounded-lg hover:border-cyan-400/50 transition-colors", children: (0, jsx_runtime_1.jsxs)("div", { className: "p-6", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between mb-4", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-neutral-400 text-sm tracking-wider", children: "MY_DEPOSITS" }), (0, jsx_runtime_1.jsxs)("div", { className: "flex gap-2", children: [(0, jsx_runtime_1.jsx)("button", { onClick: () => { setDepositOpen(true); setActionError(null); }, className: "px-3 py-1.5 text-sm bg-cyan-700 hover:bg-cyan-600 text-white rounded", children: "+ Deposit" }), (0, jsx_runtime_1.jsx)("button", { onClick: () => { setWithdrawOpen(true); setActionError(null); }, disabled: !lpData || (lpData.lp_balance ?? 0) <= 0, className: "px-3 py-1.5 text-sm border border-neutral-700 rounded text-neutral-400 hover:bg-neutral-800 disabled:opacity-50 bg-transparent", children: "- Withdraw" })] })] }), lpData && (lpData.lp_balance ?? 0) > 0 ? ((0, jsx_runtime_1.jsxs)("div", { className: "grid grid-cols-1 md:grid-cols-3 gap-4", children: [(0, jsx_runtime_1.jsxs)("div", { className: "p-4 bg-neutral-800 rounded", children: [(0, jsx_runtime_1.jsx)("div", { className: "text-xs text-neutral-400 tracking-wider mb-1", children: "lp_token_balance" }), (0, jsx_runtime_1.jsx)("div", { className: "text-2xl font-bold text-white font-mono", children: fmtMCC(lpData.lp_balance ?? 0) }), (0, jsx_runtime_1.jsx)("div", { className: "text-xs text-neutral-500 mt-1", children: "LP Token" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "p-4 bg-neutral-800 rounded", children: [(0, jsx_runtime_1.jsx)("div", { className: "text-xs text-neutral-400 tracking-wider mb-1", children: "deposit_value" }), (0, jsx_runtime_1.jsx)("div", { className: "text-2xl font-bold text-white font-mono", children: fmtMCC(lpData.lp_value_in_mcc ?? lpData.lp_balance ?? 0) }), (0, jsx_runtime_1.jsx)("div", { className: "text-xs text-neutral-500 mt-1", children: "MCC" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "p-4 bg-neutral-800 rounded", children: [(0, jsx_runtime_1.jsx)("div", { className: "text-xs text-neutral-400 tracking-wider mb-1", children: "earned_interest" }), (0, jsx_runtime_1.jsxs)("div", { className: "text-2xl font-bold text-cyan-400 font-mono", children: ["+", fmtMCC(Math.max(0, (lpData.lp_value_in_mcc ?? lpData.lp_balance ?? 0) - (lpData.lp_balance ?? 0)))] }), (0, jsx_runtime_1.jsx)("div", { className: "text-xs text-neutral-500 mt-1", children: "MCC" })] })] })) : ((0, jsx_runtime_1.jsx)("div", { className: "text-center py-8 text-neutral-500 font-mono text-sm", children: "no deposits yet \u2014 deposit MCC to earn interest" }))] }) }), (0, jsx_runtime_1.jsx)("div", { className: "bg-neutral-900 border border-neutral-700 rounded-lg hover:border-cyan-400/50 transition-colors", children: (0, jsx_runtime_1.jsxs)("div", { className: "p-6", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between mb-4", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-neutral-400 text-sm tracking-wider", children: "MY_LOANS" }), (0, jsx_runtime_1.jsx)("button", { onClick: () => { setBorrowOpen(true); setActionError(null); }, disabled: !nfts || nfts.length === 0, className: "px-3 py-1.5 text-sm bg-cyan-700 hover:bg-cyan-600 text-white rounded disabled:opacity-50", children: "+ New Loan" })] }), (0, jsx_runtime_1.jsx)("div", { className: "text-center py-8 text-neutral-500 font-mono text-sm", children: "no active loans \u2014 pledge Territory NFT to borrow MCC" })] }) }), (0, jsx_runtime_1.jsx)("div", { className: "bg-neutral-900 border border-neutral-700 rounded-lg hover:border-cyan-400/50 transition-colors", children: (0, jsx_runtime_1.jsxs)("div", { className: "p-6", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2 text-neutral-400 text-sm mb-4", children: [(0, jsx_runtime_1.jsx)("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: (0, jsx_runtime_1.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" }) }), (0, jsx_runtime_1.jsx)("span", { children: "PROTOCOL_INFO" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "space-y-4 text-sm", children: [(0, jsx_runtime_1.jsxs)("div", { className: "p-4 bg-neutral-800 rounded border border-neutral-700", children: [(0, jsx_runtime_1.jsx)("div", { className: "font-medium text-white mb-2", children: "Loan Rules" }), (0, jsx_runtime_1.jsxs)("ul", { className: "list-disc list-inside space-y-1 text-neutral-400", children: [(0, jsx_runtime_1.jsx)("li", { children: "Collateral: Territory NFT (Station/Matrix/Sector/System)" }), (0, jsx_runtime_1.jsx)("li", { children: "Max LTV: 100% of NFT valuation" }), (0, jsx_runtime_1.jsx)("li", { children: "Interest: variable rate based on pool utilization" }), (0, jsx_runtime_1.jsx)("li", { children: "Duration: 3 / 7 / 30 days with auto-renewal" })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "p-4 bg-neutral-800 rounded border border-neutral-700", children: [(0, jsx_runtime_1.jsx)("div", { className: "font-medium text-white mb-2", children: "Liquidation Rules" }), (0, jsx_runtime_1.jsxs)("ul", { className: "list-disc list-inside space-y-1 text-neutral-400", children: [(0, jsx_runtime_1.jsx)("li", { children: "LTV exceeds 90%: liquidation warning" }), (0, jsx_runtime_1.jsx)("li", { children: "Loan overdue or 2+ missed payments: liquidation eligible" }), (0, jsx_runtime_1.jsx)("li", { children: "Collateral NFT seized upon liquidation" })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "p-4 bg-neutral-800 rounded border border-neutral-700", children: [(0, jsx_runtime_1.jsx)("div", { className: "font-medium text-white mb-2", children: "NFT Valuation" }), (0, jsx_runtime_1.jsx)("div", { className: "grid grid-cols-2 md:grid-cols-4 gap-4 mt-2", children: Object.entries(COLLATERAL_TYPES).map(([key, val]) => ((0, jsx_runtime_1.jsxs)("div", { className: "text-center", children: [(0, jsx_runtime_1.jsx)("div", { className: "text-neutral-400 text-xs", children: val.label }), (0, jsx_runtime_1.jsx)("div", { className: "text-white font-bold font-mono", children: fmt(val.value) }), (0, jsx_runtime_1.jsx)("div", { className: "text-neutral-500 text-xs", children: "MCC" })] }, key))) })] })] })] }) }), (0, jsx_runtime_1.jsx)(Modal, { open: depositOpen, onClose: () => setDepositOpen(false), children: (0, jsx_runtime_1.jsxs)("div", { className: "space-y-4", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-lg font-bold text-white", children: "Deposit MCC" }), (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-neutral-400 mt-1", children: "Earn interest by providing liquidity to the lending pool" })] }), (0, jsx_runtime_1.jsx)("div", { className: "p-4 bg-cyan-400/10 border border-cyan-400/30 rounded", children: (0, jsx_runtime_1.jsxs)("div", { className: "text-sm text-cyan-400", children: [(0, jsx_runtime_1.jsx)("div", { className: "font-medium mb-1", children: "Earnings Info" }), (0, jsx_runtime_1.jsxs)("ul", { className: "list-disc list-inside space-y-1 text-xs text-cyan-400/70", children: [(0, jsx_runtime_1.jsxs)("li", { children: ["Current APR: ", (poolData?.supply_apr_percent ?? 0).toFixed(2), "%"] }), (0, jsx_runtime_1.jsx)("li", { children: "Interest accrues in real-time" }), (0, jsx_runtime_1.jsx)("li", { children: "Withdraw anytime" })] })] }) }), (0, jsx_runtime_1.jsxs)("div", { className: "space-y-2", children: [(0, jsx_runtime_1.jsx)("label", { className: "text-xs text-neutral-400 tracking-wider", children: "amount (MCC)" }), (0, jsx_runtime_1.jsx)("input", { type: "number", step: "0.01", value: depositAmount, onChange: e => setDepositAmount(e.target.value), placeholder: "Enter amount", className: "w-full px-3 py-2 bg-neutral-800 border border-neutral-600 rounded text-white placeholder-neutral-400 outline-none focus:border-cyan-400" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex justify-end gap-3 pt-2", children: [(0, jsx_runtime_1.jsx)("button", { onClick: () => setDepositOpen(false), className: "px-4 py-2 text-sm border border-neutral-700 rounded text-neutral-400 hover:bg-neutral-800 bg-transparent", children: "Cancel" }), (0, jsx_runtime_1.jsx)("button", { onClick: handleDeposit, disabled: actionLoading || !depositAmount, className: "px-4 py-2 text-sm bg-cyan-700 hover:bg-cyan-600 text-white rounded disabled:opacity-50", children: actionLoading ? 'Processing...' : 'Confirm Deposit' })] })] }) }), (0, jsx_runtime_1.jsx)(Modal, { open: withdrawOpen, onClose: () => setWithdrawOpen(false), children: (0, jsx_runtime_1.jsxs)("div", { className: "space-y-4", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-lg font-bold text-white", children: "Withdraw MCC" }), (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-neutral-400 mt-1", children: "Withdraw deposited MCC from the lending pool" })] }), (0, jsx_runtime_1.jsx)("div", { className: "p-4 bg-neutral-800 rounded border border-neutral-700", children: (0, jsx_runtime_1.jsxs)("div", { className: "flex justify-between items-center", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-neutral-400", children: "Withdrawable" }), (0, jsx_runtime_1.jsxs)("span", { className: "text-white font-bold font-mono", children: [fmtMCC(lpData?.lp_value_in_mcc ?? lpData?.lp_balance ?? 0), " MCC"] })] }) }), (0, jsx_runtime_1.jsxs)("div", { className: "space-y-2", children: [(0, jsx_runtime_1.jsx)("label", { className: "text-xs text-neutral-400 tracking-wider", children: "amount (MCC)" }), (0, jsx_runtime_1.jsx)("input", { type: "number", step: "0.01", value: withdrawAmount, onChange: e => setWithdrawAmount(e.target.value), placeholder: "Enter amount", className: "w-full px-3 py-2 bg-neutral-800 border border-neutral-600 rounded text-white placeholder-neutral-400 outline-none focus:border-cyan-400" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex justify-end gap-3 pt-2", children: [(0, jsx_runtime_1.jsx)("button", { onClick: () => setWithdrawOpen(false), className: "px-4 py-2 text-sm border border-neutral-700 rounded text-neutral-400 hover:bg-neutral-800 bg-transparent", children: "Cancel" }), (0, jsx_runtime_1.jsx)("button", { onClick: handleWithdraw, disabled: actionLoading || !withdrawAmount, className: "px-4 py-2 text-sm bg-cyan-700 hover:bg-cyan-600 text-white rounded disabled:opacity-50", children: actionLoading ? 'Processing...' : 'Confirm Withdraw' })] })] }) }), (0, jsx_runtime_1.jsx)(Modal, { open: borrowOpen, onClose: () => setBorrowOpen(false), children: (0, jsx_runtime_1.jsxs)("div", { className: "space-y-4", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-lg font-bold text-white", children: "New Loan" }), (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-neutral-400 mt-1", children: "Borrow MCC using Territory NFT as collateral" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "space-y-2", children: [(0, jsx_runtime_1.jsx)("label", { className: "text-xs text-neutral-400 tracking-wider", children: "select_nft" }), (0, jsx_runtime_1.jsxs)("select", { value: selectedNFT, onChange: e => setSelectedNFT(e.target.value), className: "w-full px-3 py-2 bg-neutral-800 border border-neutral-600 rounded text-white outline-none focus:border-cyan-400", children: [(0, jsx_runtime_1.jsx)("option", { value: "", children: "Select Territory NFT..." }), (nfts ?? []).map((nft) => ((0, jsx_runtime_1.jsxs)("option", { value: nft.mint, children: [nft.name, " (", COLLATERAL_TYPES[nft.nft_type]?.label ?? nft.nft_type, ")"] }, nft.mint)))] })] }), selectedNFT && (() => {
142
- const nft = (nfts ?? []).find((n) => n.mint === selectedNFT);
143
- const nftType = nft?.nft_type || 'Station';
144
- const maxVal = COLLATERAL_TYPES[nftType]?.value ?? 1000;
145
- return ((0, jsx_runtime_1.jsxs)("div", { className: "p-4 bg-neutral-800 rounded border border-neutral-700", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex justify-between items-center mb-2", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-neutral-400", children: "Collateral Value" }), (0, jsx_runtime_1.jsxs)("span", { className: "text-white font-bold font-mono", children: [fmt(maxVal), " MCC"] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex justify-between items-center", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-neutral-400", children: "Max Borrow" }), (0, jsx_runtime_1.jsxs)("span", { className: "text-white font-bold font-mono", children: [fmt(maxVal), " MCC"] })] })] }));
146
- })(), (0, jsx_runtime_1.jsxs)("div", { className: "space-y-2", children: [(0, jsx_runtime_1.jsx)("label", { className: "text-xs text-neutral-400 tracking-wider", children: "borrow_amount (MCC)" }), (0, jsx_runtime_1.jsx)("input", { type: "number", step: "0.01", value: borrowAmount, onChange: e => setBorrowAmount(e.target.value), placeholder: "Enter amount", className: "w-full px-3 py-2 bg-neutral-800 border border-neutral-600 rounded text-white placeholder-neutral-400 outline-none focus:border-cyan-400" })] }), (0, jsx_runtime_1.jsx)("div", { className: "p-4 bg-cyan-400/10 border border-cyan-400/30 rounded", children: (0, jsx_runtime_1.jsxs)("div", { className: "text-sm text-cyan-400", children: [(0, jsx_runtime_1.jsx)("div", { className: "font-medium mb-1", children: "Borrow Notice" }), (0, jsx_runtime_1.jsxs)("ul", { className: "list-disc list-inside space-y-1 text-xs text-cyan-400/70", children: [(0, jsx_runtime_1.jsx)("li", { children: "NFT will be locked as collateral" }), (0, jsx_runtime_1.jsxs)("li", { children: ["Current borrow APR: ", (poolData?.borrow_apr_percent ?? 0).toFixed(2), "%"] }), (0, jsx_runtime_1.jsx)("li", { children: "Failure to repay may result in NFT liquidation" })] })] }) }), (0, jsx_runtime_1.jsxs)("div", { className: "flex justify-end gap-3 pt-2", children: [(0, jsx_runtime_1.jsx)("button", { onClick: () => setBorrowOpen(false), className: "px-4 py-2 text-sm border border-neutral-700 rounded text-neutral-400 hover:bg-neutral-800 bg-transparent", children: "Cancel" }), (0, jsx_runtime_1.jsx)("button", { onClick: handleBorrow, disabled: actionLoading || !selectedNFT || !borrowAmount, className: "px-4 py-2 text-sm bg-cyan-700 hover:bg-cyan-600 text-white rounded disabled:opacity-50", children: actionLoading ? 'Processing...' : 'Confirm Borrow' })] })] }) }), (0, jsx_runtime_1.jsx)(Modal, { open: repayOpen, onClose: () => setRepayOpen(false), children: (0, jsx_runtime_1.jsxs)("div", { className: "space-y-4", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-lg font-bold text-white", children: "Repay Loan" }), (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-neutral-400 mt-1", children: "Repay borrowed MCC to release collateral" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "space-y-2", children: [(0, jsx_runtime_1.jsx)("label", { className: "text-xs text-neutral-400 tracking-wider", children: "repay_amount (MCC)" }), (0, jsx_runtime_1.jsx)("input", { type: "number", step: "0.01", value: repayAmount, onChange: e => setRepayAmount(e.target.value), placeholder: "Enter amount", className: "w-full px-3 py-2 bg-neutral-800 border border-neutral-600 rounded text-white placeholder-neutral-400 outline-none focus:border-cyan-400" })] }), (0, jsx_runtime_1.jsx)("div", { className: "p-4 bg-cyan-400/10 border border-cyan-400/30 rounded", children: (0, jsx_runtime_1.jsxs)("div", { className: "text-sm text-cyan-400", children: [(0, jsx_runtime_1.jsx)("div", { className: "font-medium mb-1", children: "After Full Repay" }), (0, jsx_runtime_1.jsxs)("ul", { className: "list-disc list-inside space-y-1 text-xs text-cyan-400/70", children: [(0, jsx_runtime_1.jsx)("li", { children: "Collateral NFT returned to your wallet" }), (0, jsx_runtime_1.jsx)("li", { children: "Loan record marked as repaid" })] })] }) }), (0, jsx_runtime_1.jsxs)("div", { className: "flex justify-end gap-3 pt-2", children: [(0, jsx_runtime_1.jsx)("button", { onClick: () => setRepayOpen(false), className: "px-4 py-2 text-sm border border-neutral-700 rounded text-neutral-400 hover:bg-neutral-800 bg-transparent", children: "Cancel" }), (0, jsx_runtime_1.jsx)("button", { onClick: handleRepay, disabled: actionLoading || !repayAmount, className: "px-4 py-2 text-sm bg-cyan-700 hover:bg-cyan-600 text-white rounded disabled:opacity-50", children: actionLoading ? 'Processing...' : 'Confirm Repay' })] })] }) })] }));
221
+ /* ── Loading state ─────────────────────────────────────────── */
222
+ if (loading) {
223
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "max-w-7xl mx-auto p-6 space-y-6 font-mono", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h1", { className: "text-2xl font-bold text-white tracking-wider", children: "Lending" }), (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-neutral-400", children: "MCC collateralized lending protocol" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-center py-20", children: [(0, jsx_runtime_1.jsx)(IconLoader, { className: "w-6 h-6 animate-spin text-neutral-400 mr-3" }), (0, jsx_runtime_1.jsx)("span", { className: "text-neutral-400", children: "Loading lending data..." })] })] }));
224
+ }
225
+ /* ── Error state ───────────────────────────────────────────── */
226
+ if (!poolData) {
227
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "max-w-7xl mx-auto p-6 space-y-6 font-mono", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h1", { className: "text-2xl font-bold text-white tracking-wider", children: "Lending" }), (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-neutral-400", children: "MCC collateralized lending protocol" })] }), (0, jsx_runtime_1.jsx)("div", { className: "bg-neutral-900 border border-neutral-700 rounded-lg p-6", children: (0, jsx_runtime_1.jsxs)("div", { className: "flex items-start gap-3", children: [(0, jsx_runtime_1.jsx)(IconAlertTriangle, { className: "w-5 h-5 text-red-500 mt-0.5" }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("p", { className: "text-red-500 font-medium", children: "Failed to load lending pool data" }), (0, jsx_runtime_1.jsx)("p", { className: "text-neutral-500 text-sm mt-1", children: "Please check your network connection and try again." })] })] }) }), (0, jsx_runtime_1.jsx)("button", { onClick: handleRefresh, className: "flex items-center gap-2 px-3 py-1.5 text-sm border border-neutral-700 rounded text-neutral-400 hover:bg-neutral-800 hover:text-neutral-300 bg-transparent", children: "Retry" })] }));
228
+ }
229
+ /* ── Main render ───────────────────────────────────────────── */
230
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "max-w-7xl mx-auto p-6 space-y-6 font-mono", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h1", { className: "text-2xl font-bold text-white tracking-wider", children: "Lending" }), (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-neutral-400", children: "MCC collateralized lending protocol" })] }), (0, jsx_runtime_1.jsxs)("button", { onClick: handleRefresh, disabled: refreshing, className: "flex items-center gap-2 px-3 py-1.5 text-sm border border-neutral-700 rounded text-neutral-400 hover:bg-neutral-800 hover:text-neutral-300 disabled:opacity-50 bg-transparent", children: [(0, jsx_runtime_1.jsx)(IconRefreshCw, { className: cn("w-4 h-4", refreshing && "animate-spin") }), "Refresh"] })] }), actionError && ((0, jsx_runtime_1.jsxs)("div", { className: "p-3 bg-red-500/10 border border-red-500/30 rounded text-red-400 text-sm flex items-start gap-2", children: [(0, jsx_runtime_1.jsx)(IconAlertTriangle, { className: "w-4 h-4 mt-0.5 shrink-0" }), actionError] })), actionSuccess && ((0, jsx_runtime_1.jsxs)("div", { className: "p-3 bg-cyan-400/10 border border-cyan-400/30 rounded text-cyan-400 text-sm flex items-start gap-2", children: [(0, jsx_runtime_1.jsx)(IconCheckCircle, { className: "w-4 h-4 mt-0.5 shrink-0" }), actionSuccess] })), (0, jsx_runtime_1.jsx)("div", { className: "bg-neutral-900 border border-neutral-700 rounded-lg hover:border-cyan-400/50 transition-colors", children: (0, jsx_runtime_1.jsxs)("div", { className: "p-6", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-4 mb-6", children: [(0, jsx_runtime_1.jsx)("div", { className: "p-4 bg-cyan-400/20 rounded-xl border border-cyan-400/30", children: (0, jsx_runtime_1.jsx)(IconLandmark, { className: "h-8 w-8 text-white" }) }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("div", { className: "text-xs text-neutral-400 tracking-wider mb-1", children: "pool_name" }), (0, jsx_runtime_1.jsx)("div", { className: "text-2xl font-bold text-white", children: "MCC Lending Pool" })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "grid grid-cols-2 md:grid-cols-4 gap-4 mb-6", children: [(0, jsx_runtime_1.jsxs)("div", { className: "p-4 bg-neutral-800 rounded", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2 mb-2", children: [(0, jsx_runtime_1.jsx)(IconPiggyBank, { className: "h-4 w-4 text-white" }), (0, jsx_runtime_1.jsx)("span", { className: "text-xs text-neutral-400 tracking-wider", children: "total_deposits" })] }), (0, jsx_runtime_1.jsx)("div", { className: "text-xl font-bold text-white font-mono", children: fmtMCC(poolData.total_deposits ?? 0) }), (0, jsx_runtime_1.jsx)("div", { className: "text-xs text-neutral-500 mt-1", children: "MCC" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "p-4 bg-neutral-800 rounded", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2 mb-2", children: [(0, jsx_runtime_1.jsx)(IconCreditCard, { className: "h-4 w-4 text-cyan-400" }), (0, jsx_runtime_1.jsx)("span", { className: "text-xs text-neutral-400 tracking-wider", children: "total_borrowed" })] }), (0, jsx_runtime_1.jsx)("div", { className: "text-xl font-bold text-cyan-400 font-mono", children: fmtMCC(poolData.total_borrows ?? 0) }), (0, jsx_runtime_1.jsx)("div", { className: "text-xs text-neutral-500 mt-1", children: "MCC" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "p-4 bg-neutral-800 rounded", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2 mb-2", children: [(0, jsx_runtime_1.jsx)(IconTrendingUp, { className: "h-4 w-4 text-white" }), (0, jsx_runtime_1.jsx)("span", { className: "text-xs text-neutral-400 tracking-wider", children: "deposit_apr" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "text-xl font-bold text-white font-mono", children: [(poolData.supply_apr_percent ?? 0).toFixed(2), "%"] }), (0, jsx_runtime_1.jsx)("div", { className: "text-xs text-neutral-500 mt-1", children: "annualized" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "p-4 bg-neutral-800 rounded", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2 mb-2", children: [(0, jsx_runtime_1.jsx)(IconTrendingUp, { className: "h-4 w-4 text-cyan-400" }), (0, jsx_runtime_1.jsx)("span", { className: "text-xs text-neutral-400 tracking-wider", children: "borrow_apr" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "text-xl font-bold text-cyan-400 font-mono", children: [(poolData.borrow_apr_percent ?? 0).toFixed(2), "%"] }), (0, jsx_runtime_1.jsx)("div", { className: "text-xs text-neutral-500 mt-1", children: "annualized" })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "mb-4", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex justify-between items-center mb-2", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-xs text-neutral-400 tracking-wider", children: "utilization_rate" }), (0, jsx_runtime_1.jsxs)("span", { className: "text-sm font-mono text-white", children: [(poolData.utilization_rate_percent ?? 0).toFixed(1), "%"] })] }), (0, jsx_runtime_1.jsx)("div", { className: "w-full bg-neutral-800 rounded-full h-2", children: (0, jsx_runtime_1.jsx)("div", { className: "bg-cyan-400 h-2 rounded-full transition-all", style: { width: `${Math.min(poolData.utilization_rate_percent ?? 0, 100)}%` } }) })] })] }) }), (0, jsx_runtime_1.jsx)("div", { className: "bg-neutral-900 border border-neutral-700 rounded-lg", children: (0, jsx_runtime_1.jsxs)("div", { className: "p-6", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between mb-4", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2 text-neutral-400 text-sm", children: [(0, jsx_runtime_1.jsx)(IconWallet, { className: "w-4 h-4" }), (0, jsx_runtime_1.jsx)("span", { className: "tracking-wider", children: "MY_DEPOSITS" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex gap-2", children: [(0, jsx_runtime_1.jsxs)("button", { onClick: () => { setDepositOpen(true); setActionError(null); }, className: "flex items-center gap-1 px-3 py-1.5 text-sm bg-cyan-700 hover:bg-cyan-600 text-white rounded", children: [(0, jsx_runtime_1.jsx)(IconPlus, { className: "w-4 h-4" }), "Deposit"] }), (0, jsx_runtime_1.jsxs)("button", { onClick: () => { setWithdrawOpen(true); setActionError(null); }, disabled: !lpData || (lpData.lp_balance ?? 0) <= 0, className: "flex items-center gap-1 px-3 py-1.5 text-sm border border-neutral-700 rounded text-neutral-400 hover:bg-neutral-800 hover:text-neutral-300 disabled:opacity-50 bg-transparent", children: [(0, jsx_runtime_1.jsx)(IconMinus, { className: "w-4 h-4" }), "Withdraw"] })] })] }), lpData && (lpData.lp_balance ?? 0) > 0 ? ((0, jsx_runtime_1.jsxs)("div", { className: "grid grid-cols-1 md:grid-cols-3 gap-4", children: [(0, jsx_runtime_1.jsxs)("div", { className: "p-4 bg-neutral-800 rounded", children: [(0, jsx_runtime_1.jsx)("div", { className: "text-xs text-neutral-400 tracking-wider mb-1", children: "lp_token_balance" }), (0, jsx_runtime_1.jsx)("div", { className: "text-2xl font-bold text-white font-mono", children: fmtMCC(lpData.lp_balance ?? 0) }), (0, jsx_runtime_1.jsx)("div", { className: "text-xs text-neutral-500 mt-1", children: "LP Token" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "p-4 bg-neutral-800 rounded", children: [(0, jsx_runtime_1.jsx)("div", { className: "text-xs text-neutral-400 tracking-wider mb-1", children: "deposit_value" }), (0, jsx_runtime_1.jsx)("div", { className: "text-2xl font-bold text-white font-mono", children: fmtMCC(lpData.lp_value_in_mcc ?? lpData.lp_balance ?? 0) }), (0, jsx_runtime_1.jsx)("div", { className: "text-xs text-neutral-500 mt-1", children: "MCC" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "p-4 bg-neutral-800 rounded", children: [(0, jsx_runtime_1.jsx)("div", { className: "text-xs text-neutral-400 tracking-wider mb-1", children: "earned_interest" }), (0, jsx_runtime_1.jsxs)("div", { className: "text-2xl font-bold text-cyan-400 font-mono", children: ["+", fmtMCC(Math.max(0, (lpData.lp_value_in_mcc ?? lpData.lp_balance ?? 0) - (lpData.lp_balance ?? 0)))] }), (0, jsx_runtime_1.jsx)("div", { className: "text-xs text-neutral-500 mt-1", children: "MCC" })] })] })) : ((0, jsx_runtime_1.jsxs)("div", { className: "text-center py-8 text-neutral-500", children: [(0, jsx_runtime_1.jsx)(IconWallet, { className: "w-12 h-12 mx-auto mb-2 opacity-50" }), (0, jsx_runtime_1.jsx)("p", { children: "No deposits yet" }), (0, jsx_runtime_1.jsx)("p", { className: "text-sm mt-1", children: "Deposit MCC to earn interest from the lending pool" })] }))] }) }), (0, jsx_runtime_1.jsx)("div", { className: "bg-neutral-900 border border-neutral-700 rounded-lg", children: (0, jsx_runtime_1.jsxs)("div", { className: "p-6", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between mb-4", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2 text-neutral-400 text-sm", children: [(0, jsx_runtime_1.jsx)(IconCreditCard, { className: "w-4 h-4" }), (0, jsx_runtime_1.jsx)("span", { className: "tracking-wider", children: "MY_LOANS" })] }), (0, jsx_runtime_1.jsxs)("button", { onClick: () => { setBorrowOpen(true); setActionError(null); }, disabled: availableNFTs.length === 0, className: "flex items-center gap-1 px-3 py-1.5 text-sm bg-cyan-700 hover:bg-cyan-600 text-white rounded disabled:opacity-50", children: [(0, jsx_runtime_1.jsx)(IconPlus, { className: "w-4 h-4" }), "New Loan"] })] }), userLoans.length > 0 ? ((0, jsx_runtime_1.jsx)("div", { className: "space-y-4", children: userLoans.map((loan) => {
231
+ const nftMintShort = `${loan.collateral_nft_mint.slice(0, 6)}...${loan.collateral_nft_mint.slice(-4)}`;
232
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "p-4 bg-neutral-800 rounded border border-neutral-700 hover:border-cyan-400/50 transition-colors", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex justify-between items-start mb-4", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-3", children: [(0, jsx_runtime_1.jsx)("div", { className: "p-2 bg-cyan-400/20 rounded border border-cyan-400/30", children: (0, jsx_runtime_1.jsx)(IconImage, { className: "h-6 w-6 text-white" }) }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsxs)("div", { className: "font-bold text-white", children: [loan.collateral_nft_type, " #", loan.loan_id] }), (0, jsx_runtime_1.jsx)("div", { className: "text-xs text-neutral-500 font-mono", children: nftMintShort })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [loan.status === 'Active' && ((0, jsx_runtime_1.jsx)("span", { className: cn("text-xs px-2 py-0.5 rounded border", loan.missed_payments > 0
233
+ ? "bg-cyan-400/20 text-cyan-400 border-cyan-400/30"
234
+ : "bg-white/20 text-white border-white/30"), children: loan.missed_payments > 0 ? `${loan.missed_payments} missed` : 'Normal' })), loan.status === 'Repaid' && ((0, jsx_runtime_1.jsx)("span", { className: "text-xs px-2 py-0.5 rounded border bg-white/20 text-white border-white/30", children: "Repaid" })), loan.status === 'Liquidated' && ((0, jsx_runtime_1.jsx)("span", { className: "text-xs px-2 py-0.5 rounded border bg-red-500/20 text-red-500 border-red-500/30", children: "Liquidated" }))] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "grid grid-cols-2 md:grid-cols-4 gap-4 mb-4", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("div", { className: "text-xs text-neutral-400 tracking-wider", children: "collateral_value" }), (0, jsx_runtime_1.jsxs)("div", { className: "text-lg font-bold text-white font-mono", children: [fmtMCC(loan.collateral_value), " MCC"] })] }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("div", { className: "text-xs text-neutral-400 tracking-wider", children: "principal" }), (0, jsx_runtime_1.jsxs)("div", { className: "text-lg font-bold text-cyan-400 font-mono", children: [fmtMCC(loan.principal), " MCC"] })] }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("div", { className: "text-xs text-neutral-400 tracking-wider", children: "interest" }), (0, jsx_runtime_1.jsxs)("div", { className: "text-lg font-bold text-cyan-400 font-mono", children: ["+", fmtMCC(loan.interest_accrued), " MCC"] })] }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("div", { className: "text-xs text-neutral-400 tracking-wider", children: "total_debt" }), (0, jsx_runtime_1.jsxs)("div", { className: "text-lg font-bold text-red-500 font-mono", children: [fmtMCC(loan.total_owed), " MCC"] })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "mb-4", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex justify-between items-center mb-2", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-xs text-neutral-400 tracking-wider", children: "LTV (Loan-to-Value)" }), (0, jsx_runtime_1.jsxs)("span", { className: cn("text-sm font-mono", loan.ltv >= 100 ? "text-red-500" : loan.ltv >= 80 ? "text-cyan-400" : "text-white"), children: [loan.ltv.toFixed(1), "%"] })] }), (0, jsx_runtime_1.jsx)("div", { className: "w-full bg-neutral-800 rounded-full h-2", children: (0, jsx_runtime_1.jsx)("div", { className: cn("h-2 rounded-full transition-all", loan.ltv >= 100 ? "bg-red-500" : loan.ltv >= 80 ? "bg-cyan-400" : "bg-white"), style: { width: `${Math.min(loan.ltv, 100)}%` } }) })] }), loan.status === 'Active' && ((0, jsx_runtime_1.jsxs)("div", { className: "flex justify-between items-center", children: [(0, jsx_runtime_1.jsxs)("div", { className: "text-xs text-neutral-500 flex items-center gap-1", children: [(0, jsx_runtime_1.jsx)(IconClock, { className: "w-3 h-3 inline" }), "Rate: ", loan.borrow_rate.toFixed(2), "% APR | Monthly repayment"] }), (0, jsx_runtime_1.jsx)("button", { onClick: () => {
235
+ setSelectedLoan(loan);
236
+ setRepayOpen(true);
237
+ setActionError(null);
238
+ }, className: "px-3 py-1.5 text-sm bg-cyan-700 hover:bg-cyan-600 text-white rounded", children: "Repay" })] })), loan.missed_payments >= 2 && loan.status === 'Active' && ((0, jsx_runtime_1.jsx)("div", { className: "mt-4 p-3 bg-red-500/10 border border-red-500/30 rounded", children: (0, jsx_runtime_1.jsxs)("div", { className: "flex items-start gap-2", children: [(0, jsx_runtime_1.jsx)(IconAlertTriangle, { className: "h-4 w-4 text-red-500 mt-0.5" }), (0, jsx_runtime_1.jsxs)("div", { className: "text-sm text-red-500", children: [(0, jsx_runtime_1.jsx)("div", { className: "font-medium", children: "Liquidation Warning" }), (0, jsx_runtime_1.jsxs)("div", { className: "text-xs text-red-500/70", children: [loan.missed_payments, " consecutive missed payments. Your NFT may be liquidated."] })] })] }) }))] }, loan.loan_id));
239
+ }) })) : ((0, jsx_runtime_1.jsxs)("div", { className: "text-center py-8 text-neutral-500", children: [(0, jsx_runtime_1.jsx)(IconCreditCard, { className: "w-12 h-12 mx-auto mb-2 opacity-50" }), (0, jsx_runtime_1.jsx)("p", { children: "No active loans" }), (0, jsx_runtime_1.jsx)("p", { className: "text-sm mt-1", children: "Pledge Territory NFT to borrow MCC from the pool" })] }))] }) }), (0, jsx_runtime_1.jsx)("div", { className: "bg-neutral-900 border border-neutral-700 rounded-lg", children: (0, jsx_runtime_1.jsxs)("div", { className: "p-6", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2 text-neutral-400 text-sm mb-4", children: [(0, jsx_runtime_1.jsx)(IconInfo, { className: "w-4 h-4" }), (0, jsx_runtime_1.jsx)("span", { className: "tracking-wider", children: "PROTOCOL_INFO" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "space-y-4 text-sm", children: [(0, jsx_runtime_1.jsxs)("div", { className: "p-4 bg-neutral-800 rounded", children: [(0, jsx_runtime_1.jsx)("div", { className: "font-medium text-white mb-2", children: "Loan Rules" }), (0, jsx_runtime_1.jsxs)("ul", { className: "list-disc list-inside space-y-1 text-neutral-400", children: [(0, jsx_runtime_1.jsx)("li", { children: "Collateral: Territory NFT (Station/Matrix/Sector/System)" }), (0, jsx_runtime_1.jsx)("li", { children: "Max LTV: 100% of NFT valuation" }), (0, jsx_runtime_1.jsx)("li", { children: "Interest: variable rate based on pool utilization" }), (0, jsx_runtime_1.jsx)("li", { children: "Duration: 3 / 7 / 30 days with auto-renewal" })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "p-4 bg-neutral-800 rounded", children: [(0, jsx_runtime_1.jsx)("div", { className: "font-medium text-white mb-2", children: "Liquidation Rules" }), (0, jsx_runtime_1.jsxs)("ul", { className: "list-disc list-inside space-y-1 text-neutral-400", children: [(0, jsx_runtime_1.jsx)("li", { children: "LTV exceeds 90%: liquidation warning" }), (0, jsx_runtime_1.jsx)("li", { children: "Loan overdue or 2+ missed payments: liquidation eligible" }), (0, jsx_runtime_1.jsx)("li", { children: "Collateral NFT seized upon liquidation" })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "p-4 bg-neutral-800 rounded", children: [(0, jsx_runtime_1.jsx)("div", { className: "font-medium text-white mb-2", children: "NFT Valuation" }), (0, jsx_runtime_1.jsx)("div", { className: "grid grid-cols-2 md:grid-cols-4 gap-4 mt-2", children: Object.entries(COLLATERAL_TYPES).map(([key, val]) => ((0, jsx_runtime_1.jsxs)("div", { className: "text-center", children: [(0, jsx_runtime_1.jsx)("div", { className: "text-neutral-400 text-xs", children: val.description }), (0, jsx_runtime_1.jsx)("div", { className: "text-white font-bold font-mono", children: fmt(val.value) }), (0, jsx_runtime_1.jsx)("div", { className: "text-neutral-500 text-xs", children: "MCC" })] }, key))) })] })] })] }) }), (0, jsx_runtime_1.jsx)(Modal, { open: depositOpen, onClose: () => setDepositOpen(false), children: (0, jsx_runtime_1.jsxs)("div", { className: "space-y-4", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-lg font-bold text-white", children: "Deposit MCC" }), (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-neutral-400 mt-1", children: "Earn interest by providing liquidity to the lending pool" })] }), (0, jsx_runtime_1.jsx)("div", { className: "p-4 bg-cyan-400/10 border border-cyan-400/30 rounded", children: (0, jsx_runtime_1.jsxs)("div", { className: "flex items-start gap-2", children: [(0, jsx_runtime_1.jsx)(IconInfo, { className: "h-4 w-4 text-cyan-400 mt-0.5 shrink-0" }), (0, jsx_runtime_1.jsxs)("div", { className: "text-sm", children: [(0, jsx_runtime_1.jsx)("div", { className: "font-medium text-cyan-400 mb-1", children: "Earnings Info" }), (0, jsx_runtime_1.jsxs)("ul", { className: "list-disc list-inside space-y-1 text-xs text-cyan-400/70", children: [(0, jsx_runtime_1.jsxs)("li", { children: ["Current APR: ", (poolData?.supply_apr_percent ?? 0).toFixed(2), "%"] }), (0, jsx_runtime_1.jsx)("li", { children: "Interest accrues in real-time" }), (0, jsx_runtime_1.jsx)("li", { children: "Withdraw anytime" })] })] })] }) }), (0, jsx_runtime_1.jsxs)("div", { className: "space-y-2", children: [(0, jsx_runtime_1.jsx)("label", { className: "text-neutral-400 text-xs tracking-wider", children: "amount (MCC)" }), (0, jsx_runtime_1.jsx)("input", { type: "number", step: "0.01", value: depositAmount, onChange: e => setDepositAmount(e.target.value), placeholder: "Enter deposit amount", className: "w-full px-3 py-2 bg-neutral-800 border border-neutral-600 rounded text-white placeholder-neutral-400 outline-none focus:border-cyan-400" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex justify-end gap-3 pt-2", children: [(0, jsx_runtime_1.jsx)("button", { onClick: () => setDepositOpen(false), className: "px-4 py-2 text-sm border border-neutral-700 rounded text-neutral-400 hover:bg-neutral-800 hover:text-neutral-300 bg-transparent", children: "Cancel" }), (0, jsx_runtime_1.jsx)("button", { onClick: handleDeposit, disabled: isSubmitting || !depositAmount, className: "px-4 py-2 text-sm bg-cyan-700 hover:bg-cyan-600 text-white rounded disabled:opacity-50", children: isSubmitting ? ((0, jsx_runtime_1.jsxs)("span", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)(IconLoader, { className: "h-4 w-4 animate-spin" }), "Depositing..."] })) : ('Confirm Deposit') })] })] }) }), (0, jsx_runtime_1.jsx)(Modal, { open: withdrawOpen, onClose: () => setWithdrawOpen(false), children: (0, jsx_runtime_1.jsxs)("div", { className: "space-y-4", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-lg font-bold text-white", children: "Withdraw MCC" }), (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-neutral-400 mt-1", children: "Withdraw deposited MCC from the lending pool" })] }), (0, jsx_runtime_1.jsx)("div", { className: "p-4 bg-neutral-800 rounded border border-neutral-700", children: (0, jsx_runtime_1.jsxs)("div", { className: "flex justify-between items-center", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-neutral-400", children: "Withdrawable Amount" }), (0, jsx_runtime_1.jsxs)("span", { className: "text-white font-bold font-mono", children: [fmtMCC(lpData?.lp_value_in_mcc ?? lpData?.lp_balance ?? 0), " MCC"] })] }) }), (0, jsx_runtime_1.jsxs)("div", { className: "space-y-2", children: [(0, jsx_runtime_1.jsx)("label", { className: "text-neutral-400 text-xs tracking-wider", children: "amount (MCC)" }), (0, jsx_runtime_1.jsx)("input", { type: "number", step: "0.01", value: withdrawAmount, onChange: e => setWithdrawAmount(e.target.value), placeholder: "Enter withdraw amount", className: "w-full px-3 py-2 bg-neutral-800 border border-neutral-600 rounded text-white placeholder-neutral-400 outline-none focus:border-cyan-400" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex justify-end gap-3 pt-2", children: [(0, jsx_runtime_1.jsx)("button", { onClick: () => setWithdrawOpen(false), className: "px-4 py-2 text-sm border border-neutral-700 rounded text-neutral-400 hover:bg-neutral-800 hover:text-neutral-300 bg-transparent", children: "Cancel" }), (0, jsx_runtime_1.jsx)("button", { onClick: handleWithdraw, disabled: isSubmitting || !withdrawAmount, className: "px-4 py-2 text-sm bg-cyan-700 hover:bg-cyan-600 text-white rounded disabled:opacity-50", children: isSubmitting ? ((0, jsx_runtime_1.jsxs)("span", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)(IconLoader, { className: "h-4 w-4 animate-spin" }), "Withdrawing..."] })) : ('Confirm Withdraw') })] })] }) }), (0, jsx_runtime_1.jsx)(Modal, { open: borrowOpen, onClose: () => setBorrowOpen(false), children: (0, jsx_runtime_1.jsxs)("div", { className: "space-y-4", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-lg font-bold text-white", children: "New Loan" }), (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-neutral-400 mt-1", children: "Borrow MCC using Territory NFT as collateral" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "space-y-2", children: [(0, jsx_runtime_1.jsx)("label", { className: "text-neutral-400 text-xs tracking-wider", children: "select_nft" }), (0, jsx_runtime_1.jsxs)("select", { value: selectedNFT, onChange: e => setSelectedNFT(e.target.value), className: "w-full px-3 py-2 bg-neutral-800 border border-neutral-600 rounded text-white outline-none focus:border-cyan-400", children: [(0, jsx_runtime_1.jsx)("option", { value: "", children: "Select Territory NFT..." }), availableNFTs.map((nft) => {
240
+ const nftType = NFT_TYPE_MAP[nft.nft_type] || 'Station';
241
+ return ((0, jsx_runtime_1.jsxs)("option", { value: nft.mint, children: [nft.name, " (", COLLATERAL_TYPES[nftType].description, ")"] }, nft.mint));
242
+ })] })] }), selectedNFT && (() => {
243
+ const selectedNftData = availableNFTs.find((n) => n.mint === selectedNFT);
244
+ const nftType = NFT_TYPE_MAP[selectedNftData?.nft_type || 'Station'] || 'Station';
245
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "p-4 bg-neutral-800 rounded border border-neutral-700", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex justify-between items-center mb-2", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-neutral-400", children: "Collateral Value" }), (0, jsx_runtime_1.jsxs)("span", { className: "text-white font-bold font-mono", children: [fmt(COLLATERAL_TYPES[nftType].value), " MCC"] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex justify-between items-center", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-neutral-400", children: "Max Borrow" }), (0, jsx_runtime_1.jsxs)("span", { className: "text-white font-bold font-mono", children: [fmt(COLLATERAL_TYPES[nftType].value), " MCC"] })] })] }));
246
+ })(), (0, jsx_runtime_1.jsxs)("div", { className: "space-y-2", children: [(0, jsx_runtime_1.jsx)("label", { className: "text-neutral-400 text-xs tracking-wider", children: "borrow_amount (MCC)" }), (0, jsx_runtime_1.jsx)("input", { type: "number", step: "0.01", value: borrowAmount, onChange: e => setBorrowAmount(e.target.value), placeholder: "Enter borrow amount", className: "w-full px-3 py-2 bg-neutral-800 border border-neutral-600 rounded text-white placeholder-neutral-400 outline-none focus:border-cyan-400" })] }), (0, jsx_runtime_1.jsx)("div", { className: "p-4 bg-cyan-400/10 border border-cyan-400/30 rounded", children: (0, jsx_runtime_1.jsxs)("div", { className: "flex items-start gap-2", children: [(0, jsx_runtime_1.jsx)(IconAlertTriangle, { className: "h-4 w-4 text-cyan-400 mt-0.5 shrink-0" }), (0, jsx_runtime_1.jsxs)("div", { className: "text-sm", children: [(0, jsx_runtime_1.jsx)("div", { className: "font-medium text-cyan-400 mb-1", children: "Borrow Notice" }), (0, jsx_runtime_1.jsxs)("ul", { className: "list-disc list-inside space-y-1 text-xs text-cyan-400/70", children: [(0, jsx_runtime_1.jsx)("li", { children: "NFT will be locked as collateral" }), (0, jsx_runtime_1.jsxs)("li", { children: ["Current borrow APR: ", (poolData?.borrow_apr_percent ?? 0).toFixed(2), "%"] }), (0, jsx_runtime_1.jsx)("li", { children: "Failure to repay may result in NFT liquidation" })] })] })] }) }), (0, jsx_runtime_1.jsxs)("div", { className: "flex justify-end gap-3 pt-2", children: [(0, jsx_runtime_1.jsx)("button", { onClick: () => setBorrowOpen(false), className: "px-4 py-2 text-sm border border-neutral-700 rounded text-neutral-400 hover:bg-neutral-800 hover:text-neutral-300 bg-transparent", children: "Cancel" }), (0, jsx_runtime_1.jsx)("button", { onClick: handleBorrow, disabled: isSubmitting || !selectedNFT || !borrowAmount, className: "px-4 py-2 text-sm bg-cyan-700 hover:bg-cyan-600 text-white rounded disabled:opacity-50", children: isSubmitting ? ((0, jsx_runtime_1.jsxs)("span", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)(IconLoader, { className: "h-4 w-4 animate-spin" }), "Processing..."] })) : ('Confirm Borrow') })] })] }) }), (0, jsx_runtime_1.jsx)(Modal, { open: repayOpen, onClose: () => { setRepayOpen(false); setSelectedLoan(null); setRepayAmount(''); }, children: (0, jsx_runtime_1.jsxs)("div", { className: "space-y-4", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-lg font-bold text-white", children: "Repay Loan" }), (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-neutral-400 mt-1", children: selectedLoan
247
+ ? `Repay loan for ${selectedLoan.collateral_nft_type} #${selectedLoan.loan_id}`
248
+ : 'Repay borrowed MCC to release collateral' })] }), selectedLoan && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { className: "p-4 bg-neutral-800 rounded border border-neutral-700", children: (0, jsx_runtime_1.jsxs)("div", { className: "space-y-2", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex justify-between items-center", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-neutral-400", children: "Principal" }), (0, jsx_runtime_1.jsxs)("span", { className: "text-white font-mono", children: [fmtMCC(selectedLoan.principal), " MCC"] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex justify-between items-center", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-neutral-400", children: "Interest" }), (0, jsx_runtime_1.jsxs)("span", { className: "text-cyan-400 font-mono", children: ["+", fmtMCC(selectedLoan.interest_accrued), " MCC"] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "border-t border-neutral-700 pt-2 flex justify-between items-center font-bold", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-neutral-300", children: "Total Debt" }), (0, jsx_runtime_1.jsxs)("span", { className: "text-red-500 font-mono", children: [fmtMCC(selectedLoan.total_owed), " MCC"] })] })] }) }), (0, jsx_runtime_1.jsxs)("div", { className: "space-y-2", children: [(0, jsx_runtime_1.jsx)("label", { className: "text-neutral-400 text-xs tracking-wider", children: "repay_amount (MCC)" }), (0, jsx_runtime_1.jsx)("input", { type: "number", step: "0.01", value: repayAmount, onChange: e => setRepayAmount(e.target.value), placeholder: "Enter repay amount", className: "w-full px-3 py-2 bg-neutral-800 border border-neutral-600 rounded text-white placeholder-neutral-400 outline-none focus:border-cyan-400" }), (0, jsx_runtime_1.jsx)("button", { onClick: () => setRepayAmount((selectedLoan.total_owed / 1000000000).toString()), className: "text-xs text-cyan-400 hover:text-cyan-300", children: "Repay full amount" })] })] })), (0, jsx_runtime_1.jsx)("div", { className: "p-4 bg-cyan-400/10 border border-cyan-400/30 rounded", children: (0, jsx_runtime_1.jsxs)("div", { className: "flex items-start gap-2", children: [(0, jsx_runtime_1.jsx)(IconCheckCircle, { className: "h-4 w-4 text-cyan-400 mt-0.5 shrink-0" }), (0, jsx_runtime_1.jsxs)("div", { className: "text-sm", children: [(0, jsx_runtime_1.jsx)("div", { className: "font-medium text-cyan-400 mb-1", children: "After Full Repay" }), (0, jsx_runtime_1.jsxs)("ul", { className: "list-disc list-inside space-y-1 text-xs text-cyan-400/70", children: [(0, jsx_runtime_1.jsx)("li", { children: "Collateral NFT returned to your wallet" }), (0, jsx_runtime_1.jsx)("li", { children: "Loan record marked as repaid" })] })] })] }) }), (0, jsx_runtime_1.jsxs)("div", { className: "flex justify-end gap-3 pt-2", children: [(0, jsx_runtime_1.jsx)("button", { onClick: () => { setRepayOpen(false); setSelectedLoan(null); setRepayAmount(''); }, className: "px-4 py-2 text-sm border border-neutral-700 rounded text-neutral-400 hover:bg-neutral-800 hover:text-neutral-300 bg-transparent", children: "Cancel" }), (0, jsx_runtime_1.jsx)("button", { onClick: handleRepay, disabled: isSubmitting || !repayAmount, className: "px-4 py-2 text-sm bg-cyan-700 hover:bg-cyan-600 text-white rounded disabled:opacity-50", children: isSubmitting ? ((0, jsx_runtime_1.jsxs)("span", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)(IconLoader, { className: "h-4 w-4 animate-spin" }), "Repaying..."] })) : ('Confirm Repay') })] })] }) })] }));
147
249
  }