show stories in dropdown

This commit is contained in:
Riley Davis
2017-06-09 14:10:21 -06:00
parent 06da4d7d26
commit de665b3a0d
12 changed files with 233 additions and 4 deletions
@@ -53,3 +53,5 @@ export const toggleSelectCommentInUserDetail = (id, active) => {
};
export const toggleStorySearch = (active) => ({type: active ? actions.SHOW_STORY_SEARCH : actions.HIDE_STORY_SEARCH});
export const storySearchChange = (e) => ({type: actions.CHANGE_ASSET_SEARCH_STRING, value: e.target.value});
@@ -14,3 +14,4 @@ export const UNSELECT_USER_DETAIL_COMMENT = 'UNSELECT_USER_DETAIL_COMMENT';
export const CLEAR_USER_DETAIL_SELECTIONS = 'CLEAR_USER_DETAIL_SELECTIONS';
export const SHOW_STORY_SEARCH = 'SHOW_STORY_SEARCH';
export const HIDE_STORY_SEARCH = 'HIDE_STORY_SEARCH';
export const CHANGE_ASSET_SEARCH_STRING = 'CHANGE_ASSET_SEARCH_STRING';
@@ -86,6 +86,8 @@ export default function moderation (state = initialState, action) {
return state.set('storySearchVisible', true);
case actions.HIDE_STORY_SEARCH:
return state.set('storySearchVisible', false);
case actions.CHANGE_ASSET_SEARCH_STRING:
return state.set('storySearchString', action.value);
case actions.SET_SORT_ORDER:
return state.set('sortOrder', action.order);
default :
@@ -10,6 +10,7 @@ import ModerationHeader from './ModerationHeader';
import NotFoundAsset from './NotFoundAsset';
import ModerationKeysModal from '../../../components/ModerationKeysModal';
import UserDetail from '../containers/UserDetail';
import StorySearch from '../containers/StorySearch';
export default class Moderation extends Component {
state = {
@@ -209,6 +210,7 @@ export default class Moderation extends Component {
acceptComment={props.acceptComment}
rejectComment={props.rejectComment} />
)}
<StorySearch />
</div>
);
}
@@ -0,0 +1,22 @@
import React, {PropTypes} from 'react';
import styles from './StorySearch.css';
const Story = ({author, title, createdAt, open}) => {
return (
<li className={styles.story}>
<p className={styles.title}>{title}</p>
<p className={styles.meta}>
<span className={styles.author}>By {author}</span><span className={styles.createdAt}>{createdAt}</span><span className={styles.status}>{open ? 'Open' : 'Closed'}</span>
</p>
</li>
);
};
Story.propTypes = {
author: PropTypes.string.isRequired,
title: PropTypes.string.isRequired,
createdAt: PropTypes.string.isRequired,
open: PropTypes.bool.isRequired
};
export default Story;
@@ -0,0 +1,69 @@
.container {
position: fixed;
background-color: white;
top: 100px;
left: 0;
right: 0;
margin-left: auto;
margin-right: auto;
width: 50%;
box-shadow: 0px 3px 5px 0px rgba(0,0,0,0.15);
}
.positionShim {
left: -50%;
}
.headInput {
background-color: #efefef;
padding: 10px 30px;
}
.searchInput {
width: calc(100% - 100px);
padding: 8px;
height: 100%;
font-size: 16px;
margin-right: 10px;
position: relative;
top: 2px;
}
.cta {
padding: 15px;
font-weight: bold;
font-size: 14px;
margin: 0;
}
.storyList {
padding: 10px;
margin: 0;
list-style: none;
border-top: 1px solid #ddd;
}
.story {
padding: 10px;
border-bottom: 1px solid #ddd;
}
.title, .meta {
margin: 0;
}
.author, .createdAt, .status {
display: inline-block;
font-size: .8em;
color: #aaa;
}
.author {
display: inline-block;
width: 200px;
}
.createdAt {
display: inline-block;
width: 200px;
}
@@ -0,0 +1,47 @@
import React, {PropTypes} from 'react';
import styles from './StorySearch.css';
import {Button, Spinner} from 'coral-ui';
import Story from './Story';
const StorySearch = (props) => {
const {
root: {assets = []},
data: {loading}
} = props;
return (
<div className={styles.container}>
<div className={styles.positionShim}>
<div className={styles.headInput}>
<input className={styles.searchInput} onChange={props.storySearchChange} />
<Button cStyle='facebook'>Search</Button>
</div>
<div className={styles.results}>
<p className={styles.cta}>Moderate comments on All Stories</p>
<ul className={styles.storyList}>
{
loading
? <Spinner />
: assets.map((story, i) => {
const storyOpen = story.closedAt === null || new Date(story.closedAt) > new Date();
return <Story
key={i}
title={story.title}
createdAt={new Date(story.created_at).toISOString()}
open={storyOpen}
author={story.author} />;
})
}
</ul>
</div>
</div>
</div>
);
};
StorySearch.propTypes = {
storySearchChange: PropTypes.func.isRequired
};
export default StorySearch;
@@ -209,7 +209,7 @@ const withModQueueQuery = withQuery(gql`
}) {
...CoralAdmin_Moderation_CommentConnection
}
assets: assets {
assets: assets(query: {}) {
id
title
url
@@ -0,0 +1,60 @@
import React from 'react';
import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
import {compose, gql} from 'react-apollo';
import StorySearch from '../components/StorySearch';
import withQuery from 'coral-framework/hocs/withQuery';
import {storySearchChange} from 'coral-admin/src/actions/moderation';
class StorySearchContainer extends React.Component {
searchChange = (e) => {
this.props.storySearchChange(e.target.value);
this.props.data.refetch();
}
componentDidUpdate (prevProps) {
if (prevProps.moderation.storySearchString !== this.props.moderation.storySearchString) {
this.props.data.refetch();
}
}
render () {
return <StorySearch searchChange={this.searchChange} {...this.props} />;
}
}
export const withAssetSearchQuery = withQuery(gql`
query SearchStories($value: String = "") {
assets(query: {value: $value}) {
id
title
url
created_at
closedAt
author
}
}
`, {
options: ({moderation: {storySearchString = ''}}) => {
return {
variables: {
value: storySearchString
}
};
}
});
const mapStateToProps = (state) => ({
moderation: state.moderation.toJS()
});
const mapDispatchToProps = (dispatch) => ({
...bindActionCreators({
storySearchChange
}, dispatch)
});
export default compose(
connect(mapStateToProps, mapDispatchToProps),
withAssetSearchQuery
)(StorySearchContainer);