mirror of
https://github.com/bellingcat/ukraine-timemap.git
synced 2026-06-11 21:08:36 +03:00
Clean store fields, move from state.ui to state.app those that make sense
This commit is contained in:
@@ -255,10 +255,3 @@ export function toggleMapView(layer) {
|
||||
layer
|
||||
}
|
||||
}
|
||||
|
||||
export const TOGGLE_GUIDEDMODE = 'TOGGLE_GUIDEDMODE';
|
||||
export function toggleGuidedMode() {
|
||||
return {
|
||||
type: TOGGLE_GUIDEDMODE
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
import copy from '../js/data/copy.json';
|
||||
import {isNotNullNorUndefined} from '../js/utilities';
|
||||
import {
|
||||
isNotNullNorUndefined,
|
||||
parseDate,
|
||||
formatterWithYear
|
||||
} from '../js/utilities';
|
||||
import React from 'react';
|
||||
|
||||
import Spinner from './presentational/Spinner';
|
||||
@@ -35,8 +39,8 @@ class Card extends React.Component {
|
||||
|
||||
makeTimelabel(timestamp) {
|
||||
if (timestamp === null) return null;
|
||||
const parsedTimestamp = this.props.tools.parser(timestamp);
|
||||
const timelabel = this.props.tools.formatterWithYear(parsedTimestamp);
|
||||
const parsedTimestamp = parseDate(timestamp);
|
||||
const timelabel = formatterWithYear(parsedTimestamp);
|
||||
return timelabel;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ class CardStack extends React.Component {
|
||||
<Card
|
||||
event={event}
|
||||
language={this.props.language}
|
||||
tools={this.props.tools}
|
||||
isLoading={this.props.isLoading}
|
||||
getNarrativeLinks={this.props.getNarrativeLinks}
|
||||
getCategoryGroup={this.props.getCategoryGroup}
|
||||
getCategoryColor={this.props.getCategoryColor}
|
||||
@@ -90,9 +90,8 @@ function mapStateToProps(state) {
|
||||
return {
|
||||
selected: state.app.selected,
|
||||
language: state.app.language,
|
||||
tools: state.ui.tools,
|
||||
isCardstack: state.ui.flags.isCardstack,
|
||||
isFetchingSources: state.ui.flags.isFetchingSources
|
||||
isCardstack: state.app.flags.isCardstack,
|
||||
isLoading: state.app.flags.isFetchingEvents
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,8 @@ import InfoPopUp from './InfoPopup.jsx';
|
||||
import Timeline from './Timeline.jsx';
|
||||
import Notification from './Notification.jsx';
|
||||
|
||||
import { parseDate } from '../js/utilities';
|
||||
|
||||
class Dashboard extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
@@ -110,12 +112,12 @@ class Dashboard extends React.Component {
|
||||
actions={this.props.actions}
|
||||
/>
|
||||
<Notification
|
||||
isNotification={this.props.ui.flags.isNotification}
|
||||
isNotification={this.props.app.flags.isNotification}
|
||||
notifications={this.props.domain.notifications}
|
||||
onToggle={this.props.actions.markNotificationsRead}
|
||||
/>
|
||||
<LoadingOverlay
|
||||
ui={this.props.ui.flags.isFetchingDomain}
|
||||
ui={this.props.app.flags.isFetchingDomain}
|
||||
language={this.props.app.language}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -27,7 +27,7 @@ export default class InfoPopUp extends React.Component{
|
||||
|
||||
renderView2DLegend() {
|
||||
return (
|
||||
<div className={`infopopup ${(this.props.ui.flags.isInfopopup) ? '' : 'hidden'}`}>
|
||||
<div className={`infopopup ${(this.props.app.flags.isInfopopup) ? '' : 'hidden'}`}>
|
||||
<button onClick={() => this.props.toggle()} className="side-menu-burg over-white is-active"><span /></button>
|
||||
{this.renderView2DCopy()}
|
||||
<div className="legend">
|
||||
|
||||
@@ -3,6 +3,7 @@ import { connect } from 'react-redux';
|
||||
import * as selectors from '../selectors';
|
||||
|
||||
import copy from '../js/data/copy.json';
|
||||
import { formatterWithYear } from '../js/utilities';
|
||||
import TimelineLogic from '../js/timeline/timeline.js';
|
||||
|
||||
class Timeline extends React.Component {
|
||||
@@ -15,7 +16,6 @@ class Timeline extends React.Component {
|
||||
|
||||
componentDidMount() {
|
||||
const ui = {
|
||||
tools: this.props.tools,
|
||||
dom: this.props.dom
|
||||
}
|
||||
|
||||
@@ -47,8 +47,8 @@ class Timeline extends React.Component {
|
||||
const labels_title_lang = copy[this.props.app.language].timeline.labels_title;
|
||||
const info_lang = copy[this.props.app.language].timeline.info;
|
||||
let classes = `timeline-wrapper ${(this.state.isFolded) ? ' folded' : ''}`;
|
||||
const date0 = this.props.tools.formatterWithYear(this.props.app.timerange[0]);
|
||||
const date1 = this.props.tools.formatterWithYear(this.props.app.timerange[1]);
|
||||
const date0 = formatterWithYear(this.props.app.timerange[0]);
|
||||
const date1 = formatterWithYear(this.props.app.timerange[1]);
|
||||
|
||||
return (
|
||||
<div className={classes}>
|
||||
@@ -82,9 +82,8 @@ function mapStateToProps(state) {
|
||||
language: state.app.language,
|
||||
zoomLevels: state.app.zoomLevels
|
||||
},
|
||||
tools: state.ui.tools,
|
||||
dom: state.ui.dom,
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(Timeline);
|
||||
export default connect(mapStateToProps)(Timeline);
|
||||
|
||||
@@ -157,7 +157,6 @@ function mapStateToProps(state) {
|
||||
categoryFilter: state.app.filters.categories,
|
||||
viewFilters: state.app.filters.views,
|
||||
features: state.app.features,
|
||||
isModeGuided: state.app.isModeGuided
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,10 +22,6 @@ class ToolbarBottomActions extends React.Component {
|
||||
this.props.actions.toggleMapView(layer);
|
||||
}
|
||||
|
||||
toggleGuidedMode() {
|
||||
this.props.actions.toggleGuidedMode();
|
||||
}
|
||||
|
||||
renderMapActions() {
|
||||
return (
|
||||
<div className="bottom-action-block">
|
||||
|
||||
@@ -5,15 +5,16 @@
|
||||
TODO: is it possible to express this idiomatically as React?
|
||||
*/
|
||||
import {
|
||||
areEqual
|
||||
areEqual,
|
||||
parseDate,
|
||||
formatterWithYear
|
||||
} from '../utilities';
|
||||
import esLocale from '../data/es-MX.json';
|
||||
import copy from '../data/copy.json';
|
||||
|
||||
export default function(app, ui, methods) {
|
||||
d3.timeFormatDefaultLocale(esLocale);
|
||||
const formatterWithYear = ui.tools.formatterWithYear;
|
||||
const parser = ui.tools.parser;
|
||||
|
||||
const zoomLevels = app.zoomLevels;
|
||||
let events = [];
|
||||
let categories = [];
|
||||
@@ -242,7 +243,7 @@ export default function(app, ui, methods) {
|
||||
* @param {object} eventPoint: regular eventPoint data
|
||||
*/
|
||||
function getEventX(eventPoint) {
|
||||
return scale.x(parser(eventPoint.timestamp));
|
||||
return scale.x(parseDate(eventPoint.timestamp));
|
||||
}
|
||||
|
||||
function getTimeScaleExtent() {
|
||||
|
||||
@@ -49,3 +49,11 @@ export function parseDate(datetime) {
|
||||
datetime.slice(17, 19)
|
||||
);
|
||||
}
|
||||
|
||||
export function formatterWithYear(datetime) {
|
||||
return d3.timeFormat("%d %b %Y, %H:%M")(datetime);
|
||||
}
|
||||
|
||||
export function formatter(datetime) {
|
||||
return d3.timeFormat("%d %b, %H:%M")(datetime);
|
||||
}
|
||||
|
||||
@@ -11,7 +11,10 @@ import {
|
||||
RESET_ALLFILTERS,
|
||||
TOGGLE_LANGUAGE,
|
||||
TOGGLE_MAPVIEW,
|
||||
TOGGLE_GUIDEDMODE,
|
||||
TOGGLE_FETCHING_DOMAIN,
|
||||
TOGGLE_FETCHING_EVENTS,
|
||||
TOGGLE_INFOPOPUP,
|
||||
TOGGLE_NOTIFICATIONS,
|
||||
FETCH_ERROR,
|
||||
} from '../actions';
|
||||
|
||||
@@ -113,12 +116,6 @@ function toggleMapView(appState, action) {
|
||||
});
|
||||
}
|
||||
|
||||
function toggleGuidedMode(appState, action) {
|
||||
return Object.assign({}, appState, {
|
||||
isModeGuided: !appState.isModeGuided
|
||||
})
|
||||
}
|
||||
|
||||
function fetchError(state, action) {
|
||||
return {
|
||||
...state,
|
||||
@@ -127,6 +124,39 @@ function fetchError(state, action) {
|
||||
}
|
||||
}
|
||||
|
||||
function toggleFetchingDomain(appState, action) {
|
||||
return Object.assign({}, appState, {
|
||||
flags: Object.assign({}, appState.flags, {
|
||||
isFetchingDomain: !appState.flags.isFetchingDomain
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
function toggleFetchingEvents(appState, action) {
|
||||
return Object.assign({}, appState, {
|
||||
flags: Object.assign({}, appState.flags, {
|
||||
isFetchingEvents: !appState.flags.isFetchingEvents
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
function toggleInfoPopup(appState, action) {
|
||||
return Object.assign({}, appState, {
|
||||
flags: Object.assign({}, appState.flags, {
|
||||
isInfopopup: !appState.flags.isInfopopup
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
function toggleNotifications(appState, action) {
|
||||
return Object.assign({}, appState, {
|
||||
flags: Object.assign({}, appState.flags, {
|
||||
isNotification: !appState.flags.isNotification
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
function app(appState = initial.app, action) {
|
||||
switch (action.type) {
|
||||
@@ -146,10 +176,16 @@ function app(appState = initial.app, action) {
|
||||
return toggleLanguage(appState, action);
|
||||
case TOGGLE_MAPVIEW:
|
||||
return toggleMapView(appState, action);
|
||||
case TOGGLE_GUIDEDMODE:
|
||||
return toggleGuidedMode(appState, action);
|
||||
case FETCH_ERROR:
|
||||
return fetchError(appState, action);
|
||||
case TOGGLE_FETCHING_DOMAIN:
|
||||
return toggleFetchingDomain(appState, action);
|
||||
case TOGGLE_FETCHING_EVENTS:
|
||||
return toggleFetchingEvents(appState, action);
|
||||
case TOGGLE_INFOPOPUP:
|
||||
return toggleInfoPopup(appState, action);
|
||||
case TOGGLE_NOTIFICATIONS:
|
||||
return toggleNotifications(appState, action);
|
||||
default:
|
||||
return appState;
|
||||
}
|
||||
|
||||
@@ -1,55 +1,9 @@
|
||||
import initial from '../store/initial.js';
|
||||
|
||||
import {
|
||||
TOGGLE_FETCHING_DOMAIN,
|
||||
TOGGLE_FETCHING_SOURCES,
|
||||
TOGGLE_VIEW,
|
||||
TOGGLE_TIMELINE,
|
||||
TOGGLE_INFOPOPUP,
|
||||
TOGGLE_NOTIFICATIONS
|
||||
} from '../actions'
|
||||
|
||||
function toggleFetchingDomain(uiState, action) {
|
||||
return {
|
||||
...uiState,
|
||||
flags: {
|
||||
...uiState.flags,
|
||||
isFetchingDomain: !uiState.flags.isFetchingDomain
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function toggleFetchingSources(uiState, action) {
|
||||
return {
|
||||
...uiState,
|
||||
flags: {
|
||||
...uiState.flags,
|
||||
isFetchingSources: !uiState.flags.isFetchingSources
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function toggleInfoPopup(uiState, action) {
|
||||
return {
|
||||
...uiState,
|
||||
flags: {
|
||||
...uiState.flags,
|
||||
isInfopopup: !uiState.flags.isInfopopup
|
||||
}
|
||||
}
|
||||
}
|
||||
import {} from '../actions'
|
||||
|
||||
function ui(uiState = initial.ui, action) {
|
||||
switch (action.type) {
|
||||
case TOGGLE_FETCHING_DOMAIN:
|
||||
return toggleFetchingDomain(uiState, action)
|
||||
case TOGGLE_FETCHING_SOURCES:
|
||||
return toggleFetchingSources(uiState, action)
|
||||
case TOGGLE_INFOPOPUP:
|
||||
return toggleInfoPopup(uiState, action)
|
||||
default:
|
||||
return uiState
|
||||
}
|
||||
return uiState;
|
||||
}
|
||||
|
||||
export default ui;
|
||||
|
||||
@@ -173,7 +173,7 @@
|
||||
.axisBoundaries {
|
||||
stroke: $offwhite;
|
||||
stroke-width: 1;
|
||||
stroke-dasharray: 1px 4px;
|
||||
stroke-dasharray: 1px 2px;
|
||||
}
|
||||
|
||||
.event {
|
||||
|
||||
@@ -45,7 +45,6 @@ const initial = {
|
||||
},
|
||||
base_uri: 'http://127.0.0.1:8000/', // Modify accordingly on production setup.
|
||||
isMobile: (/Mobi/.test(navigator.userAgent)),
|
||||
isModeGuided: true,
|
||||
language: 'en-US',
|
||||
mapAnchor: process.env.MAP_ANCHOR,
|
||||
zoomLevels: [{
|
||||
@@ -86,31 +85,24 @@ const initial = {
|
||||
features: {
|
||||
USE_TAGS: process.env.features.USE_TAGS,
|
||||
USE_SEARCH: process.env.features.USE_SEARCH
|
||||
},
|
||||
flags: {
|
||||
isFetchingDomain: false,
|
||||
isFetchingEvents: false,
|
||||
|
||||
isCardstack: true,
|
||||
isInfopopup: false,
|
||||
isNotification: true
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
* The 'ui' subtree of this state refers the state of the cosmetic
|
||||
* elements of the application, such as color palettes of groups or how some
|
||||
* of the UI tools are enabled or disabled dynamically by the user
|
||||
* elements of the application, such as color palettes of categories
|
||||
* as well as dom elements to attach SVG
|
||||
*/
|
||||
ui: {
|
||||
style: {
|
||||
|
||||
colors: {
|
||||
WHITE: "#efefef",
|
||||
YELLOW: "#ffd800",
|
||||
MIDGREY: "rgb(44, 44, 44)",
|
||||
DARKGREY: "#232323",
|
||||
PINK: "#F28B50",//rgb(232, 9, 90)",
|
||||
ORANGE: "#F25835",//rgb(232, 9, 90)",
|
||||
RED: "rgb(233, 0, 19)",
|
||||
BLUE: "#F2DE79",//"rgb(48, 103 , 217)",
|
||||
GREEN: "#4FF2F2",//"rgb(0, 158, 86)",
|
||||
},
|
||||
|
||||
palette: d3.schemeCategory10,
|
||||
|
||||
categories: {
|
||||
default: 'red',
|
||||
// Add here other categories to differentiate by color, like:
|
||||
@@ -139,18 +131,6 @@ const initial = {
|
||||
timeslider: "timeslider",
|
||||
map: "map"
|
||||
},
|
||||
flags: {
|
||||
isFetchingDomain: false,
|
||||
isFetchingSources: false,
|
||||
|
||||
isCardstack: true,
|
||||
isInfopopup: false
|
||||
},
|
||||
tools: {
|
||||
formatter: d3.timeFormat("%d %b, %H:%M"),
|
||||
formatterWithYear: d3.timeFormat("%d %b %Y, %H:%M"),
|
||||
parser: d3.timeParse("%Y-%m-%dT%H:%M:%S")
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user