mirror of
https://github.com/bellingcat/ukraine-timemap.git
synced 2026-06-08 03:18:36 +03:00
All filters working in conjunction; can filter on shape, filter, and category separately
This commit is contained in:
@@ -121,6 +121,7 @@ export function fetchDomain() {
|
||||
}
|
||||
dispatch(toggleFetchingDomain());
|
||||
dispatch(setInitialCategories(result.associations));
|
||||
dispatch(setInitialShapes(result.shapes));
|
||||
return result;
|
||||
})
|
||||
.catch((err) => {
|
||||
@@ -245,6 +246,14 @@ export function setInitialCategories(values) {
|
||||
};
|
||||
}
|
||||
|
||||
export const SET_INITIAL_SHAPES = "SET_INITIAL_SHAPES";
|
||||
export function setInitialShapes(values) {
|
||||
return {
|
||||
type: SET_INITIAL_SHAPES,
|
||||
values,
|
||||
};
|
||||
}
|
||||
|
||||
export const UPDATE_TIMERANGE = "UPDATE_TIMERANGE";
|
||||
export function updateTimeRange(timerange) {
|
||||
return {
|
||||
|
||||
@@ -513,10 +513,10 @@ export function setD3Locale(d3) {
|
||||
|
||||
export function mapStyleByShape(shapes, activeShapes) {
|
||||
const styledShapes = shapes.map((s) => {
|
||||
const { colour, shape, title } = s;
|
||||
const { colour, shape, id } = s;
|
||||
const style = {
|
||||
checkboxStyles: {
|
||||
background: activeShapes.includes(title) ? colour : "black",
|
||||
background: activeShapes.includes(id) ? colour : "black",
|
||||
border: "none",
|
||||
clipPath: POLYGON_CLIP_PATH[shape],
|
||||
},
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React from "react";
|
||||
import marked from "marked";
|
||||
import PanelTree from "./atoms/PanelTree";
|
||||
import { ASSOCIATION_MODES } from "../../common/constants";
|
||||
|
||||
const CategoriesListPanel = ({
|
||||
categories,
|
||||
@@ -22,6 +23,7 @@ const CategoriesListPanel = ({
|
||||
data={categories}
|
||||
activeValues={activeCategories}
|
||||
onSelect={onCategoryFilter}
|
||||
type={ASSOCIATION_MODES.CATEGORY}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -2,6 +2,7 @@ import React from "react";
|
||||
import marked from "marked";
|
||||
import PanelTree from "./atoms/PanelTree";
|
||||
import { mapStyleByShape } from "../../common/utilities";
|
||||
import { SHAPE } from "../../common/constants";
|
||||
|
||||
const ShapesListPanel = ({
|
||||
shapes,
|
||||
@@ -24,6 +25,7 @@ const ShapesListPanel = ({
|
||||
data={styledShapes}
|
||||
activeValues={activeShapes}
|
||||
onSelect={onShapeFilter}
|
||||
type={SHAPE}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import React from "react";
|
||||
import Checkbox from "../../atoms/Checkbox";
|
||||
import { ASSOCIATION_MODES } from "../../../common/constants";
|
||||
|
||||
const PanelTree = ({ data, activeValues, onSelect }) => {
|
||||
const PanelTree = ({ data, activeValues, onSelect, type }) => {
|
||||
// If the parent panel is of type 'CATEGORY': filter on title. If panel is 'SHAPE': filter on id
|
||||
const onSelectionType = type === ASSOCIATION_MODES.CATEGORY ? "title" : "id";
|
||||
return (
|
||||
<div>
|
||||
{data.map((val) => {
|
||||
const isActive = activeValues.includes(val.title);
|
||||
return (
|
||||
<li
|
||||
key={val.title.replace(/ /g, "_")}
|
||||
@@ -14,8 +16,8 @@ const PanelTree = ({ data, activeValues, onSelect }) => {
|
||||
>
|
||||
<Checkbox
|
||||
label={val.title}
|
||||
isActive={isActive}
|
||||
onClickCheckbox={() => onSelect(val.title)}
|
||||
isActive={activeValues.includes(val[onSelectionType])}
|
||||
onClickCheckbox={() => onSelect(val[onSelectionType])}
|
||||
styleProps={val.styles}
|
||||
/>
|
||||
</li>
|
||||
|
||||
@@ -27,6 +27,7 @@ import {
|
||||
SET_LOADING,
|
||||
SET_NOT_LOADING,
|
||||
SET_INITIAL_CATEGORIES,
|
||||
SET_INITIAL_SHAPES,
|
||||
UPDATE_SEARCH_QUERY,
|
||||
} from "../actions";
|
||||
|
||||
@@ -272,6 +273,14 @@ function setInitialCategories(appState, action) {
|
||||
};
|
||||
}
|
||||
|
||||
function setInitialShapes(appState, action) {
|
||||
const shapeIds = action.values.map((sh) => sh.id);
|
||||
return {
|
||||
...appState,
|
||||
shapes: shapeIds,
|
||||
};
|
||||
}
|
||||
|
||||
function updateSearchQuery(appState, action) {
|
||||
return {
|
||||
...appState,
|
||||
@@ -331,6 +340,8 @@ function app(appState = initial.app, action) {
|
||||
return setNotLoading(appState);
|
||||
case SET_INITIAL_CATEGORIES:
|
||||
return setInitialCategories(appState, action);
|
||||
case SET_INITIAL_SHAPES:
|
||||
return setInitialShapes(appState, action);
|
||||
case UPDATE_SEARCH_QUERY:
|
||||
return updateSearchQuery(appState, action);
|
||||
default:
|
||||
|
||||
@@ -73,9 +73,22 @@ export const selectRegions = createSelector(
|
||||
* 3. exist in an active category
|
||||
*/
|
||||
export const selectEvents = createSelector(
|
||||
[getEvents, getActiveFilters, getActiveCategories, getTimeRange, getFeatures],
|
||||
(events, activeFilters, activeCategories, timeRange, features) => {
|
||||
console.info("SELECTED EVENTS SELECTOR");
|
||||
[
|
||||
getEvents,
|
||||
getActiveFilters,
|
||||
getActiveCategories,
|
||||
getActiveShapes,
|
||||
getTimeRange,
|
||||
getFeatures,
|
||||
],
|
||||
(
|
||||
events,
|
||||
activeFilters,
|
||||
activeCategories,
|
||||
activeShapes,
|
||||
timeRange,
|
||||
features
|
||||
) => {
|
||||
return events.reduce((acc, event) => {
|
||||
const isMatchingFilter =
|
||||
(event.associations &&
|
||||
@@ -98,8 +111,14 @@ export const selectEvents = createSelector(
|
||||
isActiveTime = features.GRAPH_NONLOCATED
|
||||
? (!event.latitude && !event.longitude) || isActiveTime
|
||||
: isActiveTime;
|
||||
if (isActiveTime && isActiveCategory) {
|
||||
if (event.type === SHAPE || isActiveFilter) {
|
||||
const isActiveShape =
|
||||
event.shape && activeShapes.includes(event.shape.id);
|
||||
if (event.type === SHAPE) {
|
||||
if (isActiveShape && isActiveCategory && isActiveTime) {
|
||||
acc[event.id] = { ...event };
|
||||
}
|
||||
} else {
|
||||
if (isActiveFilter && isActiveCategory && isActiveTime) {
|
||||
acc[event.id] = { ...event };
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user