diff --git a/client/coral-admin/src/components/UserDetail.js b/client/coral-admin/src/components/UserDetail.js index 31ad999dc..e45e3f095 100644 --- a/client/coral-admin/src/components/UserDetail.js +++ b/client/coral-admin/src/components/UserDetail.js @@ -3,7 +3,7 @@ import cn from 'classnames'; import PropTypes from 'prop-types'; import capitalize from 'lodash/capitalize'; import styles from './UserDetail.css'; -import AccountHistory from './AccountHistory'; +import UserHistory from './UserHistory'; import { Slot } from 'coral-framework/components'; import UserDetailCommentList from '../components/UserDetailCommentList'; import { @@ -28,26 +28,6 @@ import UserInfoTooltip from './UserInfoTooltip'; import t from 'coral-framework/services/i18n'; class UserDetail extends React.Component { - rejectThenReload = async info => { - await this.props.rejectComment(info); - this.props.data.refetch(); - }; - - acceptThenReload = async info => { - await this.props.acceptComment(info); - this.props.data.refetch(); - }; - - bulkAcceptThenReload = async () => { - await this.props.bulkAccept(); - this.props.data.refetch(); - }; - - bulkRejectThenReload = async () => { - await this.props.bulkReject(); - this.props.data.refetch(); - }; - changeTab = tab => { this.props.changeTab(tab); }; @@ -110,8 +90,14 @@ class UserDetail extends React.Component { unbanUser, unsuspendUser, modal, + acceptComment, + rejectComment, + bulkAccept, + bulkReject, } = this.props; + console.log(rejectedComments, totalComments); + // if totalComments is 0, you're dividing by zero let rejectedPercent = rejectedComments / totalComments * 100; @@ -286,7 +272,7 @@ class UserDetail extends React.Component { 'talk-admin-user-detail-history-tab' )} > - {t('user_detail.account_history')} + {t('user_detail.user_history')} @@ -304,12 +290,12 @@ class UserDetail extends React.Component { loadMore={loadMore} toggleSelect={toggleSelect} viewUserDetail={viewUserDetail} - acceptComment={this.acceptThenReload} - rejectComment={this.rejectThenReload} + acceptComment={acceptComment} + rejectComment={rejectComment} selectedCommentIds={selectedCommentIds} toggleSelectAll={toggleSelectAll} - bulkAcceptThenReload={this.bulkAcceptThenReload} - bulkRejectThenReload={this.bulkRejectThenReload} + bulkAcceptThenReload={bulkAccept} + bulkRejectThenReload={bulkReject} /> - + diff --git a/client/coral-admin/src/components/AccountHistory.css b/client/coral-admin/src/components/UserHistory.css similarity index 100% rename from client/coral-admin/src/components/AccountHistory.css rename to client/coral-admin/src/components/UserHistory.css diff --git a/client/coral-admin/src/components/AccountHistory.js b/client/coral-admin/src/components/UserHistory.js similarity index 73% rename from client/coral-admin/src/components/AccountHistory.js rename to client/coral-admin/src/components/UserHistory.js index 0d85b62af..3a3472c86 100644 --- a/client/coral-admin/src/components/AccountHistory.js +++ b/client/coral-admin/src/components/UserHistory.js @@ -1,7 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { murmur3 } from 'murmurhash-js'; -import styles from './AccountHistory.css'; +import styles from './UserHistory.css'; import cn from 'classnames'; import flatten from 'lodash/flatten'; import orderBy from 'lodash/orderBy'; @@ -43,15 +43,15 @@ const readableDuration = (startDate, endDate) => { const buildActionResponse = (typename, created_at, until, status) => { switch (typename) { case 'UsernameStatusHistory': - return t('account_history.username_status', status); + return t('user_history.username_status', status); case 'BannedStatusHistory': return status - ? t('account_history.user_banned') - : t('account_history.ban_removed'); + ? t('user_history.user_banned') + : t('user_history.ban_removed'); case 'SuspensionStatusHistory': return until - ? t('account_history.suspended', readableDuration(created_at, until)) - : t('account_history.suspension_removed'); + ? t('user_history.suspended', readableDuration(created_at, until)) + : t('user_history.suspension_removed'); default: return '-'; } @@ -62,43 +62,41 @@ const getModerationValue = assignedBy => assignedBy.username ) : ( - {t('account_history.system')} + {t('user_history.system')} ); -class AccountHistory extends React.Component { +class UserHistory extends React.Component { render() { const { user } = this.props; const userHistory = buildUserHistory(user.state); return (
-
+
+
{t('user_history.date')}
- {t('account_history.date')} + {t('user_history.action')}
- {t('account_history.action')} -
-
- {t('account_history.taken_by')} + {t('user_history.taken_by')}
{userHistory.map( ({ __typename, created_at, assigned_by, until, status }) => (
{moment(new Date(created_at)).format('MMM DD, YYYY')} @@ -107,7 +105,7 @@ class AccountHistory extends React.Component { className={cn( styles.item, styles.action, - 'talk-admin-account-history-row-status' + 'talk-admin-user-history-row-status' )} > {buildActionResponse(__typename, created_at, until, status)} @@ -116,7 +114,7 @@ class AccountHistory extends React.Component { className={cn( styles.item, styles.username, - 'talk-admin-account-history-row-assigned-by' + 'talk-admin-user-history-row-assigned-by' )} > {getModerationValue(assigned_by)} @@ -130,8 +128,8 @@ class AccountHistory extends React.Component { } } -AccountHistory.propTypes = { +UserHistory.propTypes = { user: PropTypes.object.isRequired, }; -export default AccountHistory; +export default UserHistory; diff --git a/client/coral-admin/src/containers/UserDetail.js b/client/coral-admin/src/containers/UserDetail.js index fb1508a2f..360819dd6 100644 --- a/client/coral-admin/src/containers/UserDetail.js +++ b/client/coral-admin/src/containers/UserDetail.js @@ -148,6 +148,7 @@ UserDetailContainer.propTypes = { selectedCommentIds: PropTypes.array, unbanUser: PropTypes.func.isRequired, unsuspendUser: PropTypes.func.isRequired, + userId: PropTypes.string, }; const LOAD_MORE_QUERY = gql` @@ -245,7 +246,6 @@ export const withUserDetailQuery = withQuery( options: ({ userId, statuses }) => { return { variables: { author_id: userId, statuses }, - fetchPolicy: 'network-only', }; }, skip: ownProps => !ownProps.userId, diff --git a/client/coral-embed-stream/src/components/Embed.js b/client/coral-embed-stream/src/components/Embed.js index 0c4fed129..a2476527e 100644 --- a/client/coral-embed-stream/src/components/Embed.js +++ b/client/coral-embed-stream/src/components/Embed.js @@ -24,14 +24,20 @@ export default class Embed extends React.Component { > {t('embed_comments_tab')} , - - {t('framework.my_profile')} - , ]; + + if (this.props.currentUser) { + tabs.push( + + {t('framework.my_profile')} + + ); + } + if (can(this.props.currentUser, 'UPDATE_ASSET_CONFIG')) { tabs.push( ); } + return tabs; } diff --git a/client/coral-embed-stream/src/components/ExtendableTabPanel.js b/client/coral-embed-stream/src/components/ExtendableTabPanel.js index 1eb420ef0..1e78b21dd 100644 --- a/client/coral-embed-stream/src/components/ExtendableTabPanel.js +++ b/client/coral-embed-stream/src/components/ExtendableTabPanel.js @@ -16,9 +16,11 @@ class ExtendableTabPanel extends React.Component { } = this.props; return (
- - {tabs} - + {tabs && ( + + {tabs} + + )} {loading ? (
diff --git a/client/coral-embed-stream/src/tabs/profile/components/NotLoggedIn.css b/client/coral-embed-stream/src/tabs/profile/components/NotLoggedIn.css deleted file mode 100644 index c15c44c98..000000000 --- a/client/coral-embed-stream/src/tabs/profile/components/NotLoggedIn.css +++ /dev/null @@ -1,14 +0,0 @@ -.message { - padding: 10px 0 20px; - letter-spacing: 0.1px; - font-size: 13px; - line-height: 33px; -} - -.message a { - color: black; - font-weight: bold; - cursor: pointer; - margin: 0px; - padding-bottom: 2px; -} diff --git a/client/coral-embed-stream/src/tabs/profile/components/NotLoggedIn.js b/client/coral-embed-stream/src/tabs/profile/components/NotLoggedIn.js deleted file mode 100644 index 4987d57be..000000000 --- a/client/coral-embed-stream/src/tabs/profile/components/NotLoggedIn.js +++ /dev/null @@ -1,15 +0,0 @@ -import React from 'react'; -import styles from './NotLoggedIn.css'; -import cn from 'classnames'; - -import t from 'coral-framework/services/i18n'; - -export default ({ showSignInDialog }) => ( -
-
- {t('settings.sign_in')}{' '} - {t('settings.to_access')} -
-
{t('from_settings_page')}
-
-); diff --git a/client/coral-embed-stream/src/tabs/profile/containers/Profile.js b/client/coral-embed-stream/src/tabs/profile/containers/Profile.js index 30d634d94..84584ae5d 100644 --- a/client/coral-embed-stream/src/tabs/profile/containers/Profile.js +++ b/client/coral-embed-stream/src/tabs/profile/containers/Profile.js @@ -2,27 +2,17 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; import { compose, gql } from 'react-apollo'; -import { bindActionCreators } from 'redux'; import { withQuery } from 'coral-framework/hocs'; -import NotLoggedIn from '../components/NotLoggedIn'; import { Spinner } from 'coral-ui'; import Profile from '../components/Profile'; import TabPanel from './TabPanel'; import { getDefinitionName } from 'coral-framework/utils'; -import { showSignInDialog } from 'coral-embed-stream/src/actions/login'; import { getSlotFragmentSpreads } from 'coral-framework/utils'; class ProfileContainer extends Component { - componentWillReceiveProps(nextProps) { - if (!this.props.currentUser && nextProps.currentUser) { - // Refetch after login. - this.props.data.refetch(); - } - } - render() { - const { currentUser, showSignInDialog, root } = this.props; + const { currentUser, root } = this.props; const { me } = this.props.root; const loading = this.props.data.loading; @@ -30,10 +20,6 @@ class ProfileContainer extends Component { return
{this.props.data.error.message}
; } - if (!currentUser) { - return ; - } - if (loading || !me) { return ; } @@ -57,7 +43,6 @@ ProfileContainer.propTypes = { data: PropTypes.object, root: PropTypes.object, currentUser: PropTypes.object, - showSignInDialog: PropTypes.func, }; const slots = ['profileSections']; @@ -85,10 +70,6 @@ const mapStateToProps = state => ({ currentUser: state.auth.user, }); -const mapDispatchToProps = dispatch => - bindActionCreators({ showSignInDialog }, dispatch); - -export default compose( - connect(mapStateToProps, mapDispatchToProps), - withProfileQuery -)(ProfileContainer); +export default compose(connect(mapStateToProps), withProfileQuery)( + ProfileContainer +); diff --git a/client/coral-framework/graphql/mutations.js b/client/coral-framework/graphql/mutations.js index 1b3b4c6fc..bd31be630 100644 --- a/client/coral-framework/graphql/mutations.js +++ b/client/coral-framework/graphql/mutations.js @@ -1,5 +1,6 @@ import { gql } from 'react-apollo'; import withMutation from '../hocs/withMutation'; +import update from 'immutability-helper'; function convertItemType(item_type) { switch (item_type) { @@ -167,9 +168,39 @@ export const withSetCommentStatus = withMutation( errors: null, }, }, + updateQueries: { + CoralAdmin_UserDetail: prev => { + const increment = { + rejectedComments: { + $apply: count => + count < prev.totalComments ? count + 1 : count, + }, + }; + + const decrement = { + rejectedComments: { + $apply: count => (count > 0 ? count - 1 : 0), + }, + }; + + // If rejected then increment rejectedComments by one + if (status === 'REJECTED') { + const updated = update(prev, increment); + return updated; + } + + // If approved then decrement rejectedComments by one + if (status === 'ACCEPTED') { + const updated = update(prev, decrement); + return updated; + } + + return prev; + }, + }, update: proxy => { const fragment = gql` - fragment Talk_SetCommentStatus on Comment { + fragment Talk_SetCommentStatus_Comment on Comment { status status_history { type @@ -182,9 +213,11 @@ export const withSetCommentStatus = withMutation( const data = proxy.readFragment({ fragment, id: fragmentId }); data.status = status; + data.status_history = data.status_history ? data.status_history : []; + data.status_history.push({ __typename: 'CommentStatusHistory', type: status, diff --git a/locales/ar.yml b/locales/ar.yml index 3c94c06f0..98f6cc54e 100644 --- a/locales/ar.yml +++ b/locales/ar.yml @@ -438,8 +438,8 @@ ar: reports: "Reports" all: "All" rejected: "Rejected" - account_history: "Account History" - account_history: + user_history: "User History" + user_history: user_banned: "User banned" ban_removed: "Ban removed" username_status: "Username {0}" diff --git a/locales/da.yml b/locales/da.yml index 9618b2f58..0afe4c5ce 100644 --- a/locales/da.yml +++ b/locales/da.yml @@ -431,8 +431,8 @@ da: reports: "Rapporter" all: "Alle" rejected: "Afvist" - account_history: "Konto historik" - account_history: + user_history: "Konto historik" + user_history: user_banned: "Bruger bannet" ban_removed: "Ban fjernet" username_status: "Brugernavn {0}" diff --git a/locales/de.yml b/locales/de.yml index 972c2735b..6f7a1a66e 100644 --- a/locales/de.yml +++ b/locales/de.yml @@ -430,8 +430,8 @@ de: reports: "Meldungen" all: "Alle" rejected: "Abgelehnte" - account_history: "Konto-Verlauf" - account_history: + user_history: "Konto-Verlauf" + user_history: user_banned: "User banned" ban_removed: "Ban removed" username_status: "Username {0}" diff --git a/locales/en.yml b/locales/en.yml index 6b2330f27..73f74d184 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -446,8 +446,8 @@ en: reports: "Reports" all: "All" rejected: "Rejected" - account_history: "Account History" - account_history: + user_history: "User History" + user_history: user_banned: "User banned" ban_removed: "Ban removed" username_status: "Username {0}" diff --git a/locales/es.yml b/locales/es.yml index 4e7a2c51b..dd85b588e 100644 --- a/locales/es.yml +++ b/locales/es.yml @@ -439,8 +439,8 @@ es: reports: "Reports" all: "All" rejected: "Rejected" - account_history: "Account History" - account_history: + user_history: "User History" + user_history: user_banned: "User banned" ban_removed: "Ban removed" username_status: "Username {0}" diff --git a/locales/nl_NL.yml b/locales/nl_NL.yml index aa80f58be..9d4057065 100644 --- a/locales/nl_NL.yml +++ b/locales/nl_NL.yml @@ -431,8 +431,8 @@ nl_NL: reports: "Rapportages" all: "Alle" rejected: "Afgewezen" - account_history: "Accountgeschiedenis" - account_history: + user_history: "Accountgeschiedenis" + user_history: user_banned: "User banned" ban_removed: "Ban removed" username_status: "Username {0}" diff --git a/locales/pt_BR.yml b/locales/pt_BR.yml index 86267d51d..d9ef119ed 100644 --- a/locales/pt_BR.yml +++ b/locales/pt_BR.yml @@ -430,8 +430,8 @@ pt_BR: reports: "Reports" all: "All" rejected: "Rejected" - account_history: "Account History" - account_history: + user_history: "User History" + user_history: user_banned: "User banned" ban_removed: "Ban removed" username_status: "Username {0}" diff --git a/locales/zh_CN.yml b/locales/zh_CN.yml index 59e028eb7..b3307a886 100644 --- a/locales/zh_CN.yml +++ b/locales/zh_CN.yml @@ -432,8 +432,8 @@ zh_CN: reports: "Reports" all: "All" rejected: "Rejected" - account_history: "Account History" - account_history: + user_history: "User History" + user_history: user_banned: "User banned" ban_removed: "Ban removed" username_status: "Username {0}" diff --git a/locales/zh_TW.yml b/locales/zh_TW.yml index 1b131f636..c186a667f 100644 --- a/locales/zh_TW.yml +++ b/locales/zh_TW.yml @@ -432,8 +432,8 @@ zh_TW: reports: "Reports" all: "All" rejected: "Rejected" - account_history: "Account History" - account_history: + user_history: "User History" + user_history: user_banned: "User banned" ban_removed: "Ban removed" username_status: "Username {0}" diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 000000000..d6105c594 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,27 @@ +{ + "name": "talk", + "version": "4.3.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "exenv": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/exenv/-/exenv-1.2.2.tgz", + "integrity": "sha1-KueOhdmJQVhnCwPUe+wfA72Ru50=" + }, + "react-side-effect": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/react-side-effect/-/react-side-effect-1.1.5.tgz", + "integrity": "sha512-Z2ZJE4p/jIfvUpiUMRydEVpQRf2f8GMHczT6qLcARmX7QRb28JDBTpnM2g/i5y/p7ZDEXYGHWg0RbhikE+hJRw==", + "requires": { + "exenv": "1.2.2", + "shallowequal": "1.0.2" + } + }, + "shallowequal": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.0.2.tgz", + "integrity": "sha512-zlVXeVUKvo+HEv1e2KQF/csyeMKx2oHvatQ9l6XjCUj3agvC8XGf6R9HvIPDSmp8FNPvx7b5kaEJTRi7CqxtEw==" + } + } +} diff --git a/test/e2e/page_objects/admin.js b/test/e2e/page_objects/admin.js index 218afe425..8e319e499 100644 --- a/test/e2e/page_objects/admin.js +++ b/test/e2e/page_objects/admin.js @@ -128,8 +128,8 @@ module.exports = { rejectedTab: '.talk-admin-user-detail-rejected-tab', historyTab: '.talk-admin-user-detail-history-tab', historyPane: '.talk-admin-user-detail-history-tab-pane', - accountHistory: '.talk-admin-account-history', - accountHistoryRowStatus: '.talk-admin-account-history-row-status', + UserHistory: '.talk-admin-user-history', + UserHistoryRowStatus: '.talk-admin-user-history-row-status', actionsMenu: '.talk-admin-user-detail-actions-button', actionItemSuspendUser: '.action-menu-item#suspendUser', actionMenuButton: diff --git a/test/e2e/specs/03_embedStream.js b/test/e2e/specs/03_embedStream.js index f45c467e8..4b6831271 100644 --- a/test/e2e/specs/03_embedStream.js +++ b/test/e2e/specs/03_embedStream.js @@ -96,12 +96,6 @@ module.exports = { comments.logout(); }, - 'not logged in user clicks my profile tab': client => { - const embedStream = client.page.embedStream(); - const profile = embedStream.goToProfileSection(); - - profile.assert.visible('@notLoggedIn'); - }, 'admin logs in': client => { const { testData: { admin } } = client.globals; const embedStream = client.page.embedStream(); diff --git a/test/e2e/specs/06_suspendUser.js b/test/e2e/specs/06_suspendUser.js index 0b89c5c01..81fde3781 100644 --- a/test/e2e/specs/06_suspendUser.js +++ b/test/e2e/specs/06_suspendUser.js @@ -125,7 +125,7 @@ module.exports = { .waitForElementVisible('@historyTab') .click('@historyTab') .waitForElementVisible('@historyPane') - .waitForElementVisible('@accountHistory') + .waitForElementVisible('@UserHistory') .click('@closeButton'); }, 'admin logs out': client => {