Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ import { useDidUpdateEffect } from '@18f/identity-react-hooks';
import { SpinnerButtonRefHandle, SpinnerButton } from '@18f/identity-spinner-button';
import { ValidatedField } from '@18f/identity-validated-field';
import { t } from '@18f/identity-i18n';
import { useCallback, useContext, useEffect, useRef, useState } from 'react';
import { InPersonContext } from '../context';
import { useCallback, useEffect, useRef, useState } from 'react';
import useValidatedUspsLocations from '../hooks/use-validated-usps-locations';

interface FullAddressSearchProps {
Expand All @@ -19,9 +18,11 @@ interface FullAddressSearchProps {
onError?: (error: Error | null) => void;
disabled?: boolean;
locationsURL: string;
usStatesTerritories: [string, string][];
}

export default function FullAddressSearchInput({
usStatesTerritories,
registerField = () => undefined,
onFoundLocations = () => undefined,
onLoadingLocations = () => undefined,
Expand Down Expand Up @@ -81,8 +82,6 @@ export default function FullAddressSearchInput({
[addressValue, cityValue, stateValue, zipCodeValue],
);

const { usStatesTerritories } = useContext(InPersonContext);

return (
<>
<ValidatedField
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,22 @@ import { setupServer } from 'msw/node';
import { rest } from 'msw';
import type { SetupServer } from 'msw/node';
import { SWRConfig } from 'swr';
import FullAddressSearch from './in-person-full-address-search';
import { LOCATIONS_URL } from './in-person-location-post-office-search-step';
import FullAddressSearch from './full-address-search';

describe('FullAddressSearch', () => {
const sandbox = useSandbox();
const locationsURL = 'https://localhost:3000/locations/endpoint';
const usStatesTerritories = [['Delware', 'DE']];

context('validates form', () => {
it('displays an error for all required fields when input is empty', async () => {
const handleLocationsFound = sandbox.stub();
const { findByText, findAllByText } = render(
<SWRConfig value={{ provider: () => new Map() }}>
<FullAddressSearch
usStatesTerritories={usStatesTerritories}
onFoundLocations={handleLocationsFound}
locationsURL={LOCATIONS_URL}
locationsURL={locationsURL}
registerField={undefined}
handleLocationSelect={undefined}
disabled={undefined}
Expand All @@ -39,8 +41,9 @@ describe('FullAddressSearch', () => {
const { findByText, findByLabelText, findAllByText } = render(
<SWRConfig value={{ provider: () => new Map() }}>
<FullAddressSearch
usStatesTerritories={usStatesTerritories}
onFoundLocations={handleLocationsFound}
locationsURL={LOCATIONS_URL}
locationsURL={locationsURL}
registerField={undefined}
handleLocationSelect={undefined}
disabled={undefined}
Expand Down Expand Up @@ -77,8 +80,9 @@ describe('FullAddressSearch', () => {
const { findByText, findByLabelText, queryByText } = render(
<SWRConfig value={{ provider: () => new Map() }}>
<FullAddressSearch
usStatesTerritories={usStatesTerritories}
onFoundLocations={handleLocationsFound}
locationsURL={LOCATIONS_URL}
locationsURL={locationsURL}
registerField={undefined}
handleLocationSelect={undefined}
disabled={undefined}
Expand Down Expand Up @@ -114,7 +118,7 @@ describe('FullAddressSearch', () => {
let server: SetupServer;
before(() => {
server = setupServer(
rest.post(LOCATIONS_URL, (_req, res, ctx) => res(ctx.json([{ name: 'Baltimore' }]))),
rest.post(locationsURL, (_req, res, ctx) => res(ctx.json([{ name: 'Baltimore' }]))),
);
server.listen();
});
Expand All @@ -128,8 +132,9 @@ describe('FullAddressSearch', () => {
const { findByText, findByLabelText } = render(
<SWRConfig value={{ provider: () => new Map() }}>
<FullAddressSearch
usStatesTerritories={usStatesTerritories}
onFoundLocations={handleLocationsFound}
locationsURL={LOCATIONS_URL}
locationsURL={locationsURL}
registerField={undefined}
handleLocationSelect={undefined}
disabled={undefined}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import type { LocationQuery, FormattedLocation } from '@18f/identity-address-sea
import FullAddressSearchInput from './full-address-search-input';

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like that you shortened file name. Now component name is the same as the file name.

function FullAddressSearch({
usStatesTerritories,
registerField,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand why you decided to pass in usStatesTerritories as a prop. If we use this component in sites, I imagine we will need to write an issue to get usStateTerritories in sites (help center). (I did not look into how we are getting these- jumping into another meeting). I imagine the lift to do this in sites and pass it in is not large so am okay with passing it in- just calling it out as some additional work I think

Copy link
Contributor Author

@sheldon-b sheldon-b Sep 19, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good point. For reference how this works in identity-idp is:

  1. US states and territories are defined in the Ruby app
  2. They're passed into the javascript application on the document capture page
  3. They're loaded into the InPerson context, per this PR
  4. They're passed down into the components in the PO search step, per this PR

As-is we'll have to redefine them in the identity-site repo

An alternative is that we could write a script to read from the Ruby file and write to a javascript file, and then publish the generated javascript file as part of an npm package. And then in the Ruby file add a file comment saying something like,

If you change this set of states/territories be sure to go run script bin/update-states-and-territories.sh and publish a new version of the npm package

I'm going to go ahead and merge this PR. If we do refactor it in some way I think it should be part of a different ticket. But let me know your thoughts about it

Copy link
Contributor

@gina-yamada gina-yamada Sep 20, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think a new ticket is a good idea, extra work and out of scope to get this working in identity-sites. I think both are fine. I don't think the list will change much over time just as long as we can think of a way to try to ensure both get updated in the future

locationsURL,
handleLocationSelect,
Expand All @@ -30,6 +31,7 @@ function FullAddressSearch({
<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}
onFoundLocations={(
address: LocationQuery | null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { rest } from 'msw';
import { setupServer } from 'msw/node';
import type { SetupServer } from 'msw/node';
import useValidatedUspsLocations from './use-validated-usps-locations';
import { LOCATIONS_URL } from '../components/in-person-location-post-office-search-step';

const USPS_RESPONSE = [
{
Expand Down Expand Up @@ -31,6 +30,7 @@ const USPS_RESPONSE = [
];

describe('useValidatedUspsLocations', () => {
const locationsURL = 'https://localhost:3000/locations/endpoint';
let server: SetupServer;

before(() => {
Expand All @@ -44,13 +44,11 @@ describe('useValidatedUspsLocations', () => {

beforeEach(() => {
server.resetHandlers();
server.use(rest.post(LOCATIONS_URL, (_req, res, ctx) => res(ctx.json(USPS_RESPONSE))));
server.use(rest.post(locationsURL, (_req, res, ctx) => res(ctx.json(USPS_RESPONSE))));
});

it('returns location results', async () => {
const { result, waitForNextUpdate } = renderHook(() =>
useValidatedUspsLocations(LOCATIONS_URL),
);
const { result, waitForNextUpdate } = renderHook(() => useValidatedUspsLocations(locationsURL));

const { handleLocationSearch } = result.current;
handleLocationSearch(new Event('submit'), '200 main', 'Endeavor', 'DE', '12345');
Expand Down
2 changes: 2 additions & 0 deletions app/javascript/packages/address-search/index.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import { snakeCase, formatLocations, transformKeys } from './utils';
import AddressInput from './components/address-input';
import AddressSearch from './components/address-search';
import FullAddressSearch from './components/full-address-search';
import InPersonLocations from './components/in-person-locations';
import NoInPersonLocationsDisplay from './components/no-in-person-locations-display';
import { requestUspsLocations } from './hooks/use-usps-locations';

export {
AddressInput,
InPersonLocations,
FullAddressSearch,
NoInPersonLocationsDisplay,
formatLocations,
snakeCase,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import { usePropertyValue } from '@18f/identity-test-helpers';
import { ComponentType } from 'react';
import { InPersonContext } from '../context';
import InPersonLocationFullAddressEntryPostOfficeSearchStep from './in-person-location-full-address-entry-post-office-search-step';
import { LOCATIONS_URL } from './in-person-location-post-office-search-step';

const USPS_RESPONSE = [
{
Expand Down Expand Up @@ -39,13 +38,25 @@ const USPS_RESPONSE = [
const DEFAULT_PROPS = {
toPreviousStep() {},
onChange() {},
value: {},
registerField() {},
};

describe('InPersonLocationFullAddressEntryPostOfficeSearchStep', () => {
const usStatesTerritories: [string, string][] = [['Delware', 'DE']];
const locationsURL = 'https://localhost:3000/locations/endpoint';
const wrapper: ComponentType = ({ children }) => (
<SWRConfig value={{ provider: () => new Map() }}>{children}</SWRConfig>
<InPersonContext.Provider
value={{
locationsURL,
addressSearchURL: 'https://localhost:3000',
inPersonOutageMessageEnabled: false,
inPersonOutageExpectedUpdateDate: 'January 1, 2024',
inPersonFullAddressEntryEnabled: true,
usStatesTerritories,
}}
>
<SWRConfig value={{ provider: () => new Map() }}>{children}</SWRConfig>
</InPersonContext.Provider>
);

let server: SetupServer;
Expand All @@ -62,23 +73,12 @@ describe('InPersonLocationFullAddressEntryPostOfficeSearchStep', () => {
beforeEach(() => {
server.resetHandlers();
// todo: should we return USPS_RESPONSE here?
server.use(
rest.post(LOCATIONS_URL, (_req, res, ctx) => res(ctx.json([{ name: 'Baltimore' }]))),
);
server.use(rest.post(locationsURL, (_req, res, ctx) => res(ctx.json([{ name: 'Baltimore' }]))));
});

it('renders the step', () => {
const { getByRole } = render(
<InPersonContext.Provider
value={{
inPersonOutageMessageEnabled: false,
inPersonOutageExpectedUpdateDate: 'January 1, 2024',
inPersonFullAddressEntryEnabled: true,
usStatesTerritories: [['Delaware', 'DE']],
}}
>
<InPersonLocationFullAddressEntryPostOfficeSearchStep {...DEFAULT_PROPS} />,
</InPersonContext.Provider>,
<InPersonLocationFullAddressEntryPostOfficeSearchStep {...DEFAULT_PROPS} />,
{ wrapper },
);

Expand All @@ -87,21 +87,12 @@ describe('InPersonLocationFullAddressEntryPostOfficeSearchStep', () => {

context('USPS request returns an error', () => {
beforeEach(() => {
server.use(rest.post(LOCATIONS_URL, (_req, res, ctx) => res(ctx.status(500))));
server.use(rest.post(locationsURL, (_req, res, ctx) => res(ctx.status(500))));
});

it('displays a try again error message', async () => {
const { findByText, findByLabelText } = render(
<InPersonContext.Provider
value={{
inPersonOutageMessageEnabled: false,
inPersonOutageExpectedUpdateDate: 'January 1, 2024',
inPersonFullAddressEntryEnabled: true,
usStatesTerritories: [['Delaware', 'DE']],
}}
>
<InPersonLocationFullAddressEntryPostOfficeSearchStep {...DEFAULT_PROPS} />,
</InPersonContext.Provider>,
<InPersonLocationFullAddressEntryPostOfficeSearchStep {...DEFAULT_PROPS} />,
{ wrapper },
);

Expand Down Expand Up @@ -133,16 +124,7 @@ describe('InPersonLocationFullAddressEntryPostOfficeSearchStep', () => {

it('displays validation error messages to the user if fields are empty', async () => {
const { findAllByText, findByText } = render(
<InPersonContext.Provider
value={{
inPersonOutageMessageEnabled: false,
inPersonOutageExpectedUpdateDate: 'January 1, 2024',
inPersonFullAddressEntryEnabled: true,
usStatesTerritories: [['Delaware', 'DE']],
}}
>
<InPersonLocationFullAddressEntryPostOfficeSearchStep {...DEFAULT_PROPS} />,
</InPersonContext.Provider>,
<InPersonLocationFullAddressEntryPostOfficeSearchStep {...DEFAULT_PROPS} />,
{ wrapper },
);

Expand All @@ -156,16 +138,7 @@ describe('InPersonLocationFullAddressEntryPostOfficeSearchStep', () => {

it('displays no post office results if a successful search is followed by an unsuccessful search', async () => {
const { findByText, findByLabelText, queryByRole } = render(
<InPersonContext.Provider
value={{
inPersonOutageMessageEnabled: false,
inPersonOutageExpectedUpdateDate: 'January 1, 2024',
inPersonFullAddressEntryEnabled: true,
usStatesTerritories: [['Delaware', 'DE']],
}}
>
<InPersonLocationFullAddressEntryPostOfficeSearchStep {...DEFAULT_PROPS} />,
</InPersonContext.Provider>,
<InPersonLocationFullAddressEntryPostOfficeSearchStep {...DEFAULT_PROPS} />,
{ wrapper },
);

Expand Down Expand Up @@ -205,16 +178,7 @@ describe('InPersonLocationFullAddressEntryPostOfficeSearchStep', () => {

it('clicking search again after first results do not clear results', async () => {
const { findAllByText, findByText, findByLabelText } = render(
<InPersonContext.Provider
value={{
inPersonOutageMessageEnabled: false,
inPersonOutageExpectedUpdateDate: 'January 1, 2024',
inPersonFullAddressEntryEnabled: true,
usStatesTerritories: [['Delaware', 'DE']],
}}
>
<InPersonLocationFullAddressEntryPostOfficeSearchStep {...DEFAULT_PROPS} />,
</InPersonContext.Provider>,
<InPersonLocationFullAddressEntryPostOfficeSearchStep {...DEFAULT_PROPS} />,
{ wrapper },
);

Expand Down Expand Up @@ -253,16 +217,7 @@ describe('InPersonLocationFullAddressEntryPostOfficeSearchStep', () => {

it('displays correct pluralization for a single location result', async () => {
const { findByLabelText, findByText } = render(
<InPersonContext.Provider
value={{
inPersonOutageMessageEnabled: false,
inPersonOutageExpectedUpdateDate: 'January 1, 2024',
inPersonFullAddressEntryEnabled: true,
usStatesTerritories: [['Delaware', 'DE']],
}}
>
<InPersonLocationFullAddressEntryPostOfficeSearchStep {...DEFAULT_PROPS} />,
</InPersonContext.Provider>,
<InPersonLocationFullAddressEntryPostOfficeSearchStep {...DEFAULT_PROPS} />,
{ wrapper },
);
await userEvent.type(
Expand Down Expand Up @@ -297,18 +252,9 @@ describe('InPersonLocationFullAddressEntryPostOfficeSearchStep', () => {

it('displays correct pluralization for multiple location results', async () => {
server.resetHandlers();
server.use(rest.post(LOCATIONS_URL, (_req, res, ctx) => res(ctx.json(USPS_RESPONSE))));
server.use(rest.post(locationsURL, (_req, res, ctx) => res(ctx.json(USPS_RESPONSE))));
const { findByLabelText, findByText } = render(
<InPersonContext.Provider
value={{
inPersonOutageMessageEnabled: false,
inPersonOutageExpectedUpdateDate: 'January 1, 2024',
inPersonFullAddressEntryEnabled: true,
usStatesTerritories: [['Delaware', 'DE']],
}}
>
<InPersonLocationFullAddressEntryPostOfficeSearchStep {...DEFAULT_PROPS} />,
</InPersonContext.Provider>,
<InPersonLocationFullAddressEntryPostOfficeSearchStep {...DEFAULT_PROPS} />,
{ wrapper },
);

Expand Down Expand Up @@ -345,16 +291,7 @@ describe('InPersonLocationFullAddressEntryPostOfficeSearchStep', () => {

it('allows user to select a location', async () => {
const { findAllByText, findByLabelText, findByText, queryByText } = render(
<InPersonContext.Provider
value={{
inPersonOutageMessageEnabled: false,
inPersonOutageExpectedUpdateDate: 'January 1, 2024',
inPersonFullAddressEntryEnabled: true,
usStatesTerritories: [['Delaware', 'DE']],
}}
>
<InPersonLocationFullAddressEntryPostOfficeSearchStep {...DEFAULT_PROPS} />,
</InPersonContext.Provider>,
<InPersonLocationFullAddressEntryPostOfficeSearchStep {...DEFAULT_PROPS} />,
{ wrapper },
);
await userEvent.type(
Expand Down
Loading