diff --git a/app/components/Form/ApplicationForm.tsx b/app/components/Form/ApplicationForm.tsx index 91dc2ea9a..2b53ef4a3 100644 --- a/app/components/Form/ApplicationForm.tsx +++ b/app/components/Form/ApplicationForm.tsx @@ -379,6 +379,42 @@ const ApplicationForm: React.FC = ({ const isOtherFundingSourcesPage = sectionName === 'otherFundingSources'; const isReviewPage = sectionName === 'review'; + const isAllZoneIntake = + isProjectAreaPage && + acceptedProjectAreasArray.length === + (sectionSchema.properties?.geographicArea as any)?.items?.enum?.length; + + const isZoneSelectionValid = ( + geographicAreaInput: number[], + isFirstNationsLed: boolean, + isNullAllowed: boolean = true + ) => { + // null selection not allowed in submitted project area page + if (!isNullAllowed && geographicAreaInput?.length === 0) return false; + return ( + isAllZoneIntake || + isFirstNationsLed || + 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; @@ -455,17 +491,6 @@ const ApplicationForm: React.FC = ({ } 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] !== @@ -474,30 +499,29 @@ const ApplicationForm: React.FC = ({ 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 isProjectAreaAccepted = isZoneSelectionValid( + newFormSectionData?.geographicArea, + firstNationsLed, + !isSubmitted + ); + + if (!isProjectAreaAccepted) { + 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 @@ -507,11 +531,11 @@ const ApplicationForm: React.FC = ({ ); // 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); } diff --git a/app/tests/pages/applicantportal/form/[page].test.tsx b/app/tests/pages/applicantportal/form/[page].test.tsx index 348953f10..ec69f96ec 100644 --- a/app/tests/pages/applicantportal/form/[page].test.tsx +++ b/app/tests/pages/applicantportal/form/[page].test.tsx @@ -59,6 +59,18 @@ const mockAcceptedZones: moduleApi.FeatureResult = { ruleId: 'intake_zones_json', }; +const mockAllZones: moduleApi.FeatureResult = { + 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({ pageComponent: FormPage, compiledQuery: compiledPageQuery, @@ -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' }, @@ -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(); + }); });