Ivan - Add search article list [skip ci]
This commit is contained in:
parent
c774df46f4
commit
b4b94a883e
|
@ -18,15 +18,19 @@ class ArticlesList extends React.Component {
|
||||||
editable: React.PropTypes.bool,
|
editable: React.PropTypes.bool,
|
||||||
articlePath: React.PropTypes.string,
|
articlePath: React.PropTypes.string,
|
||||||
loading: React.PropTypes.bool,
|
loading: React.PropTypes.bool,
|
||||||
topics: React.PropTypes.array
|
topics: React.PropTypes.array,
|
||||||
|
retrieveOnMount: React.PropTypes.bool
|
||||||
};
|
};
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
editable: true
|
editable: true,
|
||||||
|
retrieveOnMount: true
|
||||||
};
|
};
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.retrieveArticles();
|
if(this.props.retrieveOnMount) {
|
||||||
|
this.retrieveArticles();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import _ from 'react';
|
||||||
|
|
||||||
import i18n from 'lib-app/i18n';
|
import i18n from 'lib-app/i18n';
|
||||||
import API from 'lib-app/api-call';
|
import API from 'lib-app/api-call';
|
||||||
|
@ -79,7 +80,7 @@ class AdminPanelBanUsers extends React.Component {
|
||||||
|
|
||||||
onSearch(query) {
|
onSearch(query) {
|
||||||
this.setState({
|
this.setState({
|
||||||
filteredEmails: SearchBox.searchQueryInList(this.state.emails, query)
|
filteredEmails: SearchBox.searchQueryInList(this.state.emails, query, _.startsWith, _.includes)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,19 +1,109 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import {connect} from 'react-redux';
|
||||||
|
import _ from 'lodash';
|
||||||
|
import {Link} from 'react-router';
|
||||||
|
|
||||||
import i18n from 'lib-app/i18n';
|
import i18n from 'lib-app/i18n';
|
||||||
import ArticlesList from 'app-components/articles-list';
|
import ArticlesList from 'app-components/articles-list';
|
||||||
|
import ArticlesActions from 'actions/articles-actions';
|
||||||
|
|
||||||
import Header from 'core-components/header';
|
import Header from 'core-components/header';
|
||||||
|
import SearchBox from 'core-components/search-box';
|
||||||
|
|
||||||
class DashboardListArticlesPage extends React.Component {
|
class DashboardListArticlesPage extends React.Component {
|
||||||
|
|
||||||
|
state = {
|
||||||
|
results: [],
|
||||||
|
showSearchResults: false
|
||||||
|
};
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.props.dispatch(ArticlesActions.retrieveArticles());
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div classnames="dashboard-list-articles-page">
|
||||||
<Header title={i18n('LIST_ARTICLES')} description={i18n('LIST_ARTICLES_DESCRIPTION')}/>
|
<Header title={i18n('LIST_ARTICLES')} description={i18n('LIST_ARTICLES_DESCRIPTION')}/>
|
||||||
<ArticlesList editable={false} articlePath="/dashboard/article/"/>
|
<SearchBox className="dashboard-list-articles-page__search-box" onSearch={this.onSearch.bind(this)} searchOnType />
|
||||||
|
{(!this.state.showSearchResults) ? this.renderArticleList() : this.renderSearchResults()}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderArticleList() {
|
||||||
|
return (
|
||||||
|
<ArticlesList editable={false} articlePath="/dashboard/article/" retrieveOnMount={false}/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderSearchResults() {
|
||||||
|
return (
|
||||||
|
<div className="dashboard-list-articles-page__search-results">
|
||||||
|
{(_.isEmpty(this.state.results)) ? i18n('NO_RESULTS') : this.state.results.map(this.renderSearchResultsItem.bind(this))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderSearchResultsItem(item) {
|
||||||
|
let content = this.stripHTML(item.content);
|
||||||
|
content = content.substring(0, 100);
|
||||||
|
content += '...';
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="dashboard-list-articles-page__search-result">
|
||||||
|
<div className="dashboard-list-articles-page__search-result-title">
|
||||||
|
<Link to={'/dashboard/article/' + item.id}>{item.title}</Link>
|
||||||
|
</div>
|
||||||
|
<div className="dashboard-list-articles-page__search-result-description">{content}</div>
|
||||||
|
<div className="dashboard-list-articles-page__search-result-topic">{item.topic}</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
onSearch(query) {
|
||||||
|
this.setState({
|
||||||
|
results: SearchBox.searchQueryInList(this.getArticles(), query, this.isQueryInTitle.bind(this), this.isQueryInContent.bind(this)),
|
||||||
|
showSearchResults: query.length
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getArticles() {
|
||||||
|
let articles = [];
|
||||||
|
|
||||||
|
_.forEach(this.props.topics, (topic) => {
|
||||||
|
_.forEach(topic.articles, (article) => {
|
||||||
|
articles.push({
|
||||||
|
id: article.id,
|
||||||
|
title: article.title,
|
||||||
|
content: article.content,
|
||||||
|
topic: topic.name
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return articles;
|
||||||
|
}
|
||||||
|
|
||||||
|
isQueryInTitle(article, query) {
|
||||||
|
return _.includes(article.title.toLowerCase(), query.toLowerCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
isQueryInContent(article, query) {
|
||||||
|
return _.includes(article.content.toLowerCase(), query.toLowerCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
stripHTML(html){
|
||||||
|
let tmp = document.createElement('DIV');
|
||||||
|
tmp.innerHTML = html;
|
||||||
|
return tmp.textContent || tmp.innerText || "";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default DashboardListArticlesPage;
|
|
||||||
|
export default connect((store) => {
|
||||||
|
return {
|
||||||
|
topics: store.articles.topics,
|
||||||
|
loading: store.articles.loading
|
||||||
|
};
|
||||||
|
})(DashboardListArticlesPage);
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
@import "../../../../scss/vars";
|
||||||
|
|
||||||
|
.dashboard-list-articles-page {
|
||||||
|
|
||||||
|
&__search-results {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
&__search-box {
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__search-result {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
text-align: left;
|
||||||
|
|
||||||
|
&-title {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
&-description {
|
||||||
|
font-size: $font-size--xs;
|
||||||
|
margin: 5px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-topic {
|
||||||
|
color: $grey;
|
||||||
|
font-size: $font-size--sm;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,5 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import _ from 'lodash';
|
|
||||||
|
|
||||||
import Input from 'core-components/input';
|
import Input from 'core-components/input';
|
||||||
import Icon from 'core-components/icon';
|
import Icon from 'core-components/icon';
|
||||||
|
@ -8,12 +7,12 @@ import keyCode from 'keycode';
|
||||||
|
|
||||||
class SearchBox extends React.Component {
|
class SearchBox extends React.Component {
|
||||||
|
|
||||||
static searchQueryInList(list, query) {
|
static searchQueryInList(list, query, startsWith, includes) {
|
||||||
let match = [];
|
let match = [];
|
||||||
let rest = [];
|
let rest = [];
|
||||||
|
|
||||||
list.forEach(function (item) {
|
list.forEach(function (item) {
|
||||||
if(_.startsWith(item, query)) {
|
if(startsWith(item, query)) {
|
||||||
match.push(item);
|
match.push(item);
|
||||||
} else {
|
} else {
|
||||||
rest.push(item);
|
rest.push(item);
|
||||||
|
@ -21,7 +20,7 @@ class SearchBox extends React.Component {
|
||||||
});
|
});
|
||||||
|
|
||||||
rest.forEach(function (item) {
|
rest.forEach(function (item) {
|
||||||
if(_.includes(item, query)) {
|
if(includes(item, query)) {
|
||||||
match.push(item);
|
match.push(item);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -92,6 +92,7 @@ export default {
|
||||||
'ADD_ARTICLE': 'Add article',
|
'ADD_ARTICLE': 'Add article',
|
||||||
'LAST_EDITED_IN': 'Last edited in {date}',
|
'LAST_EDITED_IN': 'Last edited in {date}',
|
||||||
'EDIT': 'Edit',
|
'EDIT': 'Edit',
|
||||||
|
'NO_RESULTS': 'No results',
|
||||||
|
|
||||||
//VIEW DESCRIPTIONS
|
//VIEW DESCRIPTIONS
|
||||||
'CREATE_TICKET_DESCRIPTION': 'This is a form for creating tickets. Fill the form and send us your issues/doubts/suggestions. Our support system will answer it as soon as possible.',
|
'CREATE_TICKET_DESCRIPTION': 'This is a form for creating tickets. Fill the form and send us your issues/doubts/suggestions. Our support system will answer it as soon as possible.',
|
||||||
|
|
Loading…
Reference in New Issue