source: frontend/src/pages/appointments/AppointmentList.js@ 20468d3

Last change on this file since 20468d3 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: 5.0 KB
Line 
1import React, { useState, useEffect } from 'react';
2import { Link, useSearchParams } from 'react-router-dom';
3import { appointmentService } from '../../services/appointmentService';
4import Loading from '../../components/Loading';
5import ErrorAlert from '../../components/ErrorAlert';
6
7function AppointmentList() {
8 const [appointments, setAppointments] = useState([]);
9 const [loading, setLoading] = useState(true);
10 const [error, setError] = useState(null);
11 const [searchParams] = useSearchParams();
12 const doctorId = searchParams.get('doctorId');
13 const patientId = searchParams.get('patientId');
14 const user = JSON.parse(localStorage.getItem('user') || '{}');
15
16 useEffect(() => {
17 fetchAppointments();
18 }, [doctorId, patientId]);
19
20 const fetchAppointments = async () => {
21 try {
22 setLoading(true);
23 let response;
24 if (patientId) {
25 response = await appointmentService.getAppointmentsForPatient(patientId);
26 } else if (doctorId) {
27 response = await appointmentService.getAppointmentsForDoctor(doctorId);
28 } else if (user.role === 'PATIENT') {
29 response = await appointmentService.getAppointmentsForPatient(user.patientId);
30 } else if (user.role === 'DOCTOR') {
31 response = await appointmentService.getAppointmentsForDoctor(user.doctorId);
32 } else {
33 response = await appointmentService.getAllAppointments();
34 }
35 setAppointments(response.data);
36 } catch (err) {
37 setError('Failed to fetch appointments');
38 console.error(err);
39 } finally {
40 setLoading(false);
41 }
42 };
43
44 const handleCancelAppointment = async (id) => {
45 if (window.confirm('Are you sure you want to cancel this appointment?')) {
46 try {
47 await appointmentService.cancelAppointment(id);
48 setAppointments(appointments.map(apt =>
49 apt.appointmentId === id ? { ...apt, status: 'CANCELLED' } : apt
50 ));
51 } catch (err) {
52 setError('Failed to cancel appointment');
53 }
54 }
55 };
56
57 if (loading) return <Loading />;
58
59 return (
60 <div>
61 <div className="flex justify-between items-center mb-6">
62 <h1 className="text-3xl font-bold" style={{ color: '#7c3aed' }}>
63 {patientId ? 'Patient Appointments' : doctorId ? 'My Appointments' : 'All Appointments'}
64 </h1>
65 <Link to="/appointments/new" style={{
66 display: 'inline-block',
67 background: '#bfdbfe',
68 color: '#1e1035',
69 padding: '8px 16px',
70 borderRadius: '6px',
71 textDecoration: 'none',
72 fontSize: '14px',
73 fontWeight: '400'
74 }} onMouseEnter={(e) => e.currentTarget.style.background = '#93c5fd'} onMouseLeave={(e) => e.currentTarget.style.background = '#bfdbfe'}>
75 New Appointment
76 </Link>
77 </div>
78
79 {error && <ErrorAlert message={error} onClose={() => setError(null)} />}
80
81 <div className="bg-white rounded-lg shadow overflow-hidden">
82 <table className="w-full">
83 <thead className="bg-gray-100">
84 <tr>
85 <th className="px-6 py-3 text-left text-sm font-semibold">Patient</th>
86 <th className="px-6 py-3 text-left text-sm font-semibold">Doctor</th>
87 <th className="px-6 py-3 text-left text-sm font-semibold">Date</th>
88 <th className="px-6 py-3 text-left text-sm font-semibold">Time</th>
89 <th className="px-6 py-3 text-left text-sm font-semibold">Status</th>
90 <th className="px-6 py-3 text-left text-sm font-semibold">Actions</th>
91 </tr>
92 </thead>
93 <tbody>
94 {appointments.map(appointment => (
95 <tr key={appointment.appointmentId} className="border-t hover:bg-gray-50">
96 <td className="px-6 py-3">{appointment.patient?.firstName} {appointment.patient?.lastName}</td>
97 <td className="px-6 py-3">Dr. {appointment.doctor?.firstName} {appointment.doctor?.lastName}</td>
98 <td className="px-6 py-3">{appointment.appointmentDate}</td>
99 <td className="px-6 py-3">{appointment.appointmentTime}</td>
100 <td className="px-6 py-3">
101 <span className={`px-3 py-1 rounded text-sm font-semibold ${
102 appointment.status === 'SCHEDULED' ? 'bg-purple-100 text-purple-800' :
103 appointment.status === 'COMPLETED' ? 'bg-green-100 text-green-800' :
104 'bg-red-100 text-red-800'
105 }`}>
106 {appointment.status}
107 </span>
108 </td>
109 <td className="px-6 py-3">
110 {appointment.status === 'SCHEDULED' && (
111 <button
112 onClick={() => handleCancelAppointment(appointment.appointmentId)}
113 className="text-red-600 hover:underline px-3 py-2 text-sm font-medium"
114 >
115 Cancel
116 </button>
117 )}
118 </td>
119 </tr>
120 ))}
121 </tbody>
122 </table>
123 </div>
124 </div>
125 );
126}
127
128export default AppointmentList;
Note: See TracBrowser for help on using the repository browser.