Skip to content

Commit

Permalink
[Story] Indicate voluntary reporter status (#1000)
Browse files Browse the repository at this point in the history
Added frontend support for Voluntary Filing Status and renamed some page
elements.

## Changes

- Added a Radio Button Group component to handle the state stuff of the
radio buttons.
- Added the Indicate Voluntary Reporter Status section and Radio buttons
to the Point of Contact Page
- Added Zod validation for the voluntary reporter status
- Fixed a bug which caused the extension field to no longer be optional
and fixed a test related to it
- Updated verbiage from Point of Contact to Filing Details where
appropriate
- Updated other verbiage to be in line with the Figma docs
- Moved and updated the Voluntary Reporter status section in the Sign
and Submit page
- Updated tests to use new verbiage where appropriate and fix test
failures

## How to test this PR

1. Read the notes
2. Pull the branch
3. Restart any stack components as necessary
4. Access the site
5. Fill out a submission until you can navigate to the 'Provide Filing
Details' page
6. Verify that everything appears as expected.
7. Without filing anything out, attempt to submit the form
8. Verify that the appropriate errors appear for the Voluntary Reporter
Status being blank
9. Fill out the form
10. Click 'Continue to next step'
11. Verify that the sign and submit page contains the Voluntary Reporter
Status section in the right place and that it appears correct.

## Screenshots
<img width="706" alt="Screenshot 2024-10-24 at 12 57 23 PM"
src="https://github.com/user-attachments/assets/b7a3bd9c-c6c1-4131-a0b6-600b97c0fed4">
<img width="810" alt="Screenshot 2024-10-24 at 12 57 46 PM"
src="https://github.com/user-attachments/assets/7136271c-8139-4e3a-8e88-281ad61ac40a">
<img width="787" alt="Screenshot 2024-10-24 at 12 57 02 PM"
src="https://github.com/user-attachments/assets/aa8f4b06-7352-489a-b081-9b98f3a03ce8">
<img width="797" alt="Screenshot 2024-10-24 at 12 57 13 PM"
src="https://github.com/user-attachments/assets/91ef6082-62c5-40b3-a933-dcac4d16bd2b">
<img width="798" alt="Screenshot 2024-10-24 at 12 59 42 PM"
src="https://github.com/user-attachments/assets/87e78cac-d6db-498e-8773-b522c74d1d2f">
<img width="789" alt="Screenshot 2024-10-24 at 1 00 22 PM"
src="https://github.com/user-attachments/assets/a460dbf5-1e81-41df-a2cf-96ab85775bca">
<img width="823" alt="Screenshot 2024-10-24 at 12 58 04 PM"
src="https://github.com/user-attachments/assets/633aff83-5ed6-4dee-851c-141929fe787c">

## Notes

- There may be e2e test failures at the moment. I am putting off
completely fixing/extending them until the follow on work
- Would like to rename all appropriate instances of PointOfContact to
FilingDetails as a part of the follow on work as well.
  • Loading branch information
tanner-ricks authored Oct 29, 2024
1 parent c7167c4 commit ce7802d
Show file tree
Hide file tree
Showing 24 changed files with 525 additions and 154 deletions.
10 changes: 5 additions & 5 deletions e2e/example.spec.demo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,14 +68,14 @@ test('proof of concept', async ({ page }) => {
await expect(page.locator('h1')).toContainText('Review warnings');
});

await test.step('Review warnings: navigate to Provide point of contact', async () => {
await test.step('Review warnings: navigate to Provide filing details', async () => {
await page.getByText('I verify the accuracy of').click();
await page.getByRole('button', { name: 'Continue to next step' }).click();
await expect(page.locator('h1')).toContainText('Provide point of contact');
await expect(page.locator('h1')).toContainText('Provide filing details');
});

await test.step('Provide point of contact: navigate to Sign and submit', async () => {
await test.step('Provide point of contact: fill out form', async () => {
await test.step('Provide filing details: navigate to Sign and submit', async () => {
await test.step('Provide filing details: fill out form', async () => {
await page.getByLabel('First name').fill(pointOfContactJson.first_name);
await page.getByLabel('Last name').fill(pointOfContactJson.last_name);
await page
Expand Down Expand Up @@ -107,7 +107,7 @@ test('proof of concept', async ({ page }) => {
.getByLabel('ZIP codeZIP code must be in')
.fill(pointOfContactJson.hq_address_zip);
});
await test.step('Provide point of contact: continue to next step', async () => {
await test.step('Provide filing details: continue to next step', async () => {
await page.getByRole('button', { name: 'Continue to next step' }).click();
await expect(page.locator('h1')).toContainText('Sign and submit');
});
Expand Down
12 changes: 5 additions & 7 deletions e2e/fixtures/testFixture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -322,12 +322,10 @@ export const test = baseTest.extend<{
use,
) => {
navigateToReviewWarningsAfterOnlyWarningsUpload;
await test.step('Review warnings: navigate to Provide point of contact', async () => {
await test.step('Review warnings: navigate to Provide filing details', async () => {
await page.getByText('I verify the accuracy of').click();
await clickContinueNext(test, page);
await expect(page.locator('h1')).toContainText(
'Provide point of contact',
);
await expect(page.locator('h1')).toContainText('Provide filing details');
});
await use(page);
},
Expand All @@ -337,8 +335,8 @@ export const test = baseTest.extend<{
use,
) => {
navigateToProvidePointOfContact;
await test.step('Provide point of contact: navigate to Sign and submit', async () => {
await test.step('Provide point of contact: fill out form', async () => {
await test.step('Provide filing details: navigate to Sign and submit', async () => {
await test.step('Provide filing details: fill out form', async () => {
await page.getByLabel('First name').fill(pointOfContactJson.first_name);
await page.getByLabel('Last name').fill(pointOfContactJson.last_name);
await page
Expand Down Expand Up @@ -370,7 +368,7 @@ export const test = baseTest.extend<{
.getByLabel('ZIP codeZIP code must be in')
.fill(pointOfContactJson.hq_address_zip);
});
await test.step('Provide point of contact: continue to next step', async () => {
await test.step('Provide filing details: continue to next step', async () => {
await clickContinueNext(test, page);
await expect(page.locator('h1')).toContainText('Sign and submit');
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const currentStepPath = '/contact';

const userShouldNotAccess = ['/submit'];

const afterRedirectHeading = 'Provide point of contact';
const afterRedirectHeading = 'Provide filing details';
const afterRedirectURL = /.*\/contact$/;

test(testLabel, async ({ page, navigateToProvidePointOfContact }) => {
Expand Down
5 changes: 3 additions & 2 deletions e2e/pages/filing-app/formAlerts.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ test('Form Alerts', async ({
// Point of contact page
await test.step('Point of contact page', async () => {
await expect(page.locator('h1'), 'h1 is correct').toContainText(
'Provide point of contact',
'Provide filing details',
);

// Submit Incomplete form
Expand All @@ -199,13 +199,14 @@ test('Form Alerts', async ({
page.locator('.m-notification__error'),
'Error alert is visible',
).toContainText(
'There was a problem updating your point of contact informationEnter the first name of the point of contactEnter the last name of the point of contactEnter the phone number of the point of contactEnter a valid phone extensionEnter the email address of the point of contactEnter the street address of the point of contactEnter the city of the point of contactSelect the state or territory of the point of contactEnter the ZIP code of the point of contact',
'There was a problem updating your filing detailsEnter the first name of the point of contactEnter the last name of the point of contactEnter the phone number of the point of contactEnter the email address of the point of contactEnter the street address of the point of contactEnter the city of the point of contactSelect the state or territory of the point of contactEnter the ZIP code of the point of contact',
);
});

// Submit Completed form
await test.step('Submit Completed form', async () => {
await test.step('Complete form', async () => {
await page.getByText('Voluntary reporter', { exact: true }).click();
await page.getByLabel('First name').fill('Playwright');
await page.getByLabel('Last name').fill('Test');
await page.getByLabel('Phone number').fill('555-555-5555');
Expand Down
14 changes: 7 additions & 7 deletions e2e/pages/filing-app/point-of-contact/checkPocFormErrors.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ test('Point of Contact: Checking for form errors based on user input', async ({
await test.step('Point of Contact: Check that the error header render when no input is filled', async () => {
await clickContinueNext(test, page);
await expect(
page.locator('#PointOfContactFormErrors div').first(),
page.locator('#FilingDetailsFormErrors div').first(),
).toBeVisible();
});

Expand All @@ -39,10 +39,10 @@ test('Point of Contact: Checking for form errors based on user input', async ({
await expect(page.locator('form')).toContainText(
'The last name must not contain invalid characters',
);
await expect(page.locator('#PointOfContactFormErrors')).toContainText(
await expect(page.locator('#FilingDetailsFormErrors')).toContainText(
'The first name must not contain invalid characters',
);
await expect(page.locator('#PointOfContactFormErrors')).toContainText(
await expect(page.locator('#FilingDetailsFormErrors')).toContainText(
'The last name must not contain invalid characters',
);
});
Expand All @@ -57,7 +57,7 @@ test('Point of Contact: Checking for unicode tolerance based on user input', asy
await test.step('Point of Contact: Check that the error header render when no input is filled', async () => {
await clickContinueNext(test, page);
await expect(
page.locator('#PointOfContactFormErrors div').first(),
page.locator('#FilingDetailsFormErrors div').first(),
).toBeVisible();
});

Expand Down Expand Up @@ -154,13 +154,13 @@ test('Point of Contact: Checking for unicode tolerance based on user input', asy

await clickContinueNext(test, page);

await expect(page.locator('#PointOfContactFormErrors')).toContainText(
await expect(page.locator('#FilingDetailsFormErrors')).toContainText(
'Enter a valid phone number',
);
await expect(page.locator('#PointOfContactFormErrors')).toContainText(
await expect(page.locator('#FilingDetailsFormErrors')).toContainText(
'Enter a valid email address',
);
await expect(page.locator('#PointOfContactFormErrors')).toContainText(
await expect(page.locator('#FilingDetailsFormErrors')).toContainText(
'Enter a valid ZIP code',
);

Expand Down
6 changes: 3 additions & 3 deletions e2e/pages/filing-app/unavailableApis.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,10 +108,10 @@ test('Blocking API Calls - Error Boundaries', async ({
});
});

// Provide point of contact page
await test.step('Provide point of contact page', async () => {
// Provide filing details page
await test.step('Provide filing details page', async () => {
await verifyApiBlockThenUnblock({
expectedHeading: 'Provide point of contact',
expectedHeading: 'Provide filing details',
endpointPath: '**/v1/admin/me/',
endpointLabel: '/v1/admin/me',
page,
Expand Down
26 changes: 26 additions & 0 deletions src/api/requests/submitVoluntaryReporterStatus.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { filingApiClient, request } from 'api/axiosService';
import type { SblAuthProperties } from 'api/useSblAuth';
import type { FormattedVoluntaryReporterStatusSchema } from 'types/formTypes';

interface Options {
data: FormattedVoluntaryReporterStatusSchema;
lei: string;
filingPeriod: string;
}

const submitVoluntaryReporterStatus = async (
auth: SblAuthProperties,
options: Options,
): Promise<null> => {
const { data, lei, filingPeriod } = options;

return request<FormattedVoluntaryReporterStatusSchema, null>({
axiosInstance: filingApiClient,
url: `/v1/filing/institutions/${lei}/filings/${filingPeriod}/is-voluntary`,
method: 'put',
data,
headers: { Authorization: `Bearer ${auth.user?.access_token}` },
});
};

export default submitVoluntaryReporterStatus;
2 changes: 1 addition & 1 deletion src/components/CommonLinks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ interface UpdatePointOfContactProperties {
}

function UpdatePointOfContact({
label = 'update your point of contact information',
label = 'update your filing details',
className = 'font-normal',
}: UpdatePointOfContactProperties): ReactElement {
const { lei, year } = useParams();
Expand Down
19 changes: 19 additions & 0 deletions src/components/FormErrorHeader.data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,25 @@ export const IdFormHeaderErrors: IdFormHeaderErrorsType = {
export type IdFormHeaderErrorsValues =
(typeof IdFormHeaderErrors)[IdZodSchemaErrorsValues];

// Voluntary Reporter Status - Zod Schema Error Messages
export const VrsZodSchemaErrors = {
isVoluntaryMin: 'You must indicate your voluntary reporter status.',
} as const;

export type VrsZodSchemaErrorsType = typeof VrsZodSchemaErrors;
export type VrsZodSchemaErrorsKeys = keyof typeof VrsZodSchemaErrors;
export type VrsZodSchemaErrorsValues =
(typeof VrsZodSchemaErrors)[VrsZodSchemaErrorsKeys];

// Point of Contact - Form Header Error Messages
export type VrsFormHeaderErrorsType = Record<VrsZodSchemaErrorsValues, string>;
export const VrsFormHeaderErrors: VrsFormHeaderErrorsType = {
[VrsZodSchemaErrors.isVoluntaryMin]:
'Indicate your voluntary reporter status',
} as const;
export type VrsFormHeaderErrorsValues =
(typeof VrsFormHeaderErrors)[VrsZodSchemaErrorsValues];

// Point of Contact - Zod Schema Error Messages
export const PocZodSchemaErrors = {
firstNameMin:
Expand Down
57 changes: 57 additions & 0 deletions src/components/RadioButtonGroup.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { Label } from 'design-system-react';

function RadioButtonGroup({
id = 'radio-button-group',
label = 'Radio Group',
onChange = undefined,
children,
}: {
id?: string | null | undefined;
label?: string | null | undefined;
onChange?: React.ChangeEventHandler<HTMLInputElement> | null | undefined;
children: React.ReactNode;
}): JSX.Element {
const ENTER_KEY_CODE = 13;

const onKeyDown = (event: React.KeyboardEvent<HTMLInputElement>): void => {
if (
!event.altKey &&
!event.ctrlKey &&
!event.metaKey &&
!event.shiftKey &&
event.keyCode === ENTER_KEY_CODE
) {
event.preventDefault();
event.stopPropagation();
(event.target as HTMLInputElement).click();
}
};

return (
<>
<Label
id={id ?? undefined}
htmlFor={`${id}-radio-group`}
className='mb-[0.9375rem]'
>
{label}
</Label>
{/* eslint-disable-next-line jsx-a11y/no-static-element-interactions */}
<div
id={`${id}-radio-group`}
onKeyDown={onKeyDown}
onChange={onChange ?? undefined}
>
{children}
</div>
</>
);
}

RadioButtonGroup.defaultProps = {
id: 'radio-button-group',
label: 'Radio Group',
onChange: undefined,
};

export default RadioButtonGroup;
2 changes: 1 addition & 1 deletion src/components/StepIndicator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export const mockSteps: StepType[] = [
{ status: STEP_CURRENT, label: 'Upload file' },
{ status: STEP_INCOMPLETE, label: 'Resolve errors' },
{ status: STEP_INCOMPLETE, label: 'Review warnings' },
{ status: STEP_INCOMPLETE, label: 'Provide point of contact' },
{ status: STEP_INCOMPLETE, label: 'Provide filing details' },
{ status: STEP_INCOMPLETE, label: 'Sign and submit' },
];

Expand Down
11 changes: 5 additions & 6 deletions src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ https://v1.tailwindcss.com/docs/adding-base-styles#using-css */
@apply border-pacific;
}

.a-btn.a-btn__secondary .a-btn_icon__on-right{
.a-btn.a-btn__secondary .a-btn_icon__on-right {
@apply border-pacific;
}

Expand All @@ -40,7 +40,7 @@ https://v1.tailwindcss.com/docs/adding-base-styles#using-css */
.a-btn.a-btn__secondary:hover .a-btn_icon__on-left {
@apply border-pacificDark;
}

.a-btn.a-btn__secondary:hover .a-btn_icon__on-right {
@apply border-pacificDark;
}
Expand All @@ -52,7 +52,7 @@ https://v1.tailwindcss.com/docs/adding-base-styles#using-css */
.a-btn.a-btn__secondary:focus .a-btn_icon__on-left {
@apply border-pacificDark;
}

.a-btn.a-btn__secondary:focus .a-btn_icon__on-right {
@apply border-pacificDark;
}
Expand All @@ -64,11 +64,10 @@ https://v1.tailwindcss.com/docs/adding-base-styles#using-css */
.a-btn.a-btn__secondary:active .a-btn_icon__on-left {
@apply border-navy;
}

.a-btn.a-btn__secondary:active .a-btn_icon__on-right {
@apply border-navy;
}

}

select.error {
Expand Down Expand Up @@ -127,7 +126,7 @@ td {
/* Design System overrides */

/* Alerts - all icons in DS Alerts are colored based on the Alert type */
a .link-icon-override-color .cf-icon-svg{
a .link-icon-override-color .cf-icon-svg {
@apply fill-pacific;
}

Expand Down
4 changes: 2 additions & 2 deletions src/pages/Filing/FilingApp/FilingContact.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import PointOfContact from 'pages/PointOfContact';
import FilingDetails from 'pages/PointOfContact';

function FilingContact(): JSX.Element {
return <PointOfContact />;
return <FilingDetails />;
}

export default FilingContact;
2 changes: 1 addition & 1 deletion src/pages/Filing/FilingApp/FilingSteps.helpers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ export const getFilingSteps = (
},
{
status: getContactStatus(currentSubmission, currentFiling),
label: 'Provide point of contact',
label: 'Provide filing details',
isCurrent: isStepCurrent('/contact'),
},
{
Expand Down
Loading

0 comments on commit ce7802d

Please sign in to comment.