Skip to content

Commit

Permalink
feat(tfi, poc): Provide Your Types of Financial Institutions - Skelet…
Browse files Browse the repository at this point in the history
…on; Point of Contact - Skeleton, Input Validation, Error Handling, Submission (#300)

closes #284 
closes #287 
closes #297
closes #288 

## Changes
- style(Fieldgroup): Adhere's to the 770px max-width with box-border
(includes borders, margins and padding into the max-width)
- style(SectionIntro): Adhere's to the 670px max-width with box-border
(includes borders, margins and padding into the max-width)
- feat(poc): Point of Contacts - Skeleton
- feat(poc): Point of Contacts - Zod Schema
- feat(tfi): Types of Financial Institutions - Skeleton Implemented -
awaiting functionality
- feat(vite proxy): add `v1/filing` as a vite proxy point.
- feat(poc): Create a `submitPointOfContact` request for use on the
Point of Contact form.
- chore(FormMain): Created a `FormMain` component which is a wrapper
component for `<form />`.

## Screenshots

|Point of Contact|PoC Error Header|Types of Financial Institutions|
|---|---|---|
|<img width="412" alt="Screenshot 2024-03-15 at 11 35 42 AM"
src="https://github.com/cfpb/sbl-frontend/assets/13324863/6109744d-6780-429a-b92f-d4088dc4eae5">|<img
width="416" alt="Screenshot 2024-03-15 at 11 35 59 AM"
src="https://github.com/cfpb/sbl-frontend/assets/13324863/a0e8137a-9738-44e9-98cd-341b17ff8545">|<img
width="410" alt="Screenshot 2024-03-15 at 11 39 12 AM"
src="https://github.com/cfpb/sbl-frontend/assets/13324863/44f1ce18-e37c-4e5b-b1cc-60c60b0fa326">|

## How to Test
**Pre-requisites**
- Make sure to `yarn update`, wipe all Docker containers and Docker
volumes, run `yarn seed`.
- **Add `SBL_FILING_BASE_URL="http://localhost:8882"` to your `.env`.**

**Test Set 0**
- Code inspect the proxy changes
- Ensure all previously create requests are functioning properly
- Inspect the styling of `Fieldgroup` and ensure the 770px (48.125rem)
limit is met (including borders, margins, etc).

**Test Set 1**
- If needed, `toggleRouting()` to disable enforced routing
- Navigate to `http://localhost:8899/point-of-contact` to verify Point
of Contact
- Do not fill anything and hit **submit**. Double-check regex
verification (ZIP code, phone number, email, etc)
- Fill out everything properly and hit submit. Check in Network tab
along (compare with the swagger docs) that the request is properly
implemented. NOTE: Currently, the request is **not** working (backend
problem).

**Test Set 2**
- If needed, `toggleRouting()` to disable enforced routing
- Navigate to `http://localhost:8899/types-financial-institutions` to
verify Types of Financial Institutions. No functionality at this moment.

## TODO
- `submitPointOfContact` requires a corresponding `lei` and
`filing_period`, so temporarily using **HARDCODED** values.
- Types of Financial Institutions: Waiting on `Update Your Financial
Institution` to be completed before further updates to the zod schema,
input validation and error handling.

## Notes
- Includes commits from 222: Update Your Financial Institution; wait
till that PR is merged in before this one.
- Currently, the `submitPointOfContact` request will return an `500
Internal Server Error`. This can be ignored, [see
here](#300 (comment)).

---------

Co-authored-by: Meis <[email protected]>
  • Loading branch information
shindigira and meissadia authored Mar 19, 2024
1 parent 377b28c commit e083993
Show file tree
Hide file tree
Showing 20 changed files with 637 additions and 95 deletions.
1 change: 1 addition & 0 deletions ENV-GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ SBL_OIDC_AUTHORITY="http://localhost:8880/realms/regtech"
SBL_OIDC_CLIENT_ID="regtech-client"
SBL_OIDC_REDIRECT_URI="http://localhost:${SBL_DEV_PORT}/filing"
SBL_REGTECH_BASE_URL="http://localhost:8881"
SBL_FILING_BASE_URL="http://localhost:8882"
SBL_MAIL_BASE_URL="http://localhost:8765"
```

Expand Down
20 changes: 20 additions & 0 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ const PaperworkNotice = lazy(
async () => import('pages/Filing/PaperworkNotice'),
);
const Summary = lazy(async () => import('pages/Summary/Summary'));
const PointOfContact = lazy(async () => import('pages/PointOfContact'));
const TypesFinancialInstitutions = lazy(
async () => import('pages/TypesFinancialInstitutions'),
);

// allow developers to toggle routing in development
const isRoutingEnabled = getIsRoutingEnabled();
Expand Down Expand Up @@ -237,6 +241,22 @@ export default function App(): ReactElement {
</ProtectedRoute>
}
/>
<Route
path='/point-of-contact'
element={
<ProtectedRoute {...ProtectedRouteAuthorizations}>
<PointOfContact />
</ProtectedRoute>
}
/>
<Route
path='/types-financial-institutions'
element={
<ProtectedRoute {...ProtectedRouteAuthorizations}>
<TypesFinancialInstitutions />
</ProtectedRoute>
}
/>
<Route path='/privacy-act-notice' element={<PrivacyActNotice />} />
<Route
path='/paperwork-reduction-act-notice'
Expand Down
19 changes: 19 additions & 0 deletions src/api/requests/submitPointOfContact.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { request } from 'api/axiosService';
import type { SblAuthProperties } from 'api/useSblAuth';
import type { FormattedPointOfContactSchema } from 'types/formTypes';

const submitPointOfContact = async (
auth: SblAuthProperties,
userProfileObject: FormattedPointOfContactSchema,
): Promise<null> => {
return request<null>({
// This will eventually be `/v1/filing/institutions/{lei}/filings/{period_name}/contact-info`
// CURRENTLY HARDCODED
url: `/v1/filing/institutions/123456789TESTBANK123/filings/2024/contact-info`,
method: 'put',
body: userProfileObject,
headers: { Authorization: `Bearer ${auth.user?.access_token}` },
});
};

export default submitPointOfContact;
2 changes: 1 addition & 1 deletion src/components/FieldGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ interface FieldGroupProperties {

function FieldGroup({ children }: FieldGroupProperties): JSX.Element {
return (
<div className='field-group max-w-[48.125rem] !border !border-solid !border-cfpbBorderColor bg-[#F7F8F9] p-[1.875rem]'>
<div className='field-group box-border max-w-[48.125rem] !border !border-solid !border-cfpbBorderColor bg-[#F7F8F9] p-[1.875rem]'>
{children}
</div>
);
Expand Down
5 changes: 4 additions & 1 deletion src/components/FormErrorHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ function FormErrorHeader({
id,
}: FormErrorHeaderProperties): JSX.Element | null {
if (!errors || Object.keys(errors).length === 0) return null;

return (
<div className='mb-[2.8125rem] mt-[2.8125rem] w-full'>
<Element name={id} id={id}>
Expand Down Expand Up @@ -76,7 +77,9 @@ function FormErrorHeader({
{`${
formFieldsHeaderError[
keyUsed as keyof typeof formFieldsHeaderError
]
] ??
errors[keyUsed]?.message ??
'Missing entry'
}${
// eslint-disable-next-line @typescript-eslint/no-magic-numbers
typeof keyIndex === 'number' ? ` (${keyIndex + 1})` : ''
Expand Down
18 changes: 18 additions & 0 deletions src/components/FormMain.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import type { ReactNode } from 'react';

interface FormProperties {
children: ReactNode;
}

/**
*
* @returns FormParagraph
*/
function FormMain({
children,
className = '',
}: FormProperties & React.ComponentPropsWithoutRef<'form'>): JSX.Element {
return <form className={`mb-[3.75rem] w-full ${className}`}>{children}</form>;
}

export default FormMain;
4 changes: 2 additions & 2 deletions src/components/FormWrapper.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import type { ReactNode } from 'react';

interface Properties {
interface FormWrapperProperties {
children: ReactNode;
}

function FormWrapper({ children }: Properties): JSX.Element {
function FormWrapper({ children }: FormWrapperProperties): JSX.Element {
return (
<div className='ml-5 mr-5 mt-[2.813rem]'>
<div className='mx-auto mb-12 max-w-[75rem]'>
Expand Down
5 changes: 3 additions & 2 deletions src/components/InputEntry.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { forwardRef } from 'react';
import { Element } from 'react-scroll';

import InputErrorMessage from 'components/InputErrorMessage';
import LabelOptional from 'components/LabelOptional';
import { Heading, TextInput } from 'design-system-react';
import LabelOptional from './LabelOptional';

interface InputEntryProperties
extends PropsWithoutRef<JSX.IntrinsicElements['input']> {
Expand All @@ -23,6 +23,7 @@ interface InputEntryProperties
const InputEntry = forwardRef<HTMLInputElement, InputEntryProperties>(
(
{
className = '',
id,
errorMessage,
label,
Expand All @@ -38,7 +39,7 @@ const InputEntry = forwardRef<HTMLInputElement, InputEntryProperties>(
) => {
const handleError = Boolean(showError && errorMessage);
return (
<div className={`${isLast ? '' : 'mb-[0.9375rem]'}`}>
<div className={`${isLast ? '' : 'mb-[0.9375rem]'} ${className}`}>
<Element name={id}>
<label htmlFor={id}>
<div>
Expand Down
2 changes: 1 addition & 1 deletion src/components/SectionIntro.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ function SectionIntro({
children = '',
}: SectionIntroProperties): JSX.Element {
return (
<div className='mb-[1.625rem] max-w-[48.125rem]'>
<div className='mb-[1.875rem] box-border max-w-[41.875rem]'>
<Heading type='2'>{heading}</Heading>
<FormParagraph>{children}</FormParagraph>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import FieldGroup from 'components/FieldGroup';
import InputEntry from 'components/InputEntry';
import { Checkbox, Heading, List, ListItem } from 'design-system-react';
import type {
Control,
FieldErrors,
UseFormRegister,
UseFormSetValue,
} from 'react-hook-form';
import { Controller as FormController } from 'react-hook-form';
import { Zero } from 'utils/constants';
import type { CheckboxOption, UFPSchema } from './types';
import { checkboxOptions } from './types';

interface TypesFinancialInstitutionSectionProperties {
register: UseFormRegister<UFPSchema>;
setValue: UseFormSetValue<UFPSchema>;
formErrors: FieldErrors<UFPSchema>;
control: Control<UFPSchema>;
}

function TypesFinancialInstitutionSection({
register,
setValue,
formErrors,
control,
}: TypesFinancialInstitutionSectionProperties): JSX.Element {
// const typeOtherData = data.sbl_institution_types.find(item => {
// return item.sbl_type.id === sblInstitutionTypeMap.other;
// });
return (
<FieldGroup>
<Heading type='4'>Type(s) of financial institution</Heading>
<List isUnstyled>
{checkboxOptions.map((option: CheckboxOption): JSX.Element => {
const optionId = `sbl_institution_types.${option.id}`;

const onCheckboxChange = (
event: React.ChangeEvent<HTMLInputElement>,
): void => {
setValue(optionId, event.target.checked);
};

return (
<ListItem key={option.id}>
<FormController
render={({ field }) => {
return (
<Checkbox
id={option.id}
label={option.label}
{...register(optionId)}
checked={field.value}
onChange={onCheckboxChange}
/>
);
}}
control={control}
name={optionId}
/>
</ListItem>
);
})}
</List>
<InputEntry
label=''
id='institutionTypeOther'
{...register('sbl_institution_types_other', {
// value: typeOtherData?.details,
})}
errorMessage={formErrors[Zero]}
showError
/>
</FieldGroup>
);
}

export default TypesFinancialInstitutionSection;
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import CommonLinks from 'components/CommonLinks';
import FieldGroup from 'components/FieldGroup';
import FormMain from 'components/FormMain';
import SectionIntro from 'components/SectionIntro';

import {
Checkbox,
Heading,
Expand Down Expand Up @@ -107,9 +109,9 @@ function UpdateIdentifyingInformation({
If you wish to provide additional types of financial institutions add
them to “Other” and check the box.{' '}
</Paragraph>
<form>
<FormMain>
<FieldGroup>
<Heading type='4'>Type of financial institution</Heading>
<Heading type='4'>Types of financial institutions</Heading>
<List isUnstyled>
{checkboxOptions.map((option: CheckboxOption): JSX.Element => {
const optionId = `sbl_institution_types.${option.id}`;
Expand Down Expand Up @@ -151,7 +153,7 @@ function UpdateIdentifyingInformation({
showError
/>
</FieldGroup>
</form>
</FormMain>
</FormSectionWrapper>
);
}
Expand Down
54 changes: 27 additions & 27 deletions src/pages/Filing/UpdateFinancialProfile/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,32 +118,32 @@ export const ufpSchema = z.object({
sbl_institution_types: z.object(checkboxOptionsZod),
});

// export type UFPSchema = z.infer<typeof ufpSchema>;
export type UFPSchema = z.infer<typeof ufpSchema>;

interface ExpectedObject {
sbl_institution_types?: Record<string, boolean>;
tax_id?: string;
hq_address_street_1?: string;
hq_address_street_2?: string;
hq_address_city?: string;
hq_address_state_code?: string;
hq_address_zip?: string;
parent_lei?: string;
parent_legal_name?: string;
parent_rssd_id?: string;
top_holder_lei?: string;
top_holder_legal_name?: string;
top_holder_rssd_id?: string;
lei?: string;
name?: string;
is_active?: boolean | string;
rssd_id?: string;
primary_federal_regulator_id?: string;
hmda_institution_type_id?: string;
hq_address_state?: string;
primary_federal_regulator?: string;
additional_details?: string;
domains?: string;
}
// interface ExpectedObject {
// sbl_institution_types?: Record<string, boolean>;
// tax_id?: string;
// hq_address_street_1?: string;
// hq_address_street_2?: string;
// hq_address_city?: string;
// hq_address_state_code?: string;
// hq_address_zip?: string;
// parent_lei?: string;
// parent_legal_name?: string;
// parent_rssd_id?: string;
// top_holder_lei?: string;
// top_holder_legal_name?: string;
// top_holder_rssd_id?: string;
// lei?: string;
// name?: string;
// is_active?: boolean | string;
// rssd_id?: string;
// primary_federal_regulator_id?: string;
// hmda_institution_type_id?: string;
// hq_address_state?: string;
// primary_federal_regulator?: string;
// additional_details?: string;
// domains?: string;
// }

export type UFPSchema = ExpectedObject;
// export type UFPSchema = ExpectedObject;
Loading

0 comments on commit e083993

Please sign in to comment.