@kenyaemr/esm-patient-clinical-view-app 5.4.2-pre.2126 → 5.4.2-pre.2131
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/.turbo/turbo-build.log +69 -82
- package/dist/574.js +1 -1
- package/dist/{551.js → 825.js} +1 -1
- package/dist/825.js.map +1 -0
- package/dist/kenyaemr-esm-patient-clinical-view-app.js +1 -1
- package/dist/kenyaemr-esm-patient-clinical-view-app.js.buildmanifest.json +32 -32
- package/dist/main.js +1 -1
- package/dist/main.js.map +1 -1
- package/dist/routes.json +1 -1
- package/package.json +1 -1
- package/src/config-schema.ts +21 -5
- package/src/contact-list/contact-list.component.tsx +3 -1
- package/src/contact-list/contact-list.resource.tsx +15 -13
- package/src/contact-list/contact-list.workspace.tsx +10 -249
- package/src/contact-list/contact-tracing-history.component.tsx +1 -1
- package/src/family-partner-history/family-history.component.tsx +40 -9
- package/src/family-partner-history/family-relationship.workspace.tsx +10 -4
- package/src/family-partner-history/relationships.resource.tsx +24 -98
- package/src/hooks/useContacts.ts +1 -1
- package/src/hooks/usePersonAttributes.ts +15 -0
- package/src/index.ts +0 -4
- package/src/relationships/forms/baseline-info-form-section.component.tsx +315 -0
- package/src/relationships/forms/patient-search-create-form.tsx +38 -23
- package/src/relationships/relationship.resources.ts +15 -5
- package/src/relationships/tabs/relationships-tabs-component.tsx +0 -5
- package/src/routes.json +0 -14
- package/translations/en.json +13 -3
- package/dist/551.js.map +0 -1
- package/src/other-relationships/other-relationships.component.tsx +0 -229
- package/src/other-relationships/other-relationships.scss +0 -125
- package/src/other-relationships/other-relationships.workspace.tsx +0 -155
package/dist/routes.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"$schema":"https://json.openmrs.org/routes.schema.json","backendDependencies":{"kenyaemr":"^19.0.0"},"pages":[],"extensions":[{"name":"clinical-view-section","component":"clinicalViewPatientDashboard","slot":"patient-chart-dashboard-slot"},{"name":"family-history","slot":"patient-chart-family-history-slot","component":"familyHistory","order":0,"online":true,"offline":false},{"name":"
|
|
1
|
+
{"$schema":"https://json.openmrs.org/routes.schema.json","backendDependencies":{"kenyaemr":"^19.0.0"},"pages":[],"extensions":[{"name":"clinical-view-section","component":"clinicalViewPatientDashboard","slot":"patient-chart-dashboard-slot"},{"name":"family-history","slot":"patient-chart-family-history-slot","component":"familyHistory","order":0,"online":true,"offline":false},{"name":"relationships-link","component":"relationshipsLink","slot":"patient-chart-dashboard-slot","order":14,"meta":{"columns":1,"columnSpan":1,"slot":"patient-chart-relationships-slot","path":"relationships","layoutMode":"anchored"}},{"name":"relationships","slot":"patient-chart-relationships-slot","component":"relationships","order":0,"online":true,"offline":false},{"name":"contact-list-form","component":"contactListForm"},{"name":"maternal-and-child-health-dashboard-group-link","slot":"clinical-view-section","component":"maternalAndChildHealthSideNavGroup"},{"name":"antenatal-care-dashboard-link","component":"antenatalCareLink","slot":"maternal-and-child-health-slot","meta":{"columns":1,"columnSpan":1,"slot":"patient-chart-antenatal-care-dashboard-slot","path":"antenatal-care-dashboard","layoutMode":"anchored"}},{"name":"antenatal-care-dashboard","slot":"patient-chart-antenatal-care-dashboard-slot","component":"antenatalCare"},{"name":"postnatal-care-dashboard-link","component":"postnatalCareLink","slot":"maternal-and-child-health-slot","meta":{"columns":1,"columnSpan":1,"slot":"patient-chart-postnatal-care-dashboard-slot","path":"postnatal-care-dashboard","layoutMode":"anchored"}},{"name":"postnatal-care-dashboard","slot":"patient-chart-postnatal-care-dashboard-slot","component":"postnatalCare"},{"name":"labour-and-delivery-dashboard-link","component":"labourAndDeliveryLink","slot":"maternal-and-child-health-slot","meta":{"fullWidth":true,"slot":"patient-chart-labour-and-delivery-dashboard-slot","path":"labour-and-delivery-dashboard","layoutMode":"anchored"}},{"name":"labour-and-delivery-dashboard","slot":"patient-chart-labour-and-delivery-dashboard-slot","component":"labourAndDelivery","meta":{"fullWidth":true}},{"name":"hiv-care-and-treatment-dashboard-group-link","slot":"special-clinics-slot","component":"hivCareAndTreatMentSideNavGroup"},{"name":"genericNavLinks","slot":"special-clinics-slot","component":"genericNavLinks","meta":{"columns":1,"columnSpan":1,"slot":"patient-chart-special-clinic-dashboard-slot","path":"special-clinics-dashboard","layoutMode":"anchored"}},{"name":"patient-chart-special-clinic-dashboard-slot","slot":"patient-chart-special-clinic-dashboard-slot","component":"genericDashboard"},{"name":"hts-dashboard-link","component":"htsDashboardLink","slot":"hiv-care-and-treatment-slot","meta":{"columns":1,"columnSpan":1,"slot":"patient-chart-hts-dashboard-slot","path":"hts-dashboard","layoutMode":"anchored"}},{"name":"hts-clinical-view","slot":"patient-chart-hts-dashboard-slot","component":"htsClinicalView","order":2,"online":true,"offline":false},{"name":"defaulter-tracing-dashboard-link","component":"defaulterTracingLink","slot":"hiv-care-and-treatment-slot","meta":{"columns":1,"columnSpan":1,"slot":"patient-chart-defaulter-tracing-dashboard-slot","path":"defaulter-tracing-dashboard","layoutMode":"anchored"}},{"name":"defaulter-tracing-dashboard","slot":"patient-chart-defaulter-tracing-dashboard-slot","component":"defaulterTracing","order":3,"online":true,"offline":false},{"name":"special-clinics-dashboard-group-link","slot":"clinical-view-section","component":"specialClinicsSideNavGroup"},{"name":"clinical-encounter-link","component":"inPatientClinicalEncounterLink","slot":"clinical-view-section","order":40,"meta":{"columns":1,"columnSpan":1,"slot":"patient-chart-clinical-encounter-slot","path":"clinical-encounter","layoutMode":"anchored"}},{"name":"clinical-encounter","slot":"patient-chart-clinical-encounter-slot","component":"inPatientClinicalEncounter","order":0,"online":true,"offline":false},{"component":"caseManagementDashboardLink","name":"case-management-dashboard-link","slot":"homepage-dashboard-slot","meta":{"name":"case-management","title":"Case Management","slot":"case-management-dashboard-slot","path":"/case-management"}},{"name":"in-patient-dashboard-link","component":"inPatientChartLink","slot":"patient-chart-dashboard-slot","order":7,"meta":{"slot":"patient-chart-in-patient-dashboard-slot","path":"in-patient","layoutMode":"anchored","columns":1,"columnSpan":1}},{"name":"in-patient-dashboard","slot":"patient-chart-in-patient-dashboard-slot","component":"inPatientChartDashboard","meta":{"fullWidth":false}},{"name":"wrap-component-view","slot":"case-management-dashboard-slot","component":"wrapComponent","order":2,"online":true,"offline":false},{"name":"case-encounter-link","component":"caseEncounterDashboardLink","slot":"patient-chart-dashboard-slot","order":14,"meta":{"columns":1,"columnSpan":1,"slot":"patient-chart-case-encounter-slot","path":"case-management-encounters","layoutMode":"anchored"}},{"name":"case-encounter-table","slot":"patient-chart-case-encounter-slot","component":"caseEncounterTable","order":0,"online":true,"offline":false},{"component":"peerCalendarDashboardLink","name":"peer-calendar-dashboard-link","slot":"homepage-dashboard-slot","meta":{"name":"peer-calendar","title":"Peer Calendar","slot":"peer-calendar-dashboard-slot","path":"peer-management"}},{"name":"peer-calendar","slot":"peer-calendar-dashboard-slot","component":"peerCalendar","order":0,"online":true,"offline":false},{"name":"deceased-panel-dashboard-link","component":"deceasedPanelDashboardLink","slot":"patient-chart-dashboard-slot","order":15,"meta":{"columns":1,"columnSpan":1,"slot":"patient-chart-deceased-panel-slot","path":"deceased-panel","layoutMode":"anchored"}},{"name":"deceased-details-tabs","slot":"patient-chart-deceased-panel-slot","component":"deceasedDetailsTabs","order":0,"online":true,"offline":false},{"name":"parto-graph-chart","slot":"patient-chart-labour-and-delivery-dashboard-slot","component":"partograph","meta":{"fullWidth":true}}],"modals":[{"name":"birth-date-calculator","component":"birthDateCalculator"},{"name":"relationship-delete-confirm-dialog","component":"relationshipDeleteConfirmialog"},{"name":"end-relationship-dialog","component":"endRelationshipModal"}],"workspaces":[{"name":"case-management-form","component":"caseManagementForm","title":"Case Management Form","type":"form"},{"name":"family-relationship-form","component":"familyRelationshipForm","title":"Family Relationship Form","type":"form"},{"name":"peers-form","component":"peersForm","title":"Add New Peer","type":"form"},{"name":"kenyaemr-cusom-form-entry-workspace","component":"peerCalendarFormEntry","title":"KVP Peer Educator Outreach Calendar","type":"form","width":"extra-wide","canMaximize":true,"canHide":true},{"name":"relationship-update-form","component":"relationshipUpdateForm","title":"Relationship Update Form","type":"form"},{"name":"other-relationship-form","component":"otherRelationshipsForm","title":"Other Relationships Form","type":"form"},{"name":"end-relationship-form","component":"endRelationshipWorkspace","title":"Discontinue relationship form","type":"form"}],"version":"5.4.2-pre.2131"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kenyaemr/esm-patient-clinical-view-app",
|
|
3
|
-
"version": "5.4.2-pre.
|
|
3
|
+
"version": "5.4.2-pre.2131",
|
|
4
4
|
"description": "Patient clinical view microfrontend for the OpenMRS SPA",
|
|
5
5
|
"browser": "dist/kenyaemr-esm-patient-clinical-view-app.js",
|
|
6
6
|
"main": "src/index.ts",
|
package/src/config-schema.ts
CHANGED
|
@@ -2,6 +2,11 @@ import { Type } from '@openmrs/esm-framework';
|
|
|
2
2
|
import _default from 'react-hook-form/dist/logic/appendErrors';
|
|
3
3
|
|
|
4
4
|
export const configSchema = {
|
|
5
|
+
requireMaritalStatusOnAgeGreaterThanOrEqualTo: {
|
|
6
|
+
_type: Type.Number,
|
|
7
|
+
_description: 'Age in years',
|
|
8
|
+
_default: 10,
|
|
9
|
+
},
|
|
5
10
|
encounterTypes: {
|
|
6
11
|
_type: Type.Object,
|
|
7
12
|
_description: 'List of encounter type UUIDs',
|
|
@@ -200,12 +205,12 @@ export const configSchema = {
|
|
|
200
205
|
{
|
|
201
206
|
uuid: '5f115f62-68b7-11e3-94ee-6bef9086de92',
|
|
202
207
|
display: 'Guardian/Dependant',
|
|
203
|
-
category: ['
|
|
208
|
+
category: ['family'],
|
|
204
209
|
},
|
|
205
210
|
{
|
|
206
211
|
uuid: 'd6895098-5d8d-11e3-94ee-b35a4132a5e3',
|
|
207
212
|
display: 'Spouse/Spouse',
|
|
208
|
-
category: ['sexual', '
|
|
213
|
+
category: ['sexual', 'family'],
|
|
209
214
|
},
|
|
210
215
|
{
|
|
211
216
|
uuid: '007b765f-6725-4ae9-afee-9966302bace4',
|
|
@@ -215,7 +220,17 @@ export const configSchema = {
|
|
|
215
220
|
{
|
|
216
221
|
uuid: '2ac0d501-eadc-4624-b982-563c70035d46',
|
|
217
222
|
display: 'Co-wife/Co-wife',
|
|
218
|
-
category: ['
|
|
223
|
+
category: ['family'],
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
uuid: 'a8058424-5ddf-4ce2-a5ee-6e08d01b5960',
|
|
227
|
+
display: 'Care-giver/Care-giver',
|
|
228
|
+
category: ['family'],
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
uuid: '3667e52f-8653-40e1-b227-a7278d474020',
|
|
232
|
+
display: 'Primary caregiver/Primary caregiver',
|
|
233
|
+
category: ['family'],
|
|
219
234
|
},
|
|
220
235
|
{
|
|
221
236
|
uuid: '58da0d1e-9c89-42e9-9412-275cef1e0429',
|
|
@@ -225,7 +240,7 @@ export const configSchema = {
|
|
|
225
240
|
{
|
|
226
241
|
uuid: '76edc1fe-c5ce-4608-b326-c8ecd1020a73',
|
|
227
242
|
display: 'SNS/SNS',
|
|
228
|
-
category: ['
|
|
243
|
+
category: ['pns'],
|
|
229
244
|
},
|
|
230
245
|
],
|
|
231
246
|
},
|
|
@@ -282,6 +297,7 @@ export const configSchema = {
|
|
|
282
297
|
};
|
|
283
298
|
|
|
284
299
|
export interface ConfigObject {
|
|
300
|
+
requireMaritalStatusOnAgeGreaterThanOrEqualTo: number;
|
|
285
301
|
peerEducatorRelationship: string;
|
|
286
302
|
morgueVisitTypeUuid: string;
|
|
287
303
|
morgueDischargeEncounterUuid: string;
|
|
@@ -339,7 +355,7 @@ export interface ConfigObject {
|
|
|
339
355
|
relationshipTypesList: Array<{
|
|
340
356
|
uuid: string;
|
|
341
357
|
display: string;
|
|
342
|
-
category: Array<'sexual' | 'pns' | 'family'
|
|
358
|
+
category: Array<'sexual' | 'pns' | 'family'>;
|
|
343
359
|
}>;
|
|
344
360
|
}
|
|
345
361
|
|
|
@@ -46,7 +46,7 @@ interface ContactListProps {
|
|
|
46
46
|
const ContactList: React.FC<ContactListProps> = ({ patientUuid }) => {
|
|
47
47
|
const { t } = useTranslation();
|
|
48
48
|
const [pageSize, setPageSize] = useState(10);
|
|
49
|
-
const headerTitle = t('
|
|
49
|
+
const headerTitle = t('pnsContactList', 'PNS Contact list');
|
|
50
50
|
const layout = useLayoutType();
|
|
51
51
|
const size = layout === 'tablet' ? 'lg' : 'md';
|
|
52
52
|
const { contacts, error, isLoading } = useContacts(patientUuid);
|
|
@@ -117,6 +117,8 @@ const ContactList: React.FC<ContactListProps> = ({ patientUuid }) => {
|
|
|
117
117
|
const handleLaunchContactTracingForm = (contactUuid: string) => {
|
|
118
118
|
launchWorkspace('kenyaemr-cusom-form-entry-workspace', {
|
|
119
119
|
formUuid: htsClientTracingFormUuid,
|
|
120
|
+
workspaceTitle: t('contactTracingForm', 'Contact tracing form'),
|
|
121
|
+
|
|
120
122
|
patientUuid: contactUuid,
|
|
121
123
|
encounterUuid: '',
|
|
122
124
|
mutateForm: () => {
|
|
@@ -2,22 +2,11 @@ import { Session } from '@openmrs/esm-framework';
|
|
|
2
2
|
import omit from 'lodash/omit';
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
import { ConfigObject } from '../config-schema';
|
|
5
|
-
import { relationshipFormSchema, saveRelationship } from '../relationships/relationship.resources';
|
|
6
|
-
import { Enrollment, HTSEncounter } from '../types';
|
|
5
|
+
import { BOOLEAN_YES, relationshipFormSchema, saveRelationship } from '../relationships/relationship.resources';
|
|
6
|
+
import { Enrollment, HTSEncounter, Person } from '../types';
|
|
7
7
|
import { replaceAll } from '../utils/expression-helper';
|
|
8
|
-
export const BOOLEAN_YES = '1065';
|
|
9
|
-
export const BOOLEAN_NO = '1066';
|
|
10
8
|
|
|
11
9
|
export const ContactListFormSchema = relationshipFormSchema
|
|
12
|
-
.extend({
|
|
13
|
-
physicalAssault: z.enum([BOOLEAN_YES, BOOLEAN_NO]).optional(),
|
|
14
|
-
threatened: z.enum([BOOLEAN_YES, BOOLEAN_NO]).optional(),
|
|
15
|
-
sexualAssault: z.enum([BOOLEAN_YES, BOOLEAN_NO]).optional(),
|
|
16
|
-
livingWithClient: z.string().optional(),
|
|
17
|
-
baselineStatus: z.string().optional(),
|
|
18
|
-
preferedPNSAproach: z.string().optional(),
|
|
19
|
-
ipvOutCome: z.enum(['True', 'False']).optional(),
|
|
20
|
-
})
|
|
21
10
|
.refine(
|
|
22
11
|
(data) => {
|
|
23
12
|
return !(data.mode === 'search' && !data.personB);
|
|
@@ -67,6 +56,7 @@ export const saveContact = async (
|
|
|
67
56
|
data: z.infer<typeof ContactListFormSchema>,
|
|
68
57
|
config: ConfigObject,
|
|
69
58
|
session: Session,
|
|
59
|
+
personAttributes: Person['attributes'] = [],
|
|
70
60
|
) => {
|
|
71
61
|
const { baselineStatus, ipvOutCome, preferedPNSAproach, livingWithClient } = data;
|
|
72
62
|
|
|
@@ -90,6 +80,9 @@ export const saveContact = async (
|
|
|
90
80
|
{
|
|
91
81
|
attributeType: config.contactPersonAttributesUuid.baselineHIVStatus,
|
|
92
82
|
value: replaceAll(baselineStatus, 'A', ''),
|
|
83
|
+
attribute: personAttributes.find(
|
|
84
|
+
(a) => a.attributeType.uuid === config.contactPersonAttributesUuid.baselineHIVStatus,
|
|
85
|
+
)?.uuid,
|
|
93
86
|
},
|
|
94
87
|
]
|
|
95
88
|
: []),
|
|
@@ -108,6 +101,9 @@ export const saveContact = async (
|
|
|
108
101
|
{
|
|
109
102
|
attributeType: config.contactPersonAttributesUuid.preferedPnsAproach,
|
|
110
103
|
value: replaceAll(preferedPNSAproach, 'A', ''),
|
|
104
|
+
attribute: personAttributes.find(
|
|
105
|
+
(a) => a.attributeType.uuid === config.contactPersonAttributesUuid.preferedPnsAproach,
|
|
106
|
+
)?.uuid,
|
|
111
107
|
},
|
|
112
108
|
]
|
|
113
109
|
: []),
|
|
@@ -117,6 +113,9 @@ export const saveContact = async (
|
|
|
117
113
|
{
|
|
118
114
|
attributeType: config.contactPersonAttributesUuid.livingWithContact,
|
|
119
115
|
value: replaceAll(livingWithClient, 'A', ''),
|
|
116
|
+
attribute: personAttributes.find(
|
|
117
|
+
(a) => a.attributeType.uuid === config.contactPersonAttributesUuid.livingWithContact,
|
|
118
|
+
)?.uuid,
|
|
120
119
|
},
|
|
121
120
|
]
|
|
122
121
|
: []),
|
|
@@ -125,6 +124,9 @@ export const saveContact = async (
|
|
|
125
124
|
{
|
|
126
125
|
attributeType: config.contactPersonAttributesUuid.contactIPVOutcome,
|
|
127
126
|
value: ipvOutCome,
|
|
127
|
+
attribute: personAttributes.find(
|
|
128
|
+
(a) => a.attributeType.uuid === config.contactPersonAttributesUuid.contactIPVOutcome,
|
|
129
|
+
)?.uuid,
|
|
128
130
|
},
|
|
129
131
|
]
|
|
130
132
|
: []),
|
|
@@ -1,15 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Button,
|
|
3
|
-
ButtonSet,
|
|
4
|
-
Column,
|
|
5
|
-
DatePicker,
|
|
6
|
-
DatePickerInput,
|
|
7
|
-
Dropdown,
|
|
8
|
-
Form,
|
|
9
|
-
RadioButton,
|
|
10
|
-
RadioButtonGroup,
|
|
11
|
-
Stack,
|
|
12
|
-
} from '@carbon/react';
|
|
1
|
+
import { Button, ButtonSet, Column, DatePicker, DatePickerInput, Dropdown, Form, Stack } from '@carbon/react';
|
|
13
2
|
import { zodResolver } from '@hookform/resolvers/zod';
|
|
14
3
|
import { DefaultWorkspaceProps, useConfig, useSession } from '@openmrs/esm-framework';
|
|
15
4
|
import React, { useEffect, useMemo } from 'react';
|
|
@@ -18,21 +7,11 @@ import { useTranslation } from 'react-i18next';
|
|
|
18
7
|
import { z } from 'zod';
|
|
19
8
|
import { ConfigObject } from '../config-schema';
|
|
20
9
|
import { useMappedRelationshipTypes } from '../family-partner-history/relationships.resource';
|
|
10
|
+
import usePersonAttributes from '../hooks/usePersonAttributes';
|
|
11
|
+
import RelationshipBaselineInfoFormSection from '../relationships/forms/baseline-info-form-section.component';
|
|
21
12
|
import PatientSearchCreate from '../relationships/forms/patient-search-create-form';
|
|
22
|
-
import {
|
|
23
|
-
LIVING_WITH_PATIENT_CONCEPT_UUID,
|
|
24
|
-
PARTNER_HIV_STATUS_CONCEPT_UUID,
|
|
25
|
-
PNS_APROACH_CONCEPT_UUID,
|
|
26
|
-
} from '../relationships/relationships-constants';
|
|
27
|
-
import { contactListConceptMap } from './contact-list-concept-map';
|
|
28
13
|
import styles from './contact-list-form.scss';
|
|
29
|
-
import {
|
|
30
|
-
BOOLEAN_NO,
|
|
31
|
-
BOOLEAN_YES,
|
|
32
|
-
contactIPVOutcomeOptions,
|
|
33
|
-
ContactListFormSchema,
|
|
34
|
-
saveContact,
|
|
35
|
-
} from './contact-list.resource';
|
|
14
|
+
import { ContactListFormSchema, saveContact } from './contact-list.resource';
|
|
36
15
|
interface ContactListFormProps extends DefaultWorkspaceProps {
|
|
37
16
|
patientUuid: string;
|
|
38
17
|
props: any;
|
|
@@ -40,12 +19,7 @@ interface ContactListFormProps extends DefaultWorkspaceProps {
|
|
|
40
19
|
|
|
41
20
|
type ContactListFormType = z.infer<typeof ContactListFormSchema>;
|
|
42
21
|
|
|
43
|
-
const ContactListForm: React.FC<ContactListFormProps> = ({
|
|
44
|
-
closeWorkspace,
|
|
45
|
-
closeWorkspaceWithSavedChanges,
|
|
46
|
-
promptBeforeClosing,
|
|
47
|
-
patientUuid,
|
|
48
|
-
}) => {
|
|
22
|
+
const ContactListForm: React.FC<ContactListFormProps> = ({ closeWorkspace, patientUuid }) => {
|
|
49
23
|
const form = useForm<ContactListFormType>({
|
|
50
24
|
mode: 'all',
|
|
51
25
|
defaultValues: {
|
|
@@ -56,6 +30,8 @@ const ContactListForm: React.FC<ContactListFormProps> = ({
|
|
|
56
30
|
});
|
|
57
31
|
const { t } = useTranslation();
|
|
58
32
|
const session = useSession();
|
|
33
|
+
const personUuid = form.watch('personB');
|
|
34
|
+
const { attributes } = usePersonAttributes(personUuid);
|
|
59
35
|
|
|
60
36
|
const config = useConfig<ConfigObject>();
|
|
61
37
|
const { data } = useMappedRelationshipTypes();
|
|
@@ -72,67 +48,11 @@ const ContactListForm: React.FC<ContactListFormProps> = ({
|
|
|
72
48
|
|
|
73
49
|
const onSubmit = async (values: ContactListFormType) => {
|
|
74
50
|
try {
|
|
75
|
-
await saveContact(values, config, session);
|
|
51
|
+
await saveContact(values, config, session, attributes);
|
|
76
52
|
closeWorkspace();
|
|
77
53
|
} catch (error) {}
|
|
78
54
|
};
|
|
79
55
|
|
|
80
|
-
const hivStatus = useMemo(
|
|
81
|
-
() =>
|
|
82
|
-
Object.entries(contactListConceptMap[PARTNER_HIV_STATUS_CONCEPT_UUID].answers).map(([uuid, display]) => ({
|
|
83
|
-
label: display,
|
|
84
|
-
value: uuid,
|
|
85
|
-
})),
|
|
86
|
-
[],
|
|
87
|
-
);
|
|
88
|
-
|
|
89
|
-
const pnsAproach = useMemo(
|
|
90
|
-
() =>
|
|
91
|
-
Object.entries(contactListConceptMap[PNS_APROACH_CONCEPT_UUID].answers).map(([uuid, display]) => ({
|
|
92
|
-
label: display,
|
|
93
|
-
value: uuid,
|
|
94
|
-
})),
|
|
95
|
-
[],
|
|
96
|
-
);
|
|
97
|
-
|
|
98
|
-
const contactLivingWithPatient = useMemo(
|
|
99
|
-
() =>
|
|
100
|
-
Object.entries(contactListConceptMap[LIVING_WITH_PATIENT_CONCEPT_UUID].answers).map(([uuid, display]) => ({
|
|
101
|
-
label: display,
|
|
102
|
-
value: uuid,
|
|
103
|
-
})),
|
|
104
|
-
[],
|
|
105
|
-
);
|
|
106
|
-
|
|
107
|
-
const observableRelationship = form.watch('relationshipType');
|
|
108
|
-
const observablePhysicalAssault = form.watch('physicalAssault');
|
|
109
|
-
const observableThreatened = form.watch('threatened');
|
|
110
|
-
const observableSexualAssault = form.watch('sexualAssault');
|
|
111
|
-
const observableMode = form.watch('mode');
|
|
112
|
-
const showIPVRelatedFields =
|
|
113
|
-
pnsRelationships.findIndex((r) => r.uuid === observableRelationship && r.category.some((c) => c === 'sexual')) !==
|
|
114
|
-
-1;
|
|
115
|
-
|
|
116
|
-
useEffect(() => {
|
|
117
|
-
if ([observablePhysicalAssault, observableThreatened, observableSexualAssault].includes(BOOLEAN_YES)) {
|
|
118
|
-
form.setValue('ipvOutCome', 'True');
|
|
119
|
-
} else if (
|
|
120
|
-
[observablePhysicalAssault, observableThreatened, observableSexualAssault].every((v) => v === BOOLEAN_NO)
|
|
121
|
-
) {
|
|
122
|
-
form.setValue('ipvOutCome', 'False');
|
|
123
|
-
}
|
|
124
|
-
if (!showIPVRelatedFields) {
|
|
125
|
-
form.setValue('ipvOutCome', undefined);
|
|
126
|
-
}
|
|
127
|
-
}, [
|
|
128
|
-
observablePhysicalAssault,
|
|
129
|
-
observableThreatened,
|
|
130
|
-
observableSexualAssault,
|
|
131
|
-
observableRelationship,
|
|
132
|
-
form,
|
|
133
|
-
showIPVRelatedFields,
|
|
134
|
-
]);
|
|
135
|
-
|
|
136
56
|
return (
|
|
137
57
|
<FormProvider {...form}>
|
|
138
58
|
<Form onSubmit={form.handleSubmit(onSubmit)} className={styles.form}>
|
|
@@ -212,167 +132,8 @@ const ContactListForm: React.FC<ContactListFormProps> = ({
|
|
|
212
132
|
)}
|
|
213
133
|
/>
|
|
214
134
|
</Column>
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
<Column>
|
|
218
|
-
<Controller
|
|
219
|
-
control={form.control}
|
|
220
|
-
name="livingWithClient"
|
|
221
|
-
render={({ field, fieldState: { error } }) => (
|
|
222
|
-
<Dropdown
|
|
223
|
-
ref={field.ref}
|
|
224
|
-
invalid={error?.message}
|
|
225
|
-
invalidText={error?.message}
|
|
226
|
-
id="livingWithClient"
|
|
227
|
-
titleText={t('livingWithClient', 'Living with client')}
|
|
228
|
-
onChange={(e) => {
|
|
229
|
-
field.onChange(e.selectedItem);
|
|
230
|
-
}}
|
|
231
|
-
initialSelectedItem={field.value}
|
|
232
|
-
label="Select"
|
|
233
|
-
items={contactLivingWithPatient.map((r) => r.value)}
|
|
234
|
-
itemToString={(item) => contactLivingWithPatient.find((r) => r.value === item)?.label ?? ''}
|
|
235
|
-
/>
|
|
236
|
-
)}
|
|
237
|
-
/>
|
|
238
|
-
</Column>
|
|
239
|
-
{showIPVRelatedFields && (
|
|
240
|
-
<>
|
|
241
|
-
<span className={styles.sectionHeader}>{t('ipvQuestions', 'IPV Questions')}</span>
|
|
242
|
-
<Column>
|
|
243
|
-
<Controller
|
|
244
|
-
control={form.control}
|
|
245
|
-
name="physicalAssault"
|
|
246
|
-
render={({ field, fieldState: { error } }) => (
|
|
247
|
-
<RadioButtonGroup
|
|
248
|
-
id="physicalAssault"
|
|
249
|
-
legendText={t(
|
|
250
|
-
'physicalAssault',
|
|
251
|
-
'1. Has he/she ever hit, kicked, slapped, or otherwise physically hurt you?',
|
|
252
|
-
)}
|
|
253
|
-
{...field}
|
|
254
|
-
invalid={error?.message}
|
|
255
|
-
invalidText={error?.message}
|
|
256
|
-
className={styles.billingItem}>
|
|
257
|
-
<RadioButton labelText={t('yes', 'Yes')} value={BOOLEAN_YES} id="physicalAssault_yes" />
|
|
258
|
-
<RadioButton labelText={t('no', 'No')} value={BOOLEAN_NO} id="physicalAssault_no" />
|
|
259
|
-
</RadioButtonGroup>
|
|
260
|
-
)}
|
|
261
|
-
/>
|
|
262
|
-
</Column>
|
|
263
|
-
<Column>
|
|
264
|
-
<Controller
|
|
265
|
-
control={form.control}
|
|
266
|
-
name="threatened"
|
|
267
|
-
render={({ field, fieldState: { error } }) => (
|
|
268
|
-
<RadioButtonGroup
|
|
269
|
-
id="threatened"
|
|
270
|
-
legendText={t('threatened', '2. Has he/she ever threatened to hurt you?')}
|
|
271
|
-
{...field}
|
|
272
|
-
invalid={error?.message}
|
|
273
|
-
invalidText={error?.message}
|
|
274
|
-
className={styles.billingItem}>
|
|
275
|
-
<RadioButton labelText={t('yes', 'Yes')} value={BOOLEAN_YES} id="threatened_yes" />
|
|
276
|
-
<RadioButton labelText={t('no', 'No')} value={BOOLEAN_NO} id="threatened_no" />
|
|
277
|
-
</RadioButtonGroup>
|
|
278
|
-
)}
|
|
279
|
-
/>
|
|
280
|
-
</Column>
|
|
281
|
-
<Column>
|
|
282
|
-
<Controller
|
|
283
|
-
control={form.control}
|
|
284
|
-
name="sexualAssault"
|
|
285
|
-
render={({ field, fieldState: { error } }) => (
|
|
286
|
-
<RadioButtonGroup
|
|
287
|
-
id="sexualAssault"
|
|
288
|
-
legendText={t(
|
|
289
|
-
'sexualAssault',
|
|
290
|
-
'3.Has he/she ever forced you to do something sexually that made you feel uncomfortable?',
|
|
291
|
-
)}
|
|
292
|
-
{...field}
|
|
293
|
-
invalid={error?.message}
|
|
294
|
-
invalidText={error?.message}
|
|
295
|
-
className={styles.billingItem}>
|
|
296
|
-
<RadioButton labelText={t('yes', 'Yes')} value={BOOLEAN_YES} id="sexualAssault_yes" />
|
|
297
|
-
<RadioButton labelText={t('no', 'No')} value={BOOLEAN_NO} id="sexualAssault_no" />
|
|
298
|
-
</RadioButtonGroup>
|
|
299
|
-
)}
|
|
300
|
-
/>
|
|
301
|
-
</Column>
|
|
302
|
-
<span className={styles.sectionHeader}>{t('ipvOutcome', 'IPV Outcome')}</span>
|
|
303
|
-
<Column>
|
|
304
|
-
<Controller
|
|
305
|
-
control={form.control}
|
|
306
|
-
name="ipvOutCome"
|
|
307
|
-
render={({ field, fieldState: { error } }) => (
|
|
308
|
-
<Dropdown
|
|
309
|
-
ref={field.ref}
|
|
310
|
-
invalid={error?.message}
|
|
311
|
-
invalidText={error?.message}
|
|
312
|
-
id="ipvOutCome"
|
|
313
|
-
titleText={t('ipvOutCome', 'IPV Outcome')}
|
|
314
|
-
onChange={(e) => {
|
|
315
|
-
field.onChange(e.selectedItem);
|
|
316
|
-
}}
|
|
317
|
-
selectedItem={field.value}
|
|
318
|
-
label="Choose option"
|
|
319
|
-
items={contactIPVOutcomeOptions.map((r) => r.value)}
|
|
320
|
-
itemToString={(item) => {
|
|
321
|
-
return contactIPVOutcomeOptions.find((r) => r.value === item)?.label ?? '';
|
|
322
|
-
}}
|
|
323
|
-
/>
|
|
324
|
-
)}
|
|
325
|
-
/>
|
|
326
|
-
</Column>
|
|
327
|
-
</>
|
|
328
|
-
)}
|
|
329
|
-
<span className={styles.sectionHeader}>{t('baselineInformation', 'Baseline Information')}</span>
|
|
330
|
-
<Column>
|
|
331
|
-
<Controller
|
|
332
|
-
control={form.control}
|
|
333
|
-
name="baselineStatus"
|
|
334
|
-
render={({ field, fieldState: { error } }) => (
|
|
335
|
-
<Dropdown
|
|
336
|
-
ref={field.ref}
|
|
337
|
-
invalid={error?.message}
|
|
338
|
-
invalidText={error?.message}
|
|
339
|
-
id="baselineStatus"
|
|
340
|
-
titleText={t('baselineStatus', 'HIV Status')}
|
|
341
|
-
onChange={(e) => {
|
|
342
|
-
field.onChange(e.selectedItem);
|
|
343
|
-
}}
|
|
344
|
-
initialSelectedItem={field.value}
|
|
345
|
-
label="Select HIV Status"
|
|
346
|
-
items={hivStatus.map((r) => r.value)}
|
|
347
|
-
itemToString={(item) => hivStatus.find((r) => r.value === item)?.label ?? ''}
|
|
348
|
-
/>
|
|
349
|
-
)}
|
|
350
|
-
/>
|
|
351
|
-
</Column>
|
|
352
|
-
<Column>
|
|
353
|
-
<Controller
|
|
354
|
-
control={form.control}
|
|
355
|
-
name="preferedPNSAproach"
|
|
356
|
-
render={({ field, fieldState: { error } }) => (
|
|
357
|
-
<Dropdown
|
|
358
|
-
ref={field.ref}
|
|
359
|
-
invalid={error?.message}
|
|
360
|
-
invalidText={error?.message}
|
|
361
|
-
id="preferedPNSAproach"
|
|
362
|
-
titleText={t('preferedPNSAproach', 'Prefered PNS Aproach')}
|
|
363
|
-
onChange={(e) => {
|
|
364
|
-
field.onChange(e.selectedItem);
|
|
365
|
-
}}
|
|
366
|
-
initialSelectedItem={field.value}
|
|
367
|
-
label="Select Aproach"
|
|
368
|
-
items={pnsAproach.map((r) => r.value)}
|
|
369
|
-
itemToString={(item) => pnsAproach.find((r) => r.value === item)?.label ?? ''}
|
|
370
|
-
/>
|
|
371
|
-
)}
|
|
372
|
-
/>
|
|
373
|
-
</Column>
|
|
374
|
-
</>
|
|
375
|
-
)}
|
|
135
|
+
|
|
136
|
+
<RelationshipBaselineInfoFormSection />
|
|
376
137
|
</Stack>
|
|
377
138
|
|
|
378
139
|
<ButtonSet className={styles.buttonSet}>
|
|
@@ -35,7 +35,7 @@ const ContactTracingHistory: React.FC<ContactTracingHistoryProps> = ({ patientUu
|
|
|
35
35
|
|
|
36
36
|
const handleLaunchContactTracingForm = (encounterUuid: string) => {
|
|
37
37
|
launchWorkspace('kenyaemr-cusom-form-entry-workspace', {
|
|
38
|
-
workspaceTitle: 'Contact tracing form',
|
|
38
|
+
workspaceTitle: t('contactTracingForm', 'Contact tracing form'),
|
|
39
39
|
formUuid: htsClientTracingFormUuid,
|
|
40
40
|
patientUuid,
|
|
41
41
|
encounterUuid,
|
|
@@ -30,6 +30,7 @@ import ConceptObservations from './concept-obs.component';
|
|
|
30
30
|
import type { ConfigObject } from '../config-schema';
|
|
31
31
|
import styles from './family-history.scss';
|
|
32
32
|
import { deleteRelationship } from '../relationships/relationship.resources';
|
|
33
|
+
import HIVStatus from '../contact-list/hiv-status.component';
|
|
33
34
|
|
|
34
35
|
interface FamilyHistoryProps {
|
|
35
36
|
patientUuid: string;
|
|
@@ -42,18 +43,15 @@ const FamilyHistory: React.FC<FamilyHistoryProps> = ({ patientUuid }) => {
|
|
|
42
43
|
const layout = useLayoutType();
|
|
43
44
|
const [pageSize, setPageSize] = useState(10);
|
|
44
45
|
const { relationships, error, isLoading, isValidating } = usePatientRelationships(patientUuid);
|
|
45
|
-
const familyRelationshipTypes = useMemo(
|
|
46
|
-
() => config.relationshipTypesList.filter((rl) => rl.category.some((c) => c === 'family')),
|
|
47
|
-
[config],
|
|
48
|
-
);
|
|
49
|
-
const familyRelationshipTypeUUIDs = new Set(familyRelationshipTypes.map((type) => type.uuid));
|
|
50
|
-
const familyRelationships = relationships.filter((r) => familyRelationshipTypeUUIDs.has(r.relationshipTypeUUID));
|
|
51
|
-
|
|
52
46
|
const headerTitle = t('familyContacts', 'Family contacts');
|
|
53
|
-
const { results, totalPages, currentPage, goTo } = usePagination(
|
|
47
|
+
const { results, totalPages, currentPage, goTo } = usePagination(relationships, pageSize);
|
|
54
48
|
const { pageSizes } = usePaginationInfo(pageSize, totalPages, currentPage, results.length);
|
|
55
49
|
|
|
56
50
|
const headers = [
|
|
51
|
+
{
|
|
52
|
+
header: t('listingDate', 'Listing date'),
|
|
53
|
+
key: 'startDate',
|
|
54
|
+
},
|
|
57
55
|
{
|
|
58
56
|
header: t('name', 'Name'),
|
|
59
57
|
key: 'name',
|
|
@@ -66,6 +64,10 @@ const FamilyHistory: React.FC<FamilyHistoryProps> = ({ patientUuid }) => {
|
|
|
66
64
|
header: t('age', 'Age'),
|
|
67
65
|
key: 'age',
|
|
68
66
|
},
|
|
67
|
+
{
|
|
68
|
+
header: t('sex', 'Sex'),
|
|
69
|
+
key: 'sex',
|
|
70
|
+
},
|
|
69
71
|
{
|
|
70
72
|
header: t('alive', 'Alive'),
|
|
71
73
|
key: 'alive',
|
|
@@ -78,6 +80,26 @@ const FamilyHistory: React.FC<FamilyHistoryProps> = ({ patientUuid }) => {
|
|
|
78
80
|
header: t('chronicDisease', 'Chronic Disease'),
|
|
79
81
|
key: 'chronicDisease',
|
|
80
82
|
},
|
|
83
|
+
{
|
|
84
|
+
header: t('hivStatus', 'HIV Status'),
|
|
85
|
+
key: 'hivStatus',
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
header: t('baselineHivStatus', 'Baseline HIV Status'),
|
|
89
|
+
key: 'baseLineivStatus',
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
header: t('livingWithClient', 'Living with client'),
|
|
93
|
+
key: 'livingWithClient',
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
header: t('pnsAproach', 'PNS Aproach'),
|
|
97
|
+
key: 'pnsAproach',
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
header: t('ipvOutcome', 'IPV Outcome'),
|
|
101
|
+
key: 'ipvOutcome',
|
|
102
|
+
},
|
|
81
103
|
{ header: t('actions', 'Actions'), key: 'actions' },
|
|
82
104
|
];
|
|
83
105
|
|
|
@@ -99,6 +121,7 @@ const FamilyHistory: React.FC<FamilyHistoryProps> = ({ patientUuid }) => {
|
|
|
99
121
|
|
|
100
122
|
return {
|
|
101
123
|
id: `${relation.uuid}`,
|
|
124
|
+
startDate: relation.startDate ?? '--',
|
|
102
125
|
name: (
|
|
103
126
|
<ConfigurableLink
|
|
104
127
|
style={{ textDecoration: 'none' }}
|
|
@@ -108,12 +131,20 @@ const FamilyHistory: React.FC<FamilyHistoryProps> = ({ patientUuid }) => {
|
|
|
108
131
|
),
|
|
109
132
|
relation: relation?.relationshipType,
|
|
110
133
|
age: relation?.relativeAge ?? '--',
|
|
134
|
+
sex: relation.gender,
|
|
135
|
+
|
|
111
136
|
alive: relation?.dead ? t('dead', 'Dead') : t('alive', 'Alive'),
|
|
112
137
|
causeOfDeath: (
|
|
113
138
|
<ConceptObservations patientUuid={patientUuid} conceptUuid={concepts.probableCauseOfDeathConceptUuid} />
|
|
114
139
|
),
|
|
115
140
|
patientUuid: relation,
|
|
116
141
|
chronicDisease: <ConceptObservations patientUuid={patientUuid} conceptUuid={concepts.problemListConceptUuid} />,
|
|
142
|
+
hivStatus: <HIVStatus relativeUuid={relation.relativeUuid} />,
|
|
143
|
+
baseLineivStatus: relation.baselineHIVStatus ?? '--',
|
|
144
|
+
livingWithClient: relation.livingWithClient ?? '--',
|
|
145
|
+
pnsAproach: relation.pnsAproach ?? '--',
|
|
146
|
+
ipvOutcome: relation.ipvOutcome ?? '--',
|
|
147
|
+
|
|
117
148
|
actions: (
|
|
118
149
|
<>
|
|
119
150
|
<Button
|
|
@@ -154,7 +185,7 @@ const FamilyHistory: React.FC<FamilyHistoryProps> = ({ patientUuid }) => {
|
|
|
154
185
|
return <ErrorState headerTitle={headerTitle} error={error} />;
|
|
155
186
|
}
|
|
156
187
|
|
|
157
|
-
if (
|
|
188
|
+
if (relationships.length === 0) {
|
|
158
189
|
return (
|
|
159
190
|
<Layer>
|
|
160
191
|
<Tile className={styles.tile}>
|