Skip to content

Commit

Permalink
Settings: Metric Configuration: Refactor & Clean Up (5/n) (#91)
Browse files Browse the repository at this point in the history
* Major clean up - separate components into their own files

* Fix dimension bug

* Fix switch agency bug

* Minor clean up

* Merge types with existing types and update all connected components

* Clean up

* Handle cases when settings array is empty or non-existent

* Handle cases when settings array is empty or non-existent

* Styling adjustments per prev feedback

* Recreate MetricsView Component for Data Visualization (#101)

* Recreate old MetricsView component
Update route and add to menu
Update styling
Remove unnecessary code - minor refactor
Clean up

* Fix styling issue

* Add spacing between header and data viz

* Add border top to data viz dropdown

* Update tooltip and link to direct users to Settings to change metric config

Co-authored-by: Mahmoud <mahmoud@Mahmouds-MBP.cable.rcn.com>

Co-authored-by: Mahmoud <mahmoud@Mahmouds-MBP.cable.rcn.com>
  • Loading branch information
mxosman and Mahmoud committed Oct 20, 2022
1 parent 41a1e29 commit be2d044
Show file tree
Hide file tree
Showing 16 changed files with 946 additions and 584 deletions.
2 changes: 2 additions & 0 deletions publisher/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { trackNavigation } from "./analytics";
import { DataUpload } from "./components/DataUpload";
import { PageWrapper } from "./components/Forms";
import Header from "./components/Header";
import { MetricsView } from "./components/MetricConfiguration/MetricsView";
import CreateReports from "./components/Reports/CreateReport";
import ReportDataEntry from "./components/Reports/ReportDataEntry";
import ReviewMetrics from "./components/ReviewMetrics/ReviewMetrics";
Expand All @@ -42,6 +43,7 @@ const App: React.FC = (): ReactElement => {

<Routes>
<Route path="/" element={<Reports />} />
<Route path="/data" element={<MetricsView />} />
<Route path="/reports/create" element={<CreateReports />} />
<Route path="/reports/:id" element={<ReportDataEntry />} />
<Route path="/settings" element={<Settings />} />
Expand Down
1 change: 1 addition & 0 deletions publisher/src/components/DataViz/DatapointsView.styles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export const DatapointsViewControlsContainer = styled.div`
display: flex;
flex-direction: row;
border-bottom: 1px solid ${palette.highlight.grey9};
border-top: 1px solid ${palette.highlight.grey9};
`;

const DatapointsViewDropdown = styled(Dropdown)`
Expand Down
4 changes: 2 additions & 2 deletions publisher/src/components/Forms/NotReportedIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,8 @@ export const NotReportedIcon: React.FC<{
This has been disabled by an admin because the data is unavailable.{" "}
If you have the data for this, consider changing the configuration
in the{" "}
<MetricsViewLink onClick={() => navigate("/metrics")}>
Metrics View
<MetricsViewLink onClick={() => navigate("/settings")}>
Settings
</MetricsViewLink>
.
</NotReportedIconTooltip>
Expand Down
11 changes: 11 additions & 0 deletions publisher/src/components/Menu/Menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ enum MenuItems {
LearnMore = "LEARN MORE",
Settings = "SETTINGS",
Agencies = "AGENCIES",
Data = "DATA",
}

const Menu = () => {
Expand Down Expand Up @@ -76,6 +77,8 @@ const Menu = () => {
setActiveMenuItem(MenuItems.CreateReport);
} else if (location.pathname === "/settings") {
setActiveMenuItem(MenuItems.Settings);
} else if (location.pathname === "/data") {
setActiveMenuItem(MenuItems.Data);
} else {
setActiveMenuItem(undefined);
}
Expand All @@ -97,6 +100,14 @@ const Menu = () => {
Reports
</MenuItem>

{/* Data (Visualizations) */}
<MenuItem
onClick={() => navigate("/data")}
active={activeMenuItem === MenuItems.Data}
>
Data
</MenuItem>

{/* Learn More */}
<MenuItem active={activeMenuItem === MenuItems.LearnMore}>
<a
Expand Down
257 changes: 257 additions & 0 deletions publisher/src/components/MetricConfiguration/Configuration.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,257 @@
// Recidiviz - a data platform for criminal justice reform
// Copyright (C) 2022 Recidiviz, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// =============================================================================

import React, { useEffect, useState } from "react";

import { Metric, MetricDisaggregationDimensions } from "../../shared/types";
import { removeSnakeCase } from "../../utils";
import blueCheck from "../assets/status-check-icon.png";
import { BinaryRadioButton } from "../Forms";
import { TabbedBar, TabbedItem, TabbedOptions } from "../Reports";
import {
BlueCheckIcon,
BreakdownHeader,
Checkbox,
CheckboxWrapper,
Dimension,
DimensionTitle,
DimensionTitleWrapper,
Disaggregation,
DisaggregationTab,
Header,
MetricConfigurationContainer,
MetricDisaggregations,
MetricOnOffWrapper,
MetricSettings,
RadioButtonGroupWrapper,
Subheader,
} from ".";

type MetricConfigurationProps = {
activeMetricKey: string;
filteredMetricSettings: { [key: string]: Metric };
saveAndUpdateMetricSettings: (
typeOfUpdate: "METRIC" | "DISAGGREGATION" | "DIMENSION" | "CONTEXT",
updatedSetting: MetricSettings,
debounce?: boolean
) => void;
setActiveDimension: React.Dispatch<
React.SetStateAction<MetricDisaggregationDimensions | undefined>
>;
};

export const Configuration: React.FC<MetricConfigurationProps> = ({
activeMetricKey,
filteredMetricSettings,
saveAndUpdateMetricSettings,
setActiveDimension,
}): JSX.Element => {
const [activeDisaggregation, setActiveDisaggregation] = useState(
filteredMetricSettings[activeMetricKey]?.disaggregations?.[0]
);
const metricDisplayName =
filteredMetricSettings[activeMetricKey]?.display_name;
const metricEnabled = Boolean(
filteredMetricSettings[activeMetricKey]?.enabled
);

useEffect(
() => {
const updatedDisaggregation =
activeDisaggregation &&
filteredMetricSettings[activeMetricKey]?.disaggregations?.find(
(disaggregation) => disaggregation.key === activeDisaggregation.key
);

if (updatedDisaggregation)
return setActiveDisaggregation(updatedDisaggregation);
setActiveDisaggregation(
filteredMetricSettings[activeMetricKey]?.disaggregations?.[0]
);
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[filteredMetricSettings]
);

useEffect(
() => setActiveDimension(undefined),
// eslint-disable-next-line react-hooks/exhaustive-deps
[activeMetricKey]
);

return (
<MetricConfigurationContainer>
<MetricOnOffWrapper>
<Header>
Are you currently able to report any part of this metric?
</Header>
<Subheader>
Answering “No” means that {metricDisplayName} will not appear on
automatically generated reports from here on out. You can change this
later.
</Subheader>
<RadioButtonGroupWrapper>
<BinaryRadioButton
type="radio"
id="yes"
name="metric-config"
label="Yes"
value="yes"
checked={metricEnabled}
onChange={() =>
saveAndUpdateMetricSettings("METRIC", {
key: activeMetricKey,
enabled: true,
})
}
/>
<BinaryRadioButton
type="radio"
id="no"
name="metric-config"
label="No"
value="no"
checked={!metricEnabled}
onChange={() =>
saveAndUpdateMetricSettings("METRIC", {
key: activeMetricKey,
enabled: false,
})
}
/>
</RadioButtonGroupWrapper>
</MetricOnOffWrapper>

{filteredMetricSettings[activeMetricKey]?.disaggregations.length > 0 && (
<MetricDisaggregations enabled={metricEnabled}>
<BreakdownHeader>Breakdowns</BreakdownHeader>
<Subheader>
Mark (using the checkmark) each of the breakdowns below that your
agency will be able to report. Click the arrow to edit the
definition for each metric.
</Subheader>

<TabbedBar noPadding>
<TabbedOptions>
{activeDisaggregation &&
filteredMetricSettings[activeMetricKey]?.disaggregations?.map(
(disaggregation) => (
<TabbedItem
key={disaggregation.key}
onClick={() => {
setActiveDimension(disaggregation.dimensions[0]);
setActiveDisaggregation(disaggregation);
}}
selected={disaggregation.key === activeDisaggregation.key}
capitalize
>
<DisaggregationTab>
<span>
{removeSnakeCase(
disaggregation.display_name.toLowerCase()
)}
</span>

<CheckboxWrapper>
<Checkbox
type="checkbox"
checked={disaggregation.enabled}
onChange={() =>
saveAndUpdateMetricSettings("DISAGGREGATION", {
key: activeMetricKey,
disaggregations: [
{
key: disaggregation.key,
enabled: !disaggregation.enabled,
},
],
})
}
/>
<BlueCheckIcon
src={blueCheck}
alt=""
enabled={disaggregation.enabled}
/>
</CheckboxWrapper>
</DisaggregationTab>
</TabbedItem>
)
)}
</TabbedOptions>
</TabbedBar>

<Disaggregation>
{activeDisaggregation?.dimensions.map((dimension) => {
return (
<Dimension
key={dimension.key}
enabled={!metricEnabled || activeDisaggregation.enabled}
onClick={() => setActiveDimension(dimension)}
>
<CheckboxWrapper>
<Checkbox
type="checkbox"
checked={
activeDisaggregation.enabled && dimension.enabled
}
onChange={() => {
if (activeDisaggregation.enabled) {
saveAndUpdateMetricSettings("DIMENSION", {
key: activeMetricKey,
disaggregations: [
{
key: activeDisaggregation.key,
dimensions: [
{
key: dimension.key,
enabled: !dimension.enabled,
},
],
},
],
});
}
}}
/>
<BlueCheckIcon
src={blueCheck}
alt=""
enabled={
activeDisaggregation.enabled && dimension.enabled
}
/>
</CheckboxWrapper>

<DimensionTitleWrapper>
<DimensionTitle
enabled={
activeDisaggregation.enabled && dimension.enabled
}
>
{dimension.label}
</DimensionTitle>
</DimensionTitleWrapper>
</Dimension>
);
})}
</Disaggregation>
</MetricDisaggregations>
)}
</MetricConfigurationContainer>
);
};
Loading

0 comments on commit be2d044

Please sign in to comment.