diff --git a/src/components/sections/Filter.js b/src/components/sections/Filter.js index 356afdf1e..eef01e0c0 100644 --- a/src/components/sections/Filter.js +++ b/src/components/sections/Filter.js @@ -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'; @@ -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)); @@ -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) => { diff --git a/src/components/sections/SociogramPrompts/PromptFieldsEdges.js b/src/components/sections/SociogramPrompts/PromptFieldsEdges.js index ce5a6d91f..1c67c3118 100644 --- a/src/components/sections/SociogramPrompts/PromptFieldsEdges.js +++ b/src/components/sections/SociogramPrompts/PromptFieldsEdges.js @@ -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(); diff --git a/src/components/sections/SociogramPrompts/PromptFieldsTapBehaviour.js b/src/components/sections/SociogramPrompts/PromptFieldsTapBehaviour.js index 45d0b5ea8..daa4ef099 100644 --- a/src/components/sections/SociogramPrompts/PromptFieldsTapBehaviour.js +++ b/src/components/sections/SociogramPrompts/PromptFieldsTapBehaviour.js @@ -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. @@ -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 ( diff --git a/src/components/sections/SociogramPrompts/selectors.js b/src/components/sections/SociogramPrompts/selectors.js index ace0daf30..bc00f7b6e 100644 --- a/src/components/sections/SociogramPrompts/selectors.js +++ b/src/components/sections/SociogramPrompts/selectors.js @@ -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; - }); -}; diff --git a/src/components/sections/SociogramPrompts/utils.js b/src/components/sections/SociogramPrompts/utils.js new file mode 100644 index 000000000..3efa5883a --- /dev/null +++ b/src/components/sections/SociogramPrompts/utils.js @@ -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;