source: frontend/src/pages/doctors/DoctorList.js

Last change on this file was 20468d3, checked in by MBK <marija.karapandzova@…>, 4 months ago

Add pages and routing for patients, doctors, departments and appointments with api services

  • Property mode set to 100644
File size: 4.2 KB
Line 
1import React, { useState, useEffect } from 'react';
2import { Link } from 'react-router-dom';
3import { doctorService } from '../../services/doctorService';
4import Loading from '../../components/Loading';
5import ErrorAlert from '../../components/ErrorAlert';
6
7function DoctorList() {
8 const user = JSON.parse(localStorage.getItem('user') || '{}');
9 const isAdmin = user.role === 'ADMIN';
10 const [doctors, setDoctors] = useState([]);
11 const [loading, setLoading] = useState(true);
12 const [error, setError] = useState(null);
13 const [searchTerm, setSearchTerm] = useState('');
14
15 useEffect(() => {
16 fetchDoctors();
17 }, []);
18
19 const fetchDoctors = async () => {
20 try {
21 setLoading(true);
22 const response = await doctorService.getAllDoctors();
23 setDoctors(response.data);
24 } catch (err) {
25 setError('Failed to fetch doctors');
26 console.error(err);
27 } finally {
28 setLoading(false);
29 }
30 };
31
32 const filteredDoctors = doctors.filter(doctor =>
33 doctor.firstName.toLowerCase().includes(searchTerm.toLowerCase()) ||
34 doctor.lastName.toLowerCase().includes(searchTerm.toLowerCase()) ||
35 doctor.emailAddress.includes(searchTerm)
36 );
37
38 if (loading) return <Loading />;
39
40 return (
41 <div>
42 <div className="flex justify-between items-center mb-6">
43 <h1 className="text-3xl font-bold" style={{ color: '#7c3aed' }}>Doctors</h1>
44 {isAdmin && (
45 <Link to="/doctors/new" style={{
46 display: 'inline-block',
47 background: '#bfdbfe',
48 color: '#1e1035',
49 padding: '8px 16px',
50 borderRadius: '6px',
51 textDecoration: 'none',
52 fontSize: '14px',
53 fontWeight: '400'
54 }} onMouseEnter={(e) => e.currentTarget.style.background = '#93c5fd'} onMouseLeave={(e) => e.currentTarget.style.background = '#bfdbfe'}>
55 Add Doctor
56 </Link>
57 )}
58 </div>
59
60 {error && <ErrorAlert message={error} onClose={() => setError(null)} />}
61
62 <div className="mb-6">
63 <input
64 type="text"
65 placeholder="Search by name or email..."
66 className="w-full px-4 py-2 border rounded-lg"
67 value={searchTerm}
68 onChange={(e) => setSearchTerm(e.target.value)}
69 />
70 </div>
71
72 <div className="bg-white rounded-lg shadow overflow-hidden">
73 <table className="w-full">
74 <thead className="bg-gray-100">
75 <tr>
76 <th className="px-6 py-3 text-left text-sm font-semibold">Name</th>
77 <th className="px-6 py-3 text-left text-sm font-semibold">Email</th>
78 <th className="px-6 py-3 text-left text-sm font-semibold">Specialization</th>
79 <th className="px-6 py-3 text-left text-sm font-semibold">Level</th>
80 <th className="px-6 py-3 text-left text-sm font-semibold">Department</th>
81 <th className="px-6 py-3 text-left text-sm font-semibold">Actions</th>
82 </tr>
83 </thead>
84 <tbody>
85 {filteredDoctors.map(doctor => (
86 <tr key={doctor.doctorId} className="border-t hover:bg-gray-50">
87 <td className="px-6 py-3">{doctor.firstName} {doctor.lastName}</td>
88 <td className="px-6 py-3">{doctor.emailAddress}</td>
89 <td className="px-6 py-3">{doctor.specialization?.specializationName || 'N/A'}</td>
90 <td className="px-6 py-3">{doctor.level?.level || 'N/A'}</td>
91 <td className="px-6 py-3">{doctor.department?.departmentName ? doctor.department.departmentName.replace(/_DEPT$/, '').replace(/_/g, ' ').split(' ').map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(' ') : 'N/A'}</td>
92 <td className="px-6 py-3">
93 <Link to={`/doctors/${doctor.doctorId}`} style={{ color: '#7c3aed', textDecoration: 'none', fontWeight: '400' }} onMouseEnter={(e) => e.currentTarget.style.textDecoration = 'underline'} onMouseLeave={(e) => e.currentTarget.style.textDecoration = 'none'}>
94 View
95 </Link>
96 </td>
97 </tr>
98 ))}
99 </tbody>
100 </table>
101 </div>
102 </div>
103 );
104}
105
106export default DoctorList;
Note: See TracBrowser for help on using the repository browser.