mirror of
https://github.com/wassname/talk.git
synced 2026-07-04 20:09:44 +08:00
merge
This commit is contained in:
+2
-1
@@ -13,7 +13,8 @@ EXPOSE 5000
|
||||
COPY . /usr/src/app
|
||||
|
||||
# Install app dependencies and build static assets.
|
||||
RUN yarn install --frozen-lockfile && \
|
||||
RUN yarn global add node-gyp && \
|
||||
yarn install --frozen-lockfile && \
|
||||
cli plugins reconcile && \
|
||||
yarn build && \
|
||||
yarn install --production && \
|
||||
|
||||
+1
-1
@@ -243,7 +243,7 @@ file under the `scripts` key including:
|
||||
# Setup
|
||||
|
||||
Once you've installed Talk (either via Docker or source), you still need to
|
||||
setup the application. If you are unfamiliar with any terminoligy used in the
|
||||
setup the application. If you are unfamiliar with any terminology used in the
|
||||
setup process, refer to the `TERMINOLOGY.md` document.
|
||||
|
||||
## Via Web
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ import translations from 'coral-admin/src/translations.json';
|
||||
|
||||
import styles from './Community.css';
|
||||
import Table from './Table';
|
||||
import Loading from './Loading';
|
||||
import {Pager, Icon} from 'coral-ui';
|
||||
import EmptyCard from '../../components/EmptyCard';
|
||||
|
||||
@@ -29,8 +28,8 @@ const tableHeaders = [
|
||||
}
|
||||
];
|
||||
|
||||
const People = ({isFetching, commenters, searchValue, onSearchChange, ...props}) => {
|
||||
const hasResults = !isFetching && !!commenters.length;
|
||||
const People = ({commenters, searchValue, onSearchChange, ...props}) => {
|
||||
const hasResults = !!commenters.length;
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<div className={styles.leftColumn}>
|
||||
@@ -47,7 +46,6 @@ const People = ({isFetching, commenters, searchValue, onSearchChange, ...props})
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.mainContent}>
|
||||
{ isFetching && <Loading /> }
|
||||
{
|
||||
hasResults
|
||||
? <Table
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -7,6 +7,32 @@ const fm = new IntrospectionFragmentMatcher({
|
||||
introspectionQueryResultData: {
|
||||
__schema: {
|
||||
types: [
|
||||
{
|
||||
kind: 'INTERFACE',
|
||||
name: 'UserError',
|
||||
possibleTypes: [
|
||||
{name: 'GenericUserError'},
|
||||
{name: 'ValidationUserError'}
|
||||
]
|
||||
},
|
||||
{
|
||||
kind: 'INTERFACE',
|
||||
name: 'Response',
|
||||
possibleTypes: [
|
||||
{name: 'CreateCommentResponse'},
|
||||
{name: 'CreateLikeResponse'},
|
||||
{name: 'CreateFlagResponse'},
|
||||
{name: 'CreateDontAgreeResponse'},
|
||||
{name: 'DeleteActionResponse'},
|
||||
{name: 'SetUserStatusResponse'},
|
||||
{name: 'SuspendUserResponse'},
|
||||
{name: 'SetCommentStatusResponse'},
|
||||
{name: 'AddCommentTagResponse'},
|
||||
{name: 'RemoveCommentTagResponse'},
|
||||
{name: 'IgnoreUserResponse'},
|
||||
{name: 'StopIgnoringUserResponse'}
|
||||
]
|
||||
},
|
||||
{
|
||||
kind: 'INTERFACE',
|
||||
name: 'Action',
|
||||
@@ -24,6 +50,15 @@ const fm = new IntrospectionFragmentMatcher({
|
||||
{name: 'LikeActionSummary'},
|
||||
{name: 'DontAgreeActionSummary'}
|
||||
],
|
||||
},
|
||||
{
|
||||
kind: 'INTERFACE',
|
||||
name: 'AssetActionSummary',
|
||||
possibleTypes: [
|
||||
{name: 'DefaultAssetActionSummary'},
|
||||
{name: 'FlagAssetActionSummary'},
|
||||
{name: 'LikeAssetActionSummary'}
|
||||
]
|
||||
}
|
||||
],
|
||||
},
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -352,17 +352,6 @@ button.comment__action-button[disabled],
|
||||
|
||||
/* Flag Styles */
|
||||
|
||||
.coral-plugin-flags-container {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.coral-plugin-flags-popup span {
|
||||
min-width: 280px;
|
||||
bottom: 36px;
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
}
|
||||
|
||||
.coral-plugin-flags-popup-form {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
@@ -399,6 +388,7 @@ button.comment__action-button[disabled],
|
||||
margin-top: 5px;
|
||||
width: 75%;
|
||||
font-size: 16px;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
|
||||
/* Close comments */
|
||||
|
||||
@@ -39,10 +39,21 @@ export const showSignInDialog = () => dispatch => {
|
||||
'menubar=0,resizable=0,width=500,height=550,top=200,left=500'
|
||||
);
|
||||
|
||||
signInPopUp.onbeforeunload = () => {
|
||||
dispatch(checkLogin());
|
||||
fetchMe();
|
||||
// Workaround odd behavior in older WebKit versions, where
|
||||
// onunload is called twice. (Encountered in IOS 8.3)
|
||||
let loaded = false;
|
||||
signInPopUp.onload = () => {
|
||||
loaded = true;
|
||||
};
|
||||
|
||||
// Use `onunload` instead of `onbeforeunload` which is not supported in IOS Safari.
|
||||
signInPopUp.onunload = () => {
|
||||
if (loaded) {
|
||||
dispatch(checkLogin());
|
||||
fetchMe();
|
||||
}
|
||||
};
|
||||
|
||||
dispatch({type: actions.SHOW_SIGNIN_DIALOG});
|
||||
};
|
||||
export const hideSignInDialog = () => dispatch => {
|
||||
@@ -177,7 +188,13 @@ export const fetchSignUp = (formData, redirectUri) => (dispatch) => {
|
||||
dispatch(signUpSuccess(user));
|
||||
})
|
||||
.catch(error => {
|
||||
dispatch(signUpFailure(lang.t(`error.${error.message}`)));
|
||||
let errorMessage = lang.t(`error.${error.message}`);
|
||||
|
||||
// if there is no translation defined, just show the error string
|
||||
if (errorMessage === `error.${error.message}`) {
|
||||
errorMessage = error.message;
|
||||
}
|
||||
dispatch(signUpFailure(errorMessage));
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -19,6 +19,12 @@ class FlagButton extends Component {
|
||||
localDelete: false
|
||||
}
|
||||
|
||||
componentDidUpdate () {
|
||||
if (this.popup) { // this will be defined when the reporting popup is opened
|
||||
this.popup.firstChild.style.top = `${this.flagButton.offsetTop - this.popup.firstChild.clientHeight - 15}px`;
|
||||
}
|
||||
}
|
||||
|
||||
// When the "report" button is clicked expand the menu
|
||||
onReportClick = () => {
|
||||
const {currentUser, deleteAction, flaggedByCurrentUser, flag} = this.props;
|
||||
@@ -135,7 +141,10 @@ class FlagButton extends Component {
|
||||
const popupMenu = getPopupMenu[this.state.step](this.state.itemType);
|
||||
|
||||
return <div className={`${name}-container`}>
|
||||
<button onClick={!this.props.banned ? this.onReportClick : null} className={`${name}-button`}>
|
||||
<button
|
||||
ref={ref => this.flagButton = ref}
|
||||
onClick={!this.props.banned ? this.onReportClick : null}
|
||||
className={`${name}-button`}>
|
||||
{
|
||||
flagged
|
||||
? <span className={`${name}-button-text`}>{lang.t('reported')}</span>
|
||||
@@ -147,7 +156,7 @@ class FlagButton extends Component {
|
||||
</button>
|
||||
{
|
||||
this.state.showMenu &&
|
||||
<div className={`${name}-popup`}>
|
||||
<div className={`${name}-popup`} ref={ref => this.popup = ref}>
|
||||
<PopupMenu>
|
||||
<div className={`${name}-popup-header`}>{popupMenu.header}</div>
|
||||
{
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
.popupMenu {
|
||||
display: inline-block;
|
||||
width: inherit;
|
||||
white-space: normal;
|
||||
display: block;
|
||||
position: absolute;
|
||||
max-width: 98%;
|
||||
min-width: 50%;
|
||||
border: solid 1px #999;
|
||||
box-shadow: 3px 3px 5px 0 rgba(0, 0, 0, 0.3);
|
||||
box-sizing: border-box;
|
||||
background: white;
|
||||
border-radius: 3px;
|
||||
padding: 20px 10px;
|
||||
z-index: 3;
|
||||
z-index: 300;
|
||||
right: 1%;
|
||||
}
|
||||
|
||||
.popupMenu:before{
|
||||
|
||||
@@ -2,5 +2,5 @@ import React from 'react';
|
||||
import styles from './PopupMenu.css';
|
||||
|
||||
export default ({children}) => (
|
||||
<span className={styles.popupMenu}>{children}</span>
|
||||
<div className={styles.popupMenu}>{children}</div>
|
||||
);
|
||||
|
||||
@@ -106,7 +106,7 @@ class ErrAuthentication extends APIError {
|
||||
|
||||
// ErrContainsProfanity is returned in the event that the middleware detects
|
||||
// profanity/wordlisted words in the payload.
|
||||
const ErrContainsProfanity = new APIError('Suspected profanity. If you think this in error, please let us know!', {
|
||||
const ErrContainsProfanity = new APIError('This username contains elements which are not permitted in our community. If you think this is in error, please contact us or try again.', {
|
||||
translation_key: 'PROFANITY_ERROR',
|
||||
status: 400
|
||||
});
|
||||
|
||||
+6
-2
@@ -96,11 +96,15 @@
|
||||
"prop-types": "^15.5.8",
|
||||
"react-apollo": "^1.1.0",
|
||||
"react-recaptcha": "^2.2.6",
|
||||
"recompose": "^0.23.1",
|
||||
"redis": "^2.7.1",
|
||||
"uuid": "^3.0.1",
|
||||
"simplemde": "^1.11.2",
|
||||
"subscriptions-transport-ws": "^0.5.5-alpha.0",
|
||||
"resolve": "^1.3.2",
|
||||
"semver": "^5.3.0"
|
||||
"semver": "^5.3.0",
|
||||
"simplemde": "^1.11.2",
|
||||
"uuid": "^3.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"apollo-client": "^1.0.4",
|
||||
@@ -179,8 +183,8 @@
|
||||
"redux-thunk": "^2.1.0",
|
||||
"regenerator": "^0.8.46",
|
||||
"selenium-standalone": "^5.11.2",
|
||||
"subscriptions-transport-ws": "^0.5.5-alpha.0",
|
||||
"style-loader": "^0.16.0",
|
||||
"subscriptions-transport-ws": "^0.5.5-alpha.0",
|
||||
"supertest": "^2.0.1",
|
||||
"timeago.js": "^2.0.3",
|
||||
"webpack": "^2.3.1"
|
||||
|
||||
Reference in New Issue
Block a user