@sasindi/samplecollection 1.0.0 → 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/30.js +1 -1
- package/dist/30.js.map +1 -1
- package/dist/340.js +1 -0
- package/dist/340.js.map +1 -0
- package/dist/425.js +1 -0
- package/dist/425.js.map +1 -0
- package/dist/529.js +1 -1
- package/dist/529.js.map +1 -1
- package/dist/577.js +1 -0
- package/dist/577.js.map +1 -0
- package/dist/981.js +2 -2
- 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 +92 -42
- package/dist/openmrs-esm-samplecollection.js.map +1 -1
- package/dist/routes.json +1 -1
- package/package.json +1 -1
- package/src/constants.ts +1 -1
- package/src/index.ts +1 -0
- package/src/root.component.tsx +3 -10
- package/src/routes.json +6 -0
- package/src/samplecollection.component.tsx +167 -150
- package/src/samplecollection.scss +235 -101
- package/src/samplecollectionroom.component.tsx +234 -218
- package/dist/435.js +0 -1
- package/dist/435.js.map +0 -1
package/src/routes.json
CHANGED
|
@@ -1,32 +1,14 @@
|
|
|
1
1
|
import React, { useState, useEffect } from 'react';
|
|
2
|
-
import { useNavigate } from 'react-router-dom';
|
|
3
2
|
import { useTranslation } from 'react-i18next';
|
|
4
|
-
import {
|
|
5
|
-
Tile,
|
|
6
|
-
Select,
|
|
7
|
-
SelectItem,
|
|
8
|
-
TextInput,
|
|
9
|
-
Table,
|
|
10
|
-
TableHead,
|
|
11
|
-
TableRow,
|
|
12
|
-
TableHeader,
|
|
13
|
-
TableBody,
|
|
14
|
-
TableCell,
|
|
15
|
-
Button,
|
|
16
|
-
Pagination,
|
|
17
|
-
Loading
|
|
18
|
-
} from '@carbon/react';
|
|
19
3
|
import styles from './samplecollection.scss';
|
|
20
4
|
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
);
|
|
5
|
+
const navigateTo = (url: string) => {
|
|
6
|
+
window.history.pushState({}, '', url);
|
|
7
|
+
window.dispatchEvent(new PopStateEvent('popstate'));
|
|
8
|
+
};
|
|
26
9
|
|
|
27
10
|
const Samplecollection: React.FC = () => {
|
|
28
11
|
const { t } = useTranslation();
|
|
29
|
-
const navigate = useNavigate();
|
|
30
12
|
|
|
31
13
|
// State variables
|
|
32
14
|
const [locationUuid, setLocationUuid] = useState<string>('');
|
|
@@ -39,8 +21,7 @@ const Samplecollection: React.FC = () => {
|
|
|
39
21
|
|
|
40
22
|
// Pagination state
|
|
41
23
|
const [page, setPage] = useState<number>(1);
|
|
42
|
-
const [pageSize
|
|
43
|
-
const [totalRecords, setTotalRecords] = useState<number>(0);
|
|
24
|
+
const [pageSize] = useState<number>(50);
|
|
44
25
|
const [filteredRecords, setFilteredRecords] = useState<number>(0);
|
|
45
26
|
|
|
46
27
|
// Load Session and Location context
|
|
@@ -116,7 +97,6 @@ const Samplecollection: React.FC = () => {
|
|
|
116
97
|
const resData = await response.json();
|
|
117
98
|
|
|
118
99
|
setData(resData.data || []);
|
|
119
|
-
setTotalRecords(resData.recordsTotal || 0);
|
|
120
100
|
setFilteredRecords(resData.recordsFiltered || 0);
|
|
121
101
|
} catch (err) {
|
|
122
102
|
console.error('Error fetching table data:', err);
|
|
@@ -125,7 +105,6 @@ const Samplecollection: React.FC = () => {
|
|
|
125
105
|
}
|
|
126
106
|
}
|
|
127
107
|
|
|
128
|
-
// Debounce data fetching slightly if search query is changing rapidly
|
|
129
108
|
const delayDebounceFn = setTimeout(() => {
|
|
130
109
|
fetchTableData();
|
|
131
110
|
}, 300);
|
|
@@ -137,142 +116,180 @@ const Samplecollection: React.FC = () => {
|
|
|
137
116
|
localStorage.setItem('phnNo', phnNo);
|
|
138
117
|
localStorage.setItem('section', section);
|
|
139
118
|
localStorage.setItem('progress', progress || '');
|
|
140
|
-
|
|
119
|
+
navigateTo('/openmrs/spa/samplecollection/room');
|
|
141
120
|
};
|
|
142
121
|
|
|
122
|
+
const startIndex = (page - 1) * pageSize;
|
|
123
|
+
|
|
143
124
|
return (
|
|
144
125
|
<div className={styles.container}>
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
<div className={styles.
|
|
148
|
-
<
|
|
149
|
-
|
|
150
|
-
</h1>
|
|
151
|
-
<div className={styles.locationBadge}>
|
|
152
|
-
<span className="icon-hospital" />
|
|
153
|
-
<span>{locationName}</span>
|
|
154
|
-
</div>
|
|
126
|
+
{/* Clinic/Hospital Header */}
|
|
127
|
+
<div style={{ display: 'flex', justifyContent: 'flex-end', marginBottom: '10px' }}>
|
|
128
|
+
<div className={styles.locationBadge} style={{ background: '#e9ecef', color: '#495057' }}>
|
|
129
|
+
<span className="icon-hospital" />
|
|
130
|
+
<span id="lblInstituteName" style={{ fontWeight: 'bold' }}>{locationName}</span>
|
|
155
131
|
</div>
|
|
132
|
+
</div>
|
|
156
133
|
|
|
157
|
-
|
|
158
|
-
<div className={styles.
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
}}
|
|
167
|
-
style={{ width: '200px' }}
|
|
168
|
-
>
|
|
169
|
-
<SelectItem value="ALL" text={t('allSections', 'All')} />
|
|
170
|
-
<SelectItem value="OPD" text="OPD" />
|
|
171
|
-
<SelectItem value="Clinic" text="Clinic" />
|
|
172
|
-
{wardSections.map((sect) => (
|
|
173
|
-
<SelectItem key={sect} value={sect} text={sect} />
|
|
174
|
-
))}
|
|
175
|
-
</Select>
|
|
134
|
+
<div className={styles.card}>
|
|
135
|
+
<div className={styles.cardBody}>
|
|
136
|
+
|
|
137
|
+
{/* Section title */}
|
|
138
|
+
<div className={styles.col12} style={{ marginBottom: '1rem', padding: 0 }}>
|
|
139
|
+
<h2 className={styles.heading} style={{ margin: 0 }}>
|
|
140
|
+
{t('samplecollectionHeading', 'Sample Collection List')}
|
|
141
|
+
</h2>
|
|
142
|
+
</div>
|
|
176
143
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
144
|
+
{/* Filters & Search Row */}
|
|
145
|
+
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '1rem', flexWrap: 'wrap', gap: '10px' }}>
|
|
146
|
+
<div className={`${styles.dFlex} ${styles.alignItemsCenter}`}>
|
|
147
|
+
<label htmlFor="sectionFilter" className={styles.labelCompact} style={{ fontWeight: 'bold', width: 'auto', marginRight: '8px' }}>
|
|
148
|
+
Section:
|
|
149
|
+
</label>
|
|
150
|
+
<select
|
|
151
|
+
id="sectionFilter"
|
|
152
|
+
className={styles.formControl}
|
|
153
|
+
style={{ width: 'auto', minWidth: '160px', height: '30px' }}
|
|
154
|
+
value={sectionFilter}
|
|
155
|
+
onChange={(e) => {
|
|
156
|
+
setSectionFilter(e.target.value);
|
|
157
|
+
setPage(1);
|
|
158
|
+
}}
|
|
159
|
+
>
|
|
160
|
+
<option value="ALL">All</option>
|
|
161
|
+
<option value="OPD">OPD</option>
|
|
162
|
+
<option value="Clinic">Clinic</option>
|
|
163
|
+
{wardSections.map((sect) => (
|
|
164
|
+
<option key={sect} value={sect}>{sect}</option>
|
|
165
|
+
))}
|
|
166
|
+
</select>
|
|
167
|
+
</div>
|
|
188
168
|
|
|
189
|
-
|
|
190
|
-
|
|
169
|
+
<div className={`${styles.dFlex} ${styles.alignItemsCenter}`}>
|
|
170
|
+
<label htmlFor="searchQuery" className={styles.labelCompact} style={{ fontWeight: 'bold', width: 'auto', marginRight: '8px' }}>
|
|
171
|
+
Search:
|
|
172
|
+
</label>
|
|
173
|
+
<input
|
|
174
|
+
id="searchQuery"
|
|
175
|
+
type="text"
|
|
176
|
+
className={styles.formControl}
|
|
177
|
+
placeholder="Type search query..."
|
|
178
|
+
style={{ width: '220px', height: '30px' }}
|
|
179
|
+
value={searchQuery}
|
|
180
|
+
onChange={(e) => {
|
|
181
|
+
setSearchQuery(e.target.value);
|
|
182
|
+
setPage(1);
|
|
183
|
+
}}
|
|
184
|
+
/>
|
|
185
|
+
</div>
|
|
186
|
+
</div>
|
|
191
187
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
188
|
+
{/* Table Container */}
|
|
189
|
+
<div className={styles.tableResponsive}>
|
|
190
|
+
<table className={`${styles.table} ${styles.tableBordered} ${styles.tableHover} ${styles.tableStriped}`}>
|
|
191
|
+
<thead>
|
|
192
|
+
<tr>
|
|
193
|
+
<th style={{ width: '50px' }}>No</th>
|
|
194
|
+
<th style={{ whiteSpace: 'nowrap' }}>Section</th>
|
|
195
|
+
<th style={{ whiteSpace: 'nowrap' }}>PHN No</th>
|
|
196
|
+
<th style={{ whiteSpace: 'nowrap' }}>Name</th>
|
|
197
|
+
<th style={{ whiteSpace: 'nowrap' }}>Gender</th>
|
|
198
|
+
<th style={{ whiteSpace: 'nowrap' }}>Age</th>
|
|
199
|
+
<th style={{ whiteSpace: 'nowrap' }}>Test Name</th>
|
|
200
|
+
<th style={{ width: '80px' }}></th>
|
|
201
|
+
</tr>
|
|
202
|
+
</thead>
|
|
203
|
+
<tbody>
|
|
204
|
+
{loading && data.length === 0 ? (
|
|
205
|
+
<tr>
|
|
206
|
+
<td colSpan={8} style={{ textAlign: 'center', padding: '20px' }}>
|
|
207
|
+
Loading data...
|
|
208
|
+
</td>
|
|
209
|
+
</tr>
|
|
210
|
+
) : data.length === 0 ? (
|
|
211
|
+
<tr>
|
|
212
|
+
<td colSpan={8} style={{ textAlign: 'center', padding: '20px' }}>
|
|
213
|
+
No sample collections found.
|
|
214
|
+
</td>
|
|
215
|
+
</tr>
|
|
216
|
+
) : (
|
|
217
|
+
data.map((row, index) => {
|
|
218
|
+
const phnNo = row[0];
|
|
219
|
+
const patientName = row[1];
|
|
220
|
+
const testName = row[2];
|
|
221
|
+
const gender = row[3];
|
|
222
|
+
const age = row[4];
|
|
223
|
+
const section = row[7];
|
|
224
|
+
const specimenStatus = row[8];
|
|
225
|
+
const progress = row[9];
|
|
226
|
+
const rowIndex = startIndex + index + 1;
|
|
225
227
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
228
|
+
let rowClass = '';
|
|
229
|
+
if (specimenStatus === 'Inadequate') {
|
|
230
|
+
rowClass = styles.rowInadequate;
|
|
231
|
+
} else if (specimenStatus === 'Error') {
|
|
232
|
+
rowClass = styles.rowError;
|
|
233
|
+
}
|
|
232
234
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
235
|
+
return (
|
|
236
|
+
<tr key={`${phnNo}-${section}-${index}`} className={rowClass}>
|
|
237
|
+
<td>{rowIndex}</td>
|
|
238
|
+
<td>{section}</td>
|
|
239
|
+
<td>{phnNo}</td>
|
|
240
|
+
<td>{patientName}</td>
|
|
241
|
+
<td>{gender}</td>
|
|
242
|
+
<td>{age}</td>
|
|
243
|
+
<td>{testName}</td>
|
|
244
|
+
<td style={{ textAlign: 'center' }}>
|
|
245
|
+
<button
|
|
246
|
+
type="button"
|
|
247
|
+
className={`${styles.btn} ${styles.btnPrimary}`}
|
|
248
|
+
style={{ padding: '2px 8px', fontSize: '12px' }}
|
|
249
|
+
onClick={() => handleSelectPatient(phnNo, section, progress)}
|
|
250
|
+
>
|
|
251
|
+
Select
|
|
252
|
+
</button>
|
|
253
|
+
</td>
|
|
254
|
+
</tr>
|
|
255
|
+
);
|
|
256
|
+
})
|
|
257
|
+
)}
|
|
258
|
+
</tbody>
|
|
259
|
+
</table>
|
|
260
|
+
</div>
|
|
258
261
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
262
|
+
{/* Simple Bootstrap-like Pagination */}
|
|
263
|
+
{filteredRecords > 0 && (
|
|
264
|
+
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginTop: '1rem', flexWrap: 'wrap' }}>
|
|
265
|
+
<div style={{ fontSize: '14px', color: '#6c757d' }}>
|
|
266
|
+
Showing {startIndex + 1} to {Math.min(startIndex + pageSize, filteredRecords)} of {filteredRecords} entries
|
|
267
|
+
</div>
|
|
268
|
+
<div style={{ display: 'flex', gap: '5px' }}>
|
|
269
|
+
<button
|
|
270
|
+
type="button"
|
|
271
|
+
className={`${styles.btn} ${styles.btnPrimary}`}
|
|
272
|
+
style={{ padding: '4px 12px' }}
|
|
273
|
+
disabled={page === 1}
|
|
274
|
+
onClick={() => setPage((p) => p - 1)}
|
|
275
|
+
>
|
|
276
|
+
Previous
|
|
277
|
+
</button>
|
|
278
|
+
<button
|
|
279
|
+
type="button"
|
|
280
|
+
className={`${styles.btn} ${styles.btnPrimary}`}
|
|
281
|
+
style={{ padding: '4px 12px' }}
|
|
282
|
+
disabled={page * pageSize >= filteredRecords}
|
|
283
|
+
onClick={() => setPage((p) => p + 1)}
|
|
284
|
+
>
|
|
285
|
+
Next
|
|
286
|
+
</button>
|
|
287
|
+
</div>
|
|
288
|
+
</div>
|
|
289
|
+
)}
|
|
290
|
+
|
|
291
|
+
</div>
|
|
292
|
+
</div>
|
|
276
293
|
</div>
|
|
277
294
|
);
|
|
278
295
|
};
|