Skip to content

Commit

Permalink
(feat) KHP3-6944 : Add KDOD cascading units and cadre and required id…
Browse files Browse the repository at this point in the history
…entifiers for civilian rank (#51)

* (fix) remove null values from queues query params (#27)

* (feat) KDOD service unit filters

* (feat) KHP3-6944 : Add KDOD cascading units and cadre and required identifiers for civilian rank

* (feat) add dynamic showing of publication number
  • Loading branch information
donaldkibet authored Nov 5, 2024
1 parent 66c8afe commit fb67255
Show file tree
Hide file tree
Showing 13 changed files with 35,644 additions and 36 deletions.
5,849 changes: 5,849 additions & 0 deletions packages/esm-active-visits-app/package-lock.json

Large diffs are not rendered by default.

5,893 changes: 5,893 additions & 0 deletions packages/esm-bed-management-app/package-lock.json

Large diffs are not rendered by default.

5,901 changes: 5,901 additions & 0 deletions packages/esm-patient-list-management-app/package-lock.json

Large diffs are not rendered by default.

6,047 changes: 6,047 additions & 0 deletions packages/esm-patient-registration-app/package-lock.json

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -111,10 +111,6 @@
svg {
margin-left: layout.$spacing-03;
}

.customField {
margin-bottom: layout.$spacing-05;
}
}

.attributeField {
Expand Down Expand Up @@ -169,3 +165,7 @@
line-height: 1.34;
margin: layout.$spacing-02 0 0;
}

.customField {
margin-bottom: layout.$spacing-05;
}
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ export function CodedPersonAttributeField({
return (
<>
<Select
style={{ marginBottom: '1rem' }}
id={id}
name={`person-attribute-${personAttributeType.uuid}`}
labelText={label ?? personAttributeType?.display}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,43 @@
import React from 'react';
import { Field } from 'formik';
import React, { useContext, useEffect } from 'react';
import { Field, type FieldProps } from 'formik';
import { Layer, Select, SelectItem } from '@carbon/react';
import { type PersonAttributeTypeResponse } from '../../patient-registration.types';
import { useTranslation } from 'react-i18next';
import styles from './../field.scss';
import classNames from 'classnames';
import { PatientRegistrationContext } from '../../patient-registration-context';
import styles from './../field.scss';
import { ResourcesContext } from '../../../offline.resources';
import useUpdateIdentifierRequirement from './useUpdateIdentifierRequirement';

type CustomPersonAttributeFieldProps = {
interface PersonAttributeTypeResponse {
uuid: string;
display?: string;
}

interface ConceptAnswer {
uuid?: string;
name?: string;
label?: string;
showServiceExpression?: {
attributeTypeUuid: string;
value: string;
};
}

interface CustomPersonAttributeFieldProps {
id: string;
personAttributeType: PersonAttributeTypeResponse;
answerConceptSetUuid: string;
label?: string;
customConceptAnswers: Array<{ uuid: string; label?: string }>;
customConceptAnswers: ConceptAnswer[];
required: boolean;
};
}

interface PatientRegistrationContextType {
setFieldValue: (field: string, value: any) => void;
values: {
attributes?: Record<string, string>;
};
}

const CustomPersonAttributeField: React.FC<CustomPersonAttributeFieldProps> = ({
personAttributeType,
Expand All @@ -24,30 +48,55 @@ const CustomPersonAttributeField: React.FC<CustomPersonAttributeFieldProps> = ({
}) => {
const { t } = useTranslation();
const fieldName = `attributes.${personAttributeType.uuid}`;
const { setFieldValue, values } = useContext(PatientRegistrationContext);
useUpdateIdentifierRequirement(setFieldValue, values);
// TODO: Improve this logic
const filteredCustomConceptAnswers = customConceptAnswers.filter((answer) => {
const showExpression = answer.showServiceExpression;
if (!showExpression) return true;

const attributeValue = values?.attributes?.[showExpression.attributeTypeUuid];
const answerCadreId = answer.name;

if (answerCadreId == null) return true;

return showExpression.value.toLowerCase() === attributeValue?.toLowerCase();
});

useEffect(() => {
return () => {
setFieldValue(fieldName, '');
};
}, [fieldName, setFieldValue]);

const renderSelect = ({ field, form: { touched, errors } }: FieldProps) => {
const hasError = errors[fieldName] && touched[fieldName];
const displayLabel = label ?? personAttributeType?.display ?? '';

return (
<Select
id={id}
name={`person-attribute-${personAttributeType.uuid}`}
labelText={displayLabel}
invalid={Boolean(hasError)}
required={required}
{...field}>
<SelectItem value="" text={t('selectAnOption', 'Select an option')} />
{filteredCustomConceptAnswers.map((answer) => (
<SelectItem
key={answer.uuid ?? answer.name}
value={answer.uuid ?? answer.name ?? ''}
text={answer.label ?? answer.uuid ?? answer.name ?? ''}
/>
))}
</Select>
);
};

return (
<div className={classNames(styles.customField, styles.halfWidthInDesktopView)}>
<Layer>
<Field name={fieldName}>
{({ field, form: { touched, errors }, meta }) => {
return (
<>
<Select
id={id}
name={`person-attribute-${personAttributeType.uuid}`}
labelText={label ?? personAttributeType?.display}
invalid={errors[fieldName] && touched[fieldName]}
required={required}
{...field}>
<SelectItem value={''} text={t('selectAnOption', 'Select an option')} />
{customConceptAnswers.map((answer) => (
<SelectItem key={answer.uuid} value={answer.uuid} text={answer.uuid} />
))}
</Select>
</>
);
}}
</Field>
<Field name={fieldName}>{renderSelect}</Field>
</Layer>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { useEffect, useCallback, useRef, useMemo, useContext } from 'react';
import { deleteIdentifierType, initializeIdentifier } from '../id/id-field.component';
import { ResourcesContext } from '../../../offline.resources';

const useUpdateIdentifierRequirement = (setFieldValue, values) => {
const { identifierTypes = [] } = useContext(ResourcesContext);
const previousAttributes = useRef(values.attributes);
const previousIdentifiers = useRef(values.identifiers);

const publicationNumberIdentifier = useMemo(
() => identifierTypes?.find((identifier) => identifier.name === 'Publication Number'),
[identifierTypes],
);

// Memoize the civilian check
const isCivilian = useMemo(() => Object.values(values.attributes ?? {}).includes('Civilian'), [values.attributes]);

// Memoize the identifier initialization logic
const initializePublicationIdentifier = useCallback(
(currentIdentifiers) => {
if (!publicationNumberIdentifier) {
console.warn('Publication Number identifier type not found');
return null;
}

const initializedIdentifier = initializeIdentifier(
publicationNumberIdentifier,
currentIdentifiers[publicationNumberIdentifier.uuid],
);

return initializedIdentifier;
},
[publicationNumberIdentifier],
);
// Only run the effect if isCivilian is true
useEffect(() => {
// Skip if we don't have the required data
if (!values.attributes || !publicationNumberIdentifier) {
return;
}

// Check if relevant values have actually changed
const attributesChanged = previousAttributes.current !== values.attributes;
const identifiersChanged = previousIdentifiers.current !== values.identifiers;

if (!attributesChanged && !identifiersChanged) {
return;
}

// Update refs
previousAttributes.current = values.attributes;
previousIdentifiers.current = values.identifiers;
const isDependant = Object.values(values.attributes ?? {}).includes('Dependant');
// Only proceed if the user is a civilian
if (isCivilian && isDependant) {
const initializedIdentifier = initializePublicationIdentifier(values.identifiers);

// check if values.identifiers already has the publication number identifier
const hasPublicationNumberIdentifier = values.identifiers[publicationNumberIdentifier.fieldName];

if (initializedIdentifier && !hasPublicationNumberIdentifier) {
setFieldValue('identifiers', {
...values.identifiers,
[publicationNumberIdentifier.fieldName]: { ...initializedIdentifier, required: true },
});
}
} else {
// Before deleting the publication number identifier, check if it exists
if (values.identifiers[publicationNumberIdentifier.fieldName]) {
setFieldValue('identifiers', deleteIdentifierType(values.identifiers, publicationNumberIdentifier.fieldName));
}
}
}, [
values.attributes,
values.identifiers,
isCivilian,
publicationNumberIdentifier,
initializePublicationIdentifier,
setFieldValue,
]);
};

export default useUpdateIdentifierRequirement;
Loading

0 comments on commit fb67255

Please sign in to comment.