From 28ceb3a5cebee9a5b54ec4b279a8eb37fc690029 Mon Sep 17 00:00:00 2001 From: Mahmoud Date: Tue, 22 Nov 2022 14:48:03 -0600 Subject: [PATCH] Instead of saving deltas - save all 24 dimensions Further optimize by using inputs and onChange to prevent multiple calls when clicking on the active option Debounce saving Extend binary input radio buttons to mini buttons --- .../components/Forms/BinaryRadioButton.tsx | 43 ++++- .../RaceEthnicitiesForm.tsx | 174 ++++++++++-------- publisher/src/stores/MetricConfigStore.tsx | 47 ++--- 3 files changed, 153 insertions(+), 111 deletions(-) diff --git a/publisher/src/components/Forms/BinaryRadioButton.tsx b/publisher/src/components/Forms/BinaryRadioButton.tsx index 95519810d..7afd8145c 100644 --- a/publisher/src/components/Forms/BinaryRadioButton.tsx +++ b/publisher/src/components/Forms/BinaryRadioButton.tsx @@ -20,7 +20,7 @@ import { typography, } from "@justice-counts/common/components/GlobalStyles"; import React, { InputHTMLAttributes } from "react"; -import styled from "styled-components/macro"; +import styled, { css } from "styled-components/macro"; export const BinaryRadioGroupContainer = styled.div` display: flex; @@ -43,7 +43,7 @@ export const BinaryRadioGroupQuestion = styled.div` color: ${palette.solid.darkgrey}; `; -export const RadioButtonWrapper = styled.div` +export const RadioButtonWrapper = styled.div<{ lastOptionBlue?: boolean }>` display: flex; flex: 1 1 0; margin: 15px 0 0 0; @@ -51,6 +51,22 @@ export const RadioButtonWrapper = styled.div` &:first-child { margin: 15px 10px 0 0; } + + ${({ lastOptionBlue }) => + lastOptionBlue && + css` + margin: 0; + + &:first-child { + margin: 0px 10px 0 0; + } + + &:first-child input:checked + label { + background-color: ${palette.highlight.grey9}; + border-color: unset; + color: ${palette.solid.white}; + } + `} `; export const RadioButtonElement = styled.input<{ @@ -83,6 +99,7 @@ export const RadioButtonElement = styled.input<{ export const RadioButtonLabel = styled.label<{ disabled?: boolean; + buttonSize?: string; }>` ${typography.sizeCSS.medium} width: 100%; @@ -100,6 +117,16 @@ export const RadioButtonLabel = styled.label<{ background-color: ${({ disabled }) => disabled ? "none" : palette.highlight.grey2}; } + + ${({ buttonSize }) => + buttonSize === "small" && + css` + ${typography.sizeCSS.normal} + width: unset; + height: unset; + min-width: 60px; + padding: 9px 16px; + `} `; export const BinaryRadioGroupClearButton = styled.div<{ @@ -119,6 +146,8 @@ interface RadioButtonProps extends InputHTMLAttributes { label: string; context?: string; metricKey?: string; + buttonSize?: string; + lastOptionBlue?: boolean; } /** Single radio button in the style of a regular button */ @@ -127,16 +156,22 @@ export const BinaryRadioButton: React.FC = ({ context, metricKey, disabled, + buttonSize, + lastOptionBlue, ...props }): JSX.Element => { return ( - + - + {label} diff --git a/publisher/src/components/MetricConfiguration/RaceEthnicitiesForm.tsx b/publisher/src/components/MetricConfiguration/RaceEthnicitiesForm.tsx index d906e34b0..91096230d 100644 --- a/publisher/src/components/MetricConfiguration/RaceEthnicitiesForm.tsx +++ b/publisher/src/components/MetricConfiguration/RaceEthnicitiesForm.tsx @@ -15,8 +15,9 @@ // along with this program. If not, see . // ============================================================================= +import { debounce } from "lodash"; import { observer } from "mobx-react-lite"; -import React from "react"; +import React, { useRef } from "react"; import { useStore } from "../../stores"; import { BinaryRadioButton } from "../Forms"; @@ -31,7 +32,6 @@ import { RaceEthnicitiesTitle, raceEthnicityGridStates, RaceSelection, - RaceSelectionButton, RadioButtonGroupWrapper, SpecifyEthnicityWrapper, Subheader, @@ -79,6 +79,8 @@ export const RaceEthnicitiesForm = observer(() => { const currentState = determineCurrentState(); + const debouncedSave = useRef(debounce(saveMetricSettings, 1000)).current; + return ( @@ -112,7 +114,7 @@ export const RaceEthnicitiesForm = observer(() => { "CAN_SPECIFY_ETHNICITY", raceEthnicityGridStates ); - saveMetricSettings(updatedDimensions); + debouncedSave(updatedDimensions); }} /> { "NO_ETHNICITY_HISPANIC_AS_RACE", raceEthnicityGridStates ); - saveMetricSettings(updatedDimensions); + debouncedSave(updatedDimensions); }} /> @@ -148,32 +150,44 @@ export const RaceEthnicitiesForm = observer(() => { Hispanic/Latino - { - const updatedDimensions = - updateAllRaceEthnicitiesToDefaultState( - "NO_ETHNICITY_HISPANIC_NOT_SPECIFIED", - raceEthnicityGridStates - ); - saveMetricSettings(updatedDimensions); - }} - > - No - - { - const updatedDimensions = - updateAllRaceEthnicitiesToDefaultState( - "NO_ETHNICITY_HISPANIC_AS_RACE", - raceEthnicityGridStates - ); - saveMetricSettings(updatedDimensions); - }} - > - Yes - + + { + const updatedDimensions = + updateAllRaceEthnicitiesToDefaultState( + "NO_ETHNICITY_HISPANIC_NOT_SPECIFIED", + raceEthnicityGridStates + ); + debouncedSave(updatedDimensions); + }} + /> + { + const updatedDimensions = + updateAllRaceEthnicitiesToDefaultState( + "NO_ETHNICITY_HISPANIC_AS_RACE", + raceEthnicityGridStates + ); + debouncedSave(updatedDimensions); + }} + /> + )} @@ -188,62 +202,62 @@ export const RaceEthnicitiesForm = observer(() => { {race} - { - let switchedGridStateUpdatedDimensions; - /** - * When Unknown Race is disabled in NO_ETHNICITY_HISPANIC_AS_RACE state, we automatically switch - * to the NO_ETHNICITY_HISPANIC_NOT_SPECIFIED state because the Unknown Race (Hispanic/Latino Ethnicity) - * dimension is the only dimension an agency can specify their numbers for Hispanic/Latino as a Race (while - * in the NO_ETHNICITY_HISPANIC_AS_RACE state). - */ - if ( - race === "Unknown" && - currentState === "NO_ETHNICITY_HISPANIC_AS_RACE" - ) { - switchedGridStateUpdatedDimensions = + + { + /** + * When Unknown Race is disabled in NO_ETHNICITY_HISPANIC_AS_RACE state, we automatically switch + * to the NO_ETHNICITY_HISPANIC_NOT_SPECIFIED state because the Unknown Race (Hispanic/Latino Ethnicity) + * dimension is the only dimension an agency can specify their numbers for Hispanic/Latino as a Race (while + * in the NO_ETHNICITY_HISPANIC_AS_RACE state). + */ + if ( + race === "Unknown" && + currentState === "NO_ETHNICITY_HISPANIC_AS_RACE" + ) { updateAllRaceEthnicitiesToDefaultState( "NO_ETHNICITY_HISPANIC_NOT_SPECIFIED", raceEthnicityGridStates ); - } - - const updatedDimensions = updateRaceDimensions( - race, - false, - currentState, - raceEthnicityGridStates - ); - - if (switchedGridStateUpdatedDimensions) { - /** Add the updated dimension from disabling the Unknown race to the switchedGridStateUpdatedDimensions */ - switchedGridStateUpdatedDimensions.disaggregations[0].dimensions.push( - ...updatedDimensions.disaggregations[0].dimensions + } + + const updatedDimensions = updateRaceDimensions( + race, + false, + currentState, + raceEthnicityGridStates ); - return saveMetricSettings( - switchedGridStateUpdatedDimensions + debouncedSave(updatedDimensions); + }} + /> + { + const updatedDimensions = updateRaceDimensions( + race, + true, + currentState, + raceEthnicityGridStates ); - } - saveMetricSettings(updatedDimensions); - }} - > - No - - { - const updatedDimensions = updateRaceDimensions( - race, - true, - currentState, - raceEthnicityGridStates - ); - saveMetricSettings(updatedDimensions); - }} - > - Yes - + debouncedSave(updatedDimensions); + }} + /> + ); diff --git a/publisher/src/stores/MetricConfigStore.tsx b/publisher/src/stores/MetricConfigStore.tsx index 9c9be7422..d32cd8bf8 100644 --- a/publisher/src/stores/MetricConfigStore.tsx +++ b/publisher/src/stores/MetricConfigStore.tsx @@ -701,7 +701,6 @@ class MetricConfigStore { ...acc[dimension.race], [dimension.ethnicity]: dimension, }; - return acc; }, {} as { @@ -729,7 +728,6 @@ class MetricConfigStore { state === "NO_ETHNICITY_HISPANIC_AS_RACE" && unknownRaceDisabled ? "NO_ETHNICITY_HISPANIC_NOT_SPECIFIED" : state; - const updatedDimensions = [] as UpdatedDimension[]; /** * When Unknown Race dimensions are disabled AND user is switching to NO_ETHNICITY_HISPANIC_AS_RACE state, @@ -738,18 +736,6 @@ class MetricConfigStore { if (unknownRaceDisabled && state === "NO_ETHNICITY_HISPANIC_AS_RACE") { this.ethnicitiesByRace.Unknown.Hispanic.enabled = true; this.ethnicitiesByRace.Unknown["Not Hispanic"].enabled = true; - updatedDimensions.push( - ...[ - { - ...this.ethnicitiesByRace.Unknown.Hispanic, - enabled: true, - }, - { - ...this.ethnicitiesByRace.Unknown["Not Hispanic"], - enabled: true, - }, - ] - ); sanitizedState = state; } @@ -781,21 +767,22 @@ class MetricConfigStore { this.ethnicitiesByRace[race][ethnicity].key, gridStates[sanitizedState][race][ethnicity] ); - - updatedDimensions.push({ - ...this.ethnicitiesByRace[race][ethnicity], - enabled: gridStates[sanitizedState][race][ethnicity], - }); }); }); - /** Return array of dimensions that were updated */ + const raceEthnicitiesDimensions = + this.dimensions[systemMetricKey][RACE_ETHNICITY_DISAGGREGATION_KEY]; + const dimensions = + raceEthnicitiesDimensions && + (Object.values(raceEthnicitiesDimensions) as UpdatedDimension[]); + + /** Return an object w/ all dimensions in the desired backend data structure for saving purposes */ return { key: this.activeMetricKey as string, disaggregations: [ { key: RACE_ETHNICITY_DISAGGREGATION_KEY, - dimensions: updatedDimensions, + dimensions, }, ], }; @@ -807,8 +794,6 @@ class MetricConfigStore { state: StateKeys, gridStates: RaceEthnicitiesGridStates ): UpdatedDisaggregation => { - const updatedDimensions = [] as UpdatedDimension[]; - ethnicities.forEach((ethnicity) => { /** No update if intended update matches the current state (e.g. enabling an already enabled dimension) */ if (this.ethnicitiesByRace[race][ethnicity].enabled === enabled) return; @@ -827,17 +812,25 @@ class MetricConfigStore { this.ethnicitiesByRace[race][ethnicity].key, enabled ); - - updatedDimensions.push(this.ethnicitiesByRace[race][ethnicity]); }); - /** Return array of dimensions that were updated */ + const systemMetricKey = MetricConfigStore.getSystemMetricKey( + this.activeSystem as string, + this.activeMetricKey as string + ); + const raceEthnicitiesDimensions = + this.dimensions[systemMetricKey][RACE_ETHNICITY_DISAGGREGATION_KEY]; + const dimensions = + raceEthnicitiesDimensions && + (Object.values(raceEthnicitiesDimensions) as UpdatedDimension[]); + + /** Return an object w/ all dimensions in the desired backend data structure for saving purposes */ return { key: this.activeMetricKey as string, disaggregations: [ { key: RACE_ETHNICITY_DISAGGREGATION_KEY, - dimensions: updatedDimensions, + dimensions, }, ], };