@sasindi/samplecollection 1.0.0
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/LICENSE +354 -0
- package/README.md +123 -0
- package/dist/117.js +1 -0
- package/dist/117.js.map +1 -0
- package/dist/197.js +1 -0
- package/dist/197.js.map +1 -0
- package/dist/237.js +1 -0
- package/dist/237.js.map +1 -0
- package/dist/30.js +1 -0
- package/dist/30.js.map +1 -0
- package/dist/362.js +1 -0
- package/dist/362.js.map +1 -0
- package/dist/410.js +1 -0
- package/dist/410.js.map +1 -0
- package/dist/435.js +1 -0
- package/dist/435.js.map +1 -0
- package/dist/480.js +1 -0
- package/dist/480.js.map +1 -0
- package/dist/517.js +1 -0
- package/dist/517.js.map +1 -0
- package/dist/529.js +1 -0
- package/dist/529.js.map +1 -0
- package/dist/538.js +1 -0
- package/dist/538.js.map +1 -0
- package/dist/578.js +1 -0
- package/dist/578.js.map +1 -0
- package/dist/584.js +22 -0
- package/dist/584.js.map +1 -0
- package/dist/652.js +1 -0
- package/dist/652.js.map +1 -0
- package/dist/668.js +1 -0
- package/dist/668.js.map +1 -0
- package/dist/749.js +1 -0
- package/dist/749.js.map +1 -0
- package/dist/898.js +1 -0
- package/dist/898.js.map +1 -0
- package/dist/964.js +1 -0
- package/dist/964.js.map +1 -0
- package/dist/976.js +1 -0
- package/dist/976.js.map +1 -0
- package/dist/98.js +1 -0
- package/dist/98.js.map +1 -0
- package/dist/981.js +43 -0
- package/dist/981.js.map +1 -0
- package/dist/997.js +1 -0
- package/dist/997.js.map +1 -0
- package/dist/main.js +6 -0
- package/dist/main.js.map +1 -0
- package/dist/openmrs-esm-samplecollection.js +6 -0
- package/dist/openmrs-esm-samplecollection.js.buildmanifest.json +748 -0
- package/dist/openmrs-esm-samplecollection.js.map +1 -0
- package/dist/routes.json +1 -0
- package/package.json +111 -0
- package/src/config-schema.ts +21 -0
- package/src/constants.ts +1 -0
- package/src/declarations.d.ts +23 -0
- package/src/index.ts +28 -0
- package/src/root.component.test.tsx +12 -0
- package/src/root.component.tsx +15 -0
- package/src/root.scss +5 -0
- package/src/routes.json +14 -0
- package/src/samplecollection.component.tsx +280 -0
- package/src/samplecollection.scss +163 -0
- package/src/samplecollectionroom.component.tsx +640 -0
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
import React, { useState, useEffect } from 'react';
|
|
2
|
+
import { useNavigate } from 'react-router-dom';
|
|
3
|
+
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
|
+
import styles from './samplecollection.scss';
|
|
20
|
+
|
|
21
|
+
const SearchIcon = () => (
|
|
22
|
+
<svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
|
|
23
|
+
<path d="M15 14.3l-3.3-3.3c.9-1.1 1.4-2.5 1.4-4 0-3.3-2.7-6-6-6S1.1 3.7 1.1 7s2.7 6 6 6c1.5 0 2.9-.5 4-1.4l3.3 3.3.6-.6zM7.1 12c-2.8 0-5-2.2-5-5s2.2-5 5-5 5 2.2 5 5-2.2 5-5 5z" />
|
|
24
|
+
</svg>
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
const Samplecollection: React.FC = () => {
|
|
28
|
+
const { t } = useTranslation();
|
|
29
|
+
const navigate = useNavigate();
|
|
30
|
+
|
|
31
|
+
// State variables
|
|
32
|
+
const [locationUuid, setLocationUuid] = useState<string>('');
|
|
33
|
+
const [locationName, setLocationName] = useState<string>('Loading location...');
|
|
34
|
+
const [wardSections, setWardSections] = useState<string[]>([]);
|
|
35
|
+
const [sectionFilter, setSectionFilter] = useState<string>('ALL');
|
|
36
|
+
const [searchQuery, setSearchQuery] = useState<string>('');
|
|
37
|
+
const [data, setData] = useState<any[]>([]);
|
|
38
|
+
const [loading, setLoading] = useState<boolean>(true);
|
|
39
|
+
|
|
40
|
+
// Pagination state
|
|
41
|
+
const [page, setPage] = useState<number>(1);
|
|
42
|
+
const [pageSize, setPageSize] = useState<number>(50);
|
|
43
|
+
const [totalRecords, setTotalRecords] = useState<number>(0);
|
|
44
|
+
const [filteredRecords, setFilteredRecords] = useState<number>(0);
|
|
45
|
+
|
|
46
|
+
// Load Session and Location context
|
|
47
|
+
useEffect(() => {
|
|
48
|
+
async function initSession() {
|
|
49
|
+
try {
|
|
50
|
+
const sessionRes = await fetch('/openmrs/ws/rest/v1/session');
|
|
51
|
+
if (!sessionRes.ok) throw new Error('Session request failed');
|
|
52
|
+
const sessionData = await sessionRes.json();
|
|
53
|
+
const personUuid = sessionData.user.person.uuid;
|
|
54
|
+
|
|
55
|
+
const personRes = await fetch(`/openmrs/ws/rest/v1/person/${personUuid}`);
|
|
56
|
+
if (!personRes.ok) throw new Error('Person details request failed');
|
|
57
|
+
const personData = await personRes.json();
|
|
58
|
+
|
|
59
|
+
let locUuid = '';
|
|
60
|
+
if (personData.attributes) {
|
|
61
|
+
personData.attributes.forEach((attr: any) => {
|
|
62
|
+
if (attr.display) {
|
|
63
|
+
const [key, value] = attr.display.split('=');
|
|
64
|
+
if (key && value && key.trim() === 'Institute Id') {
|
|
65
|
+
locUuid = value.trim();
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (locUuid) {
|
|
72
|
+
setLocationUuid(locUuid);
|
|
73
|
+
|
|
74
|
+
// Get Location Details
|
|
75
|
+
const locRes = await fetch(`/openmrs/ws/rest/v1/location/${locUuid}`);
|
|
76
|
+
if (locRes.ok) {
|
|
77
|
+
const locData = await locRes.json();
|
|
78
|
+
setLocationName(locData.display || 'OpenMRS Clinic');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Load Ward Sections
|
|
82
|
+
const wardRes = await fetch(`/openmrs/ws/rest/v1/samplecollection/getwardsections/${locUuid}`);
|
|
83
|
+
if (wardRes.ok) {
|
|
84
|
+
const wardData = await wardRes.json();
|
|
85
|
+
const sections = (wardData.wardSections || []).map((name: string) => name.split('@@')[0]);
|
|
86
|
+
setWardSections(sections);
|
|
87
|
+
}
|
|
88
|
+
} else {
|
|
89
|
+
setLocationName('No clinic location assigned');
|
|
90
|
+
setLoading(false);
|
|
91
|
+
}
|
|
92
|
+
} catch (err) {
|
|
93
|
+
console.error('Error during context initialization:', err);
|
|
94
|
+
setLocationName('Error loading location');
|
|
95
|
+
setLoading(false);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
initSession();
|
|
100
|
+
}, []);
|
|
101
|
+
|
|
102
|
+
// Fetch serverside table data when location, filter, search, page or pageSize changes
|
|
103
|
+
useEffect(() => {
|
|
104
|
+
if (!locationUuid) return;
|
|
105
|
+
|
|
106
|
+
async function fetchTableData() {
|
|
107
|
+
setLoading(true);
|
|
108
|
+
try {
|
|
109
|
+
const start = (page - 1) * pageSize;
|
|
110
|
+
const searchVal = encodeURIComponent(searchQuery);
|
|
111
|
+
const sectionVal = encodeURIComponent(sectionFilter);
|
|
112
|
+
|
|
113
|
+
const url = `/openmrs/ws/rest/v1/samplecollection/loadtable/serverside/${locationUuid}?draw=${page}&start=${start}&length=${pageSize}&search[value]=${searchVal}§ion=${sectionVal}`;
|
|
114
|
+
const response = await fetch(url);
|
|
115
|
+
if (!response.ok) throw new Error('Failed to load table data');
|
|
116
|
+
const resData = await response.json();
|
|
117
|
+
|
|
118
|
+
setData(resData.data || []);
|
|
119
|
+
setTotalRecords(resData.recordsTotal || 0);
|
|
120
|
+
setFilteredRecords(resData.recordsFiltered || 0);
|
|
121
|
+
} catch (err) {
|
|
122
|
+
console.error('Error fetching table data:', err);
|
|
123
|
+
} finally {
|
|
124
|
+
setLoading(false);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Debounce data fetching slightly if search query is changing rapidly
|
|
129
|
+
const delayDebounceFn = setTimeout(() => {
|
|
130
|
+
fetchTableData();
|
|
131
|
+
}, 300);
|
|
132
|
+
|
|
133
|
+
return () => clearTimeout(delayDebounceFn);
|
|
134
|
+
}, [locationUuid, sectionFilter, searchQuery, page, pageSize]);
|
|
135
|
+
|
|
136
|
+
const handleSelectPatient = (phnNo: string, section: string, progress: string) => {
|
|
137
|
+
localStorage.setItem('phnNo', phnNo);
|
|
138
|
+
localStorage.setItem('section', section);
|
|
139
|
+
localStorage.setItem('progress', progress || '');
|
|
140
|
+
navigate('/samplecollection/room');
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
return (
|
|
144
|
+
<div className={styles.container}>
|
|
145
|
+
<Tile className={styles.tile}>
|
|
146
|
+
{/* Header Section */}
|
|
147
|
+
<div className={styles.headerRow}>
|
|
148
|
+
<h1 className={styles.heading}>
|
|
149
|
+
{t('samplecollectionHeading', 'Sample Collection List')}
|
|
150
|
+
</h1>
|
|
151
|
+
<div className={styles.locationBadge}>
|
|
152
|
+
<span className="icon-hospital" />
|
|
153
|
+
<span>{locationName}</span>
|
|
154
|
+
</div>
|
|
155
|
+
</div>
|
|
156
|
+
|
|
157
|
+
{/* Filter and Search controls */}
|
|
158
|
+
<div className={styles.filterRow}>
|
|
159
|
+
<Select
|
|
160
|
+
id="sectionFilter"
|
|
161
|
+
labelText={t('sectionLabel', 'Section')}
|
|
162
|
+
value={sectionFilter}
|
|
163
|
+
onChange={(e) => {
|
|
164
|
+
setSectionFilter(e.target.value);
|
|
165
|
+
setPage(1); // Reset page on filter change
|
|
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>
|
|
176
|
+
|
|
177
|
+
<TextInput
|
|
178
|
+
id="searchQuery"
|
|
179
|
+
labelText={t('searchLabel', 'Search (PHN, Name, Test)')}
|
|
180
|
+
placeholder={t('searchPlaceholder', 'Type to search...')}
|
|
181
|
+
value={searchQuery}
|
|
182
|
+
onChange={(e) => {
|
|
183
|
+
setSearchQuery(e.target.value);
|
|
184
|
+
setPage(1); // Reset page on search
|
|
185
|
+
}}
|
|
186
|
+
/>
|
|
187
|
+
</div>
|
|
188
|
+
|
|
189
|
+
{/* Loading Indicator */}
|
|
190
|
+
{loading && <Loading description="Loading data..." withOverlay={false} />}
|
|
191
|
+
|
|
192
|
+
{/* Main Table */}
|
|
193
|
+
<div className={styles.tableContainer}>
|
|
194
|
+
<Table>
|
|
195
|
+
<TableHead>
|
|
196
|
+
<TableRow>
|
|
197
|
+
<TableHeader>No</TableHeader>
|
|
198
|
+
<TableHeader>Section</TableHeader>
|
|
199
|
+
<TableHeader>PHN No</TableHeader>
|
|
200
|
+
<TableHeader>Name</TableHeader>
|
|
201
|
+
<TableHeader>Gender</TableHeader>
|
|
202
|
+
<TableHeader>Age</TableHeader>
|
|
203
|
+
<TableHeader>Test Name</TableHeader>
|
|
204
|
+
<TableHeader />
|
|
205
|
+
</TableRow>
|
|
206
|
+
</TableHead>
|
|
207
|
+
<TableBody>
|
|
208
|
+
{data.length === 0 ? (
|
|
209
|
+
<TableRow>
|
|
210
|
+
<TableCell colSpan={8} style={{ textAlign: 'center', padding: '2rem' }}>
|
|
211
|
+
{loading ? 'Fetching data...' : 'No sample collections found.'}
|
|
212
|
+
</TableCell>
|
|
213
|
+
</TableRow>
|
|
214
|
+
) : (
|
|
215
|
+
data.map((row, index) => {
|
|
216
|
+
const phnNo = row[0];
|
|
217
|
+
const patientName = row[1];
|
|
218
|
+
const testName = row[2];
|
|
219
|
+
const gender = row[3];
|
|
220
|
+
const age = row[4];
|
|
221
|
+
const section = row[7];
|
|
222
|
+
const specimenStatus = row[8]; // 'Inadequate', 'Error'
|
|
223
|
+
const progress = row[9];
|
|
224
|
+
const rowIndex = (page - 1) * pageSize + index + 1;
|
|
225
|
+
|
|
226
|
+
let trClass = '';
|
|
227
|
+
if (specimenStatus === 'Inadequate') {
|
|
228
|
+
trClass = styles.rowInadequate;
|
|
229
|
+
} else if (specimenStatus === 'Error') {
|
|
230
|
+
trClass = styles.rowError;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return (
|
|
234
|
+
<TableRow key={`${phnNo}-${section}-${index}`} className={trClass}>
|
|
235
|
+
<TableCell>{rowIndex}</TableCell>
|
|
236
|
+
<TableCell>{section}</TableCell>
|
|
237
|
+
<TableCell>{phnNo}</TableCell>
|
|
238
|
+
<TableCell>{patientName}</TableCell>
|
|
239
|
+
<TableCell>{gender}</TableCell>
|
|
240
|
+
<TableCell>{age}</TableCell>
|
|
241
|
+
<TableCell>{testName}</TableCell>
|
|
242
|
+
<TableCell>
|
|
243
|
+
<Button
|
|
244
|
+
kind="primary"
|
|
245
|
+
size="sm"
|
|
246
|
+
onClick={() => handleSelectPatient(phnNo, section, progress)}
|
|
247
|
+
>
|
|
248
|
+
{t('selectBtn', 'Select')}
|
|
249
|
+
</Button>
|
|
250
|
+
</TableCell>
|
|
251
|
+
</TableRow>
|
|
252
|
+
);
|
|
253
|
+
})
|
|
254
|
+
)}
|
|
255
|
+
</TableBody>
|
|
256
|
+
</Table>
|
|
257
|
+
</div>
|
|
258
|
+
|
|
259
|
+
{/* Pagination */}
|
|
260
|
+
{filteredRecords > 0 && (
|
|
261
|
+
<Pagination
|
|
262
|
+
backwardText="Previous page"
|
|
263
|
+
forwardText="Next page"
|
|
264
|
+
itemsPerPageText="Items per page:"
|
|
265
|
+
onChange={({ page, pageSize }) => {
|
|
266
|
+
setPage(page);
|
|
267
|
+
setPageSize(pageSize);
|
|
268
|
+
}}
|
|
269
|
+
page={page}
|
|
270
|
+
pageSize={pageSize}
|
|
271
|
+
pageSizes={[10, 25, 50, 100]}
|
|
272
|
+
totalItems={filteredRecords}
|
|
273
|
+
/>
|
|
274
|
+
)}
|
|
275
|
+
</Tile>
|
|
276
|
+
</div>
|
|
277
|
+
);
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
export default Samplecollection;
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
@use '@carbon/layout';
|
|
2
|
+
@use '@carbon/type';
|
|
3
|
+
|
|
4
|
+
.container {
|
|
5
|
+
padding: layout.$spacing-06;
|
|
6
|
+
max-width: 1200px;
|
|
7
|
+
margin: 0 auto;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.tile {
|
|
11
|
+
padding: layout.$spacing-06;
|
|
12
|
+
margin-bottom: layout.$spacing-05;
|
|
13
|
+
background: var(--cds-layer-01, #ffffff);
|
|
14
|
+
border-radius: 8px;
|
|
15
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
|
|
16
|
+
border: 1px solid var(--cds-border-subtle-01, #e0e0e0);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.headerRow {
|
|
20
|
+
display: flex;
|
|
21
|
+
justify-content: space-between;
|
|
22
|
+
align-items: center;
|
|
23
|
+
margin-bottom: layout.$spacing-06;
|
|
24
|
+
border-bottom: 1px solid var(--cds-border-subtle-01, #e0e0e0);
|
|
25
|
+
padding-bottom: layout.$spacing-04;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.heading {
|
|
29
|
+
@include type.type-style('heading-04');
|
|
30
|
+
color: #009384;
|
|
31
|
+
margin: 0;
|
|
32
|
+
font-weight: 600;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.locationBadge {
|
|
36
|
+
display: flex;
|
|
37
|
+
align-items: center;
|
|
38
|
+
gap: layout.$spacing-03;
|
|
39
|
+
font-weight: 600;
|
|
40
|
+
color: var(--cds-text-secondary, #525252);
|
|
41
|
+
background: var(--cds-layer-02, #f4f4f4);
|
|
42
|
+
padding: layout.$spacing-02 layout.$spacing-04;
|
|
43
|
+
border-radius: 16px;
|
|
44
|
+
font-size: 14px;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.filterRow {
|
|
48
|
+
display: flex;
|
|
49
|
+
gap: layout.$spacing-05;
|
|
50
|
+
align-items: flex-end;
|
|
51
|
+
margin-bottom: layout.$spacing-05;
|
|
52
|
+
flex-wrap: wrap;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.tableContainer {
|
|
56
|
+
margin-top: layout.$spacing-05;
|
|
57
|
+
margin-bottom: layout.$spacing-05;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.rowInadequate {
|
|
61
|
+
background-color: #fff3cd !important;
|
|
62
|
+
transition: background-color 0.2s ease;
|
|
63
|
+
&:hover {
|
|
64
|
+
background-color: #ffeeb5 !important;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.rowError {
|
|
69
|
+
background-color: #f8d7da !important;
|
|
70
|
+
transition: background-color 0.2s ease;
|
|
71
|
+
&:hover {
|
|
72
|
+
background-color: #f5c2c7 !important;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/* Patient Card Info for Room view */
|
|
77
|
+
.patientCard {
|
|
78
|
+
display: grid;
|
|
79
|
+
grid-template-columns: 1fr 120px;
|
|
80
|
+
gap: layout.$spacing-05;
|
|
81
|
+
align-items: center;
|
|
82
|
+
background: var(--cds-layer-01, #ffffff);
|
|
83
|
+
padding: layout.$spacing-05;
|
|
84
|
+
border-radius: 8px;
|
|
85
|
+
border: 1px solid var(--cds-border-subtle-01, #e0e0e0);
|
|
86
|
+
margin-bottom: layout.$spacing-05;
|
|
87
|
+
|
|
88
|
+
@media (max-width: 768px) {
|
|
89
|
+
grid-template-columns: 1fr;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.patientGrid {
|
|
94
|
+
display: grid;
|
|
95
|
+
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
|
96
|
+
gap: layout.$spacing-05;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.patientField {
|
|
100
|
+
display: flex;
|
|
101
|
+
flex-direction: column;
|
|
102
|
+
gap: layout.$spacing-02;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.fieldLabel {
|
|
106
|
+
font-size: 12px;
|
|
107
|
+
color: var(--cds-text-helper, #6f6f6f);
|
|
108
|
+
text-transform: uppercase;
|
|
109
|
+
font-weight: 600;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.fieldValue {
|
|
113
|
+
font-size: 16px;
|
|
114
|
+
color: var(--cds-text-primary, #161616);
|
|
115
|
+
font-weight: 500;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.avatarContainer {
|
|
119
|
+
display: flex;
|
|
120
|
+
justify-content: center;
|
|
121
|
+
align-items: center;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.avatarImg {
|
|
125
|
+
width: 100px;
|
|
126
|
+
height: 100px;
|
|
127
|
+
border-radius: 50%;
|
|
128
|
+
object-fit: cover;
|
|
129
|
+
border: 3px solid #009384;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.roomFormSection {
|
|
133
|
+
margin-top: layout.$spacing-06;
|
|
134
|
+
border-top: 1px solid var(--cds-border-subtle-01, #e0e0e0);
|
|
135
|
+
padding-top: layout.$spacing-06;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.formGrid {
|
|
139
|
+
display: grid;
|
|
140
|
+
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
|
|
141
|
+
gap: layout.$spacing-06;
|
|
142
|
+
margin-bottom: layout.$spacing-06;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.actionsContainer {
|
|
146
|
+
display: flex;
|
|
147
|
+
justify-content: flex-end;
|
|
148
|
+
gap: layout.$spacing-04;
|
|
149
|
+
margin-top: layout.$spacing-06;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.paginationContainer {
|
|
153
|
+
display: flex;
|
|
154
|
+
justify-content: flex-end;
|
|
155
|
+
align-items: center;
|
|
156
|
+
gap: layout.$spacing-05;
|
|
157
|
+
margin-top: layout.$spacing-04;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
.checkboxCell {
|
|
161
|
+
width: 48px;
|
|
162
|
+
text-align: center;
|
|
163
|
+
}
|