mirror of
https://github.com/wassname/talk.git
synced 2026-08-19 12:40:16 +08:00
show stories in dropdown
This commit is contained in:
@@ -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);
|
||||
Reference in New Issue
Block a user