Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clickable filters #105

Merged
merged 2 commits into from
Oct 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading