Skip to content

Commit

Permalink
LG-11082 - Add optional info alert to FullAddressSearch (#9276)
Browse files Browse the repository at this point in the history
* Add FullAddressSearchProps to types.d.ts

* Rename interfact, alpha order args

* Add resultsHeaderComponent arg, alpha order

* fix linter errors

* increase version of identity-address-search

* clean up duplicate interface

* update data type and tests

* delete unused var

* changelog: Upcoming Features, In-person proofing, Add new optional resultsHeaderComponent prop onto FullAddressSearch so it can be passed in from help center

* change data type

* Move FullAddressSearchInputProps to types.d

* Added logic to show/hide header and info text

* moved props back inside component

* Add show/hide logic to AddressSearch

* fix linter errors

* change prop type

* change data type

* update test

* lint fix

* add tests for address-search

* fix linter errors
  • Loading branch information
gina-yamada authored Sep 29, 2023
1 parent 8f4ef2d commit d32eb9f
Show file tree
Hide file tree
Showing 8 changed files with 177 additions and 43 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { render } from '@testing-library/react';
import sinon from 'sinon';
import { useSandbox } from '@18f/identity-test-helpers';
import { SWRConfig } from 'swr';
import AddressSearch from './address-search';

describe('AddressSearch', () => {
const sandbox = useSandbox();
const locationsURL = 'https://localhost:3000/locations/endpoint';

context('Page Heading and PO Search About Message', () => {
it('both render when handleLocationSelect is not null', async () => {
const handleLocationsFound = sandbox.stub();
const onSelect = sinon.stub();
const { queryByText, queryByRole } = render(
<SWRConfig value={{ provider: () => new Map() }}>
<AddressSearch
addressSearchURL="test"
disabled={false}
handleLocationSelect={onSelect}
locationsURL={locationsURL}
onFoundLocations={handleLocationsFound}
registerField={() => undefined}
/>
</SWRConfig>,
);

const heading = await queryByText('in_person_proofing.headings.po_search.location');
const aboutMessage = await queryByText(
'in_person_proofing.body.location.po_search.po_search_about',
);

expect(heading).to.exist();
expect(aboutMessage).to.exist();
expect(
queryByRole('heading', { name: 'in_person_proofing.headings.po_search.location' }),
).to.exist();
});

it('both do not render when handleLocationSelect is null', async () => {
const handleLocationsFound = sandbox.stub();
const onSelect = sinon.stub();
const { queryByText } = render(
<SWRConfig value={{ provider: () => new Map() }}>
<AddressSearch
addressSearchURL="test"
disabled={false}
handleLocationSelect={onSelect}
locationsURL={locationsURL}
onFoundLocations={handleLocationsFound}
registerField={() => undefined}
/>
</SWRConfig>,
);

const heading = await queryByText('in_person_proofing.headings.po_search.location');
const aboutMessage = await queryByText(
'in_person_proofing.body.location.po_search.po_search_about',
);
expect(heading).to.be.empty;
expect(aboutMessage).to.be.empty;
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,12 @@ function AddressSearch({
{t('idv.failure.exceptions.post_office_search_error')}
</Alert>
)}
<PageHeading>{t('in_person_proofing.headings.po_search.location')}</PageHeading>
<p>{t('in_person_proofing.body.location.po_search.po_search_about')}</p>
{handleLocationSelect && (
<>
<PageHeading>{t('in_person_proofing.headings.po_search.location')}</PageHeading>
<p>{t('in_person_proofing.body.location.po_search.po_search_about')}</p>
</>
)}
<AddressInput
registerField={registerField}
onFoundAddress={setFoundAddress}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,28 +8,28 @@ import { t } from '@18f/identity-i18n';
import { useCallback, useEffect, useRef, useState } from 'react';
import useValidatedUspsLocations from '../hooks/use-validated-usps-locations';

interface FullAddressSearchProps {
registerField?: RegisterFieldCallback;
interface FullAddressSearchInputProps {
disabled?: boolean;
locationsURL: string;
onError?: (error: Error | null) => void;
onFoundLocations?: (
address: LocationQuery | null,
locations: FormattedLocation[] | null | undefined,
) => void;
onLoadingLocations?: (isLoading: boolean) => void;
onError?: (error: Error | null) => void;
disabled?: boolean;
locationsURL: string;
usStatesTerritories: [string, string][];
registerField?: RegisterFieldCallback;
usStatesTerritories: string[][];
}

export default function FullAddressSearchInput({
usStatesTerritories,
registerField = () => undefined,
onFoundLocations = () => undefined,
onLoadingLocations = () => undefined,
onError = () => undefined,
disabled = false,
locationsURL,
}: FullAddressSearchProps) {
onError = () => undefined,
onFoundLocations = () => undefined,
onLoadingLocations = () => undefined,
registerField = () => undefined,
usStatesTerritories,
}: FullAddressSearchInputProps) {
const spinnerButtonRef = useRef<SpinnerButtonRefHandle>(null);
const [addressValue, setAddressValue] = useState('');
const [cityValue, setCityValue] = useState('');
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { render } from '@testing-library/react';
import sinon from 'sinon';
import { useSandbox } from '@18f/identity-test-helpers';
import userEvent from '@testing-library/user-event';
import { setupServer } from 'msw/node';
Expand All @@ -12,6 +13,59 @@ describe('FullAddressSearch', () => {
const locationsURL = 'https://localhost:3000/locations/endpoint';
const usStatesTerritories = [['Delware', 'DE']];

context('Page Heading and PO Search About Message', () => {
it('both render when handleLocationSelect is not null', async () => {
const handleLocationsFound = sandbox.stub();
const onSelect = sinon.stub();
const { queryByText, queryByRole } = render(
<SWRConfig value={{ provider: () => new Map() }}>
<FullAddressSearch
usStatesTerritories={usStatesTerritories}
onFoundLocations={handleLocationsFound}
locationsURL={locationsURL}
registerField={() => undefined}
handleLocationSelect={onSelect}
disabled={false}
/>
</SWRConfig>,
);

const heading = await queryByText('in_person_proofing.headings.po_search.location');
const aboutMessage = await queryByText(
'in_person_proofing.body.location.po_search.po_search_about',
);

expect(heading).to.exist();
expect(aboutMessage).to.exist();
expect(
queryByRole('heading', { name: 'in_person_proofing.headings.po_search.location' }),
).to.exist();
});

it('both do not render when handleLocationSelect is null', async () => {
const handleLocationsFound = sandbox.stub();
const { queryByText } = render(
<SWRConfig value={{ provider: () => new Map() }}>
<FullAddressSearch
usStatesTerritories={usStatesTerritories}
onFoundLocations={handleLocationsFound}
locationsURL={locationsURL}
registerField={() => undefined}
handleLocationSelect={null}
disabled={false}
/>
</SWRConfig>,
);

const heading = await queryByText('in_person_proofing.headings.po_search.location');
const aboutMessage = await queryByText(
'in_person_proofing.body.location.po_search.po_search_about',
);
expect(heading).to.be.empty;
expect(aboutMessage).to.be.empty;
});
});

context('validates form', () => {
it('displays an error for all required fields when input is empty', async () => {
const handleLocationsFound = sandbox.stub();
Expand All @@ -21,9 +75,9 @@ describe('FullAddressSearch', () => {
usStatesTerritories={usStatesTerritories}
onFoundLocations={handleLocationsFound}
locationsURL={locationsURL}
registerField={undefined}
registerField={() => undefined}
handleLocationSelect={undefined}
disabled={undefined}
disabled={false}
/>
</SWRConfig>,
);
Expand All @@ -44,9 +98,9 @@ describe('FullAddressSearch', () => {
usStatesTerritories={usStatesTerritories}
onFoundLocations={handleLocationsFound}
locationsURL={locationsURL}
registerField={undefined}
registerField={() => undefined}
handleLocationSelect={undefined}
disabled={undefined}
disabled={false}
/>
</SWRConfig>,
);
Expand Down Expand Up @@ -83,9 +137,9 @@ describe('FullAddressSearch', () => {
usStatesTerritories={usStatesTerritories}
onFoundLocations={handleLocationsFound}
locationsURL={locationsURL}
registerField={undefined}
registerField={() => undefined}
handleLocationSelect={undefined}
disabled={undefined}
disabled={false}
/>
</SWRConfig>,
);
Expand Down Expand Up @@ -135,9 +189,9 @@ describe('FullAddressSearch', () => {
usStatesTerritories={usStatesTerritories}
onFoundLocations={handleLocationsFound}
locationsURL={locationsURL}
registerField={undefined}
registerField={() => undefined}
handleLocationSelect={undefined}
disabled={undefined}
disabled={false}
/>
</SWRConfig>,
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,18 @@ import { t } from '@18f/identity-i18n';
import { InPersonLocations, NoInPersonLocationsDisplay } from '@18f/identity-address-search';
import type { LocationQuery, FormattedLocation } from '@18f/identity-address-search/types';
import FullAddressSearchInput from './full-address-search-input';
import type { FullAddressSearchProps } from '../types';

function FullAddressSearch({
usStatesTerritories,
registerField,
locationsURL,
handleLocationSelect,
disabled,
onFoundLocations,
handleLocationSelect,
locationsURL,
noInPersonLocationsDisplay = NoInPersonLocationsDisplay,
}) {
onFoundLocations,
registerField,
resultsHeaderComponent,
usStatesTerritories,
}: FullAddressSearchProps) {
const [apiError, setApiError] = useState<Error | null>(null);
const [foundAddress, setFoundAddress] = useState<LocationQuery | null>(null);
const [locationResults, setLocationResults] = useState<FormattedLocation[] | null | undefined>(
Expand All @@ -28,8 +30,12 @@ function FullAddressSearch({
{t('idv.failure.exceptions.post_office_search_error')}
</Alert>
)}
<PageHeading>{t('in_person_proofing.headings.po_search.location')}</PageHeading>
<p>{t('in_person_proofing.body.location.po_search.po_search_about')}</p>
{handleLocationSelect && (
<>
<PageHeading>{t('in_person_proofing.headings.po_search.location')}</PageHeading>
<p>{t('in_person_proofing.body.location.po_search.po_search_about')}</p>
</>
)}
<FullAddressSearchInput
usStatesTerritories={usStatesTerritories}
registerField={registerField}
Expand All @@ -52,6 +58,7 @@ function FullAddressSearch({
onSelect={handleLocationSelect}
address={foundAddress.address || ''}
noInPersonLocationsDisplay={noInPersonLocationsDisplay}
resultsHeaderComponent={resultsHeaderComponent}
/>
)}
</>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ComponentType } from 'react';
import { t } from '@18f/identity-i18n';
import LocationCollection from './location-collection';
import LocationCollectionItem from './location-collection-item';
import type { InPersonLocationsProps } from '../types';

export interface FormattedLocation {
formattedCityStateZip: string;
Expand All @@ -15,14 +15,6 @@ export interface FormattedLocation {
isPilot: boolean;
}

interface InPersonLocationsProps {
locations: FormattedLocation[] | null | undefined;
onSelect;
address: string;
noInPersonLocationsDisplay: ComponentType<{ address: string }>;
resultsHeaderComponent?: ComponentType;
}

function InPersonLocations({
locations,
onSelect,
Expand Down
2 changes: 1 addition & 1 deletion app/javascript/packages/address-search/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@18f/identity-address-search",
"version": "3.0.0",
"version": "3.1.0",
"type": "module",
"private": false,
"files": [
Expand Down
19 changes: 16 additions & 3 deletions app/javascript/packages/address-search/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,17 +58,19 @@ interface AddressSearchProps {
addressSearchURL: string;
disabled: boolean;
handleLocationSelect: ((e: any, id: number) => Promise<void>) | null | undefined;
noInPersonLocationsDisplay?: ComponentType<{ address: string }>;
resultsHeaderComponent?: ComponentType;
locationsURL: string;
noInPersonLocationsDisplay?: ComponentType<{ address: string }>;
onFoundLocations: Dispatch<SetStateAction<FormattedLocation[] | null | undefined>>;
registerField: RegisterFieldCallback;
resultsHeaderComponent?: ComponentType;
}

interface InPersonLocationsProps {
address: string;
locations: FormattedLocation[] | null | undefined;
noInPersonLocationsDisplay: ComponentType<{ address: string }>;
onSelect;
address: string;
resultsHeaderComponent?: ComponentType;
}

interface LocationCollectionItemProps {
Expand All @@ -88,3 +90,14 @@ interface LocationCollectionProps {

children?: ReactNode;
}

interface FullAddressSearchProps {
disabled: boolean;
handleLocationSelect: ((e: any, id: number) => Promise<void>) | null | undefined;
locationsURL: string;
noInPersonLocationsDisplay?: ComponentType<{ address: string }>;
onFoundLocations: Dispatch<SetStateAction<FormattedLocation[] | null | undefined>>;
registerField: RegisterFieldCallback;
resultsHeaderComponent?: ComponentType;
usStatesTerritories: string[][];
}

0 comments on commit d32eb9f

Please sign in to comment.