Skip to content

Commit 97b22ef

Browse files
committed
Add admin, doctor, and patient dashboards
1 parent b2d6e9a commit 97b22ef

File tree

4 files changed

+252
-86
lines changed

4 files changed

+252
-86
lines changed

front_end/src/AdminDashboard.jsx

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
import React, { useEffect, useState } from 'react';
2+
import api from './api';
3+
import { Link } from 'react-router-dom';
4+
5+
export default function AdminDashboard() {
6+
const [users, setUsers] = useState([]);
7+
const [stats, setStats] = useState({});
8+
const [loading, setLoading] = useState(true);
9+
const [error, setError] = useState('');
10+
11+
useEffect(() => {
12+
async function fetchData() {
13+
setLoading(true);
14+
setError('');
15+
try {
16+
const [usersRes, patientsRes, doctorsRes, appointmentsRes, billingRes, medicinesRes, labTestsRes] = await Promise.all([
17+
api.get('/api/users'),
18+
api.get('/api/patients/stats/total'),
19+
api.get('/api/doctors/stats/total'),
20+
api.get('/api/appointments/stats/total'),
21+
api.get('/api/appointments/stats/billing'),
22+
api.get('/api/pharmacy/stats/total'),
23+
api.get('/api/lab/stats/total'),
24+
]);
25+
setUsers(usersRes.data);
26+
setStats({
27+
patients: patientsRes.data.total,
28+
doctors: doctorsRes.data.total,
29+
appointments: appointmentsRes.data.total,
30+
billing: billingRes.data.total,
31+
medicines: medicinesRes.data.total,
32+
labTests: labTestsRes.data.total,
33+
});
34+
} catch (err) {
35+
setError('Failed to load admin data.');
36+
}
37+
setLoading(false);
38+
}
39+
fetchData();
40+
}, []);
41+
42+
return (
43+
<div className="flex h-screen bg-gray-100">
44+
{/* Sidebar */}
45+
<aside className="w-64 bg-blue-900 text-white flex flex-col">
46+
<div className="p-6 text-2xl font-bold border-b border-blue-800">Healvista Admin</div>
47+
<nav className="flex-1 p-4">
48+
<ul className="space-y-2">
49+
<li><Link to="/admin" className="block p-2 rounded hover:bg-blue-800">Dashboard</Link></li>
50+
<li><Link to="/admin/users" className="block p-2 rounded hover:bg-blue-800">Users</Link></li>
51+
<li><Link to="/admin/stats" className="block p-2 rounded hover:bg-blue-800">Hospital Stats</Link></li>
52+
{/* Add more admin links here */}
53+
</ul>
54+
</nav>
55+
</aside>
56+
{/* Main Content */}
57+
<main className="flex-1 p-8 overflow-auto">
58+
<h2 className="text-3xl font-bold mb-6 text-blue-900">Admin Dashboard</h2>
59+
{loading ? (
60+
<div className="text-lg text-gray-600">Loading...</div>
61+
) : error ? (
62+
<div className="text-lg text-red-600">{error}</div>
63+
) : (
64+
<>
65+
<div className="grid grid-cols-3 gap-6 mb-8">
66+
<StatCard label="Patients" value={stats.patients} color="bg-blue-500" />
67+
<StatCard label="Doctors" value={stats.doctors} color="bg-green-500" />
68+
<StatCard label="Appointments" value={stats.appointments} color="bg-purple-500" />
69+
<StatCard label="Billing Records" value={stats.billing} color="bg-yellow-500" />
70+
<StatCard label="Medicines" value={stats.medicines} color="bg-pink-500" />
71+
<StatCard label="Lab Tests" value={stats.labTests} color="bg-indigo-500" />
72+
</div>
73+
<h3 className="text-2xl font-semibold mb-4 text-blue-800">All Users</h3>
74+
<div className="overflow-x-auto rounded shadow bg-white">
75+
<table className="min-w-full text-sm text-left">
76+
<thead className="bg-blue-100">
77+
<tr>
78+
<th className="p-3">User ID</th>
79+
<th className="p-3">Username</th>
80+
<th className="p-3">Full Name</th>
81+
<th className="p-3">Email</th>
82+
<th className="p-3">Phone</th>
83+
<th className="p-3">Role</th>
84+
</tr>
85+
</thead>
86+
<tbody>
87+
{users.map(user => (
88+
<tr key={user.user_id} className="even:bg-blue-50">
89+
<td className="p-3">{user.user_id}</td>
90+
<td className="p-3">{user.username}</td>
91+
<td className="p-3">{user.full_name}</td>
92+
<td className="p-3">{user.email}</td>
93+
<td className="p-3">{user.phone}</td>
94+
<td className="p-3 font-semibold capitalize">{user.role}</td>
95+
</tr>
96+
))}
97+
</tbody>
98+
</table>
99+
</div>
100+
</>
101+
)}
102+
</main>
103+
</div>
104+
);
105+
}
106+
107+
function StatCard({ label, value, color }) {
108+
return (
109+
<div className={`rounded-lg shadow p-6 text-white ${color} flex flex-col items-center`}>
110+
<div className="text-2xl font-bold">{value}</div>
111+
<div className="text-lg mt-2">{label}</div>
112+
</div>
113+
);
114+
}

front_end/src/App.js

Lines changed: 18 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1-
import React, { useEffect, useState } from 'react';
1+
import React from 'react';
22
import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom';
3+
import AdminDashboard from './AdminDashboard';
4+
import DoctorDashboard from './DoctorDashboard';
5+
import PatientDashboard from './PatientDashboard';
36
import Dashboard from './dashboard';
47
import Patient from './patient';
58
import Ward from './ward';
@@ -9,105 +12,34 @@ import Med from './med';
912
import Lab from './lab';
1013
import Doctors from './doc';
1114
import NeumorphicLogin from './Counter';
12-
import api from './api';
1315

14-
function AdminDashboard() {
15-
const [users, setUsers] = useState([]);
16-
const [stats, setStats] = useState({});
17-
const [loading, setLoading] = useState(true);
18-
const [error, setError] = useState('');
19-
20-
useEffect(() => {
21-
async function fetchData() {
22-
setLoading(true);
23-
setError('');
24-
try {
25-
const [usersRes, patientsRes, doctorsRes, appointmentsRes, billingRes, medicinesRes, labTestsRes] = await Promise.all([
26-
api.get('/users'),
27-
api.get('/patients/stats/total'),
28-
api.get('/doctors/stats/total'),
29-
api.get('/appointments/stats/total'),
30-
api.get('/appointments/stats/billing'),
31-
api.get('/pharmacy/stats/total'),
32-
api.get('/lab/stats/total'),
33-
]);
34-
setUsers(usersRes.data);
35-
setStats({
36-
patients: patientsRes.data.total,
37-
doctors: doctorsRes.data.total,
38-
appointments: appointmentsRes.data.total,
39-
billing: billingRes.data.total,
40-
medicines: medicinesRes.data.total,
41-
labTests: labTestsRes.data.total,
42-
});
43-
} catch (err) {
44-
setError('Failed to load admin data.');
45-
}
46-
setLoading(false);
47-
}
48-
fetchData();
49-
}, []);
50-
51-
if (loading) return <div style={{padding:40}}>Loading admin dashboard...</div>;
52-
if (error) return <div style={{padding:40, color:'red'}}>{error}</div>;
53-
54-
return (
55-
<div style={{padding:40}}>
56-
<h2>Admin Dashboard</h2>
57-
<h3>Hospital Stats</h3>
58-
<ul>
59-
<li><b>Total Patients:</b> {stats.patients}</li>
60-
<li><b>Total Doctors:</b> {stats.doctors}</li>
61-
<li><b>Total Appointments:</b> {stats.appointments}</li>
62-
<li><b>Total Billing Records:</b> {stats.billing}</li>
63-
<li><b>Total Medicines:</b> {stats.medicines}</li>
64-
<li><b>Total Lab Tests:</b> {stats.labTests}</li>
65-
</ul>
66-
<h3>All Users</h3>
67-
<table border="1" cellPadding="8" style={{marginTop:20, borderCollapse:'collapse'}}>
68-
<thead>
69-
<tr>
70-
<th>User ID</th>
71-
<th>Username</th>
72-
<th>Full Name</th>
73-
<th>Email</th>
74-
<th>Phone</th>
75-
<th>Role</th>
76-
</tr>
77-
</thead>
78-
<tbody>
79-
{users.map(user => (
80-
<tr key={user.user_id}>
81-
<td>{user.user_id}</td>
82-
<td>{user.username}</td>
83-
<td>{user.full_name}</td>
84-
<td>{user.email}</td>
85-
<td>{user.phone}</td>
86-
<td>{user.role}</td>
87-
</tr>
88-
))}
89-
</tbody>
90-
</table>
91-
</div>
92-
);
93-
}
94-
95-
function PrivateRoute({ children, adminOnly }) {
16+
function PrivateRoute({ children, adminOnly, doctorOnly, patientOnly }) {
9617
const token = localStorage.getItem('token');
9718
const user = JSON.parse(localStorage.getItem('user') || '{}');
9819
if (!token) return <Navigate to="/login" />;
9920
if (adminOnly && user.role !== 'admin') return <Navigate to="/" />;
21+
if (doctorOnly && user.role !== 'doctor') return <Navigate to="/" />;
22+
if (patientOnly && user.role !== 'patient') return <Navigate to="/" />;
10023
return children;
10124
}
10225

10326
function App() {
27+
const user = JSON.parse(localStorage.getItem('user') || '{}');
10428
return (
10529
<Router>
10630
<Routes>
10731
<Route path="/login" element={<NeumorphicLogin />} />
10832
<Route path="/admin" element={<PrivateRoute adminOnly={true}><AdminDashboard /></PrivateRoute>} />
109-
<Route path="/" element={<PrivateRoute><Dashboard /></PrivateRoute>} />
110-
<Route path="/patient" element={<PrivateRoute><Patient /></PrivateRoute>} />
33+
<Route path="/doctor" element={<PrivateRoute doctorOnly={true}><DoctorDashboard /></PrivateRoute>} />
34+
<Route path="/patient" element={<PrivateRoute patientOnly={true}><PatientDashboard /></PrivateRoute>} />
35+
{/* Fallback: redirect to role dashboard if logged in */}
36+
<Route path="/" element={
37+
user.role === 'admin' ? <Navigate to="/admin" /> :
38+
user.role === 'doctor' ? <Navigate to="/doctor" /> :
39+
user.role === 'patient' ? <Navigate to="/patient" /> :
40+
<Navigate to="/login" />
41+
} />
42+
{/* Other routes for legacy pages if needed */}
11143
<Route path="/ward" element={<PrivateRoute><Ward /></PrivateRoute>} />
11244
<Route path="/ambu" element={<PrivateRoute><Ambu /></PrivateRoute>} />
11345
<Route path="/fin" element={<PrivateRoute><Fin /></PrivateRoute>} />

front_end/src/DoctorDashboard.jsx

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import React from 'react';
2+
import { Link } from 'react-router-dom';
3+
4+
export default function DoctorDashboard() {
5+
// Mock data for demonstration
6+
const appointments = [
7+
{ id: 1, patient: 'John Doe', date: '2024-07-25', time: '10:00', status: 'Scheduled' },
8+
{ id: 2, patient: 'Jane Smith', date: '2024-07-25', time: '11:00', status: 'Completed' },
9+
];
10+
const patients = [
11+
{ id: 1, name: 'John Doe', diagnosis: 'Flu' },
12+
{ id: 2, name: 'Jane Smith', diagnosis: 'Diabetes' },
13+
];
14+
15+
return (
16+
<div className="flex h-screen bg-gray-100">
17+
{/* Sidebar */}
18+
<aside className="w-64 bg-green-900 text-white flex flex-col">
19+
<div className="p-6 text-2xl font-bold border-b border-green-800">Doctor Panel</div>
20+
<nav className="flex-1 p-4">
21+
<ul className="space-y-2">
22+
<li><Link to="/doctor" className="block p-2 rounded hover:bg-green-800">Dashboard</Link></li>
23+
<li><Link to="/doctor/appointments" className="block p-2 rounded hover:bg-green-800">Appointments</Link></li>
24+
<li><Link to="/doctor/patients" className="block p-2 rounded hover:bg-green-800">My Patients</Link></li>
25+
{/* Add more doctor links here */}
26+
</ul>
27+
</nav>
28+
</aside>
29+
{/* Main Content */}
30+
<main className="flex-1 p-8 overflow-auto">
31+
<h2 className="text-3xl font-bold mb-6 text-green-900">Doctor Dashboard</h2>
32+
<div className="grid grid-cols-2 gap-8 mb-8">
33+
<div className="bg-white rounded-lg shadow p-6">
34+
<h3 className="text-xl font-semibold mb-4 text-green-800">Today's Appointments</h3>
35+
<ul>
36+
{appointments.map(a => (
37+
<li key={a.id} className="mb-2 flex justify-between items-center border-b pb-2">
38+
<span>{a.time} - {a.patient}</span>
39+
<span className={`px-2 py-1 rounded text-xs ${a.status === 'Scheduled' ? 'bg-green-200 text-green-800' : 'bg-gray-200 text-gray-800'}`}>{a.status}</span>
40+
</li>
41+
))}
42+
</ul>
43+
</div>
44+
<div className="bg-white rounded-lg shadow p-6">
45+
<h3 className="text-xl font-semibold mb-4 text-green-800">My Patients</h3>
46+
<ul>
47+
{patients.map(p => (
48+
<li key={p.id} className="mb-2 flex justify-between items-center border-b pb-2">
49+
<span>{p.name}</span>
50+
<span className="text-gray-600 text-sm">{p.diagnosis}</span>
51+
</li>
52+
))}
53+
</ul>
54+
</div>
55+
</div>
56+
{/* Add more doctor features here */}
57+
</main>
58+
</div>
59+
);
60+
}

front_end/src/PatientDashboard.jsx

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import React from 'react';
2+
import { Link } from 'react-router-dom';
3+
4+
export default function PatientDashboard() {
5+
// Mock data for demonstration
6+
const appointments = [
7+
{ id: 1, doctor: 'Dr. Smith', date: '2024-07-25', time: '09:00', status: 'Scheduled' },
8+
{ id: 2, doctor: 'Dr. Johnson', date: '2024-07-26', time: '14:00', status: 'Completed' },
9+
];
10+
const labResults = [
11+
{ id: 1, test: 'Blood Test', result: 'Normal', date: '2024-07-20' },
12+
{ id: 2, test: 'X-Ray', result: 'Clear', date: '2024-07-18' },
13+
];
14+
15+
return (
16+
<div className="flex h-screen bg-gray-100">
17+
{/* Sidebar */}
18+
<aside className="w-64 bg-purple-900 text-white flex flex-col">
19+
<div className="p-6 text-2xl font-bold border-b border-purple-800">Patient Panel</div>
20+
<nav className="flex-1 p-4">
21+
<ul className="space-y-2">
22+
<li><Link to="/patient" className="block p-2 rounded hover:bg-purple-800">Dashboard</Link></li>
23+
<li><Link to="/patient/appointments" className="block p-2 rounded hover:bg-purple-800">My Appointments</Link></li>
24+
<li><Link to="/patient/lab-results" className="block p-2 rounded hover:bg-purple-800">Lab Results</Link></li>
25+
{/* Add more patient links here */}
26+
</ul>
27+
</nav>
28+
</aside>
29+
{/* Main Content */}
30+
<main className="flex-1 p-8 overflow-auto">
31+
<h2 className="text-3xl font-bold mb-6 text-purple-900">Patient Dashboard</h2>
32+
<div className="grid grid-cols-2 gap-8 mb-8">
33+
<div className="bg-white rounded-lg shadow p-6">
34+
<h3 className="text-xl font-semibold mb-4 text-purple-800">Upcoming Appointments</h3>
35+
<ul>
36+
{appointments.map(a => (
37+
<li key={a.id} className="mb-2 flex justify-between items-center border-b pb-2">
38+
<span>{a.date} {a.time} - {a.doctor}</span>
39+
<span className={`px-2 py-1 rounded text-xs ${a.status === 'Scheduled' ? 'bg-purple-200 text-purple-800' : 'bg-gray-200 text-gray-800'}`}>{a.status}</span>
40+
</li>
41+
))}
42+
</ul>
43+
</div>
44+
<div className="bg-white rounded-lg shadow p-6">
45+
<h3 className="text-xl font-semibold mb-4 text-purple-800">Lab Results</h3>
46+
<ul>
47+
{labResults.map(l => (
48+
<li key={l.id} className="mb-2 flex justify-between items-center border-b pb-2">
49+
<span>{l.test} ({l.date})</span>
50+
<span className="text-gray-600 text-sm">{l.result}</span>
51+
</li>
52+
))}
53+
</ul>
54+
</div>
55+
</div>
56+
{/* Add more patient features here */}
57+
</main>
58+
</div>
59+
);
60+
}

0 commit comments

Comments
 (0)