From 04298aca7d39d739e5d98a6fb7c353e66f4656ca Mon Sep 17 00:00:00 2001
From: Riley Davis
Date: Tue, 14 Mar 2017 16:30:02 -0600
Subject: [PATCH 1/6] change Stream > Story sometimes
---
client/coral-admin/src/AppRouter.js | 4 +-
.../coral-admin/src/components/ui/Drawer.js | 4 +-
.../coral-admin/src/components/ui/Header.js | 4 +-
.../Streams.css => Stories/Stories.css} | 0
.../Streams.js => Stories/Stories.js} | 6 +-
.../src/containers/Streams/Stories.js | 187 ++++++++++++++++++
client/coral-admin/src/translations.json | 10 +-
7 files changed, 201 insertions(+), 14 deletions(-)
rename client/coral-admin/src/containers/{Streams/Streams.css => Stories/Stories.css} (100%)
rename client/coral-admin/src/containers/{Streams/Streams.js => Stories/Stories.js} (97%)
create mode 100644 client/coral-admin/src/containers/Streams/Stories.js
diff --git a/client/coral-admin/src/AppRouter.js b/client/coral-admin/src/AppRouter.js
index 38d06dcb1..a2990677f 100644
--- a/client/coral-admin/src/AppRouter.js
+++ b/client/coral-admin/src/AppRouter.js
@@ -1,7 +1,7 @@
import React from 'react';
import {Router, Route, IndexRoute, IndexRedirect, browserHistory} from 'react-router';
-import Streams from 'containers/Streams/Streams';
+import Stories from 'containers/Stories/Stories';
import Configure from 'containers/Configure/Configure';
import LayoutContainer from 'containers/LayoutContainer';
import InstallContainer from 'containers/Install/InstallContainer';
@@ -18,7 +18,7 @@ const routes = (
-
+
{/* Moderation Routes */}
diff --git a/client/coral-admin/src/components/ui/Drawer.js b/client/coral-admin/src/components/ui/Drawer.js
index 9af651f3b..5ac55045c 100644
--- a/client/coral-admin/src/components/ui/Drawer.js
+++ b/client/coral-admin/src/components/ui/Drawer.js
@@ -23,9 +23,9 @@ const CoralDrawer = ({handleLogout, restricted = false}) => (
{lang.t('configure.moderate')}
- {lang.t('configure.streams')}
+ {lang.t('configure.stories')}
(
- {lang.t('configure.streams')}
+ {lang.t('configure.stories')}
{
};
};
-export default connect(mapStateToProps, mapDispatchToProps)(Streams);
+export default connect(mapStateToProps, mapDispatchToProps)(Stories);
const lang = new I18n(translations);
diff --git a/client/coral-admin/src/containers/Streams/Stories.js b/client/coral-admin/src/containers/Streams/Stories.js
new file mode 100644
index 000000000..4d2ad086a
--- /dev/null
+++ b/client/coral-admin/src/containers/Streams/Stories.js
@@ -0,0 +1,187 @@
+import React, {Component} from 'react';
+import styles from './Stories.css';
+import {connect} from 'react-redux';
+import I18n from 'coral-framework/modules/i18n/i18n';
+import {fetchAssets, updateAssetState} from '../../actions/assets';
+import translations from '../../translations.json';
+import {Link} from 'react-router';
+
+import {Pager, Icon} from 'coral-ui';
+import {DataTable, TableHeader, RadioGroup, Radio} from 'react-mdl';
+import EmptyCard from 'coral-admin/src/components/EmptyCard';
+
+const limit = 25;
+
+class Stories extends Component {
+
+ state = {
+ search: '',
+ sort: 'desc',
+ filter: 'all',
+ statusMenus: {},
+ timer: null,
+ page: 0
+ }
+
+ componentDidMount () {
+ this.props.fetchAssets(0, limit, '', this.state.sortBy);
+ }
+
+ onSettingChange = (setting) => (e) => {
+ let options = this.state;
+ this.setState({[setting]: e.target.value});
+ options[setting] = e.target.value;
+ this.props.fetchAssets(0, limit, options.search, options.sort, options.filter);
+ }
+
+ onSearchChange = (e) => {
+ const search = e.target.value;
+ this.setState((prevState) => {
+ prevState.search = search;
+ clearTimeout(prevState.timer);
+ const fetchAssets = this.props.fetchAssets;
+ prevState.timer = setTimeout(() => {
+ fetchAssets(0, limit, search, this.state.sort, this.state.filter);
+ }, 350);
+ return prevState;
+ });
+ }
+
+ renderDate = (date) => {
+ const d = new Date(date);
+ return `${d.getMonth() + 1}/${d.getDate()}/${d.getFullYear()}`;
+ }
+
+ onStatusClick = (closeStream, id, statusMenuOpen) => () => {
+ if (statusMenuOpen) {
+ this.setState(prev => {
+ prev.statusMenus[id] = false;
+ return prev;
+ });
+ this.props.updateAssetState(id, closeStream ? Date.now() : null)
+ .then(() => {
+ const {search, sort, filter, page} = this.state;
+ this.props.fetchAssets(page, limit, search, sort, filter);
+ });
+ } else {
+ this.setState(prev => {
+ prev.statusMenus[id] = true;
+ return prev;
+ });
+ }
+ }
+
+ renderTitle = (title, {id}) => {title}
+
+ renderStatus = (closedAt, {id}) => {
+ const closed = closedAt && new Date(closedAt).getTime() < Date.now();
+ const statusMenuOpen = this.state.statusMenus[id];
+ return
+
+ {!statusMenuOpen && }
+ {closed ? lang.t('streams.closed') : lang.t('streams.open')}
+
+ {
+ statusMenuOpen &&
+
+ {!closed ? lang.t('streams.closed') : lang.t('streams.open')}
+
+ }
+
;
+ }
+
+ onPageClick = (page) => {
+ this.setState({page});
+ const {search, sort, filter} = this.state;
+ this.props.fetchAssets((page - 1) * limit, limit, search, sort, filter);
+ }
+
+ render () {
+ const {search, sort, filter} = this.state;
+ const {assets} = this.props;
+
+ const assetsIds = assets.ids.map((id) => assets.byId[id]);
+
+ return (
+
+
+
+
+
+
+
{lang.t('streams.filter-streams')}
+
{lang.t('streams.stream-status')}
+
+ {lang.t('streams.all')}
+ {lang.t('streams.open')}
+ {lang.t('streams.closed')}
+
+
{lang.t('streams.sort-by')}
+
+ {lang.t('streams.newest')}
+ {lang.t('streams.oldest')}
+
+
+ {
+ assetsIds.length
+ ?
+
+ {lang.t('streams.article')}
+
+ {lang.t('streams.pubdate')}
+
+
+ {lang.t('streams.status')}
+
+
+
+
+ :
{lang.t('streams.empty_result')}
+ }
+
+ );
+ }
+}
+
+const mapStateToProps = ({assets}) => {
+ return {
+ assets: assets.toJS()
+ };
+};
+
+const mapDispatchToProps = (dispatch) => {
+ return {
+ fetchAssets: (...args) => {
+ dispatch(fetchAssets.apply(this, args));
+ },
+ updateAssetState: (...args) => dispatch(updateAssetState.apply(this, args))
+ };
+};
+
+export default connect(mapStateToProps, mapDispatchToProps)(Stories);
+
+const lang = new I18n(translations);
diff --git a/client/coral-admin/src/translations.json b/client/coral-admin/src/translations.json
index 58788e546..91fa60d43 100644
--- a/client/coral-admin/src/translations.json
+++ b/client/coral-admin/src/translations.json
@@ -81,7 +81,7 @@
"moderate": "Moderate",
"configure": "Configure",
"community": "Community",
- "streams": "Streams",
+ "stories": "Stories",
"closed-comments-desc": "Write a message to be displayed when when your comment stream is closed and no longer accepting comments.",
"closed-comments-label": "Write a message...",
"hours": "Hours",
@@ -138,9 +138,9 @@
"sort-by": "Sort By",
"open": "Open",
"closed": "Closed",
- "article": "Article",
+ "article": "Story",
"pubdate": "Publication Date",
- "status": "Status"
+ "status": "Stream Status"
}
},
"es": {
@@ -212,7 +212,7 @@
"moderate": "Moderar",
"configure": "Configurar",
"community": "Comunidad",
- "streams": "Streams",
+ "stories": "Artículos",
"closed-comments-desc": "Escribe un mensaje que será mostrado cuando los comentarios estén cerrados y no se acepten más comentarios.",
"closed-comments-label": "Escribe un mensaje...",
"never": "Nunca",
@@ -259,7 +259,7 @@
"sort-by": "",
"open": "",
"closed": "",
- "article": "",
+ "article": "artículo",
"pubdate": "",
"status": ""
}
From 3071b3783e92d49a5e70081e896dc555b36a9afb Mon Sep 17 00:00:00 2001
From: riley
Date: Wed, 15 Mar 2017 10:15:47 -0600
Subject: [PATCH 2/6] move pre-mod links
---
.../containers/Configure/ModerationSettings.js | 18 ++++++++++++++++++
.../src/containers/Configure/StreamSettings.js | 18 ------------------
2 files changed, 18 insertions(+), 18 deletions(-)
diff --git a/client/coral-admin/src/containers/Configure/ModerationSettings.js b/client/coral-admin/src/containers/Configure/ModerationSettings.js
index da158b612..5b7286b98 100644
--- a/client/coral-admin/src/containers/Configure/ModerationSettings.js
+++ b/client/coral-admin/src/containers/Configure/ModerationSettings.js
@@ -16,6 +16,11 @@ const updateEmailConfirmation = (updateSettings, verify) => () => {
updateSettings({requireEmailConfirmation: !verify});
};
+const updatePremodLinksEnable = (updateSettings, premodLinks) => () => {
+ const premodLinksEnable = !premodLinks;
+ updateSettings({premodLinksEnable});
+};
+
const ModerationSettings = ({settings, updateSettings, onChangeWordlist}) => {
// just putting this here for shorthand below
@@ -50,6 +55,19 @@ const ModerationSettings = ({settings, updateSettings, onChangeWordlist}) => {
+
+
+
+
+
+
{lang.t('configure.enable-premod-links')}
+
+ {lang.t('configure.enable-premod-links-text')}
+
+
+
() => {
updateSettings({infoBoxEnable});
};
-const updatePremodLinksEnable = (updateSettings, premodLinks) => () => {
- const premodLinksEnable = !premodLinks;
- updateSettings({premodLinksEnable});
-};
-
const updateInfoBoxContent = (updateSettings) => (event) => {
const infoBoxContent = event.target.value;
updateSettings({infoBoxContent});
@@ -99,19 +94,6 @@ const StreamSettings = ({updateSettings, settingsError, settings, errors}) => {
-
-
-
-
-
-
{lang.t('configure.enable-premod-links')}
-
- {lang.t('configure.enable-premod-links-text')}
-
-
-
Date: Wed, 15 Mar 2017 11:16:13 -0600
Subject: [PATCH 3/6] correctly handle error when not logged in
---
client/coral-admin/src/actions/auth.js | 20 ++++++++++++++------
client/coral-framework/actions/auth.js | 2 +-
2 files changed, 15 insertions(+), 7 deletions(-)
diff --git a/client/coral-admin/src/actions/auth.js b/client/coral-admin/src/actions/auth.js
index 389e8b4d2..dd2eaa7dc 100644
--- a/client/coral-admin/src/actions/auth.js
+++ b/client/coral-admin/src/actions/auth.js
@@ -5,9 +5,13 @@ import coralApi from 'coral-framework/helpers/response';
export const handleLogin = (email, password) => dispatch => {
dispatch({type: actions.LOGIN_REQUEST});
return coralApi('/auth/local', {method: 'POST', body: {email, password}})
- .then(result => {
- const isAdmin = !!result.user.roles.filter(i => i === 'ADMIN').length;
- dispatch(checkLoginSuccess(result.user, isAdmin));
+ .then(({user}) => {
+ if (!user) {
+ return dispatch(checkLoginFailure('not logged in'));
+ }
+
+ const isAdmin = !!user.roles.filter(i => i === 'ADMIN').length;
+ dispatch(checkLoginSuccess(user, isAdmin));
})
.catch(error => {
dispatch({type: actions.LOGIN_FAILURE, message: error.translation_key});
@@ -34,9 +38,13 @@ const checkLoginFailure = error => ({type: actions.CHECK_LOGIN_FAILURE, error});
export const checkLogin = () => dispatch => {
dispatch(checkLoginRequest());
return coralApi('/auth')
- .then(result => {
- const isAdmin = !!result.user.roles.filter(i => i === 'ADMIN').length;
- dispatch(checkLoginSuccess(result.user, isAdmin));
+ .then(({user}) => {
+ if (!user) {
+ return dispatch(checkLoginFailure('not logged in'));
+ }
+
+ const isAdmin = !!user.roles.filter(i => i === 'ADMIN').length;
+ dispatch(checkLoginSuccess(user, isAdmin));
})
.catch(error => {
console.error(error);
diff --git a/client/coral-framework/actions/auth.js b/client/coral-framework/actions/auth.js
index ba1952e29..9dedaa2f2 100644
--- a/client/coral-framework/actions/auth.js
+++ b/client/coral-framework/actions/auth.js
@@ -48,7 +48,7 @@ export const fetchSignIn = (formData) => (dispatch) => {
dispatch(signInRequest());
return coralApi('/auth/local', {method: 'POST', body: formData})
.then(({user}) => {
- const isAdmin = !!user.roles.filter(i => i === 'ADMIN').length;
+ const isAdmin = !!user && !!user.roles.filter(i => i === 'ADMIN').length;
dispatch(signInSuccess(user, isAdmin));
dispatch(hideSignInDialog());
})
From 9ddc3aa0b79592fafb30a771ef98b2d2a0d93a5e Mon Sep 17 00:00:00 2001
From: Riley Davis
Date: Wed, 15 Mar 2017 14:13:18 -0600
Subject: [PATCH 4/6] move CountdownTimer to its own component
---
.../src/components/CountdownTimer.js | 79 +++++++++++++++++++
.../src/containers/Dashboard/Dashboard.js | 71 +++--------------
2 files changed, 89 insertions(+), 61 deletions(-)
create mode 100644 client/coral-admin/src/components/CountdownTimer.js
diff --git a/client/coral-admin/src/components/CountdownTimer.js b/client/coral-admin/src/components/CountdownTimer.js
new file mode 100644
index 000000000..3eaa6d305
--- /dev/null
+++ b/client/coral-admin/src/components/CountdownTimer.js
@@ -0,0 +1,79 @@
+import React, {PropTypes} from 'react';
+import I18n from 'coral-framework/modules/i18n/i18n';
+import translations from 'coral-admin/src/translations';
+import styles from 'coral-admin/src/containers/Dashboard/Dashboard.css';
+import {Icon} from 'coral-ui';
+
+const lang = new I18n(translations);
+const refreshIntervalSeconds = 60 * 5;
+
+class CountdownTimer extends React.Component {
+
+ static propTypes = {
+ handleTimeout: PropTypes.func.isRequired
+ }
+
+ constructor (props) {
+ super(props);
+ try {
+ if (window.localStorage.getItem('coral:dashboardNote') === null) {
+ window.localStorage.setItem('coral:dashboardNote', 'show');
+ }
+ } catch (e) {
+
+ // above will fail in Private Mode in some browsers.
+ }
+
+ this.state = {
+ secondsUntilRefresh: refreshIntervalSeconds,
+ dashboardNote: window.localStorage.getItem('coral:dashboardNote') || 'show'
+ };
+ }
+
+ componentWillMount () {
+ setInterval(() => { // the countdown timer
+ let nextCount = this.state.secondsUntilRefresh - 1;
+ if (nextCount < 0) {
+ nextCount = refreshIntervalSeconds;
+ this.props.handleTimeout();
+ }
+ this.setState({secondsUntilRefresh: nextCount});
+ }, 1000);
+ }
+
+ formatTime = () => {
+ const minutes = Math.floor(this.state.secondsUntilRefresh / 60);
+ let seconds = (this.state.secondsUntilRefresh % 60).toString();
+ if (seconds.length < 2) {
+ seconds = `0${seconds}`;
+ }
+
+ return `${minutes}:${seconds}`;
+ }
+
+ dismissNote = () => {
+ try {
+ window.localStorage.setItem('coral:dashboardNote', 'hide');
+ } catch (e) {
+
+ // when setItem fails in Safari Private mode
+ this.setState({dashboardNote: 'hide'});
+ }
+ }
+
+ render () {
+ const hideReloadNote = window.localStorage.getItem('coral:dashboardNote') === 'hide' ||
+ this.state.dashboardNote === 'hide'; // for Safari Incognito
+ return (
+
+ ×
+ {lang.t('dashboard.next-update', this.formatTime())} {lang.t('dashboard.auto-update')}
+
+ );
+ }
+}
+
+export default CountdownTimer;
diff --git a/client/coral-admin/src/containers/Dashboard/Dashboard.js b/client/coral-admin/src/containers/Dashboard/Dashboard.js
index 602a48d7f..728d40c07 100644
--- a/client/coral-admin/src/containers/Dashboard/Dashboard.js
+++ b/client/coral-admin/src/containers/Dashboard/Dashboard.js
@@ -5,63 +5,15 @@ import {connect} from 'react-redux';
import {getMetrics} from 'coral-admin/src/graphql/queries';
import FlagWidget from './FlagWidget';
import ActivityWidget from './ActivityWidget';
+import CountdownTimer from 'coral-admin/src/components/CountdownTimer';
import {showBanUserDialog, hideBanUserDialog} from 'coral-admin/src/actions/moderation';
-import I18n from 'coral-framework/modules/i18n/i18n';
-import translations from 'coral-admin/src/translations';
-import {Spinner, Icon} from 'coral-ui';
-const lang = new I18n(translations);
-const refreshIntervalSeconds = 60 * 5;
+import {Spinner} from 'coral-ui';
class Dashboard extends React.Component {
- constructor (props) {
- super(props);
-
- try {
- if (window.localStorage.getItem('coral:dashboardNote') === null) {
- window.localStorage.setItem('coral:dashboardNote', 'show');
- }
- } catch (e) {
-
- // above will fail in Private Mode in some browsers.
- }
-
- this.state = {
- secondsUntilRefresh: refreshIntervalSeconds,
- dashboardNote: window.localStorage.getItem('coral:dashboardNote') || 'show'
- };
- }
-
- componentWillMount () {
- setInterval(() => { // the countdown timer
- let nextCount = this.state.secondsUntilRefresh - 1;
- if (nextCount < 0) {
- nextCount = refreshIntervalSeconds;
- this.props.data.refetch();
- }
- this.setState({secondsUntilRefresh: nextCount});
- }, 1000);
- }
-
- dismissNote = () => {
- try {
- window.localStorage.setItem('coral:dashboardNote', 'hide');
- } catch (e) {
-
- // when setItem fails in Safari Private mode
- this.setState({dashboardNote: 'hide'});
- }
- }
-
- formatTime = () => {
- const minutes = Math.floor(this.state.secondsUntilRefresh / 60);
- let seconds = (this.state.secondsUntilRefresh % 60).toString();
- if (seconds.length < 2) {
- seconds = `0${seconds}`;
- }
-
- return `${minutes}:${seconds}`;
+ reloadData = () => {
+ this.props.data.refetch();
}
render () {
@@ -70,19 +22,16 @@ class Dashboard extends React.Component {
return ;
}
+ console.log('data', this.props.data);
+
const {data: {assetsByActivity, assetsByFlag}} = this.props;
- const hideReloadNote = window.localStorage.getItem('coral:dashboardNote') === 'hide' ||
- this.state.dashboardNote === 'hide'; // for Safari Incognito
+
+ console.log('assetsByActivity', assetsByActivity);
+ console.log('assetsByFlag', assetsByActivity);
return (
-
- ×
- {lang.t('dashboard.next-update', this.formatTime())} {lang.t('dashboard.auto-update')}
-
+
From 378e855c4c02293ea5a8107048f439adee729d45 Mon Sep 17 00:00:00 2001
From: Riley Davis
Date: Wed, 15 Mar 2017 14:20:27 -0600
Subject: [PATCH 5/6] remove logs
---
client/coral-admin/src/containers/Dashboard/Dashboard.js | 5 -----
1 file changed, 5 deletions(-)
diff --git a/client/coral-admin/src/containers/Dashboard/Dashboard.js b/client/coral-admin/src/containers/Dashboard/Dashboard.js
index 728d40c07..f5d0aa39b 100644
--- a/client/coral-admin/src/containers/Dashboard/Dashboard.js
+++ b/client/coral-admin/src/containers/Dashboard/Dashboard.js
@@ -22,13 +22,8 @@ class Dashboard extends React.Component {
return ;
}
- console.log('data', this.props.data);
-
const {data: {assetsByActivity, assetsByFlag}} = this.props;
- console.log('assetsByActivity', assetsByActivity);
- console.log('assetsByFlag', assetsByActivity);
-
return (
From 1043a37eef07b697fd8cd27e530a8b7f6a2fff8e Mon Sep 17 00:00:00 2001
From: Riley Davis
Date: Thu, 16 Mar 2017 09:28:17 -0600
Subject: [PATCH 6/6] do a null check.
---
client/coral-admin/src/containers/Dashboard/FlagWidget.js | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/client/coral-admin/src/containers/Dashboard/FlagWidget.js b/client/coral-admin/src/containers/Dashboard/FlagWidget.js
index 468875d3d..17be2acbd 100644
--- a/client/coral-admin/src/containers/Dashboard/FlagWidget.js
+++ b/client/coral-admin/src/containers/Dashboard/FlagWidget.js
@@ -19,7 +19,11 @@ const FlagWidget = ({assets}) => {
{
assets.length
? assets.map(asset => {
- const flagSummary = asset.action_summaries.find(s => s.type === 'FlagAssetActionSummary');
+ let flagSummary = null;
+ if (asset.action_summaries) {
+ flagSummary = asset.action_summaries.find(s => s.type === 'FlagAssetActionSummary');
+ }
+
return (
Moderate