@microcosmmoney/portal-react 3.9.0 → 3.11.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/auction/auction-page.js +11 -9
- package/dist/components/dashboard/assets-summary.js +5 -3
- package/dist/components/dashboard/dashboard-overview.js +5 -2
- package/dist/components/dashboard/ecosystem-stats.js +7 -5
- package/dist/components/dashboard/lock-periods.js +3 -1
- package/dist/components/dashboard/market-overview-bar.js +8 -6
- package/dist/components/dashboard/mcc-token-stats.js +7 -5
- package/dist/components/dashboard/mcd-stats.js +7 -5
- package/dist/components/dashboard/mining-weight.js +3 -1
- package/dist/components/dashboard/minting-stats.js +5 -3
- package/dist/components/dashboard/my-mining.js +9 -7
- package/dist/components/dashboard/price-chart.js +4 -2
- package/dist/components/fragment/fragment-page.js +3 -1
- package/dist/components/income/manager-income-page.js +5 -3
- package/dist/components/lending/lending-page.js +3 -1
- package/dist/components/mcd/mcd-page.js +7 -5
- package/dist/components/mining/mining-page.js +5 -3
- package/dist/components/profile/email-change-card.js +5 -3
- package/dist/components/profile/profile-page.js +10 -8
- package/dist/components/profile/two-factor-settings.js +6 -4
- package/dist/components/queue/queue-status-page.js +4 -2
- package/dist/components/reincarnation/reincarnation-page.js +6 -2
- package/dist/components/rewards/rewards-page.js +5 -3
- package/dist/components/stations/station-list-page.js +10 -8
- package/dist/components/territory/territory-page.js +5 -3
- package/dist/components/voting/voting-page.js +3 -1
- package/dist/components/wallet/wallet-page.js +42 -29
- package/dist/config/mainstream-tokens.d.ts +13 -0
- package/dist/config/mainstream-tokens.js +64 -0
- package/dist/i18n-context.d.ts +11 -0
- package/dist/i18n-context.js +59 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +6 -2
- package/package.json +1 -1
|
@@ -6,6 +6,7 @@ const jsx_runtime_1 = require("react/jsx-runtime");
|
|
|
6
6
|
const react_1 = require("react");
|
|
7
7
|
const auth_react_1 = require("@microcosmmoney/auth-react");
|
|
8
8
|
const terminal_1 = require("../terminal");
|
|
9
|
+
const i18n_context_1 = require("../../i18n-context");
|
|
9
10
|
const email_change_card_1 = require("./email-change-card");
|
|
10
11
|
const two_factor_settings_1 = require("./two-factor-settings");
|
|
11
12
|
const API_BASE = 'https://api.microcosm.money/v1';
|
|
@@ -17,6 +18,7 @@ const LEVEL_INFO = {
|
|
|
17
18
|
admiral: { label: 'Admiral', description: 'Auto-minted System NFT (≥10 Sector)', color: 'text-red-400' },
|
|
18
19
|
};
|
|
19
20
|
function MicrocosmProfilePage({ walletSection, } = {}) {
|
|
21
|
+
const t = (0, i18n_context_1.useTranslations)('profile');
|
|
20
22
|
const api = (0, auth_react_1.useMicrocosmApi)();
|
|
21
23
|
const { getAccessToken } = (0, auth_react_1.useMicrocosmContext)();
|
|
22
24
|
const authState = (0, auth_react_1.useAuth)();
|
|
@@ -78,11 +80,11 @@ function MicrocosmProfilePage({ walletSection, } = {}) {
|
|
|
78
80
|
if (!file)
|
|
79
81
|
return;
|
|
80
82
|
if (!file.type.startsWith('image/')) {
|
|
81
|
-
setError('Please select an image file');
|
|
83
|
+
setError(t('selectImageFile', 'Please select an image file'));
|
|
82
84
|
return;
|
|
83
85
|
}
|
|
84
86
|
if (file.size > 2 * 1024 * 1024) {
|
|
85
|
-
setError('Image must
|
|
87
|
+
setError(t('imageTooLarge', 'Image must not exceed 2MB'));
|
|
86
88
|
return;
|
|
87
89
|
}
|
|
88
90
|
setUploadingAvatar(true);
|
|
@@ -126,20 +128,20 @@ function MicrocosmProfilePage({ walletSection, } = {}) {
|
|
|
126
128
|
}
|
|
127
129
|
};
|
|
128
130
|
if (loading) {
|
|
129
|
-
return ((0, jsx_runtime_1.jsxs)("div", { className: "max-w-7xl mx-auto px-3 py-4 space-y-3 xs:px-4 xs:space-y-4 sm:px-6 sm:py-6 sm:space-y-6 font-mono", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h1", { className: "text-lg sm:text-2xl font-bold text-white tracking-wider", children:
|
|
131
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: "max-w-7xl mx-auto px-3 py-4 space-y-3 xs:px-4 xs:space-y-4 sm:px-6 sm:py-6 sm:space-y-6 font-mono", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h1", { className: "text-lg sm:text-2xl font-bold text-white tracking-wider", children: t('title', 'Profile') }), (0, jsx_runtime_1.jsx)("p", { className: "text-xs sm:text-sm text-neutral-400", children: t('subtitle', 'View and manage your personal information') })] }), (0, jsx_runtime_1.jsx)("div", { className: "flex items-center justify-center py-20", children: (0, jsx_runtime_1.jsx)("span", { className: "text-neutral-400", children: t('loadingProfile', 'Loading profile...') }) })] }));
|
|
130
132
|
}
|
|
131
133
|
const displayName = profile?.display_name || profile?.email?.split('@')[0] || 'user';
|
|
132
134
|
const lvl = (levelData?.current_rank || levelData?.database_level || 'miner').toLowerCase();
|
|
133
135
|
const lvlInfo = LEVEL_INFO[lvl] || LEVEL_INFO.miner;
|
|
134
|
-
return ((0, jsx_runtime_1.jsxs)("div", { className: "max-w-7xl mx-auto px-3 py-4 space-y-3 xs:px-4 xs:space-y-4 sm:px-6 sm:py-6 sm:space-y-6 font-mono", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h1", { className: "text-lg sm:text-2xl font-bold text-white tracking-wider", children:
|
|
136
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: "max-w-7xl mx-auto px-3 py-4 space-y-3 xs:px-4 xs:space-y-4 sm:px-6 sm:py-6 sm:space-y-6 font-mono", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h1", { className: "text-lg sm:text-2xl font-bold text-white tracking-wider", children: t('title', 'Profile') }), (0, jsx_runtime_1.jsx)("p", { className: "text-xs sm:text-sm text-neutral-400", children: t('subtitle', 'View and manage your personal information') })] }), error && ((0, jsx_runtime_1.jsx)("div", { className: "p-3 bg-red-900/20 border border-red-800 rounded text-sm text-red-300", children: error })), (0, jsx_runtime_1.jsxs)(terminal_1.TerminalCard, { children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-start gap-4 mb-6 pb-6 border-b border-neutral-700", children: [(0, jsx_runtime_1.jsxs)("div", { className: "relative group", children: [profile?.avatar_url ? ((0, jsx_runtime_1.jsx)("img", { src: profile.avatar_url, alt: "", className: "h-20 w-20 rounded bg-neutral-800 border border-neutral-700 object-cover" })) : ((0, jsx_runtime_1.jsx)("div", { className: "h-20 w-20 rounded bg-cyan-400/20 border border-cyan-400/30 flex items-center justify-center text-cyan-400 text-3xl font-bold", children: displayName.charAt(0).toUpperCase() })), (0, jsx_runtime_1.jsx)("button", { onClick: () => fileInputRef.current?.click(), disabled: uploadingAvatar, className: "absolute inset-0 bg-black/50 rounded opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center text-white text-xs disabled:opacity-30", children: uploadingAvatar ? '...' : t('edit', 'edit') }), (0, jsx_runtime_1.jsx)("input", { ref: fileInputRef, type: "file", accept: "image/jpeg,image/png,image/gif,image/webp", onChange: handleAvatarChange, className: "hidden" })] }), (0, jsx_runtime_1.jsx)("div", { className: "flex-1", children: editing ? ((0, jsx_runtime_1.jsxs)("div", { className: "space-y-3", children: [(0, jsx_runtime_1.jsx)("input", { type: "text", value: editName, onChange: (e) => setEditName(e.target.value), className: "w-full bg-neutral-800 border border-neutral-600 rounded px-3 py-2 text-white text-sm focus:outline-none focus:border-cyan-400", placeholder: t('displayName', 'Display name') }), (0, jsx_runtime_1.jsxs)("div", { className: "flex gap-2", children: [(0, jsx_runtime_1.jsx)("button", { onClick: handleSave, disabled: saving, className: "px-3 py-1.5 bg-cyan-700 hover:bg-cyan-600 text-white rounded text-sm disabled:opacity-50", children: saving ? t('saving', 'Saving...') : t('save', 'Save') }), (0, jsx_runtime_1.jsx)("button", { onClick: () => {
|
|
135
137
|
setEditName(profile?.display_name || '');
|
|
136
138
|
setEditing(false);
|
|
137
|
-
}, disabled: saving, className: "px-3 py-1.5 border border-neutral-700 text-neutral-400 hover:bg-neutral-800 rounded text-sm", children:
|
|
139
|
+
}, disabled: saving, className: "px-3 py-1.5 border border-neutral-700 text-neutral-400 hover:bg-neutral-800 rounded text-sm", children: t('cancel', 'Cancel') })] })] })) : ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)("div", { className: "text-lg text-white", children: displayName }), (0, jsx_runtime_1.jsxs)("button", { onClick: () => setEditing(true), className: "text-xs text-neutral-500 hover:text-cyan-400", children: ["[", t('edit', 'edit'), "]"] })] }), (0, jsx_runtime_1.jsx)("div", { className: "text-sm text-neutral-400 mt-1", children: profile?.email || t('noEmail', '(no email)') }), (0, jsx_runtime_1.jsxs)("div", { className: "flex gap-2 mt-2", children: [(0, jsx_runtime_1.jsx)("span", { className: "px-2 py-0.5 bg-neutral-800 text-neutral-300 rounded text-xs border border-neutral-700", children: profile?.role || t('normalUser', 'user') }), profile?.email_verified ? ((0, jsx_runtime_1.jsx)("span", { className: "px-2 py-0.5 bg-green-900/30 text-green-400 rounded text-xs border border-green-800", children: t('verified', 'verified') })) : ((0, jsx_runtime_1.jsx)("span", { className: "px-2 py-0.5 bg-red-900/30 text-red-400 rounded text-xs border border-red-800", children: t('unverified', 'unverified') }))] })] })) })] }), (0, jsx_runtime_1.jsxs)("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: [(0, jsx_runtime_1.jsxs)("div", { className: "bg-white/5 border border-white/10 rounded-lg p-4 blockchain-sub-card", children: [(0, jsx_runtime_1.jsx)("div", { className: "text-xs text-neutral-400 tracking-wider mb-1", children: "UID" }), (0, jsx_runtime_1.jsx)("div", { className: "text-xs text-white font-mono break-all", children: profile?.uid || userInfo?.uid || '-' })] }), (0, jsx_runtime_1.jsxs)("div", { className: "bg-white/5 border border-white/10 rounded-lg p-4 blockchain-sub-card", children: [(0, jsx_runtime_1.jsx)("div", { className: "text-xs text-neutral-400 tracking-wider mb-1", children: t('shortId', 'Short ID') }), (0, jsx_runtime_1.jsx)("div", { className: "text-sm text-white font-mono", children: profile?.short_id || '-' })] }), (0, jsx_runtime_1.jsxs)("div", { className: "bg-white/5 border border-white/10 rounded-lg p-4 blockchain-sub-card", children: [(0, jsx_runtime_1.jsx)("div", { className: "text-xs text-neutral-400 tracking-wider mb-1", children: t('created', 'Created') }), (0, jsx_runtime_1.jsx)("div", { className: "text-sm text-white", children: formatDate(profile?.created_at) })] }), (0, jsx_runtime_1.jsxs)("div", { className: "bg-white/5 border border-white/10 rounded-lg p-4 blockchain-sub-card", children: [(0, jsx_runtime_1.jsx)("div", { className: "text-xs text-neutral-400 tracking-wider mb-1", children: t('lastLogin', 'Last Login') }), (0, jsx_runtime_1.jsx)("div", { className: "text-sm text-white", children: formatDate(profile?.last_login_at) })] })] })] }), levelData && ((0, jsx_runtime_1.jsx)(terminal_1.TerminalCard, { title: t('levelStatus', 'Level Status'), children: (0, jsx_runtime_1.jsxs)("div", { className: "space-y-4", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between p-4 bg-neutral-800 rounded", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("div", { className: "text-xs text-neutral-400 tracking-wider mb-1", children: t('currentLevel', 'CURRENT LEVEL') }), (0, jsx_runtime_1.jsx)("div", { className: `text-xl font-bold ${lvlInfo.color}`, children: lvlInfo.label }), (0, jsx_runtime_1.jsx)("div", { className: "text-xs text-neutral-500 mt-1", children: lvlInfo.description })] }), (0, jsx_runtime_1.jsxs)("div", { className: "text-right", children: [(0, jsx_runtime_1.jsx)("div", { className: "text-xs text-neutral-400 tracking-wider mb-1", children: t('holdings', 'HOLDINGS') }), (0, jsx_runtime_1.jsxs)("div", { className: "text-xs text-white font-mono", children: ["S:", levelData.holdings?.station ?? 0, " M:", levelData.holdings?.matrix ?? 0, " Se:", levelData.holdings?.sector ?? 0, " Sy:", levelData.holdings?.system ?? 0] })] })] }), levelData.next_level_requirement && ((0, jsx_runtime_1.jsxs)("div", { className: "p-4 bg-neutral-800 rounded", 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: t('progress', 'PROGRESS') }), (0, jsx_runtime_1.jsxs)("span", { className: "text-white text-sm font-mono", children: [levelData.progress_percent ?? 0, "%"] })] }), (0, jsx_runtime_1.jsx)("div", { className: "w-full bg-neutral-900 rounded-full h-2", children: (0, jsx_runtime_1.jsx)("div", { className: "h-2 rounded-full bg-cyan-400 transition-all", style: { width: `${Math.min(levelData.progress_percent ?? 0, 100)}%` } }) }), (0, jsx_runtime_1.jsx)("div", { className: "text-xs text-neutral-500 mt-2", children: levelData.next_level_requirement.description || '' }), (0, jsx_runtime_1.jsxs)("div", { className: "text-xs text-neutral-400 mt-1", children: [levelData.next_level_requirement.have, "/", levelData.next_level_requirement.need, ' ', levelData.next_level_requirement.tier, " \u2192 ", ' ', (0, jsx_runtime_1.jsx)("span", { className: "text-white", children: levelData.next_rank })] })] }))] }) })), (0, jsx_runtime_1.jsx)(terminal_1.TerminalCard, { title: t('emailVerification', 'Email Verification'), children: (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.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("div", { className: "text-xs text-neutral-400 tracking-wider mb-1", children: t('status', 'STATUS') }), profile?.email_verified ? ((0, jsx_runtime_1.jsx)("div", { className: "text-green-400 text-sm", children: t('statusVerified', 'Verified') })) : ((0, jsx_runtime_1.jsx)("div", { className: "text-red-400 text-sm", children: t('statusUnverified', 'Unverified') }))] }), !profile?.email_verified && ((0, jsx_runtime_1.jsx)("button", { onClick: async () => {
|
|
138
140
|
setResendingVerification(true);
|
|
139
141
|
setResendMessage(null);
|
|
140
142
|
try {
|
|
141
143
|
await api.post('/users/me/resend-verification', {});
|
|
142
|
-
setResendMessage('Verification email sent — check your inbox');
|
|
144
|
+
setResendMessage(t('verificationSent', 'Verification email sent — check your inbox'));
|
|
143
145
|
}
|
|
144
146
|
catch (e) {
|
|
145
147
|
setResendMessage(e instanceof Error ? e.message : 'Failed to send');
|
|
@@ -147,7 +149,7 @@ function MicrocosmProfilePage({ walletSection, } = {}) {
|
|
|
147
149
|
finally {
|
|
148
150
|
setResendingVerification(false);
|
|
149
151
|
}
|
|
150
|
-
}, disabled: resendingVerification, className: "px-3 py-1.5 border border-cyan-800 text-cyan-400 hover:bg-cyan-950 rounded text-xs disabled:opacity-50", children: resendingVerification ? 'Sending...' : 'Resend Email' }))] }), resendMessage && ((0, jsx_runtime_1.jsx)("div", { className: "text-xs text-cyan-400", children: resendMessage }))] }) }), (0, jsx_runtime_1.jsx)(email_change_card_1.MicrocosmEmailChangeCard, { onSuccess: (newEmail) => {
|
|
152
|
+
}, disabled: resendingVerification, className: "px-3 py-1.5 border border-cyan-800 text-cyan-400 hover:bg-cyan-950 rounded text-xs disabled:opacity-50", children: resendingVerification ? t('sending', 'Sending...') : t('resendEmail', 'Resend Email') }))] }), resendMessage && ((0, jsx_runtime_1.jsx)("div", { className: "text-xs text-cyan-400", children: resendMessage }))] }) }), (0, jsx_runtime_1.jsx)(email_change_card_1.MicrocosmEmailChangeCard, { onSuccess: (newEmail) => {
|
|
151
153
|
setProfile(prev => (prev ? { ...prev, email: newEmail, email_verified: true } : prev));
|
|
152
|
-
} }), (0, jsx_runtime_1.jsx)(two_factor_settings_1.MicrocosmTwoFactorSettings, {}), walletSection, (0, jsx_runtime_1.jsxs)(terminal_1.TerminalCard, { children: [(0, jsx_runtime_1.jsxs)("div", { className: "text-neutral-400 text-sm mb-3", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-cyan-400", children: "!" }), " Security
|
|
154
|
+
} }), (0, jsx_runtime_1.jsx)(two_factor_settings_1.MicrocosmTwoFactorSettings, {}), walletSection, (0, jsx_runtime_1.jsxs)(terminal_1.TerminalCard, { children: [(0, jsx_runtime_1.jsxs)("div", { className: "text-neutral-400 text-sm mb-3", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-cyan-400", children: "!" }), " ", t('securityTitle', 'Security')] }), (0, jsx_runtime_1.jsxs)("div", { className: "space-y-1 text-sm text-neutral-400", children: [(0, jsx_runtime_1.jsxs)("p", { children: ["- ", t('securityTip1', 'Keep your account credentials secure')] }), (0, jsx_runtime_1.jsxs)("p", { children: ["- ", t('securityTip2', 'Change password periodically via main portal')] }), (0, jsx_runtime_1.jsxs)("p", { children: ["- ", t('securityTip3', 'Report suspicious activity immediately')] }), (0, jsx_runtime_1.jsxs)("p", { children: ["- ", t('securityTip4', 'Verify your email to receive important notifications')] })] })] })] }));
|
|
153
155
|
}
|
|
@@ -6,7 +6,9 @@ const jsx_runtime_1 = require("react/jsx-runtime");
|
|
|
6
6
|
const react_1 = require("react");
|
|
7
7
|
const auth_react_1 = require("@microcosmmoney/auth-react");
|
|
8
8
|
const terminal_1 = require("../terminal");
|
|
9
|
+
const i18n_context_1 = require("../../i18n-context");
|
|
9
10
|
function MicrocosmTwoFactorSettings({} = {}) {
|
|
11
|
+
const t = (0, i18n_context_1.useTranslations)('profile');
|
|
10
12
|
const { status, setupData, loading, error, beginSetup, verifySetup, disable, clearError, clearSetup, } = (0, auth_react_1.useTwoFactor)();
|
|
11
13
|
const [step, setStep] = (0, react_1.useState)('idle');
|
|
12
14
|
const [verifyCode, setVerifyCode] = (0, react_1.useState)('');
|
|
@@ -59,15 +61,15 @@ function MicrocosmTwoFactorSettings({} = {}) {
|
|
|
59
61
|
};
|
|
60
62
|
if (loading && !status)
|
|
61
63
|
return null;
|
|
62
|
-
return ((0, jsx_runtime_1.jsxs)(terminal_1.TerminalCard, { children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between mb-4", children: [(0, jsx_runtime_1.jsx)("div", { className: "flex items-center gap-2", children: (0, jsx_runtime_1.jsx)("span", { className: "text-sm text-neutral-300 font-medium tracking-wider", children:
|
|
64
|
+
return ((0, jsx_runtime_1.jsxs)(terminal_1.TerminalCard, { children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between mb-4", children: [(0, jsx_runtime_1.jsx)("div", { className: "flex items-center gap-2", children: (0, jsx_runtime_1.jsx)("span", { className: "text-sm text-neutral-300 font-medium tracking-wider", children: t('twoFactorAuth', 'TWO FACTOR AUTH') }) }), (0, jsx_runtime_1.jsx)("span", { className: `px-2 py-0.5 rounded text-xs ${status?.enabled ? 'bg-green-900/30 text-green-400 border border-green-800' : 'bg-neutral-800 text-neutral-400 border border-neutral-700'}`, children: status?.enabled ? t('enabled', 'enabled') : t('disabled', 'disabled') })] }), error && ((0, jsx_runtime_1.jsx)("div", { className: "p-2 bg-red-900/20 border border-red-800 rounded text-xs text-red-300 mb-3", children: error })), step === 'idle' && !status?.enabled && ((0, jsx_runtime_1.jsxs)("div", { className: "space-y-3", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-xs text-neutral-400", children: t('twoFactorDesc', 'Add an extra layer of security using Google Authenticator or any TOTP app.') }), (0, jsx_runtime_1.jsx)("button", { onClick: handleBegin, disabled: loading, className: "px-3 py-1.5 bg-cyan-700 hover:bg-cyan-600 text-white rounded text-xs disabled:opacity-50", children: loading ? t('settingUp', 'Setting up...') : t('enable2fa', 'Enable 2FA') })] })), step === 'idle' && status?.enabled && ((0, jsx_runtime_1.jsxs)("div", { className: "space-y-3", children: [(0, jsx_runtime_1.jsxs)("div", { className: "bg-white/5 border border-white/10 rounded-lg p-3 blockchain-sub-card", children: [(0, jsx_runtime_1.jsx)("div", { className: "text-xs text-neutral-400 mb-1", children: t('status', 'STATUS') }), (0, jsx_runtime_1.jsxs)("div", { className: "text-green-400 text-sm", children: [t('active', 'Active'), " ", status.created_at ? `${t('since', 'since')} ${new Date(status.created_at).toLocaleDateString()}` : ''] })] }), (0, jsx_runtime_1.jsx)("button", { onClick: () => setStep('disable'), className: "px-3 py-1.5 border border-red-900 text-red-400 hover:bg-red-950 rounded text-xs", children: t('disable2fa', 'Disable 2FA') })] })), step === 'qr' && setupData && ((0, jsx_runtime_1.jsxs)("div", { className: "space-y-4", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-xs text-neutral-400", children: t('scanQrStep', '1. Scan this QR code with Google Authenticator or any TOTP app.') }), setupData.qr_code && ((0, jsx_runtime_1.jsx)("div", { className: "flex justify-center bg-white rounded p-4", children: (0, jsx_runtime_1.jsx)("img", { src: setupData.qr_code.startsWith('data:') ? setupData.qr_code : `data:image/png;base64,${setupData.qr_code}`, alt: "2FA QR Code", className: "w-48 h-48" }) })), (0, jsx_runtime_1.jsxs)("div", { className: "bg-white/5 border border-white/10 rounded-lg p-3 blockchain-sub-card", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between mb-1", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-xs text-neutral-400", children: t('manualKey', 'MANUAL KEY') }), (0, jsx_runtime_1.jsx)("button", { onClick: () => setShowSecret(!showSecret), className: "text-neutral-500 hover:text-neutral-300 text-xs", children: showSecret ? t('hide', 'hide') : t('show', 'show') })] }), (0, jsx_runtime_1.jsx)("code", { className: "text-xs text-cyan-400 break-all", children: showSecret ? setupData.secret : '••••••••••••••••' })] }), (0, jsx_runtime_1.jsx)("p", { className: "text-xs text-neutral-400", children: t('enter6DigitCode', '2. Enter the 6-digit code from your app.') }), (0, jsx_runtime_1.jsxs)("div", { className: "flex gap-2", children: [(0, jsx_runtime_1.jsx)("input", { type: "text", value: verifyCode, onChange: (e) => setVerifyCode(e.target.value.replace(/\D/g, '').slice(0, 6)), placeholder: "000000", className: "flex-1 bg-neutral-800 border border-neutral-700 text-white p-2 rounded text-center text-lg font-mono tracking-[0.5em] outline-none focus:border-cyan-500", maxLength: 6 }), (0, jsx_runtime_1.jsx)("button", { onClick: handleVerify, disabled: loading || verifyCode.length !== 6, className: "px-4 py-2 bg-cyan-700 hover:bg-cyan-600 text-white rounded text-xs disabled:opacity-50", children: loading ? t('verifying', 'Verifying...') : t('verify', 'Verify') })] }), (0, jsx_runtime_1.jsx)("button", { onClick: () => {
|
|
63
65
|
setStep('idle');
|
|
64
66
|
setVerifyCode('');
|
|
65
67
|
clearSetup();
|
|
66
|
-
}, className: "w-full py-2 text-neutral-500 hover:text-neutral-300 text-xs", children:
|
|
68
|
+
}, className: "w-full py-2 text-neutral-500 hover:text-neutral-300 text-xs", children: t('cancel', 'Cancel') })] })), step === 'backup' && backupCodes && ((0, jsx_runtime_1.jsxs)("div", { className: "space-y-4", children: [(0, jsx_runtime_1.jsxs)("div", { className: "bg-yellow-950/30 border border-yellow-900/50 rounded p-3", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-xs text-yellow-400 font-medium mb-1", children: t('saveBackupCodes', 'Save your backup codes') }), (0, jsx_runtime_1.jsx)("p", { className: "text-xs text-yellow-600", children: t('backupCodesDesc', 'These codes can be used to access your account if you lose your authenticator. Each code can only be used once. Store them safely.') })] }), (0, jsx_runtime_1.jsx)("div", { className: "bg-white/5 border border-white/10 rounded-lg p-4 blockchain-sub-card font-mono text-sm space-y-1", children: backupCodes.map((code, i) => ((0, jsx_runtime_1.jsx)("div", { className: "text-cyan-400", children: code }, i))) }), (0, jsx_runtime_1.jsx)("button", { onClick: copyBackupCodes, className: "w-full px-3 py-2 border border-neutral-700 text-neutral-300 hover:bg-neutral-800 rounded text-xs", children: t('copyCodes', 'Copy codes') }), (0, jsx_runtime_1.jsx)("button", { onClick: () => {
|
|
67
69
|
setStep('idle');
|
|
68
70
|
setBackupCodes(null);
|
|
69
|
-
}, className: "w-full px-3 py-2 bg-cyan-700 hover:bg-cyan-600 text-white rounded text-xs", children:
|
|
71
|
+
}, className: "w-full px-3 py-2 bg-cyan-700 hover:bg-cyan-600 text-white rounded text-xs", children: t('done', 'Done') })] })), step === 'disable' && ((0, jsx_runtime_1.jsxs)("div", { className: "space-y-4", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-xs text-neutral-400", children: t('enterPasswordToDisable', 'Enter your password to disable two-factor authentication.') }), (0, jsx_runtime_1.jsx)("input", { type: "password", value: disablePassword, onChange: (e) => setDisablePassword(e.target.value), placeholder: t('currentPasswordPlaceholder', 'Current password'), className: "w-full bg-neutral-800 border border-neutral-700 text-white p-2 rounded text-sm outline-none focus:border-cyan-500" }), (0, jsx_runtime_1.jsxs)("div", { className: "flex gap-2", children: [(0, jsx_runtime_1.jsx)("button", { onClick: () => {
|
|
70
72
|
setStep('idle');
|
|
71
73
|
setDisablePassword('');
|
|
72
|
-
}, className: "flex-1 px-3 py-1.5 text-neutral-500 hover:text-neutral-300 text-xs", children:
|
|
74
|
+
}, className: "flex-1 px-3 py-1.5 text-neutral-500 hover:text-neutral-300 text-xs", children: t('cancel', 'Cancel') }), (0, jsx_runtime_1.jsx)("button", { onClick: handleDisable, disabled: loading || !disablePassword, className: "flex-1 px-3 py-1.5 bg-red-900 hover:bg-red-800 text-white rounded text-xs disabled:opacity-50", children: loading ? t('disabling', 'Disabling...') : t('disable2fa', 'Disable 2FA') })] })] }))] }));
|
|
73
75
|
}
|
|
@@ -6,6 +6,7 @@ const jsx_runtime_1 = require("react/jsx-runtime");
|
|
|
6
6
|
const react_1 = require("react");
|
|
7
7
|
const auth_react_1 = require("@microcosmmoney/auth-react");
|
|
8
8
|
const terminal_1 = require("../terminal");
|
|
9
|
+
const i18n_context_1 = require("../../i18n-context");
|
|
9
10
|
const LEVEL_LABELS = {
|
|
10
11
|
miner: 'Miner',
|
|
11
12
|
commander: 'Commander',
|
|
@@ -14,6 +15,7 @@ const LEVEL_LABELS = {
|
|
|
14
15
|
admiral: 'Admiral',
|
|
15
16
|
};
|
|
16
17
|
function MicrocosmQueueStatusPage({ isAdmin = false } = {}) {
|
|
18
|
+
const t = (0, i18n_context_1.useTranslations)('queueStatus');
|
|
17
19
|
const api = (0, auth_react_1.useMicrocosmApi)();
|
|
18
20
|
const [userQueue, setUserQueue] = (0, react_1.useState)(null);
|
|
19
21
|
const [adminQueue, setAdminQueue] = (0, react_1.useState)(null);
|
|
@@ -105,9 +107,9 @@ function MicrocosmQueueStatusPage({ isAdmin = false } = {}) {
|
|
|
105
107
|
}
|
|
106
108
|
};
|
|
107
109
|
if (loading) {
|
|
108
|
-
return ((0, jsx_runtime_1.jsxs)("div", { className: "max-w-7xl mx-auto px-3 py-4 space-y-3 xs:px-4 xs:space-y-4 sm:px-6 sm:py-6 sm:space-y-6 font-mono", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h1", { className: "text-lg sm:text-2xl font-bold text-white tracking-wider", children:
|
|
110
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: "max-w-7xl mx-auto px-3 py-4 space-y-3 xs:px-4 xs:space-y-4 sm:px-6 sm:py-6 sm:space-y-6 font-mono", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h1", { className: "text-lg sm:text-2xl font-bold text-white tracking-wider", children: t('title', 'Territory Position Management') }), (0, jsx_runtime_1.jsx)("p", { className: "text-xs sm:text-sm text-neutral-400", children: t('subtitle', 'Onboarding, queuing, and territory assignment management') })] }), (0, jsx_runtime_1.jsx)("div", { className: "flex items-center justify-center py-20", children: (0, jsx_runtime_1.jsx)("span", { className: "text-neutral-400", children: t('loading', 'Loading...') }) })] }));
|
|
109
111
|
}
|
|
110
112
|
const level = userQueue?.user_type?.toLowerCase() || 'miner';
|
|
111
113
|
const levelLabel = LEVEL_LABELS[level] || 'Miner';
|
|
112
|
-
return ((0, jsx_runtime_1.jsxs)("div", { className: "max-w-7xl mx-auto px-3 py-4 space-y-3 xs:px-4 xs:space-y-4 sm:px-6 sm:py-6 sm: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-lg sm:text-2xl font-bold text-white tracking-wider", children: "Station Queue" }), (0, jsx_runtime_1.jsx)("p", { className: "text-xs sm:text-sm text-neutral-400", children: "Your onboarding status" })] }), (0, jsx_runtime_1.jsx)("button", { onClick: loadStatus, className: "px-3 py-1.5 text-xs border border-neutral-700 text-neutral-400 hover:bg-neutral-800 hover:text-white rounded transition-colors", children: "Refresh" })] }), error && ((0, jsx_runtime_1.jsx)("div", { className: "p-3 bg-red-900/20 border border-red-800 rounded text-sm text-red-300", children: error })), (0, jsx_runtime_1.jsxs)(terminal_1.TerminalCard, { children: [(0, jsx_runtime_1.jsx)("div", { className: "p-4 bg-neutral-800 rounded mb-4", 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)("div", { className: "text-xs text-[#5EEAD4] tracking-widest uppercase", children: "CURRENT LEVEL" }), (0, jsx_runtime_1.jsx)("div", { className: "text-lg font-bold text-cyan-300", children: levelLabel })] }), (0, jsx_runtime_1.jsxs)("span", { className: "px-3 py-1 bg-cyan-900/30 text-cyan-300 rounded border border-cyan-700 text-xs", children: ["Lv.", Object.keys(LEVEL_LABELS).indexOf(level) + 3] })] }) }), userQueue?.is_onboarded ? ((0, jsx_runtime_1.jsxs)("div", { className: "bg-neutral-950 rounded-lg p-6 border border-neutral-700", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between mb-4", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-lg font-semibold text-white", children: "Onboarded" }), (0, jsx_runtime_1.jsxs)("p", { className: "text-sm text-neutral-400", children: ["Assigned to ", userQueue.station_name || userQueue.territory_id || ''] })] }), (0, jsx_runtime_1.jsx)("span", { className: "px-2 py-1 bg-white/20 text-white rounded text-xs", children: "Active" })] }), (0, jsx_runtime_1.jsx)("div", { className: "grid grid-cols-1 gap-4", children: (0, jsx_runtime_1.jsxs)("div", { className: "bg-neutral-900 rounded-lg p-4 text-center", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-xl font-bold text-white", children: userQueue.territory_id }), (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-neutral-400", children: "Territory ID" })] }) })] })) : userQueue?.in_queue ? ((0, jsx_runtime_1.jsxs)("div", { className: "bg-neutral-950 rounded-lg p-6 border border-neutral-800", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between mb-4", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-lg font-semibold text-white", children: "In Queue" }), (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-neutral-400", children: "Waiting for station assignment" })] }), userQueue.status && ((0, jsx_runtime_1.jsx)("span", { className: "px-2 py-1 bg-cyan-900/30 text-cyan-300 rounded text-xs", children: userQueue.status }))] }), (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", { className: "text-center", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-3xl font-bold text-white", children: userQueue.position || '-' }), (0, jsx_runtime_1.jsx)("p", { className: "text-xs text-neutral-400", children: "Position" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "text-center", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-3xl font-bold text-white", children: userQueue.estimated_wait_minutes || '-' }), (0, jsx_runtime_1.jsx)("p", { className: "text-xs text-neutral-400", children: "Est. wait (min)" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "text-center", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-sm font-semibold text-white truncate", children: userQueue.preferred_territory_id || 'Auto' }), (0, jsx_runtime_1.jsx)("p", { className: "text-xs text-neutral-400", children: "Preferred" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "text-center", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-sm font-semibold text-white", children: userQueue.joined_at ? new Date(userQueue.joined_at).toLocaleString() : '-' }), (0, jsx_runtime_1.jsx)("p", { className: "text-xs text-neutral-400", children: "Joined at" })] })] }), (0, jsx_runtime_1.jsx)("button", { onClick: () => setShowCancelConfirm(true), disabled: submitting, className: "w-full py-2 bg-neutral-800 hover:bg-neutral-700 text-white rounded transition-colors disabled:opacity-50", children: "Cancel Queue" })] })) : ((0, jsx_runtime_1.jsxs)("div", { className: "bg-neutral-950 rounded-lg p-6 border border-neutral-800", children: [(0, jsx_runtime_1.jsxs)("div", { className: "mb-4", children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-lg font-semibold text-white", children: "Not Onboarded" }), (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-neutral-400", children: "Join the queue to be assigned a station" })] }), (0, jsx_runtime_1.jsx)("button", { onClick: () => setShowJoinConfirm(true), disabled: submitting, className: "w-full py-2 bg-white/20 hover:bg-neutral-800 text-white border border-neutral-700 rounded transition-colors disabled:opacity-50", children: "Join Queue" })] }))] }), isAdmin && adminQueue && ((0, jsx_runtime_1.jsxs)(terminal_1.TerminalCard, { title: "Queue Management (Admin)", children: [(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", { className: "bg-neutral-950 rounded p-4 text-center border border-neutral-800", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-3xl font-bold text-white", children: adminQueue.pending_count ?? 0 }), (0, jsx_runtime_1.jsx)("p", { className: "text-xs text-neutral-400 mt-1", children: "Pending" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "bg-neutral-950 rounded p-4 text-center border border-neutral-800", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-3xl font-bold text-white", children: adminQueue.processing_count ?? 0 }), (0, jsx_runtime_1.jsx)("p", { className: "text-xs text-neutral-400 mt-1", children: "Processing" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "bg-neutral-950 rounded p-4 text-center border border-neutral-800", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-3xl font-bold text-white", children: adminQueue.total_in_queue ?? 0 }), (0, jsx_runtime_1.jsx)("p", { className: "text-xs text-neutral-400 mt-1", children: "Total in queue" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "bg-neutral-950 rounded p-4 text-center border border-neutral-800", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-sm text-white", children: adminQueue.oldest_pending ? new Date(adminQueue.oldest_pending).toLocaleString() : '-' }), (0, jsx_runtime_1.jsx)("p", { className: "text-xs text-neutral-400 mt-1", children: "Oldest pending" })] })] }), (0, jsx_runtime_1.jsx)("button", { onClick: handleProcessQueue, disabled: submitting, className: "w-full px-4 py-2 bg-cyan-700 hover:bg-cyan-600 text-white rounded text-sm disabled:opacity-50", children: submitting ? 'Processing...' : 'Process Queue (batch 50)' })] })), isAdmin && expansion && ((0, jsx_runtime_1.jsx)(terminal_1.TerminalCard, { title: "Station Expansion (Admin)", children: (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between mb-3", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsxs)("div", { className: "text-sm text-neutral-300", children: ["Needs expansion: ", expansion.needs_expansion ? 'YES' : 'NO'] }), expansion.reason && ((0, jsx_runtime_1.jsxs)("div", { className: "text-xs text-neutral-500 mt-1", children: ["Reason: ", expansion.reason] }))] }), (0, jsx_runtime_1.jsx)("button", { onClick: handleTriggerExpansion, disabled: submitting || !expansion.needs_expansion, className: "px-4 py-2 bg-red-900/30 text-red-300 border border-red-800 hover:bg-red-900/50 rounded text-sm disabled:opacity-50", children: submitting ? 'Expanding...' : 'Trigger Expansion' })] }) })), showJoinConfirm && ((0, jsx_runtime_1.jsx)("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/60 p-4", onClick: () => setShowJoinConfirm(false), children: (0, jsx_runtime_1.jsxs)("div", { className: "bg-neutral-900 border border-neutral-700 rounded-lg w-full max-w-md p-6 space-y-4", onClick: e => e.stopPropagation(), children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-white font-medium", children: "Confirm Join Queue" }), (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-neutral-400", children: "You will be added to the station queue. Auto-assignment happens when a slot opens." }), (0, jsx_runtime_1.jsxs)("div", { className: "flex gap-2", children: [(0, jsx_runtime_1.jsx)("button", { onClick: () => setShowJoinConfirm(false), className: "flex-1 px-3 py-2 border border-neutral-700 text-neutral-400 hover:bg-neutral-800 rounded text-sm", children: "Cancel" }), (0, jsx_runtime_1.jsx)("button", { onClick: handleJoin, disabled: submitting, className: "flex-1 px-3 py-2 bg-cyan-700 hover:bg-cyan-600 text-white rounded text-sm disabled:opacity-50", children: submitting ? 'Joining...' : 'Confirm' })] })] }) })), showCancelConfirm && ((0, jsx_runtime_1.jsx)("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/60 p-4", onClick: () => setShowCancelConfirm(false), children: (0, jsx_runtime_1.jsxs)("div", { className: "bg-neutral-900 border border-neutral-700 rounded-lg w-full max-w-md p-6 space-y-4", onClick: e => e.stopPropagation(), children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-white font-medium", children: "Cancel Queue" }), (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-neutral-400", children: "Are you sure? You will lose your current queue position." }), (0, jsx_runtime_1.jsxs)("div", { className: "flex gap-2", children: [(0, jsx_runtime_1.jsx)("button", { onClick: () => setShowCancelConfirm(false), className: "flex-1 px-3 py-2 border border-neutral-700 text-neutral-400 hover:bg-neutral-800 rounded text-sm", children: "Keep Waiting" }), (0, jsx_runtime_1.jsx)("button", { onClick: handleCancel, disabled: submitting, className: "flex-1 px-3 py-2 bg-red-700 hover:bg-red-600 text-white rounded text-sm disabled:opacity-50", children: submitting ? 'Cancelling...' : 'Confirm Cancel' })] })] }) }))] }));
|
|
114
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: "max-w-7xl mx-auto px-3 py-4 space-y-3 xs:px-4 xs:space-y-4 sm:px-6 sm:py-6 sm: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-lg sm:text-2xl font-bold text-white tracking-wider", children: t('title', 'Territory Position Management') }), (0, jsx_runtime_1.jsx)("p", { className: "text-xs sm:text-sm text-neutral-400", children: t('subtitle', 'Onboarding, queuing, and territory assignment management') })] }), (0, jsx_runtime_1.jsx)("button", { onClick: loadStatus, className: "px-3 py-1.5 text-xs border border-neutral-700 text-neutral-400 hover:bg-neutral-800 hover:text-white rounded transition-colors", children: t('refresh', 'Refresh') })] }), error && ((0, jsx_runtime_1.jsx)("div", { className: "p-3 bg-red-900/20 border border-red-800 rounded text-sm text-red-300", children: error })), (0, jsx_runtime_1.jsxs)(terminal_1.TerminalCard, { children: [(0, jsx_runtime_1.jsx)("div", { className: "p-4 bg-neutral-800 rounded mb-4", 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)("div", { className: "text-xs text-[#5EEAD4] tracking-widest uppercase", children: t('currentLevel', 'CURRENT LEVEL') }), (0, jsx_runtime_1.jsx)("div", { className: "text-lg font-bold text-cyan-300", children: levelLabel })] }), (0, jsx_runtime_1.jsxs)("span", { className: "px-3 py-1 bg-cyan-900/30 text-cyan-300 rounded border border-cyan-700 text-xs", children: ["Lv.", Object.keys(LEVEL_LABELS).indexOf(level) + 3] })] }) }), userQueue?.is_onboarded ? ((0, jsx_runtime_1.jsxs)("div", { className: "bg-neutral-950 rounded-lg p-6 border border-neutral-700", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between mb-4", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-lg font-semibold text-white", children: t('onboarded', 'Onboarded') }), (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-neutral-400", children: t('onboardedTo', 'You have been onboarded to {station}', { station: userQueue.station_name || userQueue.territory_id || '' }) })] }), (0, jsx_runtime_1.jsx)("span", { className: "px-2 py-1 bg-white/20 text-white rounded text-xs", children: t('active', 'Active') })] }), (0, jsx_runtime_1.jsx)("div", { className: "grid grid-cols-1 gap-4", children: (0, jsx_runtime_1.jsxs)("div", { className: "bg-neutral-900 rounded-lg p-4 text-center", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-xl font-bold text-white", children: userQueue.territory_id }), (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-neutral-400", children: t('territoryId', 'Territory ID') })] }) })] })) : userQueue?.in_queue ? ((0, jsx_runtime_1.jsxs)("div", { className: "bg-neutral-950 rounded-lg p-6 border border-neutral-800", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between mb-4", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-lg font-semibold text-white", children: t('inQueue', 'In Queue') }), (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-neutral-400", children: t('waitingAssignment', 'You are waiting for territory assignment') })] }), userQueue.status && ((0, jsx_runtime_1.jsx)("span", { className: "px-2 py-1 bg-cyan-900/30 text-cyan-300 rounded text-xs", children: userQueue.status }))] }), (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", { className: "text-center", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-3xl font-bold text-white", children: userQueue.position || '-' }), (0, jsx_runtime_1.jsx)("p", { className: "text-xs text-neutral-400", children: t('queuePosition', 'Queue Position') })] }), (0, jsx_runtime_1.jsxs)("div", { className: "text-center", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-3xl font-bold text-white", children: userQueue.estimated_wait_minutes || '-' }), (0, jsx_runtime_1.jsx)("p", { className: "text-xs text-neutral-400", children: t('estimatedWait', 'Est. Wait (min)') })] }), (0, jsx_runtime_1.jsxs)("div", { className: "text-center", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-sm font-semibold text-white truncate", children: userQueue.preferred_territory_id || t('autoAssign', 'Auto Assign') }), (0, jsx_runtime_1.jsx)("p", { className: "text-xs text-neutral-400", children: t('preferredTerritory', 'Preferred Territory') })] }), (0, jsx_runtime_1.jsxs)("div", { className: "text-center", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-sm font-semibold text-white", children: userQueue.joined_at ? new Date(userQueue.joined_at).toLocaleString() : '-' }), (0, jsx_runtime_1.jsx)("p", { className: "text-xs text-neutral-400", children: t('joinTime', 'Join Time') })] })] }), (0, jsx_runtime_1.jsx)("button", { onClick: () => setShowCancelConfirm(true), disabled: submitting, className: "w-full py-2 bg-neutral-800 hover:bg-neutral-700 text-white rounded transition-colors disabled:opacity-50", children: t('cancelQueue', 'Cancel Queue') })] })) : ((0, jsx_runtime_1.jsxs)("div", { className: "bg-neutral-950 rounded-lg p-6 border border-neutral-800", children: [(0, jsx_runtime_1.jsxs)("div", { className: "mb-4", children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-lg font-semibold text-white", children: t('notOnboarded', 'Not Onboarded') }), (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-neutral-400", children: t('notOnboardedDesc', 'You have not been onboarded to any territory') })] }), (0, jsx_runtime_1.jsx)("button", { onClick: () => setShowJoinConfirm(true), disabled: submitting, className: "w-full py-2 bg-white/20 hover:bg-neutral-800 text-white border border-neutral-700 rounded transition-colors disabled:opacity-50", children: t('joinQueue', 'Join Queue') })] }))] }), isAdmin && adminQueue && ((0, jsx_runtime_1.jsxs)(terminal_1.TerminalCard, { title: t('queueManagement', 'Queue Management (Admin)'), children: [(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", { className: "bg-neutral-950 rounded p-4 text-center border border-neutral-800", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-3xl font-bold text-white", children: adminQueue.pending_count ?? 0 }), (0, jsx_runtime_1.jsx)("p", { className: "text-xs text-neutral-400 mt-1", children: t('pending', 'Pending') })] }), (0, jsx_runtime_1.jsxs)("div", { className: "bg-neutral-950 rounded p-4 text-center border border-neutral-800", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-3xl font-bold text-white", children: adminQueue.processing_count ?? 0 }), (0, jsx_runtime_1.jsx)("p", { className: "text-xs text-neutral-400 mt-1", children: t('processing', 'Processing') })] }), (0, jsx_runtime_1.jsxs)("div", { className: "bg-neutral-950 rounded p-4 text-center border border-neutral-800", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-3xl font-bold text-white", children: adminQueue.total_in_queue ?? 0 }), (0, jsx_runtime_1.jsx)("p", { className: "text-xs text-neutral-400 mt-1", children: t('totalInQueue', 'Total in Queue') })] }), (0, jsx_runtime_1.jsxs)("div", { className: "bg-neutral-950 rounded p-4 text-center border border-neutral-800", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-sm text-white", children: adminQueue.oldest_pending ? new Date(adminQueue.oldest_pending).toLocaleString() : '-' }), (0, jsx_runtime_1.jsx)("p", { className: "text-xs text-neutral-400 mt-1", children: t('oldestPending', 'Oldest Pending') })] })] }), (0, jsx_runtime_1.jsx)("button", { onClick: handleProcessQueue, disabled: submitting, className: "w-full px-4 py-2 bg-cyan-700 hover:bg-cyan-600 text-white rounded text-sm disabled:opacity-50", children: submitting ? t('submitting', 'Processing...') : t('processQueue', 'Process Queue') })] })), isAdmin && expansion && ((0, jsx_runtime_1.jsx)(terminal_1.TerminalCard, { title: t('territoryExpansion', 'Territory Expansion (Admin)'), children: (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between mb-3", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsxs)("div", { className: "text-sm text-neutral-300", children: [t('needsExpansion', 'Needs Expansion'), ": ", expansion.needs_expansion ? 'YES' : 'NO'] }), expansion.reason && ((0, jsx_runtime_1.jsxs)("div", { className: "text-xs text-neutral-500 mt-1", children: ["Reason: ", expansion.reason] }))] }), (0, jsx_runtime_1.jsx)("button", { onClick: handleTriggerExpansion, disabled: submitting || !expansion.needs_expansion, className: "px-4 py-2 bg-red-900/30 text-red-300 border border-red-800 hover:bg-red-900/50 rounded text-sm disabled:opacity-50", children: submitting ? t('submitting', 'Processing...') : t('triggerExpansion', 'Trigger Expansion Manually') })] }) })), showJoinConfirm && ((0, jsx_runtime_1.jsx)("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/60 p-4", onClick: () => setShowJoinConfirm(false), children: (0, jsx_runtime_1.jsxs)("div", { className: "bg-neutral-900 border border-neutral-700 rounded-lg w-full max-w-md p-6 space-y-4", onClick: e => e.stopPropagation(), children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-white font-medium", children: t('joinDialogTitle', 'Join Territory') }), (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-neutral-400", children: t('joinDialogDesc', 'Choose to join a specific territory or auto-assign') }), (0, jsx_runtime_1.jsxs)("div", { className: "flex gap-2", children: [(0, jsx_runtime_1.jsx)("button", { onClick: () => setShowJoinConfirm(false), className: "flex-1 px-3 py-2 border border-neutral-700 text-neutral-400 hover:bg-neutral-800 rounded text-sm", children: t('cancel', 'Cancel') }), (0, jsx_runtime_1.jsx)("button", { onClick: handleJoin, disabled: submitting, className: "flex-1 px-3 py-2 bg-cyan-700 hover:bg-cyan-600 text-white rounded text-sm disabled:opacity-50", children: submitting ? t('submitting', 'Processing...') : t('immediateJoin', 'Join Immediately') })] })] }) })), showCancelConfirm && ((0, jsx_runtime_1.jsx)("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/60 p-4", onClick: () => setShowCancelConfirm(false), children: (0, jsx_runtime_1.jsxs)("div", { className: "bg-neutral-900 border border-neutral-700 rounded-lg w-full max-w-md p-6 space-y-4", onClick: e => e.stopPropagation(), children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-white font-medium", children: t('cancelQueueTitle', 'Cancel Queue') }), (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-neutral-400", children: t('cancelQueueDesc', 'Are you sure you want to cancel queuing? You will need to rejoin the queue to get onboarded.') }), (0, jsx_runtime_1.jsxs)("div", { className: "flex gap-2", children: [(0, jsx_runtime_1.jsx)("button", { onClick: () => setShowCancelConfirm(false), className: "flex-1 px-3 py-2 border border-neutral-700 text-neutral-400 hover:bg-neutral-800 rounded text-sm", children: t('goBack', 'Go Back') }), (0, jsx_runtime_1.jsx)("button", { onClick: handleCancel, disabled: submitting, className: "flex-1 px-3 py-2 bg-red-700 hover:bg-red-600 text-white rounded text-sm disabled:opacity-50", children: submitting ? t('submitting', 'Processing...') : t('confirmCancel', 'Confirm Cancel') })] })] }) }))] }));
|
|
113
115
|
}
|
|
@@ -6,6 +6,7 @@ const jsx_runtime_1 = require("react/jsx-runtime");
|
|
|
6
6
|
const react_1 = require("react");
|
|
7
7
|
const auth_react_1 = require("@microcosmmoney/auth-react");
|
|
8
8
|
const terminal_1 = require("../terminal");
|
|
9
|
+
const i18n_context_1 = require("../../i18n-context");
|
|
9
10
|
const POOL_ADDRESS = 'REDEh89TzpwCtoWQuuNPtxskrVoUDQgowR7e7sZpWj9';
|
|
10
11
|
const USDT_VAULT = 'BnHA9jSm88wzQS4c2nCgTXch1Byzc3FWn2G7Wgrvazy3';
|
|
11
12
|
const USDC_VAULT = '5L8vPTvGH14keLq4R6CGGvSFksZFjb7bRPXarCwZbmUA';
|
|
@@ -26,8 +27,11 @@ function formatNumber(num, decimals = 2) {
|
|
|
26
27
|
return (num / 1000000).toFixed(2) + 'M';
|
|
27
28
|
return num.toLocaleString('en-US', { minimumFractionDigits: decimals, maximumFractionDigits: decimals });
|
|
28
29
|
}
|
|
29
|
-
function MicrocosmReincarnationPage({ title
|
|
30
|
+
function MicrocosmReincarnationPage({ title, subtitle, } = {}) {
|
|
31
|
+
const t = (0, i18n_context_1.useTranslations)('reincarnationDash');
|
|
32
|
+
const resolvedTitle = title ?? t('title', 'Reincarnation Pool');
|
|
33
|
+
const resolvedSubtitle = subtitle ?? t('subtitle', '2140 Protocol autonomous market making');
|
|
30
34
|
const { data: priceData, loading } = (0, auth_react_1.useMCCPrice)({ refetchInterval: 60000 });
|
|
31
35
|
const basePrice = priceData?.price ?? 0;
|
|
32
|
-
return ((0, jsx_runtime_1.jsxs)("div", { className: "max-w-7xl mx-auto px-3 py-4 space-y-3 xs:px-4 xs:space-y-4 sm:px-6 sm:py-6 sm:space-y-6 font-mono", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h1", { className: "text-lg sm:text-2xl font-bold text-white tracking-wider", children:
|
|
36
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: "max-w-7xl mx-auto px-3 py-4 space-y-3 xs:px-4 xs:space-y-4 sm:px-6 sm:py-6 sm:space-y-6 font-mono", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h1", { className: "text-lg sm:text-2xl font-bold text-white tracking-wider", children: resolvedTitle }), (0, jsx_runtime_1.jsx)("p", { className: "text-xs sm:text-sm text-neutral-400 mt-1", children: resolvedSubtitle })] }), (0, jsx_runtime_1.jsxs)("div", { className: "grid grid-cols-2 md:grid-cols-4 gap-4", children: [(0, jsx_runtime_1.jsxs)(terminal_1.TerminalCard, { children: [(0, jsx_runtime_1.jsx)("div", { className: "text-xs text-neutral-400 tracking-wider mb-2", children: "BASE PRICE" }), (0, jsx_runtime_1.jsxs)("div", { className: "text-2xl font-bold text-cyan-400", children: [loading ? '—' : formatNumber(basePrice, 4), (0, jsx_runtime_1.jsx)("span", { className: "text-sm font-normal text-neutral-500 ml-1", children: "USD" })] })] }), (0, jsx_runtime_1.jsxs)(terminal_1.TerminalCard, { children: [(0, jsx_runtime_1.jsx)("div", { className: "text-xs text-neutral-400 tracking-wider mb-2", children: "PROTOCOL" }), (0, jsx_runtime_1.jsx)("div", { className: "text-2xl font-bold text-white", children: "2140" }), (0, jsx_runtime_1.jsx)("div", { className: "text-xs text-neutral-500 mt-1", children: "EMA weighted" })] }), (0, jsx_runtime_1.jsxs)(terminal_1.TerminalCard, { children: [(0, jsx_runtime_1.jsx)("div", { className: "text-xs text-neutral-400 tracking-wider mb-2", children: "EPOCH" }), (0, jsx_runtime_1.jsx)("div", { className: "text-2xl font-bold text-white", children: "1h" }), (0, jsx_runtime_1.jsx)("div", { className: "text-xs text-neutral-500 mt-1", children: "Auto buyback" })] }), (0, jsx_runtime_1.jsxs)(terminal_1.TerminalCard, { children: [(0, jsx_runtime_1.jsx)("div", { className: "text-xs text-neutral-400 tracking-wider mb-2", children: "DEX" }), (0, jsx_runtime_1.jsx)("div", { className: "text-2xl font-bold text-cyan-400", children: "Raydium" }), (0, jsx_runtime_1.jsx)("div", { className: "text-xs text-neutral-500 mt-1", children: "CPMM pool" })] })] }), (0, jsx_runtime_1.jsx)(terminal_1.TerminalCard, { title: t('contractAddresses', 'Contract Addresses'), children: (0, jsx_runtime_1.jsxs)("div", { className: "space-y-3", children: [(0, jsx_runtime_1.jsxs)("div", { className: "bg-white/5 border border-white/10 rounded-lg p-3 blockchain-sub-card", children: [(0, jsx_runtime_1.jsx)("div", { className: "text-xs text-neutral-400 tracking-wider mb-1", children: "Reincarnation Pool PDA" }), (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between gap-2", children: [(0, jsx_runtime_1.jsx)("code", { className: "text-sm text-cyan-400 break-all", children: POOL_ADDRESS }), (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2 shrink-0", children: [(0, jsx_runtime_1.jsx)(CopyButton, { text: POOL_ADDRESS }), (0, jsx_runtime_1.jsx)("a", { href: `https://solscan.io/account/${POOL_ADDRESS}`, target: "_blank", rel: "noopener noreferrer", className: "text-neutral-400 hover:text-white text-xs", children: "\u2197" })] })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-3", children: [(0, jsx_runtime_1.jsxs)("div", { className: "bg-white/5 border border-white/10 rounded-lg p-3 blockchain-sub-card", children: [(0, jsx_runtime_1.jsx)("div", { className: "text-xs text-neutral-400 tracking-wider mb-1", children: t('usdtBalance', 'USDT Vault') }), (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between gap-2", children: [(0, jsx_runtime_1.jsx)("code", { className: "text-xs text-neutral-400 break-all", children: USDT_VAULT }), (0, jsx_runtime_1.jsx)(CopyButton, { text: USDT_VAULT })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "bg-white/5 border border-white/10 rounded-lg p-3 blockchain-sub-card", children: [(0, jsx_runtime_1.jsx)("div", { className: "text-xs text-neutral-400 tracking-wider mb-1", children: t('usdcBalance', 'USDC Vault') }), (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between gap-2", children: [(0, jsx_runtime_1.jsx)("code", { className: "text-xs text-neutral-400 break-all", children: USDC_VAULT }), (0, jsx_runtime_1.jsx)(CopyButton, { text: USDC_VAULT })] })] })] })] }) }), (0, jsx_runtime_1.jsx)(terminal_1.TerminalCard, { title: t('mechanism', 'Market Making Mechanism'), children: (0, jsx_runtime_1.jsxs)("div", { className: "text-sm space-y-2", children: [(0, jsx_runtime_1.jsx)("div", { className: "font-medium text-cyan-400 tracking-wider", children: t('mechanism', 'Market Making Mechanism') }), (0, jsx_runtime_1.jsx)("p", { className: "text-neutral-400 leading-relaxed", children: t('mechanismDesc', 'The Reincarnation Pool is a Solana PDA-owned autonomous market maker. Every epoch (1 hour), it reads the CPMM spot price, updates an EMA-weighted oracle (weight 2140), and executes a permissionless buyback via CPMM swap. Proceeds flow to the Mining Vault for the next cycle of community mining.') }), (0, jsx_runtime_1.jsxs)("div", { className: "flex flex-wrap items-center gap-2 mt-3 text-xs", children: [(0, jsx_runtime_1.jsx)("span", { className: "px-2 py-1 rounded bg-white/10 text-white", children: "Raydium CPMM" }), (0, jsx_runtime_1.jsx)("span", { className: "px-2 py-1 rounded bg-cyan-400/20 text-cyan-400", children: "PDA Autonomous" }), (0, jsx_runtime_1.jsx)("span", { className: "px-2 py-1 rounded bg-cyan-400/20 text-cyan-400", children: "EMA Oracle" }), (0, jsx_runtime_1.jsx)("span", { className: "px-2 py-1 rounded bg-cyan-400/20 text-cyan-400", children: "Permissionless" })] })] }) })] }));
|
|
33
37
|
}
|
|
@@ -6,7 +6,9 @@ const jsx_runtime_1 = require("react/jsx-runtime");
|
|
|
6
6
|
const react_1 = require("react");
|
|
7
7
|
const auth_react_1 = require("@microcosmmoney/auth-react");
|
|
8
8
|
const terminal_1 = require("../terminal");
|
|
9
|
+
const i18n_context_1 = require("../../i18n-context");
|
|
9
10
|
function MicrocosmRewardsPage({} = {}) {
|
|
11
|
+
const t = (0, i18n_context_1.useTranslations)('rewardsDash');
|
|
10
12
|
const api = (0, auth_react_1.useMicrocosmApi)();
|
|
11
13
|
const [history, setHistory] = (0, react_1.useState)([]);
|
|
12
14
|
const [stats, setStats] = (0, react_1.useState)(null);
|
|
@@ -105,11 +107,11 @@ function MicrocosmRewardsPage({} = {}) {
|
|
|
105
107
|
return '-';
|
|
106
108
|
}
|
|
107
109
|
};
|
|
108
|
-
return ((0, jsx_runtime_1.jsxs)("div", { className: "max-w-7xl mx-auto px-3 py-4 space-y-3 xs:px-4 xs:space-y-4 sm:px-6 sm:py-6 sm:space-y-6 font-mono", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between flex-wrap gap-3", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h1", { className: "text-lg sm:text-2xl font-bold text-white tracking-wider", children: "Rewards" }), (0, jsx_runtime_1.jsx)("p", { className: "text-xs sm:text-sm text-neutral-400", children: "Send MCC rewards to your territory members" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex gap-2", children: [(0, jsx_runtime_1.jsx)("button", { onClick: () => setShowSendDialog(true), className: "px-3 py-1.5 bg-cyan-700 hover:bg-cyan-600 text-white rounded text-sm", children: "Send Reward" }), (0, jsx_runtime_1.jsx)("button", { onClick: () => setShowBatchDialog(true), className: "px-3 py-1.5 border border-neutral-700 text-neutral-400 hover:bg-neutral-800 hover:text-white rounded text-sm", children: "Batch Send" })] })] }), error && ((0, jsx_runtime_1.jsx)("div", { className: "p-3 bg-red-900/20 border border-red-800 rounded text-sm text-red-300", children: error })), stats && ((0, jsx_runtime_1.jsxs)("div", { className: "grid grid-cols-2 md:grid-cols-4 gap-4", children: [(0, jsx_runtime_1.jsxs)(terminal_1.TerminalCard, { children: [(0, jsx_runtime_1.jsx)("div", { className: "text-xs text-[#5EEAD4] tracking-widest uppercase mb-1", children: "MCC RECEIVED" }), (0, jsx_runtime_1.jsx)("div", { className: "text-2xl font-bold text-white", children: Number(stats.total_received || 0).toFixed(2) })] }), (0, jsx_runtime_1.jsxs)(terminal_1.TerminalCard, { children: [(0, jsx_runtime_1.jsx)("div", { className: "text-xs text-[#5EEAD4] tracking-widest uppercase mb-1", children: "MCC SENT" }), (0, jsx_runtime_1.jsx)("div", { className: "text-2xl font-bold text-cyan-400", children: Number(stats.total_sent || 0).toFixed(2) })] }), (0, jsx_runtime_1.jsxs)(terminal_1.TerminalCard, { children: [(0, jsx_runtime_1.jsx)("div", { className: "text-xs text-[#5EEAD4] tracking-widest uppercase mb-1", children: "RECEIVE COUNT" }), (0, jsx_runtime_1.jsx)("div", { className: "text-2xl font-bold text-white", children: stats.receive_count })] }), (0, jsx_runtime_1.jsxs)(terminal_1.TerminalCard, { children: [(0, jsx_runtime_1.jsx)("div", { className: "text-xs text-[#5EEAD4] tracking-widest uppercase mb-1", children: "SEND COUNT" }), (0, jsx_runtime_1.jsx)("div", { className: "text-2xl font-bold text-white", children: stats.send_count })] })] })), (0, jsx_runtime_1.jsxs)("div", { className: "flex gap-2 border-b border-neutral-800", children: [(0, jsx_runtime_1.jsx)("button", { onClick: () => setTab('history'), className: `px-4 py-2 text-sm ${tab === 'history' ? 'text-white border-b-2 border-cyan-400' : 'text-neutral-400 hover:text-white'}`, children: "History" }), (0, jsx_runtime_1.jsx)("button", { onClick: () => setTab('leaderboard'), className: `px-4 py-2 text-sm ${tab === 'leaderboard' ? 'text-white border-b-2 border-cyan-400' : 'text-neutral-400 hover:text-white'}`, children: "Leaderboard" })] }), tab === 'history' && ((0, jsx_runtime_1.jsx)(terminal_1.TerminalCard, { title: "Reward History", children: loading ? ((0, jsx_runtime_1.jsx)("div", { className: "text-center py-8 text-neutral-500", children: "Loading..." })) : history.length === 0 ? ((0, jsx_runtime_1.jsx)("div", { className: "text-center py-8 text-neutral-500", children: "No records" })) : ((0, jsx_runtime_1.jsx)("div", { className: "overflow-x-auto", children: (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: "text-xs text-neutral-400 border-b border-neutral-800", children: [(0, jsx_runtime_1.jsx)("th", { className: "text-left py-2", children: "Time" }), (0, jsx_runtime_1.jsx)("th", { className: "text-left py-2", children: "Sender" }), (0, jsx_runtime_1.jsx)("th", { className: "text-left py-2", children: "Recipient" }), (0, jsx_runtime_1.jsx)("th", { className: "text-right py-2", children: "Amount" }), (0, jsx_runtime_1.jsx)("th", { className: "text-left py-2", children: "Reason" })] }) }), (0, jsx_runtime_1.jsx)("tbody", { children: history.map(record => ((0, jsx_runtime_1.jsxs)("tr", { className: "border-b border-neutral-800", children: [(0, jsx_runtime_1.jsx)("td", { className: "py-2 text-xs text-neutral-500", children: formatDate(record.created_at) }), (0, jsx_runtime_1.jsx)("td", { className: "py-2 text-neutral-300", children: record.manager_email || record.manager_id }), (0, jsx_runtime_1.jsx)("td", { className: "py-2 text-neutral-300", children: record.recipient_email || record.recipient_id }), (0, jsx_runtime_1.jsxs)("td", { className: "py-2 text-right text-white", children: ["+", Number(record.amount || 0).toFixed(2), " MCC"] }), (0, jsx_runtime_1.jsx)("td", { className: "py-2 text-xs text-neutral-500", children: record.reason || '-' })] }, record.id))) })] }) })) })), tab === 'leaderboard' && ((0, jsx_runtime_1.jsxs)("div", { className: "grid md:grid-cols-2 gap-6", children: [(0, jsx_runtime_1.jsx)(terminal_1.TerminalCard, { title: "Top Recipients", children: topRecipients.length === 0 ? ((0, jsx_runtime_1.jsx)("div", { className: "text-center py-4 text-neutral-500", children: "No data" })) : ((0, jsx_runtime_1.jsx)("div", { className: "space-y-3", children: topRecipients.map((entry, idx) => ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-3", children: [(0, jsx_runtime_1.jsx)("span", { className: `w-6 h-6 flex items-center justify-center rounded text-xs ${idx < 3 ? 'bg-cyan-400/20 text-cyan-300' : 'bg-neutral-800 text-neutral-400'}`, children: idx + 1 }), (0, jsx_runtime_1.jsx)("span", { className: "text-neutral-300", children: entry.email || entry.user_id })] }), (0, jsx_runtime_1.jsxs)("span", { className: "text-white", children: [Number(entry.total_received || 0).toFixed(2), " MCC"] })] }, entry.user_id))) })) }), (0, jsx_runtime_1.jsx)(terminal_1.TerminalCard, { title: "Top Senders", children: topSenders.length === 0 ? ((0, jsx_runtime_1.jsx)("div", { className: "text-center py-4 text-neutral-500", children: "No data" })) : ((0, jsx_runtime_1.jsx)("div", { className: "space-y-3", children: topSenders.map((entry, idx) => ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-3", children: [(0, jsx_runtime_1.jsx)("span", { className: `w-6 h-6 flex items-center justify-center rounded text-xs ${idx < 3 ? 'bg-cyan-400/20 text-cyan-300' : 'bg-neutral-800 text-neutral-400'}`, children: idx + 1 }), (0, jsx_runtime_1.jsx)("span", { className: "text-neutral-300", children: entry.email || entry.user_id })] }), (0, jsx_runtime_1.jsxs)("span", { className: "text-cyan-400", children: [Number(entry.total_sent || 0).toFixed(2), " MCC"] })] }, entry.user_id))) })) })] })), showSendDialog && ((0, jsx_runtime_1.jsx)("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/60 p-4", onClick: () => setShowSendDialog(false), children: (0, jsx_runtime_1.jsxs)("div", { className: "bg-neutral-900 border border-neutral-700 rounded-lg w-full max-w-md p-6 space-y-4", onClick: e => e.stopPropagation(), children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-white font-medium", children: "Send Single Reward" }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("label", { className: "text-xs text-[#5EEAD4] tracking-widest uppercase block mb-1", children: "Recipient UID" }), (0, jsx_runtime_1.jsx)("input", { type: "text", value: singleReward.recipient_id, onChange: (e) => setSingleReward({ ...singleReward, recipient_id: e.target.value }), className: "w-full bg-neutral-800 border border-neutral-600 text-white rounded px-3 py-2 text-sm", placeholder: "uid" })] }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("label", { className: "text-xs text-[#5EEAD4] tracking-widest uppercase block mb-1", children: "Amount (MCC)" }), (0, jsx_runtime_1.jsx)("input", { type: "number", min: 1, max: 10000, value: singleReward.amount, onChange: (e) => setSingleReward({ ...singleReward, amount: e.target.value }), className: "w-full bg-neutral-800 border border-neutral-600 text-white rounded px-3 py-2 text-sm", placeholder: "1-10000" })] }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("label", { className: "text-xs text-[#5EEAD4] tracking-widest uppercase block mb-1", children: "Reason" }), (0, jsx_runtime_1.jsx)("textarea", { value: singleReward.reason, onChange: (e) => setSingleReward({ ...singleReward, reason: e.target.value }), rows: 2, className: "w-full bg-neutral-800 border border-neutral-600 text-white rounded px-3 py-2 text-sm" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex gap-2", children: [(0, jsx_runtime_1.jsx)("button", { onClick: () => setShowSendDialog(false), className: "flex-1 px-3 py-2 border border-neutral-700 text-neutral-400 hover:bg-neutral-800 rounded text-sm", children: "Cancel" }), (0, jsx_runtime_1.jsx)("button", { onClick: handleSendReward, disabled: submitting, className: "flex-1 px-3 py-2 bg-cyan-700 hover:bg-cyan-600 text-white rounded text-sm disabled:opacity-50", children: submitting ? 'Sending...' : 'Send' })] })] }) })), showBatchDialog && ((0, jsx_runtime_1.jsx)("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/60 p-4", onClick: () => setShowBatchDialog(false), children: (0, jsx_runtime_1.jsxs)("div", { className: "bg-neutral-900 border border-neutral-700 rounded-lg w-full max-w-2xl p-6 space-y-4", onClick: e => e.stopPropagation(), children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-white font-medium", children: "Batch Reward Send" }), (0, jsx_runtime_1.jsxs)("div", { className: "space-y-2 max-h-96 overflow-y-auto", children: [batchRewards.map((r, i) => ((0, jsx_runtime_1.jsxs)("div", { className: "flex gap-2 items-start", children: [(0, jsx_runtime_1.jsx)("input", { value: r.user_id, onChange: (e) => {
|
|
110
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: "max-w-7xl mx-auto px-3 py-4 space-y-3 xs:px-4 xs:space-y-4 sm:px-6 sm:py-6 sm:space-y-6 font-mono", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between flex-wrap gap-3", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h1", { className: "text-lg sm:text-2xl font-bold text-white tracking-wider", children: t('title', 'Manager Rewards') }), (0, jsx_runtime_1.jsx)("p", { className: "text-xs sm:text-sm text-neutral-400", children: t('subtitle', 'Reward team members with your personal MCC') })] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex gap-2", children: [(0, jsx_runtime_1.jsx)("button", { onClick: () => setShowSendDialog(true), className: "px-3 py-1.5 bg-cyan-700 hover:bg-cyan-600 text-white rounded text-sm", children: t('sendReward', 'Send Reward') }), (0, jsx_runtime_1.jsx)("button", { onClick: () => setShowBatchDialog(true), className: "px-3 py-1.5 border border-neutral-700 text-neutral-400 hover:bg-neutral-800 hover:text-white rounded text-sm", children: t('batchSend', 'Batch Send') })] })] }), error && ((0, jsx_runtime_1.jsx)("div", { className: "p-3 bg-red-900/20 border border-red-800 rounded text-sm text-red-300", children: error })), stats && ((0, jsx_runtime_1.jsxs)("div", { className: "grid grid-cols-2 md:grid-cols-4 gap-4", children: [(0, jsx_runtime_1.jsxs)(terminal_1.TerminalCard, { children: [(0, jsx_runtime_1.jsx)("div", { className: "text-xs text-[#5EEAD4] tracking-widest uppercase mb-1", children: t('mccReceived', 'MCC Received') }), (0, jsx_runtime_1.jsx)("div", { className: "text-2xl font-bold text-white", children: Number(stats.total_received || 0).toFixed(2) })] }), (0, jsx_runtime_1.jsxs)(terminal_1.TerminalCard, { children: [(0, jsx_runtime_1.jsx)("div", { className: "text-xs text-[#5EEAD4] tracking-widest uppercase mb-1", children: t('mccSent', 'MCC Sent') }), (0, jsx_runtime_1.jsx)("div", { className: "text-2xl font-bold text-cyan-400", children: Number(stats.total_sent || 0).toFixed(2) })] }), (0, jsx_runtime_1.jsxs)(terminal_1.TerminalCard, { children: [(0, jsx_runtime_1.jsx)("div", { className: "text-xs text-[#5EEAD4] tracking-widest uppercase mb-1", children: t('receiveCount', 'Times Received') }), (0, jsx_runtime_1.jsx)("div", { className: "text-2xl font-bold text-white", children: stats.receive_count })] }), (0, jsx_runtime_1.jsxs)(terminal_1.TerminalCard, { children: [(0, jsx_runtime_1.jsx)("div", { className: "text-xs text-[#5EEAD4] tracking-widest uppercase mb-1", children: t('sendCount', 'Times Sent') }), (0, jsx_runtime_1.jsx)("div", { className: "text-2xl font-bold text-white", children: stats.send_count })] })] })), (0, jsx_runtime_1.jsxs)("div", { className: "flex gap-2 border-b border-neutral-800", children: [(0, jsx_runtime_1.jsx)("button", { onClick: () => setTab('history'), className: `px-4 py-2 text-sm ${tab === 'history' ? 'text-white border-b-2 border-cyan-400' : 'text-neutral-400 hover:text-white'}`, children: t('historyTab', 'History') }), (0, jsx_runtime_1.jsx)("button", { onClick: () => setTab('leaderboard'), className: `px-4 py-2 text-sm ${tab === 'leaderboard' ? 'text-white border-b-2 border-cyan-400' : 'text-neutral-400 hover:text-white'}`, children: t('leaderboardTab', 'Leaderboard') })] }), tab === 'history' && ((0, jsx_runtime_1.jsx)(terminal_1.TerminalCard, { title: t('rewardHistory', 'Reward History'), children: loading ? ((0, jsx_runtime_1.jsx)("div", { className: "text-center py-8 text-neutral-500", children: t('loadingText', 'Loading...') })) : history.length === 0 ? ((0, jsx_runtime_1.jsx)("div", { className: "text-center py-8 text-neutral-500", children: t('noRecords', 'No reward records') })) : ((0, jsx_runtime_1.jsx)("div", { className: "overflow-x-auto", children: (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: "text-xs text-neutral-400 border-b border-neutral-800", children: [(0, jsx_runtime_1.jsx)("th", { className: "text-left py-2", children: t('time', 'Time') }), (0, jsx_runtime_1.jsx)("th", { className: "text-left py-2", children: t('sender', 'Sender') }), (0, jsx_runtime_1.jsx)("th", { className: "text-left py-2", children: t('recipient', 'Recipient') }), (0, jsx_runtime_1.jsx)("th", { className: "text-right py-2", children: t('amount', 'Amount') }), (0, jsx_runtime_1.jsx)("th", { className: "text-left py-2", children: t('reason', 'Reason') })] }) }), (0, jsx_runtime_1.jsx)("tbody", { children: history.map(record => ((0, jsx_runtime_1.jsxs)("tr", { className: "border-b border-neutral-800", children: [(0, jsx_runtime_1.jsx)("td", { className: "py-2 text-xs text-neutral-500", children: formatDate(record.created_at) }), (0, jsx_runtime_1.jsx)("td", { className: "py-2 text-neutral-300", children: record.manager_email || record.manager_id }), (0, jsx_runtime_1.jsx)("td", { className: "py-2 text-neutral-300", children: record.recipient_email || record.recipient_id }), (0, jsx_runtime_1.jsxs)("td", { className: "py-2 text-right text-white", children: ["+", Number(record.amount || 0).toFixed(2), " MCC"] }), (0, jsx_runtime_1.jsx)("td", { className: "py-2 text-xs text-neutral-500", children: record.reason || '-' })] }, record.id))) })] }) })) })), tab === 'leaderboard' && ((0, jsx_runtime_1.jsxs)("div", { className: "grid md:grid-cols-2 gap-6", children: [(0, jsx_runtime_1.jsx)(terminal_1.TerminalCard, { title: t('topReceived', 'Most Received This Month'), children: topRecipients.length === 0 ? ((0, jsx_runtime_1.jsx)("div", { className: "text-center py-4 text-neutral-500", children: t('noData', 'No data') })) : ((0, jsx_runtime_1.jsx)("div", { className: "space-y-3", children: topRecipients.map((entry, idx) => ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-3", children: [(0, jsx_runtime_1.jsx)("span", { className: `w-6 h-6 flex items-center justify-center rounded text-xs ${idx < 3 ? 'bg-cyan-400/20 text-cyan-300' : 'bg-neutral-800 text-neutral-400'}`, children: idx + 1 }), (0, jsx_runtime_1.jsx)("span", { className: "text-neutral-300", children: entry.email || entry.user_id })] }), (0, jsx_runtime_1.jsxs)("span", { className: "text-white", children: [Number(entry.total_received || 0).toFixed(2), " MCC"] })] }, entry.user_id))) })) }), (0, jsx_runtime_1.jsx)(terminal_1.TerminalCard, { title: t('topSent', 'Most Sent This Month'), children: topSenders.length === 0 ? ((0, jsx_runtime_1.jsx)("div", { className: "text-center py-4 text-neutral-500", children: t('noData', 'No data') })) : ((0, jsx_runtime_1.jsx)("div", { className: "space-y-3", children: topSenders.map((entry, idx) => ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center justify-between", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-3", children: [(0, jsx_runtime_1.jsx)("span", { className: `w-6 h-6 flex items-center justify-center rounded text-xs ${idx < 3 ? 'bg-cyan-400/20 text-cyan-300' : 'bg-neutral-800 text-neutral-400'}`, children: idx + 1 }), (0, jsx_runtime_1.jsx)("span", { className: "text-neutral-300", children: entry.email || entry.user_id })] }), (0, jsx_runtime_1.jsxs)("span", { className: "text-cyan-400", children: [Number(entry.total_sent || 0).toFixed(2), " MCC"] })] }, entry.user_id))) })) })] })), showSendDialog && ((0, jsx_runtime_1.jsx)("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/60 p-4", onClick: () => setShowSendDialog(false), children: (0, jsx_runtime_1.jsxs)("div", { className: "bg-neutral-900 border border-neutral-700 rounded-lg w-full max-w-md p-6 space-y-4", onClick: e => e.stopPropagation(), children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-white font-medium", children: t('sendSingleTitle', 'Send Single Reward') }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("label", { className: "text-xs text-[#5EEAD4] tracking-widest uppercase block mb-1", children: t('recipientId', 'Recipient ID') }), (0, jsx_runtime_1.jsx)("input", { type: "text", value: singleReward.recipient_id, onChange: (e) => setSingleReward({ ...singleReward, recipient_id: e.target.value }), className: "w-full bg-neutral-800 border border-neutral-600 text-white rounded px-3 py-2 text-sm", placeholder: t('recipientPlaceholder', 'Enter user ID or email') })] }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("label", { className: "text-xs text-[#5EEAD4] tracking-widest uppercase block mb-1", children: t('rewardAmount', 'Reward Amount (MCC)') }), (0, jsx_runtime_1.jsx)("input", { type: "number", min: 1, max: 10000, value: singleReward.amount, onChange: (e) => setSingleReward({ ...singleReward, amount: e.target.value }), className: "w-full bg-neutral-800 border border-neutral-600 text-white rounded px-3 py-2 text-sm", placeholder: t('amountPlaceholder', 'Enter MCC amount') })] }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("label", { className: "text-xs text-[#5EEAD4] tracking-widest uppercase block mb-1", children: t('reasonLabel', 'Reason (optional)') }), (0, jsx_runtime_1.jsx)("textarea", { value: singleReward.reason, onChange: (e) => setSingleReward({ ...singleReward, reason: e.target.value }), rows: 2, className: "w-full bg-neutral-800 border border-neutral-600 text-white rounded px-3 py-2 text-sm" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex gap-2", children: [(0, jsx_runtime_1.jsx)("button", { onClick: () => setShowSendDialog(false), className: "flex-1 px-3 py-2 border border-neutral-700 text-neutral-400 hover:bg-neutral-800 rounded text-sm", children: t('cancel', 'Cancel') }), (0, jsx_runtime_1.jsx)("button", { onClick: handleSendReward, disabled: submitting, className: "flex-1 px-3 py-2 bg-cyan-700 hover:bg-cyan-600 text-white rounded text-sm disabled:opacity-50", children: submitting ? t('loadingText', 'Loading...') : t('send', 'Send') })] })] }) })), showBatchDialog && ((0, jsx_runtime_1.jsx)("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/60 p-4", onClick: () => setShowBatchDialog(false), children: (0, jsx_runtime_1.jsxs)("div", { className: "bg-neutral-900 border border-neutral-700 rounded-lg w-full max-w-2xl p-6 space-y-4", onClick: e => e.stopPropagation(), children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-white font-medium", children: t('batchTitle', 'Batch Send Rewards') }), (0, jsx_runtime_1.jsxs)("div", { className: "space-y-2 max-h-96 overflow-y-auto", children: [batchRewards.map((r, i) => ((0, jsx_runtime_1.jsxs)("div", { className: "flex gap-2 items-start", children: [(0, jsx_runtime_1.jsx)("input", { value: r.user_id, onChange: (e) => {
|
|
109
111
|
const next = [...batchRewards];
|
|
110
112
|
next[i] = { ...next[i], user_id: e.target.value };
|
|
111
113
|
setBatchRewards(next);
|
|
112
|
-
}, placeholder:
|
|
114
|
+
}, placeholder: t('userId', 'User ID'), className: "flex-1 bg-neutral-800 border border-neutral-600 text-white rounded px-2 py-1.5 text-sm" }), (0, jsx_runtime_1.jsx)("input", { type: "number", value: r.amount, onChange: (e) => {
|
|
113
115
|
const next = [...batchRewards];
|
|
114
116
|
next[i] = { ...next[i], amount: e.target.value };
|
|
115
117
|
setBatchRewards(next);
|
|
@@ -117,5 +119,5 @@ function MicrocosmRewardsPage({} = {}) {
|
|
|
117
119
|
const next = [...batchRewards];
|
|
118
120
|
next[i] = { ...next[i], reason: e.target.value };
|
|
119
121
|
setBatchRewards(next);
|
|
120
|
-
}, placeholder:
|
|
122
|
+
}, placeholder: t('reason', 'Reason'), className: "flex-1 bg-neutral-800 border border-neutral-600 text-white rounded px-2 py-1.5 text-sm" }), batchRewards.length > 1 && ((0, jsx_runtime_1.jsx)("button", { onClick: () => setBatchRewards(batchRewards.filter((_, idx) => idx !== i)), className: "px-2 py-1 text-red-400 hover:bg-red-900/20 rounded text-sm", children: "\u00D7" }))] }, i))), (0, jsx_runtime_1.jsxs)("button", { onClick: () => setBatchRewards([...batchRewards, { user_id: '', amount: '', reason: '' }]), className: "w-full px-3 py-2 border border-dashed border-neutral-700 text-neutral-400 hover:bg-neutral-800 rounded text-sm", children: ["+ ", t('addRow', 'Add Row')] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex gap-2", children: [(0, jsx_runtime_1.jsx)("button", { onClick: () => setShowBatchDialog(false), className: "flex-1 px-3 py-2 border border-neutral-700 text-neutral-400 hover:bg-neutral-800 rounded text-sm", children: t('cancel', 'Cancel') }), (0, jsx_runtime_1.jsx)("button", { onClick: handleBatchReward, disabled: submitting, className: "flex-1 px-3 py-2 bg-cyan-700 hover:bg-cyan-600 text-white rounded text-sm disabled:opacity-50", children: submitting ? t('loadingText', 'Loading...') : t('batchSend', 'Batch Send') })] })] }) }))] }));
|
|
121
123
|
}
|
|
@@ -6,6 +6,7 @@ const jsx_runtime_1 = require("react/jsx-runtime");
|
|
|
6
6
|
const react_1 = require("react");
|
|
7
7
|
const auth_react_1 = require("@microcosmmoney/auth-react");
|
|
8
8
|
const terminal_1 = require("../terminal");
|
|
9
|
+
const i18n_context_1 = require("../../i18n-context");
|
|
9
10
|
const API_BASE = 'https://api.microcosm.money/v1';
|
|
10
11
|
const cropToSquare = (file, size) => {
|
|
11
12
|
return new Promise((resolve, reject) => {
|
|
@@ -38,6 +39,7 @@ const cropToSquare = (file, size) => {
|
|
|
38
39
|
const UNIT_LABELS = { station: 'Station', matrix: 'Matrix', sector: 'Sector', system: 'System' };
|
|
39
40
|
const MAGISTRATE_TITLES = { station: 'Commander', matrix: 'Pioneer', sector: 'Warden', system: 'Admiral' };
|
|
40
41
|
function MicrocosmStationListPage({ currentUid, isAdmin = false } = {}) {
|
|
42
|
+
const t = (0, i18n_context_1.useTranslations)('stationList');
|
|
41
43
|
const api = (0, auth_react_1.useMicrocosmApi)();
|
|
42
44
|
const { getAccessToken } = (0, auth_react_1.useMicrocosmContext)();
|
|
43
45
|
const [units, setUnits] = (0, react_1.useState)([]);
|
|
@@ -117,11 +119,11 @@ function MicrocosmStationListPage({ currentUid, isAdmin = false } = {}) {
|
|
|
117
119
|
if (!file)
|
|
118
120
|
return;
|
|
119
121
|
if (!file.type.startsWith('image/')) {
|
|
120
|
-
setError('Please select an image file');
|
|
122
|
+
setError(t('selectImageFile', 'Please select an image file'));
|
|
121
123
|
return;
|
|
122
124
|
}
|
|
123
125
|
if (file.size > 2 * 1024 * 1024) {
|
|
124
|
-
setError('Image must
|
|
126
|
+
setError(t('imageTooLarge', 'Image must not exceed 2MB'));
|
|
125
127
|
return;
|
|
126
128
|
}
|
|
127
129
|
cropToSquare(file, 512)
|
|
@@ -131,7 +133,7 @@ function MicrocosmStationListPage({ currentUid, isAdmin = false } = {}) {
|
|
|
131
133
|
reader.onload = (ev) => setImagePreview(ev.target?.result);
|
|
132
134
|
reader.readAsDataURL(cropped);
|
|
133
135
|
})
|
|
134
|
-
.catch(() => setError('Image processing failed'));
|
|
136
|
+
.catch(() => setError(t('imageProcessError', 'Image processing failed')));
|
|
135
137
|
};
|
|
136
138
|
const uploadImage = async (unitId) => {
|
|
137
139
|
if (!imageFile)
|
|
@@ -203,16 +205,16 @@ function MicrocosmStationListPage({ currentUid, isAdmin = false } = {}) {
|
|
|
203
205
|
setSubmitting(false);
|
|
204
206
|
}
|
|
205
207
|
};
|
|
206
|
-
return ((0, jsx_runtime_1.jsxs)("div", { className: "max-w-7xl mx-auto px-3 py-4 space-y-3 xs:px-4 xs:space-y-4 sm:px-6 sm:py-6 sm:space-y-6 font-mono", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h1", { className: "text-lg sm:text-2xl font-bold text-white tracking-wider", children:
|
|
208
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: "max-w-7xl mx-auto px-3 py-4 space-y-3 xs:px-4 xs:space-y-4 sm:px-6 sm:py-6 sm:space-y-6 font-mono", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h1", { className: "text-lg sm:text-2xl font-bold text-white tracking-wider", children: t('title', 'Territory Management') }), (0, jsx_runtime_1.jsx)("p", { className: "text-xs sm:text-sm text-neutral-400", children: t('subtitle', 'Manage territories, view KPI and vault balances') })] }), error && ((0, jsx_runtime_1.jsx)("div", { className: "p-3 bg-red-900/20 border border-red-800 rounded text-sm text-red-300", children: error })), summary && ((0, jsx_runtime_1.jsxs)("div", { className: "grid grid-cols-2 md:grid-cols-4 gap-4", children: [(0, jsx_runtime_1.jsxs)(terminal_1.TerminalCard, { children: [(0, jsx_runtime_1.jsx)("div", { className: "text-xs text-[#5EEAD4] tracking-widest uppercase mb-1", children: "TOTAL STATIONS" }), (0, jsx_runtime_1.jsx)("div", { className: "text-2xl font-bold text-white", children: summary.total_stations ?? 0 })] }), (0, jsx_runtime_1.jsxs)(terminal_1.TerminalCard, { children: [(0, jsx_runtime_1.jsx)("div", { className: "text-xs text-[#5EEAD4] tracking-widest uppercase mb-1", children: "TOTAL MEMBERS" }), (0, jsx_runtime_1.jsx)("div", { className: "text-2xl font-bold text-cyan-400", children: summary.total_members ?? 0 })] }), (0, jsx_runtime_1.jsxs)(terminal_1.TerminalCard, { children: [(0, jsx_runtime_1.jsx)("div", { className: "text-xs text-[#5EEAD4] tracking-widest uppercase mb-1", children: "VAULT MCD" }), (0, jsx_runtime_1.jsx)("div", { className: "text-2xl font-bold text-cyan-400", children: (summary.total_vault_mcd ?? 0).toLocaleString(undefined, { maximumFractionDigits: 0 }) })] }), (0, jsx_runtime_1.jsxs)(terminal_1.TerminalCard, { children: [(0, jsx_runtime_1.jsx)("div", { className: "text-xs text-[#5EEAD4] tracking-widest uppercase mb-1", children: "AVG KPI" }), (0, jsx_runtime_1.jsx)("div", { className: "text-2xl font-bold text-white", children: (summary.avg_kpi_score ?? 0).toFixed(1) })] })] })), (0, jsx_runtime_1.jsx)(terminal_1.TerminalCard, { children: (0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col md:flex-row gap-4", children: [(0, jsx_runtime_1.jsx)("div", { className: "flex gap-2 flex-wrap", children: ['all', 'station', 'matrix', 'sector', 'system'].map(f => ((0, jsx_runtime_1.jsx)("button", { onClick: () => setFilter(f), className: `px-3 py-1.5 text-sm rounded transition-colors ${filter === f ? 'bg-cyan-700 text-white' : 'bg-neutral-800 text-neutral-400 hover:bg-neutral-700 hover:text-white'}`, children: f === 'all' ? t('all', 'All') : t(`unitTypeLabels.${f}`, UNIT_LABELS[f]) }, f))) }), (0, jsx_runtime_1.jsx)("input", { type: "text", value: searchTerm, onChange: (e) => setSearchTerm(e.target.value), placeholder: t('searchPlaceholder', 'Search territory name, path, location...'), className: "flex-1 bg-neutral-800 border border-neutral-600 text-white rounded px-3 py-1.5 text-sm focus:outline-none focus:border-cyan-400" })] }) }), loading ? ((0, jsx_runtime_1.jsx)("div", { className: "flex items-center justify-center py-20", children: (0, jsx_runtime_1.jsx)("span", { className: "text-neutral-400", children: t('loading', 'Loading units...') }) })) : filteredUnits.length === 0 ? ((0, jsx_runtime_1.jsx)(terminal_1.TerminalCard, { children: (0, jsx_runtime_1.jsx)("div", { className: "text-center py-8 text-neutral-500", children: t('noTerritories', 'no territories found') }) })) : ((0, jsx_runtime_1.jsx)("div", { className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4", children: filteredUnits.map(unit => {
|
|
207
209
|
const metrics = unitDataCache[unit.unit_id];
|
|
208
|
-
return ((0, jsx_runtime_1.jsxs)(terminal_1.TerminalCard, { children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-start justify-between mb-3", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("div", { className: "text-white font-semibold", children: unit.unit_name }), (0, jsx_runtime_1.jsxs)("div", { className: "text-xs text-neutral-500", children: [UNIT_LABELS[unit.unit_type], " \u00B7 ", MAGISTRATE_TITLES[unit.unit_type]] }), unit.short_id && ((0, jsx_runtime_1.jsx)("div", { className: "text-xs font-mono text-cyan-400 mt-1", children: unit.short_id }))] }), canEditUnit(unit) && ((0, jsx_runtime_1.jsx)("button", { onClick: () => openEditDialog(unit), className: "text-xs px-2 py-1 border border-neutral-700 text-neutral-400 hover:text-white hover:bg-neutral-800 rounded", children:
|
|
209
|
-
}) })), editingUnit && ((0, jsx_runtime_1.jsx)("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/60 p-4", onClick: () => setEditingUnit(null), children: (0, jsx_runtime_1.jsxs)("div", { className: "bg-neutral-900 border border-neutral-700 rounded-lg w-full max-w-lg p-6 space-y-4 max-h-[90vh] overflow-y-auto", onClick: e => e.stopPropagation(), children: [(0, jsx_runtime_1.jsxs)("h3", { className: "text-white font-medium", children: [
|
|
210
|
+
return ((0, jsx_runtime_1.jsxs)(terminal_1.TerminalCard, { children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-start justify-between mb-3", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("div", { className: "text-white font-semibold", children: unit.unit_name }), (0, jsx_runtime_1.jsxs)("div", { className: "text-xs text-neutral-500", children: [t(`unitTypeLabels.${unit.unit_type}`, UNIT_LABELS[unit.unit_type]), " \u00B7 ", MAGISTRATE_TITLES[unit.unit_type]] }), unit.short_id && ((0, jsx_runtime_1.jsx)("div", { className: "text-xs font-mono text-cyan-400 mt-1", children: unit.short_id }))] }), canEditUnit(unit) && ((0, jsx_runtime_1.jsx)("button", { onClick: () => openEditDialog(unit), className: "text-xs px-2 py-1 border border-neutral-700 text-neutral-400 hover:text-white hover:bg-neutral-800 rounded", children: t('edit', 'Edit') }))] }), unit.description && ((0, jsx_runtime_1.jsx)("div", { className: "text-xs text-neutral-400 mb-3 line-clamp-2", children: unit.description })), metrics && ((0, jsx_runtime_1.jsxs)("div", { className: "grid grid-cols-2 gap-2 pt-3 border-t border-neutral-700", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("div", { className: "text-xs text-neutral-500", children: t('members', 'Members') }), (0, jsx_runtime_1.jsxs)("div", { className: "text-sm text-white", children: [metrics.member_count, "/", metrics.max_capacity] })] }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("div", { className: "text-xs text-neutral-500", children: t('occupancy', 'Occupancy') }), (0, jsx_runtime_1.jsxs)("div", { className: "text-sm text-cyan-400", children: [(metrics.occupancy_rate * 100).toFixed(0), "%"] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "col-span-2", children: [(0, jsx_runtime_1.jsx)("div", { className: "text-xs text-neutral-500", children: "Vault MCD" }), (0, jsx_runtime_1.jsx)("div", { className: "text-sm text-white", children: (metrics.vault_mcd ?? 0).toLocaleString(undefined, { maximumFractionDigits: 0 }) })] })] })), unit.image_status === 'pending' && ((0, jsx_runtime_1.jsx)("div", { className: "mt-2 text-xs text-yellow-400", children: t('reviewPending', 'Under review') }))] }, unit.unit_id));
|
|
211
|
+
}) })), editingUnit && ((0, jsx_runtime_1.jsx)("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/60 p-4", onClick: () => setEditingUnit(null), children: (0, jsx_runtime_1.jsxs)("div", { className: "bg-neutral-900 border border-neutral-700 rounded-lg w-full max-w-lg p-6 space-y-4 max-h-[90vh] overflow-y-auto", onClick: e => e.stopPropagation(), children: [(0, jsx_runtime_1.jsxs)("h3", { className: "text-white font-medium", children: [t('editTerritory', 'Edit Territory'), ": ", editingUnit.unit_name] }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("label", { className: "text-xs text-[#5EEAD4] tracking-widest uppercase block mb-1", children: t('name', 'Name') }), (0, jsx_runtime_1.jsx)("input", { type: "text", value: editFormData.unit_name, onChange: (e) => setEditFormData({ ...editFormData, unit_name: e.target.value }), className: "w-full bg-neutral-800 border border-neutral-600 text-white rounded px-3 py-2 text-sm" })] }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("label", { className: "text-xs text-[#5EEAD4] tracking-widest uppercase block mb-1", children: t('description', 'Description') }), (0, jsx_runtime_1.jsx)("textarea", { value: editFormData.description, onChange: (e) => setEditFormData({ ...editFormData, description: e.target.value }), rows: 4, className: "w-full bg-neutral-800 border border-neutral-600 text-white rounded px-3 py-2 text-sm" })] }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("label", { className: "text-xs text-[#5EEAD4] tracking-widest uppercase block mb-1", children: t('image', 'Image') }), (0, jsx_runtime_1.jsxs)("div", { className: "flex items-start gap-3", children: [(imagePreview || editingUnit.image_url) ? ((0, jsx_runtime_1.jsx)("img", { src: imagePreview || editingUnit.image_url, alt: "", className: "w-24 h-24 rounded object-cover border border-neutral-700" })) : ((0, jsx_runtime_1.jsx)("div", { className: "w-24 h-24 rounded bg-neutral-800 border border-neutral-700 flex items-center justify-center text-xs text-neutral-500", children: t('noImage', 'No image') })), (0, jsx_runtime_1.jsxs)("div", { className: "flex-1 space-y-2", children: [(0, jsx_runtime_1.jsx)("input", { ref: fileInputRef, type: "file", accept: "image/jpeg,image/png,image/webp", onChange: handleFileSelect, className: "hidden" }), (0, jsx_runtime_1.jsx)("button", { onClick: () => fileInputRef.current?.click(), disabled: uploadingImage, className: "w-full px-3 py-1.5 border border-neutral-700 text-neutral-400 hover:bg-neutral-800 hover:text-white rounded text-sm", children: imageFile ? t('change', 'Change') : t('clickToUpload', 'Click to upload') }), imageFile && ((0, jsx_runtime_1.jsxs)("div", { className: "text-xs text-neutral-500", children: [imageFile.name, " (", (imageFile.size / 1024).toFixed(1), "KB)"] })), editingUnit.image_status && ((0, jsx_runtime_1.jsx)("div", { className: `text-xs px-2 py-0.5 rounded inline-block ${editingUnit.image_status === 'approved'
|
|
210
212
|
? 'bg-green-900/30 text-green-400'
|
|
211
213
|
: editingUnit.image_status === 'rejected'
|
|
212
214
|
? 'bg-red-900/30 text-red-400'
|
|
213
|
-
: 'bg-yellow-900/30 text-yellow-400'}`, children: editingUnit.image_status }))] })] }), (0, jsx_runtime_1.jsx)("p", { className: "text-xs text-neutral-500 mt-2", children:
|
|
215
|
+
: 'bg-yellow-900/30 text-yellow-400'}`, children: editingUnit.image_status }))] })] }), (0, jsx_runtime_1.jsx)("p", { className: "text-xs text-neutral-500 mt-2", children: t('imageHint', 'Max 2MB. Auto-cropped to square (512×512). JPG/PNG/WebP.') })] }), isAdmin && editingUnit.image_url && editingUnit.image_status === 'pending' && ((0, jsx_runtime_1.jsxs)("div", { className: "pt-3 border-t border-neutral-700 space-y-2", children: [(0, jsx_runtime_1.jsx)("div", { className: "text-xs text-cyan-400 tracking-wider", children: t('adminReview', 'ADMIN REVIEW') }), (0, jsx_runtime_1.jsxs)("div", { className: "flex gap-2", children: [(0, jsx_runtime_1.jsx)("button", { onClick: () => handleImageReview(editingUnit.unit_id, 'approved'), className: "flex-1 px-3 py-1.5 bg-green-900/30 text-green-400 hover:bg-green-900/50 border border-green-800 rounded text-sm", children: t('approve', 'Approve') }), (0, jsx_runtime_1.jsx)("button", { onClick: () => handleImageReview(editingUnit.unit_id, 'rejected'), className: "flex-1 px-3 py-1.5 bg-red-900/30 text-red-400 hover:bg-red-900/50 border border-red-800 rounded text-sm", children: t('reject', 'Reject') })] })] })), (0, jsx_runtime_1.jsxs)("div", { className: "flex gap-2 pt-2", children: [(0, jsx_runtime_1.jsx)("button", { onClick: () => {
|
|
214
216
|
setEditingUnit(null);
|
|
215
217
|
setImageFile(null);
|
|
216
218
|
setImagePreview(null);
|
|
217
|
-
}, className: "flex-1 px-3 py-2 border border-neutral-700 text-neutral-400 hover:bg-neutral-800 rounded text-sm", children:
|
|
219
|
+
}, className: "flex-1 px-3 py-2 border border-neutral-700 text-neutral-400 hover:bg-neutral-800 rounded text-sm", children: t('cancel', 'Cancel') }), (0, jsx_runtime_1.jsx)("button", { onClick: handleEdit, disabled: submitting || uploadingImage || !editFormData.unit_name.trim(), className: "flex-1 px-3 py-2 bg-cyan-700 hover:bg-cyan-600 text-white rounded text-sm disabled:opacity-50", children: uploadingImage ? t('uploading', 'Uploading...') : submitting ? t('saving', 'Saving...') : t('save', 'Save') })] })] }) }))] }));
|
|
218
220
|
}
|