Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: refactor modal opening in project area page #3211

Merged
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 62 additions & 38 deletions app/components/Form/ApplicationForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,42 @@ const ApplicationForm: React.FC<Props> = ({
const isOtherFundingSourcesPage = sectionName === 'otherFundingSources';
const isReviewPage = sectionName === 'review';

const allZoneIntake =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this is a bool, we should rename this to isAllZoneIntake

Suggested change
const allZoneIntake =
const isAllZoneIntake =

isProjectAreaPage &&
acceptedProjectAreasArray.length ===
(sectionSchema.properties?.geographicArea as any)?.items?.enum?.length;

const isZoneSelectionValid = (
geographicAreaInput: number[],
firstNationsLed: boolean,
nullAllowed: boolean = true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here that bools should use the is prefix

Suggested change
firstNationsLed: boolean,
nullAllowed: boolean = true
isFirstNationsLed: boolean,
isNullAllowed: boolean = true

) => {
// null selection not allowed in submitted project area page
if (!nullAllowed && geographicAreaInput?.length === 0) return false;
return (
allZoneIntake ||
firstNationsLed ||
acceptedProjectAreasArray.includes(geographicAreaInput?.[0])
);
};

const getProjectAreaModalType = (
geographicAreaInputChanged: boolean,
firstNationsLedInputChanged: boolean
) => {
if (isSubmitted && geographicAreaInputChanged) {
// display new modal saying
// Invalid selection. You have indicated that this project is not led or supported by First Nations, therefore, you may only choose from zones 1,2,3 or 6.
return 'invalid-geographic-area';
}
if (isSubmitted && firstNationsLedInputChanged) {
// display modal saying
// Invalid selection. Please first choose from zones 1,2,3 or 6 if this project is not supported or led by First Nations
return 'first-nations-led';
}
return 'pre-submitted';
};

const isSubmitEnabled = useMemo(() => {
if (isUpdating) return false;

Expand Down Expand Up @@ -455,17 +491,6 @@ const ApplicationForm: React.FC<Props> = ({
}
if (isProjectAreaPage) {
const firstNationsLed = newFormSectionData?.firstNationsLed || false;
const isGeographicAreaEmpty =
newFormSectionData?.geographicArea?.[0] === 'undefined' ||
newFormSectionData?.geographicArea?.length === 0;
const projectAreaAccepted =
firstNationsLed ||
(!isGeographicAreaEmpty &&
(firstNationsLed ||
acceptedProjectAreasArray.includes(
newFormSectionData?.geographicArea?.[0]
)));
const isZoneSpecificIntake = latestIntakeNumber !== 4;
const geographicAreaInputChanged =
typeof newFormSectionData?.geographicArea?.[0] !== 'undefined' &&
newFormSectionData?.geographicArea[0] !==
Expand All @@ -474,30 +499,29 @@ const ApplicationForm: React.FC<Props> = ({
typeof newFormSectionData?.firstNationsLed !== 'undefined' &&
firstNationsLed !== jsonData.projectArea?.firstNationsLed;

if (isSubmitted && !projectAreaAccepted) {
// revert form data
newFormData = {
...jsonData,
};
if (geographicAreaInputChanged && isZoneSpecificIntake) {
// display new modal saying
// Invalid selection. You have indicated that this project is not led or supported by First Nations, therefore, you may only choose from zones 1,2,3 or 6.
setProjectAreaModalType('invalid-geographic-area');
const projectAreaAccepted = isZoneSelectionValid(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should stick to the is prefix for booleans

Suggested change
const projectAreaAccepted = isZoneSelectionValid(
const isProjectAreaAccepted = isZoneSelectionValid(
//could also do isValidZoneSelection

newFormSectionData?.geographicArea,
firstNationsLed,
!isSubmitted
);

if (!projectAreaAccepted) {
if (isSubmitted) {
// revert form data
newFormData = {
...jsonData,
};
}
if (firstNationsLedInputChanged && isZoneSpecificIntake) {
// display modal saying
// Invalid selection. Please first choose from zones 1,2,3 or 6 if this project is not supported or led by First Nations
setProjectAreaModalType('first-nations-led');
setProjectAreaModalType(
getProjectAreaModalType(
geographicAreaInputChanged,
firstNationsLedInputChanged
)
);

if (geographicAreaInputChanged || firstNationsLedInputChanged) {
projectAreaModal.open();
}
} else if (!isSubmitted && !projectAreaAccepted && isZoneSpecificIntake) {
setProjectAreaModalType('pre-submitted');
}
if (
!projectAreaAccepted &&
(geographicAreaInputChanged ||
(firstNationsLedInputChanged && isZoneSpecificIntake))
) {
projectAreaModal.open();
}

// Setting below properties to handle validation errors separately in submission page
Expand All @@ -507,11 +531,11 @@ const ApplicationForm: React.FC<Props> = ({
);
// calculating project area selection validity to clearout temporary values
// calculated for error handling/error modals
const projectAreaValid =
newFormData?.projectArea?.firstNationsLed ||
acceptedProjectAreasArray.includes(
newFormData?.projectArea?.geographicArea?.[0]
);
const projectAreaValid = isZoneSelectionValid(
newFormData?.projectArea?.geographicArea,
newFormData?.projectArea?.firstNationsLed
);

setIsProjectAreaInvalid(!projectAreaValid);
}

Expand Down
129 changes: 129 additions & 0 deletions app/tests/pages/applicantportal/form/[page].test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,18 @@ const mockAcceptedZones: moduleApi.FeatureResult<moduleApi.JSONValue> = {
ruleId: 'intake_zones_json',
};

const mockAllZones: moduleApi.FeatureResult<moduleApi.JSONValue> = {
value: {
'1': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14],
'2': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14],
'3': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14],
},
source: 'defaultValue',
on: null,
off: null,
ruleId: 'intake_zones_json',
};

const pageTestingHelper = new PageTestingHelper<PageQuery>({
pageComponent: FormPage,
compiledQuery: compiledPageQuery,
Expand Down Expand Up @@ -676,6 +688,102 @@ describe('The form page', () => {
expect(geographicArea).toBeChecked();
});

it('project area page should not allow null on geographic area after submission even when first nation led', async () => {
const payload = {
Application() {
return {
id: 'TestApplicationId',
status: 'submitted',
intakeByIntakeId: {
ccbcIntakeNumber: 3,
closeTimestamp: '2022-09-06T23:59:59-07:00',
},
formData: {
formByFormSchemaId: {
jsonSchema: schema,
},
jsonData: {
review: {
acknowledgeIncomplete: true,
},
submission: {
submissionDate: '2023-12-28',
submissionTitle: 'asdf',
submissionCompletedBy: 'asdf',
submissionCompletedFor: 'asdf',
},
projectArea: {
geographicArea: [3],
firstNationsLed: true,
},
techSolution: {
systemDesign: 'asdfd',
},
projectFunding: {
fundingRequestedCCBC2223: 111,
totalFundingRequestedCCBC: 111,
totalApplicantContribution: null,
},
acknowledgements: {
acknowledgementsList: [
'The Applicant acknowledges that it is under no obligation or prohibition, nor is it subject to, or threatened by any actions, suits or proceedings, which could or would affect its ability to implement this proposed Project.',
'The Applicant acknowledges that the Program may collect and share Applicant information for purposes that include making enquiries of such persons, firms, corporations, federal and provincial government agencies/departments/ministries, and non-profit organizations as the Program deems necessary in order to reach a decision on this proposed project.',
'The Applicant acknowledges that any person, who is required to be registered pursuant to the Lobbyists Transparency Act (British Columbia) or the Lobbying Act (Canada), including consultant and in-house lobbyists, must be registered pursuant to, and comply with, those Acts as applicable.',
'The Applicant acknowledges that, where applicable, the Project may require an assessment under the Impact Assessment Act (Canada) or the Environmental Assessment Act (British Columbia).',
'The Applicant recognizes that there is a duty to consult Indigenous groups if a funded Project may undertake infrastructure in, or affecting, an Indigenous community, and the Applicant understands that it must provide such information and assistance to the Province or Federal government in connection with such consultation as may reasonably be required, including, but not limited to, those obligations with respect to Indigenous consultation which may be set forth in any Funding Agreement.',
'The Applicant acknowledges that any current or former public officer holder or public servant employed by the Applicant must comply with the provisions of the Standards of Conduct for BC Public Service employees, the Disclosing a Conflict of Interest: Employee Guideline & Disclosure Form (British Columbia), the Members’ Conflict of Interest Act (British Columbia), the Values and Ethics Code for the Public Service (Canada), the Policy on Conflict of Interest and Post-Employment (Canada), and the Conflict of Interest Act (Canada), as applicable.',
'The Applicant understands that all costs incurred in the preparation and submission of the application shall be wholly absorbed by the Applicant.',
'The Applicant understands that the Program reserves the right to make partial awards and to negotiate project scope changes with Applicants.',
'The Applicant understands that the Program is a discretionary program subject to available funding, and that submission of a complete application, meeting any or all of the eligibility criteria, does not guarantee that funding will be granted. All Applicants whose Projects are approved for funding will be notified in writing.',
'The Applicant acknowledges that it must ensure compliance with any applicable Canadian national security requirements as defined and/or administered by the Canadian security authorities, and any Provincial security requirements as defined and/or administered by the Province.',
'The Applicant acknowledges that it must have the managerial and financial capacity to deliver this proposed project on time and within budget and to maintain the infrastructure and services on an ongoing basis for five years after project completion.',
'The Applicant confirms that it is requesting the lowest possible Program contribution amount required to make this proposed Project financially viable.',
'The Applicant acknowledges that information provided in this Application Form (including attachments) may be shared between the Province and the Government of Canada and other levels of government to promote the Program and maximize the benefits to Canadian citizens and permanent residents.',
'The Applicant acknowledges that all activities required for this proposed Project must comply with all applicable federal, provincial, and territorial laws, regulations, municipal and other local by-laws.',
'The Applicant acknowledges that knowingly making any false statements or misrepresentations, including by omission, in an application may affect its eligibility and may result in the revocation of funding approval.',
'The Applicant acknowledges that information submitted in an application is subject to the Access to Information Act (Canada) or the Freedom of Information and Protection of Privacy Act (BC), as applicable.',
'The Applicant confirms that, to the best of its knowledge, the information submitted in this application is true and correct as of the date of submission.',
],
},
projectInformation: {
projectTitle: 'asdf',
projectDescription: 'asdfdsa',
geographicAreaDescription: 'asdf',
},
organizationProfile: {
organizationName: 'asdf',
},
existingNetworkCoverage: {
hasProvidedExitingNetworkCoverage:
'I have provided existing Network information and/or Coverage to ISED or the CRTC in the past 12 months',
},
},
},
};
},
Query() {
return {
openIntake: {
closeTimestamp: '2022-08-27T12:52:00.00000-04:00',
},
};
},
};
pageTestingHelper.setMockRouterValues({
query: { id: '1', page: '2' },
});
pageTestingHelper.loadQuery(payload);
pageTestingHelper.renderPage();

const geographicArea = screen.getAllByRole('checkbox')[3];

expect(geographicArea).toBeChecked();

await userEvent.click(geographicArea);

expect(geographicArea).toBeChecked();
});

it('handles modal correctly when first nation based and not an available zone', async () => {
pageTestingHelper.setMockRouterValues({
query: { id: '1', page: '2' },
Expand Down Expand Up @@ -733,4 +841,25 @@ describe('The form page', () => {

await userEvent.click(modalOkButton);
});

it('should not show modal if first nations led no if intake is all zone permitted', async () => {
pageTestingHelper.setMockRouterValues({
query: { id: '1', page: '2' },
});

jest.spyOn(moduleApi, 'useFeature').mockReturnValue(mockAllZones);

pageTestingHelper.loadQuery();
pageTestingHelper.renderPage();

const fnQuestionNo = screen.getAllByLabelText('No')[0];

await userEvent.click(fnQuestionNo);

expect(
screen.queryByText(
'For this intake, CCBC is considering projects that are in Zones 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, or 14 if the project is not First Nations-led or First Nations-supported.'
)
).not.toBeInTheDocument();
});
});
Loading