diff --git a/client/src/actions/articles-actions.js b/client/src/actions/articles-actions.js new file mode 100644 index 00000000..9e144e4c --- /dev/null +++ b/client/src/actions/articles-actions.js @@ -0,0 +1,21 @@ +import API from 'lib-app/api-call'; + +export default { + + initArticles() { + return { + type: 'INIT_ARTICLES', + payload: {} + }; + }, + + retrieveArticles() { + return { + type: 'GET_ARTICLES', + payload: API.call({ + path: '/article/get-all', + data: {} + }) + }; + } +}; \ No newline at end of file diff --git a/client/src/app-components/articles-list.js b/client/src/app-components/articles-list.js index 077a79ac..716b0f8f 100644 --- a/client/src/app-components/articles-list.js +++ b/client/src/app-components/articles-list.js @@ -1,7 +1,8 @@ import React from 'react'; +import {connect} from 'react-redux'; -import API from 'lib-app/api-call'; import i18n from 'lib-app/i18n'; +import ArticlesActions from 'actions/articles-actions'; import TopicViewer from 'app-components/topic-viewer'; import ModalContainer from 'app-components/modal-container'; @@ -14,24 +15,21 @@ import Icon from 'core-components/icon'; class ArticlesList extends React.Component { static propTypes = { - editable: React.PropTypes.bool + editable: React.PropTypes.bool, + loading: React.PropTypes.bool, + topics: React.PropTypes.array }; static defaultProps = { editable: true }; - state = { - loading: true, - topics: [] - }; - componentDidMount() { this.retrieveArticles(); } render() { - return (this.state.loading) ? : this.renderContent(); + return (this.props.loading) ? : this.renderContent(); } renderContent() { @@ -46,7 +44,7 @@ class ArticlesList extends React.Component { renderTopics() { return (
- {this.state.topics.map((topic, index) => { + {this.props.topics.map((topic, index) => { return (
@@ -69,18 +67,13 @@ class ArticlesList extends React.Component { } retrieveArticles() { - API.call({ - path: '/article/get-all', - data: {} - }).then(this.onRetrieveSuccess.bind(this)); - } - - onRetrieveSuccess(result) { - this.setState({ - loading: false, - topics: result.data - }); + this.props.dispatch(ArticlesActions.retrieveArticles()); } } -export default ArticlesList; \ No newline at end of file +export default connect((store) => { + return { + topics: store.articles.topics, + loading: store.articles.loading + }; +})(ArticlesList); diff --git a/client/src/app/admin/panel/articles/admin-panel-view-article.js b/client/src/app/admin/panel/articles/admin-panel-view-article.js index fa026870..393b02cc 100644 --- a/client/src/app/admin/panel/articles/admin-panel-view-article.js +++ b/client/src/app/admin/panel/articles/admin-panel-view-article.js @@ -1,14 +1,80 @@ import React from 'react'; +import _ from 'lodash'; +import {connect} from 'react-redux'; + +import ArticlesActions from 'actions/articles-actions'; +import SessionStore from 'lib-app/session-store'; +import i18n from 'lib-app/i18n'; +import DateTransformer from 'lib-core/date-transformer'; + +import Header from 'core-components/header'; +import Loading from 'core-components/loading'; class AdminPanelViewArticle extends React.Component { + static propTypes = { + topics: React.PropTypes.array, + loading: React.PropTypes.bool + }; + + static defaultProps = { + topics: [], + loading: true + }; + + componentDidMount() { + if(SessionStore.getItem('topics')) { + this.props.dispatch(ArticlesActions.initArticles()); + } else { + this.props.dispatch(ArticlesActions.retrieveArticles()); + } + } + render() { return ( -
- /admin/panel/articles/view-article +
+ {(this.props.loading) ? : this.renderContent()}
); } + + renderContent() { + let article = this.findArticle(); + + return (article) ? this.renderArticle(article) : i18n('ARTICLE_NOT_FOUND'); + } + + renderArticle(article) { + return ( +
+
+ +
+
+
+
+ {i18n('LAST_EDITED_IN', {date: DateTransformer.transformToString(article.lastEdited)})} +
+
+ ); + } + + findArticle() { + let article = null; + + _.forEach(this.props.topics, (topic) => { + if(!article) { + article = _.find(topic.articles, {id: this.props.params.articleId * 1}); + } + }); + + return article; + } } -export default AdminPanelViewArticle; \ No newline at end of file +export default connect((store) => { + return { + topics: store.articles.topics, + loading: store.articles.loading + }; +})(AdminPanelViewArticle); diff --git a/client/src/app/admin/panel/articles/admin-panel-view-article.scss b/client/src/app/admin/panel/articles/admin-panel-view-article.scss new file mode 100644 index 00000000..66bfc6e4 --- /dev/null +++ b/client/src/app/admin/panel/articles/admin-panel-view-article.scss @@ -0,0 +1,8 @@ +.admin-panel-view-article { + + &__last-edited { + font-style: italic; + text-align: right; + margin-top: 20px; + } +} \ No newline at end of file diff --git a/client/src/data/languages/en.js b/client/src/data/languages/en.js index f473f4b3..5e9baca3 100644 --- a/client/src/data/languages/en.js +++ b/client/src/data/languages/en.js @@ -86,6 +86,7 @@ export default { 'COLOR': 'Color', 'ADD_NEW_ARTICLE': 'Add new article', 'ADD_ARTICLE': 'Add article', + 'LAST_EDITED_IN': 'Last edited in {date}', //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.', diff --git a/client/src/reducers/_reducers.js b/client/src/reducers/_reducers.js index ea625665..ff73dfc3 100644 --- a/client/src/reducers/_reducers.js +++ b/client/src/reducers/_reducers.js @@ -4,12 +4,14 @@ import { routerReducer } from 'react-router-redux'; import sessionReducer from 'reducers/session-reducer'; import configReducer from 'reducers/config-reducer'; import modalReducer from 'reducers/modal-reducer'; +import articlesReducer from 'reducers/articles-reducer'; import adminDataReducer from 'reducers/admin-data-reducer'; export default combineReducers({ session: sessionReducer, config: configReducer, modal: modalReducer, + articles: articlesReducer, adminData: adminDataReducer, routing: routerReducer }); \ No newline at end of file diff --git a/client/src/reducers/articles-reducer.js b/client/src/reducers/articles-reducer.js new file mode 100644 index 00000000..fcc5a537 --- /dev/null +++ b/client/src/reducers/articles-reducer.js @@ -0,0 +1,48 @@ +import _ from 'lodash'; + +import Reducer from 'reducers/reducer'; +import SessionStore from 'lib-app/session-store'; + +class ArticlesReducer extends Reducer { + + getInitialState() { + return { + retrieved: false, + loading: true, + topics: [] + }; + } + + getTypeHandlers() { + return { + 'GET_ARTICLES_FULFILLED': this.onArticlesRetrieved, + 'INIT_ARTICLES': this.onInitArticles + }; + } + + onArticlesRetrieved(state, payload) { + SessionStore.setItem('topics', JSON.stringify(payload.data)); + + return _.extend({}, state, { + retrieved: true, + loading: false, + topics: payload.data + }); + } + + onInitArticles(state) { + let topics = SessionStore.getItem('topics'); + + if(topics) { + topics = JSON.parse(topics); + } + + return _.extend({}, state, { + retrieved: !!topics, + loading: false, + topics: topics + }); + } +} + +export default ArticlesReducer.getInstance(); \ No newline at end of file