From e67cdebb1f4e056db1951320486934e665f2856e Mon Sep 17 00:00:00 2001 From: "Erin E. Sullivan" Date: Fri, 18 Oct 2024 13:00:51 -0400 Subject: [PATCH 1/8] Creating `AdvancedSearchSubmit` component to reduce repeated code. --- .../components/AdvancedSearchForm/index.js | 9 ++------- .../components/AdvancedSearchSubmit/index.js | 15 +++++++++++++++ .../advanced/components/FiltersContainer/index.js | 10 ++-------- src/modules/advanced/index.js | 2 ++ 4 files changed, 21 insertions(+), 15 deletions(-) create mode 100644 src/modules/advanced/components/AdvancedSearchSubmit/index.js diff --git a/src/modules/advanced/components/AdvancedSearchForm/index.js b/src/modules/advanced/components/AdvancedSearchForm/index.js index 1218d933..012da538 100644 --- a/src/modules/advanced/components/AdvancedSearchForm/index.js +++ b/src/modules/advanced/components/AdvancedSearchForm/index.js @@ -1,7 +1,7 @@ +import { addFieldedSearch, AdvancedSearchSubmit } from '../../../advanced'; import { Alert, Icon } from '../../../reusable'; import React, { useCallback, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; -import { addFieldedSearch } from '../../../advanced'; import FieldInput from '../FieldInput'; import FiltersContainer from '../FiltersContainer'; import PropTypes from 'prop-types'; @@ -112,12 +112,7 @@ const AdvancedSearchForm = ({ datastore }) => { Add another field - + diff --git a/src/modules/advanced/components/AdvancedSearchSubmit/index.js b/src/modules/advanced/components/AdvancedSearchSubmit/index.js new file mode 100644 index 00000000..5bc4ce0c --- /dev/null +++ b/src/modules/advanced/components/AdvancedSearchSubmit/index.js @@ -0,0 +1,15 @@ +import { Icon } from '../../../reusable'; +import React from 'react'; + +const AdvancedSearchSubmit = () => { + return ( + + ); +}; + +export default AdvancedSearchSubmit; diff --git a/src/modules/advanced/components/FiltersContainer/index.js b/src/modules/advanced/components/FiltersContainer/index.js index abc1b46f..cc0f15ce 100644 --- a/src/modules/advanced/components/FiltersContainer/index.js +++ b/src/modules/advanced/components/FiltersContainer/index.js @@ -1,11 +1,10 @@ import './styles.css'; +import { AdvancedSearchSubmit, setAdvancedFilter } from '../../../advanced'; import { useDispatch, useSelector } from 'react-redux'; import AdvancedFilter from '../AdvancedFilter'; import getFilters from './getFilters'; -import { Icon } from '../../../reusable'; import PropTypes from 'prop-types'; import React from 'react'; -import { setAdvancedFilter } from '../../../advanced'; const ActiveAdvancedFilters = ({ datastoreUid }) => { const { activeFilters, filters } = useSelector((state) => { @@ -186,12 +185,7 @@ const FiltersContainer = ({ datastoreUid }) => { ); })} - + ); }; diff --git a/src/modules/advanced/index.js b/src/modules/advanced/index.js index 8017d339..9dfadd3b 100644 --- a/src/modules/advanced/index.js +++ b/src/modules/advanced/index.js @@ -9,6 +9,7 @@ import { } from './actions'; import advancedReducer from './reducer'; import AdvancedSearch from './components/AdvancedSearchContainer'; +import AdvancedSearchSubmit from './components/AdvancedSearchSubmit'; export { addAdvancedBooleanTypes, @@ -17,6 +18,7 @@ export { addFieldedSearch, advancedReducer, AdvancedSearch, + AdvancedSearchSubmit, removeFieldedSearch, setAdvancedFilter, setFieldedSearch From 5fae0d3ea1eec37c5c54c915012d27e0260f1881 Mon Sep 17 00:00:00 2001 From: "Erin E. Sullivan" Date: Fri, 18 Oct 2024 14:48:08 -0400 Subject: [PATCH 2/8] Pulling in `advancedFilter` object and removing `descriptionText`. --- .../components/AdvancedFilter/index.js | 12 +---- .../core/components/Multiselect/index.js | 47 +++++++------------ 2 files changed, 18 insertions(+), 41 deletions(-) diff --git a/src/modules/advanced/components/AdvancedFilter/index.js b/src/modules/advanced/components/AdvancedFilter/index.js index 1a823d79..179caa1c 100644 --- a/src/modules/advanced/components/AdvancedFilter/index.js +++ b/src/modules/advanced/components/AdvancedFilter/index.js @@ -128,19 +128,9 @@ const AdvancedFilter = ({ advancedFilter, changeAdvancedFilter }) => { ); } if (advancedFilter.type === 'multiple_select') { - const options = advancedFilter.filters.map((option) => { - return { - checked: option.isActive, - name: option.value, - value: option.value - }; - }); - return ( { return changeAdvancedFilter({ filterGroupUid: advancedFilter.uid, diff --git a/src/modules/core/components/Multiselect/index.js b/src/modules/core/components/Multiselect/index.js index 3c16e8e8..6fc3a540 100644 --- a/src/modules/core/components/Multiselect/index.js +++ b/src/modules/core/components/Multiselect/index.js @@ -2,9 +2,16 @@ import React, { useState } from 'react'; import { Checkbox } from '../../../reusable'; import PropTypes from 'prop-types'; -const Multiselect = ({ descriptionText, filterGroupUid, handleSelection, options }) => { +const Multiselect = ({ advancedFilter, handleSelection }) => { const [filterQuery, setFilterQuery] = useState(''); const [showOnlySelectedOptions, setshowOnlySelectedOptions] = useState(false); + const options = advancedFilter.filters.map((option) => { + return { + checked: option.isActive, + name: option.value, + value: option.value + }; + }); const selectedOptions = options.filter((option) => { return option.checked; }); @@ -31,12 +38,12 @@ const Multiselect = ({ descriptionText, filterGroupUid, handleSelection, options return (
- {descriptionText &&

{descriptionText}

} +

Select one or more checkboxes to narrow your results to items that match all of your {advancedFilter.name.toLowerCase()} selections.

{ @@ -44,7 +51,7 @@ const Multiselect = ({ descriptionText, filterGroupUid, handleSelection, options }} autoComplete='on' /> -

Below this edit box is a list of check boxes that allow you to filter down your options. As you type in this edit box, the list of check boxes is updated to reflect only those that match the query typed in this box.

+

Below this edit box is a list of check boxes that allow you to filter down your options. As you type in this edit box, the list of check boxes is updated to reflect only those that match the query typed in this box.

Filter Options
    @@ -55,11 +62,12 @@ const Multiselect = ({ descriptionText, filterGroupUid, handleSelection, options if (!showOnlySelectedOptions || (showOnlySelectedOptions && option.checked)) { return (
  • - { return handleOptionSelection(option, index); }} - option={option} />
  • ); @@ -76,7 +84,7 @@ const Multiselect = ({ descriptionText, filterGroupUid, handleSelection, options setshowOnlySelectedOptions(!showOnlySelectedOptions); }} > - {showOnlySelectedOptions ? 'Show all options' : `Show only selected options (${selectedOptions.length})`} + Show {showOnlySelectedOptions ? 'all options' : `only selected options (${selectedOptions.length})`} )}
@@ -84,29 +92,8 @@ const Multiselect = ({ descriptionText, filterGroupUid, handleSelection, options }; Multiselect.propTypes = { - descriptionText: PropTypes.string, - filterGroupUid: PropTypes.string, - handleSelection: PropTypes.func, - options: PropTypes.arrayOf(PropTypes.shape({ - checked: PropTypes.bool, - name: PropTypes.string, - value: PropTypes.string - })) + advancedFilter: PropTypes.object, + handleSelection: PropTypes.func }; export default Multiselect; - -const MultiselectOption = ({ option, handleClick }) => { - return ( - - ); -}; - -MultiselectOption.propTypes = { - handleClick: PropTypes.func, - option: PropTypes.object -}; From d6b83f02e35e604f763f95b5db9c7780d63ad85d Mon Sep 17 00:00:00 2001 From: "Erin E. Sullivan" Date: Fri, 18 Oct 2024 15:33:57 -0400 Subject: [PATCH 3/8] Separating `ActiveAdvancedFilters` as its own component. --- .../components/ActiveAdvancedFilters/index.js | 74 +++++++++++++++++ .../styles.css | 0 .../components/FiltersContainer/index.js | 79 +------------------ 3 files changed, 76 insertions(+), 77 deletions(-) create mode 100644 src/modules/advanced/components/ActiveAdvancedFilters/index.js rename src/modules/advanced/components/{FiltersContainer => ActiveAdvancedFilters}/styles.css (100%) diff --git a/src/modules/advanced/components/ActiveAdvancedFilters/index.js b/src/modules/advanced/components/ActiveAdvancedFilters/index.js new file mode 100644 index 00000000..694f2186 --- /dev/null +++ b/src/modules/advanced/components/ActiveAdvancedFilters/index.js @@ -0,0 +1,74 @@ +import './styles.css'; +import PropTypes from 'prop-types'; +import React from 'react'; + +const ActiveAdvancedFilters = ({ activeFilters, filters }) => { + // Remove properties that have undefined values + Object.keys(activeFilters).forEach((option) => { + if (!activeFilters[option]) { + delete activeFilters[option]; + } + }); + + const filterGroups = {}; + filters.forEach((filterGroup) => { + filterGroups[filterGroup.uid] = { ...filterGroup }; + }); + + const items = Object.keys(activeFilters).reduce((acc, group) => { + // Just don't show the checkbox filters as active filter items. + if (!filterGroups[group] || filterGroups[group].type !== 'checkbox') { + const activeFiltersToAdd = activeFilters[group].map((value) => { + return { group, value }; + }); + return [...acc, ...activeFiltersToAdd]; + } + return acc; + }, []); + + if (!items.length) { + return null; + } + + const titleCase = (string) => { + return string.toLowerCase().split('_').map((word) => { + return word.replace(word[0], word[0].toUpperCase()); + }).join(' '); + }; + + return ( +
+

+ Active filters + {' '} + + ({items.length}) + +

+ +

+ Unselect active filters through the options below. +

+ +
    + {items.map((item, index) => { + return ( +
  • + {filterGroups[item.group]?.name || titleCase(item.group)}: {item.value} +
  • + ); + })} +
+
+ ); +}; + +ActiveAdvancedFilters.propTypes = { + activeFilters: PropTypes.object, + filters: PropTypes.array +}; + +export default ActiveAdvancedFilters; diff --git a/src/modules/advanced/components/FiltersContainer/styles.css b/src/modules/advanced/components/ActiveAdvancedFilters/styles.css similarity index 100% rename from src/modules/advanced/components/FiltersContainer/styles.css rename to src/modules/advanced/components/ActiveAdvancedFilters/styles.css diff --git a/src/modules/advanced/components/FiltersContainer/index.js b/src/modules/advanced/components/FiltersContainer/index.js index cc0f15ce..4ba28015 100644 --- a/src/modules/advanced/components/FiltersContainer/index.js +++ b/src/modules/advanced/components/FiltersContainer/index.js @@ -1,86 +1,11 @@ -import './styles.css'; import { AdvancedSearchSubmit, setAdvancedFilter } from '../../../advanced'; import { useDispatch, useSelector } from 'react-redux'; +import ActiveAdvancedFilters from '../ActiveAdvancedFilters'; import AdvancedFilter from '../AdvancedFilter'; import getFilters from './getFilters'; import PropTypes from 'prop-types'; import React from 'react'; -const ActiveAdvancedFilters = ({ datastoreUid }) => { - const { activeFilters, filters } = useSelector((state) => { - return state.advanced[datastoreUid] || {}; - }); - // Check if object exists - if (!activeFilters) { - return null; - } - // Remove properties that have undefined values - Object.keys(activeFilters).forEach((option) => { - if (!activeFilters[option]) { - delete activeFilters[option]; - } - }); - - const filterGroups = {}; - filters.forEach((filterGroup) => { - filterGroups[filterGroup.uid] = { ...filterGroup }; - }); - - const items = Object.keys(activeFilters).reduce((acc, group) => { - // Just don't show the checkbox filters as active filter items. - if (!filterGroups[group] || filterGroups[group].type !== 'checkbox') { - const activeFiltersToAdd = activeFilters[group].map((value) => { - return { group, value }; - }); - return [...acc, ...activeFiltersToAdd]; - } - return acc; - }, []); - - if (!items.length) { - return null; - } - - const titleCase = (string) => { - return string.toLowerCase().split('_').map((word) => { - return word.replace(word[0], word[0].toUpperCase()); - }).join(' '); - }; - - return ( -
-

- Active filters - {' '} - - ({items.length}) - -

- -

- Unselect active filters through the options below. -

- -
    - {items.map((item, index) => { - return ( -
  • - {filterGroups[item.group]?.name || titleCase(item.group)}: {item.value} -
  • - ); - })} -
-
- ); -}; - -ActiveAdvancedFilters.propTypes = { - datastoreUid: PropTypes.string -}; - const FiltersContainer = ({ datastoreUid }) => { const dispatch = useDispatch(); const { activeFilters, filters: filterGroups } = useSelector((state) => { @@ -145,7 +70,7 @@ const FiltersContainer = ({ datastoreUid }) => { return ( <> - + {activeFilters && }

Additional search options

{filterGroupings.map((filterGroup, groupIndex) => { From 3856290a1f9aecd85d938860341bcac880b9ce53 Mon Sep 17 00:00:00 2001 From: "Erin E. Sullivan" Date: Mon, 21 Oct 2024 09:58:15 -0400 Subject: [PATCH 4/8] Moving `Multiselect` out of `AdvancedFilter`. Separating styles. Replacing `Checkbox` with native checkboxes. --- .../components/AdvancedFilter/index.js | 16 +----- .../components/FiltersContainer/index.js | 28 ++++++----- .../core/components/Multiselect/index.js | 39 ++++++++------- .../core/components/Multiselect/styles.css | 13 +++++ src/stylesheets/forms.css | 37 ++++++++++++-- src/stylesheets/main.css | 49 ------------------- 6 files changed, 87 insertions(+), 95 deletions(-) create mode 100644 src/modules/core/components/Multiselect/styles.css diff --git a/src/modules/advanced/components/AdvancedFilter/index.js b/src/modules/advanced/components/AdvancedFilter/index.js index 179caa1c..54f10b8e 100644 --- a/src/modules/advanced/components/AdvancedFilter/index.js +++ b/src/modules/advanced/components/AdvancedFilter/index.js @@ -1,5 +1,5 @@ -import { DateRangeInput, Multiselect } from '../../../core'; import { Checkbox } from '../../../reusable'; +import { DateRangeInput } from '../../../core'; import NarrowSearchTo from '../NarrowSearchTo'; import PropTypes from 'prop-types'; import React from 'react'; @@ -127,20 +127,6 @@ const AdvancedFilter = ({ advancedFilter, changeAdvancedFilter }) => { /> ); } - if (advancedFilter.type === 'multiple_select') { - return ( - { - return changeAdvancedFilter({ - filterGroupUid: advancedFilter.uid, - filterType: advancedFilter.type, - filterValue: option.value - }); - }} - /> - ); - } if (advancedFilter.type === 'date_range_input') { const { stateSelectedRangeOption, stateBeginQuery, stateEndQuery } = getStateDateRangeValues({ advancedFilter }); diff --git a/src/modules/advanced/components/FiltersContainer/index.js b/src/modules/advanced/components/FiltersContainer/index.js index 4ba28015..a032c8bd 100644 --- a/src/modules/advanced/components/FiltersContainer/index.js +++ b/src/modules/advanced/components/FiltersContainer/index.js @@ -3,6 +3,7 @@ import { useDispatch, useSelector } from 'react-redux'; import ActiveAdvancedFilters from '../ActiveAdvancedFilters'; import AdvancedFilter from '../AdvancedFilter'; import getFilters from './getFilters'; +import { Multiselect } from '../../../core'; import PropTypes from 'prop-types'; import React from 'react'; @@ -83,10 +84,21 @@ const FiltersContainer = ({ datastoreUid }) => {

{advancedFilter.name}

- + {advancedFilter.type === 'multiple_select' + ? ( + { + return changeAdvancedFilter({ + filterGroupUid: advancedFilter.uid, + filterType: advancedFilter.type, + filterValue: option.value + }); + }} + /> + ) + : }
); @@ -96,13 +108,7 @@ const FiltersContainer = ({ datastoreUid }) => {

{filterGroup}

{filters[filterGroup].map((advancedFilter, index) => { - return ( - - ); + return ; })}
)} diff --git a/src/modules/core/components/Multiselect/index.js b/src/modules/core/components/Multiselect/index.js index 6fc3a540..e9fd8df4 100644 --- a/src/modules/core/components/Multiselect/index.js +++ b/src/modules/core/components/Multiselect/index.js @@ -1,13 +1,14 @@ +import './styles.css'; import React, { useState } from 'react'; -import { Checkbox } from '../../../reusable'; import PropTypes from 'prop-types'; -const Multiselect = ({ advancedFilter, handleSelection }) => { +const Multiselect = ({ advancedFilter, datastoreUid, handleSelection }) => { const [filterQuery, setFilterQuery] = useState(''); const [showOnlySelectedOptions, setshowOnlySelectedOptions] = useState(false); const options = advancedFilter.filters.map((option) => { return { checked: option.isActive, + datastore: datastoreUid, name: option.value, value: option.value }; @@ -16,8 +17,8 @@ const Multiselect = ({ advancedFilter, handleSelection }) => { return option.checked; }); - const handleOptionSelection = (option, index) => { - handleSelection(index, option); + const handleOptionSelection = ({ option }) => { + handleSelection({ option }); if (showOnlySelectedOptions) { if (selectedOptions.length === 1) { setshowOnlySelectedOptions(false); @@ -37,11 +38,11 @@ const Multiselect = ({ advancedFilter, handleSelection }) => { } return ( -
+

Select one or more checkboxes to narrow your results to items that match all of your {advancedFilter.name.toLowerCase()} selections.

{ autoComplete='on' />

Below this edit box is a list of check boxes that allow you to filter down your options. As you type in this edit box, the list of check boxes is updated to reflect only those that match the query typed in this box.

-
+
Filter Options -
    +
      {options.map((option, index) => { if (isOptionFiltered(option) && !showOnlySelectedOptions) { return null; } if (!showOnlySelectedOptions || (showOnlySelectedOptions && option.checked)) { return ( -
    • - { - return handleOptionSelection(option, index); - }} - /> +
    • +
    • ); } @@ -79,7 +83,7 @@ const Multiselect = ({ advancedFilter, handleSelection }) => { {selectedOptions.length > 0 && (
diff --git a/src/modules/core/components/Multiselect/index.js b/src/modules/core/components/Multiselect/index.js index e9fd8df4..ca192ecc 100644 --- a/src/modules/core/components/Multiselect/index.js +++ b/src/modules/core/components/Multiselect/index.js @@ -1,14 +1,16 @@ import './styles.css'; import React, { useState } from 'react'; import PropTypes from 'prop-types'; +import { setAdvancedFilter } from '../../../advanced'; +import { useDispatch } from 'react-redux'; -const Multiselect = ({ advancedFilter, datastoreUid, handleSelection }) => { +const Multiselect = ({ advancedFilter, datastoreUid }) => { + const dispatch = useDispatch(); const [filterQuery, setFilterQuery] = useState(''); const [showOnlySelectedOptions, setshowOnlySelectedOptions] = useState(false); const options = advancedFilter.filters.map((option) => { return { checked: option.isActive, - datastore: datastoreUid, name: option.value, value: option.value }; @@ -18,7 +20,11 @@ const Multiselect = ({ advancedFilter, datastoreUid, handleSelection }) => { }); const handleOptionSelection = ({ option }) => { - handleSelection({ option }); + dispatch(setAdvancedFilter({ + datastoreUid, + filterGroupUid: advancedFilter.uid, + filterValue: option.value + })); if (showOnlySelectedOptions) { if (selectedOptions.length === 1) { setshowOnlySelectedOptions(false); @@ -97,8 +103,7 @@ const Multiselect = ({ advancedFilter, datastoreUid, handleSelection }) => { Multiselect.propTypes = { advancedFilter: PropTypes.object, - datastoreUid: PropTypes.string, - handleSelection: PropTypes.func + datastoreUid: PropTypes.string }; export default Multiselect; From 109c09d0a7c2dbe74b3a3f94146266c2f6ba8469 Mon Sep 17 00:00:00 2001 From: "Erin E. Sullivan" Date: Mon, 21 Oct 2024 12:55:44 -0400 Subject: [PATCH 6/8] Increasing performance and simplifying code. --- .../core/components/Multiselect/index.js | 87 ++++++++++--------- 1 file changed, 44 insertions(+), 43 deletions(-) diff --git a/src/modules/core/components/Multiselect/index.js b/src/modules/core/components/Multiselect/index.js index ca192ecc..e201d47d 100644 --- a/src/modules/core/components/Multiselect/index.js +++ b/src/modules/core/components/Multiselect/index.js @@ -1,5 +1,5 @@ import './styles.css'; -import React, { useState } from 'react'; +import React, { useMemo, useState } from 'react'; import PropTypes from 'prop-types'; import { setAdvancedFilter } from '../../../advanced'; import { useDispatch } from 'react-redux'; @@ -7,39 +7,40 @@ import { useDispatch } from 'react-redux'; const Multiselect = ({ advancedFilter, datastoreUid }) => { const dispatch = useDispatch(); const [filterQuery, setFilterQuery] = useState(''); - const [showOnlySelectedOptions, setshowOnlySelectedOptions] = useState(false); - const options = advancedFilter.filters.map((option) => { - return { - checked: option.isActive, - name: option.value, - value: option.value - }; - }); - const selectedOptions = options.filter((option) => { - return option.checked; - }); + const [showOnlySelectedOptions, setShowOnlySelectedOptions] = useState(false); - const handleOptionSelection = ({ option }) => { + const options = useMemo(() => { + return advancedFilter.filters.map(({ isActive, value }) => { + return { + checked: isActive, + name: value, + value + }; + }); + }, [advancedFilter.filters]); + + const selectedOptions = useMemo(() => { + return options.filter((option) => { + return option.checked; + }); + }, [options]); + + const handleOptionSelection = (option) => { dispatch(setAdvancedFilter({ datastoreUid, filterGroupUid: advancedFilter.uid, filterValue: option.value })); - if (showOnlySelectedOptions) { - if (selectedOptions.length === 1) { - setshowOnlySelectedOptions(false); - } + if (showOnlySelectedOptions && selectedOptions.length === 1) { + setShowOnlySelectedOptions(false); } }; - const isOptionFiltered = (option) => { - if (filterQuery.length === 0) { - return false; - } - return !(option.name.toLowerCase().indexOf(filterQuery.toLowerCase()) !== -1); + const isOptionFiltered = (name) => { + return filterQuery.length > 0 && !name.toLowerCase().includes(filterQuery.toLowerCase()); }; - if (!options || options.length === 0) { + if (!options.length) { return null; } @@ -54,7 +55,7 @@ const Multiselect = ({ advancedFilter, datastoreUid }) => { placeholder='Filter' value={filterQuery} onChange={(event) => { - setFilterQuery(event.target.value); + return setFilterQuery(event.target.value); }} autoComplete='on' /> @@ -63,26 +64,24 @@ const Multiselect = ({ advancedFilter, datastoreUid }) => { Filter Options
    {options.map((option, index) => { - if (isOptionFiltered(option) && !showOnlySelectedOptions) { + const { checked, name } = option; + if ((!showOnlySelectedOptions && isOptionFiltered(name)) || (showOnlySelectedOptions && !checked)) { return null; } - if (!showOnlySelectedOptions || (showOnlySelectedOptions && option.checked)) { - return ( -
  • - -
  • - ); - } - return null; + return ( +
  • + +
  • + ); })}
@@ -91,7 +90,9 @@ const Multiselect = ({ advancedFilter, datastoreUid }) => { type='button' className='button-link-light font-small margin-top__xs' onClick={() => { - setshowOnlySelectedOptions(!showOnlySelectedOptions); + return setShowOnlySelectedOptions((prev) => { + return !prev; + }); }} > Show {showOnlySelectedOptions ? 'all options' : `only selected options (${selectedOptions.length})`} From 0d83efbfd4eaf7defdcff0f598a500bacd336e0d Mon Sep 17 00:00:00 2001 From: "Erin E. Sullivan" Date: Tue, 22 Oct 2024 10:00:08 -0400 Subject: [PATCH 7/8] Setting advanced filters on load, based off of current URL parameters. --- .../components/FiltersContainer/index.js | 17 +++-- .../core/components/Multiselect/index.js | 74 +++++++++++++------ 2 files changed, 60 insertions(+), 31 deletions(-) diff --git a/src/modules/advanced/components/FiltersContainer/index.js b/src/modules/advanced/components/FiltersContainer/index.js index 20398377..9a6b8839 100644 --- a/src/modules/advanced/components/FiltersContainer/index.js +++ b/src/modules/advanced/components/FiltersContainer/index.js @@ -12,7 +12,7 @@ const FiltersContainer = ({ datastoreUid }) => { const { activeFilters, filters: filterGroups } = useSelector((state) => { return state.advanced[datastoreUid] || {}; }); - const filters = getFilters({ activeFilters, filterGroups }); + const advancedDatastoreFilters = getFilters({ activeFilters, filterGroups }); const changeAdvancedFilter = ({ filterGroupUid, filterType, filterValue }) => { switch (filterType) { @@ -56,11 +56,11 @@ const FiltersContainer = ({ datastoreUid }) => { } }; - if (filters?.length === 0) { + if (advancedDatastoreFilters?.length === 0) { return null; } - const filterGroupings = Object.keys(filters); + const filterGroupings = Object.keys(advancedDatastoreFilters); return ( <> @@ -72,13 +72,14 @@ const FiltersContainer = ({ datastoreUid }) => { {filterGroup === 'undefined' ? ( - filters[filterGroup].map((advancedFilter, index) => { + advancedDatastoreFilters[filterGroup].map((advancedFilter, index) => { + const { filters, name, type, uid } = advancedFilter; return (
-

{advancedFilter.name}

+

{name}

- {advancedFilter.type === 'multiple_select' - ? + {type === 'multiple_select' + ? : }
@@ -88,7 +89,7 @@ const FiltersContainer = ({ datastoreUid }) => { : (

{filterGroup}

- {filters[filterGroup].map((advancedFilter, index) => { + {advancedDatastoreFilters[filterGroup].map((advancedFilter, index) => { return ; })}
diff --git a/src/modules/core/components/Multiselect/index.js b/src/modules/core/components/Multiselect/index.js index e201d47d..bd43f5ef 100644 --- a/src/modules/core/components/Multiselect/index.js +++ b/src/modules/core/components/Multiselect/index.js @@ -1,23 +1,53 @@ import './styles.css'; -import React, { useMemo, useState } from 'react'; +import React, { useEffect, useMemo, useState } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; import PropTypes from 'prop-types'; import { setAdvancedFilter } from '../../../advanced'; -import { useDispatch } from 'react-redux'; -const Multiselect = ({ advancedFilter, datastoreUid }) => { +const Multiselect = ({ datastoreUid, filterGroupUid, filters = {}, name }) => { const dispatch = useDispatch(); const [filterQuery, setFilterQuery] = useState(''); const [showOnlySelectedOptions, setShowOnlySelectedOptions] = useState(false); + const { [filterGroupUid]: urlFilters = [] } = useSelector((state) => { + return state.filters.active[datastoreUid] || {}; + }); + const { [filterGroupUid]: advancedFilters = [] } = useSelector((state) => { + return state.advanced[datastoreUid].activeFilters || {}; + }); + const options = useMemo(() => { - return advancedFilter.filters.map(({ isActive, value }) => { + return filters.map(({ isActive, value }) => { return { checked: isActive, name: value, value }; }); - }, [advancedFilter.filters]); + }, [filters]); + + if (!options.length) { + return null; + } + + useEffect(() => { + // Make sure the URL filters and the advanced filters match on load + const currentFilters = [ + ...urlFilters.filter((urlFilter) => { + return !advancedFilters.includes(urlFilter); + }), + ...advancedFilters.filter((advancedFilter) => { + return !urlFilters.includes(advancedFilter); + }) + ]; + currentFilters.forEach((filterValue) => { + dispatch(setAdvancedFilter({ + datastoreUid, + filterGroupUid, + filterValue + })); + }); + }, []); const selectedOptions = useMemo(() => { return options.filter((option) => { @@ -25,33 +55,29 @@ const Multiselect = ({ advancedFilter, datastoreUid }) => { }); }, [options]); - const handleOptionSelection = (option) => { + const handleOptionSelection = ({ filterValue }) => { dispatch(setAdvancedFilter({ datastoreUid, - filterGroupUid: advancedFilter.uid, - filterValue: option.value + filterGroupUid, + filterValue })); if (showOnlySelectedOptions && selectedOptions.length === 1) { setShowOnlySelectedOptions(false); } }; - const isOptionFiltered = (name) => { - return filterQuery.length > 0 && !name.toLowerCase().includes(filterQuery.toLowerCase()); + const isOptionFiltered = ({ optionName }) => { + return filterQuery.length > 0 && !optionName.toLowerCase().includes(filterQuery.toLowerCase()); }; - if (!options.length) { - return null; - } - return (
-

Select one or more checkboxes to narrow your results to items that match all of your {advancedFilter.name.toLowerCase()} selections.

+

Select one or more checkboxes to narrow your results to items that match all of your {name.toLowerCase()} selections.

{ @@ -59,13 +85,13 @@ const Multiselect = ({ advancedFilter, datastoreUid }) => { }} autoComplete='on' /> -

Below this edit box is a list of check boxes that allow you to filter down your options. As you type in this edit box, the list of check boxes is updated to reflect only those that match the query typed in this box.

+

Below this edit box is a list of check boxes that allow you to filter down your options. As you type in this edit box, the list of check boxes is updated to reflect only those that match the query typed in this box.

Filter Options
    {options.map((option, index) => { - const { checked, name } = option; - if ((!showOnlySelectedOptions && isOptionFiltered(name)) || (showOnlySelectedOptions && !checked)) { + const { checked, name: optionName, value: filterValue } = option; + if ((!showOnlySelectedOptions && isOptionFiltered({ optionName })) || (showOnlySelectedOptions && !checked)) { return null; } return ( @@ -75,10 +101,10 @@ const Multiselect = ({ advancedFilter, datastoreUid }) => { type='checkbox' checked={checked} onChange={() => { - return handleOptionSelection(option); + return handleOptionSelection({ filterValue }); }} /> - {name} + {optionName} ); @@ -103,8 +129,10 @@ const Multiselect = ({ advancedFilter, datastoreUid }) => { }; Multiselect.propTypes = { - advancedFilter: PropTypes.object, - datastoreUid: PropTypes.string + datastoreUid: PropTypes.string, + filterGroupUid: PropTypes.string, + filters: PropTypes.array, + name: PropTypes.string }; export default Multiselect; From 5a5dec34d470738cf4e16fa38f9fc4e6ec3bb003 Mon Sep 17 00:00:00 2001 From: "Erin E. Sullivan" Date: Tue, 22 Oct 2024 10:14:57 -0400 Subject: [PATCH 8/8] Resolving duplicate label accessibility errors. --- src/modules/core/components/Multiselect/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/core/components/Multiselect/index.js b/src/modules/core/components/Multiselect/index.js index bd43f5ef..69eb968e 100644 --- a/src/modules/core/components/Multiselect/index.js +++ b/src/modules/core/components/Multiselect/index.js @@ -76,7 +76,7 @@ const Multiselect = ({ datastoreUid, filterGroupUid, filters = {}, name }) => {