Changeset b63d7b5 for frontend/src/pages/billing/BillingList.js
- Timestamp:
- 05/29/26 22:52:04 (4 months ago)
- Branches:
- master
- Children:
- 20d16ca
- Parents:
- 6c00695
- File:
-
- 1 edited
-
frontend/src/pages/billing/BillingList.js (modified) (5 diffs)
Legend:
- Unmodified
- Added
- Removed
-
frontend/src/pages/billing/BillingList.js
r6c00695 rb63d7b5 2 2 import { Link, useSearchParams } from 'react-router-dom'; 3 3 import { billingService } from '../../services/billingService'; 4 import { patientService } from '../../services/patientService'; 4 5 import Loading from '../../components/Loading'; 5 6 import ErrorAlert from '../../components/ErrorAlert'; 7 import SuccessAlert from '../../components/SuccessAlert'; 6 8 7 9 function BillingList() { … … 9 11 const [loading, setLoading] = useState(true); 10 12 const [error, setError] = useState(null); 13 const [success, setSuccess] = useState(null); 11 14 const [searchParams] = useSearchParams(); 12 15 const patientId = searchParams.get('patientId'); 13 16 const user = JSON.parse(localStorage.getItem('user') || '{}'); 14 17 15 const fetchBillings = async () => { 18 // Filters 19 const [statusFilter, setStatusFilter] = useState(''); 20 const [patientFilter, setPatientFilter] = useState(''); 21 const [patients, setPatients] = useState([]); 22 23 useEffect(() => { 24 const fetchBillings = async () => { 25 try { 26 setLoading(true); 27 let response; 28 if (patientId) { 29 response = await billingService.getBillingHistoryForPatient(patientId); 30 } else if (user.role === 'PATIENT') { 31 response = await billingService.getBillingHistoryForPatient(user.patientId); 32 } else { 33 response = await billingService.getAllBillings(); 34 } 35 setBillings(response.data || []); 36 } catch (err) { 37 setError('Failed to fetch billing records'); 38 console.error(err); 39 } finally { 40 setLoading(false); 41 } 42 }; 43 44 fetchBillings(); 45 }, [patientId, user.role, user.patientId]); 46 47 // Load patients for filter dropdown (for billing admin) 48 useEffect(() => { 49 if (user.role === 'BILLING_ADMIN') { 50 const loadPatients = async () => { 51 try { 52 const response = await patientService.getAllPatients(); 53 setPatients(response.data || []); 54 } catch (err) { 55 console.error('Failed to load patients:', err); 56 } 57 }; 58 loadPatients(); 59 } 60 }, [user.role]); 61 62 // Filter billings based on selected filters 63 const filteredBillings = billings.filter(billing => { 64 if (statusFilter && billing.paymentStatus !== statusFilter) { 65 return false; 66 } 67 if (patientFilter && billing.patientName !== patientFilter) { 68 return false; 69 } 70 return true; 71 }); 72 73 const pendingBillings = billings.filter(b => b.paymentStatus === 'PENDING'); 74 75 const handleUpdateStatus = async (billId, newStatus) => { 16 76 try { 17 setLoading(true); 18 let response; 19 if (patientId) { 20 response = await billingService.getBillingHistoryForPatient(patientId); 21 } else if (user.role === 'PATIENT') { 22 response = await billingService.getBillingHistoryForPatient(user.patientId); 23 } else { 24 response = await billingService.getAllBillings(); 77 const updateData = { 78 paymentStatus: newStatus 79 }; 80 if (newStatus === 'PAID') { 81 updateData.paymentDate = new Date().toISOString().split('T')[0]; 25 82 } 26 setBillings(response.data); 83 84 console.log('Updating billing status:', { billId, updateData }); 85 await billingService.updatePaymentStatus(billId, updateData); 86 setSuccess(`Billing status updated to ${newStatus}`); 87 88 // Refresh the list 89 const response = user.role === 'BILLING_ADMIN' 90 ? await billingService.getAllBillings() 91 : await billingService.getBillingHistoryForPatient(patientId || user.patientId); 92 setBillings(response.data || []); 27 93 } catch (err) { 28 setError('Failed to fetch billing records'); 29 console.error(err); 30 } finally { 31 setLoading(false); 94 setError(`Failed to update billing status: ${err.response?.data?.error || err.message}`); 95 console.error('Update status error:', err); 32 96 } 33 97 }; 34 35 useEffect(() => {36 fetchBillings();37 }, [patientId]);38 98 39 99 // Prevent unauthorized access to billing … … 54 114 55 115 {error && <ErrorAlert message={error} onClose={() => setError(null)} />} 116 {success && <SuccessAlert message={success} onClose={() => setSuccess(null)} />} 117 118 {/* Filters for Billing Admin */} 119 {user.role === 'BILLING_ADMIN' && ( 120 <div className="bg-white rounded-lg shadow p-6 mb-6"> 121 <h2 className="text-lg font-bold mb-4">Filters</h2> 122 <div className="grid grid-cols-1 md:grid-cols-2 gap-4"> 123 <div> 124 <label className="block text-sm font-semibold mb-2">Status</label> 125 <select 126 value={statusFilter} 127 onChange={(e) => setStatusFilter(e.target.value)} 128 className="w-full px-4 py-2 border rounded-lg" 129 > 130 <option value="">All Statuses</option> 131 <option value="PENDING">Pending</option> 132 <option value="PAID">Paid</option> 133 <option value="PROCESSING">Processing</option> 134 </select> 135 </div> 136 <div> 137 <label className="block text-sm font-semibold mb-2">Patient</label> 138 <select 139 value={patientFilter} 140 onChange={(e) => setPatientFilter(e.target.value)} 141 className="w-full px-4 py-2 border rounded-lg" 142 > 143 <option value="">All Patients</option> 144 {patients.map(p => ( 145 <option key={p.patientId} value={`${p.firstName} ${p.lastName}`}> 146 {p.firstName} {p.lastName} 147 </option> 148 ))} 149 </select> 150 </div> 151 </div> 152 </div> 153 )} 154 155 {/* Pending Billing Records Section (for Billing Admin) */} 156 {user.role === 'BILLING_ADMIN' && pendingBillings.length > 0 && ( 157 <div className="bg-yellow-50 rounded-lg shadow p-6 mb-6 border-l-4 border-yellow-500"> 158 <h2 className="text-lg font-bold mb-4">Pending Billing Records ({pendingBillings.length})</h2> 159 <div className="space-y-3"> 160 {pendingBillings.map(billing => ( 161 <div key={billing.billId} className="bg-white rounded p-4 flex justify-between items-center"> 162 <div> 163 <p className="font-semibold">{billing.patientName}</p> 164 <p className="text-sm text-gray-600">${billing.totalCost}</p> 165 </div> 166 <button 167 onClick={() => handleUpdateStatus(billing.billId, 'PAID')} 168 className="px-4 py-2 bg-green-500 text-white rounded hover:bg-green-600 text-sm" 169 > 170 Mark Paid 171 </button> 172 </div> 173 ))} 174 </div> 175 </div> 176 )} 56 177 57 178 <div className="bg-white rounded-lg shadow overflow-hidden"> … … 67 188 </thead> 68 189 <tbody> 69 { billings.map(billing => (190 {filteredBillings.map(billing => ( 70 191 <tr key={billing.billId} className="border-t hover:bg-gray-50"> 71 192 <td className="px-6 py-3">{billing.patientName}</td> … … 90 211 </tbody> 91 212 </table> 213 214 {filteredBillings.length === 0 && ( 215 <div className="p-6 text-center text-gray-500"> 216 {billings.length === 0 ? 'No billing records found' : 'No records match the selected filters'} 217 </div> 218 )} 92 219 </div> 93 220 </div>
Note:
See TracChangeset
for help on using the changeset viewer.
