diff --git a/client/coral-admin/src/actions/settings.js b/client/coral-admin/src/actions/settings.js
new file mode 100644
index 000000000..f71730663
--- /dev/null
+++ b/client/coral-admin/src/actions/settings.js
@@ -0,0 +1,66 @@
+export const SETTINGS_LOADING = 'SETTINGS_LOADING';
+export const SETTINGS_RECEIVED = 'SETTINGS_RECEIVED';
+export const SETTINGS_FETCH_ERROR = 'SETTINGS_FETCH_ERROR';
+
+export const SETTINGS_UPDATED = 'SETTINGS_UPDATED';
+
+export const SAVE_SETTINGS_LOADING = 'SAVE_SETTINGS_LOADING';
+export const SAVE_SETTINGS_SUCCESS = 'SAVE_SETTINGS_SUCCESS';
+export const SAVE_SETTINGS_FAILED = 'SAVE_SETTINGS_FAILED';
+
+const base = '/api/v1';
+
+const getInit = (method, body) => {
+ const headers = new Headers({
+ 'Content-Type': 'application/json',
+ 'Accept': 'application/json'
+ });
+
+ const init = {method, headers};
+ if (method.toLowerCase() !== 'get') {
+ init.body = JSON.stringify(body);
+ }
+
+ return init;
+};
+
+const handleResp = res => {
+ if (res.status === 401) {
+ throw new Error('Not Authorized to make this request');
+ } else if (res.status > 399) {
+ throw new Error('Error! Status ', res.status);
+ } else if (res.status === 204) {
+ return res.text();
+ } else {
+ return res.json();
+ }
+};
+
+export const fetchSettings = () => dispatch => {
+ dispatch({type: SETTINGS_LOADING});
+ fetch(`${base}/settings`, getInit('GET'))
+ .then(handleResp)
+ .then(settings => {
+ dispatch({type: SETTINGS_RECEIVED, settings});
+ })
+ .catch(error => {
+ dispatch({type: SETTINGS_FETCH_ERROR, error});
+ });
+};
+
+export const updateSettings = settings => {
+ return {type: SETTINGS_UPDATED, settings};
+};
+
+export const saveSettingsToServer = () => (dispatch, getState) => {
+ const settings = getState().settings.toJS().settings;
+ dispatch({type: SAVE_SETTINGS_LOADING});
+ fetch(`${base}/settings`, getInit('PUT', settings))
+ .then(handleResp)
+ .then(() => {
+ dispatch({type: SAVE_SETTINGS_SUCCESS, settings});
+ })
+ .catch(error => {
+ dispatch({type: SAVE_SETTINGS_FAILED, error});
+ });
+};
diff --git a/client/coral-admin/src/containers/Configure.css b/client/coral-admin/src/containers/Configure.css
index 18f12cacd..98cb0e254 100644
--- a/client/coral-admin/src/containers/Configure.css
+++ b/client/coral-admin/src/containers/Configure.css
@@ -20,6 +20,7 @@
border-radius: 4px;
height: 90px;
margin-bottom: 10px;
+ cursor: pointer;
}
.configSettingEmbed {
diff --git a/client/coral-admin/src/containers/Configure.js b/client/coral-admin/src/containers/Configure.js
index 4c6253eaf..0d4cf58d6 100644
--- a/client/coral-admin/src/containers/Configure.js
+++ b/client/coral-admin/src/containers/Configure.js
@@ -1,11 +1,13 @@
+
import React from 'react';
import {connect} from 'react-redux';
+import {fetchSettings, updateSettings, saveSettingsToServer} from '../actions/settings';
import {
List,
ListItem,
ListItemContent,
ListItemAction,
- Textfield,
+ //Textfield,
Checkbox,
Button,
Icon
@@ -17,16 +19,38 @@ import translations from '../translations';
class Configure extends React.Component {
constructor (props) {
super(props);
+
this.state = {activeSection: 'comments', copied: false};
+
this.copyToClipBoard = this.copyToClipBoard.bind(this);
+ this.updateModeration = this.updateModeration.bind(this);
+ this.saveSettings = this.saveSettings.bind(this);
+ }
+
+ componentWillMount () {
+ this.props.dispatch(fetchSettings());
+ }
+
+ updateModeration () {
+ const moderation = this.props.settings.moderation === 'pre' ? 'post' : 'pre';
+ this.props.dispatch(updateSettings({moderation}));
+ }
+
+ saveSettings () {
+ this.props.dispatch(saveSettingsToServer());
}
getCommentSettings () {
return
-
+
+
+
Enable pre-moderation
+ {/*
Include Comment Stream Description for Readers
@@ -39,6 +63,7 @@ class Configure extends React.Component {
error='Input is not a number!'
label='Maximum Characters' />
+ */}
;
}
@@ -75,10 +100,14 @@ class Configure extends React.Component {
}
render () {
- const pageTitle = this.state.activeSection === 'comments'
+ let pageTitle = this.state.activeSection === 'comments'
? 'Comment Settings'
: 'Embed Comment Stream';
+ if (this.props.fetchingSettings) {
+ pageTitle += ' - Loading...';
+ }
+
return (
@@ -94,12 +123,14 @@ class Configure extends React.Component {
icon='code'>Embed Comment Stream
-
{pageTitle}
+ { this.props.saveFetchingError }
+ { this.props.fetchSettingsError }
{
this.state.activeSection === 'comments'
? this.getCommentSettings()
@@ -111,6 +142,7 @@ class Configure extends React.Component {
}
}
-export default connect(x => x)(Configure);
+const mapStateToProps = state => state.settings.toJS();
+export default connect(mapStateToProps)(Configure);
const lang = new I18n(translations);
diff --git a/client/coral-admin/src/reducers/comments.js b/client/coral-admin/src/reducers/comments.js
index 2842e2289..01f536f71 100644
--- a/client/coral-admin/src/reducers/comments.js
+++ b/client/coral-admin/src/reducers/comments.js
@@ -39,7 +39,7 @@ const updateStatus = (state, action) => {
// Flag a comment
const flag = (state, action) => {
const byId = state.get('byId');
- const data = byId.get(action.id).get('data').set('flagged', true);
+ const data = byId.get(action.id).set('flagged', true);
const comment = byId.get(action.id).set('data', data);
return state.set('byId', byId.set(action.id, comment));
};
diff --git a/client/coral-admin/src/reducers/index.js b/client/coral-admin/src/reducers/index.js
index 3c0ddc924..63176ca3b 100644
--- a/client/coral-admin/src/reducers/index.js
+++ b/client/coral-admin/src/reducers/index.js
@@ -1,8 +1,10 @@
import {combineReducers} from 'redux';
import comments from 'reducers/comments';
+import settings from 'reducers/settings';
// Combine all reducers into a main one
export default combineReducers({
+ settings,
comments
});
diff --git a/client/coral-admin/src/reducers/settings.js b/client/coral-admin/src/reducers/settings.js
new file mode 100644
index 000000000..20cd024f5
--- /dev/null
+++ b/client/coral-admin/src/reducers/settings.js
@@ -0,0 +1,43 @@
+import {Map} from 'immutable';
+import * as types from '../actions/settings';
+
+const initialState = Map({
+ settings: Map(),
+ saveSettingsError: null,
+ fetchSettingsError: null,
+ fetchingSettings: false
+});
+
+// Handle the comment actions
+export default (state = initialState, action) => {
+ switch (action.type) {
+ case types.SETTINGS_LOADING: return state.set('fetchingSettings', true).set('fetchSettingsError', null);
+ case types.SETTINGS_RECEIVED: return updateSettings(state, action);
+ case types.SETTINGS_FETCH_ERROR: return settingsFetchFailed(state, action);
+ case types.SETTINGS_UPDATED: return updateSettings(state, action);
+ case types.SAVE_SETTINGS_LOADING: return state.set('fetchingSettings', true).set('saveSettingsError', null);
+ case types.SAVE_SETTINGS_SUCCESS: return saveComplete(state, action);
+ case types.SAVE_SETTINGS_FAILED: return settingsSaveFailed(state, action);
+ default: return state;
+ }
+};
+
+const updateSettings = (state, action) => {
+ const s = state.set('fetchingSettings', false).set('fetchSettingsError', null);
+ const settings = s.get('settings').merge(action.settings);
+ return s.set('settings', settings);
+};
+
+const saveComplete = (state, action) => {
+ const s = state.set('fetchingSettings', false).set('saveSettingsError', null);
+ const settings = s.get('settings').merge(action.settings);
+ return s.set('settings', settings);
+};
+
+const settingsFetchFailed = (state, action) => {
+ return state.set('fetchingSettings', false).set('fetchSettingsError', action.error);
+};
+
+const settingsSaveFailed = (state, action) => {
+ return state.set('fetchingSettings', false).set('fetchSettingsError', action.error);
+};
diff --git a/client/coral-admin/src/services/talk-adapter.js b/client/coral-admin/src/services/talk-adapter.js
index ce2e2692a..8122bc709 100644
--- a/client/coral-admin/src/services/talk-adapter.js
+++ b/client/coral-admin/src/services/talk-adapter.js
@@ -29,15 +29,20 @@ export default store => next => action => {
// Get comments to fill each of the three lists on the mod queue
const fetchModerationQueueComments = store =>
-fetch('/api/v1/queue')
-.then(res => res.json())
+
+Promise.all([fetch('/api/v1/comments/status/pending'), fetch('/api/v1/comments/status/rejected'), fetch('/api/v1/comments/action/flag')])
+.then(res => Promise.all(res.map(r => r.json())))
+.then(res => {
+ res[2] = res[2].map(comment => { comment.flagged = true; return comment; });
+ return res.reduce((prev, curr) => prev.concat(curr), []);
+})
.then(res => store.dispatch({type: 'COMMENTS_MODERATION_QUEUE_FETCH_SUCCESS',
comments: res}))
.catch(error => store.dispatch({type: 'COMMENTS_MODERATION_QUEUE_FETCH_FAILED', error}));
// Update a comment. Now to update a comment we need to send back the whole object
const updateComment = (store, comment) =>
-fetch(`/api/v1/comments/${comment._id}/status`, {
+fetch('/api/v1/comments/${comment._id}/status', {
method: 'POST',
body: JSON.stringify({status: comment.status})
})
diff --git a/package.json b/package.json
index a3656ddba..5563c1f36 100644
--- a/package.json
+++ b/package.json
@@ -46,6 +46,7 @@
"body-parser": "^1.15.2",
"debug": "^2.2.0",
"ejs": "^2.5.2",
+ "eslint-config-postcss": "^2.0.2",
"express": "^4.14.0",
"mongoose": "^4.6.5",
"morgan": "^1.7.0",
@@ -58,8 +59,10 @@
"babel-core": "^6.18.2",
"babel-loader": "^6.2.7",
"babel-plugin-transform-async-to-generator": "^6.16.0",
+ "babel-plugin-transform-class-properties": "^6.18.0",
"babel-plugin-transform-decorators-legacy": "^1.3.4",
"babel-plugin-transform-object-assign": "^6.8.0",
+ "babel-plugin-transform-object-rest-spread": "^6.16.0",
"babel-plugin-transform-react-jsx": "^6.8.0",
"babel-polyfill": "^6.16.0",
"babel-preset-es2015": "^6.18.0",
diff --git a/tests/models/comment.js b/tests/models/comment.js
index 0efd0c960..f81cb7609 100644
--- a/tests/models/comment.js
+++ b/tests/models/comment.js
@@ -113,7 +113,6 @@ describe('Comment: models', () => {
});
});
});
-
describe('#moderationQueue()', () => {
it('should find an array of new comments to moderate when pre-moderation', () => {
return Comment.moderationQueue('pre').then((result) => {