Skip to content

Commit

Permalink
Race & Ethnicity: UI Scaffolding (1/2) (#142)
Browse files Browse the repository at this point in the history
* Initial work on the race and ethnicity component

* Clean up race ethnicities - breakout components

* Clean up

* Styling adjustment

* Adjust copy and styling

* Feedback: change file and component names, update imports, change ethnicity cell var name

* Race & Ethnicity: Logic & Functionality (2/2) (#143)

* Initial work on logic - implementing brute force working approach

Fix out of sync bug when disaggregation is off

Continue work on logic, update types, extract grid states into own helper file, clean up, add comments

Continue work on logic, fix bugs and strange behavior, clean up

Clean up for clarity

Add turning off disaggregation indicator edge case in updateRaceDimensions function, add race and ethnicities disaggregation key constant, clean up, manual test

Random fixes

More out-of-sync bug fixes

Clean up

Update file names, etc to ease rebase

Adjustments for new dimension keys

Feedback: turn ethnicitiesByRace into computed value - remove all unnecessary state, clean up

Update name of state1, state2, state3 - update comment

Remember disabled dimensions during state switches - clean up - still need to fix a state switch bug

More clean up

Fix and adjust behavior of switching states and special cases

Fix side effect when disaggregation is off and user clicks on Yes for specifying ethnicity

General clean up, add comments

More clean up

* Remove split logic and replace with new dimension props, update metadata logic to include new dimension props, Update common type, local types and dependencies

* common types

* Fix bug not saving the unknown race dimension and switching grid states

Co-authored-by: Mahmoud <[email protected]>

Co-authored-by: Mahmoud <[email protected]>
  • Loading branch information
mxosman and Mahmoud authored Nov 16, 2022
1 parent 4f05579 commit 000fe2a
Show file tree
Hide file tree
Showing 12 changed files with 988 additions and 67 deletions.
2 changes: 2 additions & 0 deletions common/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,8 @@ export interface MetricDisaggregationDimensions {
enabled?: boolean;
settings?: MetricConfigurationSettings[];
display_name?: string;
race?: string;
ethnicity?: string;
}

export interface CreateReportFormValuesType extends Record<string, unknown> {
Expand Down
122 changes: 65 additions & 57 deletions publisher/src/components/MetricConfiguration/Configuration.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ import {
MetricConfigurationContainer,
MetricDisaggregations,
MetricOnOffWrapper,
RACE_ETHNICITY_DISAGGREGATION_KEY,
RaceEthnicitiesGrid,
RadioButtonGroupWrapper,
Subheader,
} from ".";
Expand Down Expand Up @@ -160,7 +162,7 @@ export const Configuration: React.FC<MetricConfigurationProps> = observer(
<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.
definition for each breakdown.
</Subheader>

{/* Disaggregations (Enable/Disable) */}
Expand Down Expand Up @@ -226,66 +228,72 @@ export const Configuration: React.FC<MetricConfigurationProps> = observer(

<Disaggregation>
{/* Dimension Fields (Enable/Disable) */}
{activeDimensionKeys?.map((dimensionKey) => {
const currentDisaggregation =
disaggregations[systemMetricKey][activeDisaggregationKey];
const currentDimension =
dimensions[systemMetricKey][activeDisaggregationKey][
dimensionKey
];
{/* Race & Ethnicities Grid (when active disaggregation is Race / Ethnicity) */}
{activeDisaggregationKey === RACE_ETHNICITY_DISAGGREGATION_KEY ? (
<RaceEthnicitiesGrid />
) : (
activeDimensionKeys?.map((dimensionKey) => {
const currentDisaggregation =
disaggregations[systemMetricKey][activeDisaggregationKey];
const currentDimension =
dimensions[systemMetricKey][activeDisaggregationKey][
dimensionKey
];

return (
<Dimension
key={dimensionKey}
enabled={!metricEnabled || currentDisaggregation.enabled}
inView={dimensionKey === activeDimensionKey}
onClick={() => setActiveDimensionKey(dimensionKey)}
>
<CheckboxWrapper>
<Checkbox
type="checkbox"
checked={
currentDisaggregation.enabled &&
currentDimension.enabled
}
onChange={() => {
if (activeSystem && activeMetricKey) {
const updatedSetting = updateDimensionEnabledStatus(
activeSystem,
activeMetricKey,
activeDisaggregationKey,
dimensionKey,
!currentDimension.enabled
);
saveMetricSettings(updatedSetting);
return (
<Dimension
key={dimensionKey}
enabled={!metricEnabled || currentDisaggregation.enabled}
inView={dimensionKey === activeDimensionKey}
onClick={() => setActiveDimensionKey(dimensionKey)}
>
<CheckboxWrapper>
<Checkbox
type="checkbox"
checked={
currentDisaggregation.enabled &&
currentDimension.enabled
}
}}
/>
<BlueCheckIcon
src={blueCheck}
alt=""
enabled={
currentDisaggregation.enabled &&
currentDimension.enabled
}
/>
</CheckboxWrapper>
onChange={() => {
if (activeSystem && activeMetricKey) {
const updatedSetting =
updateDimensionEnabledStatus(
activeSystem,
activeMetricKey,
activeDisaggregationKey,
dimensionKey,
!currentDimension.enabled
);
saveMetricSettings(updatedSetting);
}
}}
/>
<BlueCheckIcon
src={blueCheck}
alt=""
enabled={
currentDisaggregation.enabled &&
currentDimension.enabled
}
/>
</CheckboxWrapper>

<DimensionTitleWrapper>
<DimensionTitle
enabled={
currentDisaggregation.enabled &&
currentDimension.enabled
}
>
{currentDimension.label}
</DimensionTitle>
<DimensionTitleWrapper>
<DimensionTitle
enabled={
currentDisaggregation.enabled &&
currentDimension.enabled
}
>
{currentDimension.label}
</DimensionTitle>

<RightArrowIcon />
</DimensionTitleWrapper>
</Dimension>
);
})}
<RightArrowIcon />
</DimensionTitleWrapper>
</Dimension>
);
})
)}
</Disaggregation>
</MetricDisaggregations>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -607,6 +607,7 @@ export const DefinitionMiniButton = styled(RevertToDefaultButton)<{
showDefault?: boolean;
}>`
width: unset;
min-width: 60px;
padding: 9px 16px;
transition: color 0.2s ease;
Expand All @@ -621,7 +622,7 @@ export const DefinitionMiniButton = styled(RevertToDefaultButton)<{
opacity: 0.9;
}
&:nth-child(3) {
&:last-child {
background: ${palette.solid.blue};
&:hover {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ import {
MetricName,
MetricsViewContainer,
MetricsViewControlPanel,
RACE_ETHNICITY_DISAGGREGATION_KEY,
RaceEthnicitiesForm,
StickyHeader,
} from ".";

Expand Down Expand Up @@ -193,10 +195,16 @@ export const MetricConfiguration: React.FC = observer(() => {
</MetricConfigurationDisplay>

{/* Metric/Dimension Definitions (Includes/Excludes) & Context */}
<MetricDefinitions
activeDimensionKey={activeDimensionKey}
activeDisaggregationKey={activeDisaggregationKey}
/>
{/* Race/Ethnicities (when active disaggregation is Race / Ethnicities) */}
{activeDisaggregationKey === RACE_ETHNICITY_DISAGGREGATION_KEY &&
activeDimensionKey ? (
<RaceEthnicitiesForm />
) : (
<MetricDefinitions
activeDimensionKey={activeDimensionKey}
activeDisaggregationKey={activeDisaggregationKey}
/>
)}
</MetricConfigurationWrapper>
)}
</MetricsViewControlPanel>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
// 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 {
palette,
typography,
} from "@justice-counts/common/components/GlobalStyles";
import styled from "styled-components/macro";

import {
DefinitionDisplayName,
DefinitionItem,
DefinitionMiniButton,
Definitions,
DefinitionsDescription,
DefinitionsDisplay,
DefinitionsDisplayContainer,
DefinitionSelection,
DefinitionsTitle,
MetricOnOffWrapper,
} from ".";

export const RaceEthnicitiesBreakdownContainer = styled.div`
padding-top: 14px;
`;

export const CalloutBox = styled.div`
width: 100%;
height: 100%;
display: flex;
align-items: center;
padding: 20px 60px 20px 20px;
margin-bottom: 27px;
border-radius: 2px;
border: 1px solid ${palette.solid.blue};
box-shadow: 0px 2px 4px rgba(0, 115, 229, 0.25);
svg {
position: absolute;
right: 20px;
}
`;

export const GridHeaderContainer = styled.div`
${typography.sizeCSS.small}
color: ${palette.highlight.grey5};
width: 100%;
display: flex;
padding-bottom: 10px;
border-bottom: 1px solid ${palette.highlight.grey4};
`;

export const GridRaceHeader = styled.div`
width: 100%;
`;
export const GridEthnicitiesHeader = styled.div`
display: flex;
gap: 17px;
`;

export const EthnicityLabel = styled.div`
width: 100%;
display: flex;
align-items: center;
svg {
margin-left: 3px;
width: 10px;
path {
fill: ${palette.highlight.grey5};
}
}
`;

export const Ethnicity = styled.div`
color: ${palette.solid.darkgrey};
white-space: nowrap;
`;

export const Description = styled.div`
${typography.sizeCSS.normal}
span {
color: ${palette.solid.blue};
}
`;

export const RaceEthnicitiesTable = styled.div`
width: 100%;
`;

export const RaceEthnicitiesRow = styled.div`
display: flex;
align-items: center;
justify-content: space-between;
padding: 16px 0;
&:not(:last-child) {
border-bottom: 1px solid ${palette.highlight.grey4};
}
`;

export const RaceCell = styled.div``;

export const EthnicitiesRow = styled.div`
display: flex;
margin-right: 17px;
gap: 60px;
`;
export const EthnicityCell = styled.div<{ enabled?: boolean }>`
width: 20px;
height: 20px;
border-radius: 50%;
border: 1px solid ${palette.highlight.grey4};
${({ enabled }) => enabled && `background: ${palette.solid.blue};`}
`;

export const SpecifyEthnicityWrapper = styled(MetricOnOffWrapper)`
margin-bottom: 35px;
`;

export const RaceEthnicitiesContainer = styled(DefinitionsDisplayContainer)``;
export const RaceEthnicitiesDisplay = styled(DefinitionsDisplay)``;
export const RaceEthnicitiesTitle = styled(DefinitionsTitle)``;
export const RaceEthnicitiesDescription = styled(DefinitionsDescription)``;
export const RaceContainer = styled(Definitions)``;
export const Race = styled(DefinitionItem)``;
export const RaceDisplayName = styled(DefinitionDisplayName)``;
export const RaceSelection = styled(DefinitionSelection)``;
export const RaceSelectionButton = styled(DefinitionMiniButton)``;
Loading

0 comments on commit 000fe2a

Please sign in to comment.