Skip to content

Commit

Permalink
Khp3 6290 contact listing bug fix (#293)
Browse files Browse the repository at this point in the history
* Added ipv related fields on contact listing form for sexual relationships

* Saving ipv outcome

* Cleaned up code removing unecessary comment and magic values
  • Loading branch information
Omoshlawi authored Aug 2, 2024
1 parent 8b742d1 commit a0a1101
Show file tree
Hide file tree
Showing 6 changed files with 178 additions and 9 deletions.
17 changes: 17 additions & 0 deletions packages/esm-patient-clinical-view-app/src/config-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ export const configSchema = {
contactCreated: '7c94bd35-fba7-4ef7-96f5-29c89a318fcf',
preferedPnsAproach: '59d1b886-90c8-4f7f-9212-08b20a9ee8cf',
livingWithContact: '35a08d84-9f80-4991-92b4-c4ae5903536e',
contactIPVOutcome: '49c543c2-a72a-4b0a-8cca-39c375c0726f',
},
},
familyRelationshipsTypeList: {
Expand Down Expand Up @@ -175,6 +176,20 @@ export const configSchema = {
},
],
},
contactSexualRelationships: {
_type: Type.Array,
_description: 'List of Sexual relationship',
_default: [
{
uuid: 'd6895098-5d8d-11e3-94ee-b35a4132a5e3',
display: 'Spouse/Spouse',
},
{
uuid: '007b765f-6725-4ae9-afee-9966302bace4',
display: 'Partner/Partner',
},
],
},
};

export interface ConfigObject {
Expand Down Expand Up @@ -205,8 +220,10 @@ export interface ConfigObject {
contactCreated: string;
preferedPnsAproach: string;
livingWithContact: string;
contactIPVOutcome: string;
};
familyRelationshipsTypeList: Array<{ uuid: string; display: string }>;
contactSexualRelationships: Array<{ uuid: string; display: string }>;
}

export interface PartograpyComponents {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ const ContactList: React.FC<ContactListProps> = ({ patientUuid }) => {
header: t('pnsAproach', 'PNS Aproach'),
key: 'pnsAproach',
},
{
header: t('ipvOutcome', 'IPV Outcome'),
key: 'ipvOutcome',
},
];

const handleAddContact = () => {
Expand Down Expand Up @@ -119,6 +123,7 @@ const ContactList: React.FC<ContactListProps> = ({ patientUuid }) => {
baseLineivStatus: relation.baselineHIVStatus ?? '--',
livingWithClient: relation.livingWithClient ?? '--',
pnsAproach: relation.pnsAproach ?? '--',
ipvOutcome: relation.ipvOutcome ?? '--',
};
}) ?? [];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,18 @@ import { ConfigObject } from '../config-schema';
import { Enrollment, HTSEncounter, Patient } from '../types';
import { replaceAll } from '../utils/expression-helper';

export const BOOLEAN_YES = '1065';
export const BOOLEAN_NO = '1066';

export const ContactListFormSchema = z.object({
listingDate: z.date({ coerce: true }),
givenName: z.string().min(1, 'Required'),
middleName: z.string().min(1, 'Required'),
familyName: z.string().min(1, 'Required'),
gender: z.enum(['M', 'F']),
physicalAssault: z.enum([BOOLEAN_YES, BOOLEAN_NO]).optional(),
threatened: z.enum([BOOLEAN_YES, BOOLEAN_NO]).optional(),
sexualAssault: z.enum([BOOLEAN_YES, BOOLEAN_NO]).optional(),
dateOfBirth: z.date({ coerce: true }).max(new Date(), 'Must not be a future date'),
maritalStatus: z.string().optional(),
address: z.string().optional(),
Expand All @@ -18,8 +24,14 @@ export const ContactListFormSchema = z.object({
livingWithClient: z.string().optional(),
baselineStatus: z.string().optional(),
preferedPNSAproach: z.string().optional(),
ipvOutCome: z.enum(['True', 'False']).optional(),
});

export const contactIPVOutcomeOptions = [
{ label: 'True', value: 'True' },
{ label: 'False', value: 'False' },
];

export const getHivStatusBasedOnEnrollmentAndHTSEncounters = (
encounters: HTSEncounter[],
enrollment: Enrollment | null,
Expand Down Expand Up @@ -77,6 +89,7 @@ export const saveContact = async (
phoneNumber,
preferedPNSAproach,
relationshipToPatient,
ipvOutCome,
}: z.infer<typeof ContactListFormSchema>,
patientUuid: string,
encounter: Record<string, any>,
Expand Down Expand Up @@ -115,7 +128,7 @@ export const saveContact = async (
: []),
{
attributeType: config.contactPersonAttributesUuid.contactCreated,
value: '1065',
value: BOOLEAN_YES,
},
// Add Optional Prefered PNS Aproach attribute
...(preferedPNSAproach
Expand All @@ -135,6 +148,14 @@ export const saveContact = async (
},
]
: []),
...(ipvOutCome
? [
{
attributeType: config.contactPersonAttributesUuid.contactIPVOutcome,
value: ipvOutCome,
},
]
: []),
],
};
try {
Expand All @@ -159,9 +180,9 @@ export const saveContact = async (
});
// Create relationship payload
const relationshipPayload = {
personA: patient.person.uuid,
personA: patientUuid,
relationshipType: relationshipToPatient,
personB: patientUuid,
personB: patient.person.uuid,
startDate: listingDate.toISOString(),
};
// Create optional encounter with marital/civil status obs
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,21 @@ import {
usePatient,
useSession,
} from '@openmrs/esm-framework';
import React, { useMemo } from 'react';
import React, { useEffect, useMemo } from 'react';
import { Controller, useForm } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
import { mutate } from 'swr';
import { z } from 'zod';
import { ConfigObject } from '../config-schema';
import { contactListConceptMap } from './contact-list-concept-map';
import styles from './contact-list-form.scss';
import { ContactListFormSchema, saveContact } from './contact-list.resource';
import {
BOOLEAN_NO,
BOOLEAN_YES,
contactIPVOutcomeOptions,
ContactListFormSchema,
saveContact,
} from './contact-list.resource';
interface ContactListFormProps extends DefaultWorkspaceProps {
patientUuid: string;
props: any;
Expand Down Expand Up @@ -131,6 +137,26 @@ const ContactListForm: React.FC<ContactListFormProps> = ({
});
};

const observableRelationship = form.watch('relationshipToPatient');
const observablePhysicalAssault = form.watch('physicalAssault');
const observableThreatened = form.watch('threatened');
const observableSexualAssault = form.watch('sexualAssault');
const showIPVRelatedFields =
config.contactSexualRelationships.findIndex((r) => r.uuid === observableRelationship) !== -1;

useEffect(() => {
if ([observablePhysicalAssault, observableThreatened, observableSexualAssault].includes(BOOLEAN_YES)) {
form.setValue('ipvOutCome', 'True');
} else if (
[observablePhysicalAssault, observableThreatened, observableSexualAssault].every((v) => v === BOOLEAN_NO)
) {
form.setValue('ipvOutCome', 'False');
}
if (!showIPVRelatedFields) {
form.setValue('ipvOutCome', undefined);
}
}, [observablePhysicalAssault, observableThreatened, observableSexualAssault, observableRelationship]);

return (
<Form onSubmit={form.handleSubmit(onSubmit)}>
<span className={styles.contactFormTitle}>{t('formTitle', 'Fill in the form details')}</span>
Expand Down Expand Up @@ -212,7 +238,6 @@ const ContactListForm: React.FC<ContactListFormProps> = ({
<RadioButtonGroup
legendText={t('sex', 'Sex')}
{...field}
// defaultSelected=""
invalid={form.formState.errors[field.name]?.message}
invalidText={form.formState.errors[field.name]?.message}
className={styles.billingItem}>
Expand Down Expand Up @@ -344,6 +369,96 @@ const ContactListForm: React.FC<ContactListFormProps> = ({
)}
/>
</Column>
{showIPVRelatedFields && (
<>
<span className={styles.sectionHeader}>IPV Questions</span>
<Column>
<Controller
control={form.control}
name="physicalAssault"
render={({ field }) => (
<RadioButtonGroup
id="physicalAssault"
legendText={t(
'physicalAssault',
'1. Has he/she ever hit, kicked, slapped, or otherwise physically hurt you?',
)}
{...field}
invalid={form.formState.errors[field.name]?.message}
invalidText={form.formState.errors[field.name]?.message}
className={styles.billingItem}>
<RadioButton labelText={t('yes', 'Yes')} value={BOOLEAN_YES} id="physicalAssault_yes" />
<RadioButton labelText={t('no', 'No')} value={BOOLEAN_NO} id="physicalAssault_no" />
</RadioButtonGroup>
)}
/>
</Column>
<Column>
<Controller
control={form.control}
name="threatened"
render={({ field }) => (
<RadioButtonGroup
id="threatened"
legendText={t('threatened', '2. Has he/she ever threatened to hurt you?')}
{...field}
invalid={form.formState.errors[field.name]?.message}
invalidText={form.formState.errors[field.name]?.message}
className={styles.billingItem}>
<RadioButton labelText={t('yes', 'Yes')} value={BOOLEAN_YES} id="threatened_yes" />
<RadioButton labelText={t('no', 'No')} value={BOOLEAN_NO} id="threatened_no" />
</RadioButtonGroup>
)}
/>
</Column>
<Column>
<Controller
control={form.control}
name="sexualAssault"
render={({ field }) => (
<RadioButtonGroup
id="sexualAssault"
legendText={t(
'sexualAssault',
'3.Has he/she ever forced you to do something sexually that made you feel uncomfortable?',
)}
{...field}
invalid={form.formState.errors[field.name]?.message}
invalidText={form.formState.errors[field.name]?.message}
className={styles.billingItem}>
<RadioButton labelText={t('yes', 'Yes')} value={BOOLEAN_YES} id="sexualAssault_yes" />
<RadioButton labelText={t('no', 'No')} value={BOOLEAN_NO} id="sexualAssault_no" />
</RadioButtonGroup>
)}
/>
</Column>
<span className={styles.sectionHeader}>IPV Outcome</span>
<Column>
<Controller
control={form.control}
name="ipvOutCome"
render={({ field }) => (
<Dropdown
ref={field.ref}
invalid={form.formState.errors[field.name]?.message}
invalidText={form.formState.errors[field.name]?.message}
id="ipvOutCome"
titleText={t('ipvOutCome', 'IPV Outcome')}
onChange={(e) => {
field.onChange(e.selectedItem);
}}
selectedItem={field.value}
label="Choose option"
items={contactIPVOutcomeOptions.map((r) => r.value)}
itemToString={(item) => {
return contactIPVOutcomeOptions.find((r) => r.value === item)?.label ?? '';
}}
/>
)}
/>
</Column>
</>
)}
<span className={styles.sectionHeader}>Baseline Information</span>

<Column>
Expand Down
16 changes: 13 additions & 3 deletions packages/esm-patient-clinical-view-app/src/hooks/useContacts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ function extractName(display: string) {
return display.trim();
}

function extractTelephone(display: string) {
function extractValue(display: string) {
const pattern = /=\s*(.*)$/;
const match = display.match(pattern);
if (match && match.length > 1) {
Expand Down Expand Up @@ -46,10 +46,11 @@ function extractAttributeData(person: Person, config: ConfigObject) {
personContactCreated: string | null;
pnsAproach: string | null;
livingWithClient: string | null;
ipvOutcome: string | null;
}>(
(prev, attr) => {
if (attr.attributeType.uuid === config.contactPersonAttributesUuid.telephone) {
return { ...prev, contact: attr.display ? extractTelephone(attr.display) : null };
return { ...prev, contact: attr.display ? extractValue(attr.display) : null };
} else if (attr.attributeType.uuid === config.contactPersonAttributesUuid.baselineHIVStatus) {
return { ...prev, baselineHIVStatus: getConceptName(attr.value) ?? null };
} else if (attr.attributeType.uuid === config.contactPersonAttributesUuid.contactCreated) {
Expand All @@ -58,10 +59,19 @@ function extractAttributeData(person: Person, config: ConfigObject) {
return { ...prev, livingWithClient: getConceptName(attr.value) ?? null };
} else if (attr.attributeType.uuid === config.contactPersonAttributesUuid.preferedPnsAproach) {
return { ...prev, pnsAproach: getConceptName(attr.value) ?? null };
} else if (attr.attributeType.uuid === config.contactPersonAttributesUuid.contactIPVOutcome) {
return { ...prev, ipvOutcome: attr.display ? extractValue(attr.display) : null };
}
return prev;
},
{ contact: null, baselineHIVStatus: null, personContactCreated: null, pnsAproach: null, livingWithClient: null },
{
contact: null,
baselineHIVStatus: null,
personContactCreated: null,
pnsAproach: null,
livingWithClient: null,
ipvOutcome: null,
},
);
}

Expand Down
1 change: 1 addition & 0 deletions packages/esm-patient-clinical-view-app/src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ export interface Contact {
personContactCreated: string | null;
livingWithClient: string | null;
pnsAproach: string | null;
ipvOutcome: string | null;
}

export interface Person {
Expand Down

0 comments on commit a0a1101

Please sign in to comment.