mirror of
https://github.com/wassname/talk.git
synced 2026-09-11 12:51:33 +08:00
Merge branch 'master' into slots-b
This commit is contained in:
@@ -42,6 +42,9 @@ const routes = (
|
||||
<Route path='all' components={ModerationContainer}>
|
||||
<Route path=':id' components={ModerationContainer} />
|
||||
</Route>
|
||||
<Route path='accepted' components={ModerationContainer}>
|
||||
<Route path=':id' components={ModerationContainer} />
|
||||
</Route>
|
||||
<Route path='premod' components={ModerationContainer}>
|
||||
<Route path=':id' components={ModerationContainer} />
|
||||
</Route>
|
||||
|
||||
@@ -6,6 +6,13 @@ import {menuActionsMap} from '../containers/ModerationQueue/helpers/moderationQu
|
||||
const ActionButton = ({type = '', status, ...props}) => {
|
||||
const typeName = type.toLowerCase();
|
||||
const active = ((type === 'REJECT' && status === 'REJECTED') || (type === 'APPROVE' && status === 'ACCEPTED'));
|
||||
let text = menuActionsMap[type].text;
|
||||
|
||||
if (text === 'Approve' && active) {
|
||||
text = 'Approved';
|
||||
} else if (text === 'Reject' && active) {
|
||||
text = 'Rejected';
|
||||
}
|
||||
|
||||
return (
|
||||
<Button
|
||||
@@ -13,7 +20,7 @@ const ActionButton = ({type = '', status, ...props}) => {
|
||||
cStyle={typeName}
|
||||
icon={menuActionsMap[type].icon}
|
||||
onClick={type === 'APPROVE' ? props.acceptComment : props.rejectComment}
|
||||
>{menuActionsMap[type].text}</Button>
|
||||
>{text}</Button>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -138,6 +138,9 @@ class ModerationContainer extends Component {
|
||||
case 'all':
|
||||
activeTabCount = data.allCount;
|
||||
break;
|
||||
case 'accepted':
|
||||
activeTabCount = data.acceptedCount;
|
||||
break;
|
||||
case 'premod':
|
||||
activeTabCount = data.premodCount;
|
||||
break;
|
||||
@@ -155,6 +158,7 @@ class ModerationContainer extends Component {
|
||||
<ModerationMenu
|
||||
asset={asset}
|
||||
allCount={data.allCount}
|
||||
acceptedCount={data.acceptedCount}
|
||||
premodCount={data.premodCount}
|
||||
rejectedCount={data.rejectedCount}
|
||||
flaggedCount={data.flaggedCount}
|
||||
|
||||
@@ -23,7 +23,7 @@ LoadMore.propTypes = {
|
||||
comments: PropTypes.array.isRequired,
|
||||
loadMore: PropTypes.func.isRequired,
|
||||
sort: PropTypes.oneOf(['CHRONOLOGICAL', 'REVERSE_CHRONOLOGICAL']).isRequired,
|
||||
tab: PropTypes.oneOf(['rejected', 'premod', 'flagged', 'all']).isRequired,
|
||||
tab: PropTypes.oneOf(['rejected', 'premod', 'flagged', 'all', 'accepted']).isRequired,
|
||||
assetId: PropTypes.string,
|
||||
showLoadMore: PropTypes.bool.isRequired
|
||||
};
|
||||
|
||||
@@ -10,7 +10,7 @@ import {Link} from 'react-router';
|
||||
const lang = new I18n(translations);
|
||||
|
||||
const ModerationMenu = (
|
||||
{asset, allCount, premodCount, rejectedCount, flaggedCount, selectSort, sort}
|
||||
{asset, allCount, acceptedCount, premodCount, rejectedCount, flaggedCount, selectSort, sort}
|
||||
) => {
|
||||
|
||||
function getPath (type) {
|
||||
@@ -28,6 +28,12 @@ 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}`}
|
||||
|
||||
@@ -54,6 +54,19 @@ export const setCommentStatus = graphql(SET_COMMENT_STATUS, {
|
||||
},
|
||||
updateQueries: {
|
||||
ModQueue: (oldData) => {
|
||||
const comment = oldData.all.find(c => c.id === commentId);
|
||||
let accepted;
|
||||
let acceptedCount = oldData.acceptedCount;
|
||||
|
||||
// if the comment was already in the Approved queue, don't re-add it
|
||||
if (comment.status === 'ACCEPTED') {
|
||||
accepted = [...oldData.accepted];
|
||||
} else {
|
||||
comment.status = 'ACCEPTED';
|
||||
acceptedCount++;
|
||||
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);
|
||||
@@ -65,9 +78,11 @@ export const setCommentStatus = graphql(SET_COMMENT_STATUS, {
|
||||
...oldData,
|
||||
premodCount,
|
||||
flaggedCount,
|
||||
acceptedCount,
|
||||
rejectedCount,
|
||||
premod,
|
||||
flagged,
|
||||
accepted,
|
||||
rejected,
|
||||
};
|
||||
}
|
||||
@@ -82,21 +97,35 @@ export const setCommentStatus = graphql(SET_COMMENT_STATUS, {
|
||||
},
|
||||
updateQueries: {
|
||||
ModQueue: (oldData) => {
|
||||
const comment = oldData.premod.concat(oldData.flagged).filter(c => c.id === commentId)[0];
|
||||
const rejected = [comment].concat(oldData.rejected);
|
||||
const comment = oldData.all.find(c => c.id === commentId);
|
||||
let rejected;
|
||||
let rejectedCount = oldData.rejectedCount;
|
||||
|
||||
// if the item was already in the Rejected queue, don't put it in again
|
||||
if (comment.status === 'REJECTED') {
|
||||
rejected = oldData.rejected;
|
||||
} else {
|
||||
comment.status = 'REJECTED';
|
||||
rejectedCount++;
|
||||
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 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 = oldData.rejectedCount + 1;
|
||||
const acceptedCount = accepted.length < oldData.accepted.length ? oldData.acceptedCount - 1 : oldData.acceptedCount;
|
||||
|
||||
return {
|
||||
...oldData,
|
||||
premodCount,
|
||||
flaggedCount,
|
||||
acceptedCount,
|
||||
rejectedCount,
|
||||
premod,
|
||||
flagged,
|
||||
accepted,
|
||||
rejected
|
||||
};
|
||||
}
|
||||
|
||||
@@ -39,6 +39,9 @@ export const loadMore = (fetchMore) => ({limit, cursor, sort, tab, asset_id}) =>
|
||||
case 'all':
|
||||
statuses = null;
|
||||
break;
|
||||
case 'accepted':
|
||||
statuses = ['ACCEPTED'];
|
||||
break;
|
||||
case 'premod':
|
||||
statuses = ['PREMOD'];
|
||||
break;
|
||||
|
||||
@@ -8,6 +8,13 @@ query ModQueue ($asset_id: ID, $sort: SORT_ORDER) {
|
||||
}) {
|
||||
...commentView
|
||||
}
|
||||
accepted: comments(query: {
|
||||
statuses: [ACCEPTED],
|
||||
asset_id: $asset_id,
|
||||
sort: $sort
|
||||
}) {
|
||||
...commentView
|
||||
}
|
||||
premod: comments(query: {
|
||||
statuses: [PREMOD],
|
||||
asset_id: $asset_id,
|
||||
@@ -38,6 +45,10 @@ query ModQueue ($asset_id: ID, $sort: SORT_ORDER) {
|
||||
allCount: commentCount(query: {
|
||||
asset_id: $asset_id
|
||||
})
|
||||
acceptedCount: commentCount(query: {
|
||||
statuses: [ACCEPTED],
|
||||
asset_id: $asset_id
|
||||
})
|
||||
premodCount: commentCount(query: {
|
||||
statuses: [PREMOD],
|
||||
asset_id: $asset_id
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
"modqueue": {
|
||||
"likes": "likes",
|
||||
"all": "all",
|
||||
"approved": "approved",
|
||||
"premod": "pre-mod",
|
||||
"rejected": "rejected",
|
||||
"flagged": "flagged",
|
||||
@@ -227,6 +228,8 @@
|
||||
"loading": "Cargando resultados"
|
||||
},
|
||||
"modqueue": {
|
||||
"all": "todos",
|
||||
"approved": "aprobado",
|
||||
"likes": "gustos",
|
||||
"premod": "pre-mod",
|
||||
"rejected": "rechazado",
|
||||
|
||||
@@ -33,12 +33,14 @@ export default class Embed extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
handleShowProfile = () => this.props.setActiveTab('profile');
|
||||
|
||||
render () {
|
||||
const {activeTab, logout, viewAllComments, commentId} = this.props;
|
||||
const {asset: {totalCommentCount}} = this.props.root;
|
||||
const {loggedIn, isAdmin, user} = this.props.auth;
|
||||
|
||||
const userBox = <UserBox user={user} logout={logout} changeTab={this.changeTab}/>;
|
||||
const userBox = <UserBox user={user} onLogout={logout} onShowProfile={this.handleShowProfile}/>;
|
||||
|
||||
return (
|
||||
<div>
|
||||
|
||||
@@ -3,6 +3,8 @@ import {compose, gql, graphql} from 'react-apollo';
|
||||
import {connect} from 'react-redux';
|
||||
import {bindActionCreators} from 'redux';
|
||||
import isEqual from 'lodash/isEqual';
|
||||
import branch from 'recompose/branch';
|
||||
import renderComponent from 'recompose/renderComponent';
|
||||
|
||||
import {Spinner} from 'coral-ui';
|
||||
import {authActions, assetActions, pym} from 'coral-framework';
|
||||
@@ -19,7 +21,6 @@ class EmbedContainer extends React.Component {
|
||||
|
||||
componentDidMount() {
|
||||
pym.sendMessage('childReady');
|
||||
this.props.checkLogin();
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
@@ -108,6 +109,10 @@ const mapDispatchToProps = dispatch =>
|
||||
|
||||
export default compose(
|
||||
connect(mapStateToProps, mapDispatchToProps),
|
||||
branch(
|
||||
props => !props.auth.checkedInitialLogin,
|
||||
renderComponent(Spinner),
|
||||
),
|
||||
withQuery,
|
||||
)(EmbedContainer);
|
||||
|
||||
|
||||
@@ -19,24 +19,13 @@ const {showSignInDialog} = authActions;
|
||||
const {addNotification} = notificationActions;
|
||||
|
||||
class StreamContainer extends React.Component {
|
||||
getCounts = ({asset_id, limit, sort}) => {
|
||||
getCounts = (variables) => {
|
||||
return this.props.data.fetchMore({
|
||||
query: LOAD_COMMENT_COUNTS_QUERY,
|
||||
variables: {
|
||||
asset_id,
|
||||
limit,
|
||||
sort,
|
||||
excludeIgnored: this.props.data.variables.excludeIgnored,
|
||||
},
|
||||
updateQuery: (oldData, {fetchMoreResult:{asset}}) => {
|
||||
return {
|
||||
...oldData,
|
||||
asset: {
|
||||
...oldData.asset,
|
||||
commentCount: asset.commentCount
|
||||
}
|
||||
};
|
||||
}
|
||||
variables,
|
||||
|
||||
// Apollo requires this, even though we don't use it...
|
||||
updateQuery: data => data,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -118,14 +107,11 @@ class StreamContainer extends React.Component {
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this.props.data.refetch();
|
||||
if (this.props.previousTab) {
|
||||
this.props.data.refetch();
|
||||
}
|
||||
this.countPoll = setInterval(() => {
|
||||
const {asset} = this.props.root;
|
||||
this.getCounts({
|
||||
asset_id: asset.id,
|
||||
limit: asset.comments.length,
|
||||
sort: 'REVERSE_CHRONOLOGICAL'
|
||||
});
|
||||
this.getCounts(this.props.data.variables);
|
||||
}, NEW_COMMENT_COUNT_POLL_INTERVAL);
|
||||
}
|
||||
|
||||
@@ -139,13 +125,13 @@ class StreamContainer extends React.Component {
|
||||
}
|
||||
|
||||
const LOAD_COMMENT_COUNTS_QUERY = gql`
|
||||
query LoadCommentCounts($asset_id: ID, $limit: Int = 5, $sort: SORT_ORDER) {
|
||||
asset(id: $asset_id) {
|
||||
query LoadCommentCounts($assetUrl: String, $assetId: ID, $excludeIgnored: Boolean) {
|
||||
asset(id: $assetId, url: $assetUrl) {
|
||||
id
|
||||
commentCount
|
||||
comments(sort: $sort, limit: $limit) {
|
||||
commentCount(excludeIgnored: $excludeIgnored)
|
||||
comments(limit: 10) {
|
||||
id
|
||||
replyCount
|
||||
replyCount(excludeIgnored: $excludeIgnored)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -236,6 +222,7 @@ const mapStateToProps = state => ({
|
||||
assetId: state.stream.assetId,
|
||||
assetUrl: state.stream.assetUrl,
|
||||
activeTab: state.embed.activeTab,
|
||||
previousTab: state.embed.previousTab,
|
||||
});
|
||||
|
||||
const mapDispatchToProps = dispatch =>
|
||||
|
||||
@@ -3,6 +3,7 @@ import {render} from 'react-dom';
|
||||
import {ApolloProvider} from 'react-apollo';
|
||||
|
||||
import {client} from 'coral-framework/services/client';
|
||||
import {checkLogin} from 'coral-framework/actions/auth';
|
||||
|
||||
import reducers from './reducers';
|
||||
import localStore, {injectReducers} from 'coral-framework/services/store';
|
||||
@@ -12,6 +13,11 @@ injectReducers(reducers);
|
||||
|
||||
const store = (window.opener && window.opener.coralStore) ? window.opener.coralStore : localStore;
|
||||
|
||||
// Don't run this in the popup.
|
||||
if (store === localStore) {
|
||||
store.dispatch(checkLogin());
|
||||
}
|
||||
|
||||
render(
|
||||
<ApolloProvider client={client} store={store}>
|
||||
<AppRouter />
|
||||
|
||||
@@ -2,6 +2,7 @@ import * as actions from '../constants/embed';
|
||||
|
||||
const initialState = {
|
||||
activeTab: 'stream',
|
||||
previousTab: '',
|
||||
};
|
||||
|
||||
export default function stream(state = initialState, action) {
|
||||
@@ -10,6 +11,7 @@ export default function stream(state = initialState, action) {
|
||||
return {
|
||||
...state,
|
||||
activeTab: action.tab,
|
||||
previousTab: state.activeTab,
|
||||
};
|
||||
default:
|
||||
return state;
|
||||
|
||||
@@ -57,7 +57,7 @@ export const postComment = graphql(POST_COMMENT, {
|
||||
...oldData.asset,
|
||||
comments: oldData.asset.comments.map((oldComment) => {
|
||||
return oldComment.id === parent_id
|
||||
? {...oldComment, replies: [...oldComment.replies, comment]}
|
||||
? {...oldComment, replies: [...oldComment.replies, comment], replyCount: oldComment.replyCount + 1}
|
||||
: oldComment;
|
||||
})
|
||||
}
|
||||
|
||||
@@ -65,10 +65,10 @@ export function getSlotsFragments(slots) {
|
||||
const fragments = getComponentFragments(components);
|
||||
return {
|
||||
spreads(key) {
|
||||
return fragments[key] && fragments[key].spreads;
|
||||
return (fragments[key] && fragments[key].spreads) || '';
|
||||
},
|
||||
definitions(key) {
|
||||
return fragments[key] && fragments[key].definitions;
|
||||
return (fragments[key] && fragments[key].definitions) || '';
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ const initialState = Map({
|
||||
user: null,
|
||||
showSignInDialog: false,
|
||||
showCreateUsernameDialog: false,
|
||||
checkedInitialLogin: false,
|
||||
view: 'SIGNIN',
|
||||
error: '',
|
||||
passwordRequestSuccess: null,
|
||||
@@ -71,10 +72,12 @@ export default function auth (state = initialState, action) {
|
||||
.set('isLoading', true);
|
||||
case actions.CHECK_LOGIN_FAILURE:
|
||||
return state
|
||||
.set('checkedInitialLogin', true)
|
||||
.set('loggedIn', false)
|
||||
.set('user', null);
|
||||
case actions.CHECK_LOGIN_SUCCESS:
|
||||
return state
|
||||
.set('checkedInitialLogin', true)
|
||||
.set('loggedIn', true)
|
||||
.set('isAdmin', action.isAdmin)
|
||||
.set('user', purge(action.user));
|
||||
@@ -114,7 +117,11 @@ export default function auth (state = initialState, action) {
|
||||
.set('isLoading', false)
|
||||
.set('successSignUp', true);
|
||||
case actions.LOGOUT_SUCCESS:
|
||||
return initialState;
|
||||
return state
|
||||
.set('user', null)
|
||||
.set('isLoading', false)
|
||||
.set('loggedIn', false)
|
||||
.set('isAdmin', false);
|
||||
case actions.INVALID_FORM:
|
||||
return state
|
||||
.set('error', action.error);
|
||||
|
||||
@@ -4,11 +4,11 @@ import I18n from 'coral-framework/modules/i18n/i18n';
|
||||
import translations from '../translations';
|
||||
const lang = new I18n(translations);
|
||||
|
||||
const UserBox = ({className, user, logout, changeTab}) => (
|
||||
const UserBox = ({className, user, onLogout, onShowProfile}) => (
|
||||
<div className={`${styles.userBox} ${className ? className : ''}`}>
|
||||
{lang.t('signIn.loggedInAs')}
|
||||
<a onClick={() => changeTab(1)}>{user.username}</a>. {lang.t('signIn.notYou')}
|
||||
<a className={styles.logout} onClick={logout} id='logout'>{lang.t('signIn.logout')}</a>
|
||||
<a onClick={onShowProfile}>{user.username}</a>. {lang.t('signIn.notYou')}
|
||||
<a className={styles.logout} onClick={onLogout} id='logout'>{lang.t('signIn.logout')}</a>
|
||||
</div>
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user