Skip to content

Commit

Permalink
Merge branch 'main' into CNFT1-2753-address-type-update
Browse files Browse the repository at this point in the history
  • Loading branch information
Michael Peels authored and Michael Peels committed Sep 18, 2024
2 parents 5b48747 + 7386ba3 commit 90c02ea
Show file tree
Hide file tree
Showing 10 changed files with 396 additions and 44 deletions.
Original file line number Diff line number Diff line change
@@ -1,26 +1,27 @@
import { FormProvider, useForm } from 'react-hook-form';
import { PhoneAndEmailMultiEntry } from './inputs/phone/PhoneAndEmailMultiEntry';
import { PhoneEmailFields } from 'apps/patient/profile/phoneEmail/PhoneEmailEntry';
import { useState } from 'react';
import { AddPatientExtendedNav } from './nav/AddPatientExtendedNav';
import { AddressMultiEntry } from './inputs/address/AddressMultiEntry';
import { RaceMultiEntry } from './inputs/race/RaceMultiEntry';
import { RaceEntry } from 'apps/patient/profile/race/RaceEntry';
import { AddressEntry, AdministrativeEntry, PhoneEmailEntry } from 'apps/patient/data/entry';
import { NameEntry } from 'apps/patient/profile/names/NameEntry';
import { RaceEntry } from 'apps/patient/profile/race/RaceEntry';
import { internalizeDate } from 'date';
import { useState } from 'react';
import { FormProvider, useForm } from 'react-hook-form';
import { NameMultiEntry } from './inputs/Name/NameMultiEntry';
import { AddressMultiEntry } from './inputs/address/AddressMultiEntry';
import { Administrative } from './inputs/administrative/Administrative';
import { AddressEntry, AdministrativeEntry } from 'apps/patient/data/entry';
import { internalizeDate } from 'date';
import { PhoneAndEmailMultiEntry } from './inputs/phone/PhoneAndEmailMultiEntry';
import { RaceMultiEntry } from './inputs/race/RaceMultiEntry';
import { AddPatientExtendedNav } from './nav/AddPatientExtendedNav';
import styles from './add-patient-extended-form.module.scss';

// Once all sections have been updated with proper types this will be removed
type ExtendedPatientCreationForm = {
administrative: AdministrativeEntry;
address: AddressEntry[];
phone: PhoneEmailFields[];
phone: PhoneEmailEntry[];
race: RaceEntry[];
name: NameEntry[];
};

// used to track sub-form state to display error on parent form submisson
type DirtyState = {
address: boolean;
phone: boolean;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,16 @@ jest.mock('apps/patient/profile/phoneEmail/usePatientPhoneCodedValues', () => ({
usePatientPhoneCodedValues: () => mockPatientPhoneCodedValues
}));

const awaitRender = async () => {
// wait on render to prevent act warning
expect(await screen.findByText('URL')).toBeInTheDocument();
};

describe('PhoneAndEmailMultiEntry', () => {
it('should display correct table headers', async () => {
const { getAllByRole } = render(<PhoneAndEmailMultiEntry onChange={onChange} isDirty={isDirty} />);
// wait on render to prevent act warning
await awaitRender();

const headers = getAllByRole('columnheader');
expect(headers[0]).toHaveTextContent('As of');
Expand All @@ -29,6 +36,8 @@ describe('PhoneAndEmailMultiEntry', () => {

it('should display proper defaults', async () => {
const { getByLabelText } = render(<PhoneAndEmailMultiEntry onChange={onChange} isDirty={isDirty} />);
// wait on render to prevent act warning
await awaitRender();

const dateInput = getByLabelText('Phone & email as of');
expect(dateInput).toHaveValue(internalizeDate(new Date()));
Expand Down Expand Up @@ -62,6 +71,8 @@ describe('PhoneAndEmailMultiEntry', () => {
const { getByLabelText, getAllByRole } = render(
<PhoneAndEmailMultiEntry onChange={onChange} isDirty={isDirty} />
);
// wait on render to prevent act warning
await awaitRender();
const type = getByLabelText('Type');
const use = getByLabelText('Use');
const countryCode = getByLabelText('Country code');
Expand Down Expand Up @@ -95,10 +106,10 @@ describe('PhoneAndEmailMultiEntry', () => {
countryCode: '1',
email: 'email@email.com',
extension: '2',
number: '123-456-7890',
type: 'PH',
phoneNumber: '123-456-7890',
type: mockPatientPhoneCodedValues.types[0],
url: 'url',
use: 'H'
use: mockPatientPhoneCodedValues.uses[0]
}
]);
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,41 +1,39 @@
import { PhoneAndEmailEntryFields } from 'apps/patient/profile/phoneEmail/PhoneAndEmailEntryFields';
import { PhoneEmailFields } from 'apps/patient/profile/phoneEmail/PhoneEmailEntry';
import { PhoneEmailEntry } from 'apps/patient/data/entry';
import { PhoneEmailEntryFields } from 'apps/patient/data/phoneEmail/PhoneEmailEntryFields';
import { internalizeDate } from 'date';
import { MultiValueEntry } from 'design-system/entry/multi-value/MultiValueEntry';
import { Column } from 'design-system/table';
import { PhoneEntryView } from './PhoneEntryView';
import { usePatientPhoneCodedValues } from 'apps/patient/profile/phoneEmail/usePatientPhoneCodedValues';

const defaultValue: PhoneEmailFields = {
const defaultValue: Partial<PhoneEmailEntry> = {
asOf: internalizeDate(new Date()),
type: '',
use: '',
type: undefined,
use: undefined,
countryCode: '',
number: '',
phoneNumber: '',
extension: '',
email: '',
url: '',
comment: ''
};
type Props = {
onChange: (data: PhoneEmailFields[]) => void;
onChange: (data: PhoneEmailEntry[]) => void;
isDirty: (isDirty: boolean) => void;
};
export const PhoneAndEmailMultiEntry = ({ onChange, isDirty }: Props) => {
const coded = usePatientPhoneCodedValues();
const renderForm = () => <PhoneAndEmailEntryFields />;
const renderView = (entry: PhoneEmailFields) => <PhoneEntryView entry={entry} />;
const renderForm = () => <PhoneEmailEntryFields />;
const renderView = (entry: PhoneEmailEntry) => <PhoneEntryView entry={entry} />;

const columns: Column<PhoneEmailFields>[] = [
const columns: Column<PhoneEmailEntry>[] = [
{ id: 'phoneEmailAsOf', name: 'As of', render: (v) => v.asOf },
{ id: 'phoneEmailType', name: 'Type', render: (v) => coded.types.find((t) => t.value === v.type)?.name },
{ id: 'phoneNumber', name: 'Phone number', render: (v) => v.number },
{ id: 'phoneEmailType', name: 'Type', render: (v) => v.type?.name },
{ id: 'phoneNumber', name: 'Phone number', render: (v) => v.phoneNumber },
{ id: 'email', name: 'Email address', render: (v) => v.email },
{ id: 'comments', name: 'Comments', render: (v) => v.comment }
];

return (
<MultiValueEntry<PhoneEmailFields>
<MultiValueEntry<PhoneEmailEntry>
id="section-PhoneAndEmail"
title="Phone & email"
defaultValues={defaultValue}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { render } from '@testing-library/react';
import { PhoneEmailEntry } from 'apps/patient/data/entry';
import { PhoneEntryView } from './PhoneEntryView';
import { PhoneEmailFields } from 'apps/patient/profile/phoneEmail/PhoneEmailEntry';

const mockPatientPhoneCodedValues = {
types: [{ name: 'Phone', value: 'PH' }],
Expand All @@ -11,12 +11,12 @@ jest.mock('apps/patient/profile/phoneEmail/usePatientPhoneCodedValues', () => ({
usePatientPhoneCodedValues: () => mockPatientPhoneCodedValues
}));

const entry: PhoneEmailFields = {
const entry: PhoneEmailEntry = {
asOf: '12/25/2020',
type: 'PH',
use: 'H',
type: { name: 'Phone', value: 'PH' },
use: { name: 'Home', value: 'H' },
countryCode: '1',
number: '123-456-7890',
phoneNumber: '123-456-7890',
extension: '2',
email: 'email@email.com',
url: 'someUrl@nbs.gov',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
import { PhoneEmailFields } from 'apps/patient/profile/phoneEmail/PhoneEmailEntry';
import { usePatientPhoneCodedValues } from 'apps/patient/profile/phoneEmail/usePatientPhoneCodedValues';
import { PhoneEmailEntry } from 'apps/patient/data/entry';
import { DataDisplay } from 'design-system/data-display/DataDisplay';

type Props = {
entry: PhoneEmailFields;
entry: PhoneEmailEntry;
};
export const PhoneEntryView = ({ entry }: Props) => {
const coded = usePatientPhoneCodedValues();
return (
<>
<DataDisplay title="As of" value={entry.asOf} required />
<DataDisplay title="Type" value={coded.types.find((e) => e.value === entry.type)?.name} required />
<DataDisplay title="Use" value={coded.uses.find((e) => e.value === entry.use)?.name} required />
<DataDisplay title="Type" value={entry.type.name} required />
<DataDisplay title="Use" value={entry.use.name} required />
<DataDisplay title="Country code" value={entry.countryCode} />
<DataDisplay title="Phone number" value={entry.number} />
<DataDisplay title="Phone number" value={entry.phoneNumber} />
<DataDisplay title="Extension" value={entry.extension} />
<DataDisplay title="Email" value={entry.email} />
<DataDisplay title="URL" value={entry.url} />
Expand Down
2 changes: 1 addition & 1 deletion apps/modernization-ui/src/apps/patient/data/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
export { asAdministrative } from './asAdministrative';
export { asName } from './asName';
export { asAddress } from './address/asAddress';
export { asPhoneEmail } from './asPhoneEmail';
export { asPhoneEmail } from './phoneEmail/asPhoneEmail';
export { asIdentification } from './asIdentification';
export { asRace } from './asRace';
export { asEthnicity } from './asEthnicity';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import { fireEvent, render, waitFor, screen } from '@testing-library/react';
import { renderHook } from '@testing-library/react-hooks';
import { act } from 'react-dom/test-utils';
import { FormProvider, useForm } from 'react-hook-form';
import { PhoneEmailEntry } from '../entry';
import { PhoneEmailEntryFields } from './PhoneEmailEntryFields';
import userEvent from '@testing-library/user-event';

const mockPatientPhoneCodedValues = {
types: [{ name: 'Phone', value: 'PH' }],
uses: [{ name: 'Home', value: 'H' }]
};

jest.mock('apps/patient/profile/phoneEmail/usePatientPhoneCodedValues', () => ({
usePatientPhoneCodedValues: () => mockPatientPhoneCodedValues
}));

const form = renderHook(() =>
useForm<PhoneEmailEntry>({
mode: 'onBlur',
defaultValues: {
asOf: undefined,
type: undefined,
use: undefined,
countryCode: '',
phoneNumber: '',
extension: '',
email: '',
url: '',
comment: ''
}
})
).result.current;

describe('PhoneEmailEntryFields', () => {
it('should render the proper labels', () => {
const { getByLabelText } = render(
<FormProvider {...form}>
<PhoneEmailEntryFields />
</FormProvider>
);

expect(getByLabelText('Phone & email as of')).toBeInTheDocument();
expect(getByLabelText('Type')).toBeInTheDocument();
expect(getByLabelText('Use')).toBeInTheDocument();
expect(getByLabelText('Country code')).toBeInTheDocument();
expect(getByLabelText('Phone number')).toBeInTheDocument();
expect(getByLabelText('Extension')).toBeInTheDocument();
expect(getByLabelText('Email')).toBeInTheDocument();
expect(getByLabelText('Phone & email comments')).toBeInTheDocument();
});

it('should require type', async () => {
const { getByLabelText, getByText } = render(
<FormProvider {...form}>
<PhoneEmailEntryFields />
</FormProvider>
);

const typeInput = getByLabelText('Type');
act(() => {
fireEvent.blur(typeInput);
});
await waitFor(() => {
expect(getByText('Type is required.')).toBeInTheDocument();
});
});

it('should require use', async () => {
const { getByLabelText, getByText } = render(
<FormProvider {...form}>
<PhoneEmailEntryFields />
</FormProvider>
);

const useInput = getByLabelText('Use');
act(() => {
fireEvent.blur(useInput);
});
await waitFor(() => {
expect(getByText('Use is required.')).toBeInTheDocument();
});
});

it('should require as of', async () => {
const { getByLabelText, getByText } = render(
<FormProvider {...form}>
<PhoneEmailEntryFields />
</FormProvider>
);

const asOf = getByLabelText('Phone & email as of');
act(() => {
fireEvent.blur(asOf);
});
await waitFor(() => {
expect(getByText('As of date is required.')).toBeInTheDocument();
});
});

it('should be valid with as of, type, and use', async () => {
const { getByLabelText } = render(
<FormProvider {...form}>
<PhoneEmailEntryFields />
</FormProvider>
);

const asOf = getByLabelText('Phone & email as of');
const type = getByLabelText('Type');
const use = getByLabelText('Use');
await screen.findByText('Use');
act(() => {
userEvent.paste(asOf, '01/20/2020');
fireEvent.blur(asOf);
userEvent.selectOptions(use, 'H');
fireEvent.blur(use);
userEvent.selectOptions(type, 'PH');
fireEvent.blur(type);
});

await waitFor(() => {
expect(form.getFieldState('asOf').invalid).toBeFalsy();
expect(form.getFieldState('type').invalid).toBeFalsy();
expect(form.getFieldState('use').invalid).toBeFalsy();
});
});
});
Loading

0 comments on commit 90c02ea

Please sign in to comment.