Merge branch 'master' into OS-130-create-system-preferences-view
This commit is contained in:
commit
37ae4b1bfe
|
@ -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;
|
||||
export default connect((store) => {
|
||||
return {
|
||||
allowedLanguages: store.config.allowedLanguages,
|
||||
supportedLanguages: store.config.supportedLanguages
|
||||
};
|
||||
})(LanguageSelector);
|
||||
|
|
|
@ -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 {
|
|||
<div className="ticket-info">
|
||||
<div className="ticket-info__title">
|
||||
{this.props.ticket.title}
|
||||
<span className="ticket-info__flag">
|
||||
<Icon name={(this.props.ticket.language === 'en') ? 'us' : this.props.ticket.language}/>
|
||||
</span>
|
||||
</div>
|
||||
<div className="ticket-info__description">
|
||||
{this.props.ticket.content}
|
||||
</div>
|
||||
|
||||
<div className="ticket-info__author">
|
||||
{i18n('AUTHOR')}: {this.props.ticket.author.name}
|
||||
</div>
|
||||
|
|
|
@ -9,6 +9,10 @@
|
|||
font-size: $font-size--md;
|
||||
}
|
||||
|
||||
&__flag {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
&__description {
|
||||
margin-top: 5px;
|
||||
font-size: small;
|
||||
|
|
|
@ -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 {
|
|||
<div className="ticket-viewer__header row">
|
||||
<span className="ticket-viewer__number">#{ticket.ticketNumber}</span>
|
||||
<span className="ticket-viewer__title">{ticket.title}</span>
|
||||
<span className="ticket-viewer__flag">
|
||||
<Icon name={(ticket.language === 'en') ? 'us' : ticket.language}/>
|
||||
</span>
|
||||
</div>
|
||||
{this.props.editable ? this.renderEditableHeaders() : this.renderHeaders()}
|
||||
<div className="ticket-viewer__content">
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 (
|
||||
<div className="create-ticket-form">
|
||||
<Header title={i18n('CREATE_TICKET')} description={i18n('CREATE_TICKET_DESCRIPTION')} />
|
||||
<Form loading={this.state.loading} onSubmit={this.onSubmit.bind(this)}>
|
||||
<Form {...this.getFormProps()}>
|
||||
{(!this.props.userLogged) ? this.renderEmailAndName() : null}
|
||||
<FormField label={i18n('TITLE')} name="title" validation="TITLE" required field="input" fieldProps={{size: 'large'}}/>
|
||||
<div className="row">
|
||||
<FormField className="col-md-7" label="Title" name="title" validation="TITLE" required field="input" fieldProps={{size: 'large'}}/>
|
||||
<FormField className="col-md-5" label="Department" name="departmentIndex" field="select" fieldProps={{
|
||||
<FormField className="col-md-5" label={i18n('DEPARTMENT')} name="departmentIndex" field="select" fieldProps={{
|
||||
items: SessionStore.getDepartments().map((department) => {return {content: department.name}}),
|
||||
size: 'medium'
|
||||
}} />
|
||||
<FormField className="col-md-5" label={i18n('LANGUAGE')} name="language" field="select" decorator={LanguageSelector} fieldProps={{
|
||||
type: 'supported',
|
||||
size: 'medium'
|
||||
}}/>
|
||||
</div>
|
||||
<FormField label="Content" name="content" validation="TEXT_AREA" required field="textarea" />
|
||||
<FormField label={i18n('CONTENT')} name="content" validation="TEXT_AREA" required field="textarea" />
|
||||
{(!this.props.userLogged) ? this.renderCaptcha() : null}
|
||||
<SubmitButton>Create Ticket</SubmitButton>
|
||||
</Form>
|
||||
|
@ -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
|
||||
|
|
|
@ -13,7 +13,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']
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
};
|
|
@ -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'))
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
use Respect\Validation\Validator as DataValidator;
|
||||
|
||||
class LastEventsStaffController extends Controller {
|
||||
const PATH = '/last-events';
|
||||
|
||||
public function validations() {
|
||||
return [
|
||||
'permission' => '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());
|
||||
}
|
||||
}
|
|
@ -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
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
|
@ -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'
|
||||
|
|
|
@ -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
|
Loading…
Reference in New Issue