saving my place

This commit is contained in:
riley
2017-05-03 09:32:05 -06:00
parent 9d2b47f02b
commit 9e1b470cb5
13 changed files with 148 additions and 6 deletions
@@ -0,0 +1,39 @@
import React, {PropTypes} from 'react';
import {Button, Drawer} from 'coral-ui';
import styles from './UserDetail.js';
const UserDetail = ({user}) => {
const localProfile = user.profiles.find(p => p.provider === 'local');
const facebookProfile = user.profiles.find(p => p.provider === 'facebook');
let profile;
if (localProfile) {
profile = profile.id;
} else if (facebookProfile) {
profile = <a href={`https://facebook.com/${facebookProfile.id}`}>{facebookProfile.id}</a>;
}
return (
<Drawer>
<h3>{user.username}</h3>
<p>{profile}</p> <Button>Copy</Button>
<strong>Member since</strong> {user.created_at}
<hr/>
<strong>Account summary</strong>
<br/><span className={styles.small}>Data represents the last six months of activity</span>
<div className={styles.stats}>
</div>
</Drawer>
);
};
UserDetail.propTypes = {
user: PropTypes.shape({
username: PropTypes.string.isRequired,
profiles: PropTypes.arrayOf(PropTypes.shape({
id: PropTypes.string,
provider: PropTypes.string
}))
})
};
export default UserDetail;
@@ -5,7 +5,7 @@ import key from 'keymaster';
import isEqual from 'lodash/isEqual';
import styles from './components/styles.css';
import {modQueueQuery} from '../../graphql/queries';
import {modQueueQuery, getUserDetail} from '../../graphql/queries';
import {banUser, setCommentStatus} from '../../graphql/mutations';
import {fetchSettings} from 'actions/settings';
@@ -19,6 +19,7 @@ import ModerationMenu from './components/ModerationMenu';
import ModerationHeader from './components/ModerationHeader';
import NotFoundAsset from './components/NotFoundAsset';
import ModerationKeysModal from '../../components/ModerationKeysModal';
import UserDetail from '../../components/UserDetail';
class ModerationContainer extends Component {
state = {
@@ -76,6 +77,15 @@ class ModerationContainer extends Component {
}
}
viewUserDetail = (id) => {
console.log('getting user detail', id, typeof getUserDetail);
try {
getUserDetail({id});
} catch (e) {
console.log(e);
}
}
selectSort = (sort) => {
this.setState({sort});
this.props.modQueueResort(sort);
@@ -180,6 +190,7 @@ class ModerationContainer extends Component {
assetId={providedAssetId}
sort={this.state.sort}
commentCount={activeTabCount}
viewUserDetail={this.viewUserDetail}
/>
<BanUserDialog
open={moderation.banDialog}
@@ -190,11 +201,12 @@ class ModerationContainer extends Component {
showRejectedNote={moderation.showRejectedNote}
rejectComment={props.rejectComment}
/>
<ModerationKeysModal
<ModerationKeysModal
hideShortcutsNote={props.hideShortcutsNote}
shortcutsNoteVisible={moderation.shortcutsNoteVisible}
open={moderation.modalOpen}
onClose={onClose}/>
{data.user && <UserDetail user={data.user} />}
</div>
);
}
@@ -9,7 +9,16 @@ import translations from 'coral-admin/src/translations';
import LoadMore from './components/LoadMore';
const lang = new I18n(translations);
const ModerationQueue = ({comments, selectedIndex, commentCount, singleView, loadMore, activeTab, sort, ...props}) => {
const ModerationQueue = ({
comments,
selectedIndex,
commentCount,
singleView,
loadMore,
activeTab,
sort,
viewUserDetail,
...props}) => {
return (
<div id="moderationList" className={`${styles.list} ${singleView ? styles.singleView : ''}`}>
<ul style={{paddingLeft: 0}}>
@@ -26,6 +35,7 @@ const ModerationQueue = ({comments, selectedIndex, commentCount, singleView, loa
bannedWords={props.bannedWords}
actions={actionsMap[status]}
showBanUserDialog={props.showBanUserDialog}
viewUserDetail={viewUserDetail}
acceptComment={props.acceptComment}
rejectComment={props.rejectComment}
currentAsset={props.currentAsset}
@@ -47,6 +57,7 @@ const ModerationQueue = ({comments, selectedIndex, commentCount, singleView, loa
};
ModerationQueue.propTypes = {
viewUserDetail: PropTypes.func.isRequired,
bannedWords: PropTypes.arrayOf(PropTypes.string).isRequired,
suspectWords: PropTypes.arrayOf(PropTypes.string).isRequired,
currentAsset: PropTypes.object,
@@ -18,7 +18,7 @@ import I18n from 'coral-framework/modules/i18n/i18n';
import translations from 'coral-admin/src/translations.json';
const lang = new I18n(translations);
const Comment = ({actions = [], comment, ...props}) => {
const Comment = ({actions = [], comment, viewUserDetail, ...props}) => {
const links = linkify.getMatches(comment.body);
const linkText = links ? links.map(link => link.raw) : [];
const flagActionSummaries = getActionSummary('FlagActionSummary', comment);
@@ -35,7 +35,10 @@ const Comment = ({actions = [], comment, ...props}) => {
<div className={styles.container}>
<div className={styles.itemHeader}>
<div className={styles.author}>
<span>
<span className={styles.username} onClick={() => {
console.log('clickt', comment.user.id);
viewUserDetail(comment.user.id);
}}>
{comment.user.name}
</span>
<span className={styles.created}>
@@ -89,6 +92,7 @@ const Comment = ({actions = [], comment, ...props}) => {
};
Comment.propTypes = {
viewUserDetail: PropTypes.func.isRequired,
acceptComment: PropTypes.func.isRequired,
rejectComment: PropTypes.func.isRequired,
suspectWords: PropTypes.arrayOf(PropTypes.string).isRequired,
@@ -100,8 +104,9 @@ Comment.propTypes = {
actions: PropTypes.array,
created_at: PropTypes.string.isRequired,
user: PropTypes.shape({
id: PropTypes.string,
status: PropTypes.string
}),
}).isRequired,
asset: PropTypes.shape({
title: PropTypes.string,
id: PropTypes.string
@@ -423,3 +423,14 @@ span {
position: relative;
top: 7px;
}
.username {
color: blue;
text-decoration: underline;
padding: 5px;
cursor: pointer;
&:hover {
background-color: rgba(255, 0, 0, .1);
}
}
@@ -4,6 +4,7 @@ import MOD_QUEUE_QUERY from './modQueueQuery.graphql';
import MOD_QUEUE_LOAD_MORE from './loadMore.graphql';
import MOD_USER_FLAGGED_QUERY from './modUserFlaggedQuery.graphql';
import METRICS from './metricsQuery.graphql';
import USER_DETAIL from './userDetail.graphql';
export const modQueueQuery = graphql(MOD_QUEUE_QUERY, {
options: ({params: {id = null}}) => {
@@ -93,3 +94,17 @@ export const modQueueResort = (id, fetchMore) => (sort) => {
updateQuery: (oldData, {fetchMoreResult:{data}}) => data
});
};
export const getUserDetail = ({id}) => {
console.log('close', id);
return graphql(USER_DETAIL, {
options: () => {
console.log('so close!', id);
return {
variables: {
id
}
};
}
});
};
@@ -0,0 +1,6 @@
query UserDetail ($id: ID!) {
user(id: $id) {
id
username
}
}
+12
View File
@@ -0,0 +1,12 @@
.wrapper {
transition: opacity 250ms;
position: fixed;
z-index: 10000;
background-color: rgba(0, 0, 0, .2);
height: 100%;
width: 100%;
}
.drawer {
transition: transform 500ms ease-in-out;
}
+17
View File
@@ -0,0 +1,17 @@
import React, {PropTypes} from 'react';
import styles from './Drawer.css';
const Drawer = (props) => {
return (
<div className={styles.wrapper}>
<div className={styles.drawer}>{props.children}</div>
<div className={styles.closeButton} onClick={props.close}>×</div>
</div>
);
};
Drawer.propTypes = {
active: PropTypes.bool
};
export default Drawer;
+1
View File
@@ -23,3 +23,4 @@ export {default as Select} from './components/Select';
export {default as Option} from './components/Option';
export {default as SnackBar} from './components/SnackBar';
export {default as TextArea} from './components/TextArea';
export {default as Drawer} from './components/Drawer';
+10
View File
@@ -96,6 +96,16 @@ const RootQuery = {
return await Users.getByQuery({ids: currentUser.ignoresUsers});
},
// this returns an arbitrary user
user(_, {id}, {user, loaders: {Users}}) {
console.log("user id!", id);
if (user == null || !user.hasRoles('ADMIN')) {
return null;
}
return Users.getByID.load(id);
},
// This endpoint is used for loading the user moderation queues (users whose username has been flagged),
// so hide it in the event that we aren't an admin.
users(_, {query: {action_type, limit, cursor, sort}}, {user, loaders: {Users, Actions}}) {
+3
View File
@@ -585,6 +585,9 @@ type RootQuery {
# Users returned based on a query.
users(query: UsersQuery): [User]
# a single User by id
user(id: ID!): User
# Asset metrics related to user actions are saturated into the assets
# returned. Parameters `from` and `to` are related to the action created_at field.
assetMetrics(from: Date!, to: Date!, sort: ASSET_METRICS_SORT!, limit: Int = 10): [Asset!]