Skip to content

Commit

Permalink
Merge pull request #498 from mlibrary/LIBSEARCH-801-part-3
Browse files Browse the repository at this point in the history
[LIBSEARCH-801] Implement "clear active filters" designs for advanced search (Part 3)
  • Loading branch information
erinesullivan authored Oct 22, 2024
2 parents 7f3102c + 5a5dec3 commit e2b4cbf
Show file tree
Hide file tree
Showing 11 changed files with 248 additions and 258 deletions.
74 changes: 74 additions & 0 deletions src/modules/advanced/components/ActiveAdvancedFilters/index.js
Original file line number Diff line number Diff line change
@@ -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 (
<section aria-label='active-filters'>
<h2
id='active-filters'
className='u-margin-top-none margin-bottom__xs h4'
>
Active filters
{' '}
<span className='text-grey__light padding-right__xs'>
({items.length})
</span>
</h2>

<p className='font-small u-margin-top-none'>
Unselect active filters through the options below.
</p>

<ul className='margin-top__none active-filter-list'>
{items.map((item, index) => {
return (
<li key={index + item.group + item.value}>
<span className='strong'>{filterGroups[item.group]?.name || titleCase(item.group)}:</span> {item.value}
</li>
);
})}
</ul>
</section>
);
};

ActiveAdvancedFilters.propTypes = {
activeFilters: PropTypes.object,
filters: PropTypes.array
};

export default ActiveAdvancedFilters;
26 changes: 1 addition & 25 deletions src/modules/advanced/components/AdvancedFilter/index.js
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -127,30 +127,6 @@ 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 (
<Multiselect
options={options}
filterGroupUid={advancedFilter.uid}
descriptionText={`Select one or more checkboxes to narrow your results to items that match all of your ${advancedFilter.name.toLowerCase()} selections.`}
handleSelection={(index, option) => {
return changeAdvancedFilter({
filterGroupUid: advancedFilter.uid,
filterType: advancedFilter.type,
filterValue: option.value
});
}}
/>
);
}
if (advancedFilter.type === 'date_range_input') {
const { stateSelectedRangeOption, stateBeginQuery, stateEndQuery } = getStateDateRangeValues({ advancedFilter });

Expand Down
9 changes: 2 additions & 7 deletions src/modules/advanced/components/AdvancedSearchForm/index.js
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -112,12 +112,7 @@ const AdvancedSearchForm = ({ datastore }) => {
Add another field
</button>

<button
className='btn btn--primary margin-top__m'
type='submit'
>
<Icon icon='search' size={24} /> Advanced Search
</button>
<AdvancedSearchSubmit />

<FiltersContainer {...{ datastoreUid }} />
</form>
Expand Down
15 changes: 15 additions & 0 deletions src/modules/advanced/components/AdvancedSearchSubmit/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Icon } from '../../../reusable';
import React from 'react';

const AdvancedSearchSubmit = () => {
return (
<button
className='btn btn--primary margin-top__m'
type='submit'
>
<Icon icon='search' size={24} /> Advanced Search
</button>
);
};

export default AdvancedSearchSubmit;
125 changes: 16 additions & 109 deletions src/modules/advanced/components/FiltersContainer/index.js
Original file line number Diff line number Diff line change
@@ -1,93 +1,18 @@
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 { Icon } from '../../../reusable';
import { Multiselect } from '../../../core';
import PropTypes from 'prop-types';
import React from 'react';
import { setAdvancedFilter } from '../../../advanced';

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 (
<section aria-label='active-filters'>
<h2
id='active-filters'
className='u-margin-top-none margin-bottom__xs h4'
>
Active filters
{' '}
<span className='text-grey__light padding-right__xs'>
({items.length})
</span>
</h2>

<p className='font-small u-margin-top-none'>
Unselect active filters through the options below.
</p>

<ul className='margin-top__none active-filter-list'>
{items.map((item, index) => {
return (
<li key={index + item.group + item.value}>
<span className='strong'>{filterGroups[item.group]?.name || titleCase(item.group)}:</span> {item.value}
</li>
);
})}
</ul>
</section>
);
};

ActiveAdvancedFilters.propTypes = {
datastoreUid: PropTypes.string
};

const FiltersContainer = ({ datastoreUid }) => {
const dispatch = useDispatch();
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) {
Expand Down Expand Up @@ -126,43 +51,36 @@ const FiltersContainer = ({ datastoreUid }) => {
onlyOneFilterValue: true
}));
break;
case 'multiple_select':
dispatch(setAdvancedFilter({
datastoreUid,
filterGroupUid,
filterValue
}));
break;
default:
break;
}
};

if (filters?.length === 0) {
if (advancedDatastoreFilters?.length === 0) {
return null;
}

const filterGroupings = Object.keys(filters);
const filterGroupings = Object.keys(advancedDatastoreFilters);

return (
<>
<ActiveAdvancedFilters datastoreUid={datastoreUid} />
{activeFilters && <ActiveAdvancedFilters {...{ activeFilters, filters: filterGroups }} />}
<h2 className='heading-large'>Additional search options</h2>
<div className='advanced-filters-inner-container'>
{filterGroupings.map((filterGroup, groupIndex) => {
return (
<React.Fragment key={groupIndex}>
{filterGroup === 'undefined'
? (
filters[filterGroup].map((advancedFilter, index) => {
advancedDatastoreFilters[filterGroup].map((advancedFilter, index) => {
const { filters, name, type, uid } = advancedFilter;
return (
<div key={index} className='advanced-filter-container'>
<h2 className='advanced-filter-label-text'>{advancedFilter.name}</h2>
<h2 className='advanced-filter-label-text'>{name}</h2>
<div className='advanced-filter-inner-container'>
<AdvancedFilter
advancedFilter={advancedFilter}
changeAdvancedFilter={changeAdvancedFilter}
/>
{type === 'multiple_select'
? <Multiselect {...{ datastoreUid, filterGroupUid: uid, filters, name }} />
: <AdvancedFilter {...{ advancedFilter, changeAdvancedFilter }} />}
</div>
</div>
);
Expand All @@ -171,27 +89,16 @@ const FiltersContainer = ({ datastoreUid }) => {
: (
<div className='advanced-filter-container'>
<h2 className='advanced-filter-label-text'>{filterGroup}</h2>
{filters[filterGroup].map((advancedFilter, index) => {
return (
<AdvancedFilter
key={index}
advancedFilter={advancedFilter}
changeAdvancedFilter={changeAdvancedFilter}
/>
);
{advancedDatastoreFilters[filterGroup].map((advancedFilter, index) => {
return <AdvancedFilter key={index} {...{ advancedFilter, changeAdvancedFilter }} />;
})}
</div>
)}
</React.Fragment>
);
})}
</div>
<button
className='btn btn--primary margin-top__m'
type='submit'
>
<Icon icon='search' size={24} /> Advanced Search
</button>
<AdvancedSearchSubmit />
</>
);
};
Expand Down
2 changes: 2 additions & 0 deletions src/modules/advanced/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
} from './actions';
import advancedReducer from './reducer';
import AdvancedSearch from './components/AdvancedSearchContainer';
import AdvancedSearchSubmit from './components/AdvancedSearchSubmit';

export {
addAdvancedBooleanTypes,
Expand All @@ -17,6 +18,7 @@ export {
addFieldedSearch,
advancedReducer,
AdvancedSearch,
AdvancedSearchSubmit,
removeFieldedSearch,
setAdvancedFilter,
setFieldedSearch
Expand Down
Loading

0 comments on commit e2b4cbf

Please sign in to comment.