@kenyaemr/esm-lab-manifest-app 5.2.1-pre.821

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.
Files changed (85) hide show
  1. package/.turbo/turbo-build.log +39 -0
  2. package/LICENSE.md +401 -0
  3. package/README.md +5 -0
  4. package/dist/130.js +2 -0
  5. package/dist/130.js.LICENSE.txt +3 -0
  6. package/dist/130.js.map +1 -0
  7. package/dist/152.js +1 -0
  8. package/dist/152.js.map +1 -0
  9. package/dist/255.js +2 -0
  10. package/dist/255.js.LICENSE.txt +9 -0
  11. package/dist/255.js.map +1 -0
  12. package/dist/303.js +1 -0
  13. package/dist/303.js.map +1 -0
  14. package/dist/397.js +1 -0
  15. package/dist/397.js.map +1 -0
  16. package/dist/574.js +1 -0
  17. package/dist/589.js +1 -0
  18. package/dist/589.js.map +1 -0
  19. package/dist/591.js +2 -0
  20. package/dist/591.js.LICENSE.txt +32 -0
  21. package/dist/591.js.map +1 -0
  22. package/dist/712.js +1 -0
  23. package/dist/712.js.map +1 -0
  24. package/dist/729.js +1 -0
  25. package/dist/729.js.map +1 -0
  26. package/dist/784.js +2 -0
  27. package/dist/784.js.LICENSE.txt +9 -0
  28. package/dist/784.js.map +1 -0
  29. package/dist/803.js +1 -0
  30. package/dist/803.js.map +1 -0
  31. package/dist/883.js +1 -0
  32. package/dist/883.js.map +1 -0
  33. package/dist/896.js +1 -0
  34. package/dist/896.js.map +1 -0
  35. package/dist/949.js +1 -0
  36. package/dist/949.js.map +1 -0
  37. package/dist/975.js +2 -0
  38. package/dist/975.js.LICENSE.txt +50 -0
  39. package/dist/975.js.map +1 -0
  40. package/dist/kenyaemr-esm-lab-manifest-app.js +1 -0
  41. package/dist/kenyaemr-esm-lab-manifest-app.js.buildmanifest.json +526 -0
  42. package/dist/kenyaemr-esm-lab-manifest-app.js.map +1 -0
  43. package/dist/main.js +1 -0
  44. package/dist/main.js.map +1 -0
  45. package/dist/routes.json +1 -0
  46. package/jest.config.js +8 -0
  47. package/package.json +55 -0
  48. package/src/component/lab-manifest-detail.component.tsx +21 -0
  49. package/src/component/lab-manifest.component.tsx +18 -0
  50. package/src/component/left-panel-link.component.tsx +41 -0
  51. package/src/config-schema.ts +5 -0
  52. package/src/counties.json +1494 -0
  53. package/src/declarations.d.ts +6 -0
  54. package/src/forms/lab-manifest-form.scss +126 -0
  55. package/src/forms/lab-manifest-form.workspace.tsx +357 -0
  56. package/src/header/lab-manifest-detail-header.component.tsx +74 -0
  57. package/src/header/lab-manifest-header.component.tsx +36 -0
  58. package/src/header/lab-manifest-header.scss +105 -0
  59. package/src/header/lab-manifest-illustration.component.tsx +13 -0
  60. package/src/hooks/index.ts +2 -0
  61. package/src/hooks/useActiveRequests.ts +26 -0
  62. package/src/hooks/useLabManifest.tsx +17 -0
  63. package/src/hooks/useLabManifests.ts +17 -0
  64. package/src/index.ts +36 -0
  65. package/src/lab-manifest.mock.ts +5 -0
  66. package/src/lab-manifest.resources.ts +108 -0
  67. package/src/metrics/lab-manifest-header.scss +22 -0
  68. package/src/metrics/lab-manifest-metric-value.component.tsx +25 -0
  69. package/src/metrics/lab-manifest-metrics-header.component.tsx +34 -0
  70. package/src/metrics/lab-manifest-metrics.component.tsx +27 -0
  71. package/src/metrics/lab-manifest-metrics.scss +17 -0
  72. package/src/root.component.tsx +19 -0
  73. package/src/root.scss +15 -0
  74. package/src/routes.json +33 -0
  75. package/src/setup-tests.ts +1 -0
  76. package/src/tables/lab-manifest-active-requests.component.tsx +161 -0
  77. package/src/tables/lab-manifest-samples.component.tsx +164 -0
  78. package/src/tables/lab-manifest-table.component.tsx +214 -0
  79. package/src/tables/lab-manifest-table.scss +49 -0
  80. package/src/tabs/lab-manifest-tabs-component.tsx +33 -0
  81. package/src/tabs/lab-manifest-tabs.scss +28 -0
  82. package/src/types/index.ts +75 -0
  83. package/translations/en.json +33 -0
  84. package/tsconfig.json +5 -0
  85. package/webpack.config.js +1 -0
@@ -0,0 +1,6 @@
1
+ declare module '@carbon/react';
2
+ declare module '*.css';
3
+ declare module '*.scss';
4
+ declare module '*.png';
5
+
6
+ declare type SideNavProps = object;
@@ -0,0 +1,126 @@
1
+ @use '@carbon/styles/scss/spacing';
2
+ @use '@carbon/styles/scss/type';
3
+ @use '@carbon/layout';
4
+ @import '~@openmrs/esm-styleguide/src/vars';
5
+
6
+ .heading {
7
+ @include type.type-style('heading-compact-01');
8
+ margin: spacing.$spacing-05 0 spacing.$spacing-05;
9
+ }
10
+
11
+ .warningContainer {
12
+ background-color: $carbon--red-50;
13
+ padding: spacing.$spacing-04;
14
+ margin: spacing.$spacing-03 0 spacing.$spacing-03;
15
+ display: flex;
16
+ justify-content: space-between;
17
+ .warning {
18
+ @include type.type-style('heading-compact-01');
19
+ color: $ui-05;
20
+ }
21
+ }
22
+
23
+ .form {
24
+ display: flex;
25
+ flex-direction: column;
26
+ justify-content: space-between;
27
+ width: 50%;
28
+ }
29
+
30
+ .grid {
31
+ margin: 0 spacing.$spacing-05;
32
+ padding: 0rem;
33
+ }
34
+
35
+ .input {
36
+ margin-top: spacing.$spacing-05;
37
+ }
38
+
39
+ .inputRow {
40
+ margin-top: spacing.$spacing-05;
41
+ width: 50%; // Adjust width as per your design requirements
42
+ }
43
+
44
+ .datePickersRow {
45
+ display: flex;
46
+ flex-wrap: nowrap;
47
+ gap: spacing.$spacing-05; // Adjust gap between columns
48
+ align-items: center;
49
+ }
50
+
51
+ .datePickerInput {
52
+ width: 100%;
53
+ }
54
+
55
+ .button {
56
+ height: spacing.$spacing-10;
57
+ display: flex;
58
+ align-content: flex-start;
59
+ align-items: baseline;
60
+ min-width: 20%;
61
+ }
62
+
63
+ .buttonSet {
64
+ padding: 0rem;
65
+ margin-top: spacing.$spacing-05;
66
+ display: flex;
67
+ justify-content: flex-end;
68
+ gap: spacing.$spacing-05;
69
+ margin-bottom: spacing.$spacing-05;
70
+ }
71
+ .inlineActions {
72
+ display: flex;
73
+ gap: spacing.$spacing-05; /* Adjust the spacing as needed */
74
+ }
75
+
76
+ .contactFormTitle {
77
+ @include type.type-style('heading-02');
78
+ display: flex;
79
+ align-items: center;
80
+ justify-content: space-between;
81
+ margin: spacing.$spacing-05;
82
+ row-gap: 1.5rem;
83
+ position: relative;
84
+
85
+ &::after {
86
+ content: '';
87
+ display: block;
88
+ width: 2rem;
89
+ border-bottom: 0.375rem solid var(--brand-03);
90
+ position: absolute;
91
+ bottom: -0.75rem;
92
+ left: 0;
93
+ }
94
+
95
+ & > span {
96
+ @include type.type-style('body-01');
97
+ }
98
+ }
99
+
100
+ .sectionHeader {
101
+ @include type.type-style('heading-02');
102
+ }
103
+
104
+ :global(.omrs-breakpoint-lt-desktop) {
105
+ .form {
106
+ height: var(--tablet-workspace-window-height);
107
+ }
108
+
109
+ .buttonSet {
110
+ padding: spacing.$spacing-06 spacing.$spacing-05;
111
+ background-color: $ui-02;
112
+ justify-content: flex-end;
113
+ gap: spacing.$spacing-05;
114
+ }
115
+ }
116
+
117
+ /* New Styles for Facility and Visit Type */
118
+ .facilityVisitRow {
119
+ display: flex;
120
+ flex-wrap: nowrap;
121
+ gap: spacing.$spacing-05; /* Adjust gap between columns */
122
+ }
123
+
124
+ .facilityColumn {
125
+ flex: 1 1 0%; /* Makes columns take up equal space */
126
+ }
@@ -0,0 +1,357 @@
1
+ import {
2
+ Button,
3
+ ButtonSet,
4
+ Column,
5
+ DatePicker,
6
+ DatePickerInput,
7
+ Dropdown,
8
+ Form,
9
+ Stack,
10
+ TextInput,
11
+ } from '@carbon/react';
12
+ import { zodResolver } from '@hookform/resolvers/zod';
13
+ import { DefaultWorkspaceProps, parseDate, showSnackbar, useLayoutType } from '@openmrs/esm-framework';
14
+ import React, { useEffect } from 'react';
15
+ import { Controller, useForm } from 'react-hook-form';
16
+ import { useTranslation } from 'react-i18next';
17
+ import { z } from 'zod';
18
+ import { LabManifestFilters, labManifestFormSchema, manifestTypes, saveLabManifest } from '../lab-manifest.resources';
19
+ import styles from './lab-manifest-form.scss';
20
+ import { County, MappedLabManifest } from '../types';
21
+ import { mutate } from 'swr';
22
+ interface LabManifestFormProps extends DefaultWorkspaceProps {
23
+ patientUuid: string;
24
+ manifest?: MappedLabManifest;
25
+ }
26
+
27
+ type ContactListFormType = z.infer<typeof labManifestFormSchema>;
28
+
29
+ const LabManifestForm: React.FC<LabManifestFormProps> = ({ closeWorkspace, manifest }) => {
30
+ const counties = require('../counties.json') as County[];
31
+ const form = useForm<ContactListFormType>({
32
+ defaultValues: {
33
+ ...manifest,
34
+ dispatchDate: manifest?.dispatchDate ? parseDate(manifest.dispatchDate) : undefined,
35
+ startDate: manifest?.startDate ? parseDate(manifest.startDate) : undefined,
36
+ endDate: manifest?.endDate ? parseDate(manifest.endDate) : undefined,
37
+ },
38
+ resolver: zodResolver(labManifestFormSchema),
39
+ });
40
+ const { t } = useTranslation();
41
+ const observableSelectedCounty = form.watch('county');
42
+ const layout = useLayoutType();
43
+ const controlSize = layout === 'tablet' ? 'xl' : 'sm';
44
+ const onSubmit = async (values: ContactListFormType) => {
45
+ try {
46
+ await saveLabManifest(values, manifest?.uuid);
47
+ if (manifest?.uuid) {
48
+ mutate((key) => {
49
+ return (
50
+ typeof key === 'string' &&
51
+ key.startsWith(`/ws/rest/v1/labmanifest/${manifest!.uuid}?status=${values.manifestStatus}`)
52
+ );
53
+ });
54
+ } else {
55
+ mutate((key) => {
56
+ return typeof key === 'string' && key.startsWith(`/ws/rest/v1/labmanifest?status=${values.manifestStatus}`);
57
+ });
58
+ }
59
+ closeWorkspace();
60
+ showSnackbar({ title: 'Success', kind: 'success', subtitle: 'Lab manifest created successfully!' });
61
+ } catch (error) {
62
+ showSnackbar({ title: 'Failure', kind: 'error', subtitle: 'Error creating lab manifest' });
63
+ }
64
+ };
65
+ return (
66
+ <Form onSubmit={form.handleSubmit(onSubmit)}>
67
+ <span className={styles.contactFormTitle}>{t('formTitle', 'Fill in the form details')}</span>
68
+ <Stack gap={4} className={styles.grid}>
69
+ <Column>
70
+ <Controller
71
+ control={form.control}
72
+ name="startDate"
73
+ render={({ field }) => (
74
+ <DatePicker
75
+ dateFormat="d/m/Y"
76
+ id="startDate"
77
+ datePickerType="single"
78
+ {...field}
79
+ invalid={form.formState.errors[field.name]?.message}
80
+ invalidText={form.formState.errors[field.name]?.message}>
81
+ <DatePickerInput
82
+ invalid={form.formState.errors[field.name]?.message}
83
+ invalidText={form.formState.errors[field.name]?.message}
84
+ placeholder="mm/dd/yyyy"
85
+ labelText={t('startDate', 'Start Date')}
86
+ size={controlSize}
87
+ />
88
+ </DatePicker>
89
+ )}
90
+ />
91
+ </Column>
92
+ <Column>
93
+ <Controller
94
+ control={form.control}
95
+ name="endDate"
96
+ render={({ field }) => (
97
+ <DatePicker
98
+ dateFormat="d/m/Y"
99
+ id="endDate"
100
+ datePickerType="single"
101
+ {...field}
102
+ invalid={form.formState.errors[field.name]?.message}
103
+ invalidText={form.formState.errors[field.name]?.message}>
104
+ <DatePickerInput
105
+ invalid={form.formState.errors[field.name]?.message}
106
+ invalidText={form.formState.errors[field.name]?.message}
107
+ placeholder="mm/dd/yyyy"
108
+ labelText={t('endDate', 'End Date')}
109
+ size="xl"
110
+ />
111
+ </DatePicker>
112
+ )}
113
+ />
114
+ </Column>
115
+ <span className={styles.sectionHeader}>Manifest type</span>
116
+ <Column>
117
+ <Controller
118
+ control={form.control}
119
+ name="manifestType"
120
+ render={({ field }) => (
121
+ <Dropdown
122
+ ref={field.ref}
123
+ invalid={form.formState.errors[field.name]?.message}
124
+ invalidText={form.formState.errors[field.name]?.message}
125
+ id="manifestType"
126
+ titleText={t('manifestType', 'Manifest Type')}
127
+ onChange={(e) => {
128
+ field.onChange(e.selectedItem);
129
+ }}
130
+ initialSelectedItem={field.value}
131
+ label="Choose option"
132
+ items={manifestTypes.map((r) => r.value)}
133
+ itemToString={(item) => manifestTypes.find((r) => r.value === item)?.label ?? ''}
134
+ />
135
+ )}
136
+ />
137
+ </Column>
138
+ <span className={styles.sectionHeader}>Dispatch status</span>
139
+
140
+ <Column>
141
+ <Controller
142
+ control={form.control}
143
+ name="dispatchDate"
144
+ render={({ field }) => (
145
+ <DatePicker
146
+ dateFormat="d/m/Y"
147
+ id="dispatchDate"
148
+ datePickerType="single"
149
+ {...field}
150
+ invalid={form.formState.errors[field.name]?.message}
151
+ invalidText={form.formState.errors[field.name]?.message}>
152
+ <DatePickerInput
153
+ invalid={form.formState.errors[field.name]?.message}
154
+ invalidText={form.formState.errors[field.name]?.message}
155
+ placeholder="mm/dd/yyyy"
156
+ labelText={t('dispatchDate', 'Dispatch Date')}
157
+ size="xl"
158
+ />
159
+ </DatePicker>
160
+ )}
161
+ />
162
+ </Column>
163
+ <Column>
164
+ <Controller
165
+ control={form.control}
166
+ name="courierName"
167
+ render={({ field }) => (
168
+ <TextInput
169
+ invalid={form.formState.errors[field.name]?.message}
170
+ invalidText={form.formState.errors[field.name]?.message}
171
+ {...field}
172
+ placeholder="Courier name"
173
+ labelText={t('courierName', 'Courier name')}
174
+ />
175
+ )}
176
+ />
177
+ </Column>
178
+ <Column>
179
+ <Controller
180
+ control={form.control}
181
+ name="personHandedTo"
182
+ render={({ field }) => (
183
+ <TextInput
184
+ invalid={form.formState.errors[field.name]?.message}
185
+ invalidText={form.formState.errors[field.name]?.message}
186
+ {...field}
187
+ placeholder="Person name"
188
+ labelText={t('personHandedTo', 'Person handed to')}
189
+ />
190
+ )}
191
+ />
192
+ </Column>
193
+ <span className={styles.sectionHeader}>Address</span>
194
+ <Column>
195
+ <Controller
196
+ control={form.control}
197
+ name="county"
198
+ render={({ field }) => (
199
+ <Dropdown
200
+ ref={field.ref}
201
+ invalid={form.formState.errors[field.name]?.message}
202
+ invalidText={form.formState.errors[field.name]?.message}
203
+ id="county"
204
+ titleText={t('county', 'County')}
205
+ onChange={(e) => {
206
+ field.onChange(e.selectedItem);
207
+ form.setValue('subCounty', undefined);
208
+ }}
209
+ initialSelectedItem={field.value}
210
+ label="Select county"
211
+ items={counties.map((r) => r.name)}
212
+ itemToString={(item) => item ?? ''}
213
+ />
214
+ )}
215
+ />
216
+ </Column>
217
+ <Column>
218
+ <Controller
219
+ control={form.control}
220
+ name="subCounty"
221
+ render={({ field }) => (
222
+ <Dropdown
223
+ ref={field.ref}
224
+ invalid={form.formState.errors[field.name]?.message}
225
+ invalidText={form.formState.errors[field.name]?.message}
226
+ id="subCounty"
227
+ titleText={t('subCounty', 'Sub county')}
228
+ initialSelectedItem={field.value}
229
+ onChange={(e) => {
230
+ field.onChange(e.selectedItem);
231
+ }}
232
+ label="Select subcounty"
233
+ items={(counties.find((c) => c.name == observableSelectedCounty)?.constituencies ?? []).map(
234
+ (r) => r.name,
235
+ )}
236
+ itemToString={(item) =>
237
+ (counties.find((c) => c.name == observableSelectedCounty)?.constituencies ?? []).find(
238
+ (c) => c.name === item,
239
+ )?.name ?? 'Select subcounty'
240
+ }
241
+ />
242
+ )}
243
+ />
244
+ </Column>
245
+ <Column>
246
+ <Controller
247
+ control={form.control}
248
+ name="facilityEmail"
249
+ render={({ field }) => (
250
+ <TextInput
251
+ invalid={form.formState.errors[field.name]?.message}
252
+ invalidText={form.formState.errors[field.name]?.message}
253
+ {...field}
254
+ placeholder="Facility Email"
255
+ labelText={t('facilityEmail', 'Facility email')}
256
+ />
257
+ )}
258
+ />
259
+ </Column>
260
+ <Column>
261
+ <Controller
262
+ control={form.control}
263
+ name="facilityPhoneContact"
264
+ render={({ field }) => (
265
+ <TextInput
266
+ {...field}
267
+ invalid={form.formState.errors[field.name]?.message}
268
+ invalidText={form.formState.errors[field.name]?.message}
269
+ placeholder="Phone number"
270
+ labelText={t('facilityPhoneContact', 'Facility phone contact')}
271
+ />
272
+ )}
273
+ />
274
+ </Column>
275
+ <Column>
276
+ <Controller
277
+ control={form.control}
278
+ name="clinicianName"
279
+ render={({ field }) => (
280
+ <TextInput
281
+ invalid={form.formState.errors[field.name]?.message}
282
+ invalidText={form.formState.errors[field.name]?.message}
283
+ {...field}
284
+ placeholder="Clinician name"
285
+ labelText={t('clinicianName', 'Clinician name')}
286
+ />
287
+ )}
288
+ />
289
+ </Column>
290
+ <Column>
291
+ <Controller
292
+ control={form.control}
293
+ name="clinicianContact"
294
+ render={({ field }) => (
295
+ <TextInput
296
+ {...field}
297
+ invalid={form.formState.errors[field.name]?.message}
298
+ invalidText={form.formState.errors[field.name]?.message}
299
+ placeholder="Clinician contact"
300
+ labelText={t('clinicianContact', 'Clinician phone contact')}
301
+ />
302
+ )}
303
+ />
304
+ </Column>
305
+ <Column>
306
+ <Controller
307
+ control={form.control}
308
+ name="labPersonContact"
309
+ render={({ field }) => (
310
+ <TextInput
311
+ {...field}
312
+ invalid={form.formState.errors[field.name]?.message}
313
+ invalidText={form.formState.errors[field.name]?.message}
314
+ placeholder="Lab person contact"
315
+ labelText={t('labPersonContact', 'Lab person contact')}
316
+ />
317
+ )}
318
+ />
319
+ </Column>
320
+ <span className={styles.sectionHeader}>Manifest status</span>
321
+ <Column>
322
+ <Controller
323
+ control={form.control}
324
+ name="manifestStatus"
325
+ render={({ field }) => (
326
+ <Dropdown
327
+ ref={field.ref}
328
+ invalid={form.formState.errors[field.name]?.message}
329
+ invalidText={form.formState.errors[field.name]?.message}
330
+ id="manifestStatus"
331
+ titleText={t('status', 'Status')}
332
+ onChange={(e) => {
333
+ field.onChange(e.selectedItem);
334
+ }}
335
+ initialSelectedItem={field.value}
336
+ label="Select status"
337
+ items={LabManifestFilters.map((r) => r.value)}
338
+ itemToString={(item) => LabManifestFilters.find((r) => r.value === item)?.label ?? ''}
339
+ />
340
+ )}
341
+ />
342
+ </Column>
343
+ </Stack>
344
+
345
+ <ButtonSet className={styles.buttonSet}>
346
+ <Button className={styles.button} kind="secondary" onClick={closeWorkspace}>
347
+ {t('discard', 'Discard')}
348
+ </Button>
349
+ <Button className={styles.button} kind="primary" type="submit" disabled={form.formState.isSubmitting}>
350
+ {t('submit', 'Submit')}
351
+ </Button>
352
+ </ButtonSet>
353
+ </Form>
354
+ );
355
+ };
356
+
357
+ export default LabManifestForm;
@@ -0,0 +1,74 @@
1
+ import { Button, ButtonSet, SkeletonText } from '@carbon/react';
2
+ import { ArrowLeft, Edit } from '@carbon/react/icons';
3
+ import { formatDate, launchWorkspace, navigate, parseDate } from '@openmrs/esm-framework';
4
+ import React from 'react';
5
+ import { useTranslation } from 'react-i18next';
6
+ import { useLabManifest } from '../hooks';
7
+ import styles from './lab-manifest-header.scss';
8
+
9
+ interface LabManifestDetailHeaderProps {
10
+ manifestUuid: string;
11
+ }
12
+
13
+ const LabManifestDetailHeader: React.FC<LabManifestDetailHeaderProps> = ({ manifestUuid }) => {
14
+ const { isLoading, manifest } = useLabManifest(manifestUuid);
15
+ const { t } = useTranslation();
16
+
17
+ const handleGoBack = () => {
18
+ navigate({ to: window.getOpenmrsSpaBase() + `home/lab-manifest` });
19
+ };
20
+
21
+ const handleEditManifest = () => {
22
+ launchWorkspace('lab-manifest-form', {
23
+ workspaceTitle: 'Lab Manifest Form',
24
+ manifest,
25
+ });
26
+ };
27
+
28
+ if (isLoading) {
29
+ return (
30
+ <div className={styles.manifestDetailHeader}>
31
+ <div className={styles.manifestDetailContent}>
32
+ {Array.from({ length: 3 }).map((_) => (
33
+ <SkeletonText style={{ maxWidth: '400px' }} />
34
+ ))}
35
+ </div>
36
+ </div>
37
+ );
38
+ }
39
+
40
+ return (
41
+ <div>
42
+ <div className={styles.manifestDetailHeader}>
43
+ <div className={styles.manifestDetailContent}>
44
+ <div>
45
+ <strong>Date:</strong>
46
+ {manifest.startDate ? formatDate(parseDate(manifest.startDate)) : '--'} <strong>To</strong>{' '}
47
+ {manifest.endDate ? formatDate(parseDate(manifest.endDate)) : '--'}
48
+ </div>
49
+ <div>
50
+ <strong>Status:</strong>
51
+ {manifest.manifestStatus} | <strong>Type</strong> : {manifest.manifestType} | <strong>Courrier:</strong>
52
+ {manifest.courierName}
53
+ </div>
54
+ <div>
55
+ <strong>Dispatch Date:</strong>
56
+ {manifest.dispatchDate ? formatDate(parseDate(manifest.dispatchDate)) : '--'} |{' '}
57
+ <strong>Lab person Contact:</strong>
58
+ {manifest.labPersonContact}
59
+ </div>
60
+ </div>
61
+ </div>
62
+ <ButtonSet className={styles.btnSet}>
63
+ <Button kind="tertiary" renderIcon={ArrowLeft} onClick={handleGoBack}>
64
+ {t('back', 'Back')}
65
+ </Button>
66
+ <Button kind="tertiary" renderIcon={Edit} onClick={handleEditManifest}>
67
+ {t('editManifest', 'Edit Manifest')}
68
+ </Button>
69
+ </ButtonSet>
70
+ </div>
71
+ );
72
+ };
73
+
74
+ export default LabManifestDetailHeader;
@@ -0,0 +1,36 @@
1
+ import React from 'react';
2
+ import { useTranslation } from 'react-i18next';
3
+ import { Calendar, Location } from '@carbon/react/icons';
4
+ import { useSession, formatDate } from '@openmrs/esm-framework';
5
+ import styles from './lab-manifest-header.scss';
6
+ import LabManifestIllustration from './lab-manifest-illustration.component';
7
+
8
+ interface LabManifestHeaderProps {
9
+ title: string;
10
+ }
11
+ export const LabManifestHeader: React.FC<LabManifestHeaderProps> = ({ title }) => {
12
+ const { t } = useTranslation();
13
+ const userSession = useSession();
14
+ const userLocation = userSession?.sessionLocation?.display;
15
+
16
+ return (
17
+ <div className={styles.header}>
18
+ <div className={styles['leftJustifiedItems']}>
19
+ <LabManifestIllustration />
20
+ <div className={styles['pageLabels']}>
21
+ <p>{t('labManifest', 'Lab manifest Management')}</p>
22
+ <p className={styles['pageName']}>{title}</p>
23
+ </div>
24
+ </div>
25
+ <div className={styles['rightJustifieditems']}>
26
+ <div className={styles['dateAndLocation']}>
27
+ <Location size={16} />
28
+ <span className={styles.value}>{userLocation}</span>
29
+ <span className={styles.middot}>&middot;</span>
30
+ <Calendar size={16} />
31
+ <span className={styles.value}>{formatDate(new Date(), { mode: 'standard' })}</span>
32
+ </div>
33
+ </div>
34
+ </div>
35
+ );
36
+ };
@@ -0,0 +1,105 @@
1
+ @use '@carbon/styles/scss/spacing';
2
+ @use '@carbon/styles/scss/type';
3
+ @import '~@openmrs/esm-styleguide/src/vars';
4
+
5
+ .header {
6
+ @include type.type-style('body-compact-02');
7
+ color: $text-02;
8
+ height: spacing.$spacing-12;
9
+ background-color: $ui-02;
10
+ border: 1px solid $ui-03;
11
+ border-left: 0px;
12
+ display: flex;
13
+ justify-content: space-between;
14
+ margin-bottom: 2rem;
15
+ }
16
+
17
+ .leftJustifiedItems {
18
+ display: flex;
19
+ flex-direction: row;
20
+ align-items: center;
21
+ margin-left: 0.75rem;
22
+ }
23
+
24
+ .rightJustifieditems {
25
+ @include type.type-style('body-compact-02');
26
+ color: $text-02;
27
+ padding-top: 1rem;
28
+ }
29
+
30
+ .pageName {
31
+ @include type.type-style('heading-04');
32
+ }
33
+
34
+ .pageLabels {
35
+ margin-left: 1rem;
36
+
37
+ p:first-of-type {
38
+ margin-bottom: 0.25rem;
39
+ }
40
+ }
41
+
42
+ .dateAndLocation {
43
+ display: flex;
44
+ justify-content: flex-end;
45
+ align-items: center;
46
+ margin-right: 1rem;
47
+ }
48
+
49
+ .value {
50
+ margin-left: 0.25rem;
51
+ }
52
+
53
+ .middot {
54
+ margin: 0 0.5rem;
55
+ }
56
+
57
+ .view {
58
+ @include type.type-style('label-01');
59
+ }
60
+
61
+ svg.iconOverrides {
62
+ width: 72 !important;
63
+ height: 72 !important;
64
+ fill: var(--brand-03);
65
+ }
66
+
67
+ .svgContainer svg {
68
+ width: 72px;
69
+ height: 72px;
70
+ fill: var(--brand-03);
71
+ }
72
+
73
+ .cardContainer {
74
+ background-color: $ui-02;
75
+ display: flex;
76
+ justify-content: space-between;
77
+ padding: 0 spacing.$spacing-05 spacing.$spacing-07 spacing.$spacing-03;
78
+ flex-flow: row wrap;
79
+ margin-top: -(spacing.$spacing-03);
80
+ }
81
+
82
+ .manifestDetailHeader {
83
+ display: flex;
84
+ justify-content: space-between;
85
+ padding: spacing.$spacing-05;
86
+ flex-flow: row wrap;
87
+ align-items: center;
88
+ background-color: $ui-02;
89
+ gap: 2rem;
90
+ }
91
+
92
+ .manifestDetailContent {
93
+ flex-grow: 1;
94
+ gap: 0.5rem;
95
+ flex-direction: column;
96
+ display: flex;
97
+ }
98
+
99
+ .btnSet {
100
+ display: flex;
101
+ justify-content: space-between;
102
+ padding: spacing.$spacing-05;
103
+ flex-flow: row wrap;
104
+ align-items: center;
105
+ }