Merge branch 'master' into i18n-refactor

This commit is contained in:
gaba
2017-05-15 14:02:34 -07:00
251 changed files with 4984 additions and 1874 deletions
+2 -2
View File
@@ -1,5 +1,5 @@
import React from 'react';
import {Router, Route, IndexRoute, IndexRedirect, browserHistory} from 'react-router';
import {Router, Route, IndexRedirect, browserHistory} from 'react-router';
import Stories from 'containers/Stories/Stories';
import Configure from 'containers/Configure/Configure';
@@ -18,7 +18,7 @@ const routes = (
<div>
<Route exact path="/admin/install" component={InstallContainer}/>
<Route path='/admin' component={LayoutContainer}>
<IndexRoute component={Dashboard} />
<IndexRedirect to='/admin/moderate/all' />
<Route path='community' component={CommunityContainer} />
<Route path='configure' component={Configure} />
<Route path='stories' component={Stories} />
+3 -3
View File
@@ -24,7 +24,7 @@ export const fetchAssets = (skip = '', limit = '', search = '', sort = '', filte
assets: result,
count
}))
.catch(error => dispatch({type: FETCH_ASSETS_FAILURE, error}));
.catch((error) => dispatch({type: FETCH_ASSETS_FAILURE, error}));
};
// Update an asset state
@@ -34,9 +34,9 @@ export const updateAssetState = (id, closedAt) => (dispatch) => {
return coralApi(`/assets/${id}/status`, {method: 'PUT', body: {closedAt}})
.then(() =>
dispatch({type: UPDATE_ASSET_STATE_SUCCESS}))
.catch(error => dispatch({type: UPDATE_ASSET_STATE_FAILURE, error}));
.catch((error) => dispatch({type: UPDATE_ASSET_STATE_FAILURE, error}));
};
export const updateAssets = assets => dispatch => {
export const updateAssets = (assets) => (dispatch) => {
dispatch({type: UPDATE_ASSETS, assets});
};
+54 -33
View File
@@ -1,75 +1,96 @@
import * as actions from '../constants/auth';
import * as Storage from 'coral-framework/helpers/storage';
import coralApi from 'coral-framework/helpers/response';
import {handleAuthToken} from 'coral-framework/actions/auth';
// Log In.
export const handleLogin = (email, password, recaptchaResponse) => dispatch => {
//==============================================================================
// SIGN IN
//==============================================================================
export const handleLogin = (email, password, recaptchaResponse) => (dispatch) => {
dispatch({type: actions.LOGIN_REQUEST});
const params = {method: 'POST', body: {email, password}};
if (recaptchaResponse) {
params.headers = {'X-Recaptcha-Response': recaptchaResponse};
}
return coralApi('/auth/local', params)
.then(({user}) => {
.then(({user, token}) => {
if (!user) {
Storage.removeItem('token');
return dispatch(checkLoginFailure('not logged in'));
}
const isAdmin = !!user.roles.filter(i => i === 'ADMIN').length;
dispatch(handleAuthToken(token));
const isAdmin = !!user.roles.filter((i) => i === 'ADMIN').length;
dispatch(checkLoginSuccess(user, isAdmin));
})
.catch(error => {
.catch((error) => {
if (error.translation_key === 'login_maximum_exceeded') {
dispatch({type: actions.LOGIN_MAXIMUM_EXCEEDED, message: error.translation_key});
dispatch({
type: actions.LOGIN_MAXIMUM_EXCEEDED,
message: error.translation_key
});
} else {
dispatch({type: actions.LOGIN_FAILURE, message: error.translation_key});
}
});
};
const forgotPassowordRequest = () => ({type: actions.FETCH_FORGOT_PASSWORD_REQUEST});
const forgotPassowordSuccess = () => ({type: actions.FETCH_FORGOT_PASSWORD_SUCCESS});
const forgotPassowordFailure = () => ({type: actions.FETCH_FORGOT_PASSWORD_FAILURE});
//==============================================================================
// FORGOT PASSWORD
//==============================================================================
export const requestPasswordReset = email => dispatch => {
const forgotPassowordRequest = () => ({
type: actions.FETCH_FORGOT_PASSWORD_REQUEST
});
const forgotPassowordSuccess = () => ({
type: actions.FETCH_FORGOT_PASSWORD_SUCCESS
});
const forgotPassowordFailure = () => ({
type: actions.FETCH_FORGOT_PASSWORD_FAILURE
});
export const requestPasswordReset = (email) => (dispatch) => {
dispatch(forgotPassowordRequest(email));
return coralApi('/account/password/reset', {method: 'POST', body: {email}})
.then(() => dispatch(forgotPassowordSuccess()))
.catch(error => dispatch(forgotPassowordFailure(error)));
.catch((error) => dispatch(forgotPassowordFailure(error)));
};
// Check Login
//==============================================================================
// CHECK LOGIN
//==============================================================================
const checkLoginRequest = () => ({type: actions.CHECK_LOGIN_REQUEST});
const checkLoginSuccess = (user, isAdmin) => ({type: actions.CHECK_LOGIN_SUCCESS, user, isAdmin});
const checkLoginFailure = error => ({type: actions.CHECK_LOGIN_FAILURE, error});
const checkLoginRequest = () => ({
type: actions.CHECK_LOGIN_REQUEST
});
export const checkLogin = () => dispatch => {
const checkLoginSuccess = (user, isAdmin) => ({
type: actions.CHECK_LOGIN_SUCCESS,
user,
isAdmin
});
const checkLoginFailure = (error) => ({
type: actions.CHECK_LOGIN_FAILURE,
error
});
export const checkLogin = () => (dispatch) => {
dispatch(checkLoginRequest());
return coralApi('/auth')
.then(({user}) => {
if (!user) {
Storage.removeItem('token');
return dispatch(checkLoginFailure('not logged in'));
}
const isAdmin = !!user.roles.filter(i => i === 'ADMIN').length;
const isAdmin = !!user.roles.filter((i) => i === 'ADMIN').length;
dispatch(checkLoginSuccess(user, isAdmin));
})
.catch(error => {
.catch((error) => {
console.error(error);
dispatch(checkLoginFailure(`${error.translation_key}`));
});
};
// LogOut Actions
const logOutRequest = () => ({type: actions.LOGOUT_REQUEST});
const logOutSuccess = () => ({type: actions.LOGOUT_SUCCESS});
const logOutFailure = () => ({type: actions.LOGOUT_FAILURE});
export const logout = () => dispatch => {
dispatch(logOutRequest());
return coralApi('/auth', {method: 'DELETE'})
.then(() => dispatch(logOutSuccess()))
.catch(error => dispatch(logOutFailure(error)));
};
+3 -3
View File
@@ -16,7 +16,7 @@ import {
import coralApi from '../../../coral-framework/helpers/response';
export const fetchAccounts = (query = {}) => dispatch => {
export const fetchAccounts = (query = {}) => (dispatch) => {
dispatch(requestFetchAccounts());
coralApi(`/users?${qs.stringify(query)}`)
@@ -30,14 +30,14 @@ export const fetchAccounts = (query = {}) => dispatch => {
totalPages
});
})
.catch(error => dispatch({type: FETCH_COMMENTERS_FAILURE, error}));
.catch((error) => dispatch({type: FETCH_COMMENTERS_FAILURE, error}));
};
const requestFetchAccounts = () => ({
type: FETCH_COMMENTERS_REQUEST
});
export const updateSorting = sort => ({
export const updateSorting = (sort) => ({
type: SORT_UPDATE,
sort
});
+1 -1
View File
@@ -1,6 +1,6 @@
export const CONFIG_UPDATED = 'CONFIG_UPDATED';
export const fetchConfig = () => dispatch => {
export const fetchConfig = () => (dispatch) => {
let json = document.getElementById('data');
let data = JSON.parse(json.textContent);
dispatch({type: CONFIG_UPDATED, data});
+11 -11
View File
@@ -5,14 +5,14 @@ import errorMsj from 'coral-framework/helpers/error';
export const nextStep = () => ({type: actions.NEXT_STEP});
export const previousStep = () => ({type: actions.PREVIOUS_STEP});
export const goToStep = step => ({type: actions.GO_TO_STEP, step});
export const goToStep = (step) => ({type: actions.GO_TO_STEP, step});
const installRequest = () => ({type: actions.INSTALL_REQUEST});
const installSuccess = () => ({type: actions.INSTALL_SUCCESS});
const installFailure = error => ({type: actions.INSTALL_FAILURE, error});
const installFailure = (error) => ({type: actions.INSTALL_FAILURE, error});
const addError = (name, error) => ({type: actions.ADD_ERROR, name, error});
const hasError = error => ({type: actions.HAS_ERROR, error});
const hasError = (error) => ({type: actions.HAS_ERROR, error});
const clearErrors = () => ({type: actions.CLEAR_ERRORS});
const validation = (formData, dispatch, next) => {
@@ -21,11 +21,11 @@ const validation = (formData, dispatch, next) => {
}
const validKeys = Object.keys(formData)
.filter(name => name !== 'domains');
.filter((name) => name !== 'domains');
// Required Validation
const empty = validKeys
.filter(name => {
.filter((name) => {
const cond = !formData[name].length;
if (cond) {
@@ -45,7 +45,7 @@ const validation = (formData, dispatch, next) => {
// RegExp Validation
const validation = validKeys
.filter(name => {
.filter((name) => {
const cond = !validate[name](formData[name]);
if (cond) {
@@ -88,7 +88,7 @@ export const finishInstall = () => (dispatch, getState) => {
dispatch(installSuccess());
dispatch(nextStep());
})
.catch(error => {
.catch((error) => {
console.error(error);
dispatch(installFailure(`${error.translation_key}`));
});
@@ -99,10 +99,10 @@ export const updateUserFormData = (name, value) => ({type: actions.UPDATE_FORMDA
export const updatePermittedDomains = (value) => ({type: actions.UPDATE_PERMITTED_DOMAINS_SETTINGS, value});
const checkInstallRequest = () => ({type: actions.CHECK_INSTALL_REQUEST});
const checkInstallSuccess = installed => ({type: actions.CHECK_INSTALL_SUCCESS, installed});
const checkInstallFailure = error => ({type: actions.CHECK_INSTALL_FAILURE, error});
const checkInstallSuccess = (installed) => ({type: actions.CHECK_INSTALL_SUCCESS, installed});
const checkInstallFailure = (error) => ({type: actions.CHECK_INSTALL_FAILURE, error});
export const checkInstall = next => dispatch => {
export const checkInstall = (next) => (dispatch) => {
dispatch(checkInstallRequest());
coralApi('/setup')
.then(({installed}) => {
@@ -111,7 +111,7 @@ export const checkInstall = next => dispatch => {
next();
}
})
.catch(error => {
.catch((error) => {
console.error(error);
dispatch(checkInstallFailure(`${error.translation_key}`));
});
+2 -2
View File
@@ -1,10 +1,10 @@
import * as actions from 'constants/moderation';
export const toggleModal = open => ({type: actions.TOGGLE_MODAL, open});
export const toggleModal = (open) => ({type: actions.TOGGLE_MODAL, open});
export const singleView = () => ({type: actions.SINGLE_VIEW});
// Ban User Dialog
export const showBanUserDialog = (user, commentId, showRejectedNote) => ({type: actions.SHOW_BANUSER_DIALOG, user, commentId, showRejectedNote});
export const showBanUserDialog = (user, commentId, commentStatus, showRejectedNote) => ({type: actions.SHOW_BANUSER_DIALOG, user, commentId, commentStatus, showRejectedNote});
export const hideBanUserDialog = (showDialog) => ({type: actions.HIDE_BANUSER_DIALOG, showDialog});
// hide shortcuts note
+5 -5
View File
@@ -13,19 +13,19 @@ export const SAVE_SETTINGS_FAILED = 'SAVE_SETTINGS_FAILED';
export const WORDLIST_UPDATED = 'WORDLIST_UPDATED';
export const DOMAINLIST_UPDATED = 'DOMAINLIST_UPDATED';
export const fetchSettings = () => dispatch => {
export const fetchSettings = () => (dispatch) => {
dispatch({type: SETTINGS_LOADING});
coralApi('/settings')
.then(settings => {
.then((settings) => {
dispatch({type: SETTINGS_RECEIVED, settings});
})
.catch(error => {
.catch((error) => {
dispatch({type: SETTINGS_FETCH_ERROR, error});
});
};
// for updating top-level settings
export const updateSettings = settings => {
export const updateSettings = (settings) => {
return {type: SETTINGS_UPDATED, settings};
};
@@ -48,7 +48,7 @@ export const saveSettingsToServer = () => (dispatch, getState) => {
.then(() => {
dispatch({type: SAVE_SETTINGS_SUCCESS, settings});
})
.catch(error => {
.catch((error) => {
dispatch({type: SAVE_SETTINGS_FAILED, error});
});
};
+4 -4
View File
@@ -9,8 +9,8 @@ export const userStatusUpdate = (status, userId, commentId) => {
return (dispatch) => {
dispatch({type: userTypes.UPDATE_STATUS_REQUEST});
return coralApi(`/users/${userId}/status`, {method: 'POST', body: {status: status, comment_id: commentId}})
.then(res => dispatch({type: userTypes.UPDATE_STATUS_SUCCESS, res}))
.catch(error => dispatch({type: userTypes.UPDATE_STATUS_FAILURE, error}));
.then((res) => dispatch({type: userTypes.UPDATE_STATUS_SUCCESS, res}))
.catch((error) => dispatch({type: userTypes.UPDATE_STATUS_FAILURE, error}));
};
};
@@ -18,7 +18,7 @@ export const userStatusUpdate = (status, userId, commentId) => {
export const sendNotificationEmail = (userId, subject, body) => {
return (dispatch) => {
return coralApi(`/users/${userId}/email`, {method: 'POST', body: {subject, body}})
.catch(error => dispatch({type: userTypes.USER_EMAIL_FAILURE, error}));
.catch((error) => dispatch({type: userTypes.USER_EMAIL_FAILURE, error}));
};
};
@@ -26,6 +26,6 @@ export const sendNotificationEmail = (userId, subject, body) => {
export const enableUsernameEdit = (userId) => {
return (dispatch) => {
return coralApi(`/users/${userId}/username-enable`, {method: 'POST'})
.catch(error => dispatch({type: userTypes.USERNAME_ENABLE_FAILURE, error}));
.catch((error) => dispatch({type: userTypes.USERNAME_ENABLE_FAILURE, error}));
};
};
@@ -13,7 +13,7 @@ class AdminLogin extends React.Component {
this.state = {email: '', password: '', requestPassword: false};
}
handleSignIn = e => {
handleSignIn = (e) => {
e.preventDefault();
this.props.handleLogin(this.state.email, this.state.password);
}
@@ -27,7 +27,7 @@ class AdminLogin extends React.Component {
this.props.handleLogin(this.state.email, this.state.password, recaptchaResponse);
}
handleRequestPassword = e => {
handleRequestPassword = (e) => {
e.preventDefault();
this.props.requestPasswordReset(this.state.email);
}
@@ -40,11 +40,11 @@ class AdminLogin extends React.Component {
<TextField
label='Email Address'
value={this.state.email}
onChange={e => this.setState({email: e.target.value})} />
onChange={(e) => this.setState({email: e.target.value})} />
<TextField
label='Password'
value={this.state.password}
onChange={e => this.setState({password: e.target.value})}
onChange={(e) => this.setState({password: e.target.value})}
type='password' />
<div style={{height: 10}}></div>
<Button
@@ -53,7 +53,7 @@ class AdminLogin extends React.Component {
full
onClick={this.handleSignIn}>Sign In</Button>
<p className={styles.forgotPasswordCTA}>
Forgot your password? <a href="#" className={styles.forgotPasswordLink} onClick={e => {
Forgot your password? <a href="#" className={styles.forgotPasswordLink} onClick={(e) => {
e.preventDefault();
this.setState({requestPassword: true});
}}>Request a new one.</a>
@@ -81,7 +81,7 @@ class AdminLogin extends React.Component {
<TextField
label='Email Address'
value={this.state.email}
onChange={e => this.setState({email: e.target.value})} />
onChange={(e) => this.setState({email: e.target.value})} />
<Button
type='submit'
cStyle='black'
@@ -7,14 +7,14 @@ import Button from 'coral-ui/components/Button';
import I18n from 'coral-i18n/modules/i18n/i18n';
const lang = new I18n();
const onBanClick = (userId, commentId, handleBanUser, rejectComment, handleClose) => (e) => {
const onBanClick = (userId, commentId, commentStatus, handleBanUser, rejectComment, handleClose) => (e) => {
e.preventDefault();
handleBanUser({userId})
.then(handleClose)
.then(() => rejectComment({commentId}));
.then(() => commentStatus === 'REJECTED' ? null : rejectComment({commentId}));
};
const BanUserDialog = ({open, handleClose, handleBanUser, rejectComment, user, commentId, showRejectedNote}) => (
const BanUserDialog = ({open, handleClose, handleBanUser, rejectComment, user, commentId, commentStatus, showRejectedNote}) => (
<Dialog
className={styles.dialog}
id="banuserDialog"
@@ -35,7 +35,7 @@ const BanUserDialog = ({open, handleClose, handleBanUser, rejectComment, user, c
<Button cStyle="cancel" className={styles.cancel} onClick={handleClose} raised>
{lang.t('bandialog.cancel')}
</Button>
<Button cStyle="black" className={styles.ban} onClick={onBanClick(user.id, commentId, handleBanUser, rejectComment, handleClose)} raised>
<Button cStyle="black" className={styles.ban} onClick={onBanClick(user.id, commentId, commentStatus, handleBanUser, rejectComment, handleClose)} raised>
{lang.t('bandialog.yes_ban_user')}
</Button>
</div>
@@ -1,7 +1,7 @@
import React, {PropTypes} from 'react';
import {Card} from 'coral-ui';
const EmptyCard = props => (
const EmptyCard = (props) => (
<Card style={{textAlign: 'center', maxWidth: 400, margin: '0 auto'}}>
{props.children}
</Card>
@@ -58,8 +58,8 @@ export default class ModerationKeysModal extends React.Component {
</tr>
</thead>
<tbody>
{Object.keys(shortcut.shortcuts).map(key => (
<tr key={`${key }tr`}>
{Object.keys(shortcut.shortcuts).map((key) => (
<tr key={`${key}tr`}>
<td className={styles.shortcut}><span className={styles.key}>{key}</span></td>
<td>{lang.t(shortcut.shortcuts[key])}</td>
</tr>
@@ -193,10 +193,12 @@
box-shadow: none;
color: white;
background-color: #519954;
cursor: not-allowed;
}
.reject__active, .rejected__active {
color: white;
background-color: #D03235;
box-shadow: none;
cursor: not-allowed;
}
@@ -72,7 +72,7 @@ export default class ModerationList extends React.Component {
// Add key handlers. Each action has one and added j/k for moving around
bindKeyHandlers () {
const {modActions, isActive} = this.props;
modActions.filter(action => menuOptionsMap[action].key).forEach(action => {
modActions.filter((action) => menuOptionsMap[action].key).forEach((action) => {
key(menuOptionsMap[action].key, 'moderationList', () => isActive && this.actionKeyHandler(menuOptionsMap[action].status));
});
key('j', 'moderationList', () => isActive && this.moveKeyHandler('down'));
+1 -5
View File
@@ -2,11 +2,7 @@ export const CHECK_LOGIN_REQUEST = 'CHECK_LOGIN_REQUEST';
export const CHECK_LOGIN_SUCCESS = 'CHECK_LOGIN_SUCCESS';
export const CHECK_LOGIN_FAILURE = 'CHECK_LOGIN_FAILURE';
export const CHECK_CSRF_TOKEN = 'CHECK_CSRF_TOKEN';
export const LOGOUT_REQUEST = 'LOGOUT_REQUEST';
export const LOGOUT_SUCCESS = 'LOGOUT_SUCCESS';
export const LOGOUT_FAILURE = 'LOGOUT_FAILURE';
export const LOGOUT = 'LOGOUT';
export const LOGIN_REQUEST = 'LOGIN_REQUEST';
export const LOGIN_SUCCESS = 'LOGIN_SUCCESS';
@@ -148,12 +148,12 @@ class CommunityContainer extends Component {
}
}
const mapStateToProps = state => ({
const mapStateToProps = (state) => ({
community: state.community.toJS()
});
const mapDispatchToProps = dispatch => ({
fetchAccounts: query => dispatch(fetchAccounts(query)),
const mapDispatchToProps = (dispatch) => ({
fetchAccounts: (query) => dispatch(fetchAccounts(query)),
showBanUserDialog: (user) => dispatch(showBanUserDialog(user)),
hideBanUserDialog: () => dispatch(hideBanUserDialog(false)),
showSuspendUserDialog: (user) => dispatch(showSuspendUserDialog(user)),
@@ -1,6 +1,6 @@
import React from 'react';
const CommunityLayout = props => (
const CommunityLayout = (props) => (
<div>
{props.children}
</div>
@@ -53,7 +53,7 @@ class Table extends Component {
<SelectField label={'Select me'} value={row.status || ''}
className={styles.selectField}
label={lang.t('community.status')}
onChange={status => this.onCommenterStatusChange(row.id, status)}>
onChange={(status) => this.onCommenterStatusChange(row.id, status)}>
<Option value={'ACTIVE'}>{lang.t('community.active')}</Option>
<Option value={'BANNED'}>{lang.t('community.banned')}</Option>
</SelectField>
@@ -62,7 +62,7 @@ class Table extends Component {
<SelectField label={'Select me'} value={row.roles[0] || ''}
className={styles.selectField}
label={lang.t('community.role')}
onChange={role => this.onRoleChange(row.id, role)}>
onChange={(role) => this.onRoleChange(row.id, role)}>
<Option value={''}>.</Option>
<Option value={'MODERATOR'}>{lang.t('community.moderator')}</Option>
<Option value={'ADMIN'}>{lang.t('community.admin')}</Option>
@@ -76,4 +76,4 @@ class Table extends Component {
}
}
export default connect(state => ({commenters: state.community.get('accounts')}))(Table);
export default connect((state) => ({commenters: state.community.get('accounts')}))(Table);
@@ -7,7 +7,7 @@ import I18n from 'coral-i18n/modules/i18n/i18n';
const lang = new I18n();
// Render a single user for the list
const User = props => {
const User = (props) => {
const {user, modActionButtons} = props;
let userStatus = user.status;
@@ -35,7 +35,7 @@ const User = props => {
<div className={styles.flaggedByCount}>
<i className="material-icons">flag</i><span className={styles.flaggedByLabel}>{lang.t('community.flags')}({ user.actions.length })</span>:
{ user.action_summaries.map(
(action, i ) => {
(action, i) => {
return <span className={styles.flaggedBy} key={i}>
{lang.t(`community.${action.reason}`)} ({action.count})
</span>;
@@ -44,7 +44,7 @@ const User = props => {
</div>
<div className={styles.flaggedReasons}>
{ user.action_summaries.map(
(action_sum, i ) => {
(action_sum, i) => {
return <div key={i}>
<span className={styles.flaggedByLabel}>
{lang.t(`community.${action_sum.reason}`)} ({action_sum.count})
@@ -170,7 +170,7 @@ class Configure extends Component {
}
}
const mapStateToProps = state => ({
const mapStateToProps = (state) => ({
settings: state.settings.toJS()
});
export default connect(mapStateToProps)(Configure);
@@ -17,8 +17,8 @@ const Domainlist = ({domains, onChangeDomainlist}) => {
value={domains}
inputProps={{placeholder: 'URL'}}
addOnPaste={true}
pasteSplit={data => data.split(',').map(d => d.trim())}
onChange={tags => onChangeDomainlist('whitelist', tags)}
pasteSplit={(data) => data.split(',').map((d) => d.trim())}
onChange={(tags) => onChangeDomainlist('whitelist', tags)}
/>
</div>
</div>
@@ -30,7 +30,7 @@ class EmbedLink extends Component {
location.protocol,
'//',
location.hostname,
location.port ? (`:${ window.location.port}`) : ''
location.port ? (`:${window.location.port}`) : ''
].join('');
const coralJsUrl = [talkBaseUrl, '/embed.js'].join('');
const nonce = String(Math.random()).slice(2);
@@ -170,7 +170,7 @@ export default StreamSettings;
// To see if we are talking about weeks, days or hours
// We talk the remainder of the division and see if it's 0
const getTimeoutMeasure = ts => {
const getTimeoutMeasure = (ts) => {
if (ts % TIMESTAMPS['weeks'] === 0) {
return 'weeks';
} else if (ts % TIMESTAMPS['days'] === 0) {
@@ -182,6 +182,6 @@ const getTimeoutMeasure = ts => {
// Dividing the amount by it's measure (hours, days, weeks) we
// obtain the amount of time
const getTimeoutAmount = ts => ts / TIMESTAMPS[getTimeoutMeasure(ts)];
const getTimeoutAmount = (ts) => ts / TIMESTAMPS[getTimeoutMeasure(ts)];
const lang = new I18n();
@@ -15,8 +15,8 @@ const Wordlist = ({suspectWords, bannedWords, onChangeWordlist}) => (
value={bannedWords}
inputProps={{placeholder: 'word or phrase'}}
addOnPaste={true}
pasteSplit={data => data.split(',').map(d => d.trim())}
onChange={tags => onChangeWordlist('banned', tags)}
pasteSplit={(data) => data.split(',').map((d) => d.trim())}
onChange={(tags) => onChangeWordlist('banned', tags)}
/>
</div>
</Card>
@@ -28,8 +28,8 @@ const Wordlist = ({suspectWords, bannedWords, onChangeWordlist}) => (
value={suspectWords}
inputProps={{placeholder: 'word or phrase'}}
addOnPaste={true}
pasteSplit={data => data.split(',').map(d => d.trim())}
onChange={tags => onChangeWordlist('suspect', tags)} />
pasteSplit={(data) => data.split(',').map((d) => d.trim())}
onChange={(tags) => onChangeWordlist('suspect', tags)} />
</div>
</Card>
</div>
@@ -16,7 +16,7 @@ const ActivityWidget = ({assets}) => {
<div className={styles.widgetTable}>
{
assets.length
? assets.map(asset => {
? assets.map((asset) => {
return (
<div className={styles.rowLinkify} key={asset.id}>
<Link className={styles.linkToModerate} to={`/admin/moderate/flagged/${asset.id}`}>Moderate</Link>
@@ -6,7 +6,6 @@ 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 {Spinner} from 'coral-ui';
@@ -36,19 +35,14 @@ class Dashboard extends React.Component {
}
}
const mapStateToProps = state => {
const mapStateToProps = (state) => {
return {
settings: state.settings.toJS(),
moderation: state.moderation.toJS()
};
};
const mapDispatchToProps = dispatch => ({
showBanUserDialog: (user, commentId) => dispatch(showBanUserDialog(user, commentId)),
hideBanUserDialog: () => dispatch(hideBanUserDialog(false))
});
export default compose(
connect(mapStateToProps, mapDispatchToProps),
connect(mapStateToProps),
getMetrics
)(Dashboard);
@@ -17,10 +17,10 @@ const FlagWidget = ({assets}) => {
<div className={styles.widgetTable}>
{
assets.length
? assets.map(asset => {
? assets.map((asset) => {
let flagSummary = null;
if (asset.action_summaries) {
flagSummary = asset.action_summaries.find(s => s.__typename === 'FlagAssetActionSummary');
flagSummary = asset.action_summaries.find((s) => s.__typename === 'FlagAssetActionSummary');
}
return (
@@ -17,8 +17,8 @@ const LikeWidget = ({assets}) => {
<div className={styles.widgetTable}>
{
assets.length
? assets.map(asset => {
const likeSummary = asset.action_summaries.find(s => s.type === 'LikeAssetActionSummary');
? assets.map((asset) => {
const likeSummary = asset.action_summaries.find((s) => s.type === 'LikeAssetActionSummary');
return (
<div className={styles.rowLinkify} key={asset.id}>
<Link className={styles.linkToModerate} to={`/admin/moderate/flagged/${asset.id}`}>Moderate</Link>
@@ -7,7 +7,7 @@ import BanUserDialog from 'coral-admin/src/components/BanUserDialog';
const lang = new I18n();
const MostLikedCommentsWidget = props => {
const MostLikedCommentsWidget = (props) => {
const {
comments,
moderation,
@@ -64,32 +64,32 @@ InstallContainer.contextTypes = {
router: React.PropTypes.object
};
const mapStateToProps = state => ({
const mapStateToProps = (state) => ({
install: state.install.toJS()
});
const mapDispatchToProps = dispatch => ({
const mapDispatchToProps = (dispatch) => ({
nextStep: () => dispatch(nextStep()),
goToStep: step => dispatch(goToStep(step)),
goToStep: (step) => dispatch(goToStep(step)),
previousStep: () => dispatch(previousStep()),
finishInstall: () => dispatch(finishInstall()),
checkInstall: next => dispatch(checkInstall(next)),
handleDomainsChange: value => {
checkInstall: (next) => dispatch(checkInstall(next)),
handleDomainsChange: (value) => {
dispatch(updatePermittedDomains(value));
},
handleSettingsChange: e => {
handleSettingsChange: (e) => {
const {name, value} = e.currentTarget;
dispatch(updateSettingsFormData(name, value));
},
handleUserChange: e => {
handleUserChange: (e) => {
const {name, value} = e.currentTarget;
dispatch(updateUserFormData(name, value));
},
handleSettingsSubmit: e => {
handleSettingsSubmit: (e) => {
e.preventDefault();
dispatch(submitSettings());
},
handleUserSubmit: e => {
handleUserSubmit: (e) => {
e.preventDefault();
dispatch(submitUser());
}
@@ -6,7 +6,7 @@ const lang = new I18n();
import I18n from 'coral-i18n/modules/i18n/i18n';
const AddOrganizationName = props => {
const AddOrganizationName = (props) => {
const {handleSettingsChange, handleSettingsSubmit, install} = props;
return (
<div className={styles.step}>
@@ -6,7 +6,7 @@ const lang = new I18n();
import I18n from 'coral-i18n/modules/i18n/i18n';
const InitialStep = props => {
const InitialStep = (props) => {
const {handleUserChange, handleUserSubmit, install} = props;
return (
<div className={styles.step}>
@@ -6,7 +6,7 @@ const lang = new I18n();
import I18n from 'coral-i18n/modules/i18n/i18n';
const InitialStep = props => {
const InitialStep = (props) => {
const {nextStep} = props;
return (
<div className={styles.step}>
@@ -2,7 +2,7 @@ import React from 'react';
import styles from './style.css';
import {Button, Select, Option, TextField} from 'coral-ui';
const InviteTeamMembers = props => {
const InviteTeamMembers = (props) => {
const {nextStep} = props;
return (
<div className={styles.step}>
@@ -7,7 +7,7 @@ const lang = new I18n();
import I18n from 'coral-i18n/modules/i18n/i18n';
const PermittedDomainsStep = props => {
const PermittedDomainsStep = (props) => {
const {finishInstall, install, handleDomainsChange} = props;
const domains = install.data.settings.domains.whitelist;
return (
@@ -19,8 +19,8 @@ const PermittedDomainsStep = props => {
value={domains}
inputProps={{placeholder: 'URL'}}
addOnPaste={true}
pasteSplit={data => data.split(',').map(d => d.trim())}
onChange={tags => handleDomainsChange(tags)}
pasteSplit={(data) => data.split(',').map((d) => d.trim())}
onChange={(tags) => handleDomainsChange(tags)}
/>
</Card>
<Button cStyle='green' onClick={finishInstall} raised>{lang.t('PERMITTED_DOMAINS.SUBMIT')}</Button>
@@ -1,20 +1,21 @@
import React, {Component} from 'react';
import {connect} from 'react-redux';
import Layout from '../components/ui/Layout';
import {checkLogin, handleLogin, logout, requestPasswordReset} from '../actions/auth';
import {toggleModal as toggleShortcutModal} from '../actions/moderation';
import {fetchConfig} from '../actions/config';
import {FullLoading} from '../components/FullLoading';
import AdminLogin from '../components/AdminLogin';
import {logout} from 'coral-framework/actions/auth';
import {FullLoading} from '../components/FullLoading';
import {toggleModal as toggleShortcutModal} from '../actions/moderation';
import {checkLogin, handleLogin, requestPasswordReset} from '../actions/auth';
class LayoutContainer extends Component {
componentWillMount () {
componentWillMount() {
const {checkLogin, fetchConfig} = this.props;
checkLogin();
fetchConfig();
}
render () {
render() {
const {
isAdmin,
loggedIn,
@@ -24,39 +25,54 @@ class LayoutContainer extends Component {
passwordRequestSuccess
} = this.props.auth;
const {handleLogout, toggleShortcutModal, TALK_RECAPTCHA_PUBLIC} = this.props;
if (loadingUser) { return <FullLoading />; }
const {
handleLogout,
toggleShortcutModal,
TALK_RECAPTCHA_PUBLIC
} = this.props;
if (loadingUser) {
return <FullLoading />;
}
if (!isAdmin) {
return <AdminLogin
loginMaxExceeded={loginMaxExceeded}
handleLogin={this.props.handleLogin}
requestPasswordReset={this.props.requestPasswordReset}
passwordRequestSuccess={passwordRequestSuccess}
recaptchaPublic={TALK_RECAPTCHA_PUBLIC}
errorMessage={loginError} />;
return (
<AdminLogin
loginMaxExceeded={loginMaxExceeded}
handleLogin={this.props.handleLogin}
requestPasswordReset={this.props.requestPasswordReset}
passwordRequestSuccess={passwordRequestSuccess}
recaptchaPublic={TALK_RECAPTCHA_PUBLIC}
errorMessage={loginError}
/>
);
}
if (isAdmin && loggedIn) {
return <Layout handleLogout={handleLogout} toggleShortcutModal={toggleShortcutModal} {...this.props} />;
return (
<Layout
handleLogout={handleLogout}
toggleShortcutModal={toggleShortcutModal}
{...this.props}
/>
);
}
return <FullLoading />;
}
}
const mapStateToProps = state => ({
const mapStateToProps = (state) => ({
auth: state.auth.toJS(),
TALK_RECAPTCHA_PUBLIC: state.config.get('data').get('TALK_RECAPTCHA_PUBLIC', null)
TALK_RECAPTCHA_PUBLIC: state.config
.get('data')
.get('TALK_RECAPTCHA_PUBLIC', null)
});
const mapDispatchToProps = dispatch => ({
const mapDispatchToProps = (dispatch) => ({
checkLogin: () => dispatch(checkLogin()),
fetchConfig: () => dispatch(fetchConfig()),
handleLogin: (username, password, recaptchaResponse) => dispatch(handleLogin(username, password, recaptchaResponse)),
requestPasswordReset: email => dispatch(requestPasswordReset(email)),
toggleShortcutModal: toggle => dispatch(toggleShortcutModal(toggle)),
handleLogin: (username, password, recaptchaResponse) =>
dispatch(handleLogin(username, password, recaptchaResponse)),
requestPasswordReset: (email) => dispatch(requestPasswordReset(email)),
toggleShortcutModal: (toggle) => dispatch(toggleShortcutModal(toggle)),
handleLogout: () => dispatch(logout())
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(LayoutContainer);
export default connect(mapStateToProps, mapDispatchToProps)(LayoutContainer);
@@ -43,12 +43,13 @@ class ModerationContainer extends Component {
const {acceptComment, rejectComment} = this.props;
const {selectedIndex} = this.state;
const comments = this.getComments();
const commentId = {commentId: comments[selectedIndex].id};
const comment = comments[selectedIndex];
const commentId = {commentId: comment.id};
if (accept) {
acceptComment(commentId);
comment.status !== 'ACCEPTED' && acceptComment(commentId);
} else {
rejectComment(commentId);
comment.status !== 'REJECTED' && rejectComment(commentId);
}
}
@@ -60,14 +61,14 @@ class ModerationContainer extends Component {
select = (next) => () => {
if (next) {
this.setState(prevState =>
this.setState((prevState) =>
({
...prevState,
selectedIndex: prevState.selectedIndex < this.getComments().length - 1
? prevState.selectedIndex + 1 : prevState.selectedIndex
}));
} else {
this.setState(prevState =>
this.setState((prevState) =>
({
...prevState,
selectedIndex: prevState.selectedIndex > 0 ?
@@ -125,7 +126,7 @@ class ModerationContainer extends Component {
}
if (providedAssetId) {
asset = assets.find(asset => asset.id === this.props.params.id);
asset = assets.find((asset) => asset.id === this.props.params.id);
if (!asset) {
return <NotFoundAsset assetId={providedAssetId} />;
@@ -185,6 +186,7 @@ class ModerationContainer extends Component {
open={moderation.banDialog}
user={moderation.user}
commentId={moderation.commentId}
commentStatus={moderation.commentStatus}
handleClose={props.hideBanUserDialog}
handleBanUser={props.banUser}
showRejectedNote={moderation.showRejectedNote}
@@ -200,19 +202,19 @@ class ModerationContainer extends Component {
}
}
const mapStateToProps = state => ({
const mapStateToProps = (state) => ({
moderation: state.moderation.toJS(),
settings: state.settings.toJS(),
assets: state.assets.get('assets')
});
const mapDispatchToProps = dispatch => ({
toggleModal: toggle => dispatch(toggleModal(toggle)),
const mapDispatchToProps = (dispatch) => ({
toggleModal: (toggle) => dispatch(toggleModal(toggle)),
onClose: () => dispatch(toggleModal(false)),
singleView: () => dispatch(singleView()),
updateAssets: assets => dispatch(updateAssets(assets)),
updateAssets: (assets) => dispatch(updateAssets(assets)),
fetchSettings: () => dispatch(fetchSettings()),
showBanUserDialog: (user, commentId, showRejectedNote) => dispatch(showBanUserDialog(user, commentId, showRejectedNote)),
showBanUserDialog: (user, commentId, commentStatus, showRejectedNote) => dispatch(showBanUserDialog(user, commentId, commentStatus, showRejectedNote)),
hideBanUserDialog: () => dispatch(hideBanUserDialog(false)),
hideShortcutsNote: () => dispatch(hideShortcutsNote()),
});
@@ -1,6 +1,6 @@
import React from 'react';
const ModerationLayout = props => (
const ModerationLayout = (props) => (
<div>
{props.children}
</div>
@@ -1,27 +1,36 @@
import React, {PropTypes} from 'react';
import timeago from 'timeago.js';
import Linkify from 'react-linkify';
import Highlighter from 'react-highlight-words';
import {Link} from 'react-router';
import Linkify from 'react-linkify';
import styles from './styles.css';
import {Icon} from 'coral-ui';
import FlagBox from './FlagBox';
import styles from './styles.css';
import CommentType from './CommentType';
import Highlighter from 'react-highlight-words';
import Slot from 'coral-framework/components/Slot';
import {getActionSummary} from 'coral-framework/utils';
import ActionButton from 'coral-admin/src/components/ActionButton';
import BanUserButton from 'coral-admin/src/components/BanUserButton';
import {getActionSummary} from 'coral-framework/utils';
const linkify = new Linkify();
import I18n from 'coral-i18n/modules/i18n/i18n';
const lang = new I18n();
const Comment = ({actions = [], comment, ...props}) => {
const Comment = ({
actions = [],
comment,
suspectWords,
bannedWords,
...props
}) => {
const links = linkify.getMatches(comment.body);
const linkText = links ? links.map(link => link.raw) : [];
const linkText = links ? links.map((link) => link.raw) : [];
const flagActionSummaries = getActionSummary('FlagActionSummary', comment);
const flagActions = comment.actions && comment.actions.filter(a => a.__typename === 'FlagAction');
const flagActions =
comment.actions &&
comment.actions.filter((a) => a.__typename === 'FlagAction');
let commentType = '';
if (comment.status === 'PREMOD') {
commentType = 'premod';
@@ -29,8 +38,20 @@ const Comment = ({actions = [], comment, ...props}) => {
commentType = 'flagged';
}
// since words are checked against word boundaries on the backend,
// this should be the behavior on the front end as well.
// currently the highlighter plugin does not support this out of the box.
const searchWords = [...suspectWords, ...bannedWords]
.filter((w) => {
return new RegExp(`(^|\\s)${w}(\\s|$)`).test(comment.body);
})
.concat(linkText);
return (
<li tabIndex={props.index} className={`mdl-card ${props.selected ? 'mdl-shadow--16dp' : 'mdl-shadow--2dp'} ${styles.Comment} ${styles.listItem} ${props.selected ? styles.selected : ''}`}>
<li
tabIndex={props.index}
className={`mdl-card ${props.selected ? 'mdl-shadow--16dp' : 'mdl-shadow--2dp'} ${styles.Comment} ${styles.listItem} ${props.selected ? styles.selected : ''}`}
>
<div className={styles.container}>
<div className={styles.itemHeader}>
<div className={styles.author}>
@@ -38,53 +59,95 @@ const Comment = ({actions = [], comment, ...props}) => {
{comment.user.name}
</span>
<span className={styles.created}>
{timeago().format(comment.created_at || (Date.now() - props.index * 60 * 1000), lang.getLocale().replace('-', '_'))}
{timeago().format(
comment.created_at || Date.now() - props.index * 60 * 1000,
lang.getLocale().replace('-', '_')
)}
</span>
<BanUserButton user={comment.user} onClick={() => props.showBanUserDialog(comment.user, comment.id, comment.status !== 'REJECTED')} />
<BanUserButton
user={comment.user}
onClick={() =>
props.showBanUserDialog(
comment.user,
comment.id,
comment.status,
comment.status !== 'REJECTED'
)}
/>
<CommentType type={commentType} />
</div>
{comment.user.status === 'banned' ?
<span className={styles.banned}>
<Icon name='error_outline'/>
{lang.t('comment.banned_user')}
</span>
{comment.user.status === 'banned'
? <span className={styles.banned}>
<Icon name="error_outline" />
{lang.t('comment.banned_user')}
</span>
: null}
<Slot fill="adminCommentInfoBar" comment={comment} />
</div>
<div className={styles.moderateArticle}>
Story: {comment.asset.title}
{!props.currentAsset && (
<Link to={`/admin/moderate/${comment.asset.id}`}>Moderate </Link>
)}
{!props.currentAsset &&
<Link to={`/admin/moderate/${comment.asset.id}`}>Moderate </Link>}
</div>
<div className={styles.itemBody}>
<p className={styles.body}>
<Highlighter
searchWords={[...props.suspectWords, ...props.bannedWords, ...linkText]}
textToHighlight={comment.body} />
searchWords={searchWords}
textToHighlight={comment.body}
/>
{' '}
<a
className={styles.external}
href={`${comment.asset.url}#${comment.id}`}
target="_blank"
>
<Icon name="open_in_new" /> {lang.t('comment.view_context')}
</a>
</p>
<Slot fill="adminCommentContent" comment={comment} />
<div className={styles.sideActions}>
{links ? <span className={styles.hasLinks}><Icon name='error_outline'/> Contains Link</span> : null}
{links
? <span className={styles.hasLinks}>
<Icon name="error_outline" /> Contains Link
</span>
: null}
<div className={`actions ${styles.actions}`}>
{actions.map((action, i) => {
const active = (action === 'REJECT' && comment.status === 'REJECTED') ||
(action === 'APPROVE' && comment.status === 'ACCEPTED');
return <ActionButton key={i}
type={action}
user={comment.user}
status={comment.status}
active={active}
acceptComment={() => props.acceptComment({commentId: comment.id})}
rejectComment={() => props.rejectComment({commentId: comment.id})} />;
const active =
(action === 'REJECT' && comment.status === 'REJECTED') ||
(action === 'APPROVE' && comment.status === 'ACCEPTED');
return (
<ActionButton
key={i}
type={action}
user={comment.user}
status={comment.status}
active={active}
acceptComment={() =>
(comment.status === 'ACCEPTED'
? null
: props.acceptComment({commentId: comment.id}))}
rejectComment={() =>
(comment.status === 'REJECTED'
? null
: props.rejectComment({commentId: comment.id}))}
/>
);
})}
</div>
<Slot fill="adminSideActions" comment={comment} />
</div>
</div>
</div>
{
flagActions && flagActions.length
? <FlagBox actions={flagActions} actionSummaries={flagActionSummaries} />
: null
}
<div>
<Slot fill="adminCommentDetailArea" comment={comment} />
</div>
{flagActions && flagActions.length
? <FlagBox
actions={flagActions}
actionSummaries={flagActionSummaries}
/>
: null}
</li>
);
};
@@ -105,6 +168,7 @@ Comment.propTypes = {
}),
asset: PropTypes.shape({
title: PropTypes.string,
url: PropTypes.string,
id: PropTypes.string
})
})
@@ -2,7 +2,7 @@ import React, {PropTypes} from 'react';
import styles from './CommentType.css';
import {Icon} from 'coral-ui';
const CommentType = props => {
const CommentType = (props) => {
const typeData = getTypeData(props.type);
return (
@@ -12,7 +12,7 @@ const CommentType = props => {
);
};
const getTypeData = type => {
const getTypeData = (type) => {
switch (type) {
case 'premod':
return {icon: 'query_builder', text: 'Pre-Mod', className: 'premod'};
@@ -54,7 +54,7 @@ class FlagBox extends Component {
<ul>
{actionSummaries.map((summary, i) => {
const actionList = actions.filter(a => a.reason === summary.reason);
const actionList = actions.filter((a) => a.reason === summary.reason);
return (
<li key={i}>
@@ -3,7 +3,7 @@ import {Link} from 'react-router';
import {Icon} from 'coral-ui';
import styles from './styles.css';
const ModerationHeader = props => (
const ModerationHeader = (props) => (
<div className=''>
<div className={`mdl-tabs ${styles.header}`}>
{
@@ -27,12 +27,6 @@ const ModerationMenu = (
activeClassName={styles.active}>
<Icon name='question_answer' className={styles.tabIcon} /> {lang.t('modqueue.all')} <CommentCount count={allCount} />
</Link>
<Link
to={getPath('accepted')}
className={`mdl-tabs__tab ${styles.tab}`}
activeClassName={styles.active}>
<Icon name='check' className={styles.tabIcon} /> {lang.t('modqueue.approved')} <CommentCount count={acceptedCount} />
</Link>
<Link
to={getPath('premod')}
className={`mdl-tabs__tab ${styles.tab}`}
@@ -45,6 +39,12 @@ const ModerationMenu = (
activeClassName={styles.active}>
<Icon name='flag' className={styles.tabIcon} /> {lang.t('modqueue.flagged')} <CommentCount count={flaggedCount} />
</Link>
<Link
to={getPath('accepted')}
className={`mdl-tabs__tab ${styles.tab}`}
activeClassName={styles.active}>
<Icon name='check' className={styles.tabIcon} /> {lang.t('modqueue.approved')} <CommentCount count={acceptedCount} />
</Link>
<Link
to={getPath('rejected')}
className={`mdl-tabs__tab ${styles.tab}`}
@@ -56,7 +56,7 @@ const ModerationMenu = (
className={styles.selectField}
label="Sort"
value={sort}
onChange={sort => selectSort(sort)}>
onChange={(sort) => selectSort(sort)}>
<Option value={'REVERSE_CHRONOLOGICAL'}>Newest First</Option>
<Option value={'CHRONOLOGICAL'}>Oldest First</Option>
</SelectField>
@@ -2,7 +2,7 @@ import React from 'react';
import {Link} from 'react-router';
import styles from './styles.css';
const NotFound = props => (
const NotFound = (props) => (
<div className={`mdl-card mdl-shadow--2dp ${styles.notFound}`}>
<p>
The provided asset id <Link to={`/admin/moderate/${props.assetId}`}>{props.assetId}</Link> does not exist.
@@ -423,3 +423,24 @@ span {
position: relative;
top: 7px;
}
.external {
font-size: .7em;
text-decoration: none;
color: #063b9a;
cursor: pointer;
font-weight: normal;
margin-left: 10px;
white-space: nowrap;
&:hover {
text-decoration: underline;
opacity: .9;
}
i {
font-size: 12px;
top: 2px;
position: relative;
}
}
@@ -54,7 +54,7 @@ class Stories extends Component {
onStatusClick = (closeStream, id, statusMenuOpen) => () => {
if (statusMenuOpen) {
this.setState(prev => {
this.setState((prev) => {
prev.statusMenus[id] = false;
return prev;
});
@@ -64,7 +64,7 @@ class Stories extends Component {
this.props.fetchAssets(page, limit, search, sort, filter);
});
} else {
this.setState(prev => {
this.setState((prev) => {
prev.statusMenus[id] = true;
return prev;
});
@@ -54,7 +54,7 @@ class Stories extends Component {
onStatusClick = (closeStream, id, statusMenuOpen) => () => {
if (statusMenuOpen) {
this.setState(prev => {
this.setState((prev) => {
prev.statusMenus[id] = false;
return prev;
});
@@ -64,7 +64,7 @@ class Stories extends Component {
this.props.fetchAssets(page, limit, search, sort, filter);
});
} else {
this.setState(prev => {
this.setState((prev) => {
prev.statusMenus[id] = true;
return prev;
});
@@ -11,6 +11,7 @@ fragment commentView on Comment {
asset {
id
title
url
}
action_summaries {
count
@@ -56,7 +56,7 @@ export const setCommentStatus = graphql(SET_COMMENT_STATUS, {
updateQueries: {
ModQueue: (oldData) => {
const comment = views.reduce((comment, view) => {
return comment ? comment : oldData[view].find(c => c.id === commentId);
return comment ? comment : oldData[view].find((c) => c.id === commentId);
}, null);
let accepted;
let acceptedCount = oldData.acceptedCount;
@@ -70,9 +70,9 @@ export const setCommentStatus = graphql(SET_COMMENT_STATUS, {
accepted = [comment, ...oldData.accepted];
}
const premod = oldData.premod.filter(c => c.id !== commentId);
const flagged = oldData.flagged.filter(c => c.id !== commentId);
const rejected = oldData.rejected.filter(c => c.id !== commentId);
const premod = oldData.premod.filter((c) => c.id !== commentId);
const flagged = oldData.flagged.filter((c) => c.id !== commentId);
const rejected = oldData.rejected.filter((c) => c.id !== commentId);
const premodCount = premod.length < oldData.premod.length ? oldData.premodCount - 1 : oldData.premodCount;
const flaggedCount = flagged.length < oldData.flagged.length ? oldData.flaggedCount - 1 : oldData.flaggedCount;
const rejectedCount = rejected.length < oldData.rejected.length ? oldData.rejectedCount - 1 : oldData.rejectedCount;
@@ -101,7 +101,7 @@ export const setCommentStatus = graphql(SET_COMMENT_STATUS, {
updateQueries: {
ModQueue: (oldData) => {
const comment = views.reduce((comment, view) => {
return comment ? comment : oldData[view].find(c => c.id === commentId);
return comment ? comment : oldData[view].find((c) => c.id === commentId);
}, null);
let rejected;
let rejectedCount = oldData.rejectedCount;
@@ -115,9 +115,9 @@ export const setCommentStatus = graphql(SET_COMMENT_STATUS, {
rejected = [comment, ...oldData.rejected];
}
const premod = oldData.premod.filter(c => c.id !== commentId);
const flagged = oldData.flagged.filter(c => c.id !== commentId);
const accepted = oldData.accepted.filter(c => c.id !== commentId);
const premod = oldData.premod.filter((c) => c.id !== commentId);
const flagged = oldData.flagged.filter((c) => c.id !== commentId);
const accepted = oldData.accepted.filter((c) => c.id !== commentId);
const premodCount = premod.length < oldData.premod.length ? oldData.premodCount - 1 : oldData.premodCount;
const flaggedCount = flagged.length < oldData.flagged.length ? oldData.flaggedCount - 1 : oldData.flaggedCount;
const acceptedCount = accepted.length < oldData.accepted.length ? oldData.acceptedCount - 1 : oldData.acceptedCount;
+1 -3
View File
@@ -26,10 +26,8 @@ export default function auth (state = initialState, action) {
.set('loadingUser', false)
.set('isAdmin', action.isAdmin)
.set('user', action.user);
case actions.LOGOUT_SUCCESS:
case actions.LOGOUT:
return initialState;
case actions.LOGIN_REQUEST:
return state.set('loginError', null);
case actions.LOGIN_SUCCESS:
return state.set('loginMaxExceeded', false).set('loginError', null);
case actions.LOGIN_FAILURE:
+4 -4
View File
@@ -53,17 +53,17 @@ export default function community (state = initialState, action) {
}
case SET_ROLE : {
const commenters = state.get('accounts');
const idx = commenters.findIndex(el => el.id === action.id);
const idx = commenters.findIndex((el) => el.id === action.id);
commenters[idx].roles[0] = action.role;
return state.set('accounts', commenters.map(id => id));
return state.set('accounts', commenters.map((id) => id));
}
case SET_COMMENTER_STATUS: {
const commenters = state.get('accounts');
const idx = commenters.findIndex(el => el.id === action.id);
const idx = commenters.findIndex((el) => el.id === action.id);
commenters[idx].status = action.status;
return state.set('accounts', commenters.map(id => id));
return state.set('accounts', commenters.map((id) => id));
}
case SORT_UPDATE :
@@ -6,6 +6,7 @@ const initialState = Map({
modalOpen: false,
user: Map({}),
commentId: null,
commentStatus: null,
banDialog: false,
shortcutsNoteVisible: window.localStorage.getItem('coral:shortcutsNote') || 'show'
});
@@ -14,12 +15,14 @@ export default function moderation (state = initialState, action) {
switch (action.type) {
case actions.HIDE_BANUSER_DIALOG:
return state
.set('banDialog', false);
.set('banDialog', false)
.set('commentStatus', null);
case actions.SHOW_BANUSER_DIALOG:
return state
.merge({
user: Map(action.user),
commentId: action.commentId,
commentStatus: action.commentStatus,
showRejectedNote: action.showRejectedNote,
banDialog: true
});
+2 -2
View File
@@ -1,5 +1,5 @@
import ApolloClient, {addTypename} from 'apollo-client';
import getNetworkInterface from './transport';
import {networkInterface} from 'coral-framework/services/transport';
import fragmentMatcher from './fragmentMatcher';
export const client = new ApolloClient({
@@ -12,5 +12,5 @@ export const client = new ApolloClient({
}
return null;
},
networkInterface: getNetworkInterface()
networkInterface
});
@@ -39,7 +39,7 @@ const fm = new IntrospectionFragmentMatcher({
{name: 'DefaultAction'},
{name: 'FlagAction'},
{name: 'DontAgreeAction'}
],
]
},
{
kind: 'INTERFACE',
@@ -48,18 +48,18 @@ const fm = new IntrospectionFragmentMatcher({
{name: 'DefaultActionSummary'},
{name: 'FlagActionSummary'},
{name: 'DontAgreeActionSummary'}
],
]
},
{
kind: 'INTERFACE',
name: 'AssetActionSummary',
possibleTypes: [
{name: 'DefaultAssetActionSummary'},
{name: 'FlagAssetActionSummary'},
{name: 'FlagAssetActionSummary'}
]
}
],
},
]
}
}
});
@@ -1,11 +0,0 @@
import {createNetworkInterface} from 'apollo-client';
export default function getNetworkInterface(apiUrl = '/api/v1/graph/ql', headers = {}) {
return new createNetworkInterface({
uri: apiUrl,
opts: {
credentials: 'same-origin',
headers,
},
});
}
+2
View File
@@ -72,6 +72,7 @@
"flagged": "flagged",
"anon": "Anonymous",
"ban_user": "Ban User",
"view_context": "View context",
"banned_user": "Banned User"
},
"user": {
@@ -259,6 +260,7 @@
"comment": {
"flagged": "marcado",
"anon": "Anónimo",
"view_context": "Ver contexto",
"ban_user": "Suspender Usuario",
"banned_user": "Usuario Suspendido"
},