Skip to content

Commit

Permalink
Extended patient: Address (#1803)
Browse files Browse the repository at this point in the history
* WIP

* Address section testing

* Add dependency mock to test

---------

Co-authored-by: Michael Peels <michaelpeels@Michael-Peels.local>
  • Loading branch information
mpeels and Michael Peels authored Sep 12, 2024
1 parent 55e5177 commit 592cf67
Show file tree
Hide file tree
Showing 10 changed files with 304 additions and 20 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,29 @@
import { getAllByRole, render } from '@testing-library/react';
import { render } from '@testing-library/react';
import { AddPatientExtended } from './AddPatientExtended';
import { MemoryRouter } from 'react-router-dom';
import { CodedValue } from 'coded';
const mockPatientAddressCodedValues = {
types: [{ name: 'House', value: 'H' }],
uses: [{ name: 'Home', value: 'HM' }]
};

jest.mock('apps/patient/profile/addresses/usePatientAddressCodedValues', () => ({
usePatientAddressCodedValues: () => mockPatientAddressCodedValues
}));

const mockLocationCodedValues = {
states: {
all: [{ name: 'StateName', value: '1' }]
},
counties: {
byState: (state: string) => [{ name: 'CountyName', value: '2' }]
},
countries: [{ name: 'CountryName', value: '3' }]
};

jest.mock('location/useLocationCodedValues', () => ({
useLocationCodedValues: () => mockLocationCodedValues
}));
const mockPatientPhoneCodedValues = {
types: [{ name: 'Phone', value: 'PH' }],
uses: [{ name: 'Home', value: 'H' }]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,37 @@ 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 { AddressFields } from 'apps/patient/profile/addresses/AddressEntry';
import { RaceMultiEntry } from './inputs/race/RaceMultiEntry';
import { RaceEntry } from 'apps/patient/profile/race/RaceEntry';

type ExtendedPatientCreationForm = {
address: AddressFields[];
phone: PhoneEmailFields[];
race: RaceEntry[];
};

type DirtyState = {
address: boolean;
phone: boolean;
race: boolean;
};
export const AddPatientExtendedForm = () => {
const form = useForm<ExtendedPatientCreationForm>({ defaultValues: { phone: [] } });
const [dirtyState, setDirtyState] = useState<DirtyState>({ phone: false, race: false });
const [dirtyState, setDirtyState] = useState<DirtyState>({ address: false, phone: false, race: false });

return (
<>
<div className={styles.addPatientForm}>
<FormProvider {...form}>
<div className={styles.formContent}>
<AddressMultiEntry
isDirty={(isDirty) => setDirtyState({ ...dirtyState, address: isDirty })}
onChange={(addressData) => {
form.setValue('address', addressData);
}}
/>
<PhoneAndEmailMultiEntry
isDirty={(isDirty) => setDirtyState({ ...dirtyState, phone: isDirty })}
onChange={(phoneEmailData) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { render } from '@testing-library/react';
import { internalizeDate } from 'date';
import { AddressMultiEntry } from './AddressMultiEntry';

const mockPatientAddressCodedValues = {
types: [{ name: 'House', value: 'H' }],
uses: [{ name: 'Home', value: 'HM' }]
};

jest.mock('apps/patient/profile/addresses/usePatientAddressCodedValues', () => ({
usePatientAddressCodedValues: () => mockPatientAddressCodedValues
}));

const mockLocationCodedValues = {
states: {
all: [{ name: 'StateName', value: '1' }]
},
counties: {
byState: (state: string) => [{ name: 'CountyName', value: '2' }]
},
countries: [{ name: 'CountryName', value: '3' }]
};

jest.mock('location/useLocationCodedValues', () => ({
useLocationCodedValues: () => mockLocationCodedValues
}));

const onChange = jest.fn();
const isDirty = jest.fn();

describe('RaceMultiEntry', () => {
it('should display correct table headers', async () => {
const { getAllByRole } = render(<AddressMultiEntry onChange={onChange} isDirty={isDirty} />);

const headers = getAllByRole('columnheader');
expect(headers[0]).toHaveTextContent('As of');
expect(headers[1]).toHaveTextContent('Type');
expect(headers[2]).toHaveTextContent('Address');
expect(headers[3]).toHaveTextContent('City');
expect(headers[4]).toHaveTextContent('State');
expect(headers[5]).toHaveTextContent('Zip');
});

it('should display proper defaults', async () => {
const { getByLabelText, getAllByRole, getAllByText } = render(
<AddressMultiEntry onChange={onChange} isDirty={isDirty} />
);

const dateInput = getByLabelText('Address as of');
expect(dateInput).toHaveValue(internalizeDate(new Date()));

const race = getByLabelText('Type');
expect(race).toHaveValue('');

const use = getByLabelText('Use');
expect(use).toHaveValue('');

const street1 = getByLabelText('Street address 1');
expect(street1).toHaveValue('');

const street2 = getByLabelText('Street address 2');
expect(street2).toHaveValue('');

const city = getByLabelText('City');
expect(city).toHaveValue('');

const state = getByLabelText('State');
expect(state).toHaveValue('');

const zip = getByLabelText('Zip');
expect(zip).toHaveValue('');

const county = getByLabelText('County');
expect(county).toHaveValue('');

const censusTract = getByLabelText('Census tract');
expect(censusTract).toHaveValue('');

const country = getByLabelText('Country');
expect(country).toHaveValue('');

const comments = getByLabelText('Address comments');
expect(comments).toHaveValue('');
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { AddressFields } from 'apps/patient/profile/addresses/AddressEntry';
import { AddressEntryFields } from 'apps/patient/profile/addresses/AddressEntryFields';
import { internalizeDate } from 'date';
import { MultiValueEntry } from 'design-system/entry/multi-value/MultiValueEntry';
import { Column } from 'design-system/table';
import { AddressView } from './AddressView';
import { usePatientAddressCodedValues } from 'apps/patient/profile/addresses/usePatientAddressCodedValues';
import { useLocationCodedValues } from 'location';

const defaultValue: AddressFields = {
asOf: internalizeDate(new Date()),
type: '',
use: '',
address1: '',
address2: '',
city: '',
state: '',
zipcode: '',
county: '',
country: '',
censusTract: '',
comment: ''
};

type Props = {
onChange: (data: AddressFields[]) => void;
isDirty: (isDirty: boolean) => void;
};
export const AddressMultiEntry = ({ onChange, isDirty }: Props) => {
const coded = usePatientAddressCodedValues();
const location = useLocationCodedValues();
const renderForm = () => <AddressEntryFields />;
const renderView = (entry: AddressFields) => <AddressView entry={entry} />;

const columns: Column<AddressFields>[] = [
{ id: 'addressAsOf', name: 'As of', render: (v) => v.asOf },
{ id: 'addressType', name: 'Type', render: (v) => coded.types.find((t) => t.value === v.type)?.name },
{ id: 'address', name: 'Address', render: (v) => v.address1 },
{ id: 'city', name: 'City', render: (v) => v.city },
{ id: 'state', name: 'State', render: (v) => location.states.all.find((s) => s.value === v.state)?.name },
{ id: 'zip', name: 'Zip', render: (v) => v.zipcode }
];

return (
<MultiValueEntry<AddressFields>
id="section-Address"
title="Address"
defaultValues={defaultValue}
columns={columns}
onChange={onChange}
isDirty={isDirty}
formRenderer={renderForm}
viewRenderer={renderView}
/>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { render } from '@testing-library/react';
import { AddressView } from './AddressView';
import { AddressFields } from 'apps/patient/profile/addresses/AddressEntry';

const mockPatientAddressCodedValues = {
types: [{ name: 'House', value: 'H' }],
uses: [{ name: 'Home', value: 'HM' }]
};

jest.mock('apps/patient/profile/addresses/usePatientAddressCodedValues', () => ({
usePatientAddressCodedValues: () => mockPatientAddressCodedValues
}));

const mockLocationCodedValues = {
states: {
all: [{ name: 'StateName', value: '1' }]
},
counties: {
byState: (state: string) => [{ name: 'CountyName', value: '2' }]
},
countries: [{ name: 'CountryName', value: '3' }]
};

jest.mock('location/useLocationCodedValues', () => ({
useLocationCodedValues: () => mockLocationCodedValues
}));

const entry: AddressFields = {
asOf: '12/25/2020',
type: 'H',
use: 'HM',
address1: '123 main st',
address2: '2nd floor',
city: 'city',
state: '1',
zipcode: '12345',
county: '2',
country: '3',
censusTract: '22222',
comment: 'comment'
};

describe('PhoneEntryView', () => {
it('should render label with values', () => {
const { getByText } = render(<AddressView entry={entry} />);
const asOf = getByText('Address as of');
expect(asOf.parentElement?.children[1]).toHaveTextContent('12/25/2020');

const type = getByText('Type');
expect(type.parentElement?.children[1]).toHaveTextContent('House');

const use = getByText('Use');
expect(use.parentElement?.children[1]).toHaveTextContent('Home');

const street1 = getByText('Street address 1');
expect(street1.parentElement?.children[1]).toHaveTextContent('123 main st');

const street2 = getByText('Street address 2');
expect(street2.parentElement?.children[1]).toHaveTextContent('2nd floor');

const city = getByText('City');
expect(city.parentElement?.children[1]).toHaveTextContent('city');

const state = getByText('State');
expect(state.parentElement?.children[1]).toHaveTextContent('StateName');

const zip = getByText('Zip');
expect(zip.parentElement?.children[1]).toHaveTextContent('12345');

const county = getByText('County');
expect(county.parentElement?.children[1]).toHaveTextContent('CountyName');

const censusTract = getByText('Census tract');
expect(censusTract.parentElement?.children[1]).toHaveTextContent('22222');

const country = getByText('Country');
expect(country.parentElement?.children[1]).toHaveTextContent('CountryName');

const comments = getByText('Address comments');
expect(comments.parentElement?.children[1]).toHaveTextContent('comment');
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { AddressFields } from 'apps/patient/profile/addresses/AddressEntry';
import { usePatientAddressCodedValues } from 'apps/patient/profile/addresses/usePatientAddressCodedValues';
import { DataDisplay } from 'design-system/data-display/DataDisplay';
import { useLocationCodedValues } from 'location';

type Props = {
entry: AddressFields;
};
export const AddressView = ({ entry }: Props) => {
const coded = usePatientAddressCodedValues();
const location = useLocationCodedValues();
const counties = location.counties.byState(entry.state ?? '');

return (
<>
<DataDisplay title="Address 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="Street address 1" value={entry.address1} />
<DataDisplay title="Street address 2" value={entry.address2} />
<DataDisplay title="City" value={entry.city} />
<DataDisplay title="State" value={location.states.all.find((s) => s.value === entry.state)?.name} />
<DataDisplay title="Zip" value={entry.zipcode} />
<DataDisplay title="County" value={counties.find((c) => c.value === entry.county)?.name} />
<DataDisplay title="Census tract" value={entry.censusTract} />
<DataDisplay title="Country" value={location.countries.find((c) => c.value === entry.country)?.name} />
<DataDisplay title="Address comments" value={entry.comment} />
</>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ describe('PhoneAndEmailMultiEntry', () => {
it('should display proper defaults', async () => {
const { getByLabelText } = render(<PhoneAndEmailMultiEntry onChange={onChange} isDirty={isDirty} />);

const dateInput = getByLabelText('As of');
const dateInput = getByLabelText('Phone & email as of');
expect(dateInput).toHaveValue(internalizeDate(new Date()));

const type = getByLabelText('Type');
Expand Down Expand Up @@ -86,7 +86,7 @@ describe('PhoneAndEmailMultiEntry', () => {
});

await waitFor(async () => {
const date = internalizeDate(new Date());
const date = internalizeDate(new Date());

expect(onChange).toHaveBeenNthCalledWith(2, [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,6 @@ type AddressEntry = NewAddressEntry | UpdateAddressEntry;
const isAdd = (obj: AddressEntry): obj is NewAddressEntry => !('id' in obj);
const isUpdate = (obj: AddressEntry): obj is NewAddressEntry => 'id' in obj;

export type { AddressEntry, NewAddressEntry, UpdateAddressEntry };
export type { AddressEntry, NewAddressEntry, UpdateAddressEntry, AddressFields };

export { isAdd, isUpdate };
Loading

0 comments on commit 592cf67

Please sign in to comment.