implement TeleEMS platform architecture with centralized API client and master data management system

This commit is contained in:
2026-05-04 15:27:35 +05:30
parent e165269e92
commit 8dc773d205
61 changed files with 22829 additions and 0 deletions

244
src/App.tsx Normal file
View File

@@ -0,0 +1,244 @@
import React, { useEffect } from 'react';
import { BrowserRouter, Routes, Route, useLocation, Navigate } from 'react-router-dom';
import { Sidebar } from './components/Sidebar';
import { TopBar } from './components/TopBar';
import { ErrorBoundary } from './components/ErrorBoundary';
import { Dashboard } from './pages/Dashboard';
import { LiveIncidents } from './pages/LiveIncidents';
import { FleetDispatch } from './pages/FleetDispatch';
import { PatientClinical } from './pages/PatientClinical';
import { HospitalsNetwork } from './pages/HospitalsNetwork';
import { AnalyticsReports } from './pages/AnalyticsReports';
import { UserManagement } from './pages/UserManagement';
import { PlatformConfig } from './pages/PlatformConfig';
import { AuditCompliance } from './pages/AuditCompliance';
import { SystemHealth } from './pages/SystemHealth';
import { HospitalConsole } from './pages/HospitalConsole';
import { MasterDataManagement } from './pages/MasterData';
import { CallerPortal } from './pages/CallerPortal';
import { Login } from './pages/Login';
import { FleetLogin } from './pages/FleetLogin';
import { FleetOperatorDashboard } from './pages/FleetOperatorDashboard';
import { PerspectiveLauncher } from './pages/PerspectiveLauncher';
import { RoleLogin } from './pages/RoleLogin';
import { ComingSoonPortal } from './pages/ComingSoonPortal';
import {
Building2,
Stethoscope,
Activity,
User,
Scan,
ShoppingCart
} from 'lucide-react';
import { isTokenExpired, logout } from './utils/auth';
// --- ROLE-BASED ACCESS CONTROL ---
const RoleProtectedRoute: React.FC<{
children: React.ReactNode,
allowedRoles: string[],
user: any
}> = ({ children, allowedRoles, user }) => {
const isAuthenticated = localStorage.getItem('teleems_auth') === 'true';
if (!isAuthenticated) return <Navigate to="/login" replace />;
const userRoles = Array.isArray(user?.roles) ? user.roles : [];
const hasAccess = allowedRoles.some(role => userRoles.includes(role)) || userRoles.includes('CURESELECT_ADMIN');
if (!hasAccess) {
// Redirect to their respective "home" if they don't have access
if (userRoles.includes('FLEET_OPERATOR')) return <Navigate to="/fleet-operator" replace />;
return <Navigate to="/" replace />;
}
return <>{children}</>;
};
function AppContent() {
const location = useLocation();
// --- SESSION MONITORING ---
// Periodically check if the token has expired
useEffect(() => {
const checkSession = () => {
const token = localStorage.getItem('teleems_token');
const auth = localStorage.getItem('teleems_auth') === 'true';
if (auth && token && isTokenExpired(token)) {
console.warn('Session expired. Logging out...');
logout();
}
};
// Check on mount
checkSession();
// Check on every route change
checkSession();
// Periodically check every 30 seconds
const interval = setInterval(checkSession, 30000);
return () => clearInterval(interval);
}, [location.pathname]);
// --- DEVELOPMENT BYPASS ---
// In a real production app, this would be removed.
// For the user's request: "this admin so don't want login give me admin level access"
/* Commented out to allow testing of launcher and login flow
useEffect(() => {
const isAuth = localStorage.getItem('teleems_auth') === 'true';
const isCaller = window.location.pathname === '/caller';
const isLogin = window.location.pathname === '/login';
if (!isAuth && !isCaller && !isLogin) {
console.log('Dev Mode: Auto-authenticating as CureSelect Super Admin');
localStorage.setItem('teleems_auth', 'true');
localStorage.setItem('teleems_token', 'dev-super-token-2026');
localStorage.setItem('teleems_user', JSON.stringify({
id: 'admin-001',
username: 'CureSelect Super Admin',
roles: ['CURESELECT_ADMIN', 'ADMIN'],
metadata: {
organization: { company_name: 'CureSelect Healthcare LLP' }
}
}));
// Force reload to update navigation
window.location.reload();
}
}, []);
*/
const isLoginPage = location.pathname.startsWith('/login') || location.pathname === '/fleet-login' || location.pathname === '/launcher';
const isAuthenticated = localStorage.getItem('teleems_auth') === 'true';
const user = JSON.parse(localStorage.getItem('teleems_user') || '{}');
// --- PUBLIC ROUTES (No Auth Required) ---
if (isLoginPage || (location.pathname === '/' && !isAuthenticated)) {
return (
<Routes>
<Route path="/" element={<PerspectiveLauncher />} />
<Route path="/login" element={<Login />} />
<Route path="/login/:role" element={<RoleLogin />} />
<Route path="/fleet-login" element={<FleetLogin />} />
<Route path="/launcher" element={<PerspectiveLauncher />} />
<Route path="*" element={<Navigate to="/" replace />} />
</Routes>
);
}
// --- PROTECTED ROUTES (Auth Required) ---
if (!isAuthenticated) {
return <Navigate to="/login" replace />;
}
return (
<div className="dashboard-container">
<ErrorBoundary>
<Sidebar />
</ErrorBoundary>
<main className="main-content">
<div className="scanline" />
<TopBar />
<div style={{ flex: 1, overflow: 'hidden', position: 'relative', display: 'flex', flexDirection: 'column' }}>
<ErrorBoundary>
<Routes>
<Route path="/" element={
isAuthenticated ? (
user?.roles?.includes('FLEET_OPERATOR') && !user?.roles?.includes('CURESELECT_ADMIN')
? <Navigate to="/fleet-operator" replace />
: <Dashboard />
) : (
<Navigate to="/launcher" replace />
)
} />
<Route path="/incidents" element={
<RoleProtectedRoute allowedRoles={['CURESELECT_ADMIN', 'PILOT', 'COORDINATOR']} user={user}>
<LiveIncidents />
</RoleProtectedRoute>
} />
<Route path="/fleet" element={
<RoleProtectedRoute allowedRoles={['CURESELECT_ADMIN', 'STATION_INCHARGE']} user={user}>
<FleetDispatch />
</RoleProtectedRoute>
} />
<Route path="/clinical" element={
<RoleProtectedRoute allowedRoles={['CURESELECT_ADMIN', 'HOSPITAL_ADMIN', 'ED_DOCTOR', 'EMT']} user={user}>
<PatientClinical />
</RoleProtectedRoute>
} />
<Route path="/hospitals" element={
<RoleProtectedRoute allowedRoles={['CURESELECT_ADMIN']} user={user}>
<HospitalsNetwork />
</RoleProtectedRoute>
} />
<Route path="/analytics" element={
<RoleProtectedRoute allowedRoles={['CURESELECT_ADMIN', 'HOSPITAL_ADMIN', 'STATION_INCHARGE']} user={user}>
<AnalyticsReports />
</RoleProtectedRoute>
} />
<Route path="/users" element={
<RoleProtectedRoute allowedRoles={['CURESELECT_ADMIN']} user={user}>
<UserManagement />
</RoleProtectedRoute>
} />
<Route path="/config" element={
<RoleProtectedRoute allowedRoles={['CURESELECT_ADMIN']} user={user}>
<PlatformConfig />
</RoleProtectedRoute>
} />
<Route path="/compliance" element={
<RoleProtectedRoute allowedRoles={['CURESELECT_ADMIN', 'HOSPITAL_ADMIN']} user={user}>
<AuditCompliance />
</RoleProtectedRoute>
} />
<Route path="/health" element={
<RoleProtectedRoute allowedRoles={['CURESELECT_ADMIN']} user={user}>
<SystemHealth />
</RoleProtectedRoute>
} />
<Route path="/hospital-console" element={
<RoleProtectedRoute allowedRoles={['CURESELECT_ADMIN', 'HOSPITAL_ADMIN', 'ED_DOCTOR', 'COORDINATOR', 'EMT']} user={user}>
<HospitalConsole />
</RoleProtectedRoute>
} />
<Route path="/master-data" element={
<RoleProtectedRoute allowedRoles={['CURESELECT_ADMIN']} user={user}>
<MasterDataManagement />
</RoleProtectedRoute>
} />
<Route path="/caller" element={<CallerPortal />} />
<Route path="/fleet-operator" element={
<RoleProtectedRoute allowedRoles={['CURESELECT_ADMIN', 'FLEET_OPERATOR']} user={user}>
<FleetOperatorDashboard />
</RoleProtectedRoute>
} />
{/* --- NEW PERSPECTIVE PORTALS --- */}
<Route path="/launcher" element={<PerspectiveLauncher />} />
<Route path="/hospital-group" element={<ComingSoonPortal title="Hospital Group" icon={Building2} />} />
<Route path="/provider" element={<ComingSoonPortal title="Provider" icon={Stethoscope} />} />
<Route path="/provider-react" element={<ComingSoonPortal title="Provider React" icon={Activity} />} />
<Route path="/patient-portal" element={<ComingSoonPortal title="Patient" icon={User} />} />
<Route path="/scan-centre" element={<ComingSoonPortal title="Scan Centre" icon={Scan} />} />
<Route path="/cart" element={<ComingSoonPortal title="Cart / Mobile" icon={ShoppingCart} />} />
</Routes>
</ErrorBoundary>
</div>
</main>
</div>
);
}
function App() {
return (
<BrowserRouter>
<AppContent />
</BrowserRouter>
);
}
export default App;