source: frontend/src/pages/appointments/AppointmentList.js

Last change on this file was 9af201e, checked in by MBK <marija.karapandzova@…>, 11 days ago

Fix frontend appearance

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