From 0d921472e2bf52dda1f65828218493ad3967d6bd Mon Sep 17 00:00:00 2001 From: ivan Date: Fri, 16 Dec 2016 01:02:34 -0300 Subject: [PATCH 01/16] Ivan - Fix bug os-171 - fixed width for add article modal[skip ci] --- client/src/app-components/article-add-modal.js | 4 ++-- client/src/app-components/article-add-modal.scss | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/client/src/app-components/article-add-modal.js b/client/src/app-components/article-add-modal.js index 613abbc7..e0e34d86 100644 --- a/client/src/app-components/article-add-modal.js +++ b/client/src/app-components/article-add-modal.js @@ -19,13 +19,13 @@ class ArticleAddModal extends React.Component { render() { return ( -
+
{i18n('ADD_ARTICLE')} - diff --git a/client/src/app-components/article-add-modal.scss b/client/src/app-components/article-add-modal.scss index 50ba5b88..3634480e 100644 --- a/client/src/app-components/article-add-modal.scss +++ b/client/src/app-components/article-add-modal.scss @@ -1,4 +1,5 @@ -.article-add-article { +.article-add-modal { + width: 800px; &__cancel-button { float: right; From e0d1fd0e4004d6f64f4823680ffc40afd4e94d06 Mon Sep 17 00:00:00 2001 From: ivan Date: Fri, 16 Dec 2016 01:22:26 -0300 Subject: [PATCH 02/16] Ivan - Add delete article button[skip ci] --- .../articles/admin-panel-view-article.js | 25 ++++++++++++++++--- .../articles/admin-panel-view-article.scss | 6 ++++- client/src/data/languages/en.js | 1 + 3 files changed, 28 insertions(+), 4 deletions(-) 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 13c0af00..13ec35c2 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,6 +1,7 @@ import React from 'react'; import _ from 'lodash'; import {connect} from 'react-redux'; +import {browserHistory} from 'react-router'; import RichTextEditor from 'react-rte-browserify'; import ArticlesActions from 'actions/articles-actions'; @@ -9,6 +10,7 @@ import i18n from 'lib-app/i18n'; import API from 'lib-app/api-call'; import DateTransformer from 'lib-core/date-transformer'; +import AreYouSure from 'app-components/are-you-sure'; import Header from 'core-components/header'; import Loading from 'core-components/loading'; import Button from 'core-components/button'; @@ -61,10 +63,14 @@ class AdminPanelViewArticle extends React.Component { renderArticlePreview(article) { return (
-
- +
+ +
-
@@ -116,6 +122,10 @@ class AdminPanelViewArticle extends React.Component { }); } + onDeleteClick(article) { + AreYouSure.openModal(i18n('DELETE_ARTICLE_DESCRIPTION'), this.onArticleDeleted.bind(this, article)); + } + onFormSubmit(form) { API.call({ path: '/article/edit', @@ -139,6 +149,15 @@ class AdminPanelViewArticle extends React.Component { editable: false }); } + + onArticleDeleted(article) { + API.call({ + path: '/article/delete', + data: { + articleId: article.id + } + }).then(() => browserHistory.push('/admin/panel/articles/list-articles')); + } } export default connect((store) => { 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 index 300041c9..431fe9a4 100644 --- a/client/src/app/admin/panel/articles/admin-panel-view-article.scss +++ b/client/src/app/admin/panel/articles/admin-panel-view-article.scss @@ -1,10 +1,14 @@ .admin-panel-view-article { - &__edit-button { + &__edit-buttons { text-align: left; margin-bottom: 20px; } + &__edit-button { + margin-right: 20px; + } + &__last-edited { font-style: italic; text-align: right; diff --git a/client/src/data/languages/en.js b/client/src/data/languages/en.js index 0805e711..07d8f8e5 100644 --- a/client/src/data/languages/en.js +++ b/client/src/data/languages/en.js @@ -136,6 +136,7 @@ export default { 'ADD_ARTICLE_DESCRIPTION': 'Here you can add an article that will be available for every user. It will be added inside the category {category}.', 'LIST_ARTICLES_DESCRIPTION': 'This is a list of articles that includes information about our services.', 'ADD_TOPIC_DESCRIPTION': 'Here you can add a topic that works as a category for articles.', + 'DELETE_ARTICLE_DESCRIPTION': 'You\'re going to delete this article for ever.', 'STAFF_MEMBERS_DESCRIPTION': 'Here you can see who are your staff members.', 'ADD_STAFF_DESCRIPTION': 'Here you can add staff members to your teams.', 'EDIT_STAFF_DESCRIPTION': 'Here you can edit information about a staff member.', From 04f1d12e7d89fc60eefa0ce88d8bd158373ccec8 Mon Sep 17 00:00:00 2001 From: ivan Date: Fri, 16 Dec 2016 01:58:27 -0300 Subject: [PATCH 03/16] Ivan - Fix drag and drop os-172 multiple topics [skip ci] --- client/src/app-components/topic-viewer.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/src/app-components/topic-viewer.js b/client/src/app-components/topic-viewer.js index fc923ea5..60efe0ad 100644 --- a/client/src/app-components/topic-viewer.js +++ b/client/src/app-components/topic-viewer.js @@ -139,12 +139,12 @@ class TopicViewer extends React.Component { if(this.props.editable) { _.extend(props, { - onDragOver: this.onItemDragOver.bind(this, article, index), - onDrop: this.onItemDrop.bind(this, article, index), + onDragOver: (this.state.currentDraggedId) ? this.onItemDragOver.bind(this, article, index) : null, + onDrop: (this.state.currentDraggedId) ? this.onItemDrop.bind(this, article, index) : null, onDragStart: () => this.setState({currentDraggedId: article.id}), onDragEnd: () => { if(this.state.currentDraggedId) { - this.setState({articles: this.props.articles}); + this.setState({articles: this.props.articles, currentDraggedId: 0}); } } }); From 7ef2eec14b14b642a6ccc32204428a87aaeb592b Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 20 Dec 2016 23:26:46 -0300 Subject: [PATCH 04/16] Ivan - Add icon to drag and drop [skip ci] --- client/src/app-components/topic-viewer.js | 46 ++++++++++++--------- client/src/app-components/topic-viewer.scss | 22 +++++++++- client/src/core-components/icon.js | 2 +- 3 files changed, 48 insertions(+), 22 deletions(-) diff --git a/client/src/app-components/topic-viewer.js b/client/src/app-components/topic-viewer.js index 60efe0ad..2009da8c 100644 --- a/client/src/app-components/topic-viewer.js +++ b/client/src/app-components/topic-viewer.js @@ -1,4 +1,5 @@ import React from 'react'; +import ReactDOM from 'react-dom'; import _ from 'lodash'; import classNames from 'classnames'; import {Link} from 'react-router'; @@ -78,11 +79,33 @@ class TopicViewer extends React.Component { } renderArticleItem(article, index) { + let props = { + className: 'topic-viewer__list-item', + key: index, + draggable: true + }; + + if(this.props.editable) { + _.extend(props, { + onDragOver: (this.state.currentDraggedId) ? this.onItemDragOver.bind(this, article, index) : null, + onDrop: (this.state.currentDraggedId) ? this.onItemDrop.bind(this, article, index) : null, + onDragStart: () => { + this.setState({currentDraggedId: article.id}) + }, + onDragEnd: () => { + if(this.state.currentDraggedId) { + this.setState({articles: this.props.articles, currentDraggedId: 0}); + } + } + }); + } + return ( -
  • +
  • {article.title} +
  • ); } @@ -126,31 +149,16 @@ class TopicViewer extends React.Component { ); } - getArticleLinkProps(article, index) { + getArticleLinkProps(article) { let classes = { 'topic-viewer__list-item-button': true, 'topic-viewer__list-item-hidden': article.hidden }; - - let props = { + + return { className: classNames(classes), to: this.props.articlePath + article.id }; - - if(this.props.editable) { - _.extend(props, { - onDragOver: (this.state.currentDraggedId) ? this.onItemDragOver.bind(this, article, index) : null, - onDrop: (this.state.currentDraggedId) ? this.onItemDrop.bind(this, article, index) : null, - onDragStart: () => this.setState({currentDraggedId: article.id}), - onDragEnd: () => { - if(this.state.currentDraggedId) { - this.setState({articles: this.props.articles, currentDraggedId: 0}); - } - } - }); - } - - return props; } onDeleteClick() { diff --git a/client/src/app-components/topic-viewer.scss b/client/src/app-components/topic-viewer.scss index 0f489be2..f674fd88 100644 --- a/client/src/app-components/topic-viewer.scss +++ b/client/src/app-components/topic-viewer.scss @@ -38,12 +38,22 @@ width: 50%; color: $secondary-blue; margin-bottom: 10px; + user-select: none; &-hidden { - width: 80%; - display: inline-block; opacity: 0; } + + &:hover { + .topic-viewer__grab-icon { + display: inline-block; + left: 0; + } + } + + &-button { + user-select: none; + } } &-item:before { @@ -52,10 +62,18 @@ } &-item-button { + display: inline-block; color: $secondary-blue; } } + &__grab-icon { + color: $grey; + cursor: move; + margin-left: 10px; + display: none; + } + &__add-item { color: $dark-grey; } diff --git a/client/src/core-components/icon.js b/client/src/core-components/icon.js index d26123d1..becdb99b 100644 --- a/client/src/core-components/icon.js +++ b/client/src/core-components/icon.js @@ -19,7 +19,7 @@ class Icon extends React.Component { renderFontIcon() { return ( -
    ); } @@ -216,6 +218,12 @@ class TicketViewer extends React.Component { return customResponsesNode; } + renderCommentError() { + return ( + {i18n('TICKET_COMMENT_ERROR')} + ); + } + getCommentFormProps() { return { onSubmit: this.onSubmit.bind(this), @@ -316,7 +324,8 @@ class TicketViewer extends React.Component { onCommentSuccess() { this.setState({ - loading: false + loading: false, + commentError: false }); this.onTicketModification(); @@ -324,7 +333,8 @@ class TicketViewer extends React.Component { onCommentFail() { this.setState({ - loading: false + loading: false, + commentError: true }); } diff --git a/client/src/app/main/dashboard/dashboard-list-articles/dashboard-list-articles-page.js b/client/src/app/main/dashboard/dashboard-list-articles/dashboard-list-articles-page.js index 36837ab9..da942c22 100644 --- a/client/src/app/main/dashboard/dashboard-list-articles/dashboard-list-articles-page.js +++ b/client/src/app/main/dashboard/dashboard-list-articles/dashboard-list-articles-page.js @@ -23,7 +23,7 @@ class DashboardListArticlesPage extends React.Component { render() { return ( -
    +
    {(!this.state.showSearchResults) ? this.renderArticleList() : this.renderSearchResults()} diff --git a/client/src/data/languages/en.js b/client/src/data/languages/en.js index 79b287bd..4b30f8c7 100644 --- a/client/src/data/languages/en.js +++ b/client/src/data/languages/en.js @@ -157,6 +157,7 @@ export default { 'PASSWORD_NOT_MATCH': 'Password does not match', 'INVALID_RECOVER': 'Invalid recover data', 'TICKET_SENT_ERROR': 'An error occurred while trying to create the ticket.', + 'TICKET_COMMENT_ERROR': 'An error occurred while trying to add the comment.', 'NO_PERMISSION': 'You\'ve no permission to access to this page.', 'INVALID_USER': 'User id is invalid', From 63516662589035d3a16ce89e8e8862d9d171fa14 Mon Sep 17 00:00:00 2001 From: ivan Date: Fri, 23 Dec 2016 00:18:41 -0300 Subject: [PATCH 11/16] Ivan - Add error messages for admin tickets view [skip ci] --- .../panel/tickets/admin-panel-all-tickets.js | 16 ++++--- .../panel/tickets/admin-panel-my-tickets.js | 9 ++-- .../panel/tickets/admin-panel-new-tickets.js | 9 ++-- client/src/data/languages/en.js | 1 + client/src/reducers/admin-data-reducer.js | 47 ++++++++++++++++--- 5 files changed, 63 insertions(+), 19 deletions(-) diff --git a/client/src/app/admin/panel/tickets/admin-panel-all-tickets.js b/client/src/app/admin/panel/tickets/admin-panel-all-tickets.js index b721f35f..1f7f6cc2 100644 --- a/client/src/app/admin/panel/tickets/admin-panel-all-tickets.js +++ b/client/src/app/admin/panel/tickets/admin-panel-all-tickets.js @@ -4,9 +4,11 @@ import {connect} from 'react-redux'; import i18n from 'lib-app/i18n'; import AdminDataAction from 'actions/admin-data-actions'; -import Header from 'core-components/header'; import TicketList from 'app-components/ticket-list'; + +import Header from 'core-components/header'; import SearchBox from 'core-components/search-box'; +import Message from 'core-components/message'; class AdminPanelAllTickets extends React.Component { @@ -31,7 +33,7 @@ class AdminPanelAllTickets extends React.Component {
    - + {(this.props.error) ? {i18n('ERROR_RETRIEVING_TICKETS')} : }
    ); } @@ -52,7 +54,8 @@ class AdminPanelAllTickets extends React.Component { onSearch(query) { this.setState({query, page: 1}); - if (query) { + + if(query) { this.props.dispatch(AdminDataAction.searchTickets(query)); } else { this.props.dispatch(AdminDataAction.retrieveAllTickets()); @@ -60,9 +63,7 @@ class AdminPanelAllTickets extends React.Component { } onPageChange(event) { - this.setState({ - page: event.target.value - }); + this.setState({page: event.target.value}); if(this.state.query) { this.props.dispatch(AdminDataAction.searchTickets(this.state.query, event.target.value)); @@ -77,6 +78,7 @@ export default connect((store) => { departments: store.session.userDepartments, tickets: store.adminData.allTickets, pages: store.adminData.allTicketsPages, - loading: !store.adminData.allTicketsLoaded + loading: !store.adminData.allTicketsLoaded, + error: store.adminData.allTicketsError }; })(AdminPanelAllTickets); diff --git a/client/src/app/admin/panel/tickets/admin-panel-my-tickets.js b/client/src/app/admin/panel/tickets/admin-panel-my-tickets.js index 512454b1..e90847ec 100644 --- a/client/src/app/admin/panel/tickets/admin-panel-my-tickets.js +++ b/client/src/app/admin/panel/tickets/admin-panel-my-tickets.js @@ -4,9 +4,11 @@ import {connect} from 'react-redux'; import i18n from 'lib-app/i18n'; import AdminDataAction from 'actions/admin-data-actions'; -import Header from 'core-components/header'; import TicketList from 'app-components/ticket-list'; +import Header from 'core-components/header'; +import Message from 'core-components/message'; + class AdminPanelMyTickets extends React.Component { static defaultProps = { @@ -22,7 +24,7 @@ class AdminPanelMyTickets extends React.Component { return (
    - + {(this.props.error) ? {i18n('ERROR_RETRIEVING_TICKETS')} : }
    ); } @@ -42,6 +44,7 @@ export default connect((store) => { return { departments: store.session.userDepartments, tickets: store.adminData.myTickets, - loading: !store.adminData.myTicketsLoaded + loading: !store.adminData.myTicketsLoaded, + error: store.adminData.myTicketsError }; })(AdminPanelMyTickets); diff --git a/client/src/app/admin/panel/tickets/admin-panel-new-tickets.js b/client/src/app/admin/panel/tickets/admin-panel-new-tickets.js index 819e9b56..bb3240cb 100644 --- a/client/src/app/admin/panel/tickets/admin-panel-new-tickets.js +++ b/client/src/app/admin/panel/tickets/admin-panel-new-tickets.js @@ -4,9 +4,11 @@ import {connect} from 'react-redux'; import i18n from 'lib-app/i18n'; import AdminDataAction from 'actions/admin-data-actions'; -import Header from 'core-components/header'; import TicketList from 'app-components/ticket-list'; +import Header from 'core-components/header'; +import Message from 'core-components/message'; + class AdminPanelNewTickets extends React.Component { static defaultProps = { @@ -22,7 +24,7 @@ class AdminPanelNewTickets extends React.Component { return (
    - + {(this.props.error) ? {i18n('ERROR_RETRIEVING_TICKETS')} : }
    ); } @@ -42,6 +44,7 @@ export default connect((store) => { return { departments: store.session.userDepartments, tickets: store.adminData.newTickets, - loading: !store.adminData.newTicketsLoaded + loading: !store.adminData.newTicketsLoaded, + error: store.adminData.newTicketsError }; })(AdminPanelNewTickets); diff --git a/client/src/data/languages/en.js b/client/src/data/languages/en.js index 4b30f8c7..dfd41f50 100644 --- a/client/src/data/languages/en.js +++ b/client/src/data/languages/en.js @@ -160,6 +160,7 @@ export default { 'TICKET_COMMENT_ERROR': 'An error occurred while trying to add the comment.', 'NO_PERMISSION': 'You\'ve no permission to access to this page.', 'INVALID_USER': 'User id is invalid', + 'ERROR_RETRIEVING_TICKETS': 'An error occurred while trying to retrieve tickets.', //MESSAGES 'SIGNUP_SUCCESS': 'You have registered successfully in our support system.', diff --git a/client/src/reducers/admin-data-reducer.js b/client/src/reducers/admin-data-reducer.js index d3d753dc..30fc80f2 100644 --- a/client/src/reducers/admin-data-reducer.js +++ b/client/src/reducers/admin-data-reducer.js @@ -11,10 +11,15 @@ class AdminDataReducer extends Reducer { customResponsesLoaded: false, myTickets: [], myTicketsLoaded: false, + myTicketsError: false, + newTickets: [], newTicketsLoaded: false, + newTicketsError: false, + allTickets: [], - allTicketsLoaded: false + allTicketsLoaded: false, + allTicketsError: false }; } @@ -22,11 +27,17 @@ class AdminDataReducer extends Reducer { return { 'CUSTOM_RESPONSES_FULFILLED': this.onCustomResponses, 'SESSION_CHECKED': this.onSessionChecked, + 'MY_TICKETS_FULFILLED': this.onMyTicketsRetrieved, + 'MY_TICKETS_REJECTED': this.onMyTicketsRejected, 'MY_TICKETS_PENDING': this.onMyTicketsPending, + 'NEW_TICKETS_FULFILLED': this.onNewTicketsRetrieved, + 'NEW_TICKETS_REJECTED': this.onNewTicketsRejected, 'NEW_TICKETS_PENDING': this.onNewTicketsPending, + 'ALL_TICKETS_FULFILLED': this.onAllTicketsRetrieved, + 'ALL_TICKETS_REJECTED': this.onAllTicketsRejected, 'ALL_TICKETS_PENDING': this.onAllTicketsPending }; } @@ -53,26 +64,42 @@ class AdminDataReducer extends Reducer { return _.extend({}, state, { myTickets: payload.data, myTicketsLoaded: true + }); + } + + onMyTicketsRejected(state) { + return _.extend({}, state, { + myTicketsError: true, + myTicketsLoaded: true }) } onMyTicketsPending(state) { return _.extend({}, state, { + myTicketsError: false, myTicketsLoaded: false - }) + }); } onNewTicketsRetrieved(state, payload) { return _.extend({}, state, { newTickets: payload.data, newTicketsLoaded: true - }) + }); + } + + onNewTicketsRejected(state) { + return _.extend({}, state, { + newTicketsError: true, + newTicketsLoaded: false + }); } onNewTicketsPending(state) { return _.extend({}, state, { + newTicketsError: false, newTicketsLoaded: false - }) + }); } onAllTicketsRetrieved(state, payload) { @@ -80,13 +107,21 @@ class AdminDataReducer extends Reducer { allTickets: payload.data.tickets, allTicketsPages: payload.data.pages, allTicketsLoaded: true - }) + }); + } + + onAllTicketsRejected(state) { + return _.extend({}, state, { + allTicketsError: false, + allTicketsLoaded: false + }); } onAllTicketsPending(state) { return _.extend({}, state, { + allTicketsError: false, allTicketsLoaded: false - }) + }); } } From 5b68997437241e86d1d13b141617260740a44a51 Mon Sep 17 00:00:00 2001 From: ivan Date: Fri, 23 Dec 2016 04:28:32 -0300 Subject: [PATCH 12/16] Ivan - Add error messages for admin users view [skip ci] --- .../panel/users/admin-panel-ban-users.js | 51 +++++++++++++++---- .../panel/users/admin-panel-ban-users.scss | 8 +-- .../panel/users/admin-panel-list-users.js | 14 ++++- .../panel/users/admin-panel-view-user.js | 8 +-- client/src/core-components/message.js | 2 +- client/src/data/fixtures/user-fixtures.js | 2 +- client/src/data/languages/en.js | 4 ++ 7 files changed, 68 insertions(+), 21 deletions(-) diff --git a/client/src/app/admin/panel/users/admin-panel-ban-users.js b/client/src/app/admin/panel/users/admin-panel-ban-users.js index aac27f29..b4b215bc 100644 --- a/client/src/app/admin/panel/users/admin-panel-ban-users.js +++ b/client/src/app/admin/panel/users/admin-panel-ban-users.js @@ -11,24 +11,35 @@ import Button from 'core-components/button'; import SubmitButton from 'core-components/submit-button'; import Form from 'core-components/form'; import FormField from 'core-components/form-field'; +import Message from 'core-components/message'; class AdminPanelBanUsers extends React.Component { state = { loadingList: true, loadingForm: false, + listError: false, + addBanStatus: 'none', emails: [], filteredEmails: [] }; componentDidMount() { - this.retrieveEmails() + this.retrieveEmails(); } render() { return (
    + {(this.state.listError) ? {i18n('ERROR_RETRIEVING_BAN_LIST')} : this.renderContent()} +
    + ); + } + + renderContent() { + return ( +
    @@ -41,11 +52,23 @@ class AdminPanelBanUsers extends React.Component { {i18n('BAN_EMAIL')} + {this.renderMessage()} ); } + renderMessage() { + switch (this.state.addBanStatus) { + case 'success': + return {i18n('EMAIL_BANNED_SUCCESSFULLY')}; + case 'fail': + return {i18n('ERROR_BANNING_EMAIL')}; + default: + return null; + } + } + getTableProps() { return { loading: this.state.loadingList, @@ -94,7 +117,12 @@ class AdminPanelBanUsers extends React.Component { data: { email: form.email } - }).then(this.retrieveEmails.bind(this)); + }).then(() => { + this.setState({ + addBanStatus: 'success' + }); + this.retrieveEmails(); + }).catch(() => this.setState({addBanStatus: 'fail', loadingForm: false})); } onUnBanClick(email) { @@ -114,14 +142,17 @@ class AdminPanelBanUsers extends React.Component { API.call({ path: '/user/list-ban', data: {} - }).then((result) => { - this.setState({ - loadingList: false, - loadingForm: false, - emails: result.data, - filteredEmails: result.data - }); - }); + }).then(result => this.setState({ + listError: false, + loadingList: false, + loadingForm: false, + emails: result.data, + filteredEmails: result.data + })).catch(() => this.setState({ + listError: true, + loadingList: false, + loadingForm: false + })); } } diff --git a/client/src/app/admin/panel/users/admin-panel-ban-users.scss b/client/src/app/admin/panel/users/admin-panel-ban-users.scss index 799e21fe..379b437c 100644 --- a/client/src/app/admin/panel/users/admin-panel-ban-users.scss +++ b/client/src/app/admin/panel/users/admin-panel-ban-users.scss @@ -3,10 +3,6 @@ .admin-panel-ban-users { padding: 0 20px; - &__email-list { - - } - &__search { margin-bottom: 20px; } @@ -33,4 +29,8 @@ &__input { display: inline-block; } + + &__form-message { + margin-top: 20px; + } } \ No newline at end of file diff --git a/client/src/app/admin/panel/users/admin-panel-list-users.js b/client/src/app/admin/panel/users/admin-panel-list-users.js index 2b23c374..0b2896ec 100644 --- a/client/src/app/admin/panel/users/admin-panel-list-users.js +++ b/client/src/app/admin/panel/users/admin-panel-list-users.js @@ -8,6 +8,7 @@ import Header from 'core-components/header'; import Table from 'core-components/table'; import SearchBox from 'core-components/search-box'; import Button from 'core-components/button'; +import Message from 'core-components/message'; class AdminPanelListUsers extends React.Component { @@ -16,6 +17,7 @@ class AdminPanelListUsers extends React.Component { users: [], orderBy: 'id', desc: true, + error: false, page: 1, pages: 1 }; @@ -34,7 +36,7 @@ class AdminPanelListUsers extends React.Component {
    -
    + {(this.state.error) ? {i18n('ERROR_RETRIEVING_USERS')} :
    } ); } @@ -144,7 +146,7 @@ class AdminPanelListUsers extends React.Component { API.call({ path: '/user/get-users', data: data - }).then(this.onUsersRetrieved.bind(this)); + }).then(this.onUsersRetrieved.bind(this)).catch(this.onUsersRejected.bind(this)); } onUsersRetrieved(result) { @@ -154,6 +156,14 @@ class AdminPanelListUsers extends React.Component { users: result.data.users, orderBy: result.data.orderBy, desc: (result.data.desc === '1'), + error: false, + loading: false + }); + } + + onUsersRejected() { + this.setState({ + error: true, loading: false }); } diff --git a/client/src/app/admin/panel/users/admin-panel-view-user.js b/client/src/app/admin/panel/users/admin-panel-view-user.js index 3b56f132..b18060a2 100644 --- a/client/src/app/admin/panel/users/admin-panel-view-user.js +++ b/client/src/app/admin/panel/users/admin-panel-view-user.js @@ -5,11 +5,13 @@ import {browserHistory} from 'react-router'; import i18n from 'lib-app/i18n'; import API from 'lib-app/api-call'; -import Header from 'core-components/header'; -import Button from 'core-components/button'; import TicketList from 'app-components/ticket-list'; import AreYouSure from 'app-components/are-you-sure'; +import Header from 'core-components/header'; +import Button from 'core-components/button'; +import Message from 'core-components/message'; + class AdminPanelViewUser extends React.Component { state = { @@ -43,7 +45,7 @@ class AdminPanelViewUser extends React.Component { renderInvalid() { return (
    - {i18n('INVALID_USER')} + {i18n('INVALID_USER')}
    ); } diff --git a/client/src/core-components/message.js b/client/src/core-components/message.js index db56adfa..64f75a7a 100644 --- a/client/src/core-components/message.js +++ b/client/src/core-components/message.js @@ -29,7 +29,7 @@ class Message extends React.Component { getAnimationProps() { return { defaultStyle: { - opacity: spring(0, [100, 30]) + opacity: 0 }, style: { opacity: spring(1, [100, 30]) diff --git a/client/src/data/fixtures/user-fixtures.js b/client/src/data/fixtures/user-fixtures.js index c23622e3..bf795b56 100644 --- a/client/src/data/fixtures/user-fixtures.js +++ b/client/src/data/fixtures/user-fixtures.js @@ -147,7 +147,7 @@ module.exports = [ email: 'kurt@currycurrylady.hs', tickets: _.times(13).map(() => { return { - ticketNumber: '1185510000', + ticketNumber: '118551', title: 'Lorem ipsum door', content: 'I had a problem with the installation of the php server', department: { diff --git a/client/src/data/languages/en.js b/client/src/data/languages/en.js index dfd41f50..0f3e9c88 100644 --- a/client/src/data/languages/en.js +++ b/client/src/data/languages/en.js @@ -116,6 +116,7 @@ export default { 'UPDATE_DEPARTMENT': 'Update department', 'TRANSFER_TICKETS_TO': 'Transfer tickets to', 'COMMENTS': 'Comments', + 'EMAIL_BANNED_SUCCESSFULLY': 'Email has been banned successfully', //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.', @@ -161,6 +162,9 @@ export default { 'NO_PERMISSION': 'You\'ve no permission to access to this page.', 'INVALID_USER': 'User id is invalid', 'ERROR_RETRIEVING_TICKETS': 'An error occurred while trying to retrieve tickets.', + 'ERROR_RETRIEVING_USERS': 'An error occurred while trying to retrieve users.', + 'ERROR_RETRIEVING_BAN_LIST': 'An error occurred while trying to retrieve the list of banned emails.', + 'ERROR_BANNING_EMAIL': 'An error occurred while trying to ban the email.', //MESSAGES 'SIGNUP_SUCCESS': 'You have registered successfully in our support system.', From 0fd70ec4419d5d79a1cf2d8c03fb9ce571f93c95 Mon Sep 17 00:00:00 2001 From: ivan Date: Fri, 23 Dec 2016 17:07:21 -0300 Subject: [PATCH 13/16] Ivan - Add error messages for admin articles view [skip ci] --- client/src/app-components/articles-list.js | 7 +++++++ client/src/app-components/people-list.js | 2 +- client/src/data/languages/en.js | 1 + client/src/reducers/articles-reducer.js | 11 +++++++++++ 4 files changed, 20 insertions(+), 1 deletion(-) diff --git a/client/src/app-components/articles-list.js b/client/src/app-components/articles-list.js index ed77d30c..586babc3 100644 --- a/client/src/app-components/articles-list.js +++ b/client/src/app-components/articles-list.js @@ -11,6 +11,7 @@ import TopicEditModal from 'app-components/topic-edit-modal'; import Loading from 'core-components/loading'; import Button from 'core-components/button'; import Icon from 'core-components/icon'; +import Message from 'core-components/message'; class ArticlesList extends React.Component { @@ -18,6 +19,7 @@ class ArticlesList extends React.Component { editable: React.PropTypes.bool, articlePath: React.PropTypes.string, loading: React.PropTypes.bool, + errored: React.PropTypes.bool, topics: React.PropTypes.array, retrieveOnMount: React.PropTypes.bool }; @@ -34,6 +36,10 @@ class ArticlesList extends React.Component { } render() { + if(this.props.errored) { + return {i18n('ERROR_RETRIEVING_ARTICLES')}; + } + return (this.props.loading) ? : this.renderContent(); } @@ -84,6 +90,7 @@ class ArticlesList extends React.Component { export default connect((store) => { return { topics: store.articles.topics, + errored: store.articles.errored, loading: store.articles.loading }; })(ArticlesList); diff --git a/client/src/app-components/people-list.js b/client/src/app-components/people-list.js index 70a37feb..6a636bd3 100644 --- a/client/src/app-components/people-list.js +++ b/client/src/app-components/people-list.js @@ -10,7 +10,7 @@ class PeopleList extends React.Component { static propTypes = { list: React.PropTypes.arrayOf(React.PropTypes.shape({ profilePic: React.PropTypes.string, - name: React.PropTypes.string, + name: React.PropTypes.node, assignedTickets: React.PropTypes.number, closedTickets: React.PropTypes.number, lastLogin: React.PropTypes.number diff --git a/client/src/data/languages/en.js b/client/src/data/languages/en.js index 0f3e9c88..7ab3af00 100644 --- a/client/src/data/languages/en.js +++ b/client/src/data/languages/en.js @@ -165,6 +165,7 @@ export default { 'ERROR_RETRIEVING_USERS': 'An error occurred while trying to retrieve users.', 'ERROR_RETRIEVING_BAN_LIST': 'An error occurred while trying to retrieve the list of banned emails.', 'ERROR_BANNING_EMAIL': 'An error occurred while trying to ban the email.', + 'ERROR_RETRIEVING_ARTICLES': 'An error occurred while trying to retrieve articles.', //MESSAGES 'SIGNUP_SUCCESS': 'You have registered successfully in our support system.', diff --git a/client/src/reducers/articles-reducer.js b/client/src/reducers/articles-reducer.js index fcc5a537..5bdf9ace 100644 --- a/client/src/reducers/articles-reducer.js +++ b/client/src/reducers/articles-reducer.js @@ -9,6 +9,7 @@ class ArticlesReducer extends Reducer { return { retrieved: false, loading: true, + errored: false, topics: [] }; } @@ -16,6 +17,7 @@ class ArticlesReducer extends Reducer { getTypeHandlers() { return { 'GET_ARTICLES_FULFILLED': this.onArticlesRetrieved, + 'GET_ARTICLES_REJECTED': this.onArticlesRejected, 'INIT_ARTICLES': this.onInitArticles }; } @@ -26,10 +28,19 @@ class ArticlesReducer extends Reducer { return _.extend({}, state, { retrieved: true, loading: false, + errored: false, topics: payload.data }); } + onArticlesRejected(state) { + return _.extend({}, state, { + retrieved: true, + loading: false, + errored: true + }); + } + onInitArticles(state) { let topics = SessionStore.getItem('topics'); From 01748a2a259fb7460d19f47231a154f6f0ec7aba Mon Sep 17 00:00:00 2001 From: ivan Date: Sat, 24 Dec 2016 16:53:33 -0300 Subject: [PATCH 14/16] Ivan - Update redbean version to support php7 [skip ci] --- server/composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/composer.json b/server/composer.json index cd6c91e4..71e09ba2 100644 --- a/server/composer.json +++ b/server/composer.json @@ -1,10 +1,10 @@ { "require": { "slim/slim": "~2.0", - "gabordemooij/redbean": "~4.2", "respect/validation": "^1.1", "phpmailer/phpmailer": "^5.2", - "google/recaptcha": "~1.1" + "google/recaptcha": "~1.1", + "gabordemooij/redbean": "^4.3" }, "require-dev": { "phpunit/phpunit": "5.0.*" From cb7885f5d9abe8b8906ee535b34bee778a9ee3ff Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 26 Dec 2016 01:07:40 -0300 Subject: [PATCH 15/16] Ivan - Add messages to staff editor [skip ci] --- .../src/app/admin/panel/staff/staff-editor.js | 50 ++++++++++++++++--- .../app/admin/panel/staff/staff-editor.scss | 4 ++ client/src/data/languages/en.js | 5 +- 3 files changed, 52 insertions(+), 7 deletions(-) diff --git a/client/src/app/admin/panel/staff/staff-editor.js b/client/src/app/admin/panel/staff/staff-editor.js index 4a8905a7..c8b663cf 100644 --- a/client/src/app/admin/panel/staff/staff-editor.js +++ b/client/src/app/admin/panel/staff/staff-editor.js @@ -9,6 +9,7 @@ import TicketList from 'app-components/ticket-list'; import Form from 'core-components/form'; import FormField from 'core-components/form-field'; import SubmitButton from 'core-components/submit-button'; +import Message from 'core-components/message'; class StaffEditor extends React.Component { static propTypes = { @@ -26,12 +27,14 @@ class StaffEditor extends React.Component { state = { email: this.props.email, level: this.props.level - 1, + message: null, departments: this.getUserDepartments() }; render() { return (
    + {(this.state.message) ? this.renderMessage() : null}
    @@ -67,12 +70,12 @@ class StaffEditor extends React.Component {
    -
    this.setState({email: form.email})} onSubmit={this.onSubmit.bind(this)}> + this.setState({email: form.email})} onSubmit={this.onSubmit.bind(this, 'EMAIL')}> {i18n('UPDATE_EMAIL')} -
    + {i18n('UPDATE_PASSWORD')} @@ -100,11 +103,36 @@ class StaffEditor extends React.Component { ); } + renderMessage() { + let messageType = (this.state.message === 'FAIL') ? 'error' : 'success'; + let message = null; + + switch (this.state.message) { + case 'EMAIL': + message = 'EMAIL_CHANGED'; + break; + case 'PASSWORD': + message = 'PASSWORD_CHANGED'; + break; + case 'LEVEL': + message = 'LEVEL_UPDATED'; + break; + case 'DEPARTMENTS': + message = 'DEPARTMENTS_UPDATED'; + break; + case 'FAIL': + message = 'FAILED_EDIT_STAFF'; + break; + } + + return {i18n(message)}; + } + renderLevelForm() { return (
    - this.setState({level: form.level})} onSubmit={this.onSubmit.bind(this)}> + this.setState({level: form.level})} onSubmit={this.onSubmit.bind(this, 'LEVEL')}> this.setState({departments: form.departments})} onSubmit={this.onSubmit.bind(this)}> + this.setState({departments: form.departments})} onSubmit={this.onSubmit.bind(this, 'DEPARTMENTS')}> {i18n('UPDATE_DEPARTMENTS')} @@ -171,7 +199,7 @@ class StaffEditor extends React.Component { return SessionStore.getDepartments().map(department => department.name); } - onSubmit(form) { + onSubmit(eventType, form) { let departments; if(form.departments) { @@ -189,7 +217,17 @@ class StaffEditor extends React.Component { level: (form.level !== undefined) ? form.level + 1 : null, departments: departments && JSON.stringify(departments) } - }).then(this.props.onChange); + }).then((result) => { + window.scrollTo(0,0); + this.setState({message: eventType}); + + if(this.props.onChange) { + this.props.onChange(); + } + }).catch((result) => { + window.scrollTo(0,0); + this.setState({message: 'FAIL'}); + }); } } diff --git a/client/src/app/admin/panel/staff/staff-editor.scss b/client/src/app/admin/panel/staff/staff-editor.scss index 43883a9d..7c070a7c 100644 --- a/client/src/app/admin/panel/staff/staff-editor.scss +++ b/client/src/app/admin/panel/staff/staff-editor.scss @@ -122,4 +122,8 @@ &__separator { margin: 3px 0; } + + &__message { + margin-bottom: 20px; + } } \ No newline at end of file diff --git a/client/src/data/languages/en.js b/client/src/data/languages/en.js index 7ab3af00..3b6b6d54 100644 --- a/client/src/data/languages/en.js +++ b/client/src/data/languages/en.js @@ -179,5 +179,8 @@ export default { 'WILL_LOSE_CHANGES': 'You haven\'t save. Your changes will be lost.', 'WILL_DELETE_CUSTOM_RESPONSE': 'The custom response will be deleted.', 'WILL_DELETE_DEPARTMENT': 'The department will be deleted. All the tickets will be transfer to the department selected.', - 'NO_STAFF_ASSIGNED': 'No staff member is assigned to this department.' + 'NO_STAFF_ASSIGNED': 'No staff member is assigned to this department.', + 'LEVEL_UPDATED': 'Level has been updated successfully.', + 'DEPARTMENTS_UPDATED': 'Departments have been updated successfully.', + 'FAILED_EDIT_STAFF': 'An error occurred while trying to edit staff member.' }; From 42cd02543393b057c6b3737e9e853ebe3bf89508 Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 26 Dec 2016 01:30:04 -0300 Subject: [PATCH 16/16] Ivan - Add delete button for staff [skip ci] --- .../panel/staff/admin-panel-view-staff.js | 9 ++++- .../src/app/admin/panel/staff/staff-editor.js | 38 +++++++++++++++++-- .../app/admin/panel/staff/staff-editor.scss | 13 +++++++ client/src/data/fixtures/staff-fixtures.js | 10 +++++ client/src/data/languages/en.js | 6 ++- 5 files changed, 69 insertions(+), 7 deletions(-) diff --git a/client/src/app/admin/panel/staff/admin-panel-view-staff.js b/client/src/app/admin/panel/staff/admin-panel-view-staff.js index a1d5d933..3e5a0970 100644 --- a/client/src/app/admin/panel/staff/admin-panel-view-staff.js +++ b/client/src/app/admin/panel/staff/admin-panel-view-staff.js @@ -1,5 +1,5 @@ import React from 'react'; -import {connect} from 'react-redux'; +import {browserHistory} from 'react-router'; import _ from 'lodash'; import i18n from 'lib-app/i18n'; @@ -36,7 +36,8 @@ class AdminPanelViewStaff extends React.Component { getProps() { return _.extend({}, this.state.userData, { - staffId: this.props.params.staffId * 1 + staffId: this.props.params.staffId * 1, + onDelete: this.onDelete.bind(this) }); } @@ -46,6 +47,10 @@ class AdminPanelViewStaff extends React.Component { userData: result.data }); } + + onDelete() { + browserHistory.push('/admin/panel/staff/staff-members'); + } } export default AdminPanelViewStaff; \ No newline at end of file diff --git a/client/src/app/admin/panel/staff/staff-editor.js b/client/src/app/admin/panel/staff/staff-editor.js index c8b663cf..e5513e41 100644 --- a/client/src/app/admin/panel/staff/staff-editor.js +++ b/client/src/app/admin/panel/staff/staff-editor.js @@ -5,11 +5,13 @@ import i18n from 'lib-app/i18n'; import API from 'lib-app/api-call'; import SessionStore from 'lib-app/session-store'; import TicketList from 'app-components/ticket-list'; +import AreYouSure from 'app-components/are-you-sure'; import Form from 'core-components/form'; import FormField from 'core-components/form-field'; import SubmitButton from 'core-components/submit-button'; import Message from 'core-components/message'; +import Button from 'core-components/button'; class StaffEditor extends React.Component { static propTypes = { @@ -21,7 +23,8 @@ class StaffEditor extends React.Component { level: React.PropTypes.number.isRequired, tickets: React.PropTypes.array.isRequired, departments: React.PropTypes.array.isRequired, - onChange: React.PropTypes.func + onChange: React.PropTypes.func, + onDelete: React.PropTypes.func }; state = { @@ -99,6 +102,7 @@ class StaffEditor extends React.Component {
    {(this.props.tickets) ? this.renderTickets() : null} + {(!this.props.myAccount) ? this.renderDelete() : null}
    ); } @@ -172,6 +176,22 @@ class StaffEditor extends React.Component {
    ); } + + renderDelete() { + return ( +
    + +
    +
    + {i18n('DELETE_STAFF_MEMBER')} +
    + +
    +
    + ); + } getTicketListProps() { return { @@ -217,14 +237,26 @@ class StaffEditor extends React.Component { level: (form.level !== undefined) ? form.level + 1 : null, departments: departments && JSON.stringify(departments) } - }).then((result) => { + }).then(() => { window.scrollTo(0,0); this.setState({message: eventType}); if(this.props.onChange) { this.props.onChange(); } - }).catch((result) => { + }).catch(() => { + window.scrollTo(0,0); + this.setState({message: 'FAIL'}); + }); + } + + onDeleteClick() { + API.call({ + path: '/staff/delete', + data: { + staffId: this.props.staffId + } + }).then(this.props.onDelete).catch(() => { window.scrollTo(0,0); this.setState({message: 'FAIL'}); }); diff --git a/client/src/app/admin/panel/staff/staff-editor.scss b/client/src/app/admin/panel/staff/staff-editor.scss index 7c070a7c..aaf998d5 100644 --- a/client/src/app/admin/panel/staff/staff-editor.scss +++ b/client/src/app/admin/panel/staff/staff-editor.scss @@ -126,4 +126,17 @@ &__message { margin-bottom: 20px; } + + &__delete { + border: 1px solid $grey; + padding: 20px 50px; + text-align: right; + } + + &__delete-title { + font-size: $font-size--md; + text-align: center; + float: left; + margin-top: 11px; + } } \ No newline at end of file diff --git a/client/src/data/fixtures/staff-fixtures.js b/client/src/data/fixtures/staff-fixtures.js index dd6cae10..0de75e1f 100644 --- a/client/src/data/fixtures/staff-fixtures.js +++ b/client/src/data/fixtures/staff-fixtures.js @@ -1047,5 +1047,15 @@ module.exports = [ data: {} }; } + }, + { + path: '/staff/delete', + time: 100, + response: function () { + return { + status: 'success', + data: {} + }; + } } ]; diff --git a/client/src/data/languages/en.js b/client/src/data/languages/en.js index 3b6b6d54..ae1a3ebf 100644 --- a/client/src/data/languages/en.js +++ b/client/src/data/languages/en.js @@ -116,7 +116,7 @@ export default { 'UPDATE_DEPARTMENT': 'Update department', 'TRANSFER_TICKETS_TO': 'Transfer tickets to', 'COMMENTS': 'Comments', - 'EMAIL_BANNED_SUCCESSFULLY': 'Email has been banned successfully', + 'DELETE_STAFF_MEMBER': 'Delete staff member', //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.', @@ -182,5 +182,7 @@ export default { 'NO_STAFF_ASSIGNED': 'No staff member is assigned to this department.', 'LEVEL_UPDATED': 'Level has been updated successfully.', 'DEPARTMENTS_UPDATED': 'Departments have been updated successfully.', - 'FAILED_EDIT_STAFF': 'An error occurred while trying to edit staff member.' + 'FAILED_EDIT_STAFF': 'An error occurred while trying to edit staff member.', + 'EMAIL_BANNED_SUCCESSFULLY': 'Email has been banned successfully', + 'WILL_DELETE_STAFF': 'This staff member will be deleted and all its tickets will be unassigned.' };