Files
turnosxpress/txadmin/src/App.tsx
T
horacio 28295e346c feat: add TypeScript definitions and utility functions for date formatting
- Created a global TypeScript declaration for the txadmin interface on the Window object.
- Implemented date formatting utilities using date-fns with Spanish locale support.
- Added TypeScript configuration files for app, Electron, and Node environments.
- Set up Vite configuration for React application.
2026-08-14 19:13:32 -03:00

100 lines
3.5 KiB
TypeScript

import { useEffect, useState } from 'react';
import { HashRouter, Routes, Route } from 'react-router-dom';
import { Minus, Square, X } from 'lucide-react';
import { DashboardLayout } from './components/layout/DashboardLayout';
import { DashboardPage } from './pages/DashboardPage';
import { UsersPage } from './pages/UsersPage';
import { WapServersPage } from './pages/WapServersPage';
import { CompaniesPage } from './pages/CompaniesPage';
import { PlansPage } from './pages/PlansPage';
import txadminIcon from './assets/txadmin-icon.png';
const TitleBar = () => (
<header className="app-titlebar">
<div className="app-titlebar-brand">
<img className="app-titlebar-logo" src={txadminIcon} alt="txadmin" />
<span>txadmin</span>
</div>
<div className="app-titlebar-actions">
<button type="button" aria-label="Minimize window" onClick={() => void window.txadmin.minimizeWindow()}>
<Minus size={16} />
</button>
<button type="button" aria-label="Maximize window" onClick={() => void window.txadmin.toggleMaximizeWindow()}>
<Square size={13} />
</button>
<button type="button" className="close" aria-label="Close window" onClick={() => void window.txadmin.closeWindow()}>
<X size={16} />
</button>
</div>
</header>
);
function App() {
const [keyStatus, setKeyStatus] = useState<{ loaded: boolean; path: string | null }>({ loaded: false, path: null });
const [error, setError] = useState<string | null>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
if (!window.txadmin) {
setError('Desktop bridge is not available. Restart txadmin and try again.');
setLoading(false);
return;
}
window.txadmin.getKeyStatus()
.then(setKeyStatus)
.catch(() => setError('Could not read private key status.'))
.finally(() => setLoading(false));
}, []);
const selectPrivateKey = async () => {
setError(null);
try {
setKeyStatus(await window.txadmin.selectPrivateKey());
} catch (err) {
setError(err instanceof Error ? err.message : 'Could not load the private key.');
}
};
if (loading) {
return <div className="app-shell"><TitleBar /><div className="key-gate">Loading txadmin...</div></div>;
}
if (!keyStatus.loaded) {
return (
<div className="app-shell">
<TitleBar />
<div className="key-gate">
<div className="glass-panel key-gate-card">
<img className="key-gate-logo" src={txadminIcon} alt="txadmin" />
<h1>txadmin</h1>
<p>Load the sysadmin private key to unlock admin functions.</p>
<button className="primary-button" onClick={selectPrivateKey}>Select Private Key</button>
<p className="key-gate-hint">Expected equivalent: sysadmin/keys/tx-sysadmin-private.key</p>
{error && <p className="key-gate-error">{error}</p>}
</div>
</div>
</div>
);
}
return (
<div className="app-shell">
<TitleBar />
<HashRouter>
<Routes>
<Route path="/" element={<DashboardLayout keyPath={keyStatus.path} onSelectPrivateKey={selectPrivateKey} />}>
<Route index element={<DashboardPage />} />
<Route path="users" element={<UsersPage />} />
<Route path="companies" element={<CompaniesPage />} />
<Route path="plans" element={<PlansPage />} />
<Route path="wapservers" element={<WapServersPage />} />
</Route>
</Routes>
</HashRouter>
</div>
);
}
export default App;