Skip to content

Commit

Permalink
DATAP-1471 - convert aggregationItem class to functional component (#521
Browse files Browse the repository at this point in the history
)

* Initial conversion to functional component

* Removed or replaced references to old AggregationItem component and its tests

* Added new unit tests

* Moved IntlProvider to test, instead of actual component

* Added proper unit tests, using RTL for triggers

* Changed variable 'active' name to 'isActive'

* took out old import to AggregationItem in AggregationBranch component

* fixed remove filter unit test

* added command to run on UTC time zone

---------

Co-authored-by: cdhenley219 <chanel.henley@cfpb.gov>
  • Loading branch information
cdmh219 and cdhenley219 authored Jul 29, 2024
1 parent d6d8bc6 commit c47b059
Show file tree
Hide file tree
Showing 10 changed files with 454 additions and 459 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"prepare": "husky",
"release": "yarn run build && release-it --npm.skipChecks",
"start": "NODE_ENV=development craco start",
"test": "craco test --coverage --watchAll=false"
"test": "TZ=UTC craco test --coverage --watchAll=false"
},
"browserslist": "> 0.2% in @cfpb/browserslist-config stats",
"devDependencies": {
Expand Down
2 changes: 1 addition & 1 deletion src/components/Filters/AggregationBranch.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
slugify,
} from '../../utils';
import { removeMultipleFilters, replaceFilters } from '../../actions/filter';
import AggregationItem from './AggregationItem';
import AggregationItem from './AggregationItem/AggregationItem';
import { connect } from 'react-redux';
import { FormattedNumber } from 'react-intl';
import getIcon from '../iconMap';
Expand Down
143 changes: 0 additions & 143 deletions src/components/Filters/AggregationItem.js

This file was deleted.

126 changes: 126 additions & 0 deletions src/components/Filters/AggregationItem/AggregationItem.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import PropTypes from 'prop-types';
import { useSelector, useDispatch } from 'react-redux';
import { FormattedNumber } from 'react-intl';
import { filterPatch, SLUG_SEPARATOR } from '../../../constants';
import { coalesce, sanitizeHtmlId } from '../../../utils';
import { arrayEquals } from '../../../utils/compare';
import { replaceFilters, toggleFilter } from '../../../actions/filter';
import { getUpdatedFilters } from '../../../utils/filters';
import { selectAggsState } from '../../../reducers/aggs/selectors';
import { selectQueryState } from '../../../reducers/query/selectors';

const appliedFilters = ({ fieldName, item, aggs, filters }) => {
// We should find the parent
// determine if the other siblings are already checked
// check the parent only, and uncheck the rest so that the fake check
// will take affect
const [parentFilter, childFilter] = item.key.split(SLUG_SEPARATOR);
/* eslint-disable no-unexpected-multiline */
// TODO: reformat to not need the unexpected multiline.
const subItems = aggs
.find((agg) => agg.key === parentFilter)
['sub_' + fieldName + '.raw'].buckets.map((agg) => agg.key)
.sort();
/* eslint-enable no-unexpected-multiline */

const parentKey = parentFilter + SLUG_SEPARATOR;
const selectedFilters = filters
.filter((filter) => filter.indexOf(parentKey) > -1)
.map((filter) => filter.replace(parentKey, ''));
selectedFilters.push(childFilter);

selectedFilters.sort();

if (arrayEquals(selectedFilters, subItems)) {
// remove subitems, add parent filter
return filters
.filter((filter) => filter.indexOf(parentKey) === -1)
.concat(parentFilter);
} else {
// just add the single filter and apply filters
return filters.concat(item.key);
}
};

const AggregationItem = ({ fieldName, item }) => {
const aggsState = useSelector(selectAggsState);
const queryState = useSelector(selectQueryState);
const dispatch = useDispatch();

const aggs = coalesce(aggsState, fieldName, []);
const filters = coalesce(queryState, fieldName, []);
const isActive =
filters.includes(item.key) ||
filters.includes(item.key.split(SLUG_SEPARATOR)[0]);

const value = item.value || item.key;
const liStyle = 'layout-row m-form-field m-form-field--checkbox';
const id = sanitizeHtmlId(fieldName + '-' + item.key);

const addFilter = () => {
const isChildItem = item.key.indexOf(SLUG_SEPARATOR) > -1;
// cases where its issue / product
if (isChildItem && filterPatch.includes(fieldName)) {
const filtersToApply = appliedFilters({ fieldName, item, aggs, filters });
dispatch(replaceFilters(fieldName, filtersToApply));
} else {
dispatch(toggleFilter(fieldName, item));
}
};

const removeFilter = () => {
if (filterPatch.includes(fieldName)) {
const filterName = item.key;
const updatedFilters = getUpdatedFilters(
filterName,
filters,
aggs,
fieldName,
);
dispatch(replaceFilters(fieldName, updatedFilters));
} else {
dispatch(toggleFilter(fieldName, item));
}
};

const onChange = () => {
if (isActive) {
removeFilter();
} else {
addFilter();
}
};

return (
<li className={liStyle}>
<input
type="checkbox"
className="flex-fixed a-checkbox"
aria-label={item.key}
disabled={item.isDisabled}
checked={isActive}
id={id}
onChange={onChange}
/>
<label className="a-label flex-all bucket-key body-copy" htmlFor={id}>
{value}
</label>
<span className="flex-fixed bucket-count">
<FormattedNumber value={item.doc_count} />
</span>
</li>
);
};

AggregationItem.propTypes = {
fieldName: PropTypes.string.isRequired,
item: PropTypes.shape({
// eslint-disable-next-line camelcase
doc_count: PropTypes.number.isRequired,
key: PropTypes.string.isRequired,
value: PropTypes.string,
isDisabled: PropTypes.bool,
}).isRequired,
};

export default AggregationItem;
Loading

0 comments on commit c47b059

Please sign in to comment.