clean tag representation and filtering

This commit is contained in:
Lachlan Kermode
2019-02-14 14:27:36 +00:00
parent aba8537357
commit 4e9128476d
12 changed files with 224 additions and 225 deletions

View File

@@ -120,7 +120,7 @@ class Dashboard extends React.Component {
<Toolbar
isNarrative={!!app.narrative}
methods={{
onTagFilter: actions.updateTagFilters,
onTagFilter: actions.toggleTagFilter,
onCategoryFilter: actions.updateCategoryFilters,
onSelectNarrative: this.setNarrative
}}

View File

@@ -203,7 +203,7 @@ class Map extends React.Component {
return (
<Events
svg={this.svgRef.current}
locations={this.props.domain.locations}
locations={this.props.domain.visibleLocations}
styleLocation={this.styleLocation}
categories={this.props.domain.categories}
projectPoint={this.projectPoint}
@@ -245,7 +245,7 @@ class Map extends React.Component {
{this.renderShapes()}
{this.renderNarratives()}
{this.renderEvents()}
{this.renderSelected()}
{this.renderSelected()}
</React.Fragment>
) : null
@@ -261,7 +261,7 @@ class Map extends React.Component {
function mapStateToProps (state) {
return {
domain: {
locations: selectors.selectLocations(state),
visibleLocations: selectors.selectVisibleLocations(state),
narratives: selectors.selectNarratives(state),
categories: selectors.selectCategories(state),
sites: selectors.getSites(state),

View File

@@ -1,7 +1,7 @@
/* global fetch */
import React from 'react'
import copy from '../js/data/copy.json'
import TagFilter from './TagFilter.jsx'
import TagFilter from './TagFilter'
export default class Search extends React.Component {
constructor (props) {

View File

@@ -0,0 +1,82 @@
import React from 'react'
import Checkbox from './presentational/Checkbox'
function TagFilter (props) {
function isActive () {
if (props.isCategory) {
return props.categoryFilters.includes(props.tag.id)
}
return props.tagFilters.includes(props.tag.id)
}
function onClickTag () {
if (isActive()) {
props.filter({
tags: props.tagFilters.filter(element => element !== props.tag.id)
})
} else {
props.filter({
tags: props.tagFilters.concat(props.tag.id)
})
}
}
function onClickCategory () {
if (isActive()) {
props.filter({
categories: props.categoryFilters.filter(element => element !== props.tag.id)
})
} else {
props.filter({
categories: props.categoryFilters.concat(props.tag.id)
})
}
}
function renderTag () {
const tag = props.tag
let classes = (isActive()) ? 'tag-filter active' : 'tag-filter'
let label = `${tag.name} ( ${tag.mentions} )`
if (props.isShowTree) {
label = `${tag.group} > ${tag.subgroup} > ${tag.name} ( ${tag.mentions} )`
}
return (
<li
key={props.tag.id}
className={classes}
>
<Checkbox
isActive={isActive()}
label={label}
onClickCheckbox={() => onClickTag()}
/>
</li>
)
}
function renderCategory () {
const category = props.categories[props.tag.id]
let classes = (isActive()) ? 'tag-filter active' : 'tag-filter'
if (category) {
return (
<li
key={props.tag.id}
className={classes}
>
<Checkbox
isActive={isActive()}
label={`${category.name} ( ${category.counts} )`}
onClickCheckbox={onClickCategory}
/>
</li>
)
}
return (<div />)
}
if (props.isCategory) return (renderCategory())
return (renderTag())
}
export default TagFilter

View File

@@ -1,84 +0,0 @@
import React from 'react'
import Checkbox from './presentational/Checkbox'
class TagFilter extends React.Component {
isActive () {
if (this.props.isCategory) {
return this.props.categoryFilters.includes(this.props.tag.id)
}
return this.props.tagFilters.includes(this.props.tag.id)
}
onClickTag () {
if (this.isActive()) {
this.props.filter({
tags: this.props.tagFilters.filter(element => element !== this.props.tag.id)
})
} else {
this.props.filter({
tags: this.props.tagFilters.concat(this.props.tag.id)
})
}
}
onClickCategory () {
if (this.isActive()) {
this.props.filter({
categories: this.props.categoryFilters.filter(element => element !== this.props.tag.id)
})
} else {
this.props.filter({
categories: this.props.categoryFilters.concat(this.props.tag.id)
})
}
}
renderTag () {
const tag = this.props.tag
let classes = (this.isActive()) ? 'tag-filter active' : 'tag-filter'
let label = `${tag.name} ( ${tag.mentions} )`
if (this.props.isShowTree) {
label = `${tag.group} > ${tag.subgroup} > ${tag.name} ( ${tag.mentions} )`
}
return (
<li
key={this.props.tag.id}
className={classes}
>
<Checkbox
isActive={this.isActive()}
label={label}
onClickCheckbox={() => this.onClickTag()}
/>
</li>
)
}
renderCategory () {
const category = this.props.categories[this.props.tag.id]
let classes = (this.isActive()) ? 'tag-filter active' : 'tag-filter'
if (category) {
return (
<li
key={this.props.tag.id}
className={classes}
>
<Checkbox
isActive={this.isActive()}
label={`${category.name} ( ${category.counts} )`}
onClickCheckbox={() => this.onClickCategory()}
/>
</li>
)
}
return (<div />)
}
render () {
if (this.props.isCategory) return (this.renderCategory())
return (this.renderTag())
}
}
export default TagFilter

View File

@@ -0,0 +1,45 @@
import React from 'react'
import Checkbox from './presentational/Checkbox'
import copy from '../js/data/copy.json'
function TagListPanel ({
tags,
tagFilters,
onTagFilter,
language
}) {
function createNodeComponent (node, depth) {
return (
<li
key={node.key.replace(/ /g, '_')}
className={'tag-filter active'}
style={{ marginLeft: `${depth * 20}px` }}
>
<Checkbox
label={node.key}
isActive={tagFilters.includes(node.key)}
onClickCheckbox={() => onTagFilter(node.key)}
/>
</li>
)
}
function renderTree () {
/* NOTE: only render first layer of tags */
return (
<div>
{Object.values(tags.children).map(tag => createNodeComponent(tag, 1))}
</div>
)
}
return (
<div className='react-innertabpanel'>
<h2>{copy[language].toolbar.tags}</h2>
<p>{copy[language].toolbar.explore_by_tag__description}</p>
{renderTree()}
</div>
)
}
export default TagListPanel

View File

@@ -1,82 +0,0 @@
import React from 'react'
import Checkbox from './presentational/Checkbox'
import copy from '../js/data/copy.json'
class TagListPanel extends React.Component {
constructor (props) {
super(props)
this.state = {
treeComponents: []
}
this.treeComponents = []
this.newTagFilters = []
}
componentDidMount () {
this.computeTree(this.props.tags)// .children[this.props.tagType]);
}
componentWillReceiveProps (nextProps) {
this.computeTree(nextProps.tags)// .children[nextProps.tagType]);
}
onClickCheckbox (obj, type) {
obj.active = !obj.active
this.props.onTagFilter(obj)
}
createNodeComponent (node, depth) {
return (
<li
key={node.key.replace(/ /g, '_')}
className={'tag-filter active'}
style={{ marginLeft: `${depth * 20}px` }}
>
<Checkbox
label={node.key}
isActive={node.active}
onClickCheckbox={() => this.onClickCheckbox(node, 'tag')}
/>
</li>
)
}
traverseNodeAndCreateComponent (node, depth) {
// add and create node component
const newComponent = this.createNodeComponent(node, depth)
this.treeComponents.push(newComponent)
depth = depth + 1
if (Object.keys(node.children).length > 0) {
Object.values(node.children).forEach((childNode) => {
this.traverseNodeAndCreateComponent(childNode, depth)
})
}
}
computeTree (node) {
this.treeComponents = []
let depth = 0
this.traverseNodeAndCreateComponent(node, depth)
this.setState({ treeComponents: this.treeComponents })
}
renderTree () {
return (
<div>
{this.state.treeComponents.map(c => c)}
</div>
)
}
render () {
return (
<div className='react-innertabpanel'>
<h2>{copy[this.props.language].toolbar.tags}</h2>
<p>{copy[this.props.language].toolbar.explore_by_tag__description}</p>
{this.renderTree()}
</div>
)
}
}
export default TagListPanel

View File

@@ -6,7 +6,7 @@ import * as selectors from '../selectors'
import { Tabs, TabPanel } from 'react-tabs'
import Search from './Search.jsx'
import TagListPanel from './TagListPanel.jsx'
import TagListPanel from './TagListPanel'
import CategoriesListPanel from './CategoriesListPanel.jsx'
import ToolbarBottomActions from './ToolbarBottomActions.jsx'
import copy from '../js/data/copy.json'
@@ -199,7 +199,7 @@ function mapStateToProps (state) {
categories: selectors.getCategories(state),
narratives: selectors.selectNarratives(state),
language: state.app.language,
tagFilters: selectors.selectTagList(state),
tagFilters: selectors.getTagsFilter(state),
categoryFilters: selectors.selectCategories(state),
viewFilters: state.app.filters.views,
features: state.app.features,

View File

@@ -80,6 +80,7 @@ function MapEvents ({ getCategoryColor, categories, projectPoint, styleLocation,
const { x, y } = projectPoint([location.latitude, location.longitude])
// in narrative mode, only render events in narrative
// TODO: move this to a selector
if (narrative) {
const { steps } = narrative
const onlyIfInNarrative = e => steps.map(s => s.id).includes(e.id)