Changeset 9af201e for frontend/src/pages


Ignore:
Timestamp:
09/04/26 19:08:08 (2 weeks ago)
Author:
MBK <marija.karapandzova@…>
Branches:
master
Children:
cdcff72
Parents:
e1f74f6
Message:

Fix frontend appearance

Location:
frontend/src/pages
Files:
3 added
1 deleted
17 edited

Legend:

Unmodified
Added
Removed
  • frontend/src/pages/Dashboard.js

    re1f74f6 r9af201e  
    66import { labService } from '../services/labService';
    77import { billingService } from '../services/billingService';
    8 import { medicalRecordService } from '../services/medicalRecordService';
    98import Loading from '../components/Loading';
    109
     
    1918  const [pendingLabTests, setPendingLabTests] = useState([]);
    2019  const [billings, setBillings] = useState([]);
    21   const [medicalRecords, setMedicalRecords] = useState([]);
    2220  const [patientBillings, setPatientBillings] = useState([]);
    2321  const [loading, setLoading] = useState(true);
     
    3331        if (isPatient) {
    3432          // For patients, fetch their own appointments, medical records, and billing
    35           const [appointmentsRes, medicalRes, billingRes] = await Promise.all([
     33          const [appointmentsRes, billingRes] = await Promise.all([
    3634            appointmentService.getAppointmentsForPatient(user.patientId),
    37             medicalRecordService.getMedicalRecordByPatientId(user.patientId),
    3835            billingService.getBillingHistoryForPatient(user.patientId)
    3936          ]);
    4037          setUserAppointments(appointmentsRes.data || []);
    41           // Handle medical records - could be single object or array
    42           const medicalData = medicalRes.data;
    43           const medicalArray = Array.isArray(medicalData) ? medicalData : (medicalData ? [medicalData] : []);
    44           setMedicalRecords(medicalArray);
    4538          setPatientBillings(billingRes.data || []);
    4639        } else if (isDoctor) {
     
    8275
    8376    fetchStats();
    84   }, [user.userId, isPatient, isDoctor, isLabTechnician]);
     77  }, []);
    8578
    8679  if (loading) return <Loading />;
  • frontend/src/pages/Login.js

    re1f74f6 r9af201e  
    7575
    7676  return (
    77       <div className="min-h-screen bg-blue-200 flex items-center justify-center p-4">
    78         <div className="bg-white rounded-lg shadow-2xl p-8 w-full max-w-md">
    79           <div className="text-center mb-8">
    80             <h1 className="text-5xl font-bold text-purple-600 mb-2">Medora</h1>
    81             <p className="text-gray-600">Hospital Management System</p>
     77    <div className="min-h-screen bg-blue-200 flex items-center justify-center p-4">
     78      <div className="bg-white rounded-lg shadow-2xl p-8 w-full max-w-md">
     79        <div className="text-center mb-8">
     80          <h1 className="text-5xl font-bold text-purple-600 mb-2">Medora</h1>
     81          <p className="text-gray-600">Hospital Management System</p>
     82        </div>
     83
     84        {error && <ErrorAlert message={error} onClose={() => setError(null)} />}
     85        {success && <SuccessAlert message={success} onClose={() => setSuccess(null)} />}
     86
     87        <form onSubmit={handleLogin} className="space-y-6">
     88          <div>
     89            <label className="block text-sm font-normal text-gray-700 mb-2">
     90              Username (EMBG for Patients)
     91            </label>
     92            <input
     93              type="text"
     94              value={username}
     95              onChange={(e) => setUsername(e.target.value)}
     96              placeholder="Enter your username or EMBG"
     97              className="w-full px-4 py-3 border-2 border-gray-300 rounded-lg focus:outline-none focus:border-purple-500 transition"
     98              disabled={loading}
     99            />
    82100          </div>
    83101
    84           {error && <ErrorAlert message={error} onClose={() => setError(null)} />}
    85           {success && <SuccessAlert message={success} onClose={() => setSuccess(null)} />}
     102          <div>
     103            <label className="block text-sm font-normal text-gray-700 mb-2">
     104              Password
     105            </label>
     106            <input
     107              type="password"
     108              value={password}
     109              onChange={(e) => setPassword(e.target.value)}
     110              placeholder="Enter your password"
     111              className="w-full px-4 py-3 border-2 border-gray-300 rounded-lg focus:outline-none focus:border-purple-500 transition"
     112              disabled={loading}
     113            />
     114          </div>
    86115
    87           <form onSubmit={handleLogin} className="space-y-6">
    88             <div>
    89               <label className="block text-sm font-normal text-gray-700 mb-2">
    90                 Username (EMBG for Patients)
    91               </label>
    92               <input
    93                   type="text"
    94                   value={username}
    95                   onChange={(e) => setUsername(e.target.value)}
    96                   placeholder="Enter your username or EMBG"
    97                   className="w-full px-4 py-3 border-2 border-gray-300 rounded-lg focus:outline-none focus:border-purple-500 transition"
    98                   disabled={loading}
    99               />
    100             </div>
     116          <button
     117            type="submit"
     118            disabled={loading}
     119            className="w-full bg-purple-600 text-white font-bold py-3 rounded-lg hover:bg-purple-700 transition disabled:opacity-50 disabled:cursor-not-allowed"
     120          >
     121            {loading ? 'Logging in...' : 'Login'}
     122          </button>
     123        </form>
    101124
    102             <div>
    103               <label className="block text-sm font-normal text-gray-700 mb-2">
    104                 Password
    105               </label>
    106               <input
    107                   type="password"
    108                   value={password}
    109                   onChange={(e) => setPassword(e.target.value)}
    110                   placeholder="Enter your password"
    111                   className="w-full px-4 py-3 border-2 border-gray-300 rounded-lg focus:outline-none focus:border-purple-500 transition"
    112                   disabled={loading}
    113               />
    114             </div>
    115 
    116             <button
    117                 type="submit"
    118                 disabled={loading}
    119                 className="w-full bg-purple-600 text-white font-bold py-3 rounded-lg hover:bg-purple-700 transition disabled:opacity-50 disabled:cursor-not-allowed"
    120             >
    121               {loading ? 'Logging in...' : 'Login'}
    122             </button>
    123           </form>
    124 
    125           <div className="mt-8 p-4 bg-purple-50 rounded-lg border border-purple-200">
    126             <p className="text-sm text-gray-700 font-normal mb-2">Demo Credentials:</p>
    127             <p className="text-sm text-gray-600 mb-2">
    128               <strong>Admin:</strong> username: admin | password: admin123
    129             </p>
    130             <p className="text-sm text-gray-600 mb-2">
    131               <strong>Doctor:</strong> username: ivan.stojanov@medora.com | password: doctor123
    132             </p>
    133             <p className="text-sm text-gray-600">
    134               <strong>Patient:</strong> username: [EMBG] | password: password123
    135             </p>
    136           </div>
     125        <div className="mt-8 p-4 bg-purple-50 rounded-lg border border-purple-200">
     126          <p className="text-sm text-gray-700 font-normal mb-2">Demo Credentials:</p>
     127          <p className="text-sm text-gray-600 mb-2">
     128            <strong>Admin:</strong> username: admin | password: admin123
     129          </p>
     130          <p className="text-sm text-gray-600 mb-2">
     131            <strong>Doctor:</strong> username: ivan.stojanov@medora.com | password: doctor123
     132          </p>
     133          <p className="text-sm text-gray-600">
     134            <strong>Patient:</strong> username: [EMBG] | password: password123
     135          </p>
    137136        </div>
    138137      </div>
     138    </div>
    139139  );
    140140}
  • frontend/src/pages/appointments/AppointmentForm.js

    re1f74f6 r9af201e  
    2626
    2727  useEffect(() => {
     28    const fetchData = async () => {
     29      try {
     30        if (!isPatient) {
     31          const patientsRes = await patientService.getAllPatients();
     32          setPatients(patientsRes.data);
     33        }
     34
     35        const doctorsRes = await doctorService.getAllDoctors();
     36        setDoctors(doctorsRes.data);
     37      } catch (err) {
     38        setError('Failed to fetch doctors');
     39      }
     40    };
     41
    2842    fetchData();
    29   }, []);
    30 
    31   const fetchData = async () => {
    32     try {
    33       // For patients, we don't need to fetch all patients
    34       if (!isPatient) {
    35         const patientsRes = await patientService.getAllPatients();
    36         setPatients(patientsRes.data);
    37       }
    38 
    39       const doctorsRes = await doctorService.getAllDoctors();
    40       setDoctors(doctorsRes.data);
    41     } catch (err) {
    42       setError('Failed to fetch doctors');
    43     }
    44   };
     43  }, [isPatient]);
    4544
    4645  const handleChange = (e) => {
  • frontend/src/pages/appointments/AppointmentList.js

    re1f74f6 r9af201e  
    1515
    1616  useEffect(() => {
    17     fetchAppointments();
     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();
    1838  }, [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   };
    4339
    4440  const handleCancelAppointment = async (id) => {
     
    4743        await appointmentService.cancelAppointment(id);
    4844        setAppointments(appointments.map(apt =>
    49             apt.appointmentId === id ? { ...apt, status: 'CANCELLED' } : apt
     45          apt.appointmentId === id ? { ...apt, status: 'CANCELLED' } : apt
    5046        ));
    5147      } catch (err) {
     
    5854
    5955  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>
     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>
    7874
    79         {error && <ErrorAlert message={error} onClose={() => setError(null)} />}
     75      {error && <ErrorAlert message={error} onClose={() => setError(null)} />}
    8076
    81         <div className="bg-white rounded-lg shadow overflow-hidden">
    82           <table className="w-full">
    83             <thead className="bg-gray-100">
     77      <div className="bg-white rounded-lg shadow overflow-hidden">
     78        <table className="w-full">
     79          <thead className="bg-gray-100">
    8480            <tr>
    8581              <th className="px-6 py-3 text-left text-sm font-semibold">Patient</th>
     
    9086              <th className="px-6 py-3 text-left text-sm font-semibold">Actions</th>
    9187            </tr>
    92             </thead>
    93             <tbody>
     88          </thead>
     89          <tbody>
    9490            {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">
     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">
    10197                  <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'
     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'
    105101                  }`}>
    106102                    {appointment.status}
    107103                  </span>
    108                   </td>
    109                   <td className="px-6 py-3">
    110                     {appointment.status === 'SCHEDULED' && (
    111                         (user.role === 'DOCTOR' && appointment.doctor?.doctorId !== user.doctorId) ? null : (
    112                             <button
    113                                 onClick={() => handleCancelAppointment(appointment.appointmentId)}
    114                                 className="text-red-600 hover:underline px-3 py-2 text-sm font-medium"
    115                             >
    116                               Cancel
    117                             </button>
    118                         )
    119                     )}
    120                   </td>
    121                 </tr>
     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>
    122118            ))}
    123             </tbody>
    124           </table>
    125         </div>
     119          </tbody>
     120        </table>
    126121      </div>
     122    </div>
    127123  );
    128124}
  • frontend/src/pages/billing/BillingDetail.js

    re1f74f6 r9af201e  
    2222
    2323  useEffect(() => {
    24     fetchBilling();
    25   }, [id]);
    26 
    27   const fetchBilling = async () => {
    28     try {
    29       setLoading(true);
    30       const response = await billingService.getBillingById(id);
     24    const fetchBilling = async () => {
     25      try {
     26        setLoading(true);
     27        const response = await billingService.getBillingById(id);
    3128      setBilling(response.data);
    3229      setPaymentStatus(response.data.paymentStatus);
     
    3936        console.error('Could not fetch billing details:', err);
    4037      }
    41     } catch (err) {
    42       setError('Failed to fetch billing record');
    43       console.error(err);
    44     } finally {
    45       setLoading(false);
    46     }
    47   };
     38      } catch (err) {
     39        setError('Failed to fetch billing record');
     40        console.error(err);
     41      } finally {
     42        setLoading(false);
     43      }
     44    };
     45
     46    fetchBilling();
     47  }, [id]);
    4848
    4949  const handleUpdatePaymentStatus = async () => {
     
    8181  if (user.role === 'DOCTOR' || user.role === 'LAB_TECHNICIAN') {
    8282    return (
    83         <div style={{ padding: '20px', textAlign: 'center' }}>
    84           <h1 className="text-2xl font-bold" style={{ color: '#7c3aed', marginBottom: '10px' }}>Access Denied</h1>
    85           <p style={{ color: 'var(--color-neutral-600)' }}>You do not have permission to access billing records.</p>
    86         </div>
     83      <div style={{ padding: '20px', textAlign: 'center' }}>
     84        <h1 className="text-2xl font-bold" style={{ color: '#7c3aed', marginBottom: '10px' }}>Access Denied</h1>
     85        <p style={{ color: 'var(--color-neutral-600)' }}>You do not have permission to access billing records.</p>
     86      </div>
    8787    );
    8888  }
     
    9090  if (!billing) {
    9191    return (
    92         <div>
    93           <ErrorAlert message="Billing record not found" onClose={() => navigate('/billing')} />
    94         </div>
     92      <div>
     93        <ErrorAlert message="Billing record not found" onClose={() => navigate('/billing')} />
     94      </div>
    9595    );
    9696  }
    9797
    9898  return (
    99       <div>
    100         <div className="flex justify-between items-center mb-6">
    101           <h1 className="text-3xl font-bold" style={{ color: '#7c3aed' }}>Billing Record #{billing.billId}</h1>
    102           <div className="space-x-2">
    103             <button
    104                 onClick={handleDownloadInvoice}
    105                 disabled={downloading}
    106                 className="bg-green-600 text-white px-4 py-2 rounded hover:bg-green-700 disabled:opacity-50"
    107             >
    108               {downloading ? 'Downloading...' : 'Download Invoice (PDF)'}
    109             </button>
    110             <button onClick={() => navigate('/billing')} className="bg-gray-300 text-gray-700 px-4 py-2 rounded hover:bg-gray-400">
    111               Back
    112             </button>
    113           </div>
     99    <div>
     100      <div className="flex justify-between items-center mb-6">
     101        <h1 className="text-3xl font-bold" style={{ color: '#7c3aed' }}>Billing Record #{billing.billId}</h1>
     102        <div className="space-x-2">
     103          <button
     104            onClick={handleDownloadInvoice}
     105            disabled={downloading}
     106            className="bg-green-600 text-white px-4 py-2 rounded hover:bg-green-700 disabled:opacity-50"
     107          >
     108            {downloading ? 'Downloading...' : 'Download Invoice (PDF)'}
     109          </button>
     110          <button onClick={() => navigate('/billing')} className="bg-gray-300 text-gray-700 px-4 py-2 rounded hover:bg-gray-400">
     111            Back
     112          </button>
    114113        </div>
    115 
    116         {error && <ErrorAlert message={error} onClose={() => setError(null)} />}
    117         {success && <SuccessAlert message={success} onClose={() => setSuccess(null)} />}
    118 
    119         <div className={`grid gap-6 mb-6 ${isPatient ? 'grid-cols-1 lg:grid-cols-2' : 'grid-cols-1 lg:grid-cols-3'}`}>
     114      </div>
     115
     116      {error && <ErrorAlert message={error} onClose={() => setError(null)} />}
     117      {success && <SuccessAlert message={success} onClose={() => setSuccess(null)} />}
     118
     119      <div className={`grid gap-6 mb-6 ${isPatient ? 'grid-cols-1 lg:grid-cols-2' : 'grid-cols-1 lg:grid-cols-3'}`}>
     120        <div className="bg-white rounded-lg shadow p-6">
     121          <h2 className="text-xl font-bold mb-4">Billing Information</h2>
     122          <div className="space-y-3">
     123            <InfoRow label="Patient" value={billing.patientName} />
     124            <InfoRow label="Total Cost" value={`$${billing.totalCost}`} />
     125            <InfoRow label="Current Status" value={billing.paymentStatus} />
     126            <InfoRow label="Payment Date" value={billing.paymentDate || 'Not paid'} />
     127          </div>
     128        </div>
     129
     130        {!isPatient && (
    120131          <div className="bg-white rounded-lg shadow p-6">
    121             <h2 className="text-xl font-bold mb-4">Billing Information</h2>
    122             <div className="space-y-3">
    123               <InfoRow label="Patient" value={billing.patientName} />
    124               <InfoRow label="Total Cost" value={`$${billing.totalCost}`} />
    125               <InfoRow label="Current Status" value={billing.paymentStatus} />
    126               <InfoRow label="Payment Date" value={billing.paymentDate || 'Not paid'} />
     132            <h2 className="text-xl font-bold mb-4">Update Payment Status</h2>
     133            <div className="space-y-4">
     134              <div>
     135                <label className="block text-sm font-semibold mb-2">Payment Status</label>
     136                <select
     137                  value={paymentStatus}
     138                  onChange={(e) => setPaymentStatus(e.target.value)}
     139                  className="w-full px-4 py-2 border rounded-lg"
     140                >
     141                  <option value="PENDING">Pending</option>
     142                  <option value="PAID">Paid</option>
     143                  <option value="CANCELLED">Cancelled</option>
     144                </select>
     145              </div>
     146              <button
     147                onClick={handleUpdatePaymentStatus}
     148                disabled={updating || paymentStatus === billing.paymentStatus}
     149                className="w-full bg-purple-600 text-white px-4 py-2 rounded hover:bg-purple-700 disabled:opacity-50"
     150              >
     151                {updating ? 'Updating...' : 'Update Status'}
     152              </button>
    127153            </div>
    128154          </div>
    129 
    130           {!isPatient && (
    131               <div className="bg-white rounded-lg shadow p-6">
    132                 <h2 className="text-xl font-bold mb-4">Update Payment Status</h2>
    133                 <div className="space-y-4">
    134                   <div>
    135                     <label className="block text-sm font-semibold mb-2">Payment Status</label>
    136                     <select
    137                         value={paymentStatus}
    138                         onChange={(e) => setPaymentStatus(e.target.value)}
    139                         className="w-full px-4 py-2 border rounded-lg"
    140                     >
    141                       <option value="PENDING">Pending</option>
    142                       <option value="PAID">Paid</option>
    143                       <option value="CANCELLED">Cancelled</option>
    144                     </select>
    145                   </div>
    146                   <button
    147                       onClick={handleUpdatePaymentStatus}
    148                       disabled={updating || paymentStatus === billing.paymentStatus}
    149                       className="w-full bg-purple-600 text-white px-4 py-2 rounded hover:bg-purple-700 disabled:opacity-50"
    150                   >
    151                     {updating ? 'Updating...' : 'Update Status'}
    152                   </button>
    153                 </div>
    154               </div>
    155           )}
    156 
    157           <div className="bg-white rounded-lg shadow p-6">
    158             <h2 className="text-xl font-bold mb-4">Patient Details</h2>
    159             <div className="space-y-3">
    160               {billingDetail && (
    161                   <>
    162                     <InfoRow label="EMBG" value={billingDetail.patientEmbg} />
    163                     <InfoRow label="Phone" value={billingDetail.patientPhone} />
    164                     <InfoRow label="Bill Date" value={billingDetail.billDate} />
    165                   </>
    166               )}
     155        )}
     156
     157        <div className="bg-white rounded-lg shadow p-6">
     158          <h2 className="text-xl font-bold mb-4">Patient Details</h2>
     159          <div className="space-y-3">
     160            {billingDetail && (
     161              <>
     162                <InfoRow label="EMBG" value={billingDetail.patientEmbg} />
     163                <InfoRow label="Phone" value={billingDetail.patientPhone} />
     164                <InfoRow label="Bill Date" value={billingDetail.billDate} />
     165              </>
     166            )}
     167          </div>
     168        </div>
     169      </div>
     170
     171      <div className="bg-white rounded-lg shadow p-6">
     172        <h2 className="text-xl font-bold mb-4">Itemized Services</h2>
     173
     174        {billingDetail && (billingDetail.procedures.length > 0 || billingDetail.labTests.length > 0) ? (
     175          <div className="space-y-4">
     176            {billingDetail.procedures.length > 0 && (
     177              <div>
     178                <h3 className="font-semibold text-lg mb-2">Procedures</h3>
     179                <table className="w-full">
     180                  <thead className="bg-gray-100">
     181                    <tr>
     182                      <th className="px-4 py-2 text-left">Description</th>
     183                      <th className="px-4 py-2 text-right">Cost</th>
     184                    </tr>
     185                  </thead>
     186                  <tbody>
     187                    {billingDetail.procedures.map((proc, idx) => (
     188                      <tr key={idx} className="border-t">
     189                        <td className="px-4 py-2">{proc.description}</td>
     190                        <td className="px-4 py-2 text-right">${proc.cost}</td>
     191                      </tr>
     192                    ))}
     193                  </tbody>
     194                </table>
     195              </div>
     196            )}
     197
     198            {billingDetail.labTests.length > 0 && (
     199              <div>
     200                <h3 className="font-semibold text-lg mb-2">Lab Tests</h3>
     201                <table className="w-full">
     202                  <thead className="bg-gray-100">
     203                    <tr>
     204                      <th className="px-4 py-2 text-left">Description</th>
     205                      <th className="px-4 py-2 text-right">Cost</th>
     206                    </tr>
     207                  </thead>
     208                  <tbody>
     209                    {billingDetail.labTests.map((test, idx) => (
     210                      <tr key={idx} className="border-t">
     211                        <td className="px-4 py-2">{test.description}</td>
     212                        <td className="px-4 py-2 text-right">${test.cost}</td>
     213                      </tr>
     214                    ))}
     215                  </tbody>
     216                </table>
     217              </div>
     218            )}
     219
     220            <div className="border-t-2 pt-4 mt-4 flex justify-end">
     221              <div className="text-right">
     222                <p className="text-gray-600">Total Amount:</p>
     223                <p className="text-2xl font-bold text-purple-600">${billing.totalCost}</p>
     224              </div>
    167225            </div>
    168226          </div>
    169         </div>
    170 
    171         <div className="bg-white rounded-lg shadow p-6">
    172           <h2 className="text-xl font-bold mb-4">Itemized Services</h2>
    173 
    174           {billingDetail && (billingDetail.procedures.length > 0 || billingDetail.labTests.length > 0) ? (
    175               <div className="space-y-4">
    176                 {billingDetail.procedures.length > 0 && (
    177                     <div>
    178                       <h3 className="font-semibold text-lg mb-2">Procedures</h3>
    179                       <table className="w-full">
    180                         <thead className="bg-gray-100">
    181                         <tr>
    182                           <th className="px-4 py-2 text-left">Description</th>
    183                           <th className="px-4 py-2 text-right">Cost</th>
    184                         </tr>
    185                         </thead>
    186                         <tbody>
    187                         {billingDetail.procedures.map((proc, idx) => (
    188                             <tr key={idx} className="border-t">
    189                               <td className="px-4 py-2">{proc.description}</td>
    190                               <td className="px-4 py-2 text-right">${proc.cost}</td>
    191                             </tr>
    192                         ))}
    193                         </tbody>
    194                       </table>
    195                     </div>
    196                 )}
    197 
    198                 {billingDetail.labTests.length > 0 && (
    199                     <div>
    200                       <h3 className="font-semibold text-lg mb-2">Lab Tests</h3>
    201                       <table className="w-full">
    202                         <thead className="bg-gray-100">
    203                         <tr>
    204                           <th className="px-4 py-2 text-left">Description</th>
    205                           <th className="px-4 py-2 text-right">Cost</th>
    206                         </tr>
    207                         </thead>
    208                         <tbody>
    209                         {billingDetail.labTests.map((test, idx) => (
    210                             <tr key={idx} className="border-t">
    211                               <td className="px-4 py-2">{test.description}</td>
    212                               <td className="px-4 py-2 text-right">${test.cost}</td>
    213                             </tr>
    214                         ))}
    215                         </tbody>
    216                       </table>
    217                     </div>
    218                 )}
    219 
    220                 <div className="border-t-2 pt-4 mt-4 flex justify-end">
    221                   <div className="text-right">
    222                     <p className="text-gray-600">Total Amount:</p>
    223                     <p className="text-2xl font-bold text-purple-600">${billing.totalCost}</p>
    224                   </div>
    225                 </div>
    226               </div>
    227           ) : (
    228               <p className="text-gray-500">No services itemized for this billing record.</p>
    229           )}
    230         </div>
    231       </div>
     227        ) : (
     228          <p className="text-gray-500">No services itemized for this billing record.</p>
     229        )}
     230      </div>
     231    </div>
    232232  );
    233233}
     
    235235function InfoRow({ label, value }) {
    236236  return (
    237       <div className="flex justify-between">
    238         <span className="text-gray-800">{label}:</span>
    239         <span className="text-gray-800">{value || 'N/A'}</span>
    240       </div>
     237    <div className="flex justify-between">
     238      <span className="text-gray-800">{label}:</span>
     239      <span className="text-gray-800">{value || 'N/A'}</span>
     240    </div>
    241241  );
    242242}
  • frontend/src/pages/billing/BillingList.js

    re1f74f6 r9af201e  
    8989      // Refresh the list
    9090      const response = user.role === 'BILLING_ADMIN'
    91           ? await billingService.getAllBillings()
    92           : await billingService.getBillingHistoryForPatient(patientId || user.patientId);
     91        ? await billingService.getAllBillings()
     92        : await billingService.getBillingHistoryForPatient(patientId || user.patientId);
    9393      setBillings(response.data || []);
    9494    } catch (err) {
     
    101101  if (user.role === 'DOCTOR' || user.role === 'LAB_TECHNICIAN') {
    102102    return (
    103         <div style={{ padding: '20px', textAlign: 'center' }}>
    104           <h1 className="text-2xl font-bold" style={{ color: '#7c3aed', marginBottom: '10px' }}>Access Denied</h1>
    105           <p style={{ color: 'var(--color-neutral-600)' }}>You do not have permission to access billing records.</p>
    106         </div>
     103      <div style={{ padding: '20px', textAlign: 'center' }}>
     104        <h1 className="text-2xl font-bold" style={{ color: '#7c3aed', marginBottom: '10px' }}>Access Denied</h1>
     105        <p style={{ color: 'var(--color-neutral-600)' }}>You do not have permission to access billing records.</p>
     106      </div>
    107107    );
    108108  }
     
    111111
    112112  return (
    113       <div>
    114         <h1 className="text-3xl font-bold mb-6" style={{ color: '#7c3aed' }}>{patientId ? 'Patient Billing History' : 'Billing Records'}</h1>
    115 
    116         {error && <ErrorAlert message={error} onClose={() => setError(null)} />}
    117         {success && <SuccessAlert message={success} onClose={() => setSuccess(null)} />}
    118 
    119         {/* Filters for Billing Admin */}
    120         {user.role === 'BILLING_ADMIN' && (
    121             <div className="bg-white rounded-lg shadow p-6 mb-6">
    122               <h2 className="text-lg font-bold mb-4">Filters</h2>
    123               <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
     113    <div>
     114      <h1 className="text-3xl font-bold mb-6" style={{ color: '#7c3aed' }}>{patientId ? 'Patient Billing History' : 'Billing Records'}</h1>
     115
     116      {error && <ErrorAlert message={error} onClose={() => setError(null)} />}
     117      {success && <SuccessAlert message={success} onClose={() => setSuccess(null)} />}
     118
     119      {/* Filters for Billing Admin */}
     120      {user.role === 'BILLING_ADMIN' && (
     121        <div className="bg-white rounded-lg shadow p-6 mb-6">
     122          <h2 className="text-lg font-bold mb-4">Filters</h2>
     123          <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
     124            <div>
     125              <label className="block text-sm font-semibold mb-2">Status</label>
     126              <select
     127                value={statusFilter}
     128                onChange={(e) => setStatusFilter(e.target.value)}
     129                className="w-full px-4 py-2 border rounded-lg"
     130              >
     131                <option value="">All Statuses</option>
     132                <option value="PENDING">Pending</option>
     133                <option value="PAID">Paid</option>
     134                <option value="PROCESSING">Processing</option>
     135              </select>
     136            </div>
     137            <div>
     138              <label className="block text-sm font-semibold mb-2">Patient</label>
     139              <select
     140                value={patientFilter}
     141                onChange={(e) => setPatientFilter(e.target.value)}
     142                className="w-full px-4 py-2 border rounded-lg"
     143              >
     144                <option value="">All Patients</option>
     145                {patients.map(p => (
     146                  <option key={p.patientId} value={`${p.firstName} ${p.lastName}`}>
     147                    {p.firstName} {p.lastName}
     148                  </option>
     149                ))}
     150              </select>
     151            </div>
     152          </div>
     153        </div>
     154      )}
     155
     156      {/* Pending Billing Records Section (for Billing Admin) */}
     157      {user.role === 'BILLING_ADMIN' && pendingBillings.length > 0 && (
     158        <div className="bg-yellow-50 rounded-lg shadow p-6 mb-6 border-l-4 border-yellow-500">
     159          <h2 className="text-lg font-bold mb-4">Pending Billing Records ({pendingBillings.length})</h2>
     160          <div className="space-y-3">
     161            {pendingBillings.map(billing => (
     162              <div key={billing.billId} className="bg-white rounded p-4 flex justify-between items-center">
    124163                <div>
    125                   <label className="block text-sm font-semibold mb-2">Status</label>
    126                   <select
    127                       value={statusFilter}
    128                       onChange={(e) => setStatusFilter(e.target.value)}
    129                       className="w-full px-4 py-2 border rounded-lg"
    130                   >
    131                     <option value="">All Statuses</option>
    132                     <option value="PENDING">Pending</option>
    133                     <option value="PAID">Paid</option>
    134                     <option value="PROCESSING">Processing</option>
    135                   </select>
     164                  <p className="font-semibold">{billing.patientName}</p>
     165                  <p className="text-sm text-gray-600">${billing.totalCost}</p>
    136166                </div>
    137                 <div>
    138                   <label className="block text-sm font-semibold mb-2">Patient</label>
    139                   <select
    140                       value={patientFilter}
    141                       onChange={(e) => setPatientFilter(e.target.value)}
    142                       className="w-full px-4 py-2 border rounded-lg"
    143                   >
    144                     <option value="">All Patients</option>
    145                     {patients.map(p => (
    146                         <option key={p.patientId} value={`${p.firstName} ${p.lastName}`}>
    147                           {p.firstName} {p.lastName}
    148                         </option>
    149                     ))}
    150                   </select>
    151                 </div>
     167                <button
     168                  onClick={() => handleUpdateStatus(billing.billId, 'PAID')}
     169                  className="px-4 py-2 bg-green-500 text-white rounded hover:bg-green-600 text-sm"
     170                >
     171                  Mark Paid
     172                </button>
    152173              </div>
    153             </div>
    154         )}
    155 
    156         {/* Pending Billing Records Section (for Billing Admin) */}
    157         {user.role === 'BILLING_ADMIN' && pendingBillings.length > 0 && (
    158             <div className="bg-yellow-50 rounded-lg shadow p-6 mb-6 border-l-4 border-yellow-500">
    159               <h2 className="text-lg font-bold mb-4">Pending Billing Records ({pendingBillings.length})</h2>
    160               <div className="space-y-3">
    161                 {pendingBillings.map(billing => (
    162                     <div key={billing.billId} className="bg-white rounded p-4 flex justify-between items-center">
    163                       <div>
    164                         <p className="font-semibold">{billing.patientName}</p>
    165                         <p className="text-sm text-gray-600">${billing.totalCost}</p>
    166                       </div>
    167                       <button
    168                           onClick={() => handleUpdateStatus(billing.billId, 'PAID')}
    169                           className="px-4 py-2 bg-green-500 text-white rounded hover:bg-green-600 text-sm"
    170                       >
    171                         Mark Paid
    172                       </button>
    173                     </div>
    174                 ))}
    175               </div>
    176             </div>
    177         )}
    178 
    179         <div className="bg-white rounded-lg shadow overflow-hidden">
    180           <table className="w-full">
    181             <thead className="bg-gray-100">
     174            ))}
     175          </div>
     176        </div>
     177      )}
     178
     179      <div className="bg-white rounded-lg shadow overflow-hidden">
     180        <table className="w-full">
     181          <thead className="bg-gray-100">
    182182            <tr>
    183183              <th className="px-6 py-3 text-left text-sm font-semibold">Patient</th>
     
    187187              <th className="px-6 py-3 text-left text-sm font-semibold">Actions</th>
    188188            </tr>
    189             </thead>
    190             <tbody>
     189          </thead>
     190          <tbody>
    191191            {filteredBillings.map(billing => (
    192                 <tr key={billing.billId} className="border-t hover:bg-gray-50">
    193                   <td className="px-6 py-3">{billing.patientName}</td>
    194                   <td className="px-6 py-3">${billing.totalCost}</td>
    195                   <td className="px-6 py-3">
     192              <tr key={billing.billId} className="border-t hover:bg-gray-50">
     193                <td className="px-6 py-3">{billing.patientName}</td>
     194                <td className="px-6 py-3">${billing.totalCost}</td>
     195                <td className="px-6 py-3">
    196196                  <span className={`px-3 py-1 rounded text-sm font-semibold ${
    197                       billing.paymentStatus === 'PENDING' ? 'bg-yellow-100 text-yellow-800' :
    198                           billing.paymentStatus === 'PAID' ? 'bg-green-100 text-green-800' :
    199                               'bg-red-100 text-red-800'
     197                    billing.paymentStatus === 'PENDING' ? 'bg-yellow-100 text-yellow-800' :
     198                    billing.paymentStatus === 'PAID' ? 'bg-green-100 text-green-800' :
     199                    'bg-red-100 text-red-800'
    200200                  }`}>
    201201                    {billing.paymentStatus}
    202202                  </span>
    203                   </td>
    204                   <td className="px-6 py-3">{billing.paymentDate || 'Not paid'}</td>
    205                   <td className="px-6 py-3">
    206                     <Link to={`/billing/${billing.billId}`} style={{ color: '#7c3aed', textDecoration: 'none', fontWeight: '400' }} onMouseEnter={(e) => e.currentTarget.style.textDecoration = 'underline'} onMouseLeave={(e) => e.currentTarget.style.textDecoration = 'none'}>
    207                       View
    208                     </Link>
    209                   </td>
    210                 </tr>
     203                </td>
     204                <td className="px-6 py-3">{billing.paymentDate || 'Not paid'}</td>
     205                <td className="px-6 py-3">
     206                  <Link to={`/billing/${billing.billId}`} style={{ color: '#7c3aed', textDecoration: 'none', fontWeight: '400' }} onMouseEnter={(e) => e.currentTarget.style.textDecoration = 'underline'} onMouseLeave={(e) => e.currentTarget.style.textDecoration = 'none'}>
     207                    View
     208                  </Link>
     209                </td>
     210              </tr>
    211211            ))}
    212             </tbody>
    213           </table>
    214 
    215           {filteredBillings.length === 0 && (
    216               <div className="p-6 text-center text-gray-500">
    217                 {billings.length === 0 ? 'No billing records found' : 'No records match the selected filters'}
    218               </div>
    219           )}
    220         </div>
     212          </tbody>
     213        </table>
     214
     215        {filteredBillings.length === 0 && (
     216          <div className="p-6 text-center text-gray-500">
     217            {billings.length === 0 ? 'No billing records found' : 'No records match the selected filters'}
     218          </div>
     219        )}
    221220      </div>
     221    </div>
    222222  );
    223223}
  • frontend/src/pages/departments/DepartmentDetail.js

    re1f74f6 r9af201e  
    1919
    2020  useEffect(() => {
    21     fetchDepartmentAndDoctors();
    22   }, [departmentId]);
    23 
    24   const fetchDepartmentAndDoctors = async () => {
     21    const fetchDepartmentAndDoctors = async () => {
    2522    try {
    2623      setLoading(true);
     
    3936      setLoading(false);
    4037    }
    41   };
     38    };
     39
     40    fetchDepartmentAndDoctors();
     41  }, [departmentId]);
    4242
    4343  if (loading) return <Loading />;
  • frontend/src/pages/departments/DoctorsByDepartment.js

    re1f74f6 r9af201e  
    1919
    2020  useEffect(() => {
    21     fetchDepartmentAndDoctors();
    22   }, [departmentId]);
    23 
    24   const fetchDepartmentAndDoctors = async () => {
     21    const fetchDepartmentAndDoctors = async () => {
    2522    try {
    2623      setLoading(true);
     
    3936      setLoading(false);
    4037    }
    41   };
     38    };
     39
     40    fetchDepartmentAndDoctors();
     41  }, [departmentId]);
    4242
    4343  if (loading) return <Loading />;
  • frontend/src/pages/doctors/DoctorDetail.js

    re1f74f6 r9af201e  
    2424
    2525  useEffect(() => {
     26    const fetchDoctor = async () => {
     27      try {
     28        setLoading(true);
     29        const response = await doctorService.getDoctorById(id);
     30        setDoctor(response.data);
     31      } catch (err) {
     32        setError('Failed to fetch doctor details');
     33        console.error(err);
     34      } finally {
     35        setLoading(false);
     36      }
     37    };
     38
    2639    fetchDoctor();
    2740  }, [id]);
    28 
    29   const fetchDoctor = async () => {
    30     try {
    31       setLoading(true);
    32       const response = await doctorService.getDoctorById(id);
    33       setDoctor(response.data);
    34     } catch (err) {
    35       setError('Failed to fetch doctor details');
    36       console.error(err);
    37     } finally {
    38       setLoading(false);
    39     }
    40   };
    4141
    4242  if (loading) return <Loading />;
  • frontend/src/pages/doctors/DoctorForm.js

    re1f74f6 r9af201e  
    2222  useEffect(() => {
    2323    if (id) {
     24      const fetchDoctor = async () => {
     25        try {
     26          setLoading(true);
     27          const response = await doctorService.getDoctorById(id);
     28          setFormData({
     29            firstName: response.data.firstName,
     30            lastName: response.data.lastName,
     31            emailAddress: response.data.emailAddress,
     32            levelId: response.data.level?.levelId || '',
     33            specializationId: response.data.specialization?.specializationId || '',
     34            departmentId: response.data.department?.departmentId || '',
     35          });
     36        } catch (err) {
     37          setError('Failed to fetch doctor');
     38        } finally {
     39          setLoading(false);
     40        }
     41      };
     42
    2443      fetchDoctor();
    2544    }
    2645  }, [id]);
    27 
    28   const fetchDoctor = async () => {
    29     try {
    30       setLoading(true);
    31       const response = await doctorService.getDoctorById(id);
    32       setFormData({
    33         firstName: response.data.firstName,
    34         lastName: response.data.lastName,
    35         emailAddress: response.data.emailAddress,
    36         levelId: response.data.level?.levelId || '',
    37         specializationId: response.data.specialization?.specializationId || '',
    38         departmentId: response.data.department?.departmentId || '',
    39       });
    40     } catch (err) {
    41       setError('Failed to fetch doctor');
    42     } finally {
    43       setLoading(false);
    44     }
    45   };
    4646
    4747  const handleChange = (e) => {
  • frontend/src/pages/lab-tests/LabResultForm.js

    re1f74f6 r9af201e  
    1 import React, { useState, useEffect } from 'react';
     1import React, { useState } from 'react';
    22import { useNavigate } from 'react-router-dom';
    33import { labService } from '../../services/labService';
  • frontend/src/pages/lab-tests/LabTestList.js

    re1f74f6 r9af201e  
    55
    66function LabTestList() {
    7   const user = JSON.parse(localStorage.getItem('user') || '{}');
     7  const [user, setUser] = useState({});
    88  const isLabTechnician = user.role === 'LAB_TECHNICIAN';
    99
     
    4646    testDate: '',
    4747  });
     48
     49  // Load user from localStorage and listen for changes
     50  useEffect(() => {
     51    const loadUser = () => {
     52      const userStr = localStorage.getItem('user');
     53      console.log('[LabTestList] Loading user from localStorage:', userStr);
     54      if (userStr) {
     55        try {
     56          const parsedUser = JSON.parse(userStr);
     57          console.log('[LabTestList] Parsed user:', parsedUser);
     58          setUser(parsedUser);
     59        } catch (err) {
     60          console.error('Failed to parse user:', err);
     61          setUser({});
     62        }
     63      } else {
     64        console.log('[LabTestList] No user in localStorage');
     65        setUser({});
     66      }
     67    };
     68
     69    console.log('[LabTestList] useEffect running - loading user');
     70    loadUser();
     71
     72    // Listen for storage changes (other tabs/windows)
     73    window.addEventListener('storage', loadUser);
     74
     75    // Listen for custom event (same tab changes)
     76    window.addEventListener('userStorageChange', loadUser);
     77
     78    return () => {
     79      window.removeEventListener('storage', loadUser);
     80      window.removeEventListener('userStorageChange', loadUser);
     81    };
     82  }, []);
    4883
    4984  useEffect(() => {
     
    134169      setLoading(true);
    135170
    136       // Get doctor ID from localStorage (set during login)
    137       const doctorId = localStorage.getItem('doctorId') || 1;
     171      // Get doctor ID from logged-in user
     172      const doctorId = user.doctorId;
    138173
    139174      const request = {
     
    145180        notes: requestData.notes,
    146181      };
     182
     183      console.log('User object:', user);
     184      console.log('Sending lab test request with doctorId:', doctorId, 'Full request:', request);
    147185
    148186      await labService.requestLabTest(request);
     
    228266  if (isLabTechnician) {
    229267    return (
    230         <div>
    231           <h1 className="text-3xl font-bold mb-6" style={{ color: '#7c3aed' }}>Lab Tests - Submit Results</h1>
    232 
    233           {error && <ErrorAlert message={error} onClose={() => setError(null)} />}
    234 
    235           {selectedTest ? (
    236               // Submit Result Form
    237               <div className="bg-white rounded-lg shadow p-6 mb-6">
    238                 <h2 className="text-xl font-bold mb-4">Submit Lab Result</h2>
    239                 <div className="mb-4 p-4 bg-gray-50 rounded-lg">
    240                   <p className="mb-2"><strong>Test:</strong> {selectedTest.testName}</p>
    241                   <p className="mb-2"><strong>Patient:</strong> {selectedTest.patientName}</p>
    242                   <p className="mb-2"><strong>Doctor:</strong> {selectedTest.doctorName}</p>
    243                   <p className="mb-2"><strong>Test Date:</strong> {selectedTest.testDate}</p>
    244                   {selectedTest.notes && <p><strong>Notes:</strong> {selectedTest.notes}</p>}
     268      <div>
     269        <h1 className="text-3xl font-bold mb-6" style={{ color: '#7c3aed' }}>Lab Tests - Submit Results</h1>
     270
     271        {error && <ErrorAlert message={error} onClose={() => setError(null)} />}
     272
     273        {selectedTest ? (
     274          // Submit Result Form
     275          <div className="bg-white rounded-lg shadow p-6 mb-6">
     276            <h2 className="text-xl font-bold mb-4">Submit Lab Result</h2>
     277            <div className="mb-4 p-4 bg-gray-50 rounded-lg">
     278              <p className="mb-2"><strong>Test:</strong> {selectedTest.testName}</p>
     279              <p className="mb-2"><strong>Patient:</strong> {selectedTest.patientName}</p>
     280              <p className="mb-2"><strong>Doctor:</strong> {selectedTest.doctorName}</p>
     281              <p className="mb-2"><strong>Test Date:</strong> {selectedTest.testDate}</p>
     282              {selectedTest.notes && <p><strong>Notes:</strong> {selectedTest.notes}</p>}
     283            </div>
     284
     285            <form onSubmit={handleSubmitResult} className="space-y-4">
     286              <div>
     287                <label className="block text-sm font-semibold mb-2">Test Results *</label>
     288                <textarea
     289                  value={submitFormData.results}
     290                  onChange={(e) => setSubmitFormData({ ...submitFormData, results: e.target.value })}
     291                  placeholder="Enter detailed test results"
     292                  className="w-full px-4 py-2 border rounded-lg"
     293                  rows="4"
     294                  required
     295                />
     296              </div>
     297
     298              <div>
     299                <label className="block text-sm font-semibold mb-2">Result Date *</label>
     300                <input
     301                  type="date"
     302                  value={submitFormData.resultDate}
     303                  onChange={(e) => setSubmitFormData({ ...submitFormData, resultDate: e.target.value })}
     304                  className="w-full px-4 py-2 border rounded-lg"
     305                  required
     306                />
     307              </div>
     308
     309              <div className="flex gap-4">
     310                <button
     311                  type="submit"
     312                  disabled={loading}
     313                  style={{
     314                    background: loading ? '#d1d5db' : '#bfdbfe',
     315                    color: '#1e1035',
     316                    padding: '8px 24px',
     317                    borderRadius: '6px',
     318                    border: 'none',
     319                    cursor: loading ? 'not-allowed' : 'pointer',
     320                    fontSize: '14px',
     321                    fontWeight: '400'
     322                  }}
     323                  onMouseEnter={(e) => !loading && (e.currentTarget.style.background = '#93c5fd')}
     324                  onMouseLeave={(e) => !loading && (e.currentTarget.style.background = '#bfdbfe')}
     325                >
     326                  {loading ? 'Submitting...' : 'Submit Result'}
     327                </button>
     328                <button
     329                  type="button"
     330                  onClick={() => {
     331                    setSelectedTest(null);
     332                    setSubmitFormData({
     333                      results: '',
     334                      resultDate: new Date().toISOString().split('T')[0],
     335                    });
     336                  }}
     337                  className="bg-gray-400 text-white px-6 py-2 rounded hover:bg-gray-500"
     338                >
     339                  Cancel
     340                </button>
     341              </div>
     342            </form>
     343          </div>
     344        ) : (
     345          // Pending Tests List
     346          <div className="bg-white rounded-lg shadow overflow-hidden">
     347            <div className="p-6 border-b">
     348              <h2 className="text-xl font-bold">Pending Lab Tests ({pendingTests.length})</h2>
     349            </div>
     350
     351            {pendingTests.length === 0 ? (
     352              <div className="p-6 text-center text-gray-600">
     353                No pending lab tests
     354              </div>
     355            ) : (
     356              <>
     357                {/* Filters */}
     358                <div className="p-6 border-b bg-gray-50">
     359                  <h3 className="text-sm font-semibold mb-4">Filters</h3>
     360                  <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
     361                    <div>
     362                      <label className="block text-sm font-semibold mb-2">Test</label>
     363                      <input
     364                        type="text"
     365                        placeholder="Filter by test name..."
     366                        value={pendingFilters.testName}
     367                        onChange={(e) => setPendingFilters({...pendingFilters, testName: e.target.value})}
     368                        className="w-full px-3 py-2 border rounded-lg text-sm"
     369                      />
     370                    </div>
     371                    <div>
     372                      <label className="block text-sm font-semibold mb-2">Patient</label>
     373                      <input
     374                        type="text"
     375                        placeholder="Filter by patient name..."
     376                        value={pendingFilters.patientName}
     377                        onChange={(e) => setPendingFilters({...pendingFilters, patientName: e.target.value})}
     378                        className="w-full px-3 py-2 border rounded-lg text-sm"
     379                      />
     380                    </div>
     381                    <div>
     382                      <label className="block text-sm font-semibold mb-2">Test Date</label>
     383                      <input
     384                        type="date"
     385                        value={pendingFilters.testDate}
     386                        onChange={(e) => setPendingFilters({...pendingFilters, testDate: e.target.value})}
     387                        className="w-full px-3 py-2 border rounded-lg text-sm"
     388                      />
     389                    </div>
     390                  </div>
     391                  <button
     392                    onClick={() => setPendingFilters({testName: '', patientName: '', testDate: ''})}
     393                    className="mt-4 bg-gray-300 text-gray-700 px-4 py-2 rounded text-sm hover:bg-gray-400"
     394                  >
     395                    Clear Filters
     396                  </button>
    245397                </div>
    246398
    247                 <form onSubmit={handleSubmitResult} className="space-y-4">
    248                   <div>
    249                     <label className="block text-sm font-semibold mb-2">Test Results *</label>
    250                     <textarea
    251                         value={submitFormData.results}
    252                         onChange={(e) => setSubmitFormData({ ...submitFormData, results: e.target.value })}
    253                         placeholder="Enter detailed test results"
    254                         className="w-full px-4 py-2 border rounded-lg"
    255                         rows="4"
    256                         required
    257                     />
     399                {/* Filtered Table */}
     400                <table className="w-full">
     401                  <thead className="bg-gray-100">
     402                    <tr>
     403                      <th className="px-6 py-3 text-left text-sm font-semibold">Test</th>
     404                      <th className="px-6 py-3 text-left text-sm font-semibold">Patient</th>
     405                      <th className="px-6 py-3 text-left text-sm font-semibold">Doctor</th>
     406                      <th className="px-6 py-3 text-left text-sm font-semibold">Requested</th>
     407                      <th className="px-6 py-3 text-left text-sm font-semibold">Test Date</th>
     408                      <th className="px-6 py-3 text-left text-sm font-semibold">Notes</th>
     409                      <th className="px-6 py-3 text-left text-sm font-semibold">Action</th>
     410                    </tr>
     411                  </thead>
     412                  <tbody>
     413                    {pendingTests
     414                      .filter((test) => {
     415                        const testName = (test.testName || '').toLowerCase();
     416                        const patientName = (test.patientName || '').toLowerCase();
     417                        const testDate = (test.testDate || '');
     418
     419                        return (
     420                          testName.includes(pendingFilters.testName.toLowerCase()) &&
     421                          patientName.includes(pendingFilters.patientName.toLowerCase()) &&
     422                          (pendingFilters.testDate === '' || testDate === pendingFilters.testDate)
     423                        );
     424                      })
     425                      .map((test, index) => (
     426                    <tr key={index} className="border-t hover:bg-gray-50">
     427                      <td className="px-6 py-3 font-medium">{test.testName}</td>
     428                      <td className="px-6 py-3">{test.patientName}</td>
     429                      <td className="px-6 py-3">{test.doctorName}</td>
     430                      <td className="px-6 py-3 text-green-600">{test.requestDate}</td>
     431                      <td className="px-6 py-3 text-purple-600">{test.testDate}</td>
     432                      <td className="px-6 py-3 text-gray-600 text-sm">{test.notes || '-'}</td>
     433                      <td className="px-6 py-3">
     434                        <button
     435                          onClick={() => setSelectedTest(test)}
     436                          style={{
     437                            background: '#bfdbfe',
     438                            color: '#1e1035',
     439                            padding: '6px 12px',
     440                            borderRadius: '4px',
     441                            border: 'none',
     442                            cursor: 'pointer',
     443                            fontSize: '12px',
     444                            fontWeight: '400'
     445                          }}
     446                          onMouseEnter={(e) => e.currentTarget.style.background = '#93c5fd'}
     447                          onMouseLeave={(e) => e.currentTarget.style.background = '#bfdbfe'}
     448                        >
     449                          Submit Result
     450                        </button>
     451                      </td>
     452                    </tr>
     453                  ))}
     454                  </tbody>
     455                </table>
     456              </>
     457            )}
     458          </div>
     459        )}
     460
     461        {/* Submitted Tests History */}
     462        {!selectedTest && (
     463          <div className="bg-white rounded-lg shadow overflow-hidden mt-6">
     464            <div className="p-6 border-b">
     465              <h2 className="text-xl font-bold">Submitted Lab Results History ({submittedTests.length})</h2>
     466            </div>
     467
     468            {submittedTests.length === 0 ? (
     469              <div className="p-6 text-center text-gray-600">
     470                No submitted lab results yet
     471              </div>
     472            ) : (
     473              <>
     474                {/* Filters */}
     475                <div className="p-6 border-b bg-gray-50">
     476                  <h3 className="text-sm font-semibold mb-4">Filters</h3>
     477                  <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
     478                    <div>
     479                      <label className="block text-sm font-semibold mb-2">Test</label>
     480                      <input
     481                        type="text"
     482                        placeholder="Filter by test name..."
     483                        value={submittedFilters.testName}
     484                        onChange={(e) => setSubmittedFilters({...submittedFilters, testName: e.target.value})}
     485                        className="w-full px-3 py-2 border rounded-lg text-sm"
     486                      />
     487                    </div>
     488                    <div>
     489                      <label className="block text-sm font-semibold mb-2">Patient</label>
     490                      <input
     491                        type="text"
     492                        placeholder="Filter by patient name..."
     493                        value={submittedFilters.patientName}
     494                        onChange={(e) => setSubmittedFilters({...submittedFilters, patientName: e.target.value})}
     495                        className="w-full px-3 py-2 border rounded-lg text-sm"
     496                      />
     497                    </div>
     498                    <div>
     499                      <label className="block text-sm font-semibold mb-2">Test Date</label>
     500                      <input
     501                        type="date"
     502                        value={submittedFilters.testDate}
     503                        onChange={(e) => setSubmittedFilters({...submittedFilters, testDate: e.target.value})}
     504                        className="w-full px-3 py-2 border rounded-lg text-sm"
     505                      />
     506                    </div>
    258507                  </div>
    259 
    260                   <div>
    261                     <label className="block text-sm font-semibold mb-2">Result Date *</label>
    262                     <input
    263                         type="date"
    264                         value={submitFormData.resultDate}
    265                         onChange={(e) => setSubmitFormData({ ...submitFormData, resultDate: e.target.value })}
    266                         className="w-full px-4 py-2 border rounded-lg"
    267                         required
    268                     />
    269                   </div>
    270 
    271                   <div className="flex gap-4">
    272                     <button
    273                         type="submit"
    274                         disabled={loading}
    275                         style={{
    276                           background: loading ? '#d1d5db' : '#bfdbfe',
    277                           color: '#1e1035',
    278                           padding: '8px 24px',
    279                           borderRadius: '6px',
    280                           border: 'none',
    281                           cursor: loading ? 'not-allowed' : 'pointer',
    282                           fontSize: '14px',
    283                           fontWeight: '400'
    284                         }}
    285                         onMouseEnter={(e) => !loading && (e.currentTarget.style.background = '#93c5fd')}
    286                         onMouseLeave={(e) => !loading && (e.currentTarget.style.background = '#bfdbfe')}
    287                     >
    288                       {loading ? 'Submitting...' : 'Submit Result'}
    289                     </button>
    290                     <button
    291                         type="button"
    292                         onClick={() => {
    293                           setSelectedTest(null);
    294                           setSubmitFormData({
    295                             results: '',
    296                             resultDate: new Date().toISOString().split('T')[0],
    297                           });
    298                         }}
    299                         className="bg-gray-400 text-white px-6 py-2 rounded hover:bg-gray-500"
    300                     >
    301                       Cancel
    302                     </button>
    303                   </div>
    304                 </form>
    305               </div>
    306           ) : (
    307               // Pending Tests List
    308               <div className="bg-white rounded-lg shadow overflow-hidden">
    309                 <div className="p-6 border-b">
    310                   <h2 className="text-xl font-bold">Pending Lab Tests ({pendingTests.length})</h2>
     508                  <button
     509                    onClick={() => setSubmittedFilters({testName: '', patientName: '', testDate: ''})}
     510                    className="mt-4 bg-gray-300 text-gray-700 px-4 py-2 rounded text-sm hover:bg-gray-400"
     511                  >
     512                    Clear Filters
     513                  </button>
    311514                </div>
    312515
    313                 {pendingTests.length === 0 ? (
    314                     <div className="p-6 text-center text-gray-600">
    315                       No pending lab tests
    316                     </div>
    317                 ) : (
    318                     <>
    319                       {/* Filters */}
    320                       <div className="p-6 border-b bg-gray-50">
    321                         <h3 className="text-sm font-semibold mb-4">Filters</h3>
    322                         <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
    323                           <div>
    324                             <label className="block text-sm font-semibold mb-2">Test</label>
    325                             <input
    326                                 type="text"
    327                                 placeholder="Filter by test name..."
    328                                 value={pendingFilters.testName}
    329                                 onChange={(e) => setPendingFilters({...pendingFilters, testName: e.target.value})}
    330                                 className="w-full px-3 py-2 border rounded-lg text-sm"
    331                             />
    332                           </div>
    333                           <div>
    334                             <label className="block text-sm font-semibold mb-2">Patient</label>
    335                             <input
    336                                 type="text"
    337                                 placeholder="Filter by patient name..."
    338                                 value={pendingFilters.patientName}
    339                                 onChange={(e) => setPendingFilters({...pendingFilters, patientName: e.target.value})}
    340                                 className="w-full px-3 py-2 border rounded-lg text-sm"
    341                             />
    342                           </div>
    343                           <div>
    344                             <label className="block text-sm font-semibold mb-2">Test Date</label>
    345                             <input
    346                                 type="date"
    347                                 value={pendingFilters.testDate}
    348                                 onChange={(e) => setPendingFilters({...pendingFilters, testDate: e.target.value})}
    349                                 className="w-full px-3 py-2 border rounded-lg text-sm"
    350                             />
    351                           </div>
    352                         </div>
    353                         <button
    354                             onClick={() => setPendingFilters({testName: '', patientName: '', testDate: ''})}
    355                             className="mt-4 bg-gray-300 text-gray-700 px-4 py-2 rounded text-sm hover:bg-gray-400"
    356                         >
    357                           Clear Filters
    358                         </button>
    359                       </div>
    360 
    361                       {/* Filtered Table */}
    362                       <table className="w-full">
    363                         <thead className="bg-gray-100">
    364                         <tr>
    365                           <th className="px-6 py-3 text-left text-sm font-semibold">Test</th>
    366                           <th className="px-6 py-3 text-left text-sm font-semibold">Patient</th>
    367                           <th className="px-6 py-3 text-left text-sm font-semibold">Doctor</th>
    368                           <th className="px-6 py-3 text-left text-sm font-semibold">Requested</th>
    369                           <th className="px-6 py-3 text-left text-sm font-semibold">Test Date</th>
    370                           <th className="px-6 py-3 text-left text-sm font-semibold">Notes</th>
    371                           <th className="px-6 py-3 text-left text-sm font-semibold">Action</th>
    372                         </tr>
    373                         </thead>
    374                         <tbody>
    375                         {pendingTests
    376                             .filter((test) => {
    377                               const testName = (test.testName || '').toLowerCase();
    378                               const patientName = (test.patientName || '').toLowerCase();
    379                               const testDate = (test.testDate || '');
    380 
    381                               return (
    382                                   testName.includes(pendingFilters.testName.toLowerCase()) &&
    383                                   patientName.includes(pendingFilters.patientName.toLowerCase()) &&
    384                                   (pendingFilters.testDate === '' || testDate === pendingFilters.testDate)
    385                               );
    386                             })
    387                             .map((test, index) => (
    388                                 <tr key={index} className="border-t hover:bg-gray-50">
    389                                   <td className="px-6 py-3 font-medium">{test.testName}</td>
    390                                   <td className="px-6 py-3">{test.patientName}</td>
    391                                   <td className="px-6 py-3">{test.doctorName}</td>
    392                                   <td className="px-6 py-3 text-green-600">{test.requestDate}</td>
    393                                   <td className="px-6 py-3 text-purple-600">{test.testDate}</td>
    394                                   <td className="px-6 py-3 text-gray-600 text-sm">{test.notes || '-'}</td>
    395                                   <td className="px-6 py-3">
    396                                     <button
    397                                         onClick={() => setSelectedTest(test)}
    398                                         style={{
    399                                           background: '#bfdbfe',
    400                                           color: '#1e1035',
    401                                           padding: '6px 12px',
    402                                           borderRadius: '4px',
    403                                           border: 'none',
    404                                           cursor: 'pointer',
    405                                           fontSize: '12px',
    406                                           fontWeight: '400'
    407                                         }}
    408                                         onMouseEnter={(e) => e.currentTarget.style.background = '#93c5fd'}
    409                                         onMouseLeave={(e) => e.currentTarget.style.background = '#bfdbfe'}
    410                                     >
    411                                       Submit Result
    412                                     </button>
    413                                   </td>
    414                                 </tr>
    415                             ))}
    416                         </tbody>
    417                       </table>
    418                     </>
    419                 )}
    420               </div>
    421           )}
    422 
    423           {/* Submitted Tests History */}
    424           {!selectedTest && (
    425               <div className="bg-white rounded-lg shadow overflow-hidden mt-6">
    426                 <div className="p-6 border-b">
    427                   <h2 className="text-xl font-bold">Submitted Lab Results History ({submittedTests.length})</h2>
    428                 </div>
    429 
    430                 {submittedTests.length === 0 ? (
    431                     <div className="p-6 text-center text-gray-600">
    432                       No submitted lab results yet
    433                     </div>
    434                 ) : (
    435                     <>
    436                       {/* Filters */}
    437                       <div className="p-6 border-b bg-gray-50">
    438                         <h3 className="text-sm font-semibold mb-4">Filters</h3>
    439                         <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
    440                           <div>
    441                             <label className="block text-sm font-semibold mb-2">Test</label>
    442                             <input
    443                                 type="text"
    444                                 placeholder="Filter by test name..."
    445                                 value={submittedFilters.testName}
    446                                 onChange={(e) => setSubmittedFilters({...submittedFilters, testName: e.target.value})}
    447                                 className="w-full px-3 py-2 border rounded-lg text-sm"
    448                             />
    449                           </div>
    450                           <div>
    451                             <label className="block text-sm font-semibold mb-2">Patient</label>
    452                             <input
    453                                 type="text"
    454                                 placeholder="Filter by patient name..."
    455                                 value={submittedFilters.patientName}
    456                                 onChange={(e) => setSubmittedFilters({...submittedFilters, patientName: e.target.value})}
    457                                 className="w-full px-3 py-2 border rounded-lg text-sm"
    458                             />
    459                           </div>
    460                           <div>
    461                             <label className="block text-sm font-semibold mb-2">Test Date</label>
    462                             <input
    463                                 type="date"
    464                                 value={submittedFilters.testDate}
    465                                 onChange={(e) => setSubmittedFilters({...submittedFilters, testDate: e.target.value})}
    466                                 className="w-full px-3 py-2 border rounded-lg text-sm"
    467                             />
    468                           </div>
    469                         </div>
    470                         <button
    471                             onClick={() => setSubmittedFilters({testName: '', patientName: '', testDate: ''})}
    472                             className="mt-4 bg-gray-300 text-gray-700 px-4 py-2 rounded text-sm hover:bg-gray-400"
    473                         >
    474                           Clear Filters
    475                         </button>
    476                       </div>
    477 
    478                       {/* Filtered Results Table */}
    479                       <table className="w-full">
    480                         <thead className="bg-gray-100">
    481                         <tr>
    482                           <th className="px-6 py-3 text-left text-sm font-semibold">Test</th>
    483                           <th className="px-6 py-3 text-left text-sm font-semibold">Patient</th>
    484                           <th className="px-6 py-3 text-left text-sm font-semibold">Test Date</th>
    485                           <th className="px-6 py-3 text-left text-sm font-semibold">Result Date</th>
    486                           <th className="px-6 py-3 text-left text-sm font-semibold">Status</th>
    487                         </tr>
    488                         </thead>
    489                         <tbody>
    490                         {submittedTests
    491                             .filter((test) => {
    492                               const testName = (test.testName || '').toLowerCase();
    493                               const patientName = (test.patientName || '').toLowerCase();
    494                               const testDate = (test.testDate || '');
    495 
    496                               return (
    497                                   testName.includes(submittedFilters.testName.toLowerCase()) &&
    498                                   patientName.includes(submittedFilters.patientName.toLowerCase()) &&
    499                                   (submittedFilters.testDate === '' || testDate === submittedFilters.testDate)
    500                               );
    501                             })
    502                             .map((test, index) => (
    503                                 <tr key={index} className="border-t hover:bg-gray-50">
    504                                   <td className="px-6 py-3 font-medium">{test.testName || test.description || 'Lab Test'}</td>
    505                                   <td className="px-6 py-3">{test.patientName || 'N/A'}</td>
    506                                   <td className="px-6 py-3">{test.testDate || 'N/A'}</td>
    507                                   <td className="px-6 py-3 text-green-600">{test.resultDate || test.createdDate || 'N/A'}</td>
    508                                   <td className="px-6 py-3">
     516                {/* Filtered Results Table */}
     517                <table className="w-full">
     518                  <thead className="bg-gray-100">
     519                    <tr>
     520                      <th className="px-6 py-3 text-left text-sm font-semibold">Test</th>
     521                      <th className="px-6 py-3 text-left text-sm font-semibold">Patient</th>
     522                      <th className="px-6 py-3 text-left text-sm font-semibold">Test Date</th>
     523                      <th className="px-6 py-3 text-left text-sm font-semibold">Result Date</th>
     524                      <th className="px-6 py-3 text-left text-sm font-semibold">Status</th>
     525                    </tr>
     526                  </thead>
     527                  <tbody>
     528                    {submittedTests
     529                      .filter((test) => {
     530                        const testName = (test.testName || '').toLowerCase();
     531                        const patientName = (test.patientName || '').toLowerCase();
     532                        const testDate = (test.testDate || '');
     533
     534                        return (
     535                          testName.includes(submittedFilters.testName.toLowerCase()) &&
     536                          patientName.includes(submittedFilters.patientName.toLowerCase()) &&
     537                          (submittedFilters.testDate === '' || testDate === submittedFilters.testDate)
     538                        );
     539                      })
     540                      .map((test, index) => (
     541                        <tr key={index} className="border-t hover:bg-gray-50">
     542                          <td className="px-6 py-3 font-medium">{test.testName || test.description || 'Lab Test'}</td>
     543                          <td className="px-6 py-3">{test.patientName || 'N/A'}</td>
     544                          <td className="px-6 py-3">{test.testDate || 'N/A'}</td>
     545                          <td className="px-6 py-3 text-green-600">{test.resultDate || test.createdDate || 'N/A'}</td>
     546                          <td className="px-6 py-3">
    509547                            <span className="px-3 py-1 bg-green-100 text-green-800 rounded-full text-sm font-semibold">
    510548                              Submitted
    511549                            </span>
    512                                   </td>
    513                                 </tr>
    514                             ))}
    515                         </tbody>
    516                       </table>
    517                     </>
    518                 )}
    519               </div>
     550                          </td>
     551                        </tr>
     552                      ))}
     553                  </tbody>
     554                </table>
     555              </>
     556            )}
     557          </div>
     558        )}
     559      </div>
     560    );
     561  }
     562
     563  return (
     564    <div>
     565      <h1 className="text-3xl font-bold mb-6" style={{ color: '#7c3aed' }}>Lab Tests</h1>
     566
     567      {error && <ErrorAlert message={error} onClose={() => setError(null)} />}
     568
     569      {/* Search Form */}
     570      <div className="bg-white rounded-lg shadow p-6 mb-6">
     571        <h2 className="text-xl font-bold mb-4">Search Patient</h2>
     572        <form onSubmit={handleSearch} className="space-y-4">
     573          <div className="flex gap-4">
     574            <div className="flex-1">
     575              <label className="block text-sm font-semibold mb-2">Patient EMBG</label>
     576              <input
     577                type="text"
     578                value={embg}
     579                onChange={(e) => setEmbg(e.target.value)}
     580                placeholder="e.g., 1402994123456"
     581                className="w-full px-4 py-2 border rounded-lg"
     582              />
     583            </div>
     584            <div className="flex items-end">
     585              <button
     586                type="submit"
     587                disabled={loading}
     588                className="bg-purple-600 text-white px-8 py-2 rounded-full hover:bg-purple-700 disabled:bg-gray-400"
     589              >
     590                {loading ? 'Searching...' : 'Search'}
     591              </button>
     592            </div>
     593          </div>
     594        </form>
     595      </div>
     596
     597      {/* Patient Lab Tests */}
     598      {searched && patient && (
     599        <div className="space-y-6">
     600          {/* Patient Info */}
     601          <div className="bg-white rounded-lg shadow p-6">
     602            <div className="flex justify-between items-start mb-4">
     603              <h2 className="text-2xl font-bold">{patient.firstName} {patient.lastName}</h2>
     604              {!showRequestForm && (
     605                <button
     606                  onClick={() => setShowRequestForm(true)}
     607                  className="bg-green-600 text-white px-4 py-2 rounded hover:bg-green-700"
     608                >
     609                  Request Lab Test
     610                </button>
     611              )}
     612            </div>
     613            <div className="grid grid-cols-4 gap-4">
     614              <div>
     615                <p className="text-sm text-gray-600">EMBG</p>
     616                <p className="font-semibold">{patient.embg}</p>
     617              </div>
     618              <div>
     619                <p className="text-sm text-gray-600">Blood Type</p>
     620                <p className="font-semibold">{patient.bloodType || 'N/A'}</p>
     621              </div>
     622              <div>
     623                <p className="text-sm text-gray-600">Date of Birth</p>
     624                <p className="font-semibold">{patient.dateOfBirth}</p>
     625              </div>
     626            </div>
     627          </div>
     628
     629          {/* Request Lab Test Form */}
     630          {showRequestForm && (
     631            <div className="bg-white rounded-lg shadow p-6">
     632              <h3 className="text-xl font-bold mb-4">Request Lab Test</h3>
     633              <form onSubmit={handleRequestTest} className="space-y-4">
     634                <div className="grid grid-cols-2 gap-4">
     635                  <div>
     636                    <label className="block text-sm font-semibold mb-2">Test</label>
     637                    <select
     638                      value={requestData.testId}
     639                      onChange={(e) => setRequestData({ ...requestData, testId: e.target.value })}
     640                      className="w-full px-4 py-2 border rounded-lg"
     641                      required
     642                    >
     643                      <option value="">Select a test</option>
     644                      {availableTests.map((test) => (
     645                        <option key={test.testId} value={test.testId}>
     646                          {test.testName} (${test.cost})
     647                        </option>
     648                      ))}
     649                    </select>
     650                  </div>
     651                  <div>
     652                    <label className="block text-sm font-semibold mb-2">Test Date</label>
     653                    <input
     654                      type="date"
     655                      value={requestData.testDate}
     656                      onChange={(e) => setRequestData({ ...requestData, testDate: e.target.value })}
     657                      className="w-full px-4 py-2 border rounded-lg"
     658                    />
     659                  </div>
     660                </div>
     661                <div>
     662                  <label className="block text-sm font-semibold mb-2">Notes</label>
     663                  <textarea
     664                    value={requestData.notes}
     665                    onChange={(e) => setRequestData({ ...requestData, notes: e.target.value })}
     666                    placeholder="Additional notes for the lab technician"
     667                    className="w-full px-4 py-2 border rounded-lg"
     668                    rows="3"
     669                  />
     670                </div>
     671                <div className="flex gap-4">
     672                  <button
     673                    type="submit"
     674                    disabled={loading}
     675                    className="bg-green-600 text-white px-6 py-2 rounded hover:bg-green-700 disabled:bg-gray-400"
     676                  >
     677                    {loading ? 'Requesting...' : 'Request Test'}
     678                  </button>
     679                  <button
     680                    type="button"
     681                    onClick={() => setShowRequestForm(false)}
     682                    className="bg-gray-400 text-white px-6 py-2 rounded hover:bg-gray-500"
     683                  >
     684                    Cancel
     685                  </button>
     686                </div>
     687              </form>
     688            </div>
     689          )}
     690
     691          {/* Test Requests */}
     692          {labTestRequests && labTestRequests.length > 0 && (
     693            <div className="bg-white rounded-lg shadow p-6">
     694              <h3 className="text-xl font-bold mb-4">Lab Test Requests</h3>
     695              <div className="space-y-3">
     696                {labTestRequests.map((request) => (
     697                  <div key={request.testId} className="border-l-4 border-purple-500 pl-4 py-2">
     698                    <p className="font-semibold text-lg">{request.testName}</p>
     699                    <p className="text-sm text-gray-600">Requested by: {request.doctorName}</p>
     700                    <p className="text-sm text-gray-600">Test Date: {request.requestDate}</p>
     701                    {request.notes && (
     702                      <p className="text-sm text-gray-600">Notes: {request.notes}</p>
     703                    )}
     704                  </div>
     705                ))}
     706              </div>
     707            </div>
     708          )}
     709
     710          {/* Lab Test Results */}
     711          {labResults && labResults.length > 0 && (
     712            <div className="bg-white rounded-lg shadow p-6">
     713              <h3 className="text-xl font-bold mb-4">Lab Test Results</h3>
     714              <div className="space-y-4">
     715                {labResults.map((result) => (
     716                  <div key={result.resultId} className="border-l-4 border-green-500 pl-4 py-3 bg-green-50 rounded">
     717                    <p className="font-semibold text-lg text-green-700">{result.testName}</p>
     718                    <p className="text-sm text-gray-700 mt-2"><strong>Results:</strong> {result.results}</p>
     719                    <p className="text-sm text-gray-600">Result Date: {result.resultDate}</p>
     720                  </div>
     721                ))}
     722              </div>
     723            </div>
     724          )}
     725
     726          {/* Link to submit results */}
     727          {labTestRequests && labTestRequests.length > 0 && (
     728            <div className="bg-yellow-50 rounded-lg p-6">
     729              <h3 className="text-lg font-semibold text-yellow-800 mb-3">Lab Technician: Submit Test Results</h3>
     730              <p className="text-sm text-gray-700 mb-4">
     731                {labTestRequests.length} test{labTestRequests.length !== 1 ? 's' : ''} awaiting results
     732              </p>
     733              <a
     734                href="/lab-tests/results"
     735                className="inline-block bg-yellow-600 text-white px-6 py-2 rounded hover:bg-yellow-700"
     736              >
     737                Submit Lab Results
     738              </a>
     739            </div>
     740          )}
     741
     742          {/* No requests message */}
     743          {(!labTestRequests || labTestRequests.length === 0) && !labResults?.length && (
     744            <div className="bg-blue-50 rounded-lg p-6 text-center">
     745              <p className="text-gray-600">No lab test requests for this patient</p>
     746            </div>
    520747          )}
    521748        </div>
    522     );
    523   }
    524 
    525   return (
    526       <div>
    527         <h1 className="text-3xl font-bold mb-6" style={{ color: '#7c3aed' }}>Lab Tests</h1>
    528 
    529         {error && <ErrorAlert message={error} onClose={() => setError(null)} />}
    530 
    531         {/* Search Form */}
    532         <div className="bg-white rounded-lg shadow p-6 mb-6">
    533           <h2 className="text-xl font-bold mb-4">Search Patient</h2>
    534           <form onSubmit={handleSearch} className="space-y-4">
    535             <div className="flex gap-4">
    536               <div className="flex-1">
    537                 <label className="block text-sm font-semibold mb-2">Patient EMBG</label>
    538                 <input
    539                     type="text"
    540                     value={embg}
    541                     onChange={(e) => setEmbg(e.target.value)}
    542                     placeholder="e.g., 1402994123456"
    543                     className="w-full px-4 py-2 border rounded-lg"
    544                 />
    545               </div>
    546               <div className="flex items-end">
    547                 <button
    548                     type="submit"
    549                     disabled={loading}
    550                     className="bg-purple-600 text-white px-8 py-2 rounded-full hover:bg-purple-700 disabled:bg-gray-400"
    551                 >
    552                   {loading ? 'Searching...' : 'Search'}
    553                 </button>
    554               </div>
    555             </div>
    556           </form>
     749      )}
     750
     751      {/* No search performed */}
     752      {!searched && (
     753        <div className="bg-gray-50 rounded-lg p-12 text-center">
     754          <p className="text-gray-600 text-lg">Enter a patient EMBG to request lab tests</p>
    557755        </div>
    558 
    559         {/* Patient Lab Tests */}
    560         {searched && patient && (
    561             <div className="space-y-6">
    562               {/* Patient Info */}
    563               <div className="bg-white rounded-lg shadow p-6">
    564                 <div className="flex justify-between items-start mb-4">
    565                   <h2 className="text-2xl font-bold">{patient.firstName} {patient.lastName}</h2>
    566                   {!showRequestForm && (
    567                       <button
    568                           onClick={() => setShowRequestForm(true)}
    569                           className="bg-green-600 text-white px-4 py-2 rounded hover:bg-green-700"
    570                       >
    571                         Request Lab Test
    572                       </button>
    573                   )}
    574                 </div>
    575                 <div className="grid grid-cols-4 gap-4">
    576                   <div>
    577                     <p className="text-sm text-gray-600">EMBG</p>
    578                     <p className="font-semibold">{patient.embg}</p>
    579                   </div>
    580                   <div>
    581                     <p className="text-sm text-gray-600">Blood Type</p>
    582                     <p className="font-semibold">{patient.bloodType || 'N/A'}</p>
    583                   </div>
    584                   <div>
    585                     <p className="text-sm text-gray-600">Date of Birth</p>
    586                     <p className="font-semibold">{patient.dateOfBirth}</p>
    587                   </div>
    588                 </div>
    589               </div>
    590 
    591               {/* Request Lab Test Form */}
    592               {showRequestForm && (
    593                   <div className="bg-white rounded-lg shadow p-6">
    594                     <h3 className="text-xl font-bold mb-4">Request Lab Test</h3>
    595                     <form onSubmit={handleRequestTest} className="space-y-4">
    596                       <div className="grid grid-cols-2 gap-4">
    597                         <div>
    598                           <label className="block text-sm font-semibold mb-2">Test</label>
    599                           <select
    600                               value={requestData.testId}
    601                               onChange={(e) => setRequestData({ ...requestData, testId: e.target.value })}
    602                               className="w-full px-4 py-2 border rounded-lg"
    603                               required
    604                           >
    605                             <option value="">Select a test</option>
    606                             {availableTests.map((test) => (
    607                                 <option key={test.testId} value={test.testId}>
    608                                   {test.testName} (${test.cost})
    609                                 </option>
    610                             ))}
    611                           </select>
    612                         </div>
    613                         <div>
    614                           <label className="block text-sm font-semibold mb-2">Test Date</label>
    615                           <input
    616                               type="date"
    617                               value={requestData.testDate}
    618                               onChange={(e) => setRequestData({ ...requestData, testDate: e.target.value })}
    619                               className="w-full px-4 py-2 border rounded-lg"
    620                           />
    621                         </div>
    622                       </div>
    623                       <div>
    624                         <label className="block text-sm font-semibold mb-2">Notes</label>
    625                         <textarea
    626                             value={requestData.notes}
    627                             onChange={(e) => setRequestData({ ...requestData, notes: e.target.value })}
    628                             placeholder="Additional notes for the lab technician"
    629                             className="w-full px-4 py-2 border rounded-lg"
    630                             rows="3"
    631                         />
    632                       </div>
    633                       <div className="flex gap-4">
    634                         <button
    635                             type="submit"
    636                             disabled={loading}
    637                             className="bg-green-600 text-white px-6 py-2 rounded hover:bg-green-700 disabled:bg-gray-400"
    638                         >
    639                           {loading ? 'Requesting...' : 'Request Test'}
    640                         </button>
    641                         <button
    642                             type="button"
    643                             onClick={() => setShowRequestForm(false)}
    644                             className="bg-gray-400 text-white px-6 py-2 rounded hover:bg-gray-500"
    645                         >
    646                           Cancel
    647                         </button>
    648                       </div>
    649                     </form>
    650                   </div>
    651               )}
    652 
    653               {/* Test Requests */}
    654               {labTestRequests && labTestRequests.length > 0 && (
    655                   <div className="bg-white rounded-lg shadow p-6">
    656                     <h3 className="text-xl font-bold mb-4">Lab Test Requests</h3>
    657                     <div className="space-y-3">
    658                       {labTestRequests.map((request) => (
    659                           <div key={request.testId} className="border-l-4 border-purple-500 pl-4 py-2">
    660                             <p className="font-semibold text-lg">{request.testName}</p>
    661                             <p className="text-sm text-gray-600">Requested by: {request.doctorName}</p>
    662                             <p className="text-sm text-gray-600">Test Date: {request.requestDate}</p>
    663                             {request.notes && (
    664                                 <p className="text-sm text-gray-600">Notes: {request.notes}</p>
    665                             )}
    666                           </div>
    667                       ))}
    668                     </div>
    669                   </div>
    670               )}
    671 
    672               {/* Lab Test Results */}
    673               {labResults && labResults.length > 0 && (
    674                   <div className="bg-white rounded-lg shadow p-6">
    675                     <h3 className="text-xl font-bold mb-4">Lab Test Results</h3>
    676                     <div className="space-y-4">
    677                       {labResults.map((result) => (
    678                           <div key={result.resultId} className="border-l-4 border-green-500 pl-4 py-3 bg-green-50 rounded">
    679                             <p className="font-semibold text-lg text-green-700">{result.testName}</p>
    680                             <p className="text-sm text-gray-700 mt-2"><strong>Results:</strong> {result.results}</p>
    681                             <p className="text-sm text-gray-600">Result Date: {result.resultDate}</p>
    682                           </div>
    683                       ))}
    684                     </div>
    685                   </div>
    686               )}
    687 
    688               {/* Link to submit results */}
    689               {labTestRequests && labTestRequests.length > 0 && (
    690                   <div className="bg-yellow-50 rounded-lg p-6">
    691                     <h3 className="text-lg font-semibold text-yellow-800 mb-3">Lab Technician: Submit Test Results</h3>
    692                     <p className="text-sm text-gray-700 mb-4">
    693                       {labTestRequests.length} test{labTestRequests.length !== 1 ? 's' : ''} awaiting results
    694                     </p>
    695                     <a
    696                         href="/lab-tests/results"
    697                         className="inline-block bg-yellow-600 text-white px-6 py-2 rounded hover:bg-yellow-700"
    698                     >
    699                       Submit Lab Results
    700                     </a>
    701                   </div>
    702               )}
    703 
    704               {/* No requests message */}
    705               {!labTestRequests || labTestRequests.length === 0 && !labResults?.length && (
    706                   <div className="bg-blue-50 rounded-lg p-6 text-center">
    707                     <p className="text-gray-600">No lab test requests for this patient</p>
    708                   </div>
    709               )}
    710             </div>
    711         )}
    712 
    713         {/* No search performed */}
    714         {!searched && (
    715             <div className="bg-gray-50 rounded-lg p-12 text-center">
    716               <p className="text-gray-600 text-lg">Enter a patient EMBG to request lab tests</p>
    717             </div>
    718         )}
    719       </div>
     756      )}
     757    </div>
    720758  );
    721759}
  • frontend/src/pages/medical-records/MedicalRecordDetail.js

    re1f74f6 r9af201e  
    1 import React, { useState, useEffect } from 'react';
     1import React, { useState, useEffect, useCallback } from 'react';
    22import { useParams, useNavigate } from 'react-router-dom';
    33import { medicalRecordService } from '../../services/medicalRecordService';
     
    7777  const [procedureResults, setProcedureResults] = useState([]);
    7878
    79   useEffect(() => {
    80     fetchRecord();
    81     fetchDoctors();
    82     fetchDropdownOptions();
    83   }, [id]);
    84 
    85   const fetchDropdownOptions = async () => {
    86     try {
    87       console.log('Fetching dropdown options...');
    88       const diagnosesRes = await apiClient.get('/medical-records/dropdown/diagnoses');
    89       console.log('Diagnoses:', diagnosesRes.data);
    90 
    91       const symptomsRes = await apiClient.get('/medical-records/dropdown/symptoms');
    92       console.log('Symptoms:', symptomsRes.data);
    93 
    94       const allergiesRes = await apiClient.get('/medical-records/dropdown/allergies');
    95       console.log('Allergies:', allergiesRes.data);
    96 
    97       const prescriptionsRes = await apiClient.get('/medical-records/dropdown/prescriptions');
    98       console.log('Prescriptions:', prescriptionsRes.data);
    99 
    100       const testsRes = await labService.getAllLabTests();
    101       console.log('Lab Tests:', testsRes.data);
    102 
    103       const proceduresRes = await procedureService.getAllProcedures();
    104       console.log('Procedures:', proceduresRes.data);
    105 
    106       setDiagnoses(diagnosesRes.data || []);
    107       setSymptoms(symptomsRes.data || []);
    108       setAllergies(allergiesRes.data || []);
    109       setPrescriptions(prescriptionsRes.data || []);
    110       setLabTests(testsRes.data || []);
    111       setProcedures(proceduresRes.data || []);
    112       console.log('Dropdown options set successfully');
    113     } catch (err) {
    114       console.error('Error fetching dropdown options:', err);
    115       setError('Failed to load dropdown options: ' + (err.response?.data?.error || err.message));
    116     }
    117   };
    118 
    119   const fetchRecord = async () => {
     79  const fetchRecord = useCallback(async () => {
    12080    try {
    12181      setLoading(true);
     
    146106      setLoading(false);
    147107    }
    148   };
    149 
    150   const fetchDoctors = async () => {
    151     try {
    152       if (!isDoctor) {
    153         const response = await doctorService.getAllDoctors();
    154         setDoctors(response.data);
    155         if (response.data.length > 0 && !selectedDoctorId) {
    156           setSelectedDoctorId(response.data[0].doctorId);
     108  }, [id]);
     109
     110  useEffect(() => {
     111    const fetchDoctors = async () => {
     112      try {
     113        if (!isDoctor) {
     114          const response = await doctorService.getAllDoctors();
     115          setDoctors(response.data);
     116          if (response.data.length > 0 && !selectedDoctorId) {
     117            setSelectedDoctorId(response.data[0].doctorId);
     118          }
    157119        }
    158       }
    159     } catch (err) {
    160       console.error('Failed to fetch doctors', err);
    161     }
    162   };
     120      } catch (err) {
     121        console.error('Failed to fetch doctors', err);
     122      }
     123    };
     124
     125    const fetchDropdownOptions = async () => {
     126      try {
     127        console.log('Fetching dropdown options...');
     128        const diagnosesRes = await apiClient.get('/medical-records/dropdown/diagnoses');
     129        console.log('Diagnoses:', diagnosesRes.data);
     130
     131        const symptomsRes = await apiClient.get('/medical-records/dropdown/symptoms');
     132        console.log('Symptoms:', symptomsRes.data);
     133
     134        const allergiesRes = await apiClient.get('/medical-records/dropdown/allergies');
     135        console.log('Allergies:', allergiesRes.data);
     136
     137        const prescriptionsRes = await apiClient.get('/medical-records/dropdown/prescriptions');
     138        console.log('Prescriptions:', prescriptionsRes.data);
     139
     140        const testsRes = await labService.getAllLabTests();
     141        console.log('Lab Tests:', testsRes.data);
     142
     143        const proceduresRes = await procedureService.getAllProcedures();
     144        console.log('Procedures:', proceduresRes.data);
     145
     146        setDiagnoses(diagnosesRes.data || []);
     147        setSymptoms(symptomsRes.data || []);
     148        setAllergies(allergiesRes.data || []);
     149        setPrescriptions(prescriptionsRes.data || []);
     150        setLabTests(testsRes.data || []);
     151        setProcedures(proceduresRes.data || []);
     152        console.log('Dropdown options set successfully');
     153      } catch (err) {
     154        console.error('Error fetching dropdown options:', err);
     155        setError('Failed to load dropdown options: ' + (err.response?.data?.error || err.message));
     156      }
     157    };
     158
     159    fetchRecord();
     160    fetchDoctors();
     161    fetchDropdownOptions();
     162  }, [id, isDoctor, fetchRecord, selectedDoctorId]);
    163163
    164164  const handleAddDiagnosis = async (e) => {
     
    857857            try {
    858858              setLoading(true);
    859               const doctorId = localStorage.getItem('doctorId') || 1;
     859              const doctorId = user.doctorId || 1;
    860860
    861861              const request = {
     
    964964            try {
    965965              setLoading(true);
    966               const doctorId = localStorage.getItem('doctorId') || 1;
     966              const doctorId = user.doctorId || 1;
    967967
    968968              const request = {
  • frontend/src/pages/medical-records/MedicalRecordList.js

    re1f74f6 r9af201e  
    2323  const [loading, setLoading] = useState(false);
    2424
    25 
     25  // Auto-load patient's own records if logged in as patient, or load specific patient records if patientId is provided
    2626  React.useEffect(() => {
    27     if (patientId) {
    28 
    29       loadPatientRecords(patientId);
    30     } else if (isPatient && user.username) {
    31       handleAutoSearch();
    32     }
    33   }, [patientId]);
    34 
    35   const loadPatientRecords = async (pId) => {
     27    const loadPatientRecords = async (pId) => {
    3628    setError(null);
    3729    setLoading(true);
    3830
    3931    try {
    40       // Get patient by id
     32      // Get patient by ID
    4133      const patientResponse = await patientService.getPatientById(pId);
    4234      setPatient(patientResponse.data);
     
    7365      setLoading(false);
    7466    }
    75   };
    76 
    77   const handleAutoSearch = async () => {
    78     const searchEmbg = user.username;
    79     setError(null);
    80     setLoading(true);
    81 
    82     try {
    83       // Search patient by EMBG
    84       const patientResponse = await patientService.getPatientByEmbg(searchEmbg);
    85       setPatient(patientResponse.data);
    86 
    87       // Get medical records for this patient
    88       const recordsResponse = await medicalRecordService.getMedicalRecordByPatientId(patientResponse.data.patientId);
    89       setMedicalData(recordsResponse.data);
    90 
    91       // Get lab results
     67    };
     68
     69    const handleAutoSearch = async () => {
     70      const searchEmbg = user.username;
     71      setError(null);
     72      setLoading(true);
     73
    9274      try {
    93         const labRes = await labService.getLabResultsForMedicalRecord(recordsResponse.data.recordId);
    94         setLabResults(labRes.data || []);
     75        // Search patient by EMBG
     76        const patientResponse = await patientService.getPatientByEmbg(searchEmbg);
     77        setPatient(patientResponse.data);
     78
     79        // Get medical records for this patient
     80        const recordsResponse = await medicalRecordService.getMedicalRecordByPatientId(patientResponse.data.patientId);
     81        setMedicalData(recordsResponse.data);
     82
     83        // Get lab results
     84        try {
     85          const labRes = await labService.getLabResultsForMedicalRecord(recordsResponse.data.recordId);
     86          setLabResults(labRes.data || []);
     87        } catch (err) {
     88          setLabResults([]);
     89        }
     90
     91        // Get procedure results
     92        try {
     93          const procRes = await procedureService.getProcedureResultsForMedicalRecord(recordsResponse.data.recordId);
     94          setProcedureResults(procRes.data || []);
     95        } catch (err) {
     96          setProcedureResults([]);
     97        }
     98
     99        setSearched(true);
    95100      } catch (err) {
     101        setError(`Patient with EMBG ${searchEmbg} not found`);
     102        setSearched(true);
     103        setPatient(null);
     104        setMedicalData(null);
    96105        setLabResults([]);
    97       }
    98 
    99       // Get procedure results
    100       try {
    101         const procRes = await procedureService.getProcedureResultsForMedicalRecord(recordsResponse.data.recordId);
    102         setProcedureResults(procRes.data || []);
    103       } catch (err) {
    104106        setProcedureResults([]);
    105       }
    106 
    107       setSearched(true);
    108     } catch (err) {
    109       setError(`Patient with EMBG ${searchEmbg} not found`);
    110       setSearched(true);
    111       setPatient(null);
    112       setMedicalData(null);
    113       setLabResults([]);
    114       setProcedureResults([]);
    115     } finally {
    116       setLoading(false);
     107      } finally {
     108        setLoading(false);
     109      }
     110    };
     111
     112    // Call appropriate function based on conditions
     113    if (patientId) {
     114      loadPatientRecords(patientId);
     115    } else if (isPatient && user.username) {
     116      handleAutoSearch();
    117117    }
    118   };
     118  }, [patientId, isPatient, user.username]);
    119119
    120120  const handleSearch = async (e) => {
     
    168168
    169169  return (
    170       <div>
    171         <h1 className="text-3xl font-bold mb-6" style={{ color: '#7c3aed' }}>Medical Records</h1>
    172 
    173         {error && <ErrorAlert message={error} onClose={() => setError(null)} />}
    174 
    175         {/* Search Form - Only show for non-patients */}
    176         {!isPatient && (
    177             <div className="bg-white rounded-lg shadow p-6 mb-6">
    178               <h2 className="text-xl font-bold mb-4">Search Medical Records</h2>
    179               <form onSubmit={handleSearch} className="space-y-4">
    180                 <div className="flex gap-4">
    181                   <div className="flex-1">
    182                     <label className="block text-sm font-semibold mb-2">Patient EMBG</label>
    183                     <input
    184                         type="text"
    185                         value={embg}
    186                         onChange={(e) => setEmbg(e.target.value)}
    187                         placeholder="e.g., 1402994123456"
    188                         className="w-full px-4 py-2 border rounded-lg"
    189                     />
    190                   </div>
    191                   <div className="flex items-end">
    192                     <button
    193                         type="submit"
    194                         disabled={loading}
    195                         className="bg-purple-600 text-white px-8 py-2 rounded-full hover:bg-purple-700 disabled:bg-gray-400"
    196                     >
    197                       {loading ? 'Searching...' : 'Search'}
    198                     </button>
    199                   </div>
    200                 </div>
    201               </form>
     170    <div>
     171      <h1 className="text-3xl font-bold mb-6" style={{ color: '#7c3aed' }}>Medical Records</h1>
     172
     173      {error && <ErrorAlert message={error} onClose={() => setError(null)} />}
     174
     175      {/* Search Form - Only show for non-patients */}
     176      {!isPatient && (
     177        <div className="bg-white rounded-lg shadow p-6 mb-6">
     178          <h2 className="text-xl font-bold mb-4">Search Medical Records</h2>
     179          <form onSubmit={handleSearch} className="space-y-4">
     180            <div className="flex gap-4">
     181              <div className="flex-1">
     182                <label className="block text-sm font-semibold mb-2">Patient EMBG</label>
     183                <input
     184                  type="text"
     185                  value={embg}
     186                  onChange={(e) => setEmbg(e.target.value)}
     187                  placeholder="e.g., 1402994123456"
     188                  className="w-full px-4 py-2 border rounded-lg"
     189                />
     190              </div>
     191              <div className="flex items-end">
     192                <button
     193                  type="submit"
     194                  disabled={loading}
     195                  className="bg-purple-600 text-white px-8 py-2 rounded-full hover:bg-purple-700 disabled:bg-gray-400"
     196                >
     197                  {loading ? 'Searching...' : 'Search'}
     198                </button>
     199              </div>
    202200            </div>
    203         )}
    204 
    205         {/* Loading indicator for patients fetching their records */}
    206         {isPatient && loading && (
    207             <div className="bg-blue-50 rounded-lg shadow p-6 mb-6">
    208               <p className="text-sm text-gray-700">
    209                 <strong>Loading your medical records...</strong>
    210               </p>
     201          </form>
     202        </div>
     203      )}
     204
     205      {/* Loading indicator for patients fetching their records */}
     206      {isPatient && loading && (
     207        <div className="bg-blue-50 rounded-lg shadow p-6 mb-6">
     208          <p className="text-sm text-gray-700">
     209            <strong>Loading your medical records...</strong>
     210          </p>
     211        </div>
     212      )}
     213
     214      {/* Patient Info Message for Patients */}
     215      {isPatient && searched && !loading && (
     216        <div className="bg-blue-50 rounded-lg shadow p-6 mb-6">
     217          <p className="text-sm text-gray-700">
     218            <strong>Viewing your medical records</strong>
     219          </p>
     220        </div>
     221      )}
     222
     223      {/* Patient Medical Records */}
     224      {searched && patient && (
     225        <div className="space-y-6">
     226          {/* Patient Info */}
     227          <div className="bg-white rounded-lg shadow p-6">
     228            <div className="flex justify-between items-start mb-4">
     229              <h2 className="text-2xl font-bold">{patient.firstName} {patient.lastName}</h2>
     230              {!isPatient && (
     231                <button
     232                  onClick={() => navigate(`/medical-records/${patient.patientId}`)}
     233                  className="bg-purple-600 text-white px-4 py-2 rounded hover:bg-purple-700"
     234                >
     235                  Add Medical Data
     236                </button>
     237              )}
    211238            </div>
    212         )}
    213 
    214         {/* Patient Info Message for Patients */}
    215         {isPatient && searched && !loading && (
    216             <div className="bg-blue-50 rounded-lg shadow p-6 mb-6">
    217               <p className="text-sm text-gray-700">
    218                 <strong>Viewing your medical records</strong>
    219               </p>
     239            <div className="grid grid-cols-4 gap-4">
     240              <div>
     241                <p className="text-sm text-gray-600">EMBG</p>
     242                <p className="font-semibold">{patient.embg}</p>
     243              </div>
     244              <div>
     245                <p className="text-sm text-gray-600">Email</p>
     246                <p className="font-semibold">{patient.emailAddress}</p>
     247              </div>
     248              <div>
     249                <p className="text-sm text-gray-600">Blood Type</p>
     250                <p className="font-semibold">{patient.bloodType || 'N/A'}</p>
     251              </div>
     252              <div>
     253                <p className="text-sm text-gray-600">Date of Birth</p>
     254                <p className="font-semibold">{patient.dateOfBirth}</p>
     255              </div>
    220256            </div>
    221         )}
    222 
    223         {/* Patient Medical Records */}
    224         {searched && patient && (
    225             <div className="space-y-6">
    226               {/* Patient Info */}
    227               <div className="bg-white rounded-lg shadow p-6">
    228                 <div className="flex justify-between items-start mb-4">
    229                   <h2 className="text-2xl font-bold">{patient.firstName} {patient.lastName}</h2>
    230                   {!isPatient && (
    231                       <button
    232                           onClick={() => navigate(`/medical-records/${patient.patientId}`)}
    233                           className="bg-purple-600 text-white px-4 py-2 rounded hover:bg-purple-700"
    234                       >
    235                         Add Medical Data
    236                       </button>
    237                   )}
    238                 </div>
    239                 <div className="grid grid-cols-4 gap-4">
    240                   <div>
    241                     <p className="text-sm text-gray-600">EMBG</p>
    242                     <p className="font-semibold">{patient.embg}</p>
    243                   </div>
    244                   <div>
    245                     <p className="text-sm text-gray-600">Email</p>
    246                     <p className="font-semibold">{patient.emailAddress}</p>
    247                   </div>
    248                   <div>
    249                     <p className="text-sm text-gray-600">Blood Type</p>
    250                     <p className="font-semibold">{patient.bloodType || 'N/A'}</p>
    251                   </div>
    252                   <div>
    253                     <p className="text-sm text-gray-600">Date of Birth</p>
    254                     <p className="font-semibold">{patient.dateOfBirth}</p>
    255                   </div>
    256                 </div>
    257               </div>
    258 
    259               {/* Medical Data Sections */}
    260               {medicalData && (
    261                   <>
    262                     {/* Diagnoses */}
    263                     {medicalData.diagnoses && medicalData.diagnoses.length > 0 && (
    264                         <div className="bg-white rounded-lg shadow p-6">
    265                           <h3 className="text-xl font-bold mb-4">Diagnoses</h3>
    266                           <div className="space-y-3">
    267                             {medicalData.diagnoses.map((diagnosis) => (
    268                                 <div key={diagnosis.diagnosisId} className="border-l-4 border-purple-500 pl-4 py-2">
    269                                   <p className="font-semibold text-lg">{diagnosis.name}</p>
    270                                   {diagnosis.description && (
    271                                       <p className="text-gray-600 text-sm">{diagnosis.description}</p>
    272                                   )}
    273                                   <p className="text-xs text-gray-500">By: {diagnosis.doctorName}</p>
    274                                 </div>
    275                             ))}
    276                           </div>
    277                         </div>
    278                     )}
    279 
    280                     {/* Symptoms */}
    281                     {medicalData.symptoms && medicalData.symptoms.length > 0 && (
    282                         <div className="bg-white rounded-lg shadow p-6">
    283                           <h3 className="text-xl font-bold mb-4">Symptoms</h3>
    284                           <div className="flex flex-wrap gap-2">
    285                             {medicalData.symptoms.map((symptom) => (
    286                                 <span key={symptom.symptomId} className="bg-yellow-100 text-yellow-800 px-3 py-1 rounded-full text-sm">
     257          </div>
     258
     259          {/* Medical Data Sections */}
     260          {medicalData && (
     261            <>
     262              {/* Diagnoses */}
     263              {medicalData.diagnoses && medicalData.diagnoses.length > 0 && (
     264                <div className="bg-white rounded-lg shadow p-6">
     265                  <h3 className="text-xl font-bold mb-4">Diagnoses</h3>
     266                  <div className="space-y-3">
     267                    {medicalData.diagnoses.map((diagnosis) => (
     268                      <div key={diagnosis.diagnosisId} className="border-l-4 border-purple-500 pl-4 py-2">
     269                        <p className="font-semibold text-lg">{diagnosis.name}</p>
     270                        {diagnosis.description && (
     271                          <p className="text-gray-600 text-sm">{diagnosis.description}</p>
     272                        )}
     273                        <p className="text-xs text-gray-500">By: {diagnosis.doctorName}</p>
     274                      </div>
     275                    ))}
     276                  </div>
     277                </div>
     278              )}
     279
     280              {/* Symptoms */}
     281              {medicalData.symptoms && medicalData.symptoms.length > 0 && (
     282                <div className="bg-white rounded-lg shadow p-6">
     283                  <h3 className="text-xl font-bold mb-4">Symptoms</h3>
     284                  <div className="flex flex-wrap gap-2">
     285                    {medicalData.symptoms.map((symptom) => (
     286                      <span key={symptom.symptomId} className="bg-yellow-100 text-yellow-800 px-3 py-1 rounded-full text-sm">
    287287                        {symptom.symptomName}
    288288                      </span>
    289                             ))}
    290                           </div>
    291                         </div>
    292                     )}
    293 
    294                     {/* Allergies */}
    295                     {medicalData.allergies && medicalData.allergies.length > 0 && (
    296                         <div className="bg-white rounded-lg shadow p-6">
    297                           <h3 className="text-xl font-bold mb-4">Allergies</h3>
    298                           <div className="space-y-3">
    299                             {medicalData.allergies.map((allergy) => (
    300                                 <div key={allergy.allergyId} className="border-l-4 border-red-500 pl-4 py-2">
    301                                   <p className="font-semibold">{allergy.allergyName}</p>
    302                                   <p className="text-sm">
     289                    ))}
     290                  </div>
     291                </div>
     292              )}
     293
     294              {/* Allergies */}
     295              {medicalData.allergies && medicalData.allergies.length > 0 && (
     296                <div className="bg-white rounded-lg shadow p-6">
     297                  <h3 className="text-xl font-bold mb-4">Allergies</h3>
     298                  <div className="space-y-3">
     299                    {medicalData.allergies.map((allergy) => (
     300                      <div key={allergy.allergyId} className="border-l-4 border-red-500 pl-4 py-2">
     301                        <p className="font-semibold">{allergy.allergyName}</p>
     302                        <p className="text-sm">
    303303                          <span className={`px-2 py-1 rounded text-white text-xs ${
    304                               allergy.severity === 'CRITICAL' ? 'bg-red-600' :
    305                                   allergy.severity === 'HIGH' ? 'bg-red-500' :
    306                                       allergy.severity === 'MEDIUM' ? 'bg-yellow-500' :
    307                                           'bg-green-500'
     304                            allergy.severity === 'CRITICAL' ? 'bg-red-600' :
     305                            allergy.severity === 'HIGH' ? 'bg-red-500' :
     306                            allergy.severity === 'MEDIUM' ? 'bg-yellow-500' :
     307                            'bg-green-500'
    308308                          }`}>
    309309                            {allergy.severity} Severity
    310310                          </span>
    311                                   </p>
    312                                   {allergy.reaction && (
    313                                       <p className="text-gray-600 text-sm">Reaction: {allergy.reaction}</p>
    314                                   )}
    315                                 </div>
    316                             ))}
    317                           </div>
    318                         </div>
    319                     )}
    320 
    321                     {/* Medical Reports */}
    322                     {medicalData.reports && medicalData.reports.length > 0 && (
    323                         <div className="bg-white rounded-lg shadow p-6">
    324                           <h3 className="text-xl font-bold mb-4">Medical Reports</h3>
    325                           <div className="space-y-3">
    326                             {medicalData.reports.map((report) => (
    327                                 <div key={report.reportId} className="border-l-4 border-green-500 pl-4 py-2">
    328                                   <p className="font-semibold">Report from {report.doctorName}</p>
    329                                   <p className="text-gray-600 text-sm">{report.description}</p>
    330                                   <p className="text-xs text-gray-500">Date: {report.reportDate}</p>
    331                                 </div>
    332                             ))}
    333                           </div>
    334                         </div>
    335                     )}
    336 
    337                     {/* Lab Test Results */}
    338                     {labResults && labResults.length > 0 && (
    339                         <div className="bg-white rounded-lg shadow p-6">
    340                           <h3 className="text-xl font-bold mb-4">Lab Test Results</h3>
    341                           <div className="space-y-3">
    342                             {labResults.map((result) => (
    343                                 <div key={result.labResultId} className="border-l-4 border-purple-500 pl-4 py-2">
    344                                   <p className="font-semibold">{result.testName}</p>
    345                                   <p className="text-gray-600 text-sm">{result.result}</p>
    346                                   {result.notes && (
    347                                       <p className="text-gray-600 text-sm">Notes: {result.notes}</p>
    348                                   )}
    349                                   <p className="text-xs text-gray-500">Date: {result.resultDate}</p>
    350                                   {result.technicianName && (
    351                                       <p className="text-xs text-gray-500">Technician: {result.technicianName}</p>
    352                                   )}
    353                                 </div>
    354                             ))}
    355                           </div>
    356                         </div>
    357                     )}
    358 
    359                     {/* Procedure Results */}
    360                     {procedureResults && procedureResults.length > 0 && (
    361                         <div className="bg-white rounded-lg shadow p-6">
    362                           <h3 className="text-xl font-bold mb-4">Procedure Results</h3>
    363                           <div className="space-y-3">
    364                             {procedureResults.map((result) => (
    365                                 <div key={result.procedureResultId} className="border-l-4 border-orange-500 pl-4 py-2">
    366                                   <p className="font-semibold">{result.procedureName}</p>
    367                                   <p className="text-gray-600 text-sm">{result.result}</p>
    368                                   {result.notes && (
    369                                       <p className="text-gray-600 text-sm">Notes: {result.notes}</p>
    370                                   )}
    371                                   <p className="text-xs text-gray-500">Date: {result.resultDate}</p>
    372                                   {result.doctorName && (
    373                                       <p className="text-xs text-gray-500">Doctor: {result.doctorName}</p>
    374                                   )}
    375                                 </div>
    376                             ))}
    377                           </div>
    378                         </div>
    379                     )}
    380 
    381                     {/* No data message */}
    382                     {(!medicalData.diagnoses || medicalData.diagnoses.length === 0) &&
    383                         (!medicalData.symptoms || medicalData.symptoms.length === 0) &&
    384                         (!medicalData.allergies || medicalData.allergies.length === 0) &&
    385                         (!medicalData.reports || medicalData.reports.length === 0) &&
    386                         (!labResults || labResults.length === 0) &&
    387                         (!procedureResults || procedureResults.length === 0) && (
    388                             <div className="bg-blue-50 rounded-lg p-6 text-center">
    389                               <p className="text-gray-600">No medical records found for this patient</p>
    390                             </div>
    391                         )}
    392                   </>
    393               )}
    394             </div>
    395         )}
    396 
    397         {/* No search performed */}
    398         {!searched && !isPatient && (
    399             <div className="bg-gray-50 rounded-lg p-12 text-center">
    400               <p className="text-gray-600 text-lg">Enter a patient EMBG to view their medical records</p>
    401             </div>
    402         )}
    403 
    404         {/* Loading message for patients */}
    405         {isPatient && loading && (
    406             <div className="bg-gray-50 rounded-lg p-12 text-center">
    407               <p className="text-gray-600 text-lg">Loading your medical records...</p>
    408             </div>
    409         )}
    410       </div>
     311                        </p>
     312                        {allergy.reaction && (
     313                          <p className="text-gray-600 text-sm">Reaction: {allergy.reaction}</p>
     314                        )}
     315                      </div>
     316                    ))}
     317                  </div>
     318                </div>
     319              )}
     320
     321              {/* Medical Reports */}
     322              {medicalData.reports && medicalData.reports.length > 0 && (
     323                <div className="bg-white rounded-lg shadow p-6">
     324                  <h3 className="text-xl font-bold mb-4">Medical Reports</h3>
     325                  <div className="space-y-3">
     326                    {medicalData.reports.map((report) => (
     327                      <div key={report.reportId} className="border-l-4 border-green-500 pl-4 py-2">
     328                        <p className="font-semibold">Report from {report.doctorName}</p>
     329                        <p className="text-gray-600 text-sm">{report.description}</p>
     330                        <p className="text-xs text-gray-500">Date: {report.reportDate}</p>
     331                      </div>
     332                    ))}
     333                  </div>
     334                </div>
     335              )}
     336
     337              {/* Lab Test Results */}
     338              {labResults && labResults.length > 0 && (
     339                <div className="bg-white rounded-lg shadow p-6">
     340                  <h3 className="text-xl font-bold mb-4">Lab Test Results</h3>
     341                  <div className="space-y-3">
     342                    {labResults.map((result) => (
     343                      <div key={result.labResultId} className="border-l-4 border-purple-500 pl-4 py-2">
     344                        <p className="font-semibold">{result.testName}</p>
     345                        <p className="text-gray-600 text-sm">{result.result}</p>
     346                        {result.notes && (
     347                          <p className="text-gray-600 text-sm">Notes: {result.notes}</p>
     348                        )}
     349                        <p className="text-xs text-gray-500">Date: {result.resultDate}</p>
     350                        {result.technicianName && (
     351                          <p className="text-xs text-gray-500">Technician: {result.technicianName}</p>
     352                        )}
     353                      </div>
     354                    ))}
     355                  </div>
     356                </div>
     357              )}
     358
     359              {/* Procedure Results */}
     360              {procedureResults && procedureResults.length > 0 && (
     361                <div className="bg-white rounded-lg shadow p-6">
     362                  <h3 className="text-xl font-bold mb-4">Procedure Results</h3>
     363                  <div className="space-y-3">
     364                    {procedureResults.map((result) => (
     365                      <div key={result.procedureResultId} className="border-l-4 border-orange-500 pl-4 py-2">
     366                        <p className="font-semibold">{result.procedureName}</p>
     367                        <p className="text-gray-600 text-sm">{result.result}</p>
     368                        {result.notes && (
     369                          <p className="text-gray-600 text-sm">Notes: {result.notes}</p>
     370                        )}
     371                        <p className="text-xs text-gray-500">Date: {result.resultDate}</p>
     372                        {result.doctorName && (
     373                          <p className="text-xs text-gray-500">Doctor: {result.doctorName}</p>
     374                        )}
     375                      </div>
     376                    ))}
     377                  </div>
     378                </div>
     379              )}
     380
     381              {/* No data message */}
     382              {(!medicalData.diagnoses || medicalData.diagnoses.length === 0) &&
     383                (!medicalData.symptoms || medicalData.symptoms.length === 0) &&
     384                (!medicalData.allergies || medicalData.allergies.length === 0) &&
     385                (!medicalData.reports || medicalData.reports.length === 0) &&
     386                (!labResults || labResults.length === 0) &&
     387                (!procedureResults || procedureResults.length === 0) && (
     388                <div className="bg-blue-50 rounded-lg p-6 text-center">
     389                  <p className="text-gray-600">No medical records found for this patient</p>
     390                </div>
     391              )}
     392            </>
     393          )}
     394        </div>
     395      )}
     396
     397      {/* No search performed */}
     398      {!searched && !isPatient && (
     399        <div className="bg-gray-50 rounded-lg p-12 text-center">
     400          <p className="text-gray-600 text-lg">Enter a patient EMBG to view their medical records</p>
     401        </div>
     402      )}
     403
     404      {/* Loading message for patients */}
     405      {isPatient && loading && (
     406        <div className="bg-gray-50 rounded-lg p-12 text-center">
     407          <p className="text-gray-600 text-lg">Loading your medical records...</p>
     408        </div>
     409      )}
     410    </div>
    411411  );
    412412}
  • frontend/src/pages/medical-reports/MedicalReportList.js

    re1f74f6 r9af201e  
    44import { doctorService } from '../../services/doctorService';
    55import { medicalRecordService } from '../../services/medicalRecordService';
    6 import { medicalItemsService } from '../../services/medicalItemsService';
    76import ErrorAlert from '../../components/ErrorAlert';
    87import SuccessAlert from '../../components/SuccessAlert';
     
    1918  const [loading, setLoading] = useState(false);
    2019
    21   const [availableDiagnoses, setAvailableDiagnoses] = useState([]);
    22   const [availablePrescriptions, setAvailablePrescriptions] = useState([]);
    23   const [availableAllergies, setAvailableAllergies] = useState([]);
    24   const [availableSymptoms, setAvailableSymptoms] = useState([]);
    25 
    2620  const [selectedDiagnosisIds, setSelectedDiagnosisIds] = useState(new Set());
    2721  const [selectedPrescriptionIds, setSelectedPrescriptionIds] = useState(new Set());
     
    7064      const medicalRecordRes = await medicalRecordService.getMedicalRecordByPatientId(patientRes.data.patientId);
    7165      const medicalRecordId = medicalRecordRes.data.recordId;
    72       const patientId = patientRes.data.patientId;
    7366
    7467      const reportsRes = await medicalReportService.getReportsForMedicalRecord(medicalRecordId);
    7568      setReports(Array.isArray(reportsRes.data) ? reportsRes.data : [reportsRes.data]);
    76 
    77       // Fetch available medical items
    78       try {
    79         const diagnosesRes = await medicalItemsService.getDiagnosesForPatient(patientId);
    80         setAvailableDiagnoses(diagnosesRes.data || []);
    81       } catch (err) {
    82         console.error('Error loading diagnoses:', err);
    83         setAvailableDiagnoses([]);
    84       }
    85 
    86       try {
    87         const prescriptionsRes = await medicalItemsService.getPrescriptionsForMedicalRecord(medicalRecordId);
    88         setAvailablePrescriptions(prescriptionsRes.data || []);
    89       } catch (err) {
    90         console.error('Error loading prescriptions:', err);
    91         setAvailablePrescriptions([]);
    92       }
    93 
    94       try {
    95         const allergiesRes = await medicalItemsService.getAllergiesForMedicalRecord(medicalRecordId);
    96         setAvailableAllergies(allergiesRes.data || []);
    97       } catch (err) {
    98         console.error('Error loading allergies:', err);
    99         setAvailableAllergies([]);
    100       }
    101 
    102       try {
    103         const symptomsRes = await medicalItemsService.getSymptomsForMedicalRecord(medicalRecordId);
    104         setAvailableSymptoms(symptomsRes.data || []);
    105       } catch (err) {
    106         console.error('Error loading symptoms:', err);
    107         setAvailableSymptoms([]);
    108       }
    10969
    11070      setSelectedReport(null);
     
    11777      setReports([]);
    11878      setSearchedPatient(null);
    119       setAvailableDiagnoses([]);
    120       setAvailablePrescriptions([]);
    121       setAvailableAllergies([]);
    122       setAvailableSymptoms([]);
    12379    } finally {
    12480      setLoading(false);
     
    175131      [name]: value
    176132    }));
    177   };
    178 
    179   const toggleDiagnosisSelection = (diagnosisId) => {
    180     setSelectedDiagnosisIds(prev => {
    181       const newSet = new Set(prev);
    182       if (newSet.has(diagnosisId)) {
    183         newSet.delete(diagnosisId);
    184       } else {
    185         newSet.add(diagnosisId);
    186       }
    187       return newSet;
    188     });
    189   };
    190 
    191   const togglePrescriptionSelection = (prescriptionId) => {
    192     setSelectedPrescriptionIds(prev => {
    193       const newSet = new Set(prev);
    194       if (newSet.has(prescriptionId)) {
    195         newSet.delete(prescriptionId);
    196       } else {
    197         newSet.add(prescriptionId);
    198       }
    199       return newSet;
    200     });
    201   };
    202 
    203   const toggleAllergySelection = (allergyId) => {
    204     setSelectedAllergyIds(prev => {
    205       const newSet = new Set(prev);
    206       if (newSet.has(allergyId)) {
    207         newSet.delete(allergyId);
    208       } else {
    209         newSet.add(allergyId);
    210       }
    211       return newSet;
    212     });
    213   };
    214 
    215   const toggleSymptomSelection = (symptomId) => {
    216     setSelectedSymptomIds(prev => {
    217       const newSet = new Set(prev);
    218       if (newSet.has(symptomId)) {
    219         newSet.delete(symptomId);
    220       } else {
    221         newSet.add(symptomId);
    222       }
    223       return newSet;
    224     });
    225133  };
    226134
  • frontend/src/pages/procedures/ProcedureList.js

    re1f74f6 r9af201e  
    66
    77function ProcedureList() {
     8  const [user, setUser] = useState({});
    89  const [patient, setPatient] = useState(null);
    910  const [embg, setEmbg] = useState('');
     
    2223    notes: '',
    2324  });
     25
     26  // Load user from localStorage and listen for changes
     27  useEffect(() => {
     28    const loadUser = () => {
     29      const userStr = localStorage.getItem('user');
     30      console.log('[ProcedureList] Loading user from localStorage:', userStr);
     31      if (userStr) {
     32        try {
     33          const parsedUser = JSON.parse(userStr);
     34          console.log('[ProcedureList] Parsed user:', parsedUser);
     35          setUser(parsedUser);
     36        } catch (err) {
     37          console.error('Failed to parse user:', err);
     38          setUser({});
     39        }
     40      } else {
     41        console.log('[ProcedureList] No user in localStorage');
     42        setUser({});
     43      }
     44    };
     45
     46    console.log('[ProcedureList] useEffect running - loading user');
     47    loadUser();
     48
     49    // Listen for storage changes (other tabs/windows)
     50    window.addEventListener('storage', loadUser);
     51
     52    // Listen for custom event (same tab changes)
     53    window.addEventListener('userStorageChange', loadUser);
     54
     55    return () => {
     56      window.removeEventListener('storage', loadUser);
     57      window.removeEventListener('userStorageChange', loadUser);
     58    };
     59  }, []);
    2460
    2561  const handleSearch = async (e) => {
     
    97133      setLoading(true);
    98134
    99       // Get doctor ID from localStorage (set during login)
    100       const doctorId = localStorage.getItem('doctorId') || 1;
     135      // Get doctor ID from logged-in user
     136      const doctorId = user.doctorId;
    101137
    102138      const request = {
     
    108144      };
    109145
    110       console.log('Sending request:', request);
     146      console.log('User object:', user);
     147      console.log('Sending procedure request with doctorId:', doctorId, 'Full request:', request);
    111148      await procedureService.recordProcedure(request);
    112149
     
    313350
    314351          {/* No procedures message */}
    315           {!performedProcedures || (performedProcedures.length === 0 && !procedureResults?.length) && (
     352          {(!performedProcedures || performedProcedures.length === 0) && !procedureResults?.length && (
    316353            <div className="bg-blue-50 rounded-lg p-6 text-center">
    317354              <p className="text-gray-600">No procedures for this patient</p>
  • frontend/src/pages/procedures/ProcedureResultForm.js

    re1f74f6 r9af201e  
    1 import React, { useState, useEffect } from 'react';
     1import React, { useState } from 'react';
    22import { useNavigate } from 'react-router-dom';
    33import { procedureService } from '../../services/procedureService';
Note: See TracChangeset for help on using the changeset viewer.