From cfd7eff6e6b7c7062594993fcdb258c5bdc33e2b Mon Sep 17 00:00:00 2001 From: Tara Epp <102187683+taraepp@users.noreply.github.com> Date: Fri, 5 Apr 2024 12:31:44 -0600 Subject: [PATCH] [MDS-5712] AMS Application Purpose (#3036) * change around authorizations involved, convert to TS, fix some issues in Callout, GroupCheckbox * add 'help' text to radio buttons, make authorizations form section mostly match mockup * make field names closer to mappings, tooltip * migration to separate out AMS amended authorizations into their own rows, add new columns * update BE response to include new fields, format a bit differently when received on the FE, and update the form accordingly. Fix some validation, radio button, checkbox label that is a form section issues * fix issue with label and with radio buttons, process & validate on BE, transform payload on FE * move authorizations involved into common, put in CORE, change 'OTHER' and 'MINES ACT PERMIT' UI according to AC/mockups, make the list of checkboxes be validated * make a hidden field component to handle most of the redux-y stuff, update authorization interface, update data mocks * fix style issues on CORE * fix issues with multiselect changing value onBlur, fix issues with saving on CORE, and bug on new records * add loading indicator on multiselect, remove console log, snaps * remove failing line from cypress test * fill in an authorization for cypress test * make required fields consistent and also don't show an empty item in multiselect * rename migration for order, and update data with 'OTHER' type to use authorization description --- .../V2024.03.23.1.46__ams_authorizations.sql | 87 + .../common/src/components/common/Callout.tsx | 2 +- .../common/src/components/forms/BaseInput.tsx | 8 +- .../components/forms/RenderGroupCheckbox.tsx | 77 +- .../components/forms/RenderHiddenField.tsx | 82 + .../components/forms/RenderMultiSelect.tsx | 6 +- .../components/forms/RenderRadioButtons.tsx | 23 +- .../AuthorizationsInvolved.spec.tsx | 39 + .../projectSummary/AuthorizationsInvolved.tsx | 477 +++ .../AuthorizationsInvolved.spec.tsx.snap | 2580 +++++++++++++++++ .../BasicInformation.spec.tsx.snap | 50 +- .../ReportDetailsForm-edit.spec.tsx.snap | 76 +- .../ReportDetailsForm-view.spec.tsx.snap | 16 +- .../projectSummaryAuthorizations.interface.ts | 6 + .../src/redux/selectors/projectSelectors.ts | 57 +- services/common/src/redux/utils/Validate.ts | 4 + services/common/src/tests/mocks/dataMocks.tsx | 109 +- .../project_summary/models/project_summary.py | 105 +- .../models/project_summary_authorization.py | 173 +- .../project_summary_authorization_type.py | 5 + .../resources/project_summary.py | 2 + .../resources/project_summary_list.py | 4 +- .../app/api/projects/response_models.py | 8 +- .../core-web/cypress/e2e/createproject.cy.ts | 7 +- .../projectSummaries/ProjectSummaryForm.tsx | 175 +- .../mine/Projects/ProjectSummary.tsx | 74 +- .../core-web/src/styles/components/Forms.scss | 10 +- .../src/styles/settings/themeOverride.scss | 4 + .../ProjectSummaryForm.spec.tsx.snap | 194 +- .../ReportPage-prr.spec.tsx.snap | 16 +- .../__snapshots__/ReportPage.spec.tsx.snap | 16 +- .../RequestReportForm.spec.tsx.snap | 18 +- .../projects/projectSummary/Applicant.tsx | 12 +- .../projectSummary/AuthorizationsInvolved.js | 198 -- .../projectSummary/ProjectSummaryForm.tsx | 8 +- .../pages/Project/ProjectSummaryPage.tsx | 71 +- .../src/styles/components/Forms.scss | 4 +- .../src/styles/generic/layout.scss | 5 + .../AuthorizationsInvolved.spec.js | 28 - .../AuthorizationsInvolved.spec.js.snap | 73 - 40 files changed, 4074 insertions(+), 835 deletions(-) create mode 100644 migrations/sql/V2024.03.23.1.46__ams_authorizations.sql create mode 100644 services/common/src/components/forms/RenderHiddenField.tsx create mode 100644 services/common/src/components/projectSummary/AuthorizationsInvolved.spec.tsx create mode 100644 services/common/src/components/projectSummary/AuthorizationsInvolved.tsx create mode 100644 services/common/src/components/projectSummary/__snapshots__/AuthorizationsInvolved.spec.tsx.snap delete mode 100644 services/minespace-web/src/components/Forms/projects/projectSummary/AuthorizationsInvolved.js delete mode 100644 services/minespace-web/src/tests/components/Forms/projects/projectSummary/AuthorizationsInvolved.spec.js delete mode 100644 services/minespace-web/src/tests/components/Forms/projects/projectSummary/__snapshots__/AuthorizationsInvolved.spec.js.snap diff --git a/migrations/sql/V2024.03.23.1.46__ams_authorizations.sql b/migrations/sql/V2024.03.23.1.46__ams_authorizations.sql new file mode 100644 index 0000000000..39c2b6794b --- /dev/null +++ b/migrations/sql/V2024.03.23.1.46__ams_authorizations.sql @@ -0,0 +1,87 @@ +ALTER TABLE project_summary_authorization + ADD COLUMN IF NOT EXISTS amendment_changes text[], -- array of change types + ADD COLUMN IF NOT EXISTS amendment_severity varchar(3), -- SIG or MIN + ADD COLUMN IF NOT EXISTS is_contaminated boolean, + ADD COLUMN IF NOT EXISTS new_type varchar(3), -- permit | approval + ADD COLUMN IF NOT EXISTS authorization_description varchar(4000), + ADD COLUMN IF NOT EXISTS exemption_requested boolean, + ALTER COLUMN existing_permits_authorizations SET DEFAULT array[]::text[], + ALTER COLUMN existing_permits_authorizations DROP NOT NULL + ; + +UPDATE project_summary_authorization + SET authorization_description = array_to_string(existing_permits_authorizations, ',') + WHERE project_summary_authorization_type = 'OTHER'; + +DO +$$ +DECLARE + authorization record; + auth_no text; + auth_array text[]; + i integer; + n integer; + + other_types text[]; + type_count integer; + delete_guids uuid[]; +BEGIN + -- target authorizations with multiple auth # amendments related to EMA + FOR authorization IN SELECT * FROM project_summary_authorization + WHERE 'AMENDMENT'=ANY(project_summary_permit_type) + AND cardinality(existing_permits_authorizations) > 1 + AND project_summary_authorization_type IN( + SELECT project_summary_authorization_type FROM project_summary_authorization_type + WHERE project_summary_authorization_type_group_id = 'ENVIRONMENTAL_MANAGMENT_ACT') + LOOP + -- create a record for each auth no + i := 1; + n := cardinality("authorization"."existing_permits_authorizations"); + auth_array := "authorization"."existing_permits_authorizations"; + + type_count := cardinality("authorization"."project_summary_permit_type"); + IF type_count = 1 THEN + delete_guids := delete_guids || "authorization"."project_summary_authorization_guid"; + ELSE + other_types := array_remove("authorization"."project_summary_permit_type", 'AMENDMENT'); + UPDATE project_summary_authorization + SET project_summary_permit_type = other_types, existing_permits_authorizations = ARRAY[]::text[] + WHERE project_summary_authorization_guid = "authorization"."project_summary_authorization_guid"; + END IF; + + LOOP + auth_no := TRIM(auth_array[i]); + IF auth_no != '' THEN + INSERT INTO project_summary_authorization ( + project_summary_guid, + project_summary_authorization_type, + project_summary_permit_type, + existing_permits_authorizations, + deleted_ind, + create_user, + create_timestamp, + update_user, + update_timestamp + ) VALUES ( + "authorization"."project_summary_guid", + "authorization"."project_summary_authorization_type", + '{"AMENDMENT"}', + ARRAY [auth_no], + "authorization"."deleted_ind", + "authorization"."create_user", + "authorization"."create_timestamp", + "authorization"."update_user", + "authorization"."update_timestamp" + ); + END IF; + + i := i + 1; + EXIT WHEN i > n; + + END LOOP; + END LOOP; + + DELETE FROM project_summary_authorization + WHERE project_summary_authorization.project_summary_authorization_guid =ANY(delete_guids); +END +$$ \ No newline at end of file diff --git a/services/common/src/components/common/Callout.tsx b/services/common/src/components/common/Callout.tsx index 37bcd77e7c..08c16dc51c 100644 --- a/services/common/src/components/common/Callout.tsx +++ b/services/common/src/components/common/Callout.tsx @@ -5,7 +5,7 @@ import { CALLOUT_SEVERITY } from "@mds/common/constants/strings"; interface CallOutProps { message: string | ReactNode; title?: string; - severity: string; + severity?: string; } const Callout: FC = ({ message, title, severity = CALLOUT_SEVERITY.info }) => { diff --git a/services/common/src/components/forms/BaseInput.tsx b/services/common/src/components/forms/BaseInput.tsx index f22d9628e5..5f0c485991 100644 --- a/services/common/src/components/forms/BaseInput.tsx +++ b/services/common/src/components/forms/BaseInput.tsx @@ -100,7 +100,7 @@ export const getFormItemLabel = ( } if (isRequired) { return ( - <> +
{label} {labelSubtitle && ( <> @@ -108,11 +108,11 @@ export const getFormItemLabel = ( {labelSubtitle} )} - +
); } return ( - <> +
{label}  (optional) {labelSubtitle && ( <> @@ -120,6 +120,6 @@ export const getFormItemLabel = ( {labelSubtitle} )} - +
); }; diff --git a/services/common/src/components/forms/RenderGroupCheckbox.tsx b/services/common/src/components/forms/RenderGroupCheckbox.tsx index fa222c5177..b5508a816d 100644 --- a/services/common/src/components/forms/RenderGroupCheckbox.tsx +++ b/services/common/src/components/forms/RenderGroupCheckbox.tsx @@ -1,54 +1,59 @@ -import React from "react"; -import PropTypes from "prop-types"; -import { change } from "redux-form"; -import { connect } from "react-redux"; -import { bindActionCreators } from "redux"; +import React, { FC } from "react"; import { Checkbox, Form } from "antd"; +import { BaseInputProps } from "./BaseInput"; /** * @constant RenderGroupCheckbox - Ant Design `Checkbox` component for redux-form. + * NOTE ABOUT A REDUX BUG AFFECTING THIS COMPONENT: + * Exactly what's happening here: https://github.com/redux-form/redux-form/issues/2768 + * - When onBlur is called, it calls onChange to update the value + * - but with a group checkbox, it does it with the value of the individual checkbox, + * - not with the value of the group + * - so it will call onChange(true | false) instead of onChange(["val1", "val2"]) + * - which causes an error. + * - And event.preventDefault() on the onBlur also prevents validation + * - The best and easiest solution I found was to put a normalize function on the + * - to not update the value if it's not an array (normalize gets called first) + * - It is exported here as normalizeGroupCheckBox */ -const propTypes = { - id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired, - label: PropTypes.string.isRequired, - meta: PropTypes.objectOf(PropTypes.any).isRequired, - input: PropTypes.objectOf(PropTypes.string).isRequired, - disabled: PropTypes.bool.isRequired, - options: PropTypes.arrayOf(PropTypes.objectOf(PropTypes.string)).isRequired, - change: PropTypes.func.isRequired, - name: PropTypes.string.isRequired, - setInitialValues: PropTypes.func, -}; +interface CheckboxProps extends BaseInputProps { + label: string; + options: any; + defaultValue: any[]; +} -const onChange = (checkedValues, change, form, name) => { - change(form, name, checkedValues); -}; +export const normalizeGroupCheckBox = (val, prev) => (Array.isArray(val) ? val : prev); -const RenderGroupCheckbox = (props) => { +const RenderGroupCheckbox: FC = ({ + meta, + input, + label, + options, + required, + ...props +}) => { return ( {meta.error}) || (meta.warning && {meta.warning})) + } + getValueProps={() => ({ value: input.value })} > onChange(values, props.change, props.formName, props.fieldName)} + defaultValue={props.defaultValue} + {...input} /> ); }; -RenderGroupCheckbox.propTypes = propTypes; - -const mapDispatchToProps = (dispatch) => bindActionCreators({ change }, dispatch); -export default connect(null, mapDispatchToProps)(RenderGroupCheckbox); +export default RenderGroupCheckbox; diff --git a/services/common/src/components/forms/RenderHiddenField.tsx b/services/common/src/components/forms/RenderHiddenField.tsx new file mode 100644 index 0000000000..6363c0ba60 --- /dev/null +++ b/services/common/src/components/forms/RenderHiddenField.tsx @@ -0,0 +1,82 @@ +import React, { FC, useState, useEffect } from "react"; +import { Input, Form } from "antd"; +import { BaseInputProps, getFormItemLabel } from "./BaseInput"; + +/** + * Just can't conform the UI to play nice with redux-form? + * This will display the label and handle validation on change and submit + * Can handle string, number, string[] values, can probably use normalize on Field to coerce + + USAGE + - the main thing to note is that you should be handling the redux change to update the value + - making the "actual" input the children will put help/validation messages at the bottom + - if this is not desired, put underneath instead, + - but there is a min-height on form-item that will have to be dealt with... + + + dispatch(change(FORM_NAME, "field_name", ["5"]))} + > + Checkbox label + + {whatever else is necessary to display} + + */ +const RenderHiddenField: FC = ({ + label, + labelSubtitle, + help, + meta, + input, + disabled, + required, + defaultValue, + children, +}) => { + const [touched, setTouched] = useState(meta.touched); + + useEffect(() => { + // dirty catches when the value is set & cleared, + // touched should catch when it's submitted + if (meta.dirty || meta.touched) { + setTouched(true); + } + }, [meta.dirty, meta.touched]); + + return ( + {meta.error}) || (meta.warning && {meta.warning})) + } + > + <> +
+ +
+ {children} + {help &&
{help}
} + +
+ ); +}; + +export default RenderHiddenField; diff --git a/services/common/src/components/forms/RenderMultiSelect.tsx b/services/common/src/components/forms/RenderMultiSelect.tsx index 15b41e840f..f1864a8ddf 100644 --- a/services/common/src/components/forms/RenderMultiSelect.tsx +++ b/services/common/src/components/forms/RenderMultiSelect.tsx @@ -13,6 +13,7 @@ interface MultiSelectProps extends BaseInputProps { data: IOption[]; filterOption?: any; onSearch?: any; + loading?: boolean; } export const RenderMultiSelect: FC = (props) => { @@ -50,6 +51,7 @@ export const RenderMultiSelect: FC = (props) => { ((meta.error && {meta.error}) || (meta.warning && {meta.warning})) } + getValueProps={() => input.value !== "" && { value: input.value }} > + +
+
+
+ Mines Act +
+
+
+
+ + +
+
+
+
+ +
+
+
+
+
+ + + + + +
+
+
+
+ +
+
+
+
+
+
+
+ +
+
+
+
+ +
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+ Environmental Management Act +
+
+
+
+ +
+
+
+ +
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+ +
+
+
+
+
+
+ +
+
+
+ +
+
+
+
+
+ + +
+
+
+
+ +
+
+
+
+
+
+
+
+ +
+
+
+
+
+ + +
+
+
+
+ +
+
+
+
+
+
+ +
+
+
+
+ +
+ + Maximum 4000 characters + + + 3978 / 4000 + +
+
+
+
+ +
+
+
+
+
+
+ +
+
+
+
+
+ + +
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+ Water Sustainability Act +
+
+
+
+ +
+
+
+
+
+
+ +
+
+
+
+
+
+ +
+
+
+
+ +
+
+
+
+
+ + + + + +
+
+
+
+ +
+
+
+
+
+
+ +
+
+
+
+ +
+ Please separate each permit with a comma +
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+ Forestry Act +
+
+
+
+ +
+
+
+
+ +
+
+
+
+
+ + + + + +
+
+
+
+ +
+
+
+
+
+
+ +
+
+
+
+ +
+ Please separate each permit with a comma +
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+ Other legislation +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+ + Maximum 100 characters + + + 75 / 100 + +
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+ +
+`; diff --git a/services/common/src/components/projectSummary/__snapshots__/BasicInformation.spec.tsx.snap b/services/common/src/components/projectSummary/__snapshots__/BasicInformation.spec.tsx.snap index 2249ed41c2..2c2bd75f87 100644 --- a/services/common/src/components/projectSummary/__snapshots__/BasicInformation.spec.tsx.snap +++ b/services/common/src/components/projectSummary/__snapshots__/BasicInformation.spec.tsx.snap @@ -25,7 +25,11 @@ exports[`BasicInformation renders properly 1`] = ` for="ADD_EDIT_PROJECT_SUMMARY_project_summary_title" title="" > - Project title +
+ Project title +
- Proponent project tracking ID - - -  (optional) - -
- - If your company uses a tracking number to identify projects, please provide it here. - +
+ Proponent project tracking ID + + +  (optional) + +
+ + If your company uses a tracking number to identify projects, please provide it here. + +
- Project overview -
- - Provide a 2-3 paragraph high-level description of your proposed project. - + Project overview +
+ + Provide a 2-3 paragraph high-level description of your proposed project. + +
- Who is the report for? +
+ Who is the report for? +
- Report Compliance Year/Period +
+ Report Compliance Year/Period +
- Due Date +
+ Due Date +
- Submitter Name - - -  (optional) - +
+ Submitter Name + + +  (optional) + +
- Submitter Email - - -  (optional) - +
+ Submitter Email + + +  (optional) + +
- Who is the report for? +
+ Who is the report for? +