Skip to content

Commit

Permalink
[Point of Contact] Phone extension field (#961)
Browse files Browse the repository at this point in the history
## Note
Be sure the pull the latest from
[_sbl-filing_](cfpb/sbl-filing-api#421) via
`yarn update`

closes #945

## Changes

- feat(Point of Contact): Added Phone Extension field to Point of
Contact Field
- chore(Point of Contact): Phone Extension breakpoint of 600px
- feat(Sign and Submit): Added Phone Extension field to Verification
field
- chore(Sign and Submit): Matched order of fields to be the same as
Point of Contact
- feat(e2e): Added Phone Extension field to e2e test
- style(DisplayField): added `work-break: break-all;`
- content(Sign and Submit): added 'Extension'

## How to test this PR

### First Test
1. Upload a filing and navigate all the way to _Point of Contact_
2. Verify the Phone Extension in both mobile and desktop (901 px and
_above_)
3. Open the Network tab, submit and verify the request and response
jsons contain the phone extension (i.e. `phone_ext`)

### Second Test
1. Navigate all the way to _Sign and Submit_
2. Verify the `DisplayField` contains the submitted phone extension


### Third Test
1. Run `yarn run test:e2e`
2. Run the _sign-and-submit_ test to ensure it passes

## Screenshots
| PoC (Desktop) | PoC (Mobile) | Sign and Submit |
| -------- | ------- | ------- |
|<img width="533" alt="Screenshot 2024-09-30 at 9 07 06 AM"
src="https://github.com/user-attachments/assets/2210a4d8-e088-4cad-9d78-392aabc0de41">|<img
width="516" alt="Screenshot 2024-09-30 at 9 07 20 AM"
src="https://github.com/user-attachments/assets/cc203268-85bf-4826-8adc-d4740d1a91ea">|<img
width="632" alt="Screenshot 2024-09-30 at 2 18 43 PM"
src="https://github.com/user-attachments/assets/d18a1416-1cbc-494f-a561-d3cd44df22ba">|
  • Loading branch information
shindigira authored Sep 30, 2024
1 parent c6f68dc commit 7368475
Show file tree
Hide file tree
Showing 15 changed files with 93 additions and 24 deletions.
5 changes: 4 additions & 1 deletion e2e/example.spec.demo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,11 @@ test('proof of concept', async ({ page }) => {
await page.getByLabel('First name').fill(pointOfContactJson.first_name);
await page.getByLabel('Last name').fill(pointOfContactJson.last_name);
await page
.getByLabel('Work phone numberPhone number')
.getByLabel('Phone numberPhone number')
.fill(pointOfContactJson.phone_number);
await page
.getByLabel('Extension (optional)Extension')
.fill(pointOfContactJson.phone_ext);
await page
.getByLabel('Email addressEmail address')
.fill(pointOfContactJson.email);
Expand Down
6 changes: 5 additions & 1 deletion e2e/fixtures/testFixture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,7 @@ export const test = baseTest.extend<{
await page.getByRole('button', { name: 'Continue to next step' }).click();
await expect(page.locator('h1')).toContainText(
'Provide point of contact',
{ timeout: 30_000 },
);
});
await use(page);
Expand All @@ -273,8 +274,11 @@ export const test = baseTest.extend<{
await page.getByLabel('First name').fill(pointOfContactJson.first_name);
await page.getByLabel('Last name').fill(pointOfContactJson.last_name);
await page
.getByLabel('Work phone numberPhone number')
.getByLabel('Phone numberPhone number')
.fill(pointOfContactJson.phone_number);
await page
.getByLabel('Extension (optional)Extension')
.fill(pointOfContactJson.phone_ext);
await page
.getByLabel('Email addressEmail address')
.fill(pointOfContactJson.email);
Expand Down
2 changes: 1 addition & 1 deletion e2e/pages/filing-app/formAlerts.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ test('Form Alerts', async ({
await test.step('Complete form', async () => {
await page.getByLabel('First name').fill('Playwright');
await page.getByLabel('Last name').fill('Test');
await page.getByLabel('Work phone').fill('555-555-5555');
await page.getByLabel('Phone number').fill('555-555-5555');
await page.getByLabel('Email address').fill('[email protected]');
await page.getByLabel('Street address line 1').fill('555 Main St.');
await page.getByLabel('City').fill('Utah (U');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@
"hq_address_state": "CA",
"hq_address_zip": "55555",
"phone_number": "555-555-5555",
"phone_ext": "8942",
"email": "[email protected]"
}
2 changes: 1 addition & 1 deletion src/components/LabelOptional.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
function LabelOptional(): JSX.Element {
return (
<span className='text-base font-normal text-grayDark'> (optional)</span>
<span className='text-[1rem] font-normal text-grayDark'> (optional)</span>
);
}

Expand Down
9 changes: 6 additions & 3 deletions src/pages/Filing/FilingApp/FilingSubmit.helpers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export function getDescriptionForSignAndSubmitSection(

export function PointOfContactConfirm({
data,
heading = 'Confirm your filing point of contact',
heading = 'Confirm the point of contact for your filing',
description = getDescriptionForSignAndSubmitSection('poc'),
}: {
data: FilingType;
Expand All @@ -51,10 +51,13 @@ export function PointOfContactConfirm({
<WellContainer className='u-mt30'>
<DisplayField label='First name' value={poc?.first_name} />
<DisplayField label='Last name' value={poc?.last_name} />
<DisplayField label='Phone number' value={poc?.phone_number} />
{poc?.phone_ext ? (
<DisplayField label='Extension' value={poc?.phone_ext} />
) : null}
<DisplayField label='Email address' value={poc?.email} />
<DisplayField label='Work phone number' value={poc?.phone_number} />
<DisplayField
label='Business address'
label='Address'
value={
poc ? (
<>
Expand Down
4 changes: 2 additions & 2 deletions src/pages/Filing/ViewInstitutionProfile/DisplayField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ export function DisplayField({
return (
<div className={classNames('display-field', className)}>
{label ? (
<Heading className='h4' type='3'>
<Heading className='h4 break-all' type='3'>
{label}
</Heading>
) : undefined}
<p className='u-mt10'>{value ?? fallbackValue}</p>
<p className='u-mt10 break-all'>{value ?? fallbackValue}</p>
</div>
);
}
Expand Down
36 changes: 25 additions & 11 deletions src/pages/PointOfContact/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import type {
PointOfContactSchema,
} from 'types/formTypes';
import { ContactInfoMap, pointOfContactSchema } from 'types/formTypes';
import { inputCharLimit } from 'utils/constants';
import useAddressStates from 'utils/useAddressStates';
import useFilingStatus from 'utils/useFilingStatus';
import useInstitutionDetails from 'utils/useInstitutionDetails';
Expand Down Expand Up @@ -243,7 +244,7 @@ function PointOfContact(): JSX.Element {
keyLogicFunc={normalKeyLogic}
/>
<div className='mb-[1.875rem]'>
<SectionIntro heading='Provide contact information for your filing'>
<SectionIntro heading='Provide the point of contact for your filing'>
You are required to complete all fields with the exception of the
street address lines labeled optional. Your point of contact
information will not be saved until you provide all required
Expand All @@ -263,26 +264,39 @@ function PointOfContact(): JSX.Element {
label='First name'
id='firstName'
{...register('firstName')}
maxLength={255}
maxLength={inputCharLimit}
errorMessage={formErrors.firstName?.message}
showError
/>
<InputEntry
label='Last name'
id='lastName'
{...register('lastName')}
maxLength={255}
maxLength={inputCharLimit}
errorMessage={formErrors.lastName?.message}
showError
/>
<InputEntry
label='Work phone number'
id='phone'
{...register('phone')}
helperText='Phone number must be in 555-555-5555 format.'
errorMessage={formErrors.phone?.message}
showError
/>
<div className='flex flex-col items-stretch bpSM:flex-row bpSM:gap-[0.9375rem]'>
<InputEntry
className='w-full bpSM:flex-[5]'
label='Phone number'
id='phone'
{...register('phone')}
helperText='Phone number must be in 555-555-5555 format.'
errorMessage={formErrors.phone?.message}
showError
/>
<InputEntry
className='w-full bpSM:flex-[3]'
label='Extension'
id='phoneExtension'
helperText='Extension should be a number.'
{...register('phoneExtension')}
maxLength={inputCharLimit}
isOptional
/>
</div>

<InputEntry
label='Email address'
id='email'
Expand Down
1 change: 1 addition & 0 deletions src/pages/ProfileForm/ProfileFormUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export const formatPointOfContactObject = (
first_name: userProfileObject.firstName,
last_name: userProfileObject.lastName,
phone_number: userProfileObject.phone,
phone_ext: userProfileObject.phoneExtension,
email: userProfileObject.email,
hq_address_street_1: userProfileObject.hq_address_street_1,
hq_address_street_2: userProfileObject.hq_address_street_2,
Expand Down
5 changes: 3 additions & 2 deletions src/pages/ProfileForm/Step1Form/Step1FormInfoFieldGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import InputEntry from 'components/InputEntry';
import { Link } from 'components/Link';
import type { FieldErrors, UseFormRegister } from 'react-hook-form';
import type { BasicInfoSchema, ValidationSchema } from 'types/formTypes';
import { inputCharLimit } from 'utils/constants';

// TODO: Refactor to take a generic and pass these TS schemas in
type FormSchema = BasicInfoSchema | ValidationSchema;
Expand Down Expand Up @@ -31,15 +32,15 @@ function Step1FormInfoFieldGroup({
label='First name'
id='firstName'
{...register('firstName')}
maxLength={255}
maxLength={inputCharLimit}
errorMessage={formErrors.firstName?.message}
showError
/>
<InputEntry
label='Last name'
id='lastName'
{...register('lastName')}
maxLength={255}
maxLength={inputCharLimit}
errorMessage={formErrors.lastName?.message}
showError
/>
Expand Down
1 change: 1 addition & 0 deletions src/types/filingTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ export const FilingSchema = z.object({
hq_address_zip: z.string(),
email: z.string(),
phone_number: z.string(),
phone_ext: z.string(),
}),
z.null(),
]),
Expand Down
10 changes: 9 additions & 1 deletion src/types/formTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,12 @@ export const pointOfContactSchema = z.object({
.regex(usPhoneNumberRegex, {
message: PocZodSchemaErrors.phoneRegex,
}),
phoneExtension: z
.string()
.max(inputCharLimit, {
message: "The phone number extension's maximum character limit is 255",
})
.optional(),
email: z
.string()
.trim()
Expand Down Expand Up @@ -374,6 +380,7 @@ export const ContactInfoMap = {
first_name: 'firstName',
last_name: 'lastName',
phone_number: 'phone',
phone_ext: 'phoneExtension',
email: 'email',
hq_address_street_1: 'hq_address_street_1',
hq_address_street_2: 'hq_address_street_2',
Expand All @@ -390,9 +397,10 @@ export type ContactInfoValues = (typeof ContactInfoMap)[ContactInfoKeys];

export type FormattedPointOfContactSchema = Omit<
PointOfContactSchema,
'firstName' | 'lastName' | 'phone'
'firstName' | 'lastName' | 'phone' | 'phoneExtension'
> & {
first_name: string;
last_name: string;
phone_number: string;
phone_ext: string | undefined;
};
2 changes: 1 addition & 1 deletion src/utils/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export const Ten = 10;
export const ITEMS_PER_PAGE = 20;
export const Thirty = 30;
export const Hundred = 100;
export const inputCharLimit = 255;
export const inputCharLimit = 254;
export const EightHundred = 800;
export const Thousand = 1000;
export const CACHE_TIME = 600_000;
Expand Down
24 changes: 24 additions & 0 deletions src/utils/useWidthMatch.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { useEffect, useState } from 'react';

function useWidthMatch(query: string): boolean {
const [matches, setMatches] = useState<boolean>(false);

useEffect(() => {
const mediaQuery = window.matchMedia(query);
setMatches(mediaQuery.matches); // Initial check

const handleChange = (event: MediaQueryListEvent) => {
setMatches(event.matches);
};

mediaQuery.addEventListener('change', handleChange);

return () => {
mediaQuery.removeEventListener('change', handleChange);
};
}, [query]);

return matches;
}

export default useWidthMatch;
9 changes: 9 additions & 0 deletions tailwind.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,15 @@ const config = {
fontFamily: {
inter: ['Inter', ...defaultConfig.theme.fontFamily.sans],
},
// See `vars-breakpoints.js` of the `design-system` repo
screens: {
bpXS: '0px',
bpSM: '601px',
bpMED: '901px',
bpLG: '1021px',
bpXL: '1201px'

}
},
},
experimental: { optimizeUniversalDefaults: true },
Expand Down

0 comments on commit 7368475

Please sign in to comment.