@kenyaemr/esm-patient-clinical-view-app 5.4.2-pre.2128 → 5.4.2-pre.2135

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 (31) hide show
  1. package/.turbo/turbo-build.log +67 -80
  2. package/dist/574.js +1 -1
  3. package/dist/{551.js → 825.js} +1 -1
  4. package/dist/825.js.map +1 -0
  5. package/dist/kenyaemr-esm-patient-clinical-view-app.js +1 -1
  6. package/dist/kenyaemr-esm-patient-clinical-view-app.js.buildmanifest.json +32 -32
  7. package/dist/main.js +1 -1
  8. package/dist/main.js.map +1 -1
  9. package/dist/routes.json +1 -1
  10. package/package.json +1 -1
  11. package/src/config-schema.ts +21 -5
  12. package/src/contact-list/contact-list.component.tsx +3 -1
  13. package/src/contact-list/contact-list.resource.tsx +15 -13
  14. package/src/contact-list/contact-list.workspace.tsx +10 -249
  15. package/src/contact-list/contact-tracing-history.component.tsx +1 -1
  16. package/src/family-partner-history/family-history.component.tsx +40 -9
  17. package/src/family-partner-history/family-relationship.workspace.tsx +10 -4
  18. package/src/family-partner-history/relationships.resource.tsx +24 -98
  19. package/src/hooks/useContacts.ts +1 -1
  20. package/src/hooks/usePersonAttributes.ts +15 -0
  21. package/src/index.ts +0 -4
  22. package/src/relationships/forms/baseline-info-form-section.component.tsx +315 -0
  23. package/src/relationships/forms/patient-search-create-form.tsx +38 -23
  24. package/src/relationships/relationship.resources.ts +15 -5
  25. package/src/relationships/tabs/relationships-tabs-component.tsx +0 -5
  26. package/src/routes.json +0 -16
  27. package/translations/en.json +13 -3
  28. package/dist/551.js.map +0 -1
  29. package/src/other-relationships/other-relationships.component.tsx +0 -229
  30. package/src/other-relationships/other-relationships.scss +0 -125
  31. package/src/other-relationships/other-relationships.workspace.tsx +0 -155
@@ -1,229 +0,0 @@
1
- import React, { useMemo, useState } from 'react';
2
- import { useTranslation } from 'react-i18next';
3
- import {
4
- DataTable,
5
- DataTableSkeleton,
6
- Layer,
7
- Pagination,
8
- Table,
9
- TableBody,
10
- TableCell,
11
- TableContainer,
12
- TableHead,
13
- TableHeader,
14
- TableRow,
15
- Tile,
16
- Button,
17
- } from '@carbon/react';
18
- import { Add, Edit, TrashCan } from '@carbon/react/icons';
19
- import { EmptyDataIllustration, ErrorState, CardHeader, usePaginationInfo } from '@openmrs/esm-patient-common-lib';
20
- import {
21
- ConfigurableLink,
22
- isDesktop,
23
- launchWorkspace,
24
- useConfig,
25
- useLayoutType,
26
- usePagination,
27
- } from '@openmrs/esm-framework';
28
- import type { ConfigObject } from '../config-schema';
29
- import styles from './other-relationships.scss';
30
- import { usePatientRelationships } from '../family-partner-history/relationships.resource';
31
- import ConceptObservations from '../family-partner-history/concept-obs.component';
32
- import { deleteRelationship } from '../relationships/relationship.resources';
33
-
34
- interface OtherRelationshipsProps {
35
- patientUuid: string;
36
- }
37
-
38
- export const OtherRelationships: React.FC<OtherRelationshipsProps> = ({ patientUuid }) => {
39
- const { t } = useTranslation();
40
- const config = useConfig<ConfigObject>();
41
- const layout = useLayoutType();
42
- const { concepts } = config;
43
- const [pageSize, setPageSize] = useState(10);
44
- const familyRelationships = useMemo(
45
- () => config.relationshipTypesList.filter((rl) => rl.category.some((c) => c === 'family')),
46
- [config],
47
- );
48
- const { relationships, error, isLoading, isValidating } = usePatientRelationships(patientUuid);
49
- const familyRelationshipTypeUUIDs = new Set(familyRelationships.map((type) => type.uuid));
50
- const nonFamilyRelationships = relationships.filter((r) => !familyRelationshipTypeUUIDs.has(r.relationshipTypeUUID));
51
-
52
- const headerTitle = t('otherRelationships', 'Other Relationships');
53
- const { results, totalPages, currentPage, goTo } = usePagination(nonFamilyRelationships, pageSize);
54
- const { pageSizes } = usePaginationInfo(pageSize, totalPages, currentPage, results.length);
55
-
56
- const handleEditRelationship = (relationShipUuid: string) => {
57
- launchWorkspace('relationship-update-form', {
58
- relationShipUuid,
59
- });
60
- };
61
-
62
- const headers = [
63
- {
64
- header: t('name', 'Name'),
65
- key: 'name',
66
- },
67
- {
68
- header: t('relation', 'Relation'),
69
- key: 'relation',
70
- },
71
- {
72
- header: t('age', 'Age'),
73
- key: 'age',
74
- },
75
- {
76
- header: t('alive', 'Alive'),
77
- key: 'alive',
78
- },
79
- {
80
- header: t('causeOfDeath', 'Cause of Death'),
81
- key: 'causeOfDeath',
82
- },
83
- {
84
- header: t('chronicDisease', 'Chronic Disease'),
85
- key: 'chronicDisease',
86
- },
87
- { header: t('actions', 'Actions'), key: 'actions' },
88
- ];
89
-
90
- const handleAddHistory = () => {
91
- launchWorkspace('other-relationship-form', {
92
- workspaceTitle: 'Other Relationship Form',
93
- patientUuid,
94
- });
95
- };
96
-
97
- const tableRows =
98
- results?.map((relation) => {
99
- const patientUuid = relation.patientUuid;
100
-
101
- return {
102
- id: `${relation.uuid}`,
103
- name: (
104
- <ConfigurableLink
105
- style={{ textDecoration: 'none' }}
106
- to={window.getOpenmrsSpaBase() + `patient/${relation.relativeUuid}/chart/Patient Summary`}>
107
- {relation.name}
108
- </ConfigurableLink>
109
- ),
110
- relation: relation?.relationshipType,
111
- age: relation?.relativeAge ?? '--',
112
- alive: relation?.dead ? t('dead', 'Dead') : t('alive', 'Alive'),
113
- causeOfDeath: (
114
- <ConceptObservations patientUuid={patientUuid} conceptUuid={concepts.probableCauseOfDeathConceptUuid} />
115
- ),
116
- patientUuid: relation,
117
- chronicDisease: <ConceptObservations patientUuid={patientUuid} conceptUuid={concepts.problemListConceptUuid} />,
118
- actions: (
119
- <>
120
- <Button
121
- renderIcon={Edit}
122
- hasIconOnly
123
- kind="ghost"
124
- iconDescription="Edit"
125
- onClick={() => handleEditRelationship(relation.uuid)}
126
- />
127
- <Button
128
- renderIcon={TrashCan}
129
- hasIconOnly
130
- kind="ghost"
131
- iconDescription="Delete"
132
- onClick={() => deleteRelationship(relation.uuid)}
133
- />
134
- </>
135
- ),
136
- };
137
- }) ?? [];
138
-
139
- if (isLoading || isValidating) {
140
- return (
141
- <DataTableSkeleton
142
- headers={headers}
143
- aria-label="patient bills table"
144
- showToolbar={false}
145
- showHeader={false}
146
- rowCount={3}
147
- zebra
148
- columnCount={3}
149
- className={styles.dataTableSkeleton}
150
- />
151
- );
152
- }
153
-
154
- if (error) {
155
- return <ErrorState headerTitle={headerTitle} error={error} />;
156
- }
157
-
158
- if (nonFamilyRelationships.length === 0) {
159
- return (
160
- <Layer>
161
- <Tile className={styles.tile}>
162
- <div className={!isDesktop(layout) ? styles.tabletHeading : styles.desktopHeading}>
163
- <h4>{headerTitle}</h4>
164
- </div>
165
- <EmptyDataIllustration />
166
- <p className={styles.content}>There is no other relationships data to display for this patient.</p>
167
- <Button onClick={handleAddHistory} renderIcon={Add} kind="ghost">
168
- {t('addRelationship', 'Add relationship')}
169
- </Button>
170
- </Tile>
171
- </Layer>
172
- );
173
- }
174
-
175
- return (
176
- <div className={styles.widgetContainer}>
177
- <CardHeader title={headerTitle}>
178
- {isLoading && <DataTableSkeleton rowCount={5} />}{' '}
179
- <Button onClick={handleAddHistory} renderIcon={Add} kind="ghost">
180
- {t('add', 'Add')}
181
- </Button>
182
- </CardHeader>
183
- <DataTable
184
- useZebraStyles
185
- size="sm"
186
- rows={tableRows ?? []}
187
- headers={headers}
188
- render={({ rows, headers, getHeaderProps, getTableProps, getTableContainerProps }) => (
189
- <TableContainer {...getTableContainerProps()}>
190
- <Table {...getTableProps()}>
191
- <TableHead>
192
- <TableRow>
193
- {headers.map((header) => (
194
- <TableHeader
195
- {...getHeaderProps({
196
- header,
197
- isSortable: header.isSortable,
198
- })}>
199
- {header.header?.content ?? header.header}
200
- </TableHeader>
201
- ))}
202
- </TableRow>
203
- </TableHead>
204
- <TableBody>
205
- {rows.map((row) => (
206
- <TableRow key={row.id}>
207
- {row.cells.map((cell) => (
208
- <TableCell key={cell.id}>{cell.value}</TableCell>
209
- ))}
210
- </TableRow>
211
- ))}
212
- </TableBody>
213
- </Table>
214
- </TableContainer>
215
- )}
216
- />
217
- <Pagination
218
- page={currentPage}
219
- pageSize={pageSize}
220
- pageSizes={pageSizes}
221
- totalItems={relationships.length}
222
- onChange={({ page, pageSize }) => {
223
- goTo(page);
224
- setPageSize(pageSize);
225
- }}
226
- />
227
- </div>
228
- );
229
- };
@@ -1,125 +0,0 @@
1
- @use '@carbon/styles/scss/spacing';
2
- @use '@carbon/styles/scss/type';
3
- @use '@carbon/styles/scss/colors';
4
- @use '@carbon/layout';
5
- @import '~@openmrs/esm-styleguide/src/vars';
6
-
7
- .heading {
8
- @include type.type-style('heading-compact-01');
9
- margin: spacing.$spacing-05 0 spacing.$spacing-05;
10
- }
11
-
12
- .warningContainer {
13
- background-color: $carbon--red-50;
14
- padding: spacing.$spacing-04;
15
- margin: spacing.$spacing-03 0 spacing.$spacing-03;
16
- display: flex;
17
- justify-content: space-between;
18
- .warning {
19
- @include type.type-style('heading-compact-01');
20
- color: $ui-05;
21
- }
22
- }
23
-
24
- .datePickerInput span,
25
- .datePickerInput div,
26
- .datePickerInput input,
27
- .datePickerInput {
28
- min-width: 100%;
29
- }
30
-
31
- .form {
32
- display: flex;
33
- flex-direction: column;
34
- justify-content: space-between;
35
- width: 100%;
36
- height: 100%;
37
- }
38
-
39
- .grid {
40
- margin: layout.$spacing-05 layout.$spacing-05;
41
- padding: layout.$spacing-05 0 0 0;
42
- }
43
-
44
- .button {
45
- display: flex;
46
- align-content: flex-start;
47
- align-items: baseline;
48
- min-width: 50%;
49
- }
50
-
51
- .buttonSet {
52
- display: flex;
53
- justify-content: space-between;
54
- width: 100%;
55
- }
56
- .textbox {
57
- margin-bottom: spacing.$spacing-08;
58
- }
59
-
60
- .sectionHeader {
61
- @include type.type-style('heading-02');
62
- margin-top: spacing.$spacing-05;
63
- }
64
-
65
- :global(.omrs-breakpoint-lt-desktop) {
66
- .form {
67
- height: var(--tablet-workspace-window-height);
68
- }
69
-
70
- .buttonSet {
71
- padding: spacing.$spacing-06 spacing.$spacing-05;
72
- background-color: $ui-02;
73
- justify-content: flex-end;
74
- gap: spacing.$spacing-05;
75
- padding: 0;
76
- margin-top: auto;
77
- display: flex;
78
- justify-content: end;
79
- }
80
- }
81
-
82
- .widgetContainer {
83
- background-color: colors.$white-0;
84
- border: 1px solid colors.$gray-20;
85
- margin-bottom: 1rem;
86
- }
87
-
88
- .widgetContainer :global(.cds--data-table) thead th button span {
89
- height: unset !important;
90
- }
91
-
92
- .tile {
93
- text-align: center;
94
- }
95
-
96
- .emptyStateContainer {
97
- margin: 2rem 0;
98
- }
99
-
100
- .content {
101
- @include type.type-style('heading-compact-01');
102
- color: colors.$gray-70;
103
- margin-top: layout.$layout-05;
104
- margin-bottom: layout.$spacing-03;
105
- }
106
-
107
- .desktopHeading,
108
- .tabletHeading {
109
- text-align: left;
110
- text-transform: capitalize;
111
-
112
- h4 {
113
- @include type.type-style('heading-compact-02');
114
- color: colors.$gray-70;
115
-
116
- &:after {
117
- content: '';
118
- display: block;
119
- width: 2rem;
120
- padding-top: 3px;
121
- border-bottom: 0.375rem solid;
122
- @include brand-03(border-bottom-color);
123
- }
124
- }
125
- }
@@ -1,155 +0,0 @@
1
- import { Button, ButtonSet, Column, ComboBox, DatePicker, DatePickerInput, Form, Stack, TextArea } from '@carbon/react';
2
- import { zodResolver } from '@hookform/resolvers/zod';
3
- import { useConfig, useSession } from '@openmrs/esm-framework';
4
- import React, { useMemo } from 'react';
5
- import { Controller, FormProvider, SubmitHandler, useForm } from 'react-hook-form';
6
- import { useTranslation } from 'react-i18next';
7
- import { z } from 'zod';
8
- import { ConfigObject } from '../config-schema';
9
- import { useMappedRelationshipTypes } from '../family-partner-history/relationships.resource';
10
- import PatientSearchCreate from '../relationships/forms/patient-search-create-form';
11
- import { relationshipFormSchema, saveRelationship } from '../relationships/relationship.resources';
12
- import { uppercaseText } from '../utils/expression-helper';
13
- import styles from './other-relationships.scss';
14
-
15
- const schema = relationshipFormSchema
16
- .refine(
17
- (data) => {
18
- return !(data.mode === 'search' && !data.personB);
19
- },
20
- { message: 'Required', path: ['personB'] },
21
- )
22
- .refine(
23
- (data) => {
24
- return !(data.mode === 'create' && !data.personBInfo);
25
- },
26
- { path: ['personBInfo'], message: 'Please provide patient information' },
27
- );
28
- type FormData = z.infer<typeof schema>;
29
-
30
- type OtherRelationshipsFormProps = {
31
- closeWorkspace: () => void;
32
- patientUuid: string;
33
- };
34
-
35
- export const OtherRelationshipsForm: React.FC<OtherRelationshipsFormProps> = ({ closeWorkspace, patientUuid }) => {
36
- const { t } = useTranslation();
37
- const { data: mappedRelationshipTypes } = useMappedRelationshipTypes();
38
- const config = useConfig<ConfigObject>();
39
- const familyRelationships = useMemo(
40
- () => config.relationshipTypesList.filter((rl) => rl.category.some((c) => c === 'family')),
41
- [config],
42
- );
43
- const familyRelationshipTypesUUIDs = new Set(familyRelationships.map((r) => r.uuid));
44
- const otherRelationshipTypes = mappedRelationshipTypes.filter((type) => !familyRelationshipTypesUUIDs.has(type.uuid));
45
- const session = useSession();
46
- const relationshipTypes = otherRelationshipTypes.map((relationship) => ({
47
- id: relationship.uuid,
48
- text: relationship.display,
49
- }));
50
-
51
- const form = useForm<FormData>({
52
- mode: 'all',
53
- defaultValues: {
54
- personA: patientUuid,
55
- mode: 'search',
56
- },
57
- resolver: zodResolver(schema),
58
- });
59
-
60
- const { control, handleSubmit } = form;
61
-
62
- const onSubmit: SubmitHandler<FormData> = async (data) => {
63
- try {
64
- await saveRelationship(data, config, session, []);
65
- closeWorkspace();
66
- } catch (error) {}
67
- };
68
-
69
- return (
70
- <FormProvider {...form}>
71
- <Form className={styles.form} onSubmit={handleSubmit(onSubmit)}>
72
- <Stack gap={5} className={styles.grid}>
73
- <PatientSearchCreate />
74
- <span className={styles.sectionHeader}>{t('relationship', 'Relationship')}</span>
75
- <Column>
76
- <Controller
77
- control={form.control}
78
- name="startDate"
79
- render={({ field }) => (
80
- <DatePicker
81
- className={styles.datePickerInput}
82
- dateFormat="d/m/Y"
83
- id="startDate"
84
- datePickerType="single"
85
- {...field}
86
- ref={undefined}
87
- invalid={form.formState.errors[field.name]?.message}
88
- invalidText={form.formState.errors[field.name]?.message}>
89
- <DatePickerInput
90
- invalid={form.formState.errors[field.name]?.message}
91
- invalidText={form.formState.errors[field.name]?.message}
92
- placeholder="mm/dd/yyyy"
93
- labelText={t('startDate', 'Start Date')}
94
- size="xl"
95
- />
96
- </DatePicker>
97
- )}
98
- />
99
- </Column>
100
- <Column>
101
- <Controller
102
- control={form.control}
103
- name="endDate"
104
- render={({ field }) => (
105
- <DatePicker
106
- className={styles.datePickerInput}
107
- dateFormat="d/m/Y"
108
- id="endDate"
109
- datePickerType="single"
110
- {...field}
111
- ref={undefined}
112
- invalid={form.formState.errors[field.name]?.message}
113
- invalidText={form.formState.errors[field.name]?.message}>
114
- <DatePickerInput
115
- invalid={form.formState.errors[field.name]?.message}
116
- invalidText={form.formState.errors[field.name]?.message}
117
- placeholder="mm/dd/yyyy"
118
- labelText={t('endDate', 'End Date')}
119
- size="xl"
120
- />
121
- </DatePicker>
122
- )}
123
- />
124
- </Column>
125
- <Column>
126
- <Controller
127
- name="relationshipType"
128
- control={control}
129
- render={({ field, fieldState }) => (
130
- <ComboBox
131
- id="relationship_name"
132
- titleText={t('relationship', 'Relationship')}
133
- placeholder="Select Relationship"
134
- items={relationshipTypes}
135
- itemToString={(item) => (item ? uppercaseText(item.text) : '')}
136
- onChange={(e) => field.onChange(e.selectedItem?.id)}
137
- invalid={!!fieldState.error}
138
- invalidText={fieldState.error?.message}
139
- />
140
- )}
141
- />
142
- </Column>
143
- </Stack>
144
- <ButtonSet className={styles.buttonSet}>
145
- <Button className={styles.button} kind="secondary" onClick={closeWorkspace}>
146
- {t('discard', 'Discard')}
147
- </Button>
148
- <Button className={styles.button} kind="primary" type="submit" disabled={form.formState.isSubmitting}>
149
- {t('save', 'Save')}
150
- </Button>
151
- </ButtonSet>
152
- </Form>
153
- </FormProvider>
154
- );
155
- };