diff --git a/client/coral-admin/src/actions/moderation.js b/client/coral-admin/src/actions/moderation.js index 557954b70..5107669cf 100644 --- a/client/coral-admin/src/actions/moderation.js +++ b/client/coral-admin/src/actions/moderation.js @@ -20,3 +20,4 @@ export const hideShortcutsNote = () => { }; export const viewUserDetail = userId => ({type: actions.VIEW_USER_DETAIL, userId}); +export const hideUserDetail = () => ({type: actions.HIDE_USER_DETAIL}); diff --git a/client/coral-admin/src/components/UserDetail.css b/client/coral-admin/src/components/UserDetail.css deleted file mode 100644 index e69de29bb..000000000 diff --git a/client/coral-admin/src/containers/ModerationQueue/ModerationContainer.js b/client/coral-admin/src/containers/ModerationQueue/ModerationContainer.js index 29612b0a3..480666637 100644 --- a/client/coral-admin/src/containers/ModerationQueue/ModerationContainer.js +++ b/client/coral-admin/src/containers/ModerationQueue/ModerationContainer.js @@ -16,7 +16,8 @@ import { showBanUserDialog, hideBanUserDialog, hideShortcutsNote, - viewUserDetail + viewUserDetail, + hideUserDetail } from 'actions/moderation'; import {Spinner} from 'coral-ui'; @@ -118,7 +119,7 @@ class ModerationContainer extends Component { } render () { - const {data, moderation, settings, assets, onClose, viewUserDetail, ...props} = this.props; + const {data, moderation, settings, assets, onClose, viewUserDetail, hideUserDetail, ...props} = this.props; const providedAssetId = this.props.params.id; const activeTab = this.props.route.path === ':id' ? 'premod' : this.props.route.path; @@ -189,6 +190,7 @@ class ModerationContainer extends Component { sort={this.state.sort} commentCount={activeTabCount} viewUserDetail={viewUserDetail} + hideUserDetail={hideUserDetail} /> - {moderation.userDetailId && } + {moderation.userDetailId && } ); } @@ -223,6 +225,7 @@ const mapDispatchToProps = dispatch => ({ updateAssets: assets => dispatch(updateAssets(assets)), fetchSettings: () => dispatch(fetchSettings()), viewUserDetail: id => dispatch(viewUserDetail(id)), + hideUserDetail: () => dispatch(hideUserDetail()), showBanUserDialog: (user, commentId, showRejectedNote) => dispatch(showBanUserDialog(user, commentId, showRejectedNote)), hideBanUserDialog: () => dispatch(hideBanUserDialog(false)), hideShortcutsNote: () => dispatch(hideShortcutsNote()), diff --git a/client/coral-admin/src/containers/ModerationQueue/UserDetail.css b/client/coral-admin/src/containers/ModerationQueue/UserDetail.css new file mode 100644 index 000000000..9f41a9d8d --- /dev/null +++ b/client/coral-admin/src/containers/ModerationQueue/UserDetail.css @@ -0,0 +1,12 @@ +.copyButton { + float: right; + top: -10px; +} + +.memberSince { + clear: both; +} + +.small { + color: #aaa; +} diff --git a/client/coral-admin/src/containers/ModerationQueue/UserDetail.js b/client/coral-admin/src/containers/ModerationQueue/UserDetail.js index 45d98c56c..06587065e 100644 --- a/client/coral-admin/src/containers/ModerationQueue/UserDetail.js +++ b/client/coral-admin/src/containers/ModerationQueue/UserDetail.js @@ -1,16 +1,27 @@ import React, {PropTypes} from 'react'; import {Button, Drawer} from 'coral-ui'; -import styles from './UserDetail.js'; +import styles from './UserDetail.css'; import {compose} from 'react-apollo'; import {getUserDetail} from 'coral-admin/src/graphql/queries'; class UserDetail extends React.Component { static propTypes = { - id: PropTypes.string.isRequired + id: PropTypes.string.isRequired, + hideUserDetail: PropTypes.func.isRequired + } + + copyPermalink () { + this.profile.select(); + try { + document.execCommand('copy'); + } catch (e) { + + /* nothing */ + } } render () { - const {data} = this.props; + const {data, hideUserDetail} = this.props; if (!('user' in data)) { return null; @@ -27,13 +38,16 @@ class UserDetail extends React.Component { } return ( - +

{user.username}

-

{profile}

- Member since {user.created_at} + +

this.profile = ref} contentEditable="true">{profile}

+

Member since {new Date(user.created_at).toLocaleString()}


- Account summary -
Data represents the last six months of activity +

+ Account summary +
Data represents the last six months of activity +

diff --git a/client/coral-admin/src/graphql/queries/userDetail.graphql b/client/coral-admin/src/graphql/queries/userDetail.graphql index f489e16d9..6d42682ea 100644 --- a/client/coral-admin/src/graphql/queries/userDetail.graphql +++ b/client/coral-admin/src/graphql/queries/userDetail.graphql @@ -2,5 +2,10 @@ query UserDetail ($id: ID!) { user(id: $id) { id username + created_at + profiles { + id + provider + } } } diff --git a/client/coral-ui/components/Drawer.css b/client/coral-ui/components/Drawer.css index 57a44075e..b967b20ab 100644 --- a/client/coral-ui/components/Drawer.css +++ b/client/coral-ui/components/Drawer.css @@ -1,12 +1,31 @@ -.wrapper { - transition: opacity 250ms; +.drawer { + max-width: 700px; + padding: 20px; position: fixed; - z-index: 10000; - background-color: rgba(0, 0, 0, .2); - height: 100%; - width: 100%; + top: 0; + right: 0; + bottom: 0; + background-color: white; + transition: transform 500ms ease-in-out; + box-shadow: -3px 0px 4px 0px rgba(0,0,0,0.15); } -.drawer { - transition: transform 500ms ease-in-out; +.closeButton { + position: absolute; + width: 40px; + height: 40px; + left: -40px; + background-color: white; + border-radius: 4px 0 0 4px; + box-sizing: border-box; + font-size: 32px; + top: 60px; + box-shadow: -1px 3px 4px 0px rgba(0,0,0,0.15); + text-align: center; + padding-top: 10px; + cursor: pointer; + + &:hover { + color: #ccc; + } } diff --git a/client/coral-ui/components/Drawer.js b/client/coral-ui/components/Drawer.js index d56677d76..d896203a8 100644 --- a/client/coral-ui/components/Drawer.js +++ b/client/coral-ui/components/Drawer.js @@ -1,17 +1,19 @@ import React, {PropTypes} from 'react'; import styles from './Drawer.css'; +import onClickOutside from 'react-onclickoutside'; -const Drawer = (props) => { +const Drawer = ({children, handleClickOutside}) => { return ( -
-
{props.children}
-
×
+
+
×
+ {children}
); }; Drawer.propTypes = { - active: PropTypes.bool + active: PropTypes.bool, + handleClickOutside: PropTypes.func.isRequired }; -export default Drawer; +export default onClickOutside(Drawer); diff --git a/graph/resolvers/user.js b/graph/resolvers/user.js index 4f6528454..4dbdc43c4 100644 --- a/graph/resolvers/user.js +++ b/graph/resolvers/user.js @@ -10,6 +10,13 @@ const User = { } }, + created_at({roles, created_at}, _, {user}) { + if (user && user.hasRoles('ADMIN')) { + return created_at; + } + + return null; + }, comments({id}, _, {loaders: {Comments}, user}) { // If the user is not an admin, only return comment list for the owner of @@ -20,10 +27,10 @@ const User = { return null; }, - profiles({id, profiles}, _, {user}) { + profiles({profiles}, _, {user}) { // if the user is not an admin, do not return the profiles - if (user && (user.hasRoles('ADMIN') || user.id === id)) { + if (user && user.hasRoles('ADMIN')) { return profiles; } diff --git a/graph/typeDefs.graphql b/graph/typeDefs.graphql index a505f558e..7a5f0b76f 100644 --- a/graph/typeDefs.graphql +++ b/graph/typeDefs.graphql @@ -38,6 +38,9 @@ type User { # Username of a user. username: String! + # creation date of user + created_at: String! + # Action summaries against the user. action_summaries: [ActionSummary]! diff --git a/package.json b/package.json index bfca21643..d61431b3a 100644 --- a/package.json +++ b/package.json @@ -98,12 +98,10 @@ "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", "simplemde": "^1.11.2", + "subscriptions-transport-ws": "^0.5.5-alpha.0", "uuid": "^3.0.1" }, "devDependencies": { @@ -174,7 +172,7 @@ "react-linkify": "^0.1.3", "react-mdl": "^1.7.2", "react-mdl-selectfield": "^0.2.0", - "react-onclickoutside": "^5.7.1", + "react-onclickoutside": "^5.11.1", "react-redux": "^4.4.5", "react-router": "^3.0.0", "react-tagsinput": "^3.14.0", diff --git a/yarn.lock b/yarn.lock index 99703bdf3..7a5163706 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6780,7 +6780,7 @@ react-mdl@^1.7.1, react-mdl@^1.7.2: lodash.isequal "^4.4.0" prop-types "^15.5.0" -react-onclickoutside@^5.7.1: +react-onclickoutside@^5.11.1: version "5.11.1" resolved "https://registry.yarnpkg.com/react-onclickoutside/-/react-onclickoutside-5.11.1.tgz#00314e52567cf55faba94cabbacd119619070623" dependencies: