source: frontend/src/pages/lab-tests/LabResultForm.js@ 84249b1

Last change on this file since 84249b1 was f05de05, checked in by MBK <marija.karapandzova@…>, 4 months ago

Add pages and routing for lab tests, procedures and billing with api services

  • Property mode set to 100644
File size: 10.4 KB
Line 
1import React, { useState, useEffect } from 'react';
2import { useNavigate } from 'react-router-dom';
3import { labService } from '../../services/labService';
4import { patientService } from '../../services/patientService';
5import { medicalRecordService } from '../../services/medicalRecordService';
6import ErrorAlert from '../../components/ErrorAlert';
7import SuccessAlert from '../../components/SuccessAlert';
8
9function LabResultForm() {
10 const navigate = useNavigate();
11 const [error, setError] = useState(null);
12 const [success, setSuccess] = useState(null);
13 const [loading, setLoading] = useState(false);
14 const [searchEmbg, setSearchEmbg] = useState('');
15 const [patient, setPatient] = useState(null);
16 const [pendingTests, setPendingTests] = useState([]);
17 const [selectedTest, setSelectedTest] = useState(null);
18 const [medicalRecordId, setMedicalRecordId] = useState(null);
19
20 const [formData, setFormData] = useState({
21 medicalRecordId: '',
22 testId: '',
23 results: '',
24 resultDate: new Date().toISOString().split('T')[0],
25 });
26
27 const handleSearch = async (e) => {
28 e.preventDefault();
29 setError(null);
30 setLoading(true);
31
32 try {
33 if (!searchEmbg.trim()) {
34 setError('Please enter patient EMBG');
35 setLoading(false);
36 return;
37 }
38
39 const patientRes = await patientService.getPatientByEmbg(searchEmbg);
40 setPatient(patientRes.data);
41
42 // Get medical record
43 const medicalRecordRes = await medicalRecordService.getMedicalRecordByPatientId(patientRes.data.patientId);
44 setMedicalRecordId(medicalRecordRes.data.recordId);
45
46 // Get pending tests
47 const testsRes = await labService.getLabTestRequestsForPatient(patientRes.data.patientId);
48 setPendingTests(testsRes.data || []);
49
50 setFormData(prev => ({
51 ...prev,
52 medicalRecordId: medicalRecordRes.data.recordId
53 }));
54 } catch (err) {
55 setError('Patient not found or error loading tests');
56 setPatient(null);
57 setPendingTests([]);
58 } finally {
59 setLoading(false);
60 }
61 };
62
63 const handleSelectTest = (test) => {
64 setSelectedTest(test);
65 setFormData(prev => ({
66 ...prev,
67 testId: test.testId,
68 medicalRecordId: medicalRecordId || prev.medicalRecordId
69 }));
70 };
71
72 const handleChange = (e) => {
73 const { name, value } = e.target;
74 setFormData({
75 ...formData,
76 [name]: value,
77 });
78 };
79
80 const handleSubmit = async (e) => {
81 e.preventDefault();
82 setError(null);
83 setSuccess(null);
84
85 if (!formData.medicalRecordId || !formData.testId || !formData.results) {
86 setError('Please fill in all required fields');
87 return;
88 }
89
90 try {
91 setLoading(true);
92
93 const submitData = {
94 medicalRecordId: parseInt(formData.medicalRecordId),
95 testId: parseInt(formData.testId),
96 results: formData.results,
97 resultDate: formData.resultDate,
98 };
99
100 await labService.submitLabResult(submitData);
101
102 setSuccess('Lab result submitted successfully!');
103 setFormData({
104 medicalRecordId: '',
105 testId: '',
106 results: '',
107 resultDate: new Date().toISOString().split('T')[0],
108 });
109 setSelectedTest(null);
110 setPatient(null);
111 setSearchEmbg('');
112 setPendingTests([]);
113
114 // Navigate back to lab tests page after a short delay
115 setTimeout(() => navigate('/lab-tests'), 2000);
116 } catch (err) {
117 setError('Failed to submit lab result: ' + (err.response?.data?.error || err.message));
118 setLoading(false);
119 }
120 };
121
122 return (
123 <div className="max-w-3xl mx-auto">
124 <h1 className="text-3xl font-bold mb-6">Submit Lab Result</h1>
125
126 {error && <ErrorAlert message={error} onClose={() => setError(null)} />}
127 {success && <SuccessAlert message={success} onClose={() => setSuccess(null)} />}
128
129 {/* Search Patient Form */}
130 <div className="bg-white rounded-lg shadow p-6 mb-6">
131 <h2 className="text-xl font-bold mb-4">Search Patient</h2>
132 <form onSubmit={handleSearch} className="flex gap-4">
133 <input
134 type="text"
135 value={searchEmbg}
136 onChange={(e) => setSearchEmbg(e.target.value)}
137 placeholder="Enter patient EMBG"
138 className="flex-1 px-4 py-2 border rounded-lg"
139 />
140 <button
141 type="submit"
142 disabled={loading}
143 className="bg-purple-600 text-white px-8 py-2 rounded hover:bg-purple-700 disabled:bg-gray-400"
144 >
145 {loading ? 'Searching...' : 'Search'}
146 </button>
147 </form>
148 </div>
149
150 {/* Patient Info and Pending Tests */}
151 {patient && (
152 <div className="space-y-6">
153 {/* Patient Card */}
154 <div className="bg-white rounded-lg shadow p-6">
155 <h2 className="text-2xl font-bold mb-4">{patient.firstName} {patient.lastName}</h2>
156 <div className="grid grid-cols-3 gap-4">
157 <div>
158 <p className="text-sm text-gray-600">EMBG</p>
159 <p className="font-semibold">{patient.embg}</p>
160 </div>
161 <div>
162 <p className="text-sm text-gray-600">Blood Type</p>
163 <p className="font-semibold">{patient.bloodType || 'N/A'}</p>
164 </div>
165 <div>
166 <p className="text-sm text-gray-600">Date of Birth</p>
167 <p className="font-semibold">{patient.dateOfBirth}</p>
168 </div>
169 </div>
170 </div>
171
172 {/* Pending Tests List */}
173 {pendingTests.length > 0 ? (
174 <div className="bg-white rounded-lg shadow p-6">
175 <h2 className="text-xl font-bold mb-4">Pending Lab Tests</h2>
176 <div className="space-y-2">
177 {pendingTests.map((test) => (
178 <div
179 key={test.testId}
180 onClick={() => handleSelectTest(test)}
181 className={`p-4 rounded-lg border-2 cursor-pointer transition ${
182 selectedTest?.testId === test.testId
183 ? 'border-purple-600 bg-blue-50'
184 : 'border-gray-200 bg-gray-50 hover:border-blue-400'
185 }`}
186 >
187 <p className="font-semibold text-lg">{test.testName}</p>
188 <p className="text-sm text-gray-600">Requested by: {test.doctorName}</p>
189 <p className="text-sm text-gray-600">Request Date: {test.requestDate}</p>
190 {test.notes && (
191 <p className="text-sm text-gray-600 mt-1">Notes: {test.notes}</p>
192 )}
193 </div>
194 ))}
195 </div>
196 </div>
197 ) : (
198 <div className="bg-blue-50 rounded-lg p-6 text-center">
199 <p className="text-gray-600">No pending lab tests for this patient</p>
200 </div>
201 )}
202
203 {/* Result Submission Form */}
204 {selectedTest && (
205 <div className="bg-white rounded-lg shadow p-6">
206 <h2 className="text-xl font-bold mb-4">Submit Results for {selectedTest.testName}</h2>
207 <form onSubmit={handleSubmit} className="space-y-4">
208 <div className="grid grid-cols-2 gap-4">
209 <div>
210 <label className="block text-sm font-semibold mb-2">Test ID</label>
211 <input
212 type="number"
213 value={formData.testId}
214 disabled
215 className="w-full px-4 py-2 border rounded-lg bg-gray-100"
216 />
217 </div>
218 <div>
219 <label className="block text-sm font-semibold mb-2">Medical Record ID</label>
220 <input
221 type="number"
222 value={formData.medicalRecordId}
223 disabled
224 className="w-full px-4 py-2 border rounded-lg bg-gray-100"
225 />
226 </div>
227 </div>
228
229 <div>
230 <label className="block text-sm font-semibold mb-2">Results *</label>
231 <textarea
232 name="results"
233 value={formData.results}
234 onChange={handleChange}
235 placeholder="Enter the lab test results"
236 className="w-full px-4 py-2 border rounded-lg"
237 rows="6"
238 required
239 />
240 </div>
241
242 <div>
243 <label className="block text-sm font-semibold mb-2">Result Date</label>
244 <input
245 type="date"
246 name="resultDate"
247 value={formData.resultDate}
248 onChange={handleChange}
249 className="w-full px-4 py-2 border rounded-lg"
250 />
251 </div>
252
253 <div className="flex gap-4 pt-6">
254 <button
255 type="submit"
256 disabled={loading}
257 style={{
258 flex: 1,
259 background: loading ? '#d1d5db' : '#bfdbfe',
260 color: '#1e1035',
261 padding: '8px 12px',
262 borderRadius: '6px',
263 border: 'none',
264 cursor: loading ? 'not-allowed' : 'pointer',
265 fontWeight: '400',
266 fontSize: '13px'
267 }}
268 onMouseEnter={(e) => !loading && (e.currentTarget.style.background = '#93c5fd')}
269 onMouseLeave={(e) => !loading && (e.currentTarget.style.background = '#bfdbfe')}
270 >
271 {loading ? 'Submitting...' : 'Submit Result'}
272 </button>
273 <button
274 type="button"
275 onClick={() => navigate('/lab-tests')}
276 className="flex-1 bg-gray-400 text-white py-2 rounded-lg hover:bg-gray-500"
277 >
278 Cancel
279 </button>
280 </div>
281 </form>
282 </div>
283 )}
284 </div>
285 )}
286
287 {/* No search performed */}
288 {!patient && (
289 <div className="bg-gray-50 rounded-lg p-12 text-center">
290 <p className="text-gray-600 text-lg">Enter a patient EMBG to view pending lab tests</p>
291 </div>
292 )}
293 </div>
294 );
295}
296
297export default LabResultForm;
Note: See TracBrowser for help on using the repository browser.