source: frontend/src/pages/lab-tests/LabTestList.js

Last change on this file was 9af201e, checked in by MBK <marija.karapandzova@…>, 11 days ago

Fix frontend appearance

  • Property mode set to 100644
File size: 30.0 KB
Line 
1import React, { useState, useEffect } from 'react';
2import { patientService } from '../../services/patientService';
3import { labService } from '../../services/labService';
4import ErrorAlert from '../../components/ErrorAlert';
5
6function LabTestList() {
7 const [user, setUser] = useState({});
8 const isLabTechnician = user.role === 'LAB_TECHNICIAN';
9
10 const [patient, setPatient] = useState(null);
11 const [embg, setEmbg] = useState('');
12 const [searched, setSearched] = useState(false);
13 const [loading, setLoading] = useState(false);
14 const [error, setError] = useState(null);
15
16 const [availableTests, setAvailableTests] = useState([]);
17 const [labTestRequests, setLabTestRequests] = useState([]);
18 const [labResults, setLabResults] = useState([]);
19 const [pendingTests, setPendingTests] = useState([]);
20 const [submittedTests, setSubmittedTests] = useState([]);
21 const [selectedTest, setSelectedTest] = useState(null);
22
23 const [showRequestForm, setShowRequestForm] = useState(false);
24 const [requestData, setRequestData] = useState({
25 testId: '',
26 testDate: new Date().toISOString().split('T')[0],
27 notes: '',
28 });
29
30 const [submitFormData, setSubmitFormData] = useState({
31 results: '',
32 resultDate: new Date().toISOString().split('T')[0],
33 });
34
35 // Filter states for pending tests
36 const [pendingFilters, setPendingFilters] = useState({
37 testName: '',
38 patientName: '',
39 testDate: '',
40 });
41
42 // Filter states for submitted tests
43 const [submittedFilters, setSubmittedFilters] = useState({
44 testName: '',
45 patientName: '',
46 testDate: '',
47 });
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 }, []);
83
84 useEffect(() => {
85 if (isLabTechnician) {
86 loadLabTestsData();
87 }
88 }, [isLabTechnician]);
89
90 const loadLabTestsData = async () => {
91 try {
92 setLoading(true);
93 setError(null);
94
95 // Load pending tests
96 const pendingRes = await labService.getPendingLabTests();
97 setPendingTests(pendingRes.data || []);
98
99 // Try to load submitted tests, but don't fail if this endpoint doesn't exist
100 try {
101 const submittedRes = await labService.getAllSubmittedLabResults();
102 setSubmittedTests(submittedRes.data || []);
103 } catch (err) {
104 console.warn('Could not load submitted tests:', err);
105 setSubmittedTests([]);
106 }
107 } catch (err) {
108 setError('Failed to load pending lab tests');
109 setPendingTests([]);
110 } finally {
111 setLoading(false);
112 }
113 };
114
115 const handleSearch = async (e) => {
116 e.preventDefault();
117 setError(null);
118 setLoading(true);
119
120 try {
121 if (!embg.trim()) {
122 setError('Please enter an EMBG');
123 setLoading(false);
124 return;
125 }
126
127 const patientResponse = await patientService.getPatientByEmbg(embg);
128 setPatient(patientResponse.data);
129 setSearched(true);
130
131 // Fetch available tests
132 const testsResponse = await labService.getAllLabTests();
133 setAvailableTests(testsResponse.data);
134
135 // Fetch medical record for patient
136 const { medicalRecordService } = await import('../../services/medicalRecordService');
137 const medicalRecordRes = await medicalRecordService.getMedicalRecordByPatientId(patientResponse.data.patientId);
138
139 // Fetch existing test requests for patient
140 const requestsResponse = await labService.getLabTestRequestsForPatient(patientResponse.data.patientId);
141 setLabTestRequests(requestsResponse.data);
142
143 // Fetch lab results for medical record
144 const resultsResponse = await labService.getLabResultsForMedicalRecord(medicalRecordRes.data.recordId);
145 setLabResults(resultsResponse.data);
146 } catch (err) {
147 setError(`Patient with EMBG ${embg} not found`);
148 setPatient(null);
149 } finally {
150 setLoading(false);
151 }
152 };
153
154 const handleRequestTest = async (e) => {
155 e.preventDefault();
156 setError(null);
157
158 if (!requestData.testId) {
159 setError('Please select a test');
160 return;
161 }
162
163 if (!patient) {
164 setError('Patient not found');
165 return;
166 }
167
168 try {
169 setLoading(true);
170
171 // Get doctor ID from logged-in user
172 const doctorId = user.doctorId;
173
174 const request = {
175 patientId: patient.patientId,
176 medicalRecordId: patient.patientId, // Assuming medical record ID matches patient ID
177 doctorId: parseInt(doctorId),
178 testId: parseInt(requestData.testId),
179 testDate: requestData.testDate,
180 notes: requestData.notes,
181 };
182
183 console.log('User object:', user);
184 console.log('Sending lab test request with doctorId:', doctorId, 'Full request:', request);
185
186 await labService.requestLabTest(request);
187
188 // Refresh the test requests
189 const requestsResponse = await labService.getLabTestRequestsForPatient(patient.patientId);
190 setLabTestRequests(requestsResponse.data);
191
192 // Reset form
193 setRequestData({
194 testId: '',
195 testDate: new Date().toISOString().split('T')[0],
196 notes: '',
197 });
198 setShowRequestForm(false);
199 setError(null);
200 } catch (err) {
201 setError('Failed to request lab test: ' + err.response?.data?.error || err.message);
202 } finally {
203 setLoading(false);
204 }
205 };
206
207 const handleSubmitResult = async (e) => {
208 e.preventDefault();
209 setError(null);
210
211 if (!submitFormData.results.trim()) {
212 setError('Please enter test results');
213 return;
214 }
215
216 if (!selectedTest) {
217 setError('No test selected');
218 return;
219 }
220
221 try {
222 setLoading(true);
223
224 const { medicalRecordService } = await import('../../services/medicalRecordService');
225 const medicalRecordRes = await medicalRecordService.getMedicalRecordByPatientId(selectedTest.patientId);
226
227 const resultData = {
228 medicalRecordId: medicalRecordRes.data.recordId,
229 testId: selectedTest.testId,
230 results: submitFormData.results,
231 resultDate: submitFormData.resultDate,
232 };
233
234 await labService.submitLabResult(resultData);
235
236 // Refresh pending tests
237 await loadLabTestsData();
238
239 // Reset form
240 setSelectedTest(null);
241 setSubmitFormData({
242 results: '',
243 resultDate: new Date().toISOString().split('T')[0],
244 });
245
246 // Show success message
247 setError(null);
248 alert('Lab result submitted successfully!');
249
250 // Refresh the lab tests data
251 await loadLabTestsData();
252
253 // Reset form
254 setSelectedTest(null);
255 setSubmitFormData({
256 results: '',
257 resultDate: new Date().toISOString().split('T')[0],
258 });
259 } catch (err) {
260 setError('Failed to submit lab result: ' + (err.response?.data?.error || err.message));
261 } finally {
262 setLoading(false);
263 }
264 };
265
266 if (isLabTechnician) {
267 return (
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>
397 </div>
398
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>
507 </div>
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>
514 </div>
515
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">
547 <span className="px-3 py-1 bg-green-100 text-green-800 rounded-full text-sm font-semibold">
548 Submitted
549 </span>
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>
747 )}
748 </div>
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>
755 </div>
756 )}
757 </div>
758 );
759}
760
761export default LabTestList;
Note: See TracBrowser for help on using the repository browser.