Skip to content

Commit

Permalink
Merge pull request #1211 from cityofaustin/14560-jc-atd-calculated-fi…
Browse files Browse the repository at this point in the history
…elds

Add `substantial_completion_date` to project and component views
  • Loading branch information
johnclary authored Jan 18, 2024
2 parents 7bda69f + 0e5e4f0 commit 1ff42b3
Show file tree
Hide file tree
Showing 22 changed files with 3,143 additions and 440 deletions.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
-- revert to 1697679713991_confirmed_date_trigger
CREATE OR REPLACE FUNCTION moped_proj_phases_confirmed_dates() RETURNS trigger
LANGUAGE plpgsql
AS $$
BEGIN
IF NEW.phase_start <= current_date AND NEW.is_phase_start_confirmed != TRUE THEN
new.is_phase_start_confirmed := true;
END IF;
IF NEW.phase_end <= current_date AND NEW.is_phase_end_confirmed != TRUE THEN
new.is_phase_end_confirmed := true;
END IF;
IF NEW.phase_start > current_date THEN
new.is_phase_start_confirmed := false;
END IF;
IF NEW.phase_end > current_date THEN
new.is_phase_end_confirmed := false;
END IF;
RETURN NEW;
END;
$$;

CREATE TRIGGER set_moped_proj_phases_confirmed_dates_trigger BEFORE INSERT OR UPDATE ON public.moped_proj_phases
FOR EACH ROW EXECUTE FUNCTION public.moped_proj_phases_confirmed_dates();
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
DROP TRIGGER set_moped_proj_phases_confirmed_dates_trigger ON public.moped_proj_phases;

DROP FUNCTION moped_proj_phases_confirmed_dates;
497 changes: 497 additions & 0 deletions moped-database/migrations/1704906960001_phase_timestamps/down.sql

Large diffs are not rendered by default.

500 changes: 500 additions & 0 deletions moped-database/migrations/1704906960001_phase_timestamps/up.sql

Large diffs are not rendered by default.

14 changes: 9 additions & 5 deletions moped-database/views/component_arcgis_online_view.sql
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
-- current version 1699891030861_change_contractor_column_name
-- current_version: 1704744986000_substantial_completion_date
DROP VIEW component_arcgis_online_view;

DROP VIEW IF EXISTS component_arcgis_online_view;
CREATE OR REPLACE VIEW component_arcgis_online_view AS (
SELECT
mpc.project_id,
Expand All @@ -22,7 +22,8 @@ CREATE OR REPLACE VIEW component_arcgis_online_view AS (
mpc.is_deleted is_project_component_deleted,
plv.is_deleted is_project_deleted,
mpc.interim_project_component_id,
mpc.completion_date,
mpc.completion_date,
COALESCE(mpc.completion_date, substantial_completion_date) as substantial_completion_date,
mpc.srts_id,
mpc.location_description,
plv.project_name,
Expand Down Expand Up @@ -173,7 +174,8 @@ CREATE OR REPLACE VIEW component_arcgis_online_view AS (
string_agg(ms.subcomponent_name, ', ') subcomponents
FROM
moped_proj_components_subcomponents mpcs
LEFT JOIN moped_subcomponents ms ON mpcs.subcomponent_id = ms.subcomponent_id
LEFT JOIN moped_subcomponents ms ON mpcs.subcomponent_id = ms.subcomponent_id
WHERE mpcs.is_deleted = FALSE
GROUP BY
project_component_id
) subcomponents ON subcomponents.project_component_id = mpc.project_component_id
Expand All @@ -185,6 +187,7 @@ CREATE OR REPLACE VIEW component_arcgis_online_view AS (
FROM
moped_proj_component_work_types mpcwt
LEFT JOIN moped_work_types mwt ON mpcwt.work_type_id = mwt.id
WHERE mpcwt.is_deleted = FALSE
GROUP BY
project_component_id
) work_types ON work_types.project_component_id = mpc.project_component_id
Expand All @@ -195,7 +198,8 @@ CREATE OR REPLACE VIEW component_arcgis_online_view AS (
string_agg(mct.type || ' - ' || mct.name, ', ') component_tags
FROM
moped_proj_component_tags mpct
LEFT JOIN moped_component_tags mct ON mpct.component_tag_id = mct.id
LEFT JOIN moped_component_tags mct ON mpct.component_tag_id = mct.id
WHERE mpct.is_deleted = FALSE
GROUP BY
project_component_id
) component_tags ON component_tags.project_component_id = mpc.project_component_id
Expand Down
35 changes: 34 additions & 1 deletion moped-database/views/project_list_view.sql
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
-- latest version 1700515730257_fix_delete_component_bug
-- latest version 1704744986000_substantial_completion_date
DROP VIEW project_list_view CASCADE;

CREATE OR REPLACE VIEW public.project_list_view
Expand Down Expand Up @@ -119,6 +119,39 @@ AS WITH project_person_list_lookup AS (
AND phases.phase_id = 11 -- phase_id 11 is complete
AND phases.is_deleted = false
) AS completion_end_date,
( -- get the earliest confirmed phase_start or phase_end with a simple phase of 'Complete'
SELECT
min(min_confirmed_date)
FROM (
-- earliest confirmed phase start
SELECT
min(phases.phase_start) AS min_confirmed_date
FROM
moped_proj_phases phases
LEFT JOIN moped_phases ON phases.phase_id = moped_phases.phase_id
WHERE
TRUE
AND phases.phase_start IS NOT NULL
AND phases.is_phase_start_confirmed = TRUE
AND phases.project_id = mp.project_id
AND moped_phases.phase_name_simple = 'Complete'
AND phases.is_deleted = FALSE
UNION ALL
-- earliest confirmed phase end
SELECT
min(phases.phase_end) AS min_confirmed_date
FROM
moped_proj_phases phases
LEFT JOIN moped_phases ON phases.phase_id = moped_phases.phase_id
WHERE
TRUE
AND phases.phase_end IS NOT NULL
AND phases.is_phase_end_confirmed = TRUE
AND phases.project_id = mp.project_id
AND moped_phases.phase_name_simple = 'Complete'
AND phases.is_deleted = FALSE
) min_confirmed_dates
) AS substantial_completion_date,
( -- get me a list of the inspectors for this project
SELECT string_agg(concat(users.first_name, ' ', users.last_name), ', '::text) AS string_agg
FROM moped_proj_personnel mpp
Expand Down
37 changes: 37 additions & 0 deletions moped-editor/src/components/forms/ControlledCheckbox.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import React from "react";
import Checkbox from "@mui/material/Checkbox";
import FormControlLabel from "@mui/material/FormControlLabel";
import { Controller } from "react-hook-form";

/**
* A react-hook-form wrapper of the MUI Checkbox component
* @param {object} control - react-hook-form `control` object from useController - required
* @param {string} name - unique field name which be used in react-hook-form data object
* @param {string} label - the label to render next to the checkbox
* @param {object} checkboxProps additional optional MUI checkbox props such as `sx` or `icon`
* @return {JSX.Element}
*/
const ControlledCheckbox = ({ name, control, label, ...checkBoxProps }) => {
return (
<Controller
name={name}
control={control}
render={({ field }) => {
return (
<FormControlLabel
label={label}
control={
<Checkbox
checked={!!field.value}
onChange={(e) => field.onChange(e.target.checked)}
{...checkBoxProps}
/>
}
/>
);
}}
/>
);
};

export default ControlledCheckbox;
79 changes: 79 additions & 0 deletions moped-editor/src/components/forms/ControlledDateField.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import React from "react";
import { DatePicker } from "@mui/x-date-pickers";
import { Controller } from "react-hook-form";

/**
* Test if an input is not null and can be coerced to a Date object.
* @param {any} value - any value, but in our case either a string, a Date object,
* an Invalid Date object, or null
* @returns true if the value is not null and can be coerced to a Date object
*/
const isValidDateStringOrObject = (value) => {
return value !== null && !isNaN(new Date(value));
};

/**
* A react-hook-form wrapper of the MUI DatePicker component.
* @param {object} control - react-hook-form `control` object from useController - required
* @param {string} name - unique field name which be used in react-hook-form data object
* @param {string} label - the label to render next to the checkbox
* @param {bool} error - if the error state is active (triggers red outline around textfield)
* @param {object} datePickerProps additional optional MUI date picker props
* @return {JSX.Element}
*/
const ControlledDateField = ({
name,
control,
label,
error,
...datePickerProps
}) => {
return (
<Controller
name={name}
control={control}
render={({ field }) => {
/**
* The MUI component requires a Date object as the input value.
* So we try to construct a Date object from the value in
* react-hook-form.
*
* Otherwise just pass whatever the value is in state
*/
let value = field.value;
if (isValidDateStringOrObject(value)) {
value = new Date(field.value);
}
return (
<DatePicker
size="small"
label={label}
slotProps={{
textField: { size: "small", error },
field: { clearable: true },
}}
value={value}
onChange={(newValue) => {
/**
* This component's value is a Date object or an Invalid Date object.
* If the date object is valid, we can convert it to an ISO string
* and store the string in react-hook-form state.
*
* If the date object is invalid, we store the invalid date in
* react-hook-form-state and let the Yup schema validation prevent
* form submit.
*/
const valueToStore = isValidDateStringOrObject(newValue)
? newValue.toISOString()
: newValue;
field.onChange(valueToStore);
}}
{...datePickerProps}
/>
);
}}
/>
);
};

export default ControlledDateField;
38 changes: 38 additions & 0 deletions moped-editor/src/components/forms/ControlledSwitch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import Switch from "@mui/material/Switch";
import { Controller } from "react-hook-form";
import FormControlLabel from "@mui/material/FormControlLabel";

/**
* A react-hook-form wrapper of the MUI Switch component
* @param {object} control - react-hook-form `control` object from useController - required
* @param {string} name - unique field name which be used in react-hook-form data object
* @param {string} label - the label to render next to the checkbox
* @param {object} switchProps additional optional MUI switch props
* @return {JSX.Element}
*/
const ControlledSwitch = ({ name, control, label, ...switchProps }) => {
return (
<Controller
name={name}
control={control}
render={({ field }) => {
return (
<FormControlLabel
label={label}
control={
<Switch
checked={!!field.value}
onChange={(e) => field.onChange(e.target.checked)}
color="primary"
inputProps={{ "aria-label": "primary checkbox" }}
{...switchProps}
/>
}
/>
);
}}
/>
);
};

export default ControlledSwitch;
Loading

0 comments on commit 1ff42b3

Please sign in to comment.