Ignore:
Timestamp:
05/25/26 13:43:53 (4 months ago)
Author:
MBK <marija.karapandzova@…>
Branches:
master
Children:
f18b11b
Parents:
84249b1
Message:

Fix doctor authorization and prevent canceling other doctors appointments and restrict them from billing access

File:
1 edited

Legend:

Unmodified
Added
Removed
  • frontend/src/pages/billing/BillingDetail.js

    r84249b1 ra64c772  
    7878  if (loading) return <Loading />;
    7979
     80  // Prevent unauthorized access to billing
     81  if (user.role === 'DOCTOR' || user.role === 'LAB_TECHNICIAN') {
     82    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>
     87    );
     88  }
     89
    8090  if (!billing) {
    8191    return (
    82       <div>
    83         <ErrorAlert message="Billing record not found" onClose={() => navigate('/billing')} />
    84       </div>
     92        <div>
     93          <ErrorAlert message="Billing record not found" onClose={() => navigate('/billing')} />
     94        </div>
    8595    );
    8696  }
    8797
    8898  return (
    89     <div>
    90       <div className="flex justify-between items-center mb-6">
    91         <h1 className="text-3xl font-bold" style={{ color: '#7c3aed' }}>Billing Record #{billing.billId}</h1>
    92         <div className="space-x-2">
    93           <button
    94             onClick={handleDownloadInvoice}
    95             disabled={downloading}
    96             className="bg-green-600 text-white px-4 py-2 rounded hover:bg-green-700 disabled:opacity-50"
    97           >
    98             {downloading ? 'Downloading...' : 'Download Invoice (PDF)'}
    99           </button>
    100           <button onClick={() => navigate('/billing')} className="bg-gray-300 text-gray-700 px-4 py-2 rounded hover:bg-gray-400">
    101             Back
    102           </button>
    103         </div>
    104       </div>
    105 
    106       {error && <ErrorAlert message={error} onClose={() => setError(null)} />}
    107       {success && <SuccessAlert message={success} onClose={() => setSuccess(null)} />}
    108 
    109       <div className={`grid gap-6 mb-6 ${isPatient ? 'grid-cols-1 lg:grid-cols-2' : 'grid-cols-1 lg:grid-cols-3'}`}>
    110         <div className="bg-white rounded-lg shadow p-6">
    111           <h2 className="text-xl font-bold mb-4">Billing Information</h2>
    112           <div className="space-y-3">
    113             <InfoRow label="Patient" value={billing.patientName} />
    114             <InfoRow label="Total Cost" value={`$${billing.totalCost}`} />
    115             <InfoRow label="Current Status" value={billing.paymentStatus} />
    116             <InfoRow label="Payment Date" value={billing.paymentDate || 'Not paid'} />
     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>
    117113          </div>
    118114        </div>
    119115
    120         {!isPatient && (
     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'}`}>
    121120          <div className="bg-white rounded-lg shadow p-6">
    122             <h2 className="text-xl font-bold mb-4">Update Payment Status</h2>
    123             <div className="space-y-4">
    124               <div>
    125                 <label className="block text-sm font-semibold mb-2">Payment Status</label>
    126                 <select
    127                   value={paymentStatus}
    128                   onChange={(e) => setPaymentStatus(e.target.value)}
    129                   className="w-full px-4 py-2 border rounded-lg"
    130                 >
    131                   <option value="PENDING">Pending</option>
    132                   <option value="PAID">Paid</option>
    133                   <option value="CANCELLED">Cancelled</option>
    134                 </select>
    135               </div>
    136               <button
    137                 onClick={handleUpdatePaymentStatus}
    138                 disabled={updating || paymentStatus === billing.paymentStatus}
    139                 className="w-full bg-purple-600 text-white px-4 py-2 rounded hover:bg-purple-700 disabled:opacity-50"
    140               >
    141                 {updating ? 'Updating...' : 'Update Status'}
    142               </button>
     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'} />
    143127            </div>
    144128          </div>
    145         )}
    146 
    147         <div className="bg-white rounded-lg shadow p-6">
    148           <h2 className="text-xl font-bold mb-4">Patient Details</h2>
    149           <div className="space-y-3">
    150             {billingDetail && (
    151               <>
    152                 <InfoRow label="EMBG" value={billingDetail.patientEmbg} />
    153                 <InfoRow label="Phone" value={billingDetail.patientPhone} />
    154                 <InfoRow label="Bill Date" value={billingDetail.billDate} />
    155               </>
    156             )}
    157           </div>
    158         </div>
    159       </div>
    160 
    161       <div className="bg-white rounded-lg shadow p-6">
    162         <h2 className="text-xl font-bold mb-4">Itemized Services</h2>
    163 
    164         {billingDetail && (billingDetail.procedures.length > 0 || billingDetail.labTests.length > 0) ? (
    165           <div className="space-y-4">
    166             {billingDetail.procedures.length > 0 && (
    167               <div>
    168                 <h3 className="font-semibold text-lg mb-2">Procedures</h3>
    169                 <table className="w-full">
    170                   <thead className="bg-gray-100">
    171                     <tr>
    172                       <th className="px-4 py-2 text-left">Description</th>
    173                       <th className="px-4 py-2 text-right">Cost</th>
    174                     </tr>
    175                   </thead>
    176                   <tbody>
    177                     {billingDetail.procedures.map((proc, idx) => (
    178                       <tr key={idx} className="border-t">
    179                         <td className="px-4 py-2">{proc.description}</td>
    180                         <td className="px-4 py-2 text-right">${proc.cost}</td>
    181                       </tr>
    182                     ))}
    183                   </tbody>
    184                 </table>
     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>
    185154              </div>
    186             )}
    187 
    188             {billingDetail.labTests.length > 0 && (
    189               <div>
    190                 <h3 className="font-semibold text-lg mb-2">Lab Tests</h3>
    191                 <table className="w-full">
    192                   <thead className="bg-gray-100">
    193                     <tr>
    194                       <th className="px-4 py-2 text-left">Description</th>
    195                       <th className="px-4 py-2 text-right">Cost</th>
    196                     </tr>
    197                   </thead>
    198                   <tbody>
    199                     {billingDetail.labTests.map((test, idx) => (
    200                       <tr key={idx} className="border-t">
    201                         <td className="px-4 py-2">{test.description}</td>
    202                         <td className="px-4 py-2 text-right">${test.cost}</td>
    203                       </tr>
    204                     ))}
    205                   </tbody>
    206                 </table>
    207               </div>
    208             )}
    209 
    210             <div className="border-t-2 pt-4 mt-4 flex justify-end">
    211               <div className="text-right">
    212                 <p className="text-gray-600">Total Amount:</p>
    213                 <p className="text-2xl font-bold text-purple-600">${billing.totalCost}</p>
    214               </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              )}
    215167            </div>
    216168          </div>
    217         ) : (
    218           <p className="text-gray-500">No services itemized for this billing record.</p>
    219         )}
     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>
    220231      </div>
    221     </div>
    222232  );
    223233}
     
    225235function InfoRow({ label, value }) {
    226236  return (
    227     <div className="flex justify-between">
    228       <span className="text-gray-800">{label}:</span>
    229       <span className="text-gray-800">{value || 'N/A'}</span>
    230     </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>
    231241  );
    232242}
Note: See TracChangeset for help on using the changeset viewer.