From 9bea0d149bc22b07c2a4d3a650a6ed720431acd6 Mon Sep 17 00:00:00 2001 From: Zach Margolis Date: Fri, 17 Mar 2023 11:01:44 -0700 Subject: [PATCH] Revert "Merge pull request #8014 from 18F/stages/rc-2023-03-17" This reverts commit 3741fd71e94914765d503244568c7e53ec1bcffa, reversing changes made to f472381f5b1402bd02a57289a04c10918b02778d. --- Gemfile.lock | 2 +- app/components/phone_input_component.html.erb | 6 + app/controllers/application_controller.rb | 1 - .../concerns/idv/verify_info_concern.rb | 30 +- .../in_person/address_search_controller.rb | 4 + .../in_person/usps_locations_controller.rb | 31 +- app/controllers/redirect/policy_controller.rb | 10 - .../components/document-capture.tsx | 5 +- ...-location-post-office-search-step.spec.tsx | 14 +- .../in-person-location-step.spec.tsx | 68 +++ .../components/in-person-location-step.tsx | 201 +++++++ .../components/in-person-prepare-step.tsx | 11 +- .../document-capture/context/in-person.ts | 6 + .../packages/phone-input/index.spec.ts | 4 + app/javascript/packages/phone-input/index.ts | 20 +- app/javascript/packs/document-capture.tsx | 2 + app/javascript/packs/pw-strength.js | 55 +- app/jobs/reports/daily_dropoffs_report.rb | 6 +- app/jobs/reports/duplicate_ssn_report.rb | 6 +- app/jobs/resolution_proofing_job.rb | 16 +- app/mailers/user_mailer.rb | 2 +- app/services/analytics.rb | 6 +- app/services/analytics_events.rb | 28 +- .../idv/actions/cancel_link_sent_action.rb | 5 +- .../idv/actions/cancel_send_link_action.rb | 13 + app/services/idv/flows/doc_auth_flow.rb | 2 + app/services/idv/flows/in_person_flow.rb | 2 +- app/services/idv/session.rb | 5 - app/services/idv/steps/send_link_step.rb | 128 ++++ app/services/idv/steps/upload_step.rb | 40 +- app/services/idv/steps/verify_base_step.rb | 3 +- app/services/pii/attributes.rb | 7 +- .../lexis_nexis/instant_verify/proofer.rb | 2 +- app/services/user_event_creator.rb | 42 +- .../usps_in_person_proofing/mock/proofer.rb | 11 + .../usps_in_person_proofing/proofer.rb | 7 + .../idv/doc_auth/_combined_upload.html.erb | 74 +++ app/views/idv/doc_auth/_upload.html.erb | 55 ++ app/views/idv/doc_auth/send_link.html.erb | 33 ++ app/views/idv/doc_auth/upload.html.erb | 82 +-- .../in_person/ready_to_verify/show.html.erb | 2 +- .../idv/shared/_document_capture.html.erb | 1 + app/views/idv/shared/_ssn.html.erb | 7 +- app/views/idv/ssn/show.html.erb | 4 +- config/application.yml.default | 2 + config/database.yml | 2 - config/ipp_pilot_usps_facilities.json | 165 ++++++ config/locales/doc_auth/en.yml | 19 +- config/locales/doc_auth/es.yml | 22 +- config/locales/doc_auth/fr.yml | 26 +- config/locales/errors/en.yml | 1 - config/locales/errors/es.yml | 1 - config/locales/errors/fr.yml | 1 - config/locales/in_person_proofing/en.yml | 13 +- config/locales/in_person_proofing/es.yml | 15 +- config/locales/in_person_proofing/fr.yml | 16 +- config/locales/titles/en.yml | 1 + config/locales/titles/es.yml | 1 + config/locales/titles/fr.yml | 1 + config/routes.rb | 1 - config/service_providers.localdev.yml | 49 -- lib/identity_config.rb | 2 + lib/session_encryptor.rb | 8 +- lib/tasks/review_profile.rake | 23 +- lib/tasks/users_lookup.rake | 9 +- .../application_controller_spec.rb | 4 +- .../idv/doc_auth_controller_spec.rb | 1 + .../address_search_controller_spec.rb | 11 + .../usps_locations_controller_spec.rb | 264 +++++---- .../redirect/contact_controller_spec.rb | 2 +- .../redirect/policy_controller_spec.rb | 25 - .../actions/cancel_link_sent_action_spec.rb | 4 +- .../actions/cancel_send_link_action_spec.rb | 17 + spec/features/idv/analytics_spec.rb | 2 +- .../idv/doc_auth/agreement_step_spec.rb | 3 +- .../idv/doc_auth/link_sent_step_spec.rb | 116 ++++ .../idv/doc_auth/send_link_step_spec.rb | 212 +++++++ .../features/idv/doc_auth/upload_step_spec.rb | 392 +++++++------ spec/features/idv/hybrid_flow_spec.rb | 19 +- spec/features/idv/in_person_spec.rb | 12 +- .../two_factor_authentication/sign_in_spec.rb | 5 + .../visitors/password_recovery_spec.rb | 8 +- spec/features/visitors/set_password_spec.rb | 22 +- .../date_of_birth_failure_response.json | 4 +- .../jobs/reports/duplicate_ssn_report_spec.rb | 6 +- spec/jobs/resolution_proofing_job_spec.rb | 554 +++++++++--------- spec/lib/tasks/review_profile_spec.rb | 6 +- spec/services/analytics_spec.rb | 27 - spec/services/idv/agent_spec.rb | 4 +- .../services/idv/steps/send_link_step_spec.rb | 95 +++ spec/services/idv/steps/upload_step_spec.rb | 5 +- spec/services/pii/attributes_spec.rb | 16 - .../usps_in_person_proofing/proofer_spec.rb | 9 + spec/support/features/doc_auth_helper.rb | 35 +- spec/support/features/idv_step_helper.rb | 2 +- spec/support/matchers/accessibility.rb | 2 +- .../idv/doc_auth/upload.html.erb_spec.rb | 21 + 97 files changed, 2316 insertions(+), 1026 deletions(-) delete mode 100644 app/controllers/redirect/policy_controller.rb create mode 100644 app/javascript/packages/document-capture/components/in-person-location-step.spec.tsx create mode 100644 app/javascript/packages/document-capture/components/in-person-location-step.tsx create mode 100644 app/services/idv/actions/cancel_send_link_action.rb create mode 100644 app/services/idv/steps/send_link_step.rb create mode 100644 app/views/idv/doc_auth/_combined_upload.html.erb create mode 100644 app/views/idv/doc_auth/_upload.html.erb create mode 100644 app/views/idv/doc_auth/send_link.html.erb create mode 100644 config/ipp_pilot_usps_facilities.json delete mode 100644 spec/controllers/redirect/policy_controller_spec.rb create mode 100644 spec/features/idv/actions/cancel_send_link_action_spec.rb create mode 100644 spec/features/idv/doc_auth/send_link_step_spec.rb create mode 100644 spec/services/idv/steps/send_link_step_spec.rb create mode 100644 spec/views/idv/doc_auth/upload.html.erb_spec.rb diff --git a/Gemfile.lock b/Gemfile.lock index d6f072de731..0f3e99521c1 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -197,7 +197,7 @@ GEM debug_inspector (>= 0.0.1) bootsnap (1.15.0) msgpack (~> 1.2) - brakeman (5.4.1) + brakeman (5.4.0) browser (5.3.1) builder (3.2.4) bullet (7.0.7) diff --git a/app/components/phone_input_component.html.erb b/app/components/phone_input_component.html.erb index 24a495525de..efe8510bb5c 100644 --- a/app/components/phone_input_component.html.erb +++ b/app/components/phone_input_component.html.erb @@ -36,6 +36,12 @@ :phone, class: 'usa-label', ) { t('two_factor_authentication.phone_label') } %> +
+ <%= f.hint(capture do %> + <%= t('forms.example') %> + + <% end) %> +
<%= render ValidatedFieldComponent.new( form: f, name: :phone, diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 9c17fec259f..ec78024eaef 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -65,7 +65,6 @@ def analytics sp: current_sp&.issuer, session: session, ahoy: ahoy, - irs_session_id: irs_attempts_api_session_id, ) end diff --git a/app/controllers/concerns/idv/verify_info_concern.rb b/app/controllers/concerns/idv/verify_info_concern.rb index 9e1acd7dce2..0635f2c248f 100644 --- a/app/controllers/concerns/idv/verify_info_concern.rb +++ b/app/controllers/concerns/idv/verify_info_concern.rb @@ -97,8 +97,7 @@ def async_state_done(current_async_state) extra: { address_edited: !!flow_session['address_edited'], address_line2_present: !pii[:address2].blank?, - pii_like_keypaths: [[:errors, :ssn], [:response_body, :first_name], - [:state_id, :state_id_jurisdiction]], + pii_like_keypaths: [[:errors, :ssn], [:response_body, :first_name]], }, ) log_idv_verification_submitted_event( @@ -106,14 +105,15 @@ def async_state_done(current_async_state) failure_reason: irs_attempts_api_tracker.parse_failure_reason(form_response), ) - form_response = form_response.merge(check_ssn) if form_response.success? + if form_response.success? + response = check_ssn + form_response = form_response.merge(response) + end summarize_result_and_throttle_failures(form_response) delete_async if form_response.success? - move_applicant_to_idv_session idv_session.mark_verify_info_step_complete! - idv_session.invalidate_steps_after_verify_info! redirect_to idv_phone_url else idv_session.invalidate_verify_info_step! @@ -196,13 +196,27 @@ def log_idv_verification_submitted_event(success: false, failure_reason: nil) end def check_ssn - Idv::SsnForm.new(current_user).submit(ssn: pii[:ssn]) + result = Idv::SsnForm.new(current_user).submit(ssn: pii[:ssn]) + + if result.success? + save_legacy_state + delete_pii + end + + result end - def move_applicant_to_idv_session + def save_legacy_state + skip_legacy_steps idv_session.applicant = pii idv_session.applicant['uuid'] = current_user.uuid - delete_pii + end + + def skip_legacy_steps + idv_session.mark_verify_info_step_complete! + idv_session.vendor_phone_confirmation = false + idv_session.user_phone_confirmation = false + idv_session.address_verification_mechanism = 'phone' end def add_proofing_costs(results) diff --git a/app/controllers/idv/in_person/address_search_controller.rb b/app/controllers/idv/in_person/address_search_controller.rb index 725ab329e1d..e96e4208fee 100644 --- a/app/controllers/idv/in_person/address_search_controller.rb +++ b/app/controllers/idv/in_person/address_search_controller.rb @@ -1,6 +1,10 @@ module Idv module InPerson class AddressSearchController < ApplicationController + include RenderConditionConcern + + check_or_render_not_found -> { IdentityConfig.store.arcgis_search_enabled } + def index response = addresses(params[:address]) render(**response) diff --git a/app/controllers/idv/in_person/usps_locations_controller.rb b/app/controllers/idv/in_person/usps_locations_controller.rb index ec7e9cc2a16..6e62cb11ecf 100644 --- a/app/controllers/idv/in_person/usps_locations_controller.rb +++ b/app/controllers/idv/in_person/usps_locations_controller.rb @@ -20,21 +20,26 @@ class UspsLocationsController < ApplicationController # retrieve the list of nearby IPP Post Office locations with a POST request def index - candidate = UspsInPersonProofing::Applicant.new( - address: search_params['street_address'], - city: search_params['city'], state: search_params['state'], - zip_code: search_params['zip_code'] - ) - response = proofer.request_facilities(candidate) - if response.length > 0 - analytics.idv_in_person_locations_searched( - success: true, - result_total: response.length, + response = [] + if IdentityConfig.store.arcgis_search_enabled + candidate = UspsInPersonProofing::Applicant.new( + address: search_params['street_address'], + city: search_params['city'], state: search_params['state'], + zip_code: search_params['zip_code'] ) + response = proofer.request_facilities(candidate) + if response.length > 0 + analytics.idv_in_person_locations_searched( + success: true, + result_total: response.length, + ) + else + analytics.idv_in_person_locations_searched( + success: false, errors: 'No USPS locations found', + ) + end else - analytics.idv_in_person_locations_searched( - success: false, errors: 'No USPS locations found', - ) + response = proofer.request_pilot_facilities end render json: response.to_json end diff --git a/app/controllers/redirect/policy_controller.rb b/app/controllers/redirect/policy_controller.rb deleted file mode 100644 index 9e75c5dfd79..00000000000 --- a/app/controllers/redirect/policy_controller.rb +++ /dev/null @@ -1,10 +0,0 @@ -module Redirect - class PolicyController < RedirectController - def show - redirect_to_and_log( - MarketingSite.security_and_privacy_practices_url, - tracker_method: analytics.method(:policy_redirect), - ) - end - end - end diff --git a/app/javascript/packages/document-capture/components/document-capture.tsx b/app/javascript/packages/document-capture/components/document-capture.tsx index 5dd591c2de5..42e6f2bacc1 100644 --- a/app/javascript/packages/document-capture/components/document-capture.tsx +++ b/app/javascript/packages/document-capture/components/document-capture.tsx @@ -9,6 +9,7 @@ import { getConfigValue } from '@18f/identity-config'; import { UploadFormEntriesError } from '../services/upload'; import DocumentsStep from './documents-step'; import InPersonPrepareStep from './in-person-prepare-step'; +import InPersonLocationStep from './in-person-location-step'; import InPersonLocationPostOfficeSearchStep from './in-person-location-post-office-search-step'; import InPersonSwitchBackStep from './in-person-switch-back-step'; import ReviewIssuesStep from './review-issues-step'; @@ -59,7 +60,7 @@ function DocumentCapture({ isAsyncForm = false, onStepChange = () => {} }: Docum const { t } = useI18n(); const { flowPath } = useContext(UploadContext); const { trackSubmitEvent, trackVisitEvent } = useContext(AnalyticsContext); - const { inPersonURL } = useContext(InPersonContext); + const { inPersonURL, arcgisSearchEnabled } = useContext(InPersonContext); const appName = getConfigValue('appName'); useDidUpdateEffect(onStepChange, [stepName]); @@ -113,7 +114,7 @@ function DocumentCapture({ isAsyncForm = false, onStepChange = () => {} }: Docum : ([ { name: 'location', - form: InPersonLocationPostOfficeSearchStep, + form: arcgisSearchEnabled ? InPersonLocationPostOfficeSearchStep : InPersonLocationStep, title: t('in_person_proofing.headings.po_search.location'), }, { diff --git a/app/javascript/packages/document-capture/components/in-person-location-post-office-search-step.spec.tsx b/app/javascript/packages/document-capture/components/in-person-location-post-office-search-step.spec.tsx index e88a91c6e57..4df8ac8d242 100644 --- a/app/javascript/packages/document-capture/components/in-person-location-post-office-search-step.spec.tsx +++ b/app/javascript/packages/document-capture/components/in-person-location-post-office-search-step.spec.tsx @@ -7,7 +7,9 @@ import type { SetupServerApi } from 'msw/node'; import { SWRConfig } from 'swr'; import { I18nContext } from '@18f/identity-react-i18n'; import { ComponentType } from 'react'; -import { ADDRESS_SEARCH_URL, LOCATIONS_URL } from './address-search'; +import { LOCATIONS_URL } from './in-person-location-step'; +import { ADDRESS_SEARCH_URL } from './address-search'; +import InPersonContext from '../context/in-person'; import InPersonLocationPostOfficeSearchStep from './in-person-location-post-office-search-step'; const DEFAULT_RESPONSE = [ @@ -56,9 +58,11 @@ const DEFAULT_PROPS = { registerField() {}, }; -describe('InPersonPostOfficeSearchStep', () => { +describe('InPersonLocationStep', () => { const wrapper: ComponentType = ({ children }) => ( - new Map() }}>{children} + + new Map() }}>{children} + ); let server: SetupServerApi; @@ -86,7 +90,9 @@ describe('InPersonPostOfficeSearchStep', () => { it('displays a try again error message', async () => { const { findByText, findByLabelText } = render( new Map() }}> - + + + , ); diff --git a/app/javascript/packages/document-capture/components/in-person-location-step.spec.tsx b/app/javascript/packages/document-capture/components/in-person-location-step.spec.tsx new file mode 100644 index 00000000000..a5de88ed931 --- /dev/null +++ b/app/javascript/packages/document-capture/components/in-person-location-step.spec.tsx @@ -0,0 +1,68 @@ +import sinon from 'sinon'; +import { useContext } from 'react'; +import { render } from '@testing-library/react'; +import { getAllByRole } from '@testing-library/dom'; +import userEvent from '@testing-library/user-event'; +import { setupServer } from 'msw/node'; +import { rest } from 'msw'; +import type { SetupServerApi } from 'msw/node'; +import AnalyticsContext, { AnalyticsContextProvider } from '../context/analytics'; +import InPersonLocationStep, { LOCATIONS_URL } from './in-person-location-step'; +import { ADDRESS_SEARCH_URL } from './address-search'; + +const DEFAULT_RESPONSE = [ + { + address: '100 Main St E, Bronwood, Georgia, 39826', + location: { + latitude: 31.831686000000005, + longitude: -84.363768, + }, + street_address: '100 Main St E', + city: 'Bronwood', + state: 'GA', + zip_code: '39826', + }, +]; + +const DEFAULT_PROPS = { + toPreviousStep() {}, + onChange() {}, + value: {}, + registerField() {}, +}; + +describe('InPersonLocationStep', () => { + let server: SetupServerApi; + before(() => { + server = setupServer( + rest.post(LOCATIONS_URL, (_req, res, ctx) => res(ctx.json([{ name: 'Baltimore' }]))), + rest.post(ADDRESS_SEARCH_URL, (_req, res, ctx) => res(ctx.json(DEFAULT_RESPONSE))), + rest.put(LOCATIONS_URL, (_req, res, ctx) => res(ctx.json([{ success: true }]))), + ); + server.listen(); + }); + + after(() => { + server.close(); + }); + + it('logs step submission with selected location', async () => { + const trackEvent = sinon.stub(); + function MetadataValue() { + return <>{JSON.stringify(useContext(AnalyticsContext).submitEventMetadata)}; + } + const { findByText } = render( + + + + , + ); + + const item = await findByText('Baltimore — in_person_proofing.body.location.post_office'); + const button = getAllByRole(item.closest('.location-collection-item')!, 'button')[0]; + + await userEvent.click(button); + + await findByText('{"selected_location":"Baltimore","in_person_cta_variant":""}'); + }); +}); diff --git a/app/javascript/packages/document-capture/components/in-person-location-step.tsx b/app/javascript/packages/document-capture/components/in-person-location-step.tsx new file mode 100644 index 00000000000..6712e3b8ef1 --- /dev/null +++ b/app/javascript/packages/document-capture/components/in-person-location-step.tsx @@ -0,0 +1,201 @@ +import { useState, useEffect, useCallback, useRef, useContext } from 'react'; +import { useI18n } from '@18f/identity-react-i18n'; +import { PageHeading, SpinnerDots } from '@18f/identity-components'; +import { request } from '@18f/identity-request'; +import BackButton from './back-button'; +import LocationCollection from './location-collection'; +import LocationCollectionItem from './location-collection-item'; +import AnalyticsContext from '../context/analytics'; +import { InPersonContext } from '../context'; + +interface PostOffice { + address: string; + city: string; + name: string; + saturday_hours: string; + state: string; + sunday_hours: string; + weekday_hours: string; + zip_code_4: string; + zip_code_5: string; +} + +interface FormattedLocation { + formattedCityStateZip: string; + id: number; + name: string; + saturdayHours: string; + streetAddress: string; + sundayHours: string; + weekdayHours: string; +} +interface LocationQuery { + streetAddress: string; + city: string; + state: string; + zipCode: string; +} + +export const LOCATIONS_URL = '/verify/in_person/usps_locations'; + +const getUspsLocations = (address) => + request(LOCATIONS_URL, { + method: 'post', + json: { address }, + }); + +const formatLocation = (postOffices: PostOffice[]) => { + const formattedLocations = [] as FormattedLocation[]; + postOffices.forEach((po: PostOffice, index) => { + const location = { + formattedCityStateZip: `${po.city}, ${po.state}, ${po.zip_code_5}-${po.zip_code_4}`, + id: index, + name: po.name, + saturdayHours: po.saturday_hours, + streetAddress: po.address, + sundayHours: po.sunday_hours, + weekdayHours: po.weekday_hours, + } as FormattedLocation; + formattedLocations.push(location); + }); + return formattedLocations; +}; + +const snakeCase = (value: string) => + value + .split(/(?=[A-Z])/) + .join('_') + .toLowerCase(); + +// snake case the keys of the location +const prepToSend = (location: object) => { + const sendObject = {}; + Object.keys(location).forEach((key) => { + sendObject[snakeCase(key)] = location[key]; + }); + return sendObject; +}; + +function InPersonLocationStep({ onChange, toPreviousStep }) { + const { inPersonCtaVariantActive } = useContext(InPersonContext); + const { t } = useI18n(); + const [locationData, setLocationData] = useState([] as FormattedLocation[]); + const [foundAddress] = useState({} as LocationQuery); + const [inProgress, setInProgress] = useState(false); + const [autoSubmit, setAutoSubmit] = useState(false); + const [isLoadingComplete, setIsLoadingComplete] = useState(false); + const { setSubmitEventMetadata } = useContext(AnalyticsContext); + + // ref allows us to avoid a memory leak + const mountedRef = useRef(false); + + useEffect(() => { + mountedRef.current = true; + return () => { + mountedRef.current = false; + }; + }, []); + + // useCallBack here prevents unnecessary rerenders due to changing function identity + const handleLocationSelect = useCallback( + async (e: any, id: number) => { + const selectedLocation = locationData[id]; + const { name: selectedLocationName } = selectedLocation; + setSubmitEventMetadata({ + selected_location: selectedLocationName, + in_person_cta_variant: inPersonCtaVariantActive, + }); + onChange({ selectedLocationName }); + if (autoSubmit) { + return; + } + // prevent navigation from continuing + e.preventDefault(); + if (inProgress) { + return; + } + const selected = prepToSend(selectedLocation); + setInProgress(true); + await request(LOCATIONS_URL, { + json: selected, + method: 'PUT', + }) + .then(() => { + if (!mountedRef.current) { + return; + } + setAutoSubmit(true); + setImmediate(() => { + // continue with navigation + e.target.click(); + // allow process to be re-triggered in case submission did not work as expected + setAutoSubmit(false); + }); + }) + .finally(() => { + if (!mountedRef.current) { + return; + } + setInProgress(false); + }); + }, + [locationData, inProgress], + ); + + useEffect(() => { + let didCancel = false; + (async () => { + try { + const fetchedLocations = await getUspsLocations(prepToSend(foundAddress)); + + if (!didCancel) { + const formattedLocations = formatLocation(fetchedLocations); + setLocationData(formattedLocations); + } + } finally { + if (!didCancel) { + setIsLoadingComplete(true); + } + } + })(); + return () => { + didCancel = true; + }; + }, [foundAddress]); + + let locationsContent: React.ReactNode; + if (!isLoadingComplete) { + locationsContent = ; + } else if (locationData.length < 1) { + locationsContent =

{t('in_person_proofing.body.location.none_found')}

; + } else { + locationsContent = ( + + {locationData.map((item, index) => ( + + ))} + + ); + } + + return ( + <> + {t('in_person_proofing.headings.location')} +

{t('in_person_proofing.body.location.location_step_about')}

+ {locationsContent} + + + ); +} + +export default InPersonLocationStep; diff --git a/app/javascript/packages/document-capture/components/in-person-prepare-step.tsx b/app/javascript/packages/document-capture/components/in-person-prepare-step.tsx index 91f5bbcf829..1043d3afdcc 100644 --- a/app/javascript/packages/document-capture/components/in-person-prepare-step.tsx +++ b/app/javascript/packages/document-capture/components/in-person-prepare-step.tsx @@ -20,7 +20,8 @@ function InPersonPrepareStep({ toPreviousStep, value }) { const { flowPath } = useContext(UploadContext); const { trackEvent } = useContext(AnalyticsContext); const { securityAndPrivacyHowItWorksURL } = useContext(MarketingSiteContext); - const { selectedLocationAddress } = value; + /* Remove selectedLocationName when request_pilot_facilities removed */ + const { selectedLocationName, selectedLocationAddress } = value; const onContinue: MouseEventHandler = async (event) => { event.preventDefault(); @@ -35,6 +36,14 @@ function InPersonPrepareStep({ toPreviousStep, value }) { return ( <> + {/* Remove selectedLocationName version of alert when request_pilot_facilities removed */} + {selectedLocationName && ( + + {t('in_person_proofing.body.prepare.alert_selected_po_name', { + name: selectedLocationName, + })} + + )} {selectedLocationAddress && ( {t('in_person_proofing.body.prepare.alert_selected_post_office', { diff --git a/app/javascript/packages/document-capture/context/in-person.ts b/app/javascript/packages/document-capture/context/in-person.ts index f8bb51ba8fd..90e7fdd6ced 100644 --- a/app/javascript/packages/document-capture/context/in-person.ts +++ b/app/javascript/packages/document-capture/context/in-person.ts @@ -1,6 +1,11 @@ import { createContext } from 'react'; export interface InPersonContextProps { + /** + * Feature flag for enabling address search + */ + arcgisSearchEnabled?: boolean; + /** * Whether or not A/B testing of the in-person proofing CTA is enabled. */ @@ -18,6 +23,7 @@ export interface InPersonContextProps { } const InPersonContext = createContext({ + arcgisSearchEnabled: false, inPersonCtaVariantTestingEnabled: false, inPersonCtaVariantActive: '', }); diff --git a/app/javascript/packages/phone-input/index.spec.ts b/app/javascript/packages/phone-input/index.spec.ts index 75505c5fdb9..c8c09d97ec5 100644 --- a/app/javascript/packages/phone-input/index.spec.ts +++ b/app/javascript/packages/phone-input/index.spec.ts @@ -80,6 +80,10 @@ describe('PhoneInput', () => { ${!isSingleOption && !isNonUSSingleOption ? MULTIPLE_OPTIONS_HTML : ''} +
+ Example: + +