From 6b3a24370ae17f710c24d405ca4ff5eb9dd19ead Mon Sep 17 00:00:00 2001 From: Ivan Diaz Date: Sat, 31 Dec 2016 15:34:29 -0300 Subject: [PATCH 1/3] Ivan - Add supported and allowed languages architecture for frontend [skip ci] --- .../src/app-components/language-selector.js | 67 +++++++++---------- client/src/app-components/ticket-info.js | 5 ++ client/src/app-components/ticket-info.scss | 4 ++ client/src/app-components/ticket-viewer.js | 6 +- client/src/app-components/ticket-viewer.scss | 5 ++ .../create-ticket-form.js | 40 +++++++---- client/src/data/fixtures/system-fixtures.js | 4 +- client/src/data/i18n-data.js | 20 +----- client/src/data/language-list.js | 53 +++++++++++++++ client/src/lib-app/session-store.js | 6 +- 10 files changed, 142 insertions(+), 68 deletions(-) create mode 100644 client/src/data/language-list.js diff --git a/client/src/app-components/language-selector.js b/client/src/app-components/language-selector.js index a5e7c1ae..14ab8012 100644 --- a/client/src/app-components/language-selector.js +++ b/client/src/app-components/language-selector.js @@ -1,22 +1,24 @@ import React from 'react'; +import {connect} from 'react-redux'; import classNames from 'classnames'; + +import languageList from 'data/language-list'; import DropDown from 'core-components/drop-down'; -const codeLanguages = { - 'English': 'us', - 'Spanish': 'es', - 'German': 'de', - 'French': 'fr', - 'Chinese': 'cn', - 'Turkish': 'tr', - 'Indian': 'in' -}; -const languages = Object.keys(codeLanguages); -const languageCodes = languages.map((key) => { return codeLanguages[key]; }).concat(['en']); +const languageCodes = Object.keys(languageList); class LanguageSelector extends React.Component { static propTypes = { - value: React.PropTypes.oneOf(languageCodes) + value: React.PropTypes.oneOf(languageCodes), + type: React.PropTypes.oneOf(['allowed', 'supported']), + allowedLanguages: React.PropTypes.array, + supportedLanguages: React.PropTypes.array + }; + + static defaultProps = { + type: 'allowed', + allowedLanguages: languageCodes, + supportedLanguages: languageCodes }; render() { @@ -28,7 +30,7 @@ class LanguageSelector extends React.Component { getProps() { return { className: this.getClass(), - items: this.getLanguageList(), + items: this.getLanguageItems(), selectedIndex: this.getSelectedIndex(), onChange: this.changeLanguage.bind(this), size: this.props.size @@ -45,37 +47,23 @@ class LanguageSelector extends React.Component { return classNames(classes); } - getLanguageList() { - return languages.map((language) => { + getLanguageItems() { + return this.getLanguageList().map((languageKey) => { return { - content: language, - icon: codeLanguages[language] + content: languageList[languageKey].name, + icon: (languageKey === 'en') ? 'us' : languageKey }; }); } getSelectedIndex() { - let selectedIndex = languages.map((key) => codeLanguages[key]).indexOf(this.getPropLanguage()); + let selectedIndex = this.getLanguageList().indexOf(this.props.value); - return (selectedIndex != -1) ? selectedIndex : undefined; - } - - getPropLanguage() { - let language = this.props.value; - - if (language === 'en') { - language = 'us'; - } - - return language; + return (selectedIndex !== -1) ? selectedIndex : undefined; } changeLanguage(event) { - let language = codeLanguages[languages[event.index]]; - - if (language === 'us') { - language = 'en'; - } + let language = this.getLanguageList()[event.index]; if (this.props.onChange) { this.props.onChange({ @@ -85,6 +73,15 @@ class LanguageSelector extends React.Component { }); } } + + getLanguageList() { + return (this.props.type === 'supported') ? this.props.supportedLanguages : this.props.allowedLanguages; + } } -export default LanguageSelector; \ No newline at end of file +export default connect((store) => { + return { + allowedLanguages: store.config.allowedLanguages, + supportedLanguages: store.config.supportedLanguages + }; +})(LanguageSelector); diff --git a/client/src/app-components/ticket-info.js b/client/src/app-components/ticket-info.js index 0feaa64b..530f8c8d 100644 --- a/client/src/app-components/ticket-info.js +++ b/client/src/app-components/ticket-info.js @@ -2,6 +2,7 @@ import React from 'react'; import _ from 'lodash'; import i18n from 'lib-app/i18n'; +import Icon from 'core-components/icon'; class TicketInfo extends React.Component { static propTypes = { @@ -13,10 +14,14 @@ class TicketInfo extends React.Component {
{this.props.ticket.title} + + +
{this.props.ticket.content}
+
{i18n('AUTHOR')}: {this.props.ticket.author.name}
diff --git a/client/src/app-components/ticket-info.scss b/client/src/app-components/ticket-info.scss index 13ccaf62..4ee52a3f 100644 --- a/client/src/app-components/ticket-info.scss +++ b/client/src/app-components/ticket-info.scss @@ -9,6 +9,10 @@ font-size: $font-size--md; } + &__flag { + margin-left: 10px; + } + &__description { margin-top: 5px; font-size: small; diff --git a/client/src/app-components/ticket-viewer.js b/client/src/app-components/ticket-viewer.js index 262a7b9a..6b6f1362 100644 --- a/client/src/app-components/ticket-viewer.js +++ b/client/src/app-components/ticket-viewer.js @@ -14,7 +14,8 @@ import FormField from 'core-components/form-field'; import SubmitButton from 'core-components/submit-button'; import DropDown from 'core-components/drop-down'; import Button from 'core-components/button'; -import Message from 'core-components/message'; +import Message from 'core-components/message'; +import Icon from 'core-components/icon'; class TicketViewer extends React.Component { static propTypes = { @@ -48,6 +49,9 @@ class TicketViewer extends React.Component {
#{ticket.ticketNumber} {ticket.title} + + +
{this.props.editable ? this.renderEditableHeaders() : this.renderHeaders()}
diff --git a/client/src/app-components/ticket-viewer.scss b/client/src/app-components/ticket-viewer.scss index 0b885aa2..9f03fbf7 100644 --- a/client/src/app-components/ticket-viewer.scss +++ b/client/src/app-components/ticket-viewer.scss @@ -1,6 +1,7 @@ @import "../scss/vars"; .ticket-viewer { + &__header { background-color: $primary-blue; border-top-right-radius: 4px; @@ -20,6 +21,10 @@ display: inline-block; } + &__flag { + margin-left: 10px; + } + &__info-row-header { background-color: $light-grey; font-weight: bold; diff --git a/client/src/app/main/dashboard/dashboard-create-ticket/create-ticket-form.js b/client/src/app/main/dashboard/dashboard-create-ticket/create-ticket-form.js index ca2543cd..84eb980b 100644 --- a/client/src/app/main/dashboard/dashboard-create-ticket/create-ticket-form.js +++ b/client/src/app/main/dashboard/dashboard-create-ticket/create-ticket-form.js @@ -2,12 +2,14 @@ import React from 'react'; import _ from 'lodash'; import ReCAPTCHA from 'react-google-recaptcha'; import { browserHistory } from 'react-router'; +import RichTextEditor from 'react-rte-browserify'; import i18n from 'lib-app/i18n'; import API from 'lib-app/api-call'; import SessionStore from 'lib-app/session-store'; import store from 'app/store'; import SessionActions from 'actions/session-actions'; +import LanguageSelector from 'app-components/language-selector'; import Header from 'core-components/header'; import Form from 'core-components/form'; @@ -25,29 +27,34 @@ class CreateTicketForm extends React.Component { userLogged: true }; - constructor(props) { - super(props); - - this.state = { - loading: false, - message: null - }; - } + state = { + loading: false, + message: null, + form: { + title: '', + content: RichTextEditor.createEmptyValue(), + language: 'en' + } + }; render() { return (
-
+ {(!this.props.userLogged) ? this.renderEmailAndName() : null} +
- - {return {content: department.name}}), size: 'medium' }} /> +
- + {(!this.props.userLogged) ? this.renderCaptcha() : null} Create Ticket @@ -84,6 +91,15 @@ class CreateTicketForm extends React.Component { } } + getFormProps() { + return { + loading: this.state.loading, + onSubmit: this.onSubmit.bind(this), + values: this.state.form, + onChange: form => this.setState({form}) + }; + } + onSubmit(formState) { this.setState({ loading: true diff --git a/client/src/data/fixtures/system-fixtures.js b/client/src/data/fixtures/system-fixtures.js index 672e964e..316abee2 100644 --- a/client/src/data/fixtures/system-fixtures.js +++ b/client/src/data/fixtures/system-fixtures.js @@ -12,7 +12,9 @@ module.exports = [ {id: 1, name: 'Sales Support', owners: 2}, {id: 2, name: 'Technical Issues', owners: 5}, {id: 3, name: 'System and Administration', owners: 0} - ] + ], + 'allowedLanguages': ['en', 'es', 'de', 'fr', 'pt', 'jp', 'ru', 'cn', 'in', 'tr'], + 'supportedLanguages': ['en', 'es', 'de'] } }; } diff --git a/client/src/data/i18n-data.js b/client/src/data/i18n-data.js index 58b1ed38..57f06096 100644 --- a/client/src/data/i18n-data.js +++ b/client/src/data/i18n-data.js @@ -1,23 +1,7 @@ -import englishLanguage from 'data/languages/en'; -import spanishLanguage from 'data/languages/en'; -import germanLanguage from 'data/languages/en'; -import frenchLanguage from 'data/languages/en'; -import chineseLanguage from 'data/languages/en'; -import turkishLanguage from 'data/languages/en'; -import indianLanguage from 'data/languages/en'; - -const languages = { - 'en': englishLanguage, - 'es': spanishLanguage, - 'de': germanLanguage, - 'fr': frenchLanguage, - 'cn': chineseLanguage, - 'tr': turkishLanguage, - 'in': indianLanguage -}; +import languageList from 'data/language-list'; const i18nData = function (key, lang) { - return (languages[lang] && languages[lang][key]) || key; + return (languageList[lang] && languageList[lang].data[key]) || key; }; export default i18nData diff --git a/client/src/data/language-list.js b/client/src/data/language-list.js new file mode 100644 index 00000000..a961c5b1 --- /dev/null +++ b/client/src/data/language-list.js @@ -0,0 +1,53 @@ +import englishLanguage from 'data/languages/en'; +import spanishLanguage from 'data/languages/en'; +import germanLanguage from 'data/languages/en'; +import frenchLanguage from 'data/languages/en'; +import portugueseLanguage from 'data/languages/en'; +import japaneseLanguage from 'data/languages/en'; +import russianLanguage from 'data/languages/en'; +import chineseLanguage from 'data/languages/en'; +import turkishLanguage from 'data/languages/en'; +import indianLanguage from 'data/languages/en'; + +export default { + 'en': { + name: 'English', + data: englishLanguage + }, + 'es': { + name: 'Spanish', + data: spanishLanguage + }, + 'de': { + name: 'German', + data: germanLanguage + }, + 'fr': { + name: 'French', + data: frenchLanguage + }, + 'pt': { + name: 'Portuguese', + data: portugueseLanguage + }, + 'jp': { + name: 'Japanese', + data: japaneseLanguage + }, + 'ru': { + name: 'Russian', + data: russianLanguage + }, + 'cn': { + name: 'Chinese', + data: chineseLanguage + }, + 'tr': { + name: 'Turkish', + data: turkishLanguage + }, + 'in': { + name: 'Indian', + data: indianLanguage + } +}; \ No newline at end of file diff --git a/client/src/lib-app/session-store.js b/client/src/lib-app/session-store.js index 64b11da8..6eaa5783 100644 --- a/client/src/lib-app/session-store.js +++ b/client/src/lib-app/session-store.js @@ -56,13 +56,17 @@ class SessionStore { this.setItem('language', configs.language); this.setItem('reCaptchaKey', configs.reCaptchaKey); this.setItem('departments', JSON.stringify(configs.departments)); + this.setItem('allowedLanguages', JSON.stringify(configs.allowedLanguages)); + this.setItem('supportedLanguages', JSON.stringify(configs.supportedLanguages)); } getConfigs() { return { language: this.getItem('language'), reCaptchaKey: this.getItem('reCaptchaKey'), - departments: this.getDepartments() + departments: this.getDepartments(), + allowedLanguages: JSON.parse(this.getItem('allowedLanguages')), + supportedLanguages: JSON.parse(this.getItem('supportedLanguages')) }; } From af4853ed514d58cde884671fef0ae16e6c2811ca Mon Sep 17 00:00:00 2001 From: AntonyAntonio Date: Tue, 3 Jan 2017 18:52:18 -0300 Subject: [PATCH 2/3] Guillermo - path and tests staff/last-events [skip ci] --- server/controllers/staff.php | 2 ++ server/controllers/staff/last-events.php | 34 ++++++++++++++++++++++++ server/models/Ticketevent.php | 13 +++++++++ tests/init.rb | 3 +-- 4 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 server/controllers/staff/last-events.php diff --git a/server/controllers/staff.php b/server/controllers/staff.php index fff73e65..9967e9db 100644 --- a/server/controllers/staff.php +++ b/server/controllers/staff.php @@ -10,6 +10,7 @@ require_once 'staff/add.php'; require_once 'staff/get-all.php'; require_once 'staff/delete.php'; require_once 'staff/edit.php'; +require_once 'staff/last-events.php'; $systemControllerGroup = new ControllerGroup(); $systemControllerGroup->setGroupPath('/staff'); @@ -25,5 +26,6 @@ $systemControllerGroup->addController(new AddStaffController); $systemControllerGroup->addController(new GetAllStaffController); $systemControllerGroup->addController(new DeleteStaffController); $systemControllerGroup->addController(new EditStaffController); +$systemControllerGroup->addController(new LastEventsStaffController); $systemControllerGroup->finalize(); \ No newline at end of file diff --git a/server/controllers/staff/last-events.php b/server/controllers/staff/last-events.php new file mode 100644 index 00000000..6950bf47 --- /dev/null +++ b/server/controllers/staff/last-events.php @@ -0,0 +1,34 @@ + 'staff_1', + 'requestData' => [ + 'page' => [ + 'validation' => DataValidator::numeric(), + 'error' => ERRORS::INVALID_PAGE + ] + ] + ]; + } + + public function handler() { + $page = Controller::request('page'); + + $user = Controller::getLoggedUser(); + $query = ' ('; + foreach ($user->sharedTicketList as $ticket) { + $query .= 'ticket_id =' . $ticket->id . ' OR '; + } + $query = substr($query,0,-3); + $query .= ') ORDER BY id desc LIMIT ? OFFSET ?' ; + + $eventList = Ticketevent::find($query, [10, 10*($page-1)+1]); + + Response::respondSuccess($eventList->toArray()); + } +} \ No newline at end of file diff --git a/server/models/Ticketevent.php b/server/models/Ticketevent.php index 598eadb3..be1229bf 100644 --- a/server/models/Ticketevent.php +++ b/server/models/Ticketevent.php @@ -58,4 +58,17 @@ class Ticketevent extends DataStore { return new NullDataStore(); } + + public function toArray() { + $user = ($this->authorUser instanceof User) ? $this->authorUser : $this->authorStaff; + + return [ + 'type' => $this->type, + 'ticketNumber' => $this->ticket->ticketNumber, + 'author' => [ + 'name' => $user->name, + 'id' => $user->id + ] + ]; + } } \ No newline at end of file diff --git a/tests/init.rb b/tests/init.rb index 48ea0c17..a300a6fd 100644 --- a/tests/init.rb +++ b/tests/init.rb @@ -47,5 +47,4 @@ require './staff/get-all.rb' require './system/add-department.rb' require './system/edit-department.rb' require './system/delete-department.rb' - - +require './staff/last-events.rb' From 78e3a4383acfcb3fb4f1167e28fc211dd97aa7ea Mon Sep 17 00:00:00 2001 From: AntonyAntonio Date: Tue, 3 Jan 2017 19:02:08 -0300 Subject: [PATCH 3/3] Guillermo - path and tests staff/last-events [skip ci] --- tests/staff/last-events.rb | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 tests/staff/last-events.rb diff --git a/tests/staff/last-events.rb b/tests/staff/last-events.rb new file mode 100644 index 00000000..939005bb --- /dev/null +++ b/tests/staff/last-events.rb @@ -0,0 +1,16 @@ +describe '/staff/last-events' do + request('/user/logout') + Scripts.login($staff[:email], $staff[:password], true) + + it 'should get last events' do + + result = request('/staff/last-events', { + page: 1, + csrf_userid: $csrf_userid, + csrf_token: $csrf_token + }) + + (result['status']).should.equal('success') + (result['data'].size).should.equal(10) + end +end