synchronous updateSource logic

This commit is contained in:
Lachlan Kermode
2018-12-17 17:05:07 +00:00
parent 795acac7ca
commit c10b741325
7 changed files with 295 additions and 50 deletions

148
src/components/:w Normal file
View File

@@ -0,0 +1,148 @@
import React from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import * as actions from '../actions';
import * as selectors from '../selectors';
import MediaOverlay from './presentational/MediaOverlay';
import LoadingOverlay from './presentational/LoadingOverlay';
import Viewport from './Viewport.jsx';
import Toolbar from './Toolbar.jsx';
import CardStack from './CardStack.jsx';
import NarrativeCard from './NarrativeCard.js';
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);
this.handleViewSource = this.handleViewSource.bind(this)
this.handleHighlight = this.handleHighlight.bind(this)
this.handleSelect = this.handleSelect.bind(this)
this.handleTagFilter = this.handleTagFilter.bind(this)
this.updateTimerange = this.updateTimerange.bind(this)
this.eventsById = {}
}
componentDidMount() {
if (!this.props.app.isMobile) {
this.props.actions.fetchDomain()
.then(domain => this.props.actions.updateDomain(domain));
}
}
handleHighlight(highlighted) {
this.props.actions.updateHighlighted((highlighted) ? highlighted : null);
}
getEventById(eventId) {
if (this.eventsById[eventId]) return this.eventsById[eventId];
this.eventsById[eventId] = this.props.domain.events.find(ev => ev.id === eventId);
return this.eventsById[eventId];
}
handleViewSource(source) {
console.log('handleViewSource: to implement in Dashboard.jsx')
this.props.actions.updateSource(source)
}
handleSelect(selected) {
if (selected) {
let eventsToSelect = selected.map(event => this.getEventById(event.id));
eventsToSelect = eventsToSelect.sort((a, b) => parseDate(a.timestamp) - parseDate(b.timestamp))
this.props.actions.updateSelected(eventsToSelect)
}
}
handleTagFilter(tag) {
this.props.actions.updateTagFilters(tag);
}
updateTimerange(timeRange) {
this.props.actions.updateTimeRange(timeRange);
}
getCategoryColor(category='other') {
return this.props.ui.style.categories[category] || this.props.ui.style.categories['other']
}
getNarrativeLinks(event) {
const narrative = this.props.domain.narratives.find(nv => nv.id === event.narrative);
if (narrative) return narrative.byId[event.id];
return null;
}
render() {
return (
<div>
<Viewport
methods={{
onSelect: this.handleSelect,
getCategoryColor: category => this.getCategoryColor(category)
}}
/>
<Toolbar
onFilter={this.handleTagFilter}
actions={this.props.actions}
/>
<CardStack
onViewSource={this.handleViewSource}
onSelect={this.handleSelect}
onHighlight={this.handleHighlight}
onToggleCardstack={() => this.props.actions.updateSelected([])}
getNarrativeLinks={event => this.getNarrativeLinks(event)}
getCategoryColor={category => this.getCategoryColor(category)}
/>
<Timeline
methods={{
onSelect: this.handleSelect,
onUpdateTimerange: this.updateTimerange,
getCategoryColor: category => this.getCategoryColor(category)
}}
/>
<InfoPopUp
ui={this.props.ui}
app={this.props.app}
toggle={() => this.props.actions.toggleInfoPopup()}
/>
<NarrativeCard
onSelect={this.handleSelect}
actions={this.props.actions}
/>
<NarrativeCard
onSelect={this.handleSelect}
/>
<Notification
isNotification={this.props.app.flags.isNotification}
notifications={this.props.domain.notifications}
onToggle={this.props.actions.markNotificationsRead}
/>
<MediaOverlay
/>
<LoadingOverlay
ui={this.props.app.flags.isFetchingDomain}
language={this.props.app.language}
/>
</div>
);
}
}
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators(actions, dispatch)
};
}
export default connect(
state => state,
mapDispatchToProps,
)(Dashboard);

View File

@@ -4,6 +4,7 @@ import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import * as actions from '../actions';
import MediaOverlay from './MediaOverlay.jsx';
import LoadingOverlay from './presentational/LoadingOverlay';
import Map from './Map.jsx';
import Toolbar from './Toolbar.jsx';
@@ -48,7 +49,6 @@ class Dashboard extends React.Component {
}
handleViewSource(source) {
console.log('handleViewSource: to implement in Dashboard.jsx')
this.props.actions.updateSource(source)
}
@@ -131,6 +131,13 @@ class Dashboard extends React.Component {
notifications={this.props.domain.notifications}
onToggle={this.props.actions.markNotificationsRead}
/>
{this.props.app.source ? (
<MediaOverlay
onCancel={() => {
this.props.actions.updateSource(null)}
}
/>
) : null}
<LoadingOverlay
ui={this.props.app.flags.isFetchingDomain}
language={this.props.app.language}

View File

@@ -0,0 +1,27 @@
import React from 'react'
class MediaOverlay extends React.Component {
render() {
return (
<div className="mo-overlay">
<div className="mo-container" onClick={this.props.onCancel}>
<div className="mo-media-container">
<iframe
className="vimeo-iframe"
src="https://player.vimeo.com/video/33044546"
frameborder="0"
webkitallowfullscreen
mozallowfullscreen
allowfullscreen
></iframe>
</div>
{/* <div className="mo-controls"> */}
{/* ciao ciao */}
{/* </div> */}
</div>
</div>
)
}
}
export default MediaOverlay

View File

@@ -8,6 +8,7 @@ import {
UPDATE_TAGFILTERS,
UPDATE_TIMERANGE,
UPDATE_NARRATIVE,
UPDATE_SOURCE,
RESET_ALLFILTERS,
TOGGLE_LANGUAGE,
TOGGLE_MAPVIEW,
@@ -117,6 +118,13 @@ function toggleMapView(appState, action) {
});
}
function updateSource(appState, action) {
return {
...appState,
source: action.source
}
}
function fetchError(state, action) {
return {
...state,
@@ -181,6 +189,8 @@ function app(appState = initial.app, action) {
return updateTimeRange(appState, action);
case UPDATE_NARRATIVE:
return updateNarrative(appState, action);
case UPDATE_SOURCE:
return updateSource(appState, action);
case RESET_ALLFILTERS:
return resetAllFilters(appState, action);
case TOGGLE_LANGUAGE:

View File

@@ -7,6 +7,7 @@
@import 'header';
@import 'cardstack';
@import 'narrativecard';
@import 'mediaoverlay';
@import 'map';
@import 'timeline';
@import 'tag-filters';

View File

@@ -0,0 +1,51 @@
$vimeo-height: 800px;
$vimeo-width: 1000px;
.mo-overlay {
display: flex;
justify-content: center;
align-items: center;
position: absolute;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background-color: rgba(230, 230, 230, 0.5);
z-index: 20;
}
.mo-container {
background-color: transparent;
max-width: 80vw;
min-width: 80vw;
max-height: 90vh;
min-height: 90vh;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
.mo-controls, .mo-media-container {
flex: 1;
display: flex;
justify-content: center;
}
}
.mo-media-container {
max-height: $vimeo-height;
}
.mo-controls {
color: white;
width: $vimeo-width;
background-color: black;
}
.vimeo-iframe {
min-height: $vimeo-height;
max-height: $vimeo-height;
min-width: $vimeo-width;
max-width: $vimeo-width;
border: none;
}

View File

@@ -1,11 +1,11 @@
const initial = {
/*
* The Domain or 'domain' of this state refers to the tree of data
* available for render and display.
* Selections and filters in the 'app' subtree will operate the domain
* in mapStateToProps of the Dashboard, and deterimne which items
* in the domain will get rendered by React
*/
* The Domain or 'domain' of this state refers to the tree of data
* available for render and display.
* Selections and filters in the 'app' subtree will operate the domain
* in mapStateToProps of the Dashboard, and deterimne which items
* in the domain will get rendered by React
*/
domain: {
events: [],
narratives: [],
@@ -17,24 +17,25 @@ const initial = {
},
/*
* The 'app' subtree of this state determines the data and information to be
* displayed.
* It may refer to those the user interacts with, by selecting,
* fitlering and so on, which ultimately operate on the data to be displayed.
* Additionally, some of the 'app' flags are determined by the config file
* or by the characteristics of the client, browser, etc.
*/
* The 'app' subtree of this state determines the data and information to be
* displayed.
* It may refer to those the user interacts with, by selecting,
* fitlering and so on, which ultimately operate on the data to be displayed.
* Additionally, some of the 'app' flags are determined by the config file
* or by the characteristics of the client, browser, etc.
*/
app: {
errors: {
source: null,
},
highlighted: null,
selected: [],
source: null,
narrative: null,
filters: {
timerange: [
d3.timeParse("%Y-%m-%dT%H:%M:%S")("2013-02-23T12:00:00"),
d3.timeParse("%Y-%m-%dT%H:%M:%S")("2016-02-23T12:00:00")
d3.timeParse("%Y-%m-%dT%H:%M:%S")("2013-02-23T12:00:00"),
d3.timeParse("%Y-%m-%dT%H:%M:%S")("2016-02-23T12:00:00")
],
tags: [],
categories: [],
@@ -54,36 +55,36 @@ const initial = {
duration: 1576800,
active: false
},
{
label: '3 meses',
duration: 129600,
active: false
},
{
label: '3 días',
duration: 4320,
active: false
},
{
label: '12 horas',
duration: 720,
active: false
},
{
label: '2 horas',
duration: 120,
active: false
},
{
label: '30 min',
duration: 30,
active: false
},
{
label: '10 min',
duration: 10,
active: false
}],
{
label: '3 meses',
duration: 129600,
active: false
},
{
label: '3 días',
duration: 4320,
active: false
},
{
label: '12 horas',
duration: 720,
active: false
},
{
label: '2 horas',
duration: 120,
active: false
},
{
label: '30 min',
duration: 30,
active: false
},
{
label: '10 min',
duration: 10,
active: false
}],
features: {
USE_TAGS: process.env.features.USE_TAGS,
USE_SEARCH: process.env.features.USE_SEARCH
@@ -99,10 +100,10 @@ const initial = {
},
/*
* The 'ui' subtree of this state refers the state of the cosmetic
* elements of the application, such as color palettes of categories
* as well as dom elements to attach SVG
*/
* The 'ui' subtree of this state refers the state of the cosmetic
* elements of the application, such as color palettes of categories
* as well as dom elements to attach SVG
*/
ui: {
style: {
categories: {