Changeset 9af201e for frontend/src/pages/billing/BillingList.js
- Timestamp:
- 09/04/26 19:08:08 (2 weeks ago)
- Branches:
- master
- Children:
- cdcff72
- Parents:
- e1f74f6
- File:
-
- 1 edited
-
frontend/src/pages/billing/BillingList.js (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
-
frontend/src/pages/billing/BillingList.js
re1f74f6 r9af201e 89 89 // Refresh the list 90 90 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); 93 93 setBillings(response.data || []); 94 94 } catch (err) { … … 101 101 if (user.role === 'DOCTOR' || user.role === 'LAB_TECHNICIAN') { 102 102 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> 107 107 ); 108 108 } … … 111 111 112 112 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"> 124 163 <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> 136 166 </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> 152 173 </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"> 182 182 <tr> 183 183 <th className="px-6 py-3 text-left text-sm font-semibold">Patient</th> … … 187 187 <th className="px-6 py-3 text-left text-sm font-semibold">Actions</th> 188 188 </tr> 189 </thead>190 <tbody>189 </thead> 190 <tbody> 191 191 {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"> 196 196 <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' 200 200 }`}> 201 201 {billing.paymentStatus} 202 202 </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 View208 </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> 211 211 ))} 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 )} 221 220 </div> 221 </div> 222 222 ); 223 223 }
Note:
See TracChangeset
for help on using the changeset viewer.
