@sasindi/radiologytestscheduling 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/540.css +1 -1
- package/dist/540.css.map +1 -1
- package/dist/647.js +1 -1
- package/dist/647.js.map +1 -1
- package/dist/974.css +1 -1
- package/dist/974.css.map +1 -1
- package/dist/openmrs-esm-radiologytestscheduling.js +1 -1
- package/dist/routes.json +1 -1
- package/package.json +1 -1
- package/src/radiology-test-scheduling.component.tsx +403 -567
- package/src/radiology-test-scheduling.resource.ts +34 -16
- package/src/radiology-test-scheduling.scss +154 -236
|
@@ -7,10 +7,10 @@ import {
|
|
|
7
7
|
fetchInstitutes,
|
|
8
8
|
fetchPendingSchedulingOrders,
|
|
9
9
|
fetchPatientDetails,
|
|
10
|
+
fetchPatientBasicInfo,
|
|
10
11
|
fetchLocationDisplay,
|
|
11
12
|
fetchUserDisplay,
|
|
12
13
|
fetchExamRooms,
|
|
13
|
-
fetchCalendarData,
|
|
14
14
|
saveScheduling,
|
|
15
15
|
SessionInfo,
|
|
16
16
|
} from './radiology-test-scheduling.resource';
|
|
@@ -19,7 +19,6 @@ import {
|
|
|
19
19
|
PatientDemographics,
|
|
20
20
|
InstituteOption,
|
|
21
21
|
ExamRoom,
|
|
22
|
-
RadiologyOrder,
|
|
23
22
|
} from './types';
|
|
24
23
|
import styles from './radiology-test-scheduling.scss';
|
|
25
24
|
|
|
@@ -49,18 +48,13 @@ const RadiologyTestScheduling: React.FC = () => {
|
|
|
49
48
|
const [patientDetails, setPatientDetails] = useState<PatientDemographics | null>(null);
|
|
50
49
|
const [loadingPatient, setLoadingPatient] = useState<boolean>(false);
|
|
51
50
|
|
|
52
|
-
// Scheduling inputs
|
|
51
|
+
// Scheduling Form inputs: Scheduled Date Time, Remarks, Modality, Exam Room
|
|
53
52
|
const [scheduledDateTime, setScheduledDateTime] = useState<string>('');
|
|
54
53
|
const [remarks, setRemarks] = useState<string>('');
|
|
55
|
-
const [isSaving, setIsSaving] = useState<boolean>(false);
|
|
56
|
-
|
|
57
|
-
// Calendar filter states
|
|
58
54
|
const [selectedModality, setSelectedModality] = useState<string>('all');
|
|
59
55
|
const [examRooms, setExamRooms] = useState<ExamRoom[]>([]);
|
|
60
56
|
const [selectedExamRoom, setSelectedExamRoom] = useState<string>('all');
|
|
61
|
-
const [
|
|
62
|
-
const [calendarDate, setCalendarDate] = useState<Date>(new Date());
|
|
63
|
-
const [loadingCalendar, setLoadingCalendar] = useState<boolean>(false);
|
|
57
|
+
const [isSaving, setIsSaving] = useState<boolean>(false);
|
|
64
58
|
|
|
65
59
|
// Initialize Session and Institutes
|
|
66
60
|
useEffect(() => {
|
|
@@ -91,17 +85,25 @@ const RadiologyTestScheduling: React.FC = () => {
|
|
|
91
85
|
setLoadingOrders(true);
|
|
92
86
|
try {
|
|
93
87
|
const orders = await fetchPendingSchedulingOrders(instUuid);
|
|
94
|
-
|
|
88
|
+
|
|
89
|
+
// Enhance with location, clinician, and patient basic demographics
|
|
95
90
|
const enhanced = await Promise.all(
|
|
96
91
|
orders.map(async (dto) => {
|
|
97
92
|
const loc = dto.radiology.location ? await fetchLocationDisplay(dto.radiology.location) : '';
|
|
98
93
|
const ordBy = dto.radiology.requesterReference
|
|
99
94
|
? await fetchUserDisplay(dto.radiology.requesterReference)
|
|
100
95
|
: '';
|
|
96
|
+
const patientInfo = dto.radiology.patientPhn
|
|
97
|
+
? await fetchPatientBasicInfo(dto.radiology.patientPhn)
|
|
98
|
+
: { name: '', gender: '', age: '' };
|
|
99
|
+
|
|
101
100
|
return {
|
|
102
101
|
...dto,
|
|
103
102
|
locationName: loc,
|
|
104
103
|
orderedByName: ordBy,
|
|
104
|
+
patientName: patientInfo.name,
|
|
105
|
+
patientGender: patientInfo.gender,
|
|
106
|
+
patientAge: patientInfo.age,
|
|
105
107
|
};
|
|
106
108
|
}),
|
|
107
109
|
);
|
|
@@ -112,6 +114,7 @@ const RadiologyTestScheduling: React.FC = () => {
|
|
|
112
114
|
icon: 'error',
|
|
113
115
|
title: 'Error Loading Orders',
|
|
114
116
|
text: 'Unable to fetch pending radiology test orders.',
|
|
117
|
+
confirmButtonColor: '#da1e28',
|
|
115
118
|
});
|
|
116
119
|
} finally {
|
|
117
120
|
setLoadingOrders(false);
|
|
@@ -124,34 +127,16 @@ const RadiologyTestScheduling: React.FC = () => {
|
|
|
124
127
|
|
|
125
128
|
// Load Exam Rooms when modality changes
|
|
126
129
|
useEffect(() => {
|
|
127
|
-
(
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
130
|
+
if (selectedModality === 'all' || !selectedModality) {
|
|
131
|
+
setExamRooms([]);
|
|
132
|
+
setSelectedExamRoom('all');
|
|
133
|
+
} else {
|
|
134
|
+
(async () => {
|
|
132
135
|
const rooms = await fetchExamRooms(selectedModality);
|
|
133
136
|
setExamRooms(rooms);
|
|
134
|
-
|
|
135
|
-
}
|
|
136
|
-
})();
|
|
137
|
-
}, [selectedModality]);
|
|
138
|
-
|
|
139
|
-
// Load Calendar Data
|
|
140
|
-
const loadCalendar = useCallback(async () => {
|
|
141
|
-
setLoadingCalendar(true);
|
|
142
|
-
try {
|
|
143
|
-
const data = await fetchCalendarData(selectedModality, selectedExamRoom, selectedInstitute);
|
|
144
|
-
setCalendarOrders(data);
|
|
145
|
-
} catch (err) {
|
|
146
|
-
console.error('Failed to load calendar data', err);
|
|
147
|
-
} finally {
|
|
148
|
-
setLoadingCalendar(false);
|
|
137
|
+
})();
|
|
149
138
|
}
|
|
150
|
-
}, [selectedModality
|
|
151
|
-
|
|
152
|
-
useEffect(() => {
|
|
153
|
-
loadCalendar();
|
|
154
|
-
}, [loadCalendar]);
|
|
139
|
+
}, [selectedModality]);
|
|
155
140
|
|
|
156
141
|
// Handle row selection
|
|
157
142
|
const handleSelectRow = async (dto: SchedulingOrderDTO) => {
|
|
@@ -160,6 +145,28 @@ const RadiologyTestScheduling: React.FC = () => {
|
|
|
160
145
|
setRemarks('');
|
|
161
146
|
setLoadingPatient(true);
|
|
162
147
|
|
|
148
|
+
// Auto-populate Modality and Exam Room from selected test order if available
|
|
149
|
+
const modality = dto.radiology.categoryDisplay || 'all';
|
|
150
|
+
setSelectedModality(modality);
|
|
151
|
+
|
|
152
|
+
if (modality && modality !== 'all') {
|
|
153
|
+
try {
|
|
154
|
+
const rooms = await fetchExamRooms(modality);
|
|
155
|
+
setExamRooms(rooms);
|
|
156
|
+
const roomName = dto.radiology.supportingInfo;
|
|
157
|
+
if (roomName && roomName !== '--Select--') {
|
|
158
|
+
setSelectedExamRoom(roomName);
|
|
159
|
+
} else {
|
|
160
|
+
setSelectedExamRoom('all');
|
|
161
|
+
}
|
|
162
|
+
} catch (e) {
|
|
163
|
+
console.warn('Failed to load exam rooms on select', e);
|
|
164
|
+
}
|
|
165
|
+
} else {
|
|
166
|
+
setSelectedExamRoom('all');
|
|
167
|
+
setExamRooms([]);
|
|
168
|
+
}
|
|
169
|
+
|
|
163
170
|
try {
|
|
164
171
|
const details = await fetchPatientDetails(dto.radiology.patientPhn);
|
|
165
172
|
setPatientDetails(details);
|
|
@@ -176,6 +183,9 @@ const RadiologyTestScheduling: React.FC = () => {
|
|
|
176
183
|
setPatientDetails(null);
|
|
177
184
|
setScheduledDateTime('');
|
|
178
185
|
setRemarks('');
|
|
186
|
+
setSelectedModality('all');
|
|
187
|
+
setSelectedExamRoom('all');
|
|
188
|
+
setExamRooms([]);
|
|
179
189
|
};
|
|
180
190
|
|
|
181
191
|
// Save Schedule Handler
|
|
@@ -201,7 +211,7 @@ const RadiologyTestScheduling: React.FC = () => {
|
|
|
201
211
|
}
|
|
202
212
|
|
|
203
213
|
// Format datetime string: "YYYY-MM-DD HH:mm:ss"
|
|
204
|
-
const formattedDateTime = scheduledDateTime.replace('T', ' ') + ':00';
|
|
214
|
+
const formattedDateTime = scheduledDateTime.replace('T', ' ') + (scheduledDateTime.length === 16 ? ':00' : '');
|
|
205
215
|
|
|
206
216
|
const result = await Swal.fire({
|
|
207
217
|
title: 'Confirm Scheduling',
|
|
@@ -237,7 +247,6 @@ const RadiologyTestScheduling: React.FC = () => {
|
|
|
237
247
|
|
|
238
248
|
handleClear();
|
|
239
249
|
loadPendingOrders(selectedInstitute);
|
|
240
|
-
loadCalendar();
|
|
241
250
|
} catch (err: any) {
|
|
242
251
|
console.error('Failed to save schedule', err);
|
|
243
252
|
Swal.fire({
|
|
@@ -257,12 +266,14 @@ const RadiologyTestScheduling: React.FC = () => {
|
|
|
257
266
|
const term = searchTerm.toLowerCase();
|
|
258
267
|
return pendingOrders.filter((dto) => {
|
|
259
268
|
const phn = dto.radiology.patientPhn?.toLowerCase() || '';
|
|
269
|
+
const name = dto.patientName?.toLowerCase() || '';
|
|
260
270
|
const test = dto.radiology.codeDisplay?.toLowerCase() || '';
|
|
261
271
|
const section = dto.type?.toLowerCase() || '';
|
|
262
272
|
const priority = dto.radiology.priority?.toLowerCase() || '';
|
|
263
273
|
const location = dto.locationName?.toLowerCase() || '';
|
|
264
274
|
return (
|
|
265
275
|
phn.includes(term) ||
|
|
276
|
+
name.includes(term) ||
|
|
266
277
|
test.includes(term) ||
|
|
267
278
|
section.includes(term) ||
|
|
268
279
|
priority.includes(term) ||
|
|
@@ -271,109 +282,6 @@ const RadiologyTestScheduling: React.FC = () => {
|
|
|
271
282
|
});
|
|
272
283
|
}, [pendingOrders, searchTerm]);
|
|
273
284
|
|
|
274
|
-
// Calendar grouping helper
|
|
275
|
-
const calendarDays = useMemo(() => {
|
|
276
|
-
const year = calendarDate.getFullYear();
|
|
277
|
-
const month = calendarDate.getMonth();
|
|
278
|
-
const firstDayIndex = new Date(year, month, 1).getDay();
|
|
279
|
-
const totalDays = new Date(year, month + 1, 0).getDate();
|
|
280
|
-
const prevMonthDays = new Date(year, month, 0).getDate();
|
|
281
|
-
|
|
282
|
-
// Map scheduled tests by date string "YYYY-MM-DD"
|
|
283
|
-
const dateMap = new Map<string, RadiologyOrder[]>();
|
|
284
|
-
for (const ord of calendarOrders) {
|
|
285
|
-
if (ord.scheduledDateTime) {
|
|
286
|
-
const dStr = ord.scheduledDateTime.split(' ')[0];
|
|
287
|
-
if (!dateMap.has(dStr)) {
|
|
288
|
-
dateMap.set(dStr, []);
|
|
289
|
-
}
|
|
290
|
-
dateMap.get(dStr)!.push(ord);
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
const cells = [];
|
|
295
|
-
|
|
296
|
-
// Previous month filler days
|
|
297
|
-
for (let i = firstDayIndex - 1; i >= 0; i--) {
|
|
298
|
-
const dayNum = prevMonthDays - i;
|
|
299
|
-
cells.push({
|
|
300
|
-
dayNum,
|
|
301
|
-
isCurrentMonth: false,
|
|
302
|
-
dateStr: '',
|
|
303
|
-
orders: [],
|
|
304
|
-
});
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
// Current month days
|
|
308
|
-
const todayStr = new Date().toISOString().split('T')[0];
|
|
309
|
-
for (let day = 1; day <= totalDays; day++) {
|
|
310
|
-
const monthStr = String(month + 1).padStart(2, '0');
|
|
311
|
-
const dayStr = String(day).padStart(2, '0');
|
|
312
|
-
const dateStr = `${year}-${monthStr}-${dayStr}`;
|
|
313
|
-
cells.push({
|
|
314
|
-
dayNum: day,
|
|
315
|
-
isCurrentMonth: true,
|
|
316
|
-
isToday: dateStr === todayStr,
|
|
317
|
-
dateStr,
|
|
318
|
-
orders: dateMap.get(dateStr) || [],
|
|
319
|
-
});
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
// Next month filler days to complete grid (multiples of 7)
|
|
323
|
-
const remaining = 7 - (cells.length % 7);
|
|
324
|
-
if (remaining < 7) {
|
|
325
|
-
for (let i = 1; i <= remaining; i++) {
|
|
326
|
-
cells.push({
|
|
327
|
-
dayNum: i,
|
|
328
|
-
isCurrentMonth: false,
|
|
329
|
-
dateStr: '',
|
|
330
|
-
orders: [],
|
|
331
|
-
});
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
return cells;
|
|
336
|
-
}, [calendarDate, calendarOrders]);
|
|
337
|
-
|
|
338
|
-
// Handle clicking calendar event or day
|
|
339
|
-
const handleCalendarEventClick = (dateStr: string, orders: RadiologyOrder[]) => {
|
|
340
|
-
if (!orders || orders.length === 0) return;
|
|
341
|
-
|
|
342
|
-
// Group orders by modality and exam room
|
|
343
|
-
const breakdown: Record<string, Record<string, number>> = {};
|
|
344
|
-
for (const ord of orders) {
|
|
345
|
-
const mod = ord.categoryDisplay || 'Other';
|
|
346
|
-
const room = ord.supportingInfo || 'Default Room';
|
|
347
|
-
if (!breakdown[mod]) {
|
|
348
|
-
breakdown[mod] = {};
|
|
349
|
-
}
|
|
350
|
-
breakdown[mod][room] = (breakdown[mod][room] || 0) + 1;
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
let html = `<div style="text-align: left; font-size: 0.92rem;">`;
|
|
354
|
-
for (const [mod, rooms] of Object.entries(breakdown)) {
|
|
355
|
-
html += `<div style="margin-bottom: 0.75rem;"><strong style="color: #009384;">${mod}</strong><ul style="margin: 0.25rem 0 0 1.25rem; padding: 0;">`;
|
|
356
|
-
for (const [room, count] of Object.entries(rooms)) {
|
|
357
|
-
html += `<li><strong>${room}:</strong> ${count} scheduled</li>`;
|
|
358
|
-
}
|
|
359
|
-
html += `</ul></div>`;
|
|
360
|
-
}
|
|
361
|
-
html += `</div>`;
|
|
362
|
-
|
|
363
|
-
Swal.fire({
|
|
364
|
-
title: `Scheduled Tests (${dateStr})`,
|
|
365
|
-
html,
|
|
366
|
-
icon: 'info',
|
|
367
|
-
confirmButtonColor: '#0f62fe',
|
|
368
|
-
confirmButtonText: 'Close',
|
|
369
|
-
});
|
|
370
|
-
};
|
|
371
|
-
|
|
372
|
-
const monthNames = [
|
|
373
|
-
'January', 'February', 'March', 'April', 'May', 'June',
|
|
374
|
-
'July', 'August', 'September', 'October', 'November', 'December',
|
|
375
|
-
];
|
|
376
|
-
|
|
377
285
|
return (
|
|
378
286
|
<div className={styles.bodyWrapper}>
|
|
379
287
|
{/* Main Unified Card: Heading inside the form container as required */}
|
|
@@ -384,15 +292,15 @@ const RadiologyTestScheduling: React.FC = () => {
|
|
|
384
292
|
</h2>
|
|
385
293
|
</div>
|
|
386
294
|
|
|
387
|
-
{
|
|
388
|
-
|
|
389
|
-
<div className={styles.
|
|
390
|
-
<div className={
|
|
391
|
-
<
|
|
392
|
-
<span>{t('institute', 'Institute')}</span>
|
|
393
|
-
</label>
|
|
295
|
+
<div className={styles.serviceBox}>
|
|
296
|
+
{/* Top Filter Row: Institute Dropdown & Search Bar */}
|
|
297
|
+
<div className={styles.filterRow}>
|
|
298
|
+
<div className={styles.instituteSelectGroup}>
|
|
299
|
+
<h4 className={styles.instituteLabel}>{t('institute', 'Institute')}</h4>
|
|
394
300
|
<select
|
|
301
|
+
id="drpInstitute"
|
|
395
302
|
className={styles.formControl}
|
|
303
|
+
style={{ width: '260px' }}
|
|
396
304
|
value={selectedInstitute}
|
|
397
305
|
onChange={(e) => setSelectedInstitute(e.target.value)}
|
|
398
306
|
>
|
|
@@ -405,466 +313,394 @@ const RadiologyTestScheduling: React.FC = () => {
|
|
|
405
313
|
</select>
|
|
406
314
|
</div>
|
|
407
315
|
|
|
408
|
-
<div className={
|
|
409
|
-
<label className={styles.label}>
|
|
410
|
-
<span>{t('searchPendingTests', 'Search Pending Tests')}</span>
|
|
411
|
-
</label>
|
|
316
|
+
<div className={styles.searchGroup}>
|
|
412
317
|
<input
|
|
413
318
|
type="text"
|
|
414
319
|
className={styles.formControl}
|
|
415
|
-
placeholder={t('searchPlaceholder', '
|
|
320
|
+
placeholder={t('searchPlaceholder', 'Search by PHN, Patient Name, Test Name, Section, or Location...')}
|
|
416
321
|
value={searchTerm}
|
|
417
322
|
onChange={(e) => setSearchTerm(e.target.value)}
|
|
418
323
|
/>
|
|
419
324
|
</div>
|
|
420
325
|
</div>
|
|
421
|
-
</div>
|
|
422
326
|
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
<
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
<
|
|
474
|
-
{dto.
|
|
475
|
-
</
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
<
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
</
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
</
|
|
519
|
-
</
|
|
520
|
-
|
|
521
|
-
)
|
|
522
|
-
|
|
523
|
-
</
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
</div>
|
|
327
|
+
{/* Table Container: Exact 17 columns as in team's module */}
|
|
328
|
+
<div className={styles.tableContainer}>
|
|
329
|
+
{loadingOrders ? (
|
|
330
|
+
<div style={{ padding: '2rem' }}>
|
|
331
|
+
<Loading description="Loading pending tests..." withOverlay={false} small />
|
|
332
|
+
</div>
|
|
333
|
+
) : filteredOrders.length === 0 ? (
|
|
334
|
+
<div className={styles.emptyState}>
|
|
335
|
+
{t('noPendingOrders', 'No pending radiology test scheduling requests found.')}
|
|
336
|
+
</div>
|
|
337
|
+
) : (
|
|
338
|
+
<table id="tblRadiologyTestScheduling" className={styles.table}>
|
|
339
|
+
<thead>
|
|
340
|
+
<tr>
|
|
341
|
+
<th>#</th>
|
|
342
|
+
<th>{t('institute', 'Institute')}</th>
|
|
343
|
+
<th>{t('section', 'Section')}</th>
|
|
344
|
+
<th>{t('phn', 'PHN')}</th>
|
|
345
|
+
<th>{t('name', 'Name')}</th>
|
|
346
|
+
<th>{t('gender', 'Gender')}</th>
|
|
347
|
+
<th>{t('age', 'Age')}</th>
|
|
348
|
+
<th>{t('admittedDate', 'Admitted Date')}</th>
|
|
349
|
+
<th>{t('orderedBy', 'Ordered By')}</th>
|
|
350
|
+
<th>{t('orderedDatetime', 'Ordered Datetime')}</th>
|
|
351
|
+
<th>{t('testName', 'Test Name')}</th>
|
|
352
|
+
<th>{t('region', 'Region')}</th>
|
|
353
|
+
<th>{t('examRoom', 'Exam Room')}</th>
|
|
354
|
+
<th>{t('comment', 'Comment')}</th>
|
|
355
|
+
<th>{t('priority', 'Priority')}</th>
|
|
356
|
+
<th>{t('consultant', 'Consultant')}</th>
|
|
357
|
+
<th style={{ textAlign: 'center' }}>{t('action', 'Action')}</th>
|
|
358
|
+
</tr>
|
|
359
|
+
</thead>
|
|
360
|
+
<tbody id="tbodyRadTestsScheduling">
|
|
361
|
+
{filteredOrders.map((dto, idx) => {
|
|
362
|
+
const isUrgent = dto.radiology.priority === 'Urgent';
|
|
363
|
+
const isSelected = selectedOrder?.radiology.id === dto.radiology.id;
|
|
364
|
+
const rowClass = `${isUrgent ? styles.urgentRow : ''} ${
|
|
365
|
+
isSelected ? styles.selectedRow : ''
|
|
366
|
+
}`.trim();
|
|
367
|
+
|
|
368
|
+
return (
|
|
369
|
+
<tr key={`${dto.type}-${dto.radiology.id}`} className={rowClass}>
|
|
370
|
+
<td>{idx + 1}</td>
|
|
371
|
+
<td>{dto.locationName || dto.radiology.location}</td>
|
|
372
|
+
<td>
|
|
373
|
+
<span className={`${styles.badge} ${styles.badgeType}`}>
|
|
374
|
+
{dto.type}
|
|
375
|
+
</span>
|
|
376
|
+
</td>
|
|
377
|
+
<td>
|
|
378
|
+
<strong>{dto.radiology.patientPhn}</strong>
|
|
379
|
+
</td>
|
|
380
|
+
<td>{dto.patientName || '-'}</td>
|
|
381
|
+
<td>{dto.patientGender || '-'}</td>
|
|
382
|
+
<td>{dto.patientAge !== undefined && dto.patientAge !== '' ? dto.patientAge : '-'}</td>
|
|
383
|
+
<td>
|
|
384
|
+
{dto.radiology.occurrenceDateTime
|
|
385
|
+
? dto.radiology.occurrenceDateTime.split(' ')[0]
|
|
386
|
+
: '-'}
|
|
387
|
+
</td>
|
|
388
|
+
<td>{dto.orderedByName || dto.radiology.requesterReference || '-'}</td>
|
|
389
|
+
<td>{dto.radiology.occurrenceDateTime || '-'}</td>
|
|
390
|
+
<td>
|
|
391
|
+
<strong>{dto.radiology.codeDisplay || '-'}</strong>
|
|
392
|
+
</td>
|
|
393
|
+
<td>{dto.radiology.bodySiteText || '-'}</td>
|
|
394
|
+
<td>
|
|
395
|
+
{dto.radiology.supportingInfo === '--Select--'
|
|
396
|
+
? '-'
|
|
397
|
+
: dto.radiology.supportingInfo || '-'}
|
|
398
|
+
</td>
|
|
399
|
+
<td>{dto.radiology.note || '-'}</td>
|
|
400
|
+
<td>
|
|
401
|
+
<span
|
|
402
|
+
className={`${styles.badge} ${
|
|
403
|
+
isUrgent ? styles.badgeUrgent : styles.badgeRoutine
|
|
404
|
+
}`}
|
|
405
|
+
>
|
|
406
|
+
{dto.radiology.priority || 'Routine'}
|
|
407
|
+
</span>
|
|
408
|
+
</td>
|
|
409
|
+
<td>
|
|
410
|
+
{dto.radiology.requesterDisplay === '--Select--'
|
|
411
|
+
? '-'
|
|
412
|
+
: dto.radiology.requesterDisplay || '-'}
|
|
413
|
+
</td>
|
|
414
|
+
<td style={{ textAlign: 'center' }}>
|
|
415
|
+
<button
|
|
416
|
+
type="button"
|
|
417
|
+
className={`${styles.btnSelect} ${isSelected ? styles.btnSelected : ''}`}
|
|
418
|
+
onClick={() => handleSelectRow(dto)}
|
|
419
|
+
>
|
|
420
|
+
{isSelected ? t('selected', 'Selected') : t('select', 'Select')}
|
|
421
|
+
</button>
|
|
422
|
+
</td>
|
|
423
|
+
</tr>
|
|
424
|
+
);
|
|
425
|
+
})}
|
|
426
|
+
</tbody>
|
|
427
|
+
</table>
|
|
428
|
+
)}
|
|
429
|
+
</div>
|
|
527
430
|
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
<div className={styles.detailsPanel}>
|
|
431
|
+
{/* Demographics, Investigation Details & Scheduling Form Section */}
|
|
432
|
+
<div className={styles.demographicsSection}>
|
|
531
433
|
<div className={styles.row}>
|
|
532
|
-
{/* Patient
|
|
533
|
-
<div className={`${styles.
|
|
534
|
-
<div className={styles.sectionHeader}>
|
|
535
|
-
<span>{t('patientDemographics', 'Patient Demographics')}</span>
|
|
536
|
-
{selectedOrder.radiology.patientPhn && (
|
|
537
|
-
<span style={{ fontSize: '0.85rem', color: '#6c757d', marginLeft: 'auto' }}>
|
|
538
|
-
PHN: ({selectedOrder.radiology.patientPhn})
|
|
539
|
-
</span>
|
|
540
|
-
)}
|
|
541
|
-
</div>
|
|
542
|
-
|
|
434
|
+
{/* Patient Info (col10) */}
|
|
435
|
+
<div className={`${styles.col10} ${styles.formGroup}`}>
|
|
543
436
|
{loadingPatient ? (
|
|
544
|
-
<
|
|
437
|
+
<div style={{ padding: '1rem' }}>
|
|
438
|
+
<Loading description="Loading patient details..." withOverlay={false} small />
|
|
439
|
+
</div>
|
|
545
440
|
) : (
|
|
546
441
|
<div className={styles.row}>
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
<span className={styles.
|
|
551
|
-
|
|
442
|
+
{/* Left Column */}
|
|
443
|
+
<div className={styles.col6}>
|
|
444
|
+
<div className={styles.fieldItem}>
|
|
445
|
+
<span className={styles.fieldIcon}>👉</span>
|
|
446
|
+
<span className={styles.fieldTitle}>{t('fullName', 'Full Name')}:</span>
|
|
447
|
+
<span id="txtFullName" className={styles.fieldVal}>
|
|
448
|
+
{patientDetails?.fullName || (selectedOrder?.patientName || '-')}
|
|
552
449
|
</span>
|
|
553
450
|
</div>
|
|
554
|
-
<div className={styles.
|
|
555
|
-
<span className={styles.
|
|
556
|
-
<span className={styles.
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
<span className={styles.infoLabel}>{t('nicNo', 'NIC No')}:</span>
|
|
560
|
-
<span className={styles.infoValue}>{patientDetails?.nicNo || '-'}</span>
|
|
561
|
-
</div>
|
|
562
|
-
<div className={styles.infoField}>
|
|
563
|
-
<span className={styles.infoLabel}>{t('guardianInfo', 'Guardian Info')}:</span>
|
|
564
|
-
<span className={styles.infoValue}>
|
|
565
|
-
{patientDetails?.guardianInfo || '-'}
|
|
451
|
+
<div className={styles.fieldItem}>
|
|
452
|
+
<span className={styles.fieldIcon}>👉</span>
|
|
453
|
+
<span className={styles.fieldTitle}>{t('gender', 'Gender')}:</span>
|
|
454
|
+
<span id="txtGender" className={styles.fieldVal}>
|
|
455
|
+
{patientDetails?.gender || (selectedOrder?.patientGender || '-')}
|
|
566
456
|
</span>
|
|
567
457
|
</div>
|
|
568
|
-
<div className={styles.
|
|
569
|
-
<span className={styles.
|
|
570
|
-
<span className={styles.
|
|
458
|
+
<div className={styles.fieldItem}>
|
|
459
|
+
<span className={styles.fieldIcon}>👉</span>
|
|
460
|
+
<span className={styles.fieldTitle}>{t('nicNo', 'NIC No')}:</span>
|
|
461
|
+
<span id="txtNICNo" className={styles.fieldVal}>{patientDetails?.nicNo || '-'}</span>
|
|
571
462
|
</div>
|
|
572
|
-
<div className={styles.
|
|
573
|
-
<span className={styles.
|
|
574
|
-
<span className={styles.
|
|
575
|
-
|
|
576
|
-
{patientDetails?.days || 0}
|
|
577
|
-
</span>
|
|
463
|
+
<div className={styles.fieldItem}>
|
|
464
|
+
<span className={styles.fieldIcon}>👉</span>
|
|
465
|
+
<span className={styles.fieldTitle}>{t('guardianInfo', 'Guardian Info')}:</span>
|
|
466
|
+
<span id="txtGurdianInfo" className={styles.fieldVal}>{patientDetails?.guardianInfo || '-'}</span>
|
|
578
467
|
</div>
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
468
|
+
</div>
|
|
469
|
+
|
|
470
|
+
{/* Right Column */}
|
|
471
|
+
<div className={styles.col6}>
|
|
472
|
+
<div className={styles.fieldItem}>
|
|
473
|
+
<span className={styles.fieldIcon}>👉</span>
|
|
474
|
+
<span className={styles.fieldTitle}>{t('address', 'Address')}:</span>
|
|
475
|
+
<span id="txtAddress" className={styles.fieldVal}>{patientDetails?.address || '-'}</span>
|
|
584
476
|
</div>
|
|
585
|
-
<div className={styles.
|
|
586
|
-
<span className={styles.
|
|
587
|
-
<span className={styles.
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
477
|
+
<div className={styles.fieldItem}>
|
|
478
|
+
<span className={styles.fieldIcon}>👉</span>
|
|
479
|
+
<span className={styles.fieldTitle}>{t('age', 'Age')}:</span>
|
|
480
|
+
<span className={styles.fieldVal}>
|
|
481
|
+
Y: <span id="txtYears">{patientDetails?.years !== undefined && patientDetails?.years !== '' ? patientDetails.years : '-'}</span> |{' '}
|
|
482
|
+
M: <span id="txtMonths">{patientDetails?.months !== undefined && patientDetails?.months !== '' ? patientDetails.months : '-'}</span> |{' '}
|
|
483
|
+
D: <span id="txtDays">{patientDetails?.days !== undefined && patientDetails?.days !== '' ? patientDetails.days : '-'}</span>
|
|
591
484
|
</span>
|
|
592
485
|
</div>
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
src={patientDetails?.profileImage || DEFAULT_AVATAR}
|
|
599
|
-
alt="Patient"
|
|
600
|
-
onError={(e) => {
|
|
601
|
-
(e.currentTarget as HTMLImageElement).src = DEFAULT_AVATAR;
|
|
602
|
-
}}
|
|
603
|
-
/>
|
|
486
|
+
<div className={styles.fieldItem}>
|
|
487
|
+
<span className={styles.fieldIcon}>👉</span>
|
|
488
|
+
<span className={styles.fieldTitle}>{t('dob', 'Date Of Birth')}:</span>
|
|
489
|
+
<span id="txtDateOfBirth" className={styles.fieldVal}>{patientDetails?.dateOfBirth || '-'}</span>
|
|
490
|
+
</div>
|
|
604
491
|
</div>
|
|
605
492
|
</div>
|
|
606
493
|
)}
|
|
607
494
|
</div>
|
|
608
495
|
|
|
609
|
-
{/*
|
|
610
|
-
<div className={`${styles.
|
|
611
|
-
<
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
</span>
|
|
620
|
-
</div>
|
|
621
|
-
<div className={styles.infoField}>
|
|
622
|
-
<span className={styles.infoLabel}>{t('region', 'Region')}:</span>
|
|
623
|
-
<span className={styles.infoValue}>
|
|
624
|
-
{selectedOrder.radiology.bodySiteText || '-'}
|
|
625
|
-
</span>
|
|
626
|
-
</div>
|
|
627
|
-
<div className={styles.infoField}>
|
|
628
|
-
<span className={styles.infoLabel}>{t('localization', 'Localization')}:</span>
|
|
629
|
-
<span className={styles.infoValue}>
|
|
630
|
-
{selectedOrder.radiology.specimen || '-'}
|
|
631
|
-
</span>
|
|
632
|
-
</div>
|
|
633
|
-
<div className={styles.infoField}>
|
|
634
|
-
<span className={styles.infoLabel}>{t('position', 'Position')}:</span>
|
|
635
|
-
<span className={styles.infoValue}>
|
|
636
|
-
{selectedOrder.radiology.bodySiteDisplay || '-'}
|
|
637
|
-
</span>
|
|
638
|
-
</div>
|
|
639
|
-
<div className={styles.infoField}>
|
|
640
|
-
<span className={styles.infoLabel}>{t('comment', 'Comment')}:</span>
|
|
641
|
-
<span className={styles.infoValue}>{selectedOrder.radiology.note || '-'}</span>
|
|
642
|
-
</div>
|
|
643
|
-
<div className={styles.infoField}>
|
|
644
|
-
<span className={styles.infoLabel}>{t('priority', 'Priority')}:</span>
|
|
645
|
-
<span
|
|
646
|
-
className={`${styles.badge} ${
|
|
647
|
-
selectedOrder.radiology.priority === 'Urgent'
|
|
648
|
-
? styles.badgeUrgent
|
|
649
|
-
: styles.badgeRoutine
|
|
650
|
-
}`}
|
|
651
|
-
>
|
|
652
|
-
{selectedOrder.radiology.priority || 'Routine'}
|
|
653
|
-
</span>
|
|
654
|
-
</div>
|
|
655
|
-
<div className={styles.infoField}>
|
|
656
|
-
<span className={styles.infoLabel}>{t('consultant', 'Consultant')}:</span>
|
|
657
|
-
<span className={styles.infoValue}>
|
|
658
|
-
{selectedOrder.radiology.requesterDisplay === '--Select--'
|
|
659
|
-
? '-'
|
|
660
|
-
: selectedOrder.radiology.requesterDisplay || '-'}
|
|
661
|
-
</span>
|
|
662
|
-
</div>
|
|
663
|
-
<div className={styles.infoField}>
|
|
664
|
-
<span className={styles.infoLabel}>{t('orderedDateTime', 'Ordered Date & Time')}:</span>
|
|
665
|
-
<span className={styles.infoValue}>
|
|
666
|
-
{selectedOrder.radiology.occurrenceDateTime || '-'}
|
|
667
|
-
</span>
|
|
668
|
-
</div>
|
|
669
|
-
</div>
|
|
670
|
-
</div>
|
|
671
|
-
|
|
672
|
-
{/* Scheduling Form Inputs */}
|
|
673
|
-
<div className={styles.row} style={{ marginTop: '1.25rem' }}>
|
|
674
|
-
<div className={`${styles.col6} ${styles.formGroup}`}>
|
|
675
|
-
<label className={styles.label}>
|
|
676
|
-
<span>{t('scheduledDateTime', 'Scheduled Date Time')} *</span>
|
|
677
|
-
</label>
|
|
678
|
-
<input
|
|
679
|
-
type="datetime-local"
|
|
680
|
-
className={styles.formControl}
|
|
681
|
-
value={scheduledDateTime}
|
|
682
|
-
onChange={(e) => setScheduledDateTime(e.target.value)}
|
|
683
|
-
required
|
|
684
|
-
/>
|
|
685
|
-
</div>
|
|
686
|
-
|
|
687
|
-
<div className={`${styles.col6} ${styles.formGroup}`}>
|
|
688
|
-
<label className={styles.label}>
|
|
689
|
-
<span>{t('remarks', 'Remarks')}</span>
|
|
690
|
-
</label>
|
|
691
|
-
<textarea
|
|
692
|
-
className={styles.formControl}
|
|
693
|
-
rows={2}
|
|
694
|
-
placeholder={t('enterRemarks', 'Add scheduling remarks or instructions...')}
|
|
695
|
-
value={remarks}
|
|
696
|
-
onChange={(e) => setRemarks(e.target.value)}
|
|
496
|
+
{/* Patient Image (col2) */}
|
|
497
|
+
<div className={`${styles.col2} ${styles.uploadImgWrapper}`}>
|
|
498
|
+
<img
|
|
499
|
+
id="file_upload"
|
|
500
|
+
className={styles.uploadImg}
|
|
501
|
+
src={patientDetails?.profileImage || DEFAULT_AVATAR}
|
|
502
|
+
alt="Patient"
|
|
503
|
+
onError={(e) => {
|
|
504
|
+
(e.currentTarget as HTMLImageElement).src = DEFAULT_AVATAR;
|
|
505
|
+
}}
|
|
697
506
|
/>
|
|
698
507
|
</div>
|
|
699
|
-
</div>
|
|
700
|
-
|
|
701
|
-
{/* Action Buttons: Save button is prominent blue as requested */}
|
|
702
|
-
<div className={styles.buttonGroup}>
|
|
703
|
-
<button
|
|
704
|
-
type="button"
|
|
705
|
-
className={styles.btnPrimary}
|
|
706
|
-
onClick={handleSave}
|
|
707
|
-
disabled={isSaving}
|
|
708
|
-
>
|
|
709
|
-
{isSaving ? t('saving', 'Saving...') : t('saveSchedule', 'Save Schedule')}
|
|
710
|
-
</button>
|
|
711
|
-
<button
|
|
712
|
-
type="button"
|
|
713
|
-
className={styles.btnCancel}
|
|
714
|
-
onClick={handleClear}
|
|
715
|
-
disabled={isSaving}
|
|
716
|
-
>
|
|
717
|
-
{t('cancel', 'Cancel')}
|
|
718
|
-
</button>
|
|
719
|
-
</div>
|
|
720
|
-
</div>
|
|
721
|
-
)}
|
|
722
|
-
|
|
723
|
-
{/* Calendar Overview Section */}
|
|
724
|
-
<div style={{ marginTop: '2.5rem' }}>
|
|
725
|
-
<div className={styles.sectionHeader}>
|
|
726
|
-
<span>{t('scheduledCalendarOverview', 'Scheduled Calendar Overview')}</span>
|
|
727
|
-
</div>
|
|
728
|
-
|
|
729
|
-
<div className={styles.row} style={{ marginBottom: '1rem' }}>
|
|
730
|
-
<div className={`${styles.col4} ${styles.formGroup}`}>
|
|
731
|
-
<label className={styles.label}>
|
|
732
|
-
<span>{t('modality', 'Modality')}</span>
|
|
733
|
-
</label>
|
|
734
|
-
<select
|
|
735
|
-
className={styles.formControl}
|
|
736
|
-
value={selectedModality}
|
|
737
|
-
onChange={(e) => setSelectedModality(e.target.value)}
|
|
738
|
-
>
|
|
739
|
-
<option value="all">{t('allModalities', '-- All Modalities --')}</option>
|
|
740
|
-
<option value="Xray">Xray</option>
|
|
741
|
-
<option value="CT">CT</option>
|
|
742
|
-
<option value="MRI">MRI</option>
|
|
743
|
-
</select>
|
|
744
|
-
</div>
|
|
745
508
|
|
|
746
|
-
|
|
747
|
-
<
|
|
748
|
-
<
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
<
|
|
759
|
-
{
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
509
|
+
{/* Investigation Details Row (col12 with border-bottom) */}
|
|
510
|
+
<div className={`${styles.col12} ${styles.investigationRow}`}>
|
|
511
|
+
<div className={styles.row}>
|
|
512
|
+
<div className={styles.col3}>
|
|
513
|
+
<div className={styles.fieldItem}>
|
|
514
|
+
<span className={styles.fieldIcon}>👉</span>
|
|
515
|
+
<span className={styles.fieldTitle}>{t('testName', 'Test Name')}:</span>
|
|
516
|
+
<span id="lblTestName" className={styles.fieldVal}>
|
|
517
|
+
{selectedOrder?.radiology.codeDisplay || '-'}
|
|
518
|
+
</span>
|
|
519
|
+
</div>
|
|
520
|
+
</div>
|
|
521
|
+
<div className={styles.col3}>
|
|
522
|
+
<div className={styles.fieldItem}>
|
|
523
|
+
<span className={styles.fieldIcon}>👉</span>
|
|
524
|
+
<span className={styles.fieldTitle}>{t('region', 'Region')}:</span>
|
|
525
|
+
<span id="lblRegion" className={styles.fieldVal}>
|
|
526
|
+
{selectedOrder?.radiology.bodySiteText || '-'}
|
|
527
|
+
</span>
|
|
528
|
+
</div>
|
|
529
|
+
</div>
|
|
530
|
+
<div className={styles.col3}>
|
|
531
|
+
<div className={styles.fieldItem}>
|
|
532
|
+
<span className={styles.fieldIcon}>👉</span>
|
|
533
|
+
<span className={styles.fieldTitle}>{t('localization', 'Localization')}:</span>
|
|
534
|
+
<span id="lblLocalization" className={styles.fieldVal}>
|
|
535
|
+
{selectedOrder?.radiology.specimen || '-'}
|
|
536
|
+
</span>
|
|
537
|
+
</div>
|
|
538
|
+
</div>
|
|
539
|
+
<div className={styles.col3}>
|
|
540
|
+
<div className={styles.fieldItem}>
|
|
541
|
+
<span className={styles.fieldIcon}>👉</span>
|
|
542
|
+
<span className={styles.fieldTitle}>{t('position', 'Position')}:</span>
|
|
543
|
+
<span id="lblPosition" className={styles.fieldVal}>
|
|
544
|
+
{selectedOrder?.radiology.bodySiteDisplay || '-'}
|
|
545
|
+
</span>
|
|
546
|
+
</div>
|
|
547
|
+
</div>
|
|
765
548
|
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
549
|
+
<div className={styles.col3}>
|
|
550
|
+
<div className={styles.fieldItem}>
|
|
551
|
+
<span className={styles.fieldIcon}>👉</span>
|
|
552
|
+
<span className={styles.fieldTitle}>{t('comment', 'Comment')}:</span>
|
|
553
|
+
<span id="lblComment" className={styles.fieldVal}>
|
|
554
|
+
{selectedOrder?.radiology.note || '-'}
|
|
555
|
+
</span>
|
|
556
|
+
</div>
|
|
557
|
+
</div>
|
|
558
|
+
<div className={styles.col3}>
|
|
559
|
+
<div className={styles.fieldItem}>
|
|
560
|
+
<span className={styles.fieldIcon}>👉</span>
|
|
561
|
+
<span className={styles.fieldTitle}>{t('priority', 'Priority')}:</span>
|
|
562
|
+
<span id="lblPriority" className={styles.fieldVal}>
|
|
563
|
+
{selectedOrder?.radiology.priority || '-'}
|
|
564
|
+
</span>
|
|
565
|
+
</div>
|
|
566
|
+
</div>
|
|
567
|
+
<div className={styles.col3}>
|
|
568
|
+
<div className={styles.fieldItem}>
|
|
569
|
+
<span className={styles.fieldIcon}>👉</span>
|
|
570
|
+
<span className={styles.fieldTitle}>{t('consultant', 'Consultant')}:</span>
|
|
571
|
+
<span id="lblConsultant" className={styles.fieldVal}>
|
|
572
|
+
{selectedOrder?.radiology.requesterDisplay === '--Select--'
|
|
573
|
+
? '-'
|
|
574
|
+
: selectedOrder?.radiology.requesterDisplay || '-'}
|
|
575
|
+
</span>
|
|
576
|
+
</div>
|
|
577
|
+
</div>
|
|
578
|
+
<div className={styles.col3}>
|
|
579
|
+
<div className={styles.fieldItem}>
|
|
580
|
+
<span className={styles.fieldIcon}>👉</span>
|
|
581
|
+
<span className={styles.fieldTitle}>{t('orderedDateTime', 'Ordered Date & Time')}:</span>
|
|
582
|
+
<span id="lblOdrDateTime" className={styles.fieldVal}>
|
|
583
|
+
{selectedOrder?.radiology.occurrenceDateTime || '-'}
|
|
584
|
+
</span>
|
|
585
|
+
</div>
|
|
586
|
+
</div>
|
|
587
|
+
</div>
|
|
802
588
|
</div>
|
|
803
|
-
</div>
|
|
804
589
|
|
|
805
|
-
|
|
806
|
-
<div
|
|
807
|
-
<
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
590
|
+
{/* Scheduling Form Section: Scheduled Date Time, Remarks, Modality, Exam Room */}
|
|
591
|
+
<div className={`${styles.col12} ${styles.schedulingFormArea}`}>
|
|
592
|
+
<div className={styles.row}>
|
|
593
|
+
{/* Left Column: Scheduled Date Time & Remarks */}
|
|
594
|
+
<div className={styles.col6}>
|
|
595
|
+
<div className={`${styles.row} ${styles.formGroup}`}>
|
|
596
|
+
<div className={styles.col4}>
|
|
597
|
+
<label className={styles.label}>
|
|
598
|
+
{t('scheduledDateTime', 'Scheduled Date Time')}
|
|
599
|
+
</label>
|
|
600
|
+
</div>
|
|
601
|
+
<div className={styles.col8}>
|
|
602
|
+
<input
|
|
603
|
+
id="txtScheduledDateTime"
|
|
604
|
+
type="datetime-local"
|
|
605
|
+
className={styles.formControl}
|
|
606
|
+
value={scheduledDateTime}
|
|
607
|
+
onChange={(e) => setScheduledDateTime(e.target.value)}
|
|
608
|
+
/>
|
|
609
|
+
</div>
|
|
610
|
+
</div>
|
|
816
611
|
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
className={
|
|
841
|
-
|
|
842
|
-
}
|
|
612
|
+
<div className={`${styles.row} ${styles.formGroup}`}>
|
|
613
|
+
<div className={styles.col4}>
|
|
614
|
+
<label className={styles.label}>
|
|
615
|
+
{t('remarks', 'Remarks')}
|
|
616
|
+
</label>
|
|
617
|
+
</div>
|
|
618
|
+
<div className={styles.col8}>
|
|
619
|
+
<textarea
|
|
620
|
+
id="txtRemarks"
|
|
621
|
+
className={styles.formControl}
|
|
622
|
+
rows={2}
|
|
623
|
+
placeholder={t('enterRemarks', 'Remarks...')}
|
|
624
|
+
value={remarks}
|
|
625
|
+
onChange={(e) => setRemarks(e.target.value)}
|
|
626
|
+
/>
|
|
627
|
+
</div>
|
|
628
|
+
</div>
|
|
629
|
+
|
|
630
|
+
{/* Action Buttons: Big blue Save button + Cancel */}
|
|
631
|
+
<div className={styles.buttonGroup}>
|
|
632
|
+
<button
|
|
633
|
+
id="btnSave"
|
|
634
|
+
type="button"
|
|
635
|
+
className={styles.btnPrimary}
|
|
636
|
+
onClick={handleSave}
|
|
637
|
+
disabled={isSaving}
|
|
843
638
|
>
|
|
844
|
-
{
|
|
845
|
-
</
|
|
639
|
+
{isSaving ? t('saving', 'Saving...') : t('save', 'Save')}
|
|
640
|
+
</button>
|
|
641
|
+
<button
|
|
642
|
+
id="btnClear"
|
|
643
|
+
type="button"
|
|
644
|
+
className={styles.btnCancel}
|
|
645
|
+
onClick={handleClear}
|
|
646
|
+
disabled={isSaving}
|
|
647
|
+
>
|
|
648
|
+
{t('cancel', 'Cancel')}
|
|
649
|
+
</button>
|
|
650
|
+
</div>
|
|
651
|
+
</div>
|
|
846
652
|
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
653
|
+
{/* Right Column: Modality & Exam Room */}
|
|
654
|
+
<div className={styles.col6}>
|
|
655
|
+
<div className={`${styles.row} ${styles.formGroup}`}>
|
|
656
|
+
<div className={styles.col4}>
|
|
657
|
+
<label className={styles.label}>
|
|
658
|
+
{t('modality', 'Modality')}
|
|
659
|
+
</label>
|
|
660
|
+
</div>
|
|
661
|
+
<div className={styles.col8}>
|
|
662
|
+
<select
|
|
663
|
+
id="drpSelectModality"
|
|
664
|
+
className={styles.formControl}
|
|
665
|
+
value={selectedModality}
|
|
666
|
+
onChange={(e) => setSelectedModality(e.target.value)}
|
|
667
|
+
>
|
|
668
|
+
<option value="all">--Select--</option>
|
|
669
|
+
<option value="Xray">Xray</option>
|
|
670
|
+
<option value="CT">CT</option>
|
|
671
|
+
<option value="MRI">MRI</option>
|
|
672
|
+
</select>
|
|
673
|
+
</div>
|
|
674
|
+
</div>
|
|
852
675
|
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
676
|
+
<div className={`${styles.row} ${styles.formGroup}`}>
|
|
677
|
+
<div className={styles.col4}>
|
|
678
|
+
<label className={styles.label}>
|
|
679
|
+
{t('examRoom', 'Exam Room')}
|
|
680
|
+
</label>
|
|
681
|
+
</div>
|
|
682
|
+
<div className={styles.col8}>
|
|
683
|
+
<select
|
|
684
|
+
id="drpSelectExamRoom"
|
|
685
|
+
className={styles.formControl}
|
|
686
|
+
value={selectedExamRoom}
|
|
687
|
+
onChange={(e) => setSelectedExamRoom(e.target.value)}
|
|
688
|
+
disabled={selectedModality === 'all'}
|
|
689
|
+
>
|
|
690
|
+
<option value="all">--Select--</option>
|
|
691
|
+
{examRooms.map((room, i) => (
|
|
692
|
+
<option key={`${room.name}-${i}`} value={room.name}>
|
|
693
|
+
{room.name}
|
|
694
|
+
</option>
|
|
695
|
+
))}
|
|
696
|
+
</select>
|
|
697
|
+
</div>
|
|
863
698
|
</div>
|
|
864
|
-
|
|
865
|
-
|
|
699
|
+
</div>
|
|
700
|
+
</div>
|
|
866
701
|
</div>
|
|
867
|
-
|
|
702
|
+
|
|
703
|
+
</div>
|
|
868
704
|
</div>
|
|
869
705
|
</div>
|
|
870
706
|
</div>
|