Skip to content

Commit

Permalink
Merge branch 'main' into id-field
Browse files Browse the repository at this point in the history
  • Loading branch information
ayush-AI authored Jul 8, 2023
2 parents e6da75e + 2d15566 commit 06b428b
Show file tree
Hide file tree
Showing 23 changed files with 470 additions and 177 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -253,9 +253,7 @@ export function useVisitQueueEntries(currServiceName: string, locationUuid: stri
?.map(mapVisitQueueEntryProperties)
.filter((data) => dayjs(data.visitStartDateTime).isToday());
} else {
mappedVisitQueueEntries = data?.data?.results
?.map(mapVisitQueueEntryProperties)
.filter((data) => data.service === currServiceName && dayjs(data.visitStartDateTime).isToday());
mappedVisitQueueEntries = data?.data?.results?.map(mapVisitQueueEntryProperties);
}

return {
Expand Down Expand Up @@ -349,9 +347,7 @@ export function useServiceQueueEntries(service: string, locationUuid: string) {
patientUuid: visitQueueEntry.queueEntry ? visitQueueEntry?.queueEntry.uuid : '--',
});

const mappedServiceQueueEntries = data?.data?.results
?.map(mapServiceQueueEntryProperties)
.filter(({ returnDate }) => dayjs(returnDate).isToday());
const mappedServiceQueueEntries = data?.data?.results?.map(mapServiceQueueEntryProperties);

return {
serviceQueueEntries: mappedServiceQueueEntries ? mappedServiceQueueEntries : [],
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React from 'react';
import { render, fireEvent } from '@testing-library/react';
import * as esmFramework from '@openmrs/esm-framework';
import Root from './add-patient-link';

describe('Add patient link component', () => {
it('renders an "Add Patient" button and triggers navigation on click', () => {
const navigateMock = jest.fn();
jest.spyOn(esmFramework, 'navigate').mockImplementation(navigateMock);

const { getByRole } = render(<Root />);
const addButton = getByRole('button', { name: /add patient/i });

fireEvent.click(addButton);

expect(navigateMock).toHaveBeenCalledWith({ to: '${openmrsSpaBase}/patient-registration' });
});
});
6 changes: 6 additions & 0 deletions packages/esm-patient-registration-app/src/config-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export interface RegistrationConfig {
defaultUnknownGivenName: string;
defaultUnknownFamilyName: string;
displayCapturePhoto: boolean;
displayReverseFieldOrder: boolean;
};
gender: Array<Gender>;
address: {
Expand Down Expand Up @@ -220,6 +221,11 @@ export const esmPatientRegistrationSchema = {
_default: true,
_description: 'Whether to display capture patient photo slot on name field',
},
displayReverseFieldOrder: {
_type: Type.Boolean,
_default: false,
_description: "Whether to display the name fields in the order 'Family name' -> 'Middle name' -> 'First name'",
},
},
gender: {
_type: Type.Array,
Expand Down
13 changes: 13 additions & 0 deletions packages/esm-patient-registration-app/src/nav-link.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React from 'react';
import { render } from '@testing-library/react';
import Root from './nav-link';

describe('Nav link component', () => {
it('renders a link to the patient registration page', () => {
const { getByText } = render(<Root />);
const linkElement = getByText('Patient Registration');

expect(linkElement).toBeInTheDocument();
expect(linkElement).toHaveAttribute('href', '/openmrs/spa/patient-registration');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ function checkNumber(value: string) {
export const NameField = () => {
const {
fieldConfigurations: {
name: { displayCapturePhoto },
name: { displayCapturePhoto, displayReverseFieldOrder },
},
} = useConfig() as RegistrationConfig;
const { t } = useTranslation();
Expand Down Expand Up @@ -55,6 +55,36 @@ export const NameField = () => {
}
};

const firstNameField = (
<Input
id="givenName"
name="givenName"
labelText={t('givenNameLabelText', 'First Name')}
checkWarning={checkNumber}
required
/>
);

const middleNameField = fieldConfigs.displayMiddleName && (
<Input
id="middleName"
name="middleName"
labelText={t('middleNameLabelText', 'Middle Name')}
light
checkWarning={checkNumber}
/>
);

const familyNameField = (
<Input
id="familyName"
name="familyName"
labelText={t('familyNameLabelText', 'Family Name')}
checkWarning={checkNumber}
required
/>
);

return (
<div>
<h4 className={styles.productiveHeading02Light}>{t('fullNameLabelText', 'Full Name')}</h4>
Expand All @@ -75,33 +105,20 @@ export const NameField = () => {
<Switch name="known" text={t('yes', 'Yes')} />
<Switch name="unknown" text={t('no', 'No')} />
</ContentSwitcher>
{nameKnown && (
<>
<Input
id="givenName"
name="givenName"
labelText={t('givenNameLabelText', 'First Name')}
checkWarning={checkNumber}
required
/>
{fieldConfigs.displayMiddleName && (
<Input
id="middleName"
name="middleName"
labelText={t('middleNameLabelText', 'Middle Name')}
light
checkWarning={checkNumber}
/>
)}
<Input
id="familyName"
name="familyName"
labelText={t('familyNameLabelText', 'Family Name')}
checkWarning={checkNumber}
required
/>
</>
)}
{nameKnown &&
(!displayReverseFieldOrder ? (
<>
{firstNameField}
{middleNameField}
{familyNameField}
</>
) : (
<>
{familyNameField}
{middleNameField}
{firstNameField}
</>
))}
</div>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useCallback, useMemo, useRef, useState } from 'react';
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { TextInput, Layer } from '@carbon/react';
import SelectionTick from './selection-tick.component';
import styles from '../input.scss';
Expand Down Expand Up @@ -26,18 +26,6 @@ const ComboInput: React.FC<ComboInputProps> = ({ entries, fieldProps, handleInpu
setHighlightedEntry(-1);
}, [setShowEntries, setHighlightedEntry]);

const handleBlur = useCallback(
(e) => {
// This check is in place to not hide the entries when an entry is clicked
// Else the onClick of the entry will not be counted.
if (!comboInputRef?.current?.contains(e.target)) {
setShowEntries(false);
}
setHighlightedEntry(-1);
},
[setShowEntries, setHighlightedEntry],
);

const filteredEntries = useMemo(() => {
if (!entries) {
return [];
Expand All @@ -60,6 +48,12 @@ const ComboInput: React.FC<ComboInputProps> = ({ entries, fieldProps, handleInpu
const handleKeyPress = useCallback(
(e: KeyboardEvent) => {
const totalResults = filteredEntries.length ?? 0;

if (e.key === 'Tab') {
setShowEntries(false);
setHighlightedEntry(-1);
}

if (e.key === 'ArrowUp') {
setHighlightedEntry((prev) => Math.max(-1, prev - 1));
} else if (e.key === 'ArrowDown') {
Expand All @@ -68,17 +62,32 @@ const ComboInput: React.FC<ComboInputProps> = ({ entries, fieldProps, handleInpu
handleOptionClick(filteredEntries[highlightedEntry], e);
}
},
[highlightedEntry, handleOptionClick, filteredEntries, setHighlightedEntry],
[highlightedEntry, handleOptionClick, filteredEntries, setHighlightedEntry, setShowEntries],
);

useEffect(() => {
const listener = (e) => {
if (!comboInputRef.current.contains(e.target as Node)) {
setShowEntries(false);
setHighlightedEntry(-1);
}
};
window.addEventListener('click', listener);
return () => {
window.removeEventListener('click', listener);
};
});

return (
<div className={styles.comboInput} ref={comboInputRef}>
<Layer>
<TextInput
{...fieldProps}
onChange={(e) => handleInputChange(e.target.value)}
onChange={(e) => {
setHighlightedEntry(-1);
handleInputChange(e.target.value);
}}
onFocus={handleFocus}
onBlur={handleBlur}
autoComplete={'off'}
onKeyDown={handleKeyPress}
/>
Expand All @@ -98,7 +107,7 @@ const ComboInput: React.FC<ComboInputProps> = ({ entries, fieldProps, handleInpu
aria-selected="true"
onClick={() => handleOptionClick(entry)}>
<div
className={`cds--list-box__menu-item__option ${
className={`cds--list-box__menu-item__option ${styles.comboInputItemOption} ${
entry === value && 'cds--list-box__menu-item--active'
}`}>
{entry}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,3 +111,8 @@
.comboInputEntries {
position: relative;
}

.comboInputItemOption {
margin: 0;
padding-left: 1rem;
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Formik, Form } from 'formik';
import { initialFormValues } from '../../patient-registration.component';
import { DeathInfoSection } from './death-info-section.component';
import { FormValues } from '../../patient-registration-types';
import { PatientRegistrationContext } from '../../patient-registration-context';

jest.mock('@openmrs/esm-framework', () => {
const originalModule = jest.requireActual('@openmrs/esm-framework');
Expand All @@ -15,16 +16,18 @@ jest.mock('@openmrs/esm-framework', () => {
});

// TODO: Implement feature and get tests to pass
describe.skip('death info section', () => {
describe('death info section', () => {
const formValues: FormValues = initialFormValues;

const setupSection = async (isDead?: boolean) => {
render(
<Formik initialValues={{ ...initialFormValues, isDead }} onSubmit={null}>
<Form>
<DeathInfoSection />
</Form>
</Formik>,
<PatientRegistrationContext.Provider value={{ values: { isDead: isDead || false } }}>
<Formik initialValues={{ ...initialFormValues, isDead }} onSubmit={null}>
<Form>
<DeathInfoSection />
</Form>
</Formik>
</PatientRegistrationContext.Provider>,
);
const allInputs = screen.queryAllByLabelText(
(content, element) => element.tagName.toLowerCase() === 'input',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { SearchedPatient } from '../types';
import { Search, Button } from '@carbon/react';
import { useTranslation } from 'react-i18next';
import styles from './compact-patient-search.scss';
import { usePatientSearchInfinite } from '../patient-search.resource';
import { useInfinitePatientSearch } from '../patient-search.resource';
import { useConfig, navigate, interpolateString } from '@openmrs/esm-framework';
import useArrowNavigation from '../hooks/useArrowNavigation';

Expand All @@ -24,7 +24,7 @@ const CompactPatientSearchComponent: React.FC<CompactPatientSearchProps> = ({
const handleChange = useCallback((val) => setSearchTerm(val), [setSearchTerm]);
const showSearchResults = useMemo(() => !!searchTerm?.trim(), [searchTerm]);
const config = useConfig();
const patientSearchResponse = usePatientSearchInfinite(searchTerm, config.includeDead, showSearchResults);
const patientSearchResponse = useInfinitePatientSearch(searchTerm, config.includeDead, showSearchResults);
const { data: patients } = patientSearchResponse;

const handleSubmit = useCallback((evt) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,24 @@ import React, { useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { SkeletonIcon, SkeletonText, Tag } from '@carbon/react';
import { ExtensionSlot, useConfig, interpolateString, ConfigurableLink, age } from '@openmrs/esm-framework';
import { Identifier, SearchedPatient } from '../types/index';
import type { Identifier, SearchedPatient } from '../types';
import styles from './compact-patient-banner.scss';

interface PatientSearchResultsProps {
patients: Array<SearchedPatient>;
selectPatientAction?: (evt: any, index: number) => void;
selectPatientAction?: (
event: React.MouseEvent<HTMLAnchorElement>,
index: number,
patients: Array<SearchedPatient>,
) => void;
}

const PatientSearchResults = React.forwardRef<HTMLDivElement, PatientSearchResultsProps>(
({ patients, selectPatientAction }, ref) => {
const config = useConfig();
const { t } = useTranslation();

const getGender = (gender) => {
const getGender = (gender: string) => {
switch (gender) {
case 'M':
return t('male', 'Male');
Expand Down Expand Up @@ -68,14 +72,15 @@ const PatientSearchResults = React.forwardRef<HTMLDivElement, PatientSearchResul

return (
<div ref={ref}>
{fhirPatients.map((patient, indx) => {
{fhirPatients.map((patient, index) => {
const patientIdentifiers = patient.identifier.filter((identifier) =>
config.defaultIdentifierTypes.includes(identifier.identifierType.uuid),
);
const isDeceased = Boolean(patient?.deceasedDateTime);

return (
<ConfigurableLink
onClick={(evt) => selectPatientAction(evt, indx)}
onClick={(event) => selectPatientAction(event, index, patients)}
to={`${interpolateString(config.search.patientResultUrl, {
patientUuid: patient.id,
})}`}
Expand Down Expand Up @@ -110,7 +115,7 @@ const PatientSearchResults = React.forwardRef<HTMLDivElement, PatientSearchResul
{patientIdentifiers.length > 1 ? (
<PatientIdentifier identifiers={patientIdentifiers} />
) : (
<CustomIdentifier patient={patients[indx]} identifierName={config.defaultIdentifier} />
<CustomIdentifier patient={patients[index]} identifierName={config.defaultIdentifier} />
)}
</>
) : (
Expand Down Expand Up @@ -172,6 +177,7 @@ const CustomIdentifier: React.FC<{ patient: SearchedPatient; identifierName: str
identifierName,
}) => {
const identifier = patient.identifiers.find((identifier) => identifier.identifierType.display === identifierName);

return identifier ? (
<>
<Tag size="sm" className={styles.configuredTag} type="warm-gray" title={identifier.display}>
Expand Down
Loading

0 comments on commit 06b428b

Please sign in to comment.