Refactored filter list for display; converting filter paths to node, child objects that are toggleable

This commit is contained in:
efarooqui
2020-09-01 09:33:05 -07:00
parent 2aaf7c09ff
commit 6492be18d9
5 changed files with 48 additions and 29 deletions

2
src/common/constants.js Normal file
View File

@@ -0,0 +1,2 @@
export const FILTER_MODE = 'FILTER'
export const NARRATIVE_MODE = 'NARRATIVE'

View File

@@ -3,57 +3,73 @@ import Checkbox from '../presentational/Checkbox'
import copy from '../../common/data/copy.json'
/** recursively get an array of node keys to toggle */
function childrenToToggle (node, activeFilters, parentOn) {
const isOn = activeFilters.includes(node.key)
if (!node.children) {
return [node.key]
function childrenToToggle (filter, activeFilters, parentOn) {
const [key, children] = filter
const isOn = activeFilters.includes(key)
if (children === {}) {
return [key]
}
const childKeys = Object.values(node.children)
.flatMap(n => childrenToToggle(n, activeFilters, isOn))
const childKeys = Object.entries(children)
.flatMap(filter => childrenToToggle(filter, activeFilters, isOn))
// NB: if turning a parent off, don't toggle off children on.
// likewise if turning a parent on, don't toggle on children off
if (!((!parentOn && isOn) || (parentOn && !isOn))) {
childKeys.push(node.key)
childKeys.push(key)
}
return childKeys
}
function aggregatePaths (filters) {
const aggregated = {}
filters.forEach(item => {
let currentDepth = aggregated
item.filter_paths.forEach(path => {
if (!(path in aggregated)) {
currentDepth[path] = {}
}
currentDepth = currentDepth[path]
})
})
return aggregated
}
function FilterListPanel ({
filters,
activeFilters,
onSelectFilter,
language
}) {
function createNodeComponent (node, depth) {
const matchingKeys = childrenToToggle(node, activeFilters, activeFilters.includes(node.key))
const children = Object.values(node.children)
function createNodeComponent (filter, depth) {
const [key, children] = filter
const matchingKeys = childrenToToggle(filter, activeFilters, activeFilters.includes(key))
return (
<li
key={node.key.replace(/ /g, '_')}
key={key.replace(/ /g, '_')}
className={'filter-filter'}
style={{ marginLeft: `${depth * 20}px` }}
>
{/* <svg width='10' height='10'> */}
{/* <g className='filter-inline'> */}
{/* <path d='M0,-7.847549217020565L6.796176979388489,3.9237746085102825L-6.796176979388489,3.9237746085102825Z' transform='rotate(270)' /> */}
{/* </g> */}
{/* </svg> */}
<Checkbox
label={node.key}
isActive={activeFilters.includes(node.key)}
label={key}
isActive={activeFilters.includes(key)}
onClickCheckbox={() => onSelectFilter(matchingKeys)}
/>
{children.length > 0
? children.map(filter => createNodeComponent(filter, depth + 1))
{Object.keys(children).length > 0
? Object.entries(children).map(filter => createNodeComponent(filter, depth + 1))
: null}
</li>
)
}
function renderTree (children) {
function renderTree (filters) {
const aggregatedFilterPaths = aggregatePaths(filters)
console.info(aggregatedFilterPaths)
return (
<div>
{Object.values(children).map(filter => createNodeComponent(filter, 1))}
{Object.entries(aggregatedFilterPaths).map(filter => createNodeComponent(filter, 1))}
</div>
)
}
@@ -62,7 +78,7 @@ function FilterListPanel ({
<div className='react-innertabpanel'>
<h2>{copy[language].toolbar.filters}</h2>
<p>{copy[language].toolbar.explore_by_filter__description}</p>
{renderTree(filters.children)}
{renderTree(filters)}
</div>
)
}

View File

@@ -197,7 +197,7 @@ class Toolbar extends React.Component {
function mapStateToProps (state) {
return {
filters: selectors.getFilterTree(state),
filters: selectors.getFilters(state),
categories: selectors.getCategories(state),
narratives: selectors.selectNarratives(state),
language: state.app.language,

View File

@@ -114,7 +114,7 @@ function toggleFilter (appState, action) {
action.value = [action.value]
}
let newFilters = appState.filters[action.filter].slice(0)
let newFilters = appState.associations.filters.slice(0)
action.value.forEach(vl => {
if (newFilters.includes(vl)) {
newFilters = newFilters.filter(s => s !== vl)
@@ -125,9 +125,9 @@ function toggleFilter (appState, action) {
return {
...appState,
filters: {
...appState.filters,
[action.filter]: newFilters
associations: {
...appState.associations,
filters: newFilters,
}
}
}

View File

@@ -1,6 +1,7 @@
import { createSelector } from 'reselect'
import { insetSourceFrom, dateMin, dateMax } from '../common/utilities'
import { isTimeRangedIn } from './helpers'
import { FILTER_MODE } from '../common/constants'
// Input selectors
export const getEvents = state => state.domain.events
@@ -11,8 +12,8 @@ export const getSelected = state => state.app.selected
export const getSites = state => state.domain.sites
export const getSources = state => state.domain.sources
export const getShapes = state => state.domain.shapes
export const getFilters = state => state.domain.associations.filter(item => item.mode === FILTER_MODE)
export const getNotifications = state => state.domain.notifications
export const getFilterTree = state => state.domain.filters
export const getActiveFilters = state => state.app.associations.filters
export const getActiveCategories = state => state.app.associations.categories
export const getTimeRange = state => state.app.timeline.range