From dd2e0a4bf25d65b9dbc5ffa5939911749f218bb3 Mon Sep 17 00:00:00 2001 From: Ryan Herman Date: Thu, 17 Oct 2024 11:37:56 -0600 Subject: [PATCH] Add option to remove lens search panel filters with click and pass additional filters to display --- .../components/_search-panel-filters.scss | 13 ++++ src/components/Lens/Lens.js | 6 +- .../LensSearchPanelFilters.js | 54 +++++++++++++-- src/components/SearchFilters/SearchFilters.js | 2 +- .../SearchFiltersRange/SearchFiltersRange.js | 66 +++++++++++-------- .../SearchPanelFilters/SearchPanelFilters.js | 39 ++++++++--- src/hooks/useGeoFilters.js | 22 +++++++ 7 files changed, 159 insertions(+), 43 deletions(-) diff --git a/src/assets/stylesheets/components/_search-panel-filters.scss b/src/assets/stylesheets/components/_search-panel-filters.scss index dd1f5dd4..70f3cade 100644 --- a/src/assets/stylesheets/components/_search-panel-filters.scss +++ b/src/assets/stylesheets/components/_search-panel-filters.scss @@ -26,6 +26,19 @@ border-bottom: none; } } + + .search-panel-filters-list-item-remove { + background: transparent; + box-shadow: none; + font-size: 0.8em; + height: 100%; + display: flex; + + button { + padding: 0; + color: black; + } + } } } diff --git a/src/components/Lens/Lens.js b/src/components/Lens/Lens.js index 8a924736..5276ba8f 100644 --- a/src/components/Lens/Lens.js +++ b/src/components/Lens/Lens.js @@ -34,6 +34,8 @@ const Lens = ({ placeholder = 'Search', availableFilters, showFilters = true, + additionalFilterItems, + hideGeometryFilter = false, availableLayers = null, hideNativeLayers = true, fetchLayerData, @@ -182,7 +184,7 @@ const Lens = ({ )} {displayFiltersPanel && ( - + )} {SidebarComponents && ( @@ -252,6 +254,8 @@ Lens.propTypes = { searchType: PropTypes.string, placeholder: PropTypes.string, showFilters: PropTypes.bool, + hideGeometryFilter: PropTypes.bool, + additionalFilterItems: PropTypes.array, availableFilters: PropTypes.array, hideNativeLayers: PropTypes.bool, fetchLayerData: PropTypes.oneOfType([ diff --git a/src/components/LensSearchPanelFilters/LensSearchPanelFilters.js b/src/components/LensSearchPanelFilters/LensSearchPanelFilters.js index 0e779f22..74494c8b 100644 --- a/src/components/LensSearchPanelFilters/LensSearchPanelFilters.js +++ b/src/components/LensSearchPanelFilters/LensSearchPanelFilters.js @@ -1,17 +1,19 @@ import React from 'react'; +import PropTypes from 'prop-types'; import { useLens } from '../../hooks'; import SearchPanelFilters from '../SearchPanelFilters'; -const LensSearchPanelFilters = (props) => { - const { geoSearch = {}, geoFilters = {} } = useLens(); - const { updateSearch } = geoSearch; +const LensSearchPanelFilters = ({ hideGeometryFilter = false, additionalFilterItems = [], ...props }) => { + const { map = {}, geoSearch = {}, geoFilters = {} } = useLens(); + const { queryParams: { date, geoJson } = {}, updateSearch } = geoSearch; const { filters = {}, openFilters, cancelFilterChanges, - saveFilterChanges + saveFilterChanges, + removeSingleFilter } = geoFilters; function handleSaveFilters () { @@ -23,15 +25,59 @@ const LensSearchPanelFilters = (props) => { }); } + function handleRemoveFilter (filterId) { + const { active } = removeSingleFilter(filterId); + updateSearch({ + filters: active + }); + } + + additionalFilterItems = additionalFilterItems.map(({ onClickParams, ...rest }) => ({ + ...rest, + onClick: onClickParams && (() => { + map.clearLayers(); + updateSearch(onClickParams); + }) + })); + + if (!hideGeometryFilter && geoJson && geoJson.features && geoJson.features[0]) { + additionalFilterItems.push({ + label: 'Geometry', + value: geoJson.features[0].geometry.type === 'Point' ? 'POINT' : 'POLYGON', + onClick: () => { + map.clearLayers(); + updateSearch({ geoJson: {} }); + } + }); + } + + if (date && (date.start || date.end)) { + additionalFilterItems.push({ + label: 'Datetime', + value: `${(date.start && new Date(date.start).toISOString()) || 'Any'} to ${(date.end && new Date(date.end).toISOString()) || 'Any'}`, + onClick: () => { + map.clearLayers(); + updateSearch({ date: {} }); + } + }); + } + return ( ); }; +LensSearchPanelFilters.propTypes = { + hideGeometryFilter: PropTypes.bool, + additionalFilterItems: PropTypes.array +}; + export default LensSearchPanelFilters; diff --git a/src/components/SearchFilters/SearchFilters.js b/src/components/SearchFilters/SearchFilters.js index ccafd290..c1f3d492 100644 --- a/src/components/SearchFilters/SearchFilters.js +++ b/src/components/SearchFilters/SearchFilters.js @@ -172,7 +172,7 @@ const SearchFilters = ({ id={id} label={label} subLabel={subLabel} - value={value || defaultValue} + value={value || defaultValue || range} range={range} onChange={handleFilterChange} /> diff --git a/src/components/SearchFiltersRange/SearchFiltersRange.js b/src/components/SearchFiltersRange/SearchFiltersRange.js index 9548e1bd..9dfc3b1b 100644 --- a/src/components/SearchFiltersRange/SearchFiltersRange.js +++ b/src/components/SearchFiltersRange/SearchFiltersRange.js @@ -28,14 +28,23 @@ const SearchFiltersRange = ({ const [rangeValue, setRangeValue] = useState(value); useEffect(() => { - if ( maxError === true ) { - handleInputChange({target : { id: 'incidence_angle-range-max', value: valueMaxLocal.toString() }}); + if (maxError === true) { + handleInputChange({ target: { id: 'incidence_angle-range-max', value: valueMaxLocal.toString() } }); } - if ( minError === true ) { - handleInputChange({target : { id: 'incidence_angle-range-min', value: valueMinLocal.toString() }}); + if (minError === true) { + handleInputChange({ target: { id: 'incidence_angle-range-min', value: valueMinLocal.toString() } }); } }, [valueMinLocal, valueMaxLocal, rangeValue]); + useEffect(() => { + const { min, max } = value; + if ((min && (rangeValue.min !== min)) || (max && (rangeValue.max !== max))) { + setValueMinLocal(min); + setValueMaxLocal(max); + setRangeValue({ min, max }); + } + }, [value]); + /** * handleInputChange * @description When the text inputs change, fire away @@ -70,20 +79,20 @@ const SearchFiltersRange = ({ if (floatValue < range.min || floatValue > range.max || floatValue > valueMaxLocal) { updateMinErrorState(true); return; - } else { - updateMinErrorState(false); - setRangeValue({min: floatValue, max: rangeValue.max}); - }; + } else { + updateMinErrorState(false); + setRangeValue({ min: floatValue, max: rangeValue.max }); + } break; case 'max': setValueMaxLocal(floatValue); if (floatValue > range.max || floatValue < range.min || floatValue < valueMinLocal) { updateMaxErrorState(true); return; - } else { + } else { updateMaxErrorState(false); - setRangeValue({min: rangeValue.min, max: floatValue}); - }; + setRangeValue({ min: rangeValue.min, max: floatValue }); + } break; default: } @@ -102,14 +111,14 @@ const SearchFiltersRange = ({ function handleOnSliderChange (updatedValue) { handleOnChange(updatedValue); - let cleanedValues = updatedValue; + const cleanedValues = updatedValue; const { min, max } = cleanedValues; - if ( parseInt(min) % 1 !== 0 ) { - cleanedValues.min = parseInt(parseFloat(cleanedValues.min).toFixed(2)); - }; - if ( parseInt(max) % 1 !== 0 ) { - cleanedValues.max = parseInt(parseFloat(cleanedValues.max).toFixed(2)); - }; + if (parseInt(min) % 1 !== 0) { + cleanedValues.min = parseInt(parseFloat(cleanedValues.min).toFixed(2)); + } + if (parseInt(max) % 1 !== 0) { + cleanedValues.max = parseInt(parseFloat(cleanedValues.max).toFixed(2)); + } setValueMaxLocal(cleanedValues.max); setValueMinLocal(cleanedValues.min); @@ -118,18 +127,17 @@ const SearchFiltersRange = ({ if (cleanedValues.min < range.min || cleanedValues.min > range.max) { updateMinErrorState(true); return; - } else { - updateMinErrorState(false); - setRangeValue(cleanedValues); - }; + } else { + updateMinErrorState(false); + setRangeValue(cleanedValues); + } - if (cleanedValues.max > range.max|| cleanedValues.max < range.min) { + if (cleanedValues.max > range.max || cleanedValues.max < range.min) { updateMaxErrorState(true); - return; - } else { + } else { updateMaxErrorState(false); setRangeValue(cleanedValues); - }; + } } /** @@ -187,7 +195,7 @@ const SearchFiltersRange = ({ )}
-
+
- {`${minError ? "Invalid Min Range" : ""}`} - {`${maxError ? "Invalid Max Range" : ""}`} + {`${minError ? 'Invalid Min Range' : ''}`} + {`${maxError ? 'Invalid Max Range' : ''}`}
{ const { active, isOpen, available } = filters; @@ -104,6 +107,7 @@ const SearchPanelFilters = ({ value = `${value}`; return { + id, label, value }; @@ -134,15 +138,15 @@ const SearchPanelFilters = ({ function hasActiveFilters (filters) { const availableValues = filters.map(({ value } = {}) => value); - return availableValues.filter((value) => valueIsValid(value)).length > 0; + return (availableValues.filter((value) => valueIsValid(value)).length > 0 || additionalFilterItems.length > 0); } - const panelFiltersMapped = - panelFilters && - panelFilters + const panelFiltersMapped = additionalFilterItems.concat( + (panelFilters || []) .filter(filterActiveFiltersNoValue) .filter(({ type } = {}) => type !== 'hidden') - .map(mapActiveFiltersToRow); + .map(mapActiveFiltersToRow) + ); return ( {filter.label}
- {filter.value} + {filter.value}
+ {(handleRemoveClick || filter.onClick) && ( +
+ +
+ )}
))}
@@ -173,7 +194,9 @@ SearchPanelFilters.propTypes = { onOpenFilters: PropTypes.func, onSaveFiltersChanges: PropTypes.func, onCancelFilterChanges: PropTypes.func, - hasFilterCancel: PropTypes.bool + hasFilterCancel: PropTypes.bool, + additionalFilterItems: PropTypes.array, + handleRemoveClick: PropTypes.func }; export default SearchPanelFilters; diff --git a/src/hooks/useGeoFilters.js b/src/hooks/useGeoFilters.js index c719eb98..aaa25e81 100644 --- a/src/hooks/useGeoFilters.js +++ b/src/hooks/useGeoFilters.js @@ -117,6 +117,27 @@ export default function useGeoFilters (filterSettings) { return setActiveFilters(newFilters, options); } + /** + * removeSingleFilter + * @description Disables a single activated filter + */ + + function removeSingleFilter (filterId) { + const updatedFilterState = { + ...filters, + active: filters.active.filter(({ id } = {}) => id !== filterId), + unsaved: filters.unsaved.filter(({ id } = {}) => id !== filterId), + available: filters.available.map(filterInstance => ({ + ...filterInstance, + value: filterInstance.id === filterId ? undefined : filterInstance.value + })) + }; + + updateFilters(updatedFilterState); + + return updatedFilterState; + } + /** * saveFilterChanges * @description Stores any new unsaved changes to active and clears unsaved @@ -225,6 +246,7 @@ export default function useGeoFilters (filterSettings) { saveFilterChanges, setActiveFilters, addActiveFilters, + removeSingleFilter, cancelFilterChanges, clearActiveFilters };