Skip to content

Commit

Permalink
feat(FSADT1-1349): Create client for staff Step 1 - Individuals (#1008)
Browse files Browse the repository at this point in the history
* feat(FSADT1-1346): add create client to staff dashboard

* chore: updating project files

* feat(FSADT1-1346): soft-locking feature behind a feature flag

* fix(FSADT1-1346): fixing tests with feature flag

* add new business fields

* add the individual client component

* use the individual page component

* update client type codes

* add Date of birth tooltip

* add the person id fields

* fix input fields width

* prevent horizontal scroll

Prevents horizontal scroll when the vertical scrollbar is present, by accounting for its width.

* make province names visible when options are expanded

* set default issuing province to BC

When ID type is CDL.

* copy validations from BCeID

* fix validators for empty string

* add validations

* validate id number

* fix ID type codes

* add type checking to ID type

* validate birth certificate

* validate passport

* validate citizenship card

* validate First Nation status ID

* update max default size

* improve error message

* set the business name as the individual's full name

* add button Next

* fix message to refer to the applicant

* add button Cancel

* update max length for non-BC DL

* add ID Type Other

* validate ID type Other

* validate Other ID right-hand side

* improve validation for ID type Other

* prevent bad data hidden when the input mask gets updated

* fix interference on Form BCeID validations

* remove duplicated code

* add selectorErrorMessage

* test validators

* improve Other validator

* improve Other validation

* expose validate function

* fix idNumber validations

Updates some keys and fixes the FNID type.

* test StaffFormValidations

* move to next step

* fix: keep selected client type stored in state

* keep the state of local fields

* rename the types for virtual fields

* fix: button next is not enabled when returning to the first step

* fix component rendering

For loading the proper validation and mask.

* refactor: create virtual fields refs internally

* test IndividualClientInformationWizardStep

* test: remove only

* test businessName

* test: add e2e tests

* change Canadian DL codes

* fix max validator

* test: use all input fields in the test

* docs: remove misplaced comment

* switch to new DTO structure

Among other changes, it adds the identification type and province as independent fields.

* use firstName and lastName in businessInformation

* load external validations to be used as default

* rename input fields and variables

In conformation to the new DTO structure.

* test: validate firstName and lastName

* test the step

* fix: clear dropdown programmatically

* test: fix test

* test: add tests

---------

Co-authored-by: Paulo Gomes da Cruz Junior <[email protected]>
  • Loading branch information
fterra-encora and paulushcgcj authored Jun 24, 2024
1 parent 9c3c590 commit 8ab7191
Show file tree
Hide file tree
Showing 14 changed files with 1,985 additions and 75 deletions.
168 changes: 168 additions & 0 deletions frontend/cypress/e2e/FormStaffPage.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,4 +99,172 @@ describe("Staff Form", () => {

});

describe("when the user clicks the Create client button", () => {
beforeEach(() => {
cy.login("[email protected]", "Uat Test", "idir", {
given_name: "James",
family_name: "Baxter",
"cognito:groups": ["CLIENT_ADMIN"],
});

// Check if the Create client button is visible
cy.get('#menu-list-staff-form')
.should('be.visible')
.click();
});

it("should display the Client type input field", () => {
cy.get("#clientType").should("be.visible").and("have.value", "");
});

it("should not display any Client type specific input fields", () => {
cy.get("#firstName").should("not.exist");
});

describe("when option Individual gets selected", () => {
beforeEach(() => {
cy.get("#clientType")
.should("be.visible")
.and("have.value", "")
.find("[part='trigger-button']")
.click();

cy.get("#clientType")
.find('cds-combo-box-item[data-id="I"]')
.should("be.visible")
.click()
.and("have.value", "Individual");
});
it("should display the Individual information input fields", () => {
cy.contains("h2", "Client information");
cy.get("#firstName").should("be.visible");
cy.get("#middleName").should("be.visible");
cy.get("#lastName").should("be.visible");
cy.get("#birthdate").should("be.visible");
cy.get("#identificationType").should("be.visible");
cy.get("#clientIdentification").should("be.visible");
});

describe("when all the required information is filled in", () => {
const baseData = {
firstName: "John",
middleName: "Michael",
lastName: "Silver",
birthdateYear: "2001",
birthdateMonth: "05",
birthdateDay: "30",
identificationTypeValue: "Canadian passport",
identificationProvinceValue: undefined,
clientIdentification: "AB345678",
};
const scenarios = [
{
name: "and the selected ID type doesn't require Issuing province",
data: {
...baseData,
},
},
{
name: "and the selected ID type requires Issuing province",
data: {
...baseData,
identificationTypeValue: "Canadian driver's licence",
identificationProvinceValue: "Nova Scotia",
},
},
];
scenarios.forEach(({ name, data }) => {
describe(name, () => {
beforeEach(() => {
cy.get("#firstName").shadow().find("input").type(data.firstName);

cy.get("#middleName").shadow().find("input").type(data.middleName);

cy.get("#lastName").shadow().find("input").type(data.lastName);

cy.get("#birthdateYear").shadow().find("input").type(data.birthdateYear);
cy.get("#birthdateMonth").shadow().find("input").type(data.birthdateMonth);
cy.get("#birthdateDay").shadow().find("input").type(data.birthdateDay);

cy.get("#identificationType").find("[part='trigger-button']").click();
cy.get("#identificationType")
.find(`cds-combo-box-item[data-value="${data.identificationTypeValue}"]`)
.click();

if (data.identificationProvinceValue) {
cy.get("#identificationProvince").find("[part='trigger-button']").click();
cy.get("#identificationProvince")
.find(`cds-combo-box-item[data-value="${data.identificationProvinceValue}"]`)
.click();
}

cy.get("#clientIdentification")
.shadow()
.find("input")
.type(data.clientIdentification);

cy.get("#clientIdentification").shadow().find("input").blur();
});
it("enables the button Next", () => {
cy.get("[data-test='wizard-next-button']")
.shadow()
.find("button")
.should("be.enabled");
});

describe("and the button Next is clicked", () => {
beforeEach(() => {
cy.get("[data-test='wizard-next-button']").click();
});
it("hides the Client information section", () => {
cy.contains("h2", "Client information").should("not.exist");
});
describe("and the button Back is clicked", () => {
beforeEach(() => {
cy.get("[data-test='wizard-back-button']").click();
});
it("renders the Individual input fields with the same data", () => {
cy.get("#firstName").shadow().find("input").should("have.value", data.firstName);

cy.get("#middleName")
.shadow()
.find("input")
.should("have.value", data.middleName);

cy.get("#lastName").shadow().find("input").should("have.value", data.lastName);

cy.get("#birthdateYear")
.shadow()
.find("input")
.should("have.value", data.birthdateYear);
cy.get("#birthdateMonth")
.shadow()
.find("input")
.should("have.value", data.birthdateMonth);
cy.get("#birthdateDay")
.shadow()
.find("input")
.should("have.value", data.birthdateDay);

cy.get("#identificationType").should("have.value", data.identificationTypeValue);

if (data.identificationProvinceValue) {
cy.get("#identificationProvince").should(
"have.value",
data.identificationProvinceValue,
);
}

cy.get("#clientIdentification")
.shadow()
.find("input")
.should("have.value", data.clientIdentification);
});
});
});
});
});
});
});
});
});
69 changes: 60 additions & 9 deletions frontend/src/assets/styles/global.scss
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@
The value is in pixels instead of rem because it shouldn't vary with text resize.
*/
--scroll-bar-width-px: 15;
--scroll-bar-width: calc(1rem * var(--scroll-bar-width-px) / 16);
}

@media screen and (hover: none) {
Expand Down Expand Up @@ -275,6 +276,12 @@ cds-combo-box-item[data-loading="true"]::part(
border-top: 0;
}

cds-combo-box#identificationProvince::part(menu-body) {
width: min-content;
min-width: 100%;
max-width: 200%;
}

.top-notification {
margin-top: 3rem;
display: flex;
Expand Down Expand Up @@ -648,7 +655,7 @@ cds-actionable-notification * {
align-items: flex-start;
}

.form-steps {
.form-steps, .form-steps-staff {
flex-grow: 1;
align-self: stretch;
display: flex;
Expand All @@ -657,6 +664,10 @@ cds-actionable-notification * {
max-width: 50.4375rem;
}

.form-steps-staff {
max-width: 42.5rem;
}

.form-steps-01 {
display: flex;
flex-direction: column;
Expand Down Expand Up @@ -807,6 +818,22 @@ cds-actionable-notification * {
background-blend-mode: multiply;
}

.form-steps-staff :is(
.grouping-02,
.grouping-03
) {
width: 42.5rem;
}

.grouping-03:has(#identificationType) {
width: 20.75rem;
}

.grouping-03:has(#identificationProvince),
.grouping-02:has(#clientIdentification) {
width: 9.875rem;
}

.grouping-04 {
align-self: stretch;
display: flex;
Expand Down Expand Up @@ -1005,6 +1032,12 @@ cds-actionable-notification * {
margin: 0.5rem 0;
}

.horizontal-input-grouping {
display: flex;
flex-direction: row;
gap: 1rem;
}

.label-01 {
align-self: stretch;
padding-bottom: 0.25rem;
Expand Down Expand Up @@ -1069,6 +1102,16 @@ cds-text-input::part(label)::before, .cds-text-input-required-label {
color: var(--light-theme-text-text-error, #b32001);
}

.label-with-icon .cds-text-input-label {
padding-bottom: 0;
}

.label-with-icon {
padding-bottom: 1rem;
display: flex;
gap: 0.5rem;
}

cds-text-input[data-required-label="true"]::part(label)::before {
content: '* ';
}
Expand Down Expand Up @@ -1774,8 +1817,10 @@ Useful for scrolling to the *start* of an HTML element without having it covered
margin-bottom: 2rem;
}
.submission-content {
padding: 2.5rem 2rem 2.5rem 18.5rem;
max-width: calc(100vw - 21rem);
--padding-right: 2rem;
--padding-left: 18.5rem;
padding: 2.5rem var(--padding-right) 2.5rem var(--padding-left);
max-width: calc(100vw - (var(--padding-right) + var(--padding-left) + var(--scroll-bar-width)));
}

#datatable {
Expand Down Expand Up @@ -1843,8 +1888,10 @@ Useful for scrolling to the *start* of an HTML element without having it covered
}

.submission-content {
padding: 2.5rem 2rem 2.5rem 18.5rem;
max-width: calc(100vw - 21rem);
--padding-right: 2rem;
--padding-left: 18.5rem;
padding: 2.5rem var(--padding-right) 2.5rem var(--padding-left);
max-width: calc(100vw - (var(--padding-right) + var(--padding-left) + var(--scroll-bar-width)));
}
}

Expand Down Expand Up @@ -1892,8 +1939,10 @@ Useful for scrolling to the *start* of an HTML element without having it covered
}

.submission-content {
padding: 2.5rem 2rem 2.5rem 18.5rem;
max-width: calc(100vw - 21rem);
--padding-right: 2rem;
--padding-left: 18.5rem;
padding: 2.5rem var(--padding-right) 2.5rem var(--padding-left);
max-width: calc(100vw - (var(--padding-right) + var(--padding-left) + var(--scroll-bar-width)));
}
}

Expand Down Expand Up @@ -1927,7 +1976,9 @@ Useful for scrolling to the *start* of an HTML element without having it covered
}

.submission-content {
padding: 2.5rem 2.5rem 2.5rem 18.5rem;
max-width: calc(100vw - 21rem);
--padding-right: 2.5rem;
--padding-left: 18.5rem;
padding: 2.5rem var(--padding-right) 2.5rem var(--padding-left);
max-width: calc(100vw - (var(--padding-right) + var(--padding-left) + var(--scroll-bar-width)));
}
}
2 changes: 1 addition & 1 deletion frontend/src/components/forms/DropdownInputComponent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ const comboBoxMountTime = ref<[number]>([Date.now()]);
//Watch for changes on the input
watch([selectedValue], () => {
if (selectedValue.value === "") {
if (!selectedValue.value) {
comboBoxMountTime.value = [Date.now()];
}
const reference = selectedValue.value
Expand Down
7 changes: 7 additions & 0 deletions frontend/src/dto/ApplyClientNumberDto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@ export interface FormDataDto {
goodStandingInd: string;
birthdate: string;
address: Address;
firstName?: string;
middleName?: string;
lastName?: string;
identificationType?: string;
clientIdentification?: string;
identificationCountry?: string;
identificationProvince?: string;
};
location: {
addresses: Address[];
Expand Down
14 changes: 14 additions & 0 deletions frontend/src/dto/CommonTypesDto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,20 @@ export enum ClientTypeEnum {
USP,
}

export enum IdentificationTypeEnum {
BRTH,
CDDL,
PASS,
CITZ,
FNID,
USDL,
OTHR,
}

export interface IdentificationType extends CodeNameType {
code: keyof typeof IdentificationTypeEnum;
}

export interface ProgressData {
kind: string;
title: string;
Expand Down
5 changes: 4 additions & 1 deletion frontend/src/helpers/CustomDirectives.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
import { mask } from 'vue-the-mask'
import { mask, tokens } from "vue-the-mask";

// add custom token
tokens.N = { pattern: /[0-9a-zA-Z]/, transform: (v) => v.toLocaleUpperCase() };

export const masking = (shadowSelector: string) => (el: any, binding: any) => {
if (el.shadowRoot && binding.value) {
Expand Down
Loading

0 comments on commit 8ab7191

Please sign in to comment.