@microcosmmoney/portal-react 3.0.0 → 3.2.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.
- package/dist/components/dashboard/assets-summary.d.ts +2 -1
- package/dist/components/dashboard/assets-summary.js +11 -6
- package/dist/components/dashboard/dashboard-overview.d.ts +2 -1
- package/dist/components/dashboard/dashboard-overview.js +11 -2
- package/dist/components/dashboard/ecosystem-stats.d.ts +4 -1
- package/dist/components/dashboard/ecosystem-stats.js +12 -9
- package/dist/components/dashboard/lock-periods.d.ts +4 -1
- package/dist/components/dashboard/lock-periods.js +2 -2
- package/dist/components/dashboard/market-overview-bar.d.ts +4 -1
- package/dist/components/dashboard/market-overview-bar.js +9 -6
- package/dist/components/dashboard/mcc-token-stats.d.ts +4 -1
- package/dist/components/dashboard/mcc-token-stats.js +12 -9
- package/dist/components/dashboard/mcd-stats.d.ts +4 -1
- package/dist/components/dashboard/mcd-stats.js +14 -11
- package/dist/components/dashboard/mining-weight.d.ts +4 -1
- package/dist/components/dashboard/mining-weight.js +10 -7
- package/dist/components/dashboard/minting-stats.d.ts +4 -1
- package/dist/components/dashboard/minting-stats.js +6 -3
- package/dist/components/dashboard/my-mining.d.ts +2 -1
- package/dist/components/dashboard/my-mining.js +4 -2
- package/dist/components/dashboard/price-chart.d.ts +4 -1
- package/dist/components/dashboard/price-chart.js +6 -4
- package/dist/components/dashboard/quick-actions.d.ts +2 -1
- package/dist/components/dashboard/quick-actions.js +52 -37
- package/dist/components/territory/territory-page.js +191 -119
- package/dist/index.d.ts +8 -0
- package/package.json +4 -4
|
@@ -6,163 +6,235 @@ exports.MicrocosmTerritoryPage = MicrocosmTerritoryPage;
|
|
|
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 recharts_1 = require("recharts");
|
|
9
10
|
/* ------------------------------------------------------------------ */
|
|
10
|
-
/* Inline SVG Icons (
|
|
11
|
+
/* Inline SVG Icons (24x24 viewBox, stroke 2, round caps) */
|
|
11
12
|
/* ------------------------------------------------------------------ */
|
|
12
13
|
const IconBuilding2 = ({ className = '' }) => ((0, jsx_runtime_1.jsxs)("svg", { className: className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [(0, jsx_runtime_1.jsx)("path", { d: "M6 22V4a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v18Z" }), (0, jsx_runtime_1.jsx)("path", { d: "M6 12H4a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h2" }), (0, jsx_runtime_1.jsx)("path", { d: "M18 9h2a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2h-2" }), (0, jsx_runtime_1.jsx)("path", { d: "M10 6h4" }), (0, jsx_runtime_1.jsx)("path", { d: "M10 10h4" }), (0, jsx_runtime_1.jsx)("path", { d: "M10 14h4" }), (0, jsx_runtime_1.jsx)("path", { d: "M10 18h4" })] }));
|
|
13
14
|
const IconGrid3x3 = ({ className = '' }) => ((0, jsx_runtime_1.jsxs)("svg", { className: className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [(0, jsx_runtime_1.jsx)("rect", { width: "18", height: "18", x: "3", y: "3", rx: "2" }), (0, jsx_runtime_1.jsx)("path", { d: "M3 9h18" }), (0, jsx_runtime_1.jsx)("path", { d: "M3 15h18" }), (0, jsx_runtime_1.jsx)("path", { d: "M9 3v18" }), (0, jsx_runtime_1.jsx)("path", { d: "M15 3v18" })] }));
|
|
14
15
|
const IconMap = ({ className = '' }) => ((0, jsx_runtime_1.jsxs)("svg", { className: className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [(0, jsx_runtime_1.jsx)("path", { d: "M14.106 5.553a2 2 0 0 0 1.788 0l3.659-1.83A1 1 0 0 1 21 4.619v12.764a1 1 0 0 1-.553.894l-4.553 2.277a2 2 0 0 1-1.788 0l-4.212-2.106a2 2 0 0 0-1.788 0l-3.659 1.83A1 1 0 0 1 3 19.381V6.618a1 1 0 0 1 .553-.894l4.553-2.277a2 2 0 0 1 1.788 0z" }), (0, jsx_runtime_1.jsx)("path", { d: "M15 5.764v15" }), (0, jsx_runtime_1.jsx)("path", { d: "M9 3.236v15" })] }));
|
|
15
16
|
const IconGlobe = ({ className = '' }) => ((0, jsx_runtime_1.jsxs)("svg", { className: className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [(0, jsx_runtime_1.jsx)("circle", { cx: "12", cy: "12", r: "10" }), (0, jsx_runtime_1.jsx)("path", { d: "M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20" }), (0, jsx_runtime_1.jsx)("path", { d: "M2 12h20" })] }));
|
|
16
|
-
const
|
|
17
|
+
const IconUsers = ({ className = '' }) => ((0, jsx_runtime_1.jsxs)("svg", { className: className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [(0, jsx_runtime_1.jsx)("path", { d: "M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2" }), (0, jsx_runtime_1.jsx)("circle", { cx: "9", cy: "7", r: "4" }), (0, jsx_runtime_1.jsx)("path", { d: "M22 21v-2a4 4 0 0 0-3-3.87" }), (0, jsx_runtime_1.jsx)("path", { d: "M16 3.13a4 4 0 0 1 0 7.75" })] }));
|
|
18
|
+
const IconVault = ({ className = '' }) => ((0, jsx_runtime_1.jsxs)("svg", { className: className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [(0, jsx_runtime_1.jsx)("rect", { x: "2", y: "4", width: "20", height: "16", rx: "2" }), (0, jsx_runtime_1.jsx)("circle", { cx: "12", cy: "12", r: "4" }), (0, jsx_runtime_1.jsx)("path", { d: "M12 8v8" }), (0, jsx_runtime_1.jsx)("path", { d: "M8 12h8" }), (0, jsx_runtime_1.jsx)("path", { d: "M2 10h2" }), (0, jsx_runtime_1.jsx)("path", { d: "M2 14h2" }), (0, jsx_runtime_1.jsx)("path", { d: "M20 10h2" }), (0, jsx_runtime_1.jsx)("path", { d: "M20 14h2" })] }));
|
|
19
|
+
const IconZap = ({ className = '' }) => ((0, jsx_runtime_1.jsx)("svg", { className: className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: (0, jsx_runtime_1.jsx)("path", { d: "M13 2 3 14h9l-1 8 10-12h-9l1-8z" }) }));
|
|
17
20
|
const IconSearch = ({ className = '' }) => ((0, jsx_runtime_1.jsxs)("svg", { className: className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [(0, jsx_runtime_1.jsx)("circle", { cx: "11", cy: "11", r: "8" }), (0, jsx_runtime_1.jsx)("path", { d: "m21 21-4.3-4.3" })] }));
|
|
18
|
-
const
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
-
const
|
|
22
|
-
const
|
|
21
|
+
const IconArrowLeft = ({ className = '' }) => ((0, jsx_runtime_1.jsxs)("svg", { className: className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [(0, jsx_runtime_1.jsx)("path", { d: "m12 19-7-7 7-7" }), (0, jsx_runtime_1.jsx)("path", { d: "M19 12H5" })] }));
|
|
22
|
+
const IconShield = ({ className = '' }) => ((0, jsx_runtime_1.jsx)("svg", { className: className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: (0, jsx_runtime_1.jsx)("path", { d: "M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67 0C8.5 20.5 5 18 5 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C15.5 3.8 18 5 20 5a1 1 0 0 1 1 1z" }) }));
|
|
23
|
+
const IconCalendar = ({ className = '' }) => ((0, jsx_runtime_1.jsxs)("svg", { className: className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [(0, jsx_runtime_1.jsx)("path", { d: "M8 2v4" }), (0, jsx_runtime_1.jsx)("path", { d: "M16 2v4" }), (0, jsx_runtime_1.jsx)("rect", { width: "18", height: "18", x: "3", y: "4", rx: "2" }), (0, jsx_runtime_1.jsx)("path", { d: "M3 10h18" })] }));
|
|
24
|
+
const IconImage = ({ className = '' }) => ((0, jsx_runtime_1.jsxs)("svg", { className: className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [(0, jsx_runtime_1.jsx)("rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", ry: "2" }), (0, jsx_runtime_1.jsx)("circle", { cx: "9", cy: "9", r: "2" }), (0, jsx_runtime_1.jsx)("path", { d: "m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21" })] }));
|
|
25
|
+
const IconSettings = ({ className = '' }) => ((0, jsx_runtime_1.jsxs)("svg", { className: className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [(0, jsx_runtime_1.jsx)("path", { d: "M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z" }), (0, jsx_runtime_1.jsx)("circle", { cx: "12", cy: "12", r: "3" })] }));
|
|
26
|
+
const IconEdit3 = ({ className = '' }) => ((0, jsx_runtime_1.jsxs)("svg", { className: className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [(0, jsx_runtime_1.jsx)("path", { d: "M12 20h9" }), (0, jsx_runtime_1.jsx)("path", { d: "M16.376 3.622a1 1 0 0 1 3.002 3.002L7.368 18.635a2 2 0 0 1-.855.506l-2.872.838a.5.5 0 0 1-.62-.62l.838-2.872a2 2 0 0 1 .506-.855z" })] }));
|
|
23
27
|
/* ------------------------------------------------------------------ */
|
|
24
28
|
/* Helpers */
|
|
25
29
|
/* ------------------------------------------------------------------ */
|
|
26
30
|
const fmt = (n) => n.toLocaleString('en-US');
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
return `${address.slice(0, start)}...${address.slice(-end)}`;
|
|
33
|
-
}
|
|
34
|
-
const getNftTypeIcon = (type) => {
|
|
35
|
-
switch (type?.toLowerCase()) {
|
|
36
|
-
case 'station': return (0, jsx_runtime_1.jsx)(IconBuilding2, { className: "w-5 h-5" });
|
|
37
|
-
case 'matrix': return (0, jsx_runtime_1.jsx)(IconGrid3x3, { className: "w-5 h-5" });
|
|
38
|
-
case 'sector': return (0, jsx_runtime_1.jsx)(IconMap, { className: "w-5 h-5" });
|
|
39
|
-
case 'system': return (0, jsx_runtime_1.jsx)(IconGlobe, { className: "w-5 h-5" });
|
|
40
|
-
default: return (0, jsx_runtime_1.jsx)(IconImage, { className: "w-5 h-5" });
|
|
41
|
-
}
|
|
31
|
+
const TECH_BONUS = {
|
|
32
|
+
station: 10,
|
|
33
|
+
matrix: 20,
|
|
34
|
+
sector: 30,
|
|
35
|
+
system: 40,
|
|
42
36
|
};
|
|
43
|
-
const
|
|
37
|
+
const getTypeIcon = (type, className = 'w-5 h-5') => {
|
|
44
38
|
switch (type?.toLowerCase()) {
|
|
45
|
-
case 'station': return
|
|
46
|
-
case 'matrix': return
|
|
47
|
-
case 'sector': return
|
|
48
|
-
case 'system': return
|
|
49
|
-
default: return
|
|
39
|
+
case 'station': return (0, jsx_runtime_1.jsx)(IconBuilding2, { className: className });
|
|
40
|
+
case 'matrix': return (0, jsx_runtime_1.jsx)(IconGrid3x3, { className: className });
|
|
41
|
+
case 'sector': return (0, jsx_runtime_1.jsx)(IconMap, { className: className });
|
|
42
|
+
case 'system': return (0, jsx_runtime_1.jsx)(IconGlobe, { className: className });
|
|
43
|
+
default: return (0, jsx_runtime_1.jsx)(IconSettings, { className: className });
|
|
50
44
|
}
|
|
51
45
|
};
|
|
52
|
-
const
|
|
46
|
+
const getTypeBadgeColor = (type) => {
|
|
53
47
|
switch (type?.toLowerCase()) {
|
|
54
|
-
case 'station': return '
|
|
55
|
-
case 'matrix': return '
|
|
56
|
-
case 'sector': return '
|
|
57
|
-
case 'system': return '
|
|
58
|
-
default: return
|
|
59
|
-
}
|
|
60
|
-
};
|
|
61
|
-
const getStatIcon = (label) => {
|
|
62
|
-
switch (label) {
|
|
63
|
-
case 'Station': return (0, jsx_runtime_1.jsx)(IconBuilding2, { className: "w-4 h-4 text-neutral-400" });
|
|
64
|
-
case 'Matrix': return (0, jsx_runtime_1.jsx)(IconGrid3x3, { className: "w-4 h-4 text-cyan-300" });
|
|
65
|
-
case 'Sector': return (0, jsx_runtime_1.jsx)(IconMap, { className: "w-4 h-4 text-cyan-300" });
|
|
66
|
-
case 'Total Minted': return (0, jsx_runtime_1.jsx)(IconImage, { className: "w-4 h-4 text-cyan-400" });
|
|
67
|
-
default: return null;
|
|
48
|
+
case 'station': return 'border-cyan-400/40 text-cyan-400';
|
|
49
|
+
case 'matrix': return 'border-white/40 text-white';
|
|
50
|
+
case 'sector': return 'border-cyan-300/40 text-cyan-300';
|
|
51
|
+
case 'system': return 'border-cyan-200/40 text-cyan-200';
|
|
52
|
+
default: return 'border-neutral-600 text-neutral-400';
|
|
68
53
|
}
|
|
69
54
|
};
|
|
55
|
+
const UNIT_TYPE_LABELS = [
|
|
56
|
+
{ key: 'all', label: 'All' },
|
|
57
|
+
{ key: 'station', label: 'Station' },
|
|
58
|
+
{ key: 'matrix', label: 'Matrix' },
|
|
59
|
+
{ key: 'sector', label: 'Sector' },
|
|
60
|
+
{ key: 'system', label: 'System' },
|
|
61
|
+
];
|
|
70
62
|
/* ------------------------------------------------------------------ */
|
|
71
|
-
/* Spinner
|
|
63
|
+
/* Spinner / Skeleton */
|
|
72
64
|
/* ------------------------------------------------------------------ */
|
|
73
65
|
function Spinner() {
|
|
74
66
|
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" });
|
|
75
67
|
}
|
|
76
|
-
/* ------------------------------------------------------------------ */
|
|
77
|
-
/* Skeleton */
|
|
78
|
-
/* ------------------------------------------------------------------ */
|
|
79
68
|
function Skeleton({ className = '' }) {
|
|
80
69
|
return (0, jsx_runtime_1.jsx)("div", { className: `animate-pulse bg-neutral-800 rounded-lg ${className}` });
|
|
81
70
|
}
|
|
82
71
|
/* ------------------------------------------------------------------ */
|
|
83
|
-
/*
|
|
72
|
+
/* Territory Card (list view) */
|
|
84
73
|
/* ------------------------------------------------------------------ */
|
|
85
|
-
function
|
|
86
|
-
|
|
74
|
+
function TerritoryCard({ unit, onClick }) {
|
|
75
|
+
const unitType = (unit.unit_type || 'station');
|
|
76
|
+
const techBonus = TECH_BONUS[unitType.toLowerCase()] ?? 0;
|
|
77
|
+
const occupancy = unit.max_capacity && unit.max_capacity > 0
|
|
78
|
+
? Math.round(((unit.member_count ?? 0) / unit.max_capacity) * 100)
|
|
79
|
+
: 0;
|
|
80
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: "bg-neutral-900 border border-neutral-700 rounded-lg hover:border-cyan-400/50 cursor-pointer transition-colors overflow-hidden", onClick: onClick, children: [(0, jsx_runtime_1.jsx)("div", { className: "aspect-[4/3] bg-neutral-800 relative flex items-center justify-center overflow-hidden", children: unit.image_url ? ((0, jsx_runtime_1.jsx)("img", { src: unit.image_url, alt: unit.unit_name, className: "w-full h-full object-cover" })) : ((0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col items-center justify-center text-neutral-600", children: [getTypeIcon(unitType, 'w-10 h-10'), (0, jsx_runtime_1.jsx)("span", { className: "text-xs mt-2 capitalize", children: unitType })] })) }), (0, jsx_runtime_1.jsxs)("div", { className: "p-3 space-y-2", style: { backgroundColor: '#0a0e14' }, children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2 flex-wrap", children: [(0, jsx_runtime_1.jsx)("span", { className: `border px-1.5 py-0.5 rounded text-xs capitalize ${getTypeBadgeColor(unitType)}`, children: unitType }), (0, jsx_runtime_1.jsxs)("span", { className: "text-xs text-yellow-400", children: [(0, jsx_runtime_1.jsx)(IconZap, { className: "w-3 h-3 inline-block -mt-0.5 mr-0.5" }), "+", techBonus, "%"] }), unit.short_id && ((0, jsx_runtime_1.jsx)("span", { className: "text-xs text-neutral-500 font-mono ml-auto", children: unit.short_id }))] }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-white font-bold text-sm truncate", children: unit.unit_name }), unit.full_path && ((0, jsx_runtime_1.jsx)("p", { className: "text-neutral-500 text-xs font-mono truncate", children: unit.full_path }))] }), unit.description && ((0, jsx_runtime_1.jsx)("p", { className: "text-neutral-400 text-xs line-clamp-2", children: unit.description })), (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-4 pt-2 border-t border-neutral-700/50 text-xs text-neutral-400", children: [(0, jsx_runtime_1.jsxs)("span", { className: "flex items-center gap-1", children: [(0, jsx_runtime_1.jsx)(IconUsers, { className: "w-3.5 h-3.5" }), fmt(unit.member_count ?? 0)] }), (0, jsx_runtime_1.jsxs)("span", { className: "flex items-center gap-1", children: [(0, jsx_runtime_1.jsx)(IconVault, { className: "w-3.5 h-3.5" }), fmt(Math.round(unit.vault_balance ?? 0)), " MCD"] }), (0, jsx_runtime_1.jsxs)("span", { className: "ml-auto", children: [occupancy, "%"] })] })] })] }));
|
|
81
|
+
}
|
|
82
|
+
/* ------------------------------------------------------------------ */
|
|
83
|
+
/* Detail View */
|
|
84
|
+
/* ------------------------------------------------------------------ */
|
|
85
|
+
/* ------------------------------------------------------------------ */
|
|
86
|
+
/* Income Chart (recharts LineChart) */
|
|
87
|
+
/* ------------------------------------------------------------------ */
|
|
88
|
+
function IncomeChart({ territoryId }) {
|
|
89
|
+
const { data: raw, loading } = (0, auth_react_1.useTerritoryIncome)(territoryId, '30d');
|
|
90
|
+
const uid = (0, react_1.useId)();
|
|
91
|
+
const chartData = (0, react_1.useMemo)(() => {
|
|
92
|
+
if (!raw)
|
|
93
|
+
return [];
|
|
94
|
+
// API may return { labels, datasets: { income, cumulative } } or array
|
|
95
|
+
if (Array.isArray(raw))
|
|
96
|
+
return raw;
|
|
97
|
+
if (raw.labels && raw.datasets) {
|
|
98
|
+
return raw.labels.map((label, i) => ({
|
|
99
|
+
date: label,
|
|
100
|
+
income: raw.datasets.income?.[i] ?? 0,
|
|
101
|
+
cumulative: raw.datasets.cumulative?.[i] ?? 0,
|
|
102
|
+
}));
|
|
103
|
+
}
|
|
104
|
+
return raw.data ?? [];
|
|
105
|
+
}, [raw]);
|
|
106
|
+
if (loading)
|
|
107
|
+
return (0, jsx_runtime_1.jsx)("div", { className: "bg-neutral-900 border border-neutral-700 rounded-lg p-6", children: (0, jsx_runtime_1.jsx)("div", { className: "h-64 flex items-center justify-center", children: (0, jsx_runtime_1.jsx)(Spinner, {}) }) });
|
|
108
|
+
if (chartData.length === 0)
|
|
87
109
|
return null;
|
|
88
|
-
return ((0, jsx_runtime_1.jsxs)("div", { className: "
|
|
110
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: "bg-neutral-900 border border-neutral-700 rounded-lg hover:border-cyan-400/50 transition-colors p-6", children: [(0, jsx_runtime_1.jsxs)("h3", { className: "text-white font-semibold mb-4 flex items-center gap-2 text-sm", children: [(0, jsx_runtime_1.jsx)(IconZap, { className: "w-4 h-4 text-cyan-400" }), "Income Trend (30D)"] }), (0, jsx_runtime_1.jsx)("div", { className: "h-64", children: (0, jsx_runtime_1.jsx)(recharts_1.ResponsiveContainer, { width: "100%", height: "100%", children: (0, jsx_runtime_1.jsxs)(recharts_1.LineChart, { data: chartData, margin: { top: 5, right: 10, left: 0, bottom: 5 }, children: [(0, jsx_runtime_1.jsx)(recharts_1.CartesianGrid, { strokeDasharray: "3 3", stroke: "#404040" }), (0, jsx_runtime_1.jsx)(recharts_1.XAxis, { dataKey: "date", tick: { fill: '#a3a3a3', fontSize: 11 }, axisLine: { stroke: '#525252' } }), (0, jsx_runtime_1.jsx)(recharts_1.YAxis, { tick: { fill: '#a3a3a3', fontSize: 11 }, axisLine: { stroke: '#525252' } }), (0, jsx_runtime_1.jsx)(recharts_1.Tooltip, { contentStyle: { backgroundColor: '#171717', border: '1px solid #404040', borderRadius: '8px' }, labelStyle: { color: '#a3a3a3' }, itemStyle: { color: '#fff' } }), (0, jsx_runtime_1.jsx)(recharts_1.Line, { type: "monotone", dataKey: "income", name: "Daily Income", stroke: "#22d3ee", strokeWidth: 2, dot: false, activeDot: { r: 4 } }), (0, jsx_runtime_1.jsx)(recharts_1.Line, { type: "monotone", dataKey: "cumulative", name: "Cumulative", stroke: "#ffffff", strokeWidth: 2, dot: false, activeDot: { r: 4 } })] }) }) }), (0, jsx_runtime_1.jsxs)("div", { className: "flex justify-center gap-6 mt-3", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)("div", { className: "w-3 h-0.5 bg-cyan-400" }), (0, jsx_runtime_1.jsx)("span", { className: "text-xs text-neutral-400", children: "Daily Income" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)("div", { className: "w-3 h-0.5 bg-white" }), (0, jsx_runtime_1.jsx)("span", { className: "text-xs text-neutral-400", children: "Cumulative" })] })] })] }));
|
|
89
111
|
}
|
|
90
112
|
/* ------------------------------------------------------------------ */
|
|
91
|
-
/*
|
|
113
|
+
/* Member Ranking */
|
|
92
114
|
/* ------------------------------------------------------------------ */
|
|
93
|
-
|
|
94
|
-
|
|
115
|
+
const RANK_BADGE = { 1: 'bg-cyan-400/20 text-cyan-400', 2: 'bg-white/20 text-white', 3: 'bg-cyan-300/20 text-cyan-300' };
|
|
116
|
+
function MemberRanking({ territoryId }) {
|
|
117
|
+
const { data: raw, loading } = (0, auth_react_1.useTerritoryRanking)(territoryId, { page_size: 10 });
|
|
118
|
+
const rankList = (0, react_1.useMemo)(() => {
|
|
119
|
+
if (!raw)
|
|
120
|
+
return [];
|
|
121
|
+
return Array.isArray(raw) ? raw : raw.data ?? [];
|
|
122
|
+
}, [raw]);
|
|
123
|
+
if (loading)
|
|
124
|
+
return (0, jsx_runtime_1.jsx)("div", { className: "bg-neutral-900 border border-neutral-700 rounded-lg p-6", children: (0, jsx_runtime_1.jsx)("div", { className: "h-64 flex items-center justify-center", children: (0, jsx_runtime_1.jsx)(Spinner, {}) }) });
|
|
125
|
+
if (rankList.length === 0)
|
|
126
|
+
return null;
|
|
127
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: "bg-neutral-900 border border-neutral-700 rounded-lg hover:border-cyan-400/50 transition-colors p-6", children: [(0, jsx_runtime_1.jsxs)("h3", { className: "text-white font-semibold mb-4 flex items-center gap-2 text-sm", children: [(0, jsx_runtime_1.jsx)(IconShield, { className: "w-4 h-4 text-cyan-400" }), "Member Contribution Ranking"] }), (0, jsx_runtime_1.jsx)("div", { className: "space-y-2", children: rankList.map((m, idx) => {
|
|
128
|
+
const rank = m.rank ?? idx + 1;
|
|
129
|
+
const name = m.nickname || m.display_name || 'Unknown';
|
|
130
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-3 p-2 bg-neutral-800 rounded hover:bg-neutral-700 transition-colors", children: [(0, jsx_runtime_1.jsx)("div", { className: "w-8 text-center", children: rank <= 3 ? ((0, jsx_runtime_1.jsxs)("span", { className: `inline-block px-1.5 py-0.5 rounded text-xs font-bold ${RANK_BADGE[rank] ?? ''}`, children: ["#", rank] })) : ((0, jsx_runtime_1.jsxs)("span", { className: "text-neutral-500 font-mono text-sm", children: ["#", rank] })) }), (0, jsx_runtime_1.jsx)("div", { className: "w-8 h-8 rounded-full bg-neutral-700 flex items-center justify-center text-xs text-white font-bold flex-shrink-0", children: name.slice(0, 2).toUpperCase() }), (0, jsx_runtime_1.jsxs)("div", { className: "flex-1 min-w-0", children: [(0, jsx_runtime_1.jsx)("div", { className: "text-white text-sm truncate", children: name }), m.email && (0, jsx_runtime_1.jsx)("div", { className: "text-neutral-500 text-xs truncate", children: m.email })] }), (0, jsx_runtime_1.jsxs)("div", { className: "text-right flex-shrink-0", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-white font-mono font-medium text-sm", children: (m.contribution ?? 0).toLocaleString() }), (0, jsx_runtime_1.jsx)("span", { className: "text-neutral-500 text-xs ml-1", children: "MCD" })] })] }, m.user_id || idx));
|
|
131
|
+
}) })] }));
|
|
95
132
|
}
|
|
96
133
|
/* ------------------------------------------------------------------ */
|
|
97
|
-
/*
|
|
134
|
+
/* KPI History Chart (recharts AreaChart) */
|
|
98
135
|
/* ------------------------------------------------------------------ */
|
|
99
|
-
function
|
|
100
|
-
const
|
|
101
|
-
const
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
const
|
|
114
|
-
const
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
const
|
|
122
|
-
|
|
136
|
+
function KPIHistoryChart({ territoryId }) {
|
|
137
|
+
const { data: raw, loading } = (0, auth_react_1.useTerritoryKPI)(territoryId);
|
|
138
|
+
const uid = (0, react_1.useId)();
|
|
139
|
+
const chartData = (0, react_1.useMemo)(() => {
|
|
140
|
+
if (!raw)
|
|
141
|
+
return [];
|
|
142
|
+
if (Array.isArray(raw))
|
|
143
|
+
return raw;
|
|
144
|
+
return raw.data ?? [];
|
|
145
|
+
}, [raw]);
|
|
146
|
+
if (loading)
|
|
147
|
+
return (0, jsx_runtime_1.jsx)("div", { className: "bg-neutral-900 border border-neutral-700 rounded-lg p-6", children: (0, jsx_runtime_1.jsx)("div", { className: "h-64 flex items-center justify-center", children: (0, jsx_runtime_1.jsx)(Spinner, {}) }) });
|
|
148
|
+
if (chartData.length === 0)
|
|
149
|
+
return null;
|
|
150
|
+
const gradMember = `kpi-member-${uid}`;
|
|
151
|
+
const gradVolume = `kpi-volume-${uid}`;
|
|
152
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: "bg-neutral-900 border border-neutral-700 rounded-lg hover:border-cyan-400/50 transition-colors p-6", children: [(0, jsx_runtime_1.jsxs)("h3", { className: "text-white font-semibold mb-4 flex items-center gap-2 text-sm", children: [(0, jsx_runtime_1.jsx)(IconEdit3, { className: "w-4 h-4 text-cyan-400" }), "KPI History"] }), (0, jsx_runtime_1.jsx)("div", { className: "h-64", children: (0, jsx_runtime_1.jsx)(recharts_1.ResponsiveContainer, { width: "100%", height: "100%", children: (0, jsx_runtime_1.jsxs)(recharts_1.AreaChart, { data: chartData, margin: { top: 5, right: 10, left: 0, bottom: 5 }, children: [(0, jsx_runtime_1.jsxs)("defs", { children: [(0, jsx_runtime_1.jsxs)("linearGradient", { id: gradMember, x1: "0", y1: "0", x2: "0", y2: "1", children: [(0, jsx_runtime_1.jsx)("stop", { offset: "5%", stopColor: "#22d3ee", stopOpacity: 0.3 }), (0, jsx_runtime_1.jsx)("stop", { offset: "95%", stopColor: "#22d3ee", stopOpacity: 0 })] }), (0, jsx_runtime_1.jsxs)("linearGradient", { id: gradVolume, x1: "0", y1: "0", x2: "0", y2: "1", children: [(0, jsx_runtime_1.jsx)("stop", { offset: "5%", stopColor: "#ffffff", stopOpacity: 0.3 }), (0, jsx_runtime_1.jsx)("stop", { offset: "95%", stopColor: "#ffffff", stopOpacity: 0 })] })] }), (0, jsx_runtime_1.jsx)(recharts_1.CartesianGrid, { strokeDasharray: "3 3", stroke: "#404040" }), (0, jsx_runtime_1.jsx)(recharts_1.XAxis, { dataKey: "date", tick: { fill: '#a3a3a3', fontSize: 11 }, axisLine: { stroke: '#525252' } }), (0, jsx_runtime_1.jsx)(recharts_1.YAxis, { domain: [0, 100], tick: { fill: '#a3a3a3', fontSize: 11 }, axisLine: { stroke: '#525252' }, tickFormatter: (v) => `${v}%` }), (0, jsx_runtime_1.jsx)(recharts_1.Tooltip, { contentStyle: { backgroundColor: '#171717', border: '1px solid #404040', borderRadius: '8px' }, labelStyle: { color: '#a3a3a3' }, formatter: (value) => [`${Number(value).toFixed(1)}%`, ''] }), (0, jsx_runtime_1.jsx)(recharts_1.Area, { type: "monotone", dataKey: "member_progress", name: "Member Progress", stroke: "#22d3ee", strokeWidth: 2, fill: `url(#${gradMember})` }), (0, jsx_runtime_1.jsx)(recharts_1.Area, { type: "monotone", dataKey: "volume_progress", name: "Volume Progress", stroke: "#ffffff", strokeWidth: 2, fill: `url(#${gradVolume})` })] }) }) }), (0, jsx_runtime_1.jsxs)("div", { className: "flex justify-center gap-6 mt-3", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)("div", { className: "w-3 h-3 rounded-full bg-cyan-400" }), (0, jsx_runtime_1.jsx)("span", { className: "text-xs text-neutral-400", children: "Member Progress" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)("div", { className: "w-3 h-3 rounded-full bg-white" }), (0, jsx_runtime_1.jsx)("span", { className: "text-xs text-neutral-400", children: "Volume Progress" })] })] })] }));
|
|
153
|
+
}
|
|
154
|
+
/* ------------------------------------------------------------------ */
|
|
155
|
+
/* Edit Territory Dialog */
|
|
156
|
+
/* ------------------------------------------------------------------ */
|
|
157
|
+
function EditTerritoryDialog({ territory, open, onClose, onSaved }) {
|
|
158
|
+
const { update, loading: updating } = (0, auth_react_1.useTerritoryUpdate)();
|
|
159
|
+
const [name, setName] = (0, react_1.useState)(territory.unit_name);
|
|
160
|
+
const [desc, setDesc] = (0, react_1.useState)(territory.description || '');
|
|
161
|
+
const [error, setError] = (0, react_1.useState)('');
|
|
162
|
+
const handleSave = (0, react_1.useCallback)(async () => {
|
|
163
|
+
if (!name.trim()) {
|
|
164
|
+
setError('Name is required');
|
|
123
165
|
return;
|
|
124
|
-
try {
|
|
125
|
-
setSearching(true);
|
|
126
|
-
const res = await api.get(`/territory/nft/${searchQuery.trim()}`);
|
|
127
|
-
const data = res?.data;
|
|
128
|
-
if (data && typeof data === 'object' && 'success' in data && data.success && data.data) {
|
|
129
|
-
setSearchResults([data.data]);
|
|
130
|
-
}
|
|
131
|
-
else if (data && data.mint) {
|
|
132
|
-
setSearchResults([data]);
|
|
133
|
-
}
|
|
134
|
-
else {
|
|
135
|
-
setSearchResults([]);
|
|
136
|
-
}
|
|
137
166
|
}
|
|
138
|
-
|
|
139
|
-
|
|
167
|
+
try {
|
|
168
|
+
setError('');
|
|
169
|
+
await update(territory.unit_id, { unit_name: name, description: desc });
|
|
170
|
+
onSaved();
|
|
171
|
+
onClose();
|
|
140
172
|
}
|
|
141
|
-
|
|
142
|
-
|
|
173
|
+
catch (e) {
|
|
174
|
+
setError(e.message || 'Update failed');
|
|
143
175
|
}
|
|
144
|
-
}, [
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
},
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
176
|
+
}, [update, territory.unit_id, name, desc, onSaved, onClose]);
|
|
177
|
+
if (!open)
|
|
178
|
+
return null;
|
|
179
|
+
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: "fixed inset-0 bg-black/60" }), (0, jsx_runtime_1.jsxs)("div", { className: "relative bg-neutral-900 border border-neutral-700 rounded-lg w-full max-w-lg p-6 space-y-4 mx-4", onClick: (e) => e.stopPropagation(), children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-white font-bold text-lg", children: "Edit Territory" }), (0, jsx_runtime_1.jsxs)("p", { className: "text-neutral-500 text-xs font-mono mt-1", children: [territory.unit_type, " \u00B7 ", territory.full_path || territory.short_id || territory.unit_id] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "space-y-3", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("label", { className: "text-xs text-neutral-400 tracking-wider block mb-1", children: "unit_name *" }), (0, jsx_runtime_1.jsx)("input", { value: name, onChange: (e) => setName(e.target.value), className: "w-full bg-neutral-800 border border-neutral-700 text-white px-3 py-2 rounded text-sm focus:border-cyan-400/50 outline-none" })] }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("label", { className: "text-xs text-neutral-400 tracking-wider block mb-1", children: "description" }), (0, jsx_runtime_1.jsx)("textarea", { value: desc, onChange: (e) => setDesc(e.target.value), rows: 3, className: "w-full bg-neutral-800 border border-neutral-700 text-white px-3 py-2 rounded text-sm focus:border-cyan-400/50 outline-none resize-none" })] })] }), error && (0, jsx_runtime_1.jsx)("p", { className: "text-red-400 text-xs", children: error }), (0, jsx_runtime_1.jsxs)("div", { className: "flex justify-end gap-3 pt-2", children: [(0, jsx_runtime_1.jsx)("button", { onClick: onClose, disabled: updating, className: "px-4 py-2 text-sm text-neutral-400 border border-neutral-700 rounded hover:bg-neutral-800 transition-colors", children: "Cancel" }), (0, jsx_runtime_1.jsx)("button", { onClick: handleSave, disabled: updating, className: "px-4 py-2 text-sm text-white bg-cyan-700 hover:bg-cyan-600 rounded transition-colors disabled:opacity-50", children: updating ? 'Saving...' : 'Save' })] })] })] }));
|
|
180
|
+
}
|
|
181
|
+
/* ------------------------------------------------------------------ */
|
|
182
|
+
/* Detail View (full) */
|
|
183
|
+
/* ------------------------------------------------------------------ */
|
|
184
|
+
function TerritoryDetailView({ territoryId, territory, onBack }) {
|
|
185
|
+
const { data: detailedStats, loading: statsLoading } = (0, auth_react_1.useTerritoryDetailedStats)(territoryId);
|
|
186
|
+
const { data: members, loading: membersLoading } = (0, auth_react_1.useTerritoryMembers)(territoryId);
|
|
187
|
+
const [editOpen, setEditOpen] = (0, react_1.useState)(false);
|
|
188
|
+
const stats = detailedStats;
|
|
189
|
+
const memberList = Array.isArray(members) ? members : [];
|
|
190
|
+
const unitType = (territory?.unit_type || 'station');
|
|
191
|
+
const techBonus = TECH_BONUS[unitType.toLowerCase()] ?? 0;
|
|
192
|
+
const memberCount = territory?.member_count ?? stats?.stats?.member_count ?? stats?.metrics?.member_count ?? 0;
|
|
193
|
+
const maxCapacity = territory?.max_capacity ?? stats?.stats?.max_capacity ?? stats?.metrics?.max_capacity ?? 0;
|
|
194
|
+
const vaultBalance = territory?.vault_balance ?? stats?.stats?.vault_balance ?? stats?.metrics?.vault_mcd ?? 0;
|
|
195
|
+
const occupancy = maxCapacity > 0 ? Math.round((memberCount / maxCapacity) * 100) : 0;
|
|
196
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: "space-y-6", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between", children: [(0, jsx_runtime_1.jsxs)("button", { onClick: onBack, className: "flex items-center gap-2 text-sm text-neutral-400 hover:text-white transition-colors bg-transparent border-none cursor-pointer", children: [(0, jsx_runtime_1.jsx)(IconArrowLeft, { className: "w-4 h-4" }), "Back to list"] }), territory && ((0, jsx_runtime_1.jsxs)("button", { onClick: () => setEditOpen(true), className: "flex items-center gap-1.5 px-3 py-1.5 text-sm text-white bg-cyan-700 hover:bg-cyan-600 rounded transition-colors", children: [(0, jsx_runtime_1.jsx)(IconEdit3, { className: "w-3.5 h-3.5" }), "Edit"] }))] }), (0, jsx_runtime_1.jsx)("div", { className: "bg-neutral-900 border border-neutral-700 rounded-lg hover:border-cyan-400/50 transition-colors p-6", children: (0, jsx_runtime_1.jsxs)("div", { className: "flex items-start gap-5", children: [(0, jsx_runtime_1.jsx)("div", { className: "w-28 h-28 bg-neutral-800 rounded-lg flex items-center justify-center overflow-hidden flex-shrink-0", children: territory?.image_url ? ((0, jsx_runtime_1.jsx)("img", { src: territory.image_url, alt: territory.unit_name, className: "w-full h-full object-cover" })) : ((0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col items-center text-neutral-600", children: [getTypeIcon(unitType, 'w-10 h-10'), (0, jsx_runtime_1.jsx)("span", { className: "text-[10px] mt-1 capitalize", children: unitType })] })) }), (0, jsx_runtime_1.jsxs)("div", { className: "flex-1 min-w-0", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-3 flex-wrap", children: [(0, jsx_runtime_1.jsx)("h2", { className: "text-xl font-bold text-white", children: territory?.unit_name ?? territoryId }), territory?.short_id && ((0, jsx_runtime_1.jsx)("span", { className: "text-sm text-neutral-400 font-mono bg-neutral-800 px-2 py-0.5 rounded", children: territory.short_id })), (0, jsx_runtime_1.jsx)("span", { className: `border px-1.5 py-0.5 rounded text-xs capitalize ${getTypeBadgeColor(unitType)}`, children: unitType }), occupancy >= 90 ? ((0, jsx_runtime_1.jsx)("span", { className: "text-xs bg-white/20 text-white px-1.5 py-0.5 rounded", children: "Qualified" })) : ((0, jsx_runtime_1.jsx)("span", { className: "text-xs bg-neutral-500/20 text-neutral-400 px-1.5 py-0.5 rounded", children: "Not Qualified" }))] }), territory?.manager_display_name && ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-1.5 mt-2 text-xs text-emerald-400", children: [(0, jsx_runtime_1.jsx)(IconShield, { className: "w-3.5 h-3.5" }), "Magistrate: ", territory.manager_display_name] })), territory?.full_path && ((0, jsx_runtime_1.jsx)("p", { className: "text-neutral-500 text-sm font-mono mt-1", children: territory.full_path })), territory?.description && ((0, jsx_runtime_1.jsx)("p", { className: "text-neutral-400 text-sm mt-2", children: territory.description }))] })] }) }), statsLoading ? ((0, jsx_runtime_1.jsx)("div", { className: "grid grid-cols-2 md:grid-cols-4 gap-4", children: [...Array(4)].map((_, i) => (0, jsx_runtime_1.jsx)(Skeleton, { className: "h-24" }, i)) })) : ((0, jsx_runtime_1.jsxs)("div", { className: "grid grid-cols-2 md:grid-cols-4 gap-4", children: [(0, jsx_runtime_1.jsxs)("div", { className: "bg-neutral-900 border border-neutral-700 rounded-lg hover:border-cyan-400/50 transition-colors p-4", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2 mb-2", children: [(0, jsx_runtime_1.jsx)(IconUsers, { className: "w-5 h-5 text-neutral-400" }), (0, jsx_runtime_1.jsx)("span", { className: "text-xs text-neutral-400", children: "Members" })] }), (0, jsx_runtime_1.jsx)("p", { className: "text-2xl font-bold text-white font-mono", children: fmt(memberCount) }), (0, jsx_runtime_1.jsxs)("p", { className: "text-xs text-neutral-500 mt-1", children: ["Capacity: ", (0, jsx_runtime_1.jsx)("span", { className: "font-mono", children: fmt(maxCapacity) })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "bg-neutral-900 border border-neutral-700 rounded-lg hover:border-cyan-400/50 transition-colors p-4", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2 mb-2", children: [(0, jsx_runtime_1.jsx)(IconVault, { className: "w-5 h-5 text-neutral-400" }), (0, jsx_runtime_1.jsx)("span", { className: "text-xs text-neutral-400", children: "Vault Balance" })] }), (0, jsx_runtime_1.jsx)("p", { className: "text-2xl font-bold text-white font-mono", children: fmt(Math.round(vaultBalance)) }), (0, jsx_runtime_1.jsx)("p", { className: "text-xs text-neutral-500 mt-1", children: "MCD" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "bg-neutral-900 border border-neutral-700 rounded-lg hover:border-cyan-400/50 transition-colors p-4", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2 mb-2", children: [(0, jsx_runtime_1.jsx)(IconZap, { className: "w-5 h-5 text-yellow-400" }), (0, jsx_runtime_1.jsx)("span", { className: "text-xs text-neutral-400", children: "Tech Bonus" })] }), (0, jsx_runtime_1.jsxs)("p", { className: "text-2xl font-bold text-white font-mono", children: ["+", stats?.tech_bonus ?? techBonus, "%"] }), (0, jsx_runtime_1.jsx)("p", { className: "text-xs text-neutral-500 mt-1", children: "Mining output bonus" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "bg-neutral-900 border border-neutral-700 rounded-lg hover:border-cyan-400/50 transition-colors p-4", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2 mb-2", children: [(0, jsx_runtime_1.jsx)(IconSettings, { className: "w-5 h-5 text-neutral-400" }), (0, jsx_runtime_1.jsx)("span", { className: "text-xs text-neutral-400", children: "Occupancy" })] }), (0, jsx_runtime_1.jsxs)("p", { className: "text-2xl font-bold text-white font-mono", children: [occupancy, "%"] }), (0, jsx_runtime_1.jsx)("p", { className: "text-xs text-neutral-500 mt-1", children: "Members / Capacity" })] })] })), (0, jsx_runtime_1.jsxs)("div", { className: "bg-neutral-900 border border-neutral-700 rounded-lg hover:border-cyan-400/50 transition-colors p-6", children: [(0, jsx_runtime_1.jsxs)("h3", { className: "text-white font-semibold mb-4 flex items-center gap-2 text-sm", children: [(0, jsx_runtime_1.jsx)(IconEdit3, { className: "w-4 h-4 text-cyan-400" }), "KPI Progress"] }), (0, jsx_runtime_1.jsxs)("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-6", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between text-sm mb-2", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-neutral-400", children: "Members" }), (0, jsx_runtime_1.jsxs)("span", { className: "text-white font-mono", children: [fmt(memberCount), " / ", fmt(maxCapacity)] })] }), (0, jsx_runtime_1.jsx)("div", { className: "h-2 bg-neutral-800 rounded-full overflow-hidden", children: (0, jsx_runtime_1.jsx)("div", { className: "h-full bg-cyan-400 rounded-full transition-all duration-500", style: { width: `${Math.min(occupancy, 100)}%` } }) }), (0, jsx_runtime_1.jsxs)("p", { className: "text-xs text-neutral-500 font-mono mt-1", children: [occupancy, "% filled"] })] }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between text-sm mb-2", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-neutral-400", children: "Vault Balance" }), (0, jsx_runtime_1.jsxs)("span", { className: "text-white font-mono", children: [fmt(Math.round(vaultBalance)), " MCD"] })] }), (0, jsx_runtime_1.jsx)("div", { className: "h-2 bg-neutral-800 rounded-full overflow-hidden", children: (0, jsx_runtime_1.jsx)("div", { className: "h-full bg-cyan-400 rounded-full transition-all duration-500", style: { width: `${Math.min(vaultBalance > 0 ? Math.max(Math.log10(vaultBalance) * 10, 5) : 0, 100)}%` } }) }), (0, jsx_runtime_1.jsx)("p", { className: "text-xs text-neutral-500 mt-1", children: "Current vault funds" })] })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "bg-neutral-900 border border-neutral-700 rounded-lg hover:border-cyan-400/50 transition-colors p-6", children: [(0, jsx_runtime_1.jsxs)("h3", { className: "text-white font-semibold mb-3 flex items-center gap-2 text-sm", children: [(0, jsx_runtime_1.jsx)(IconSettings, { className: "w-4 h-4 text-cyan-400" }), "Distribution Mechanism"] }), (0, jsx_runtime_1.jsxs)("div", { className: "bg-neutral-800 rounded p-4", children: [(0, jsx_runtime_1.jsx)("h4", { className: "text-white font-semibold text-sm mb-2", children: "Auto Distribution by Contribution" }), (0, jsx_runtime_1.jsx)("p", { className: "text-neutral-400 text-sm", children: "Vault MCD is distributed daily at 1% of balance, allocated to miners proportional to their mining activity." }), (0, jsx_runtime_1.jsx)("p", { className: "text-neutral-500 text-xs mt-2", children: "Distribution ratio: Miners 100% (by contribution)" })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "grid grid-cols-1 lg:grid-cols-2 gap-6", children: [(0, jsx_runtime_1.jsx)(IncomeChart, { territoryId: territoryId }), (0, jsx_runtime_1.jsx)(MemberRanking, { territoryId: territoryId })] }), (0, jsx_runtime_1.jsx)(KPIHistoryChart, { territoryId: territoryId }), (0, jsx_runtime_1.jsxs)("div", { className: "bg-neutral-900 border border-neutral-700 rounded-lg hover:border-cyan-400/50 transition-colors", children: [(0, jsx_runtime_1.jsx)("div", { className: "p-4 border-b border-neutral-700/50", children: (0, jsx_runtime_1.jsxs)("h3", { className: "text-white font-semibold flex items-center gap-2 text-sm", children: [(0, jsx_runtime_1.jsx)(IconUsers, { className: "w-4 h-4 text-cyan-400" }), "Members (", memberList.length, ")"] }) }), (0, jsx_runtime_1.jsx)("div", { className: "overflow-x-auto", children: membersLoading ? ((0, jsx_runtime_1.jsx)("div", { className: "p-6 flex justify-center", children: (0, jsx_runtime_1.jsx)(Spinner, {}) })) : memberList.length === 0 ? ((0, jsx_runtime_1.jsx)("div", { className: "p-8 text-center text-neutral-500 text-sm", children: "No members found" })) : ((0, jsx_runtime_1.jsxs)("table", { className: "w-full text-sm", children: [(0, jsx_runtime_1.jsx)("thead", { children: (0, jsx_runtime_1.jsxs)("tr", { className: "border-b border-neutral-700/50", children: [(0, jsx_runtime_1.jsx)("th", { className: "text-left px-4 py-3 text-neutral-400 font-medium", children: "Name / UID" }), (0, jsx_runtime_1.jsx)("th", { className: "text-left px-4 py-3 text-neutral-400 font-medium", children: "Role" }), (0, jsx_runtime_1.jsx)("th", { className: "text-left px-4 py-3 text-neutral-400 font-medium", children: "Email" }), (0, jsx_runtime_1.jsx)("th", { className: "text-left px-4 py-3 text-neutral-400 font-medium", children: "Joined" })] }) }), (0, jsx_runtime_1.jsx)("tbody", { children: memberList.map((member, idx) => ((0, jsx_runtime_1.jsxs)("tr", { className: "border-b border-neutral-800/50 hover:bg-neutral-800/30", children: [(0, jsx_runtime_1.jsxs)("td", { className: "px-4 py-3", children: [(0, jsx_runtime_1.jsx)("div", { className: "text-white", children: member.display_name || member.username || 'Unknown' }), (0, jsx_runtime_1.jsx)("div", { className: "text-neutral-500 text-xs font-mono", children: member.uid ? `${member.uid.slice(0, 12)}...` : '-' })] }), (0, jsx_runtime_1.jsx)("td", { className: "px-4 py-3", children: (0, jsx_runtime_1.jsx)("span", { className: "text-neutral-300 capitalize", children: member.role || member.level_name || 'Miner' }) }), (0, jsx_runtime_1.jsx)("td", { className: "px-4 py-3", children: (0, jsx_runtime_1.jsx)("span", { className: "text-neutral-400 font-mono text-xs", children: member.email ? (member.email.length > 20 ? member.email.slice(0, 20) + '...' : member.email) : '-' }) }), (0, jsx_runtime_1.jsx)("td", { className: "px-4 py-3", children: (0, jsx_runtime_1.jsxs)("span", { className: "text-neutral-400 flex items-center gap-1", children: [(0, jsx_runtime_1.jsx)(IconCalendar, { className: "w-3 h-3" }), member.joined_at || member.created_at ? new Date(member.joined_at || member.created_at).toLocaleDateString() : '-'] }) })] }, member.uid || idx))) })] })) })] }), territory && ((0, jsx_runtime_1.jsx)(EditTerritoryDialog, { territory: territory, open: editOpen, onClose: () => setEditOpen(false), onSaved: () => { } }))] }));
|
|
197
|
+
}
|
|
198
|
+
/* ------------------------------------------------------------------ */
|
|
199
|
+
/* Main Component */
|
|
200
|
+
/* ------------------------------------------------------------------ */
|
|
201
|
+
function MicrocosmTerritoryPage({ basePath = '', onNavigate }) {
|
|
202
|
+
const [selectedId, setSelectedId] = (0, react_1.useState)(null);
|
|
203
|
+
const [filterType, setFilterType] = (0, react_1.useState)('all');
|
|
204
|
+
const [searchTerm, setSearchTerm] = (0, react_1.useState)('');
|
|
205
|
+
const { data: summary, loading: summaryLoading } = (0, auth_react_1.useTerritorySummary)();
|
|
206
|
+
const { data: territories, loading: territoriesLoading } = (0, auth_react_1.useTerritories)(filterType === 'all' ? {} : { unitType: filterType });
|
|
207
|
+
const territoryList = Array.isArray(territories) ? territories : [];
|
|
208
|
+
const sum = summary;
|
|
209
|
+
// Client-side search filtering
|
|
210
|
+
const filteredTerritories = (0, react_1.useMemo)(() => {
|
|
211
|
+
if (!searchTerm.trim())
|
|
212
|
+
return territoryList;
|
|
213
|
+
const q = searchTerm.toLowerCase();
|
|
214
|
+
return territoryList.filter((t) => (t.unit_name && t.unit_name.toLowerCase().includes(q)) ||
|
|
215
|
+
(t.description && t.description.toLowerCase().includes(q)) ||
|
|
216
|
+
(t.short_id && t.short_id.toLowerCase().includes(q)) ||
|
|
217
|
+
(t.full_path && t.full_path.toLowerCase().includes(q)));
|
|
218
|
+
}, [territoryList, searchTerm]);
|
|
219
|
+
// Find selected territory object for detail view
|
|
220
|
+
const selectedTerritory = selectedId
|
|
221
|
+
? territoryList.find((t) => t.unit_id === selectedId)
|
|
222
|
+
: undefined;
|
|
223
|
+
/* -- Detail view -- */
|
|
224
|
+
if (selectedId) {
|
|
225
|
+
return ((0, jsx_runtime_1.jsx)(TerritoryDetailView, { territoryId: selectedId, territory: selectedTerritory, onBack: () => setSelectedId(null) }));
|
|
226
|
+
}
|
|
227
|
+
/* -- List view -- */
|
|
228
|
+
// Loading skeleton for initial load
|
|
229
|
+
if (summaryLoading && territoriesLoading) {
|
|
230
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: "space-y-6", children: [(0, jsx_runtime_1.jsx)("div", { className: "flex items-center justify-between", children: (0, jsx_runtime_1.jsx)(Skeleton, { className: "h-8 w-56" }) }), (0, jsx_runtime_1.jsx)("div", { className: "grid grid-cols-2 md:grid-cols-4 gap-4", children: [...Array(4)].map((_, i) => (0, jsx_runtime_1.jsx)(Skeleton, { className: "h-24" }, i)) }), (0, jsx_runtime_1.jsx)(Skeleton, { className: "h-14" }), (0, jsx_runtime_1.jsx)("div", { className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4", children: [...Array(6)].map((_, i) => (0, jsx_runtime_1.jsx)(Skeleton, { className: "h-72" }, i)) })] }));
|
|
157
231
|
}
|
|
158
|
-
return ((0, jsx_runtime_1.jsxs)("div", { className: "space-y-6", children: [(0, jsx_runtime_1.jsxs)("div", {
|
|
159
|
-
{ label: '
|
|
160
|
-
{ label: '
|
|
161
|
-
{ label: '
|
|
162
|
-
{ label: '
|
|
163
|
-
].map((s) => ((0, jsx_runtime_1.jsxs)("div", { className: "bg-neutral-900 border border-neutral-700 rounded-lg
|
|
164
|
-
? 'bg-
|
|
165
|
-
: 'text-neutral-
|
|
166
|
-
? 'bg-neutral-700 text-white'
|
|
167
|
-
: 'text-neutral-500 hover:text-neutral-300'}`, children: "All NFTs" })] }), (0, jsx_runtime_1.jsx)("div", { className: "mt-4", children: activeTab === 'my' ? (nftsLoading ? ((0, jsx_runtime_1.jsx)("div", { className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4", children: [...Array(4)].map((_, i) => ((0, jsx_runtime_1.jsx)(Skeleton, { className: "h-64" }, i))) })) : nftList.length === 0 ? ((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-8 text-center", children: [(0, jsx_runtime_1.jsx)(IconImage, { className: "w-12 h-12 mx-auto mb-4 text-neutral-600" }), (0, jsx_runtime_1.jsx)("p", { className: "text-neutral-400", children: "No territory NFTs found" }), (0, jsx_runtime_1.jsx)("p", { className: "text-xs text-neutral-500 mt-1", children: "Territory NFTs will appear here once assigned" })] }) })) : ((0, jsx_runtime_1.jsx)("div", { className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4", children: nftList.map((nft) => ((0, jsx_runtime_1.jsx)(NFTCard, { nft: nft, onClick: () => openNftDetail(nft) }, nft.mint))) }))) : ((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-8 text-center", children: [(0, jsx_runtime_1.jsx)(IconSearch, { className: "w-12 h-12 mx-auto mb-4 text-neutral-600" }), (0, jsx_runtime_1.jsx)("p", { className: "text-neutral-400", children: "Use the search above to find specific NFTs" }), (0, jsx_runtime_1.jsx)("p", { className: "text-xs text-neutral-500 mt-1", children: "Enter a mint address to look up any territory NFT" })] }) })) })] }), (0, jsx_runtime_1.jsx)(Modal, { open: showNftDetail, onClose: () => setShowNftDetail(false), children: selectedNft && ((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsxs)("div", { className: "p-6 pb-0", children: [(0, jsx_runtime_1.jsx)("h2", { className: "text-lg font-semibold text-white", children: selectedNft.name }), (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-neutral-400", children: "NFT Details" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "p-6 space-y-4", children: [(0, jsx_runtime_1.jsx)("div", { className: "aspect-square bg-neutral-800 rounded-lg flex items-center justify-center overflow-hidden", children: selectedNft.image ? ((0, jsx_runtime_1.jsx)("img", { src: selectedNft.image, alt: selectedNft.name, className: "w-full h-full object-cover" })) : ((0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col items-center justify-center text-neutral-600", children: [getNftTypeIcon(selectedNft.nft_type), (0, jsx_runtime_1.jsx)("span", { className: "text-sm mt-2", children: "No Image" })] })) }), (0, jsx_runtime_1.jsxs)("div", { className: "space-y-3", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-neutral-400 text-sm", children: "Type" }), (0, jsx_runtime_1.jsx)("span", { className: `text-xs px-2 py-0.5 rounded border ${getNftTypeColor(selectedNft.nft_type)}`, children: getNftTypeLabel(selectedNft.nft_type) })] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-neutral-400 text-sm", children: "Unit ID" }), (0, jsx_runtime_1.jsx)("span", { className: "text-white font-mono text-sm", children: selectedNft.unit_id })] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-neutral-400 text-sm", children: "Symbol" }), (0, jsx_runtime_1.jsx)("span", { className: "text-white font-mono text-sm", children: selectedNft.symbol })] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-neutral-400 text-sm", children: "Mint Address" }), (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-white font-mono text-xs", children: truncateAddress(selectedNft.mint, 8, 8) }), (0, jsx_runtime_1.jsx)("button", { onClick: () => copyAddress(selectedNft.mint), className: "text-neutral-400 hover:text-white transition-colors", children: copiedAddress === selectedNft.mint ? ((0, jsx_runtime_1.jsx)(IconCheckCircle, { className: "w-4 h-4 text-white" })) : ((0, jsx_runtime_1.jsx)(IconCopy, { className: "w-4 h-4" })) })] })] }), selectedNft.owner && ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-neutral-400 text-sm", children: "Owner" }), (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-white font-mono text-xs", children: truncateAddress(selectedNft.owner, 8, 8) }), (0, jsx_runtime_1.jsx)("button", { onClick: () => copyAddress(selectedNft.owner), className: "text-neutral-400 hover:text-white transition-colors", children: copiedAddress === selectedNft.owner ? ((0, jsx_runtime_1.jsx)(IconCheckCircle, { className: "w-4 h-4 text-white" })) : ((0, jsx_runtime_1.jsx)(IconCopy, { className: "w-4 h-4" })) })] })] })), selectedNft.created_at && ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-neutral-400 text-sm", children: "Created" }), (0, jsx_runtime_1.jsx)("span", { className: "text-white text-sm", children: new Date(selectedNft.created_at * 1000).toLocaleString() })] }))] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex gap-2 pt-2", children: [(0, jsx_runtime_1.jsxs)("button", { className: "flex-1 flex items-center justify-center gap-2 px-3 py-2 text-sm border border-neutral-700 rounded-lg text-neutral-300 hover:bg-neutral-800 transition-colors bg-transparent", onClick: () => window.open(`https://explorer.solana.com/address/${selectedNft.mint}`, '_blank'), children: [(0, jsx_runtime_1.jsx)(IconExternalLink, { className: "w-4 h-4" }), "Solana Explorer"] }), selectedNft.uri && ((0, jsx_runtime_1.jsxs)("button", { className: "flex-1 flex items-center justify-center gap-2 px-3 py-2 text-sm border border-neutral-700 rounded-lg text-neutral-300 hover:bg-neutral-800 transition-colors bg-transparent", onClick: () => window.open(selectedNft.uri, '_blank'), children: [(0, jsx_runtime_1.jsx)(IconExternalLink, { className: "w-4 h-4" }), "Metadata"] }))] })] })] })) })] }));
|
|
232
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: "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: "Territory Management" }), (0, jsx_runtime_1.jsx)("p", { className: "text-neutral-400 text-sm mt-1", children: "Manage territories, view KPI and vault balances" })] }), (0, jsx_runtime_1.jsx)("div", { className: "grid grid-cols-2 md:grid-cols-4 gap-4", children: [
|
|
233
|
+
{ label: 'Total Territories', value: sum?.total_stations ?? 0, icon: (0, jsx_runtime_1.jsx)(IconBuilding2, { className: "w-4 h-4 text-cyan-400" }), suffix: '' },
|
|
234
|
+
{ label: 'Total Members', value: sum?.total_members ?? 0, icon: (0, jsx_runtime_1.jsx)(IconUsers, { className: "w-4 h-4 text-neutral-400" }), suffix: '' },
|
|
235
|
+
{ label: 'Total Vault MCD', value: Math.round(sum?.total_vault_mcd ?? 0), icon: (0, jsx_runtime_1.jsx)(IconVault, { className: "w-4 h-4 text-neutral-400" }), suffix: ' MCD' },
|
|
236
|
+
{ label: 'Avg KPI', value: sum?.avg_kpi_score != null ? Math.round(sum.avg_kpi_score * 100) : 0, icon: (0, jsx_runtime_1.jsx)(IconEdit3, { className: "w-4 h-4 text-neutral-400" }), suffix: '%' },
|
|
237
|
+
].map((s) => ((0, jsx_runtime_1.jsxs)("div", { className: "bg-neutral-900 border border-neutral-700 rounded-lg hover:border-cyan-400/50 transition-colors p-4", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2 mb-2", children: [s.icon, (0, jsx_runtime_1.jsx)("span", { className: "text-sm text-neutral-400", children: s.label })] }), (0, jsx_runtime_1.jsx)("p", { className: "text-2xl font-bold text-white font-mono", children: summaryLoading ? (0, jsx_runtime_1.jsx)(Spinner, {}) : (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [fmt(s.value), s.suffix] }) })] }, s.label))) }), (0, jsx_runtime_1.jsx)("div", { className: "bg-neutral-900 border border-neutral-700 rounded-lg hover:border-cyan-400/50 transition-colors p-4", children: (0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col sm:flex-row gap-3", children: [(0, jsx_runtime_1.jsxs)("div", { className: "relative flex-1", children: [(0, jsx_runtime_1.jsx)(IconSearch, { className: "w-4 h-4 absolute left-3 top-1/2 -translate-y-1/2 text-neutral-500" }), (0, jsx_runtime_1.jsx)("input", { type: "text", placeholder: "Search territories...", value: searchTerm, onChange: (e) => setSearchTerm(e.target.value), className: "w-full pl-10 pr-3 py-2 bg-neutral-800 border border-neutral-700 rounded-lg text-white text-sm placeholder:text-neutral-500 outline-none focus:border-cyan-400/50 transition-colors" })] }), (0, jsx_runtime_1.jsx)("div", { className: "flex gap-2 flex-wrap", children: UNIT_TYPE_LABELS.map((ut) => ((0, jsx_runtime_1.jsx)("button", { onClick: () => setFilterType(ut.key), className: `px-3 py-2 text-sm rounded-lg border transition-colors ${filterType === ut.key
|
|
238
|
+
? 'bg-cyan-700 text-white border-cyan-700'
|
|
239
|
+
: 'bg-transparent border-neutral-700 text-neutral-400 hover:text-neutral-200 hover:border-neutral-500'}`, children: ut.label }, ut.key))) })] }) }), territoriesLoading ? ((0, jsx_runtime_1.jsx)("div", { className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4", children: [...Array(6)].map((_, i) => (0, jsx_runtime_1.jsx)(Skeleton, { className: "h-72" }, i)) })) : filteredTerritories.length === 0 ? ((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-12 text-center", children: [(0, jsx_runtime_1.jsx)(IconImage, { className: "w-12 h-12 mx-auto mb-4 text-neutral-600" }), (0, jsx_runtime_1.jsx)("p", { className: "text-neutral-400", children: "No territories found" }), searchTerm && ((0, jsx_runtime_1.jsx)("p", { className: "text-xs text-neutral-500 mt-1", children: "Try adjusting your search or filter criteria" }))] }) })) : ((0, jsx_runtime_1.jsx)("div", { className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4", children: filteredTerritories.map((unit) => ((0, jsx_runtime_1.jsx)(TerritoryCard, { unit: unit, onClick: () => setSelectedId(unit.unit_id) }, unit.unit_id))) }))] }));
|
|
168
240
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -26,19 +26,27 @@ export type { KPIRadialChartProps } from './components/kpi-radial-chart';
|
|
|
26
26
|
export { MicrocosmDashboardOverview } from './components/dashboard/dashboard-overview';
|
|
27
27
|
export type { MicrocosmDashboardOverviewProps } from './components/dashboard/dashboard-overview';
|
|
28
28
|
export { MicrocosmMarketBar } from './components/dashboard/market-overview-bar';
|
|
29
|
+
export type { MicrocosmMarketBarProps } from './components/dashboard/market-overview-bar';
|
|
29
30
|
export { MicrocosmQuickActions } from './components/dashboard/quick-actions';
|
|
30
31
|
export type { MicrocosmQuickActionsProps } from './components/dashboard/quick-actions';
|
|
31
32
|
export { MicrocosmAssetsSummary } from './components/dashboard/assets-summary';
|
|
32
33
|
export type { MicrocosmAssetsSummaryProps } from './components/dashboard/assets-summary';
|
|
33
34
|
export { MicrocosmPriceChart } from './components/dashboard/price-chart';
|
|
35
|
+
export type { MicrocosmPriceChartProps } from './components/dashboard/price-chart';
|
|
34
36
|
export { MicrocosmMintingStats } from './components/dashboard/minting-stats';
|
|
37
|
+
export type { MicrocosmMintingStatsProps } from './components/dashboard/minting-stats';
|
|
35
38
|
export { MicrocosmMiningWeight } from './components/dashboard/mining-weight';
|
|
39
|
+
export type { MicrocosmMiningWeightProps } from './components/dashboard/mining-weight';
|
|
36
40
|
export { MicrocosmMyMining } from './components/dashboard/my-mining';
|
|
37
41
|
export type { MicrocosmMyMiningProps } from './components/dashboard/my-mining';
|
|
38
42
|
export { MicrocosmEcosystemStats } from './components/dashboard/ecosystem-stats';
|
|
43
|
+
export type { MicrocosmEcosystemStatsProps } from './components/dashboard/ecosystem-stats';
|
|
39
44
|
export { MicrocosmMCCTokenStats } from './components/dashboard/mcc-token-stats';
|
|
45
|
+
export type { MicrocosmMCCTokenStatsProps } from './components/dashboard/mcc-token-stats';
|
|
40
46
|
export { MicrocosmMCDStats } from './components/dashboard/mcd-stats';
|
|
47
|
+
export type { MicrocosmMCDStatsProps } from './components/dashboard/mcd-stats';
|
|
41
48
|
export { MicrocosmLockPeriods } from './components/dashboard/lock-periods';
|
|
49
|
+
export type { MicrocosmLockPeriodsProps } from './components/dashboard/lock-periods';
|
|
42
50
|
export { MicrocosmFragmentPage } from './components/fragment/fragment-page';
|
|
43
51
|
export type { MicrocosmFragmentPageProps } from './components/fragment/fragment-page';
|
|
44
52
|
export { MicrocosmLendingPage } from './components/lending/lending-page';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@microcosmmoney/portal-react",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.2.0",
|
|
4
4
|
"description": "Microcosm Portal UI components for React/Next.js",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -14,12 +14,12 @@
|
|
|
14
14
|
"peerDependencies": {
|
|
15
15
|
"react": ">=18.0.0",
|
|
16
16
|
"react-dom": ">=18.0.0",
|
|
17
|
-
"recharts": ">=2.0.0"
|
|
17
|
+
"recharts": ">=2.0.0",
|
|
18
|
+
"lucide-react": ">=0.300.0"
|
|
18
19
|
},
|
|
19
20
|
"dependencies": {
|
|
20
21
|
"@microcosmmoney/auth-core": "file:../auth-core",
|
|
21
|
-
"@microcosmmoney/auth-react": "file:../auth-react"
|
|
22
|
-
"lucide-react": ">=0.300.0"
|
|
22
|
+
"@microcosmmoney/auth-react": "file:../auth-react"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"@types/react": "^18.0.0",
|