@sasindi/samplecollection 1.0.1 → 1.0.3
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/30.js +1 -1
- package/dist/30.js.map +1 -1
- package/dist/425.js +1 -1
- package/dist/425.js.map +1 -1
- package/dist/529.js +1 -1
- package/dist/577.js +1 -1
- package/dist/577.js.map +1 -1
- package/dist/main.js +3 -3
- package/dist/main.js.map +1 -1
- package/dist/openmrs-esm-samplecollection.js +3 -3
- package/dist/openmrs-esm-samplecollection.js.buildmanifest.json +48 -48
- package/dist/openmrs-esm-samplecollection.js.map +1 -1
- package/dist/routes.json +1 -1
- package/package.json +1 -1
- package/src/routes.json +1 -1
- package/src/samplecollection.component.tsx +167 -150
- package/src/samplecollection.scss +235 -101
- package/src/samplecollectionroom.component.tsx +233 -217
|
@@ -1,26 +1,9 @@
|
|
|
1
1
|
import React, { useState, useEffect } from 'react';
|
|
2
2
|
import { useTranslation } from 'react-i18next';
|
|
3
|
-
import {
|
|
4
|
-
Tile,
|
|
5
|
-
TextInput,
|
|
6
|
-
Select,
|
|
7
|
-
SelectItem,
|
|
8
|
-
TextArea,
|
|
9
|
-
Button,
|
|
10
|
-
Table,
|
|
11
|
-
TableHead,
|
|
12
|
-
TableRow,
|
|
13
|
-
TableHeader,
|
|
14
|
-
TableBody,
|
|
15
|
-
TableCell,
|
|
16
|
-
Checkbox,
|
|
17
|
-
Loading,
|
|
18
|
-
InlineNotification
|
|
19
|
-
} from '@carbon/react';
|
|
20
3
|
import styles from './samplecollection.scss';
|
|
21
4
|
|
|
22
5
|
const UserAvatar = () => (
|
|
23
|
-
<svg width="
|
|
6
|
+
<svg width="60" height="60" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg" style={{ borderRadius: '16px', border: '3px solid #20e5bf' }}>
|
|
24
7
|
<circle cx="50" cy="50" r="50" fill="#E0F2F1"/>
|
|
25
8
|
<circle cx="50" cy="40" r="18" fill="#009384"/>
|
|
26
9
|
<path d="M18 78C18 62.536 32.3269 50 50 50C67.6731 50 82 62.536 82 78" stroke="#009384" strokeWidth="8" strokeLinecap="round"/>
|
|
@@ -141,8 +124,11 @@ const SamplecollectionRoom: React.FC = () => {
|
|
|
141
124
|
personAttrData.attributes.forEach((attr: any) => {
|
|
142
125
|
if (attr.display) {
|
|
143
126
|
const [key, value] = attr.display.split('=');
|
|
144
|
-
if (key && value
|
|
145
|
-
|
|
127
|
+
if (key && value) {
|
|
128
|
+
const cleanKey = key.trim();
|
|
129
|
+
if (cleanKey === 'Institute Id' || cleanKey === 'Institute') {
|
|
130
|
+
locUuid = value.trim();
|
|
131
|
+
}
|
|
146
132
|
}
|
|
147
133
|
}
|
|
148
134
|
});
|
|
@@ -419,223 +405,253 @@ const SamplecollectionRoom: React.FC = () => {
|
|
|
419
405
|
}
|
|
420
406
|
};
|
|
421
407
|
|
|
422
|
-
if (loading)
|
|
408
|
+
if (loading) {
|
|
409
|
+
return (
|
|
410
|
+
<div className={styles.container} style={{ textAlign: 'center', padding: '50px' }}>
|
|
411
|
+
Loading patient details...
|
|
412
|
+
</div>
|
|
413
|
+
);
|
|
414
|
+
}
|
|
423
415
|
|
|
424
416
|
return (
|
|
425
417
|
<div className={styles.container}>
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
<div className={styles.
|
|
429
|
-
<
|
|
430
|
-
|
|
431
|
-
</h1>
|
|
432
|
-
<div className={styles.locationBadge}>
|
|
433
|
-
<span className="icon-hospital" />
|
|
434
|
-
<span>{locationName}</span>
|
|
435
|
-
</div>
|
|
418
|
+
{/* Clinic/Hospital Header */}
|
|
419
|
+
<div style={{ display: 'flex', justifyContent: 'flex-end', marginBottom: '10px' }}>
|
|
420
|
+
<div className={styles.locationBadge} style={{ background: '#e9ecef', color: '#495057' }}>
|
|
421
|
+
<span className="icon-hospital" />
|
|
422
|
+
<span id="lblInstituteName" style={{ fontWeight: 'bold' }}>{locationName}</span>
|
|
436
423
|
</div>
|
|
424
|
+
</div>
|
|
437
425
|
|
|
438
|
-
|
|
439
|
-
{
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
subtitle={successMsg}
|
|
453
|
-
onClose={() => setSuccessMsg('')}
|
|
454
|
-
style={{ marginBottom: '1rem' }}
|
|
455
|
-
/>
|
|
456
|
-
)}
|
|
457
|
-
|
|
458
|
-
{/* Patient Profile Card */}
|
|
459
|
-
<div className={styles.patientCard}>
|
|
460
|
-
<div className={styles.patientGrid}>
|
|
461
|
-
<div className={styles.patientField}>
|
|
462
|
-
<span className={styles.fieldLabel}>Full Name</span>
|
|
463
|
-
<span className={styles.fieldValue}>{patientName || 'N/A'}</span>
|
|
464
|
-
</div>
|
|
465
|
-
<div className={styles.patientField}>
|
|
466
|
-
<span className={styles.fieldLabel}>Section</span>
|
|
467
|
-
<span className={styles.fieldValue}>{initialSection || 'N/A'}</span>
|
|
426
|
+
<div className={styles.card}>
|
|
427
|
+
<div className={styles.cardBody}>
|
|
428
|
+
|
|
429
|
+
{/* Section title */}
|
|
430
|
+
<div className={styles.col12} style={{ marginBottom: '1rem', padding: 0 }}>
|
|
431
|
+
<h2 className={styles.heading} style={{ margin: 0 }}>
|
|
432
|
+
{t('samplecollectionRoomHeading', 'Sample Collection Room')}
|
|
433
|
+
</h2>
|
|
434
|
+
</div>
|
|
435
|
+
|
|
436
|
+
{/* Messages */}
|
|
437
|
+
{errorMsg && (
|
|
438
|
+
<div style={{ padding: '8px', color: '#721c24', backgroundColor: '#f8d7da', border: '1px solid #f5c6cb', borderRadius: '4px', marginBottom: '10px' }}>
|
|
439
|
+
{errorMsg}
|
|
468
440
|
</div>
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
441
|
+
)}
|
|
442
|
+
{successMsg && (
|
|
443
|
+
<div style={{ padding: '8px', color: '#155724', backgroundColor: '#d4edda', border: '1px solid #c3e6cb', borderRadius: '4px', marginBottom: '10px' }}>
|
|
444
|
+
{successMsg}
|
|
472
445
|
</div>
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
446
|
+
)}
|
|
447
|
+
|
|
448
|
+
{/* Patient Card Grid (Col-10 fields, Col-2 avatar) */}
|
|
449
|
+
<div className={styles.row} style={{ marginBottom: '1.5rem' }}>
|
|
450
|
+
<div className={styles.col10}>
|
|
451
|
+
<div className={styles.row}>
|
|
452
|
+
|
|
453
|
+
<div className={styles.formGroupCol}>
|
|
454
|
+
<label className={styles.labelCompact}>Full Name</label>
|
|
455
|
+
<input type="text" className={styles.formControl} value={patientName} readOnly />
|
|
456
|
+
</div>
|
|
457
|
+
|
|
458
|
+
<div className={styles.formGroupCol}>
|
|
459
|
+
<label className={styles.labelCompact}>Section</label>
|
|
460
|
+
<input type="text" className={styles.formControl} value={initialSection} readOnly />
|
|
461
|
+
</div>
|
|
462
|
+
|
|
463
|
+
<div className={styles.formGroupCol}>
|
|
464
|
+
<label className={styles.labelCompact}>PHN No</label>
|
|
465
|
+
<input type="text" className={styles.formControl} value={phnNo} readOnly />
|
|
466
|
+
</div>
|
|
467
|
+
|
|
468
|
+
<div className={styles.formGroupCol}>
|
|
469
|
+
<label className={styles.labelCompact}>Age</label>
|
|
470
|
+
<input type="text" className={styles.formControl} value={patientAge} readOnly />
|
|
471
|
+
</div>
|
|
472
|
+
|
|
473
|
+
<div className={styles.formGroupCol}>
|
|
474
|
+
<label className={styles.labelCompact}>Gender</label>
|
|
475
|
+
<input type="text" className={styles.formControl} value={patientGender} readOnly />
|
|
476
|
+
</div>
|
|
477
|
+
|
|
478
|
+
</div>
|
|
476
479
|
</div>
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
<
|
|
480
|
+
|
|
481
|
+
<div className={styles.col2}>
|
|
482
|
+
<div className={styles.avatarContainer}>
|
|
483
|
+
{profileImgName ? (
|
|
484
|
+
<img
|
|
485
|
+
src={`${window.location.origin}/openmrs/owa/PatientImagesUploaded/${profileImgName}`}
|
|
486
|
+
alt="Patient avatar"
|
|
487
|
+
className={styles.uploadImg}
|
|
488
|
+
onError={(e) => {
|
|
489
|
+
(e.target as HTMLElement).style.display = 'none';
|
|
490
|
+
}}
|
|
491
|
+
/>
|
|
492
|
+
) : (
|
|
493
|
+
<UserAvatar />
|
|
494
|
+
)}
|
|
495
|
+
</div>
|
|
480
496
|
</div>
|
|
481
497
|
</div>
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
498
|
+
|
|
499
|
+
{/* Pending Tests Table */}
|
|
500
|
+
<div className={styles.tableResponsive} style={{ maxHeight: '200px', overflowY: 'auto', border: '1px solid #dee2e6', marginBottom: '1.5rem' }}>
|
|
501
|
+
<table className={`${styles.table} ${styles.tableBordered} ${styles.tableHover} ${styles.tableStriped}`}>
|
|
502
|
+
<thead>
|
|
503
|
+
<tr>
|
|
504
|
+
<th style={{ width: '50px' }}>No</th>
|
|
505
|
+
<th style={{ whiteSpace: 'nowrap' }}>Test Name</th>
|
|
506
|
+
<th style={{ whiteSpace: 'nowrap' }}>Order By</th>
|
|
507
|
+
<th style={{ whiteSpace: 'nowrap' }}>Order Date/Time</th>
|
|
508
|
+
<th style={{ width: '40px' }}></th>
|
|
509
|
+
</tr>
|
|
510
|
+
</thead>
|
|
511
|
+
<tbody>
|
|
512
|
+
{testList.length === 0 ? (
|
|
513
|
+
<tr>
|
|
514
|
+
<td colSpan={5} style={{ textAlign: 'center', padding: '10px' }}>
|
|
515
|
+
No active tests pending collection.
|
|
516
|
+
</td>
|
|
517
|
+
</tr>
|
|
518
|
+
) : (
|
|
519
|
+
testList.map((row, index) => {
|
|
520
|
+
const id = row[8];
|
|
521
|
+
const testName = row[2];
|
|
522
|
+
const orderBy = row[5];
|
|
523
|
+
const orderDateTime = row[6];
|
|
524
|
+
const urgent = row[9];
|
|
525
|
+
const isChecked = selectedIds.includes(String(id));
|
|
526
|
+
|
|
527
|
+
return (
|
|
528
|
+
<tr key={id || index}>
|
|
529
|
+
<td>{index + 1}</td>
|
|
530
|
+
<td>{testName}</td>
|
|
531
|
+
<td>{orderBy}</td>
|
|
532
|
+
<td>{orderDateTime}</td>
|
|
533
|
+
<td style={{ textAlign: 'center' }}>
|
|
534
|
+
<input
|
|
535
|
+
type="checkbox"
|
|
536
|
+
className={styles.formControl}
|
|
537
|
+
style={{ width: '16px', height: '16px', margin: 0 }}
|
|
538
|
+
checked={isChecked}
|
|
539
|
+
onChange={(e) =>
|
|
540
|
+
handleCheckboxChange(e.target.checked, String(id), testName, String(urgent), row)
|
|
541
|
+
}
|
|
542
|
+
/>
|
|
543
|
+
</td>
|
|
544
|
+
</tr>
|
|
545
|
+
);
|
|
546
|
+
})
|
|
547
|
+
)}
|
|
548
|
+
</tbody>
|
|
549
|
+
</table>
|
|
496
550
|
</div>
|
|
497
|
-
</div>
|
|
498
551
|
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
<
|
|
503
|
-
<
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
<TableHeader>Order By</TableHeader>
|
|
507
|
-
<TableHeader>Order Date/Time</TableHeader>
|
|
508
|
-
<TableHeader className={styles.checkboxCell} />
|
|
509
|
-
</TableRow>
|
|
510
|
-
</TableHead>
|
|
511
|
-
<TableBody>
|
|
512
|
-
{testList.length === 0 ? (
|
|
513
|
-
<TableRow>
|
|
514
|
-
<TableCell colSpan={5} style={{ textAlign: 'center' }}>
|
|
515
|
-
No active tests pending collection.
|
|
516
|
-
</TableCell>
|
|
517
|
-
</TableRow>
|
|
518
|
-
) : (
|
|
519
|
-
testList.map((row, index) => {
|
|
520
|
-
const id = row[8];
|
|
521
|
-
const testName = row[2];
|
|
522
|
-
const orderBy = row[5];
|
|
523
|
-
const orderDateTime = row[6];
|
|
524
|
-
const urgent = row[9]; // 'true' or 'false'
|
|
525
|
-
const isChecked = selectedIds.includes(String(id));
|
|
526
|
-
|
|
527
|
-
return (
|
|
528
|
-
<TableRow key={id || index}>
|
|
529
|
-
<TableCell>{index + 1}</TableCell>
|
|
530
|
-
<TableCell>{testName}</TableCell>
|
|
531
|
-
<TableCell>{orderBy}</TableCell>
|
|
532
|
-
<TableCell>{orderDateTime}</TableCell>
|
|
533
|
-
<TableCell className={styles.checkboxCell}>
|
|
534
|
-
<Checkbox
|
|
535
|
-
id={`chk-${id}`}
|
|
536
|
-
labelText=""
|
|
537
|
-
checked={isChecked}
|
|
538
|
-
onChange={(e, { checked }) =>
|
|
539
|
-
handleCheckboxChange(checked, String(id), testName, String(urgent), row)
|
|
540
|
-
}
|
|
541
|
-
/>
|
|
542
|
-
</TableCell>
|
|
543
|
-
</TableRow>
|
|
544
|
-
);
|
|
545
|
-
})
|
|
546
|
-
)}
|
|
547
|
-
</TableBody>
|
|
548
|
-
</Table>
|
|
549
|
-
</div>
|
|
552
|
+
{/* Test Detail Display inputs */}
|
|
553
|
+
<div className={styles.row} style={{ marginBottom: '1rem' }}>
|
|
554
|
+
|
|
555
|
+
<div className={styles.formGroupCol}>
|
|
556
|
+
<label className={styles.labelCompact}>Test Name</label>
|
|
557
|
+
<input type="text" className={styles.formControl} value={displayTestNames} readOnly />
|
|
558
|
+
</div>
|
|
550
559
|
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
readOnly
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
value={
|
|
564
|
-
|
|
565
|
-
/>
|
|
566
|
-
<TextInput
|
|
567
|
-
id="txtorderdate"
|
|
568
|
-
labelText="Order Date"
|
|
569
|
-
value={displayOrderDate}
|
|
570
|
-
readOnly
|
|
571
|
-
/>
|
|
572
|
-
<TextInput
|
|
573
|
-
id="txtordertime"
|
|
574
|
-
labelText="Order Time"
|
|
575
|
-
value={displayOrderTime}
|
|
576
|
-
readOnly
|
|
577
|
-
/>
|
|
578
|
-
</div>
|
|
560
|
+
<div className={styles.formGroupCol}>
|
|
561
|
+
<label className={styles.labelCompact}>Order By</label>
|
|
562
|
+
<input type="text" className={styles.formControl} value={displayOrderBy} readOnly />
|
|
563
|
+
</div>
|
|
564
|
+
|
|
565
|
+
<div className={styles.formGroupCol}>
|
|
566
|
+
<label className={styles.labelCompact}>Order Date</label>
|
|
567
|
+
<input type="text" className={styles.formControl} value={displayOrderDate} readOnly />
|
|
568
|
+
</div>
|
|
569
|
+
|
|
570
|
+
<div className={styles.formGroupCol}>
|
|
571
|
+
<label className={styles.labelCompact}>Order Time</label>
|
|
572
|
+
<input type="text" className={styles.formControl} value={displayOrderTime} readOnly />
|
|
573
|
+
</div>
|
|
579
574
|
|
|
580
|
-
<hr style={{ border: 'none', height: '1px', backgroundColor: '#e0e0e0', margin: '20px 0' }} />
|
|
581
|
-
|
|
582
|
-
{/* User inputs */}
|
|
583
|
-
<div className={styles.formGrid}>
|
|
584
|
-
<TextInput
|
|
585
|
-
id="txtdate"
|
|
586
|
-
labelText="Date"
|
|
587
|
-
type="date"
|
|
588
|
-
value={saveDate}
|
|
589
|
-
onChange={(e) => setSaveDate(e.target.value)}
|
|
590
|
-
/>
|
|
591
|
-
<TextInput
|
|
592
|
-
id="txttime"
|
|
593
|
-
labelText="Time"
|
|
594
|
-
type="time"
|
|
595
|
-
value={saveTime}
|
|
596
|
-
onChange={(e) => setSaveTime(e.target.value)}
|
|
597
|
-
/>
|
|
598
|
-
<Select
|
|
599
|
-
id="drpstatus"
|
|
600
|
-
labelText="Collection Status"
|
|
601
|
-
value={saveStatus}
|
|
602
|
-
onChange={(e) => setSaveStatus(e.target.value)}
|
|
603
|
-
>
|
|
604
|
-
<SelectItem value="0" text="--Select--" />
|
|
605
|
-
<SelectItem value="Done" text="Done" />
|
|
606
|
-
<SelectItem value="Not Done" text="Not Done" />
|
|
607
|
-
</Select>
|
|
608
575
|
</div>
|
|
609
576
|
|
|
610
|
-
<
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
577
|
+
<hr style={{ border: 'none', height: '1px', backgroundColor: '#000', margin: '20px 0' }} />
|
|
578
|
+
|
|
579
|
+
{/* Date, Time, Status fields */}
|
|
580
|
+
<div className={styles.row} style={{ marginBottom: '1rem' }}>
|
|
581
|
+
|
|
582
|
+
<div className={styles.formGroupCol}>
|
|
583
|
+
<label className={styles.labelCompact}>Date</label>
|
|
584
|
+
<input
|
|
585
|
+
type="date"
|
|
586
|
+
className={styles.formControl}
|
|
587
|
+
value={saveDate}
|
|
588
|
+
onChange={(e) => setSaveDate(e.target.value)}
|
|
589
|
+
/>
|
|
590
|
+
</div>
|
|
591
|
+
|
|
592
|
+
<div className={styles.formGroupCol}>
|
|
593
|
+
<label className={styles.labelCompact}>Time</label>
|
|
594
|
+
<input
|
|
595
|
+
type="time"
|
|
596
|
+
className={styles.formControl}
|
|
597
|
+
value={saveTime}
|
|
598
|
+
onChange={(e) => setSaveTime(e.target.value)}
|
|
599
|
+
/>
|
|
600
|
+
</div>
|
|
601
|
+
|
|
602
|
+
<div className={styles.formGroupCol}>
|
|
603
|
+
<label className={styles.labelCompact}>Collection Status</label>
|
|
604
|
+
<select
|
|
605
|
+
className={styles.formControl}
|
|
606
|
+
value={saveStatus}
|
|
607
|
+
onChange={(e) => setSaveStatus(e.target.value)}
|
|
608
|
+
>
|
|
609
|
+
<option value="0">--Select--</option>
|
|
610
|
+
<option value="Done">Done</option>
|
|
611
|
+
<option value="Not Done">Not Done</option>
|
|
612
|
+
</select>
|
|
613
|
+
</div>
|
|
614
|
+
|
|
618
615
|
</div>
|
|
619
616
|
|
|
620
|
-
{/* Action buttons */}
|
|
621
|
-
<div className={styles.
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
>
|
|
634
|
-
|
|
635
|
-
|
|
617
|
+
{/* Remark text box and Action buttons row */}
|
|
618
|
+
<div className={styles.row}>
|
|
619
|
+
|
|
620
|
+
<div className={styles.formGroupCol} style={{ flex: '0 0 66.6666%', maxWidth: '66.6666%', alignItems: 'flex-start' }}>
|
|
621
|
+
<label className={styles.labelCompact}>Remark</label>
|
|
622
|
+
<textarea
|
|
623
|
+
className={`${styles.formControl} ${styles.textareaControl}`}
|
|
624
|
+
rows={3}
|
|
625
|
+
value={saveRemark}
|
|
626
|
+
onChange={(e) => setSaveRemark(e.target.value)}
|
|
627
|
+
/>
|
|
628
|
+
</div>
|
|
629
|
+
|
|
630
|
+
<div className={`${styles.formGroupCol} ${styles.justifyContentEnd}`} style={{ flex: '0 0 33.3333%', maxWidth: '33.3333%', alignSelf: 'flex-end' }}>
|
|
631
|
+
<button
|
|
632
|
+
type="button"
|
|
633
|
+
className={`${styles.btn} ${styles.btnSuccess} ${styles.mx2}`}
|
|
634
|
+
style={{ height: '40px', width: '100px' }}
|
|
635
|
+
disabled={saving || testList.length === 0}
|
|
636
|
+
onClick={handleSave}
|
|
637
|
+
>
|
|
638
|
+
{saving ? 'Saving...' : 'Save'}
|
|
639
|
+
</button>
|
|
640
|
+
<button
|
|
641
|
+
type="button"
|
|
642
|
+
className={`${styles.btn} ${styles.btnDanger}`}
|
|
643
|
+
style={{ height: '40px', width: '100px' }}
|
|
644
|
+
disabled={saving}
|
|
645
|
+
onClick={() => navigateTo('/openmrs/spa/samplecollection')}
|
|
646
|
+
>
|
|
647
|
+
Back
|
|
648
|
+
</button>
|
|
649
|
+
</div>
|
|
650
|
+
|
|
636
651
|
</div>
|
|
652
|
+
|
|
637
653
|
</div>
|
|
638
|
-
</
|
|
654
|
+
</div>
|
|
639
655
|
</div>
|
|
640
656
|
);
|
|
641
657
|
};
|