Skip to content

Commit

Permalink
make getEdgeFilteringWarning a util, memoize derived state
Browse files Browse the repository at this point in the history
  • Loading branch information
buckhalt committed Dec 9, 2024
1 parent 55b9b72 commit 3422a77
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 59 deletions.
30 changes: 16 additions & 14 deletions src/components/sections/Filter.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useCallback } from 'react';
import React, { useCallback, useMemo } from 'react';
import { change, Field, formValueSelector } from 'redux-form';
import { useDispatch, useSelector } from 'react-redux';
import { Section } from '@components/EditorLayout';
Expand All @@ -8,7 +8,7 @@ import {
Filter as FilterQuery, withFieldConnector, withStoreConnector, ruleValidator,
} from '../Query';
import Tip from '../Tip';
import { getEdgeFilteringWarning } from './SociogramPrompts/selectors';
import getEdgeFilteringWarning from './SociogramPrompts/utils';

const FilterField = withFieldConnector(withStoreConnector(FilterQuery));

Expand All @@ -33,25 +33,27 @@ const Filter = () => {
);

// get edge creation and display values for edges across all prompts
let shouldShowWarning = false;
const prompts = useSelector((state) => getFormValue(state, 'prompts'));

if (prompts) {
const edgeCreationValues = prompts
.filter((prompt) => prompt?.edges?.create)
.map((prompt) => prompt.edges.create);

const edgeDisplayValues = prompts
.filter((prompt) => prompt?.edges?.display)
.flatMap((prompt) => prompt.edges.display);

const { edgeCreationValues, edgeDisplayValues } = useMemo(() => {
if (!prompts) return { edgeCreationValues: [], edgeDisplayValues: [] };
const creationValues = [];
const displayValues = [];
prompts.forEach((prompt) => {
if (prompt?.edges?.create) creationValues.push(prompt.edges.create);
if (prompt?.edges?.display) displayValues.push(...prompt.edges.display);
});
return { edgeCreationValues: creationValues, edgeDisplayValues: displayValues };
}, [prompts]);
const shouldShowWarning = useMemo(() => {
if (edgeCreationValues.length > 0 || edgeDisplayValues.length > 0) {
shouldShowWarning = getEdgeFilteringWarning(
return getEdgeFilteringWarning(
currentValue.rules,
[...edgeCreationValues, ...edgeDisplayValues],
);
}
}
return false;
}, [currentValue, edgeCreationValues, edgeDisplayValues]);

const handleToggleChange = useCallback(
async (newState) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import { change, Field, formValueSelector } from 'redux-form';
import * as Fields from '@codaco/ui/lib/components/Fields';
import { Section, Row } from '@components/EditorLayout';
import Tip from '../../Tip';
import { getEdgeFilteringWarning, getEdgeFilters, getEdgesForSubject } from './selectors';
import { getEdgeFilters, getEdgesForSubject } from './selectors';
import getEdgeFilteringWarning from './utils';

const DisplayEdges = ({ form, entity, type }) => {
const dispatch = useDispatch();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ import Tip from '@components/Tip';
import EntitySelectField from '../fields/EntitySelectField/EntitySelectField';
import DetachedField from '../../DetachedField';
import VariablePicker from '../../Form/Fields/VariablePicker/VariablePicker';
import { getHighlightVariablesForSubject, getEdgeFilteringWarning, getEdgeFilters } from './selectors';
import { getHighlightVariablesForSubject, getEdgeFilters } from './selectors';
import { actionCreators as codebookActions } from '../../../ducks/modules/protocol/codebook';
import getEdgeFilteringWarning from './utils';

// TODO: Move this somewhere else!
// This was created as part of removing the HOC pattern used throughout the app.
Expand Down Expand Up @@ -104,7 +105,7 @@ const TapBehaviour = ({

const selectedValue = useSelector((state) => getFormValue(state, 'edges.create'));

const edgeFilters = useSelector((state) => getEdgeFilters(state));
const edgeFilters = useSelector(getEdgeFilters);
const showNetworkFilterWarning = getEdgeFilteringWarning(edgeFilters, [selectedValue]);

return (
Expand Down
42 changes: 0 additions & 42 deletions src/components/sections/SociogramPrompts/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,45 +45,3 @@ export const getEdgeFilters = (state) => {

return edgeFilters;
};

/**
* Compare selected edges to edge filters to determine if a warning should be shown
* @param {Array} filters - edge filters
* @param {Array} edges - selected edges
* There are four main cases to consider:
* 1. Selected edge is in the filters with rule EXISTS -- no warning
* 2. Selected edge is not in the filters with rule EXISTS -- show a warning
* 3. Selected edge is in the filters with rule DOES_NOT_EXIST -- show a warning
* 4. Selected edge is not in the filters with rule DOES_NOT_EXIST -- no warning
*/

export const getEdgeFilteringWarning = (filters, edges) => {
const existFilters = filters.filter((rule) => rule.options.operator === 'EXISTS');
const doesNotExistFilters = filters.filter((rule) => rule.options.operator === 'NOT_EXISTS');

// if any edge should show a warning, return true
return edges.some((edge) => {
const isEdgeInExistFilters = existFilters.some((rule) => rule.options.type === edge);
const isEdgeInDoesNotExistFilters = doesNotExistFilters.some(
(rule) => rule.options.type === edge,
);

// case 1
if (isEdgeInExistFilters) {
return false;
}

// case 2
if (!isEdgeInExistFilters && existFilters.length > 0) {
return true;
}

// case 3
if (isEdgeInDoesNotExistFilters) {
return true;
}

// No warning in other cases
return false;
});
};
43 changes: 43 additions & 0 deletions src/components/sections/SociogramPrompts/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/**
* Compare selected edges to edge filters to determine if a warning should be shown
* @param {Array} filters - edge filters
* @param {Array} edges - selected edges
* There are four main cases to consider:
* 1. Selected edge is in the filters with rule EXISTS -- no warning
* 2. Selected edge is not in the filters with rule EXISTS -- show a warning
* 3. Selected edge is in the filters with rule DOES_NOT_EXIST -- show a warning
* 4. Selected edge is not in the filters with rule DOES_NOT_EXIST -- no warning
*/

const getEdgeFilteringWarning = (filters, edges) => {
const existFilters = filters.filter((rule) => rule.options.operator === 'EXISTS');
const doesNotExistFilters = filters.filter((rule) => rule.options.operator === 'NOT_EXISTS');

// if any edge should show a warning, return true
return edges.some((edge) => {
const isEdgeInExistFilters = existFilters.some((rule) => rule.options.type === edge);
const isEdgeInDoesNotExistFilters = doesNotExistFilters.some(
(rule) => rule.options.type === edge,
);

// case 1
if (isEdgeInExistFilters) {
return false;
}

// case 2
if (!isEdgeInExistFilters && existFilters.length > 0) {
return true;
}

// case 3
if (isEdgeInDoesNotExistFilters) {
return true;
}

// No warning in other cases
return false;
});
};

export default getEdgeFilteringWarning;

0 comments on commit 3422a77

Please sign in to comment.