diff --git a/client/src/app-components/are-you-sure.js b/client/src/app-components/are-you-sure.js index a1502c09..13c86819 100644 --- a/client/src/app-components/are-you-sure.js +++ b/client/src/app-components/are-you-sure.js @@ -2,6 +2,7 @@ import React from 'react'; import i18n from 'lib-app/i18n'; import Button from 'core-components/button'; +import ModalContainer from 'app-components/modal-container'; class AreYouSure extends React.Component { static propTypes = { @@ -12,6 +13,12 @@ class AreYouSure extends React.Component { static contextTypes = { closeModal: React.PropTypes.func }; + + static openModal(description, onYes) { + ModalContainer.openModal( + + ); + } componentDidMount() { this.refs.yesButton && this.refs.yesButton.focus(); diff --git a/client/src/app-components/language-selector.js b/client/src/app-components/language-selector.js index 127ed793..5ee64a17 100644 --- a/client/src/app-components/language-selector.js +++ b/client/src/app-components/language-selector.js @@ -12,10 +12,11 @@ const codeLanguages = { 'Indian': 'in' }; const languages = Object.keys(codeLanguages); +const languageCodes = Object.values(codeLanguages).concat(['en']); class LanguageSelector extends React.Component { static propTypes = { - language: React.PropTypes.oneOf(languages) + language: React.PropTypes.oneOf(languageCodes) }; render() { diff --git a/client/src/app/admin/panel/tickets/admin-panel-custom-responses.js b/client/src/app/admin/panel/tickets/admin-panel-custom-responses.js index ea619f6f..3a400595 100644 --- a/client/src/app/admin/panel/tickets/admin-panel-custom-responses.js +++ b/client/src/app/admin/panel/tickets/admin-panel-custom-responses.js @@ -4,9 +4,9 @@ import {connect} from 'react-redux'; import RichTextEditor from 'react-rte-browserify'; import i18n from 'lib-app/i18n'; +import API from 'lib-app/api-call'; import AdminDataActions from 'actions/admin-data-actions'; -import ModalContainer from 'app-components/modal-container'; import AreYouSure from 'app-components/are-you-sure'; import Icon from 'core-components/icon'; @@ -24,6 +24,7 @@ class AdminPanelCustomResponses extends React.Component { }; state = { + formLoading: false, selectedIndex: -1, edited: false, errors: {}, @@ -32,7 +33,7 @@ class AdminPanelCustomResponses extends React.Component { componentDidMount() { if (!this.props.loaded) { - this.props.dispatch(AdminDataActions.retrieveCustomResponses()); + this.retrieveCustomResponses(); } } @@ -59,12 +60,7 @@ class AdminPanelCustomResponses extends React.Component {
{i18n('SAVE')}
-
- -
-
- -
+ {(this.state.selectedIndex !== -1) ? this.renderOptionalButtons() : null} @@ -80,6 +76,19 @@ class AdminPanelCustomResponses extends React.Component { ); } + renderOptionalButtons() { + return ( +
+
+ +
+
+ +
+
+ ); + } + getListingProps() { return { title: i18n('CUSTOM_RESPONSES'), @@ -95,8 +104,10 @@ class AdminPanelCustomResponses extends React.Component { return { values: this.state.form, errors: this.state.errors, + loading: this.state.formLoading, onChange: (form) => {this.setState({form, edited: true})}, - onValidateErrors: (errors) => {this.setState({errors})} + onValidateErrors: (errors) => {this.setState({errors})}, + onSubmit: this.onFormSubmit.bind(this) } } @@ -117,14 +128,61 @@ class AdminPanelCustomResponses extends React.Component { onItemChange(index) { if(this.state.edited) { - ModalContainer.openModal( - - ); + AreYouSure.openModal(i18n('WILL_LOSE_CHANGES'), this.updateForm.bind(this, index)); } else { this.updateForm(index); } } + onFormSubmit(form) { + this.setState({formLoading: true}); + + if(this.state.selectedIndex !== -1) { + API.call({ + path: '/ticket/edit-custom-response', + data: { + id: this.state.selectedIndex, + name: form.name, + content: form.content, + language: form.language + } + }).then(() => { + this.setState({formLoading: false}); + this.retrieveCustomResponses(); + }); + } else { + API.call({ + path: '/ticket/add-custom-response', + data: { + id: this.state.selectedIndex, + name: form.title, + content: form.content, + language: form.language + } + }).then(() => { + this.setState({formLoading: false}); + this.retrieveCustomResponses(); + }); + } + } + + onDiscardChangesClick() { + this.onItemChange(this.state.selectedIndex); + } + + onDeleteClick() { + AreYouSure.openModal(i18n('WILL_DELETE_CUSTOM_RESPONSE'), this.deleteCustomResponse.bind(this)); + } + + deleteCustomResponse() { + API.call({ + path: '/ticket/delete-custom-response', + data: { + id: this.state.selectedIndex + } + }).then(this.retrieveCustomResponses.bind(this)); + } + updateForm(index) { let form = _.clone(this.state.form); @@ -138,6 +196,10 @@ class AdminPanelCustomResponses extends React.Component { errors: {} }); } + + retrieveCustomResponses() { + this.props.dispatch(AdminDataActions.retrieveCustomResponses()); + } } export default connect((store) => { diff --git a/client/src/app/admin/panel/tickets/admin-panel-custom-responses.scss b/client/src/app/admin/panel/tickets/admin-panel-custom-responses.scss index b92025bb..33f00b58 100644 --- a/client/src/app/admin/panel/tickets/admin-panel-custom-responses.scss +++ b/client/src/app/admin/panel/tickets/admin-panel-custom-responses.scss @@ -16,6 +16,10 @@ margin-right: 30px; } + &__optional-buttons { + display: inline; + } + &__discard-button { display: inline-block; } diff --git a/client/src/core-components/menu.js b/client/src/core-components/menu.js index b0b98eb2..de7cd63e 100644 --- a/client/src/core-components/menu.js +++ b/client/src/core-components/menu.js @@ -13,7 +13,7 @@ class Menu extends React.Component { header: React.PropTypes.string, type: React.PropTypes.oneOf(['primary', 'secondary', 'navigation', 'horizontal', 'horizontal-list']), items: React.PropTypes.arrayOf(React.PropTypes.shape({ - content: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.number]), + content: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.number, React.PropTypes.node]), icon: React.PropTypes.string })).isRequired, selectedIndex: React.PropTypes.number, diff --git a/client/src/data/fixtures/ticket-fixtures.js b/client/src/data/fixtures/ticket-fixtures.js index d7a178d5..f589dd78 100644 --- a/client/src/data/fixtures/ticket-fixtures.js +++ b/client/src/data/fixtures/ticket-fixtures.js @@ -47,5 +47,35 @@ module.exports = [ ] }; } + }, + { + path: '/ticket/add-custom-response', + time: 1000, + response: function () { + return { + status: 'success', + data: {} + }; + } + }, + { + path: '/ticket/edit-custom-response', + time: 1000, + response: function () { + return { + status: 'success', + data: {} + }; + } + }, + { + path: '/ticket/delete-custom-response', + time: 1000, + response: function () { + return { + status: 'success', + data: {} + }; + } } ]; \ No newline at end of file diff --git a/client/src/data/languages/en.js b/client/src/data/languages/en.js index ee46f1c5..8517c52d 100644 --- a/client/src/data/languages/en.js +++ b/client/src/data/languages/en.js @@ -91,5 +91,6 @@ export default { 'EMAIL_CHANGED': 'Email has been changed successfully', 'PASSWORD_CHANGED': 'Password has been changed successfully', 'OLD_PASSWORD_INCORRECT': 'Old password is incorrect', - 'WILL_LOSE_CHANGES': 'You haven\'t save. Your changes will be lost.' + 'WILL_LOSE_CHANGES': 'You haven\'t save. Your changes will be lost.', + 'WILL_DELETE_CUSTOM_RESPONSE': 'The custom response will be deleted.' }; \ No newline at end of file diff --git a/client/src/lib-app/validations/length-validator.js b/client/src/lib-app/validations/length-validator.js index 82c277b9..9aa33f7d 100644 --- a/client/src/lib-app/validations/length-validator.js +++ b/client/src/lib-app/validations/length-validator.js @@ -10,7 +10,7 @@ class LengthValidator extends Validator { this.errorKey = errorKey; } - validate(value, form) { + validate(value = '', form = {}) { if (value instanceof RichTextEditor.EditorValue) { value = value.getEditorState().getCurrentContent().getPlainText(); } diff --git a/client/src/reducers/admin-data-reducer.js b/client/src/reducers/admin-data-reducer.js index 82717d97..60c59d20 100644 --- a/client/src/reducers/admin-data-reducer.js +++ b/client/src/reducers/admin-data-reducer.js @@ -1,7 +1,6 @@ import _ from 'lodash'; import Reducer from 'reducers/reducer'; -//import sessionStore from 'lib-app/session-store'; class AdminDataReducer extends Reducer { @@ -19,8 +18,6 @@ class AdminDataReducer extends Reducer { } onCustomResponses(state, payload) { - //sessionStore.setItem('language', payload); - return _.extend({}, state, { customResponses: payload.data, customResponsesLoaded: true