Skip to content

Commit

Permalink
Merge pull request #105 from log0s/clickable-filters
Browse files Browse the repository at this point in the history
Clickable filters
  • Loading branch information
parksjr authored Oct 31, 2024
2 parents a9c9290 + 5c9b22b commit 631ef80
Show file tree
Hide file tree
Showing 8 changed files with 163 additions and 47 deletions.
8 changes: 4 additions & 4 deletions config/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ module.exports = {

coverageThreshold: {
global: {
branches: 35.36,
functions: 32.11,
lines: 41.35,
statements: 40.09
branches: 35.3,
functions: 31.85,
lines: 41.31,
statements: 40.07
}
},

Expand Down
13 changes: 13 additions & 0 deletions src/assets/stylesheets/components/_search-panel-filters.scss
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
}

}
6 changes: 5 additions & 1 deletion src/components/Lens/Lens.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ const Lens = ({
placeholder = 'Search',
availableFilters,
showFilters = true,
additionalFilterItems,
hideGeometryFilter = false,
availableLayers = null,
hideNativeLayers = true,
fetchLayerData,
Expand Down Expand Up @@ -182,7 +184,7 @@ const Lens = ({
</div>
)}
{displayFiltersPanel && (
<LensSearchPanelFilters hasFilterCancel={hasFilterCancel} />
<LensSearchPanelFilters hasFilterCancel={hasFilterCancel} hideGeometryFilter={hideGeometryFilter} additionalFilterItems={additionalFilterItems} />
)}
{SidebarComponents && (
<LensSidebarComponents SidebarComponents={SidebarComponents} />
Expand Down Expand Up @@ -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([
Expand Down
54 changes: 50 additions & 4 deletions src/components/LensSearchPanelFilters/LensSearchPanelFilters.js
Original file line number Diff line number Diff line change
@@ -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 () {
Expand All @@ -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 (
<SearchPanelFilters
filters={filters}
onOpenFilters={openFilters}
onCancelFilterChanges={cancelFilterChanges}
onSaveFiltersChanges={handleSaveFilters}
handleRemoveClick={handleRemoveFilter}
additionalFilterItems={additionalFilterItems}
{...props}
/>
);
};

LensSearchPanelFilters.propTypes = {
hideGeometryFilter: PropTypes.bool,
additionalFilterItems: PropTypes.array
};

export default LensSearchPanelFilters;
2 changes: 1 addition & 1 deletion src/components/SearchFilters/SearchFilters.js
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ const SearchFilters = ({
id={id}
label={label}
subLabel={subLabel}
value={value || defaultValue}
value={value || defaultValue || range}
range={range}
onChange={handleFilterChange}
/>
Expand Down
66 changes: 37 additions & 29 deletions src/components/SearchFiltersRange/SearchFiltersRange.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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:
}
Expand All @@ -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);
Expand All @@ -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);
};
}
}

/**
Expand Down Expand Up @@ -187,7 +195,7 @@ const SearchFiltersRange = ({
</div>
)}
<div className="search-filters-range">
<div className={`search-filters-range-input ${minError ? "min-error" : ""} ${maxError ? "max-error" : ""}`}>
<div className={`search-filters-range-input ${minError ? 'min-error' : ''} ${maxError ? 'max-error' : ''}`}>
<FormInputDebounced
id={`${namePrefix}-min`}
type="number"
Expand All @@ -202,8 +210,8 @@ const SearchFiltersRange = ({
value={Math.round(rangeValue.max * 100) / 100}
onChange={handleInputChange}
/>
<span className="error">{`${minError ? "Invalid Min Range" : ""}`}</span>
<span className="error">{`${maxError ? "Invalid Max Range" : ""}`}</span>
<span className="error">{`${minError ? 'Invalid Min Range' : ''}`}</span>
<span className="error">{`${maxError ? 'Invalid Max Range' : ''}`}</span>
</div>
<div className="search-filters-range-slider">
<InputRange
Expand Down
39 changes: 31 additions & 8 deletions src/components/SearchPanelFilters/SearchPanelFilters.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { FaPlus, FaCheck, FaTimes, FaEdit } from 'react-icons/fa';
import { findFilterById } from '../../lib/filters';
import { sortByKey } from '../../lib/util';

import Button from '../Button';
import Panel from '../Panel';
import PanelActions from '../PanelActions';
import { ALL_VALUES_ITEM } from '../../data/search-filters';
Expand All @@ -14,7 +15,9 @@ const SearchPanelFilters = ({
onOpenFilters,
onSaveFiltersChanges,
onCancelFilterChanges,
hasFilterCancel = true
hasFilterCancel = true,
additionalFilterItems = [],
handleRemoveClick
}) => {
const { active, isOpen, available } = filters;

Expand Down Expand Up @@ -104,6 +107,7 @@ const SearchPanelFilters = ({
value = `${value}`;

return {
id,
label,
value
};
Expand Down Expand Up @@ -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 (
<Panel
Expand All @@ -158,8 +162,25 @@ const SearchPanelFilters = ({
<span>{filter.label}</span>
</div>
<div className="table-cell table-row-first table-column-first table-cell-align-right column-value">
<span>{filter.value}</span>
<span style={{ verticalAlign: 'middle' }}>{filter.value}</span>
</div>
{(handleRemoveClick || filter.onClick) && (
<div className="table-cell" style={{ width: 'auto' }}>
<Button
className="search-panel-filters-list-item-remove"
onClick={() => {
if (filter.onClick) {
filter.onClick();
} else {
handleRemoveClick(filter.id);
}
}}
>
<span className="visually-hidden">Remove Filter</span>
<FaTimes />
</Button>
</div>
)}
</div>
))}
</div>
Expand All @@ -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;
Expand Down
Loading

0 comments on commit 631ef80

Please sign in to comment.