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

[MDS-5712] AMS Application Purpose #3036

Merged
merged 22 commits into from
Apr 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
f396c47
change around authorizations involved, convert to TS, fix some issues…
taraepp Mar 18, 2024
bbfa96e
add 'help' text to radio buttons, make authorizations form section mo…
taraepp Mar 20, 2024
48446c6
make field names closer to mappings, tooltip
taraepp Mar 22, 2024
5b42909
migration to separate out AMS amended authorizations into their own r…
taraepp Mar 25, 2024
f9c9d8b
update BE response to include new fields, format a bit differently wh…
taraepp Mar 27, 2024
eecfedf
fix issue with label and with radio buttons, process & validate on BE…
taraepp Apr 2, 2024
59828e6
move authorizations involved into common, put in CORE, change 'OTHER'…
taraepp Apr 3, 2024
5ccdda3
make a hidden field component to handle most of the redux-y stuff, up…
taraepp Apr 4, 2024
0ca8605
fix style issues on CORE
taraepp Apr 4, 2024
77355b8
fix issues with multiselect changing value onBlur, fix issues with sa…
taraepp Apr 4, 2024
101545d
add loading indicator on multiselect, remove console log, snaps
taraepp Apr 4, 2024
d843948
reverted changes to a method that's no longer being used
taraepp Apr 4, 2024
d4436a5
remove failing line from cypress test
taraepp Apr 4, 2024
a895ce5
fix indent error
taraepp Apr 4, 2024
7110897
fill in an authorization for cypress test
taraepp Apr 4, 2024
fd22d67
update snap
taraepp Apr 4, 2024
2956d5a
forgot to save change to data-cy before last commit
taraepp Apr 4, 2024
d2ce89d
fix snap again
taraepp Apr 4, 2024
99adad3
make required fields consistent and also don't show an empty item in …
taraepp Apr 4, 2024
c271966
missed change to cypress test
taraepp Apr 4, 2024
f5d3c27
rename migration for order, and update data with 'OTHER' type to use …
taraepp Apr 5, 2024
eb87872
fix validation method
taraepp Apr 5, 2024
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
87 changes: 87 additions & 0 deletions migrations/sql/V2024.03.23.1.46__ams_authorizations.sql
Original file line number Diff line number Diff line change
@@ -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
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nice work with the sql scrip here 👍

-- 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
$$
2 changes: 1 addition & 1 deletion services/common/src/components/common/Callout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<CallOutProps> = ({ message, title, severity = CALLOUT_SEVERITY.info }) => {
Expand Down
8 changes: 4 additions & 4 deletions services/common/src/components/forms/BaseInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,26 +100,26 @@ export const getFormItemLabel = (
}
if (isRequired) {
return (
<>
<div style={{ width: "100%" }}>
{label}
{labelSubtitle && (
<>
<br />
<span className="label-subtitle">{labelSubtitle}</span>
</>
)}
</>
</div>
);
}
return (
<>
<div>
{label} <span className="form-item-optional">&nbsp;(optional)</span>
{labelSubtitle && (
<>
<br />
<span className="label-subtitle">{labelSubtitle}</span>
</>
)}
</>
</div>
);
};
77 changes: 41 additions & 36 deletions services/common/src/components/forms/RenderGroupCheckbox.tsx
Original file line number Diff line number Diff line change
@@ -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 <Field />
* - 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<CheckboxProps> = ({
meta,
input,
label,
options,
required,
...props
}) => {
return (
<Form.Item
label={props.label}
validateStatus={props.meta.touched ? props.meta.error && "error" : ""}
name={input.name}
label={label}
required={required}
validateStatus={meta.touched ? meta.error && "error" : ""}
help={
meta.touched &&
((meta.error && <span>{meta.error}</span>) || (meta.warning && <span>{meta.warning}</span>))
}
getValueProps={() => ({ value: input.value })}
>
<Checkbox.Group
// apparently id & checked do not exist on Checkbox.Group
// id={props.id}
name={props.name}
// checked={props.input.value}
options={props.options}
name={input.name}
options={options}
disabled={props.disabled}
defaultValue={props.formValues[props.fieldName]}
value={
props.setInitialValues && !props.meta.dirty ? props.setInitialValues() : props.input.value
}
onChange={(values) => onChange(values, props.change, props.formName, props.fieldName)}
defaultValue={props.defaultValue}
{...input}
/>
</Form.Item>
);
};

RenderGroupCheckbox.propTypes = propTypes;

const mapDispatchToProps = (dispatch) => bindActionCreators({ change }, dispatch);
export default connect(null, mapDispatchToProps)(RenderGroupCheckbox);
export default RenderGroupCheckbox;
82 changes: 82 additions & 0 deletions services/common/src/components/forms/RenderHiddenField.tsx
Original file line number Diff line number Diff line change
@@ -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?
Copy link
Collaborator

Choose a reason for hiding this comment

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

😆 Love it. Reminds me of an infomercial. "Has this ever happened to you!?"

* 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 <Field /> instead,
- but there is a min-height on form-item that will have to be dealt with...

<Field
name="field_name"
component={RenderHiddenField}
required
validate={[required]}
label="Label"
>
<Checkbox
value
checked
onChange={(e) => dispatch(change(FORM_NAME, "field_name", ["5"]))}
>
Checkbox label
</Checkbox>
{whatever else is necessary to display}
</Field>
*/
const RenderHiddenField: FC<BaseInputProps> = ({
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 (
<Form.Item
className="form-item-hidden"
name={input.name}
required={required}
label={getFormItemLabel(label, required, labelSubtitle)}
validateStatus={touched ? (meta.error && "error") || (meta.warning && "warning") : ""}
help={
touched &&
((meta.error && <span>{meta.error}</span>) || (meta.warning && <span>{meta.warning}</span>))
}
>
<>
<div style={{ display: "none" }}>
<Input
disabled={disabled}
defaultValue={defaultValue}
name={input.name}
value={input.value}
/>
</div>
{children}
{help && <div className={`form-item-help ${input.name}-form-help`}>{help}</div>}
</>
</Form.Item>
);
};

export default RenderHiddenField;
6 changes: 3 additions & 3 deletions services/common/src/components/forms/RenderMultiSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ interface MultiSelectProps extends BaseInputProps {
data: IOption[];
filterOption?: any;
onSearch?: any;
loading?: boolean;
}

export const RenderMultiSelect: FC<MultiSelectProps> = (props) => {
Expand Down Expand Up @@ -50,6 +51,7 @@ export const RenderMultiSelect: FC<MultiSelectProps> = (props) => {
((meta.error && <span>{meta.error}</span>) ||
(meta.warning && <span>{meta.warning}</span>))
}
getValueProps={() => input.value !== "" && { value: input.value }}
>
<Select
loading={props.loading}
Expand All @@ -59,11 +61,9 @@ export const RenderMultiSelect: FC<MultiSelectProps> = (props) => {
mode="multiple"
size="small"
placeholder={placeholder}
{...input}
id={props.id}
id={props.id ?? props.input.name}
onSearch={onSearch}
options={data}
value={input.value ?? undefined}
onChange={input.onChange}
filterOption={filterOption || caseInsensitiveLabelFilter}
showArrow
Expand Down
23 changes: 14 additions & 9 deletions services/common/src/components/forms/RenderRadioButtons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const RenderRadioButtons: FC<RenderRadioButtonsProps> = ({
disabled = false,
input,
id,
help,
customOptions,
required = false,
optionType = "default",
Expand Down Expand Up @@ -47,15 +48,19 @@ const RenderRadioButtons: FC<RenderRadioButtonsProps> = ({
}
label={getFormItemLabel(label, required)}
>
<Radio.Group
disabled={disabled}
name={input.name}
onChange={handleRadioChange}
options={options}
optionType={optionType}
buttonStyle="solid"
{...(isVertical && { className: "vertical-radio-group" })}
/>
<>
<Radio.Group
disabled={disabled}
name={input.name}
value={input.value}
onChange={handleRadioChange}
options={options}
optionType={optionType}
buttonStyle="solid"
{...(isVertical && { className: "vertical-radio-group" })}
/>
{help && <div className={`form-item-help ${input.name}-form-help`}>{help}</div>}
</>
</Form.Item>
);
};
Expand Down
Loading
Loading