mirror of
https://github.com/opensupports/opensupports.git
synced 2025-07-27 15:54:23 +02:00
Merge branch 'master' into OS-27-tooltip-ticket-number
Conflicts: client/src/app/main/dashboard/dashboard-list-tickets/dashboard-list-tickets-page.js
This commit is contained in:
commit
bbfcda7522
@ -12,7 +12,7 @@ export default {
|
|||||||
path: '/user/login',
|
path: '/user/login',
|
||||||
data: loginData
|
data: loginData
|
||||||
}).then((result) => {
|
}).then((result) => {
|
||||||
store.dispatch(this.getUserData(result.data.userId, result.data.token));
|
store.dispatch(this.getUserData(result.data.userId, result.data.token, result.data.staff));
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
})
|
})
|
||||||
@ -49,7 +49,7 @@ export default {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
getUserData(userId, token) {
|
getUserData(userId, token, staff) {
|
||||||
let data = {};
|
let data = {};
|
||||||
|
|
||||||
if (userId && token) {
|
if (userId && token) {
|
||||||
@ -62,7 +62,7 @@ export default {
|
|||||||
return {
|
return {
|
||||||
type: 'USER_DATA',
|
type: 'USER_DATA',
|
||||||
payload: API.call({
|
payload: API.call({
|
||||||
path: '/user/get',
|
path: (staff) ? '/staff/get' : '/user/get',
|
||||||
data: data
|
data: data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
136
client/src/app-components/ticket-list.js
Normal file
136
client/src/app-components/ticket-list.js
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import i18n from 'lib-app/i18n';
|
||||||
|
|
||||||
|
import Table from 'core-components/table';
|
||||||
|
import Button from 'core-components/button';
|
||||||
|
import Tooltip from 'core-components/tooltip';
|
||||||
|
|
||||||
|
class TicketList extends React.Component {
|
||||||
|
static propTypes = {
|
||||||
|
tickets: React.PropTypes.arrayOf(React.PropTypes.object),
|
||||||
|
type: React.PropTypes.oneOf([
|
||||||
|
'primary',
|
||||||
|
'secondary'
|
||||||
|
])
|
||||||
|
};
|
||||||
|
|
||||||
|
static defaultProps = {
|
||||||
|
tickets: [],
|
||||||
|
type: 'primary'
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div className="ticket-list">
|
||||||
|
<Table headers={this.getTableHeaders()} rows={this.getTableRows()} pageSize={10} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
getTableHeaders() {
|
||||||
|
if (this.props.type == 'primary' ) {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
key: 'number',
|
||||||
|
value: i18n('NUMBER'),
|
||||||
|
className: 'ticket-list__number col-md-1'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'title',
|
||||||
|
value: i18n('TITLE'),
|
||||||
|
className: 'ticket-list__title col-md-6'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'department',
|
||||||
|
value: i18n('DEPARTMENT'),
|
||||||
|
className: 'ticket-list__department col-md-3'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'date',
|
||||||
|
value: i18n('DATE'),
|
||||||
|
className: 'ticket-list__date col-md-2'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
} else if (this.props.type == 'secondary') {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
key: 'number',
|
||||||
|
value: i18n('NUMBER'),
|
||||||
|
className: 'ticket-list__number col-md-1'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'title',
|
||||||
|
value: i18n('TITLE'),
|
||||||
|
className: 'ticket-list__title col-md-4'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'priority',
|
||||||
|
value: i18n('PRIORITY'),
|
||||||
|
className: 'ticket-list__priority col-md-1'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'department',
|
||||||
|
value: i18n('DEPARTMENT'),
|
||||||
|
className: 'ticket-list__department col-md-2'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'author',
|
||||||
|
value: i18n('AUTHOR'),
|
||||||
|
className: 'ticket-list__author col-md-2'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'date',
|
||||||
|
value: i18n('DATE'),
|
||||||
|
className: 'ticket-list__date col-md-2'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getTableRows() {
|
||||||
|
return this.props.tickets.map(this.gerTicketTableObject.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
gerTicketTableObject(ticket) {
|
||||||
|
let titleText = (ticket.unread) ? ticket.title + ' (1)' : ticket.title;
|
||||||
|
|
||||||
|
return {
|
||||||
|
number: (
|
||||||
|
<Tooltip content="hola">
|
||||||
|
{'#' + ticket.ticketNumber}
|
||||||
|
</Tooltip>
|
||||||
|
),
|
||||||
|
title: (
|
||||||
|
<Button className="ticket-list__title-link" type="clean" route={{to: '/dashboard/ticket/' + ticket.ticketNumber}}>
|
||||||
|
{titleText}
|
||||||
|
</Button>
|
||||||
|
),
|
||||||
|
priority: this.getTicketPriority(ticket.priority),
|
||||||
|
department: ticket.department.name,
|
||||||
|
author: ticket.author.name,
|
||||||
|
date: ticket.date,
|
||||||
|
highlighted: ticket.unread
|
||||||
|
};
|
||||||
|
}
|
||||||
|
getTicketPriority(priority){
|
||||||
|
if(priority == 'high'){
|
||||||
|
return (
|
||||||
|
<span className="ticket-list__priority-high">{i18n('HIGH')}</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if(priority == 'medium'){
|
||||||
|
return (
|
||||||
|
<span className="ticket-list__priority-medium">{i18n('MEDIUM')}</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if(priority == 'low'){
|
||||||
|
return (
|
||||||
|
<span className="ticket-list__priority-low">{i18n('LOW')}</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export default TicketList;
|
47
client/src/app-components/tiket-list.scss
Normal file
47
client/src/app-components/tiket-list.scss
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
@import "../scss/vars";
|
||||||
|
|
||||||
|
.ticket-list {
|
||||||
|
|
||||||
|
&__number {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__title {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__department {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__date {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__title-link:hover,
|
||||||
|
&__title-link:focus {
|
||||||
|
outline: none;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__priority-low,
|
||||||
|
&__priority-medium,
|
||||||
|
&__priority-high {
|
||||||
|
display: inline-block;
|
||||||
|
border-radius: 10px;
|
||||||
|
width: 70px;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__priority-low {
|
||||||
|
background-color: $primary-green;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__priority-medium {
|
||||||
|
background-color: $secondary-blue;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__priority-high {
|
||||||
|
background-color: $primary-red;
|
||||||
|
}
|
||||||
|
}
|
@ -44,7 +44,9 @@ class App extends React.Component {
|
|||||||
const validations = {
|
const validations = {
|
||||||
languageChanged: props.config.language !== this.props.config.language,
|
languageChanged: props.config.language !== this.props.config.language,
|
||||||
loggedIn: !_.includes(props.location.pathname, '/dashboard') && props.session.logged,
|
loggedIn: !_.includes(props.location.pathname, '/dashboard') && props.session.logged,
|
||||||
loggedOut: _.includes(props.location.pathname, '/dashboard') && !props.session.logged
|
loggedOut: _.includes(props.location.pathname, '/dashboard') && !props.session.logged,
|
||||||
|
loggedInStaff: !_.includes(props.location.pathname, '/admin/panel') && props.session.logged && props.session.staff,
|
||||||
|
loggedOutStaff: _.includes(props.location.pathname, '/admin/panel') && !props.session.logged
|
||||||
};
|
};
|
||||||
|
|
||||||
if (validations.languageChanged) {
|
if (validations.languageChanged) {
|
||||||
@ -55,8 +57,14 @@ class App extends React.Component {
|
|||||||
browserHistory.push('/');
|
browserHistory.push('/');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (validations.loggedIn) {
|
if (validations.loggedOutStaff) {
|
||||||
|
browserHistory.push('/admin');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (validations.loggedIn && !props.session.staff) {
|
||||||
browserHistory.push('/dashboard');
|
browserHistory.push('/dashboard');
|
||||||
|
} else if(validations.loggedInStaff) {
|
||||||
|
browserHistory.push('/admin/panel');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {Router, Route, IndexRoute, browserHistory} from 'react-router';
|
import {Router, Route, IndexRoute, IndexRedirect, browserHistory} from 'react-router';
|
||||||
import { syncHistoryWithStore } from 'react-router-redux';
|
import { syncHistoryWithStore } from 'react-router-redux';
|
||||||
|
|
||||||
import store from 'app/store';
|
import store from 'app/store';
|
||||||
@ -20,8 +20,35 @@ import DashboardEditProfilePage from 'app/main/dashboard/dashboard-edit-profile/
|
|||||||
import DashboardArticlePage from 'app/main/dashboard/dashboard-article/dashboard-article-page';
|
import DashboardArticlePage from 'app/main/dashboard/dashboard-article/dashboard-article-page';
|
||||||
import DashboardTicketPage from 'app/main/dashboard/dashboard-ticket/dashboard-ticket-page';
|
import DashboardTicketPage from 'app/main/dashboard/dashboard-ticket/dashboard-ticket-page';
|
||||||
|
|
||||||
|
// ADMIN PANEL
|
||||||
import AdminLoginPage from 'app/admin/admin-login-page';
|
import AdminLoginPage from 'app/admin/admin-login-page';
|
||||||
import AdminPanel from 'app/admin/panel/admin-panel';
|
import AdminPanelLayout from 'app/admin/panel/admin-panel-layout';
|
||||||
|
|
||||||
|
import AdminPanelStats from 'app/admin/panel/dashboard/admin-panel-stats';
|
||||||
|
import AdminPanelActivity from 'app/admin/panel/dashboard/admin-panel-activity';
|
||||||
|
import AdminPanelMyAccount from 'app/admin/panel/dashboard/admin-panel-my-account';
|
||||||
|
|
||||||
|
import AdminPanelMyTickets from 'app/admin/panel/tickets/admin-panel-my-tickets';
|
||||||
|
import AdminPanelNewTickets from 'app/admin/panel/tickets/admin-panel-new-tickets';
|
||||||
|
import AdminPanelAllTickets from 'app/admin/panel/tickets/admin-panel-all-tickets';
|
||||||
|
import AdminPanelViewTicket from 'app/admin/panel/tickets/admin-panel-view-ticket';
|
||||||
|
import AdminPanelCustomResponses from 'app/admin/panel/tickets/admin-panel-custom-responses';
|
||||||
|
|
||||||
|
import AdminPanelListUsers from 'app/admin/panel/users/admin-panel-list-users';
|
||||||
|
import AdminPanelViewUser from 'app/admin/panel/users/admin-panel-view-user';
|
||||||
|
import AdminPanelBanUsers from 'app/admin/panel/users/admin-panel-ban-users';
|
||||||
|
|
||||||
|
import AdminPanelListArticles from 'app/admin/panel/articles/admin-panel-list-articles';
|
||||||
|
import AdminPanelViewArticle from 'app/admin/panel/articles/admin-panel-view-article';
|
||||||
|
|
||||||
|
import AdminPanelStaffMembers from 'app/admin/panel/staff/admin-panel-staff-members';
|
||||||
|
import AdminPanelDepartments from 'app/admin/panel/staff/admin-panel-departments';
|
||||||
|
import AdminPanelViewStaff from 'app/admin/panel/staff/admin-panel-view-staff';
|
||||||
|
|
||||||
|
import AdminPanelSystemPreferences from 'app/admin/panel/settings/admin-panel-system-preferences';
|
||||||
|
import AdminPanelUserSystem from 'app/admin/panel/settings/admin-panel-user-system';
|
||||||
|
import AdminPanelEmailTemplates from 'app/admin/panel/settings/admin-panel-email-templates';
|
||||||
|
import AdminPanelCustomFields from 'app/admin/panel/settings/admin-panel-custom-fields';
|
||||||
|
|
||||||
const history = syncHistoryWithStore(browserHistory, store);
|
const history = syncHistoryWithStore(browserHistory, store);
|
||||||
|
|
||||||
@ -43,10 +70,50 @@ export default (
|
|||||||
<Route path='ticket/:ticketNumber' component={DashboardTicketPage}/>
|
<Route path='ticket/:ticketNumber' component={DashboardTicketPage}/>
|
||||||
</Route>
|
</Route>
|
||||||
</Route>
|
</Route>
|
||||||
<Route path='admin'>
|
<Route path="admin">
|
||||||
<IndexRoute component={AdminLoginPage} />
|
<IndexRoute component={AdminLoginPage} />
|
||||||
<Route path='panel' component={MainLayout}>
|
<Route path="panel" component={AdminPanelLayout}>
|
||||||
<IndexRoute component={AdminPanel} />
|
<IndexRedirect to="stats" />
|
||||||
|
<Route path="stats" component={AdminPanelStats} />
|
||||||
|
<Route path="activity" component={AdminPanelActivity} />
|
||||||
|
<Route path="my-account" component={AdminPanelMyAccount} />
|
||||||
|
|
||||||
|
<Route path="tickets">
|
||||||
|
<IndexRedirect to="my-tickets" />
|
||||||
|
<Route path="my-tickets" component={AdminPanelMyTickets} />
|
||||||
|
<Route path="new-tickets" component={AdminPanelNewTickets} />
|
||||||
|
<Route path="all-tickets" component={AdminPanelAllTickets} />
|
||||||
|
<Route path="custom-responses" component={AdminPanelCustomResponses} />
|
||||||
|
<Route path="view-ticket" component={AdminPanelViewTicket} />
|
||||||
|
</Route>
|
||||||
|
|
||||||
|
<Route path="users">
|
||||||
|
<IndexRedirect to="list-users" />
|
||||||
|
<Route path="list-users" component={AdminPanelListUsers} />
|
||||||
|
<Route path="view-user" component={AdminPanelViewUser} />
|
||||||
|
<Route path="ban-users" component={AdminPanelBanUsers} />
|
||||||
|
</Route>
|
||||||
|
|
||||||
|
<Route path="articles">
|
||||||
|
<IndexRedirect to="list-articles" />
|
||||||
|
<Route path="list-articles" component={AdminPanelListArticles} />
|
||||||
|
<Route path="view-article" component={AdminPanelViewArticle} />
|
||||||
|
</Route>
|
||||||
|
|
||||||
|
<Route path="staff">
|
||||||
|
<IndexRedirect to="staff-members" />
|
||||||
|
<Route path="staff-members" component={AdminPanelStaffMembers} />
|
||||||
|
<Route path="view-staff" component={AdminPanelViewStaff} />
|
||||||
|
<Route path="departments" component={AdminPanelDepartments} />
|
||||||
|
</Route>
|
||||||
|
|
||||||
|
<Route path="settings">
|
||||||
|
<IndexRedirect to="system-preferences" />
|
||||||
|
<Route path="system-preferences" component={AdminPanelSystemPreferences} />
|
||||||
|
<Route path="user-system" component={AdminPanelUserSystem} />
|
||||||
|
<Route path="email-templates" component={AdminPanelEmailTemplates} />
|
||||||
|
<Route path="custom-fields" component={AdminPanelCustomFields} />
|
||||||
|
</Route>
|
||||||
</Route>
|
</Route>
|
||||||
</Route>
|
</Route>
|
||||||
|
|
||||||
|
@ -1,33 +1,58 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import _ from 'lodash';
|
||||||
|
import {connect} from 'react-redux';
|
||||||
|
|
||||||
import i18n from 'lib-app/i18n';
|
import i18n from 'lib-app/i18n';
|
||||||
import API from 'lib-app/api-call';
|
import SessionActions from 'actions/session-actions';
|
||||||
|
|
||||||
import Form from 'core-components/form';
|
import Form from 'core-components/form';
|
||||||
import FormField from 'core-components/form-field';
|
import FormField from 'core-components/form-field';
|
||||||
import SubmitButton from 'core-components/submit-button';
|
import SubmitButton from 'core-components/submit-button';
|
||||||
|
import Message from 'core-components/message';
|
||||||
|
import Widget from 'core-components/widget';
|
||||||
|
|
||||||
class AdminLoginPage extends React.Component {
|
class AdminLoginPage extends React.Component {
|
||||||
render(){
|
render() {
|
||||||
return (
|
return (
|
||||||
<div className="admin-login-page">
|
<div className="admin-login-page">
|
||||||
<div className="admin-login-page__content">
|
<Widget className="admin-login-page__content">
|
||||||
<div className="admin-login-page__image"><img width="100%" src="/images/logo.png" alt="OpenSupports Admin Panel"/></div>
|
<div className="admin-login-page__image"><img width="100%" src="/images/logo.png" alt="OpenSupports Admin Panel"/></div>
|
||||||
<div className="admin-login-page__login-form">
|
<div className="admin-login-page__login-form">
|
||||||
<Form onSubmit={this.onSubmit.bind(this)}>
|
<Form onSubmit={this.onSubmit.bind(this)} loading={this.props.session.pending}>
|
||||||
<FormField name="email" label={i18n('EMAIL')} field="input" validation="EMAIL" fieldProps={{size:'large'}} required />
|
<FormField name="email" label={i18n('EMAIL')} field="input" validation="EMAIL" fieldProps={{size:'large'}} required />
|
||||||
<FormField name="password" label={i18n('PASSWORD')} field="input" validation="PASSWORD" fieldProps={{password:true, size:'large'}} required />
|
<FormField name="password" label={i18n('PASSWORD')} field="input" fieldProps={{password:true, size:'large'}} />
|
||||||
<SubmitButton> {i18n('LOG_IN')} </SubmitButton>
|
<SubmitButton>{i18n('LOG_IN')}</SubmitButton>
|
||||||
</Form>
|
</Form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{this.renderMessage()}
|
||||||
|
</Widget>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderMessage() {
|
||||||
|
let message = null;
|
||||||
|
|
||||||
|
if(this.props.session.failed) {
|
||||||
|
message = (
|
||||||
|
<Message className="admin-login-page__error" type="error">
|
||||||
|
{i18n('EMAIL_OR_PASSWORD')}
|
||||||
|
</Message>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
onSubmit(formState) {
|
onSubmit(formState) {
|
||||||
|
this.props.dispatch(SessionActions.login(_.extend({}, formState, {
|
||||||
|
staff: true
|
||||||
|
})));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default AdminLoginPage;
|
export default connect((store) => {
|
||||||
|
return {
|
||||||
|
session: store.session
|
||||||
|
};
|
||||||
|
})(AdminLoginPage);
|
||||||
|
@ -5,11 +5,7 @@
|
|||||||
|
|
||||||
&__content {
|
&__content {
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
display: inline-block;
|
|
||||||
background-color: white;
|
|
||||||
padding: 40px;
|
padding: 40px;
|
||||||
border-radius: 4px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&__image {
|
&__image {
|
||||||
@ -21,4 +17,8 @@
|
|||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__error {
|
||||||
|
margin-top: 30px;
|
||||||
|
}
|
||||||
}
|
}
|
36
client/src/app/admin/panel/admin-panel-layout.js
Normal file
36
client/src/app/admin/panel/admin-panel-layout.js
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import MainLayout from 'app/main/main-layout';
|
||||||
|
import AdminPanelStaffWidget from 'app/admin/panel/admin-panel-staff-widget';
|
||||||
|
import AdminPanelMenu from 'app/admin/panel/admin-panel-menu';
|
||||||
|
|
||||||
|
import Widget from 'core-components/widget';
|
||||||
|
|
||||||
|
class AdminPanel extends React.Component {
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<MainLayout>
|
||||||
|
<div className="admin-panel-layout">
|
||||||
|
<div className="row admin-panel-layout__header">
|
||||||
|
<div className="col-md-3">
|
||||||
|
<AdminPanelStaffWidget />
|
||||||
|
</div>
|
||||||
|
<div className="col-md-9">
|
||||||
|
<AdminPanelMenu location={this.props.location} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-md-12 admin-panel-layout__content">
|
||||||
|
<Widget>
|
||||||
|
{this.props.children}
|
||||||
|
</Widget>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</MainLayout>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AdminPanel;
|
7
client/src/app/admin/panel/admin-panel-layout.scss
Normal file
7
client/src/app/admin/panel/admin-panel-layout.scss
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
.admin-panel-layout {
|
||||||
|
padding: 0 10px;
|
||||||
|
|
||||||
|
&__header {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
}
|
202
client/src/app/admin/panel/admin-panel-menu.js
Normal file
202
client/src/app/admin/panel/admin-panel-menu.js
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import _ from 'lodash';
|
||||||
|
|
||||||
|
import {dispatch} from 'app/store';
|
||||||
|
import i18n from 'lib-app/i18n';
|
||||||
|
|
||||||
|
import Menu from 'core-components/menu';
|
||||||
|
|
||||||
|
class AdminPanelMenu extends React.Component {
|
||||||
|
static contextTypes = {
|
||||||
|
router: React.PropTypes.object
|
||||||
|
};
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
location: React.PropTypes.object
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div className="admin-panel-menu">
|
||||||
|
<Menu {...this.getGroupsMenuProps()} />
|
||||||
|
<Menu {...this.getGroupMenuProps()} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
getGroupsMenuProps() {
|
||||||
|
return {
|
||||||
|
items: this.getGroups(),
|
||||||
|
selectedIndex: this.getGroupIndex(),
|
||||||
|
onItemClick: this.onGroupClick.bind(this),
|
||||||
|
tabbable: true,
|
||||||
|
type: 'horizontal'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
getGroupMenuProps() {
|
||||||
|
return {
|
||||||
|
items: this.getGroupItems(),
|
||||||
|
selectedIndex: this.getGroupItemIndex(),
|
||||||
|
onItemClick: this.onGroupItemClick.bind(this),
|
||||||
|
tabbable: true,
|
||||||
|
type: 'horizontal-list'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
getGroups() {
|
||||||
|
return this.getRoutes().map((group) => {
|
||||||
|
return {
|
||||||
|
content: group.groupName,
|
||||||
|
icon: group.icon
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getGroupItems() {
|
||||||
|
const group = this.getRoutes()[this.getGroupIndex()];
|
||||||
|
|
||||||
|
return group.items.map((item) => {
|
||||||
|
return {
|
||||||
|
content: item.name
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onGroupClick(index) {
|
||||||
|
this.context.router.push(this.getRoutes()[index].path);
|
||||||
|
}
|
||||||
|
|
||||||
|
onGroupItemClick(index) {
|
||||||
|
const group = this.getRoutes()[this.getGroupIndex()];
|
||||||
|
|
||||||
|
this.context.router.push(group.items[index].path);
|
||||||
|
}
|
||||||
|
|
||||||
|
getGroupItemIndex() {
|
||||||
|
const group = this.getRoutes()[this.getGroupIndex()];
|
||||||
|
const pathname = this.props.location.pathname;
|
||||||
|
|
||||||
|
return _.findIndex(group.items, {path: pathname});
|
||||||
|
}
|
||||||
|
|
||||||
|
getGroupIndex() {
|
||||||
|
const pathname = this.props.location.pathname;
|
||||||
|
const groupIndex = _.findLastIndex(this.getRoutes(), (group) => {
|
||||||
|
return _.includes(pathname, group.path);
|
||||||
|
});
|
||||||
|
|
||||||
|
return (groupIndex === -1) ? 0 : groupIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
getRoutes() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
groupName: i18n('DASHBOARD'),
|
||||||
|
path: '/admin/panel',
|
||||||
|
icon: 'tachometer',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
name: i18n('TICKET_STATS'),
|
||||||
|
path: '/admin/panel/stats'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: i18n('LAST_ACTIVITY'),
|
||||||
|
path: '/admin/panel/activity'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
groupName: i18n('TICKETS'),
|
||||||
|
path: '/admin/panel/tickets',
|
||||||
|
icon: 'ticket',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
name: i18n('MY_TICKETS'),
|
||||||
|
path: '/admin/panel/tickets/my-tickets'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: i18n('NEW_TICKETS'),
|
||||||
|
path: '/admin/panel/tickets/new-tickets'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: i18n('ALL_TICKETS'),
|
||||||
|
path: '/admin/panel/tickets/all-tickets'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: i18n('CUSTOM_RESPONSES'),
|
||||||
|
path: '/admin/panel/tickets/custom-responses'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
groupName: i18n('USERS'),
|
||||||
|
path: '/admin/panel/users',
|
||||||
|
icon: 'user',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
name: i18n('LIST_USERS'),
|
||||||
|
path: '/admin/panel/users/list-users'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: i18n('BAN_USERS'),
|
||||||
|
path: '/admin/panel/users/ban-users'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
groupName: i18n('ARTICLES'),
|
||||||
|
path: '/admin/panel/articles',
|
||||||
|
icon: 'book',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
name: i18n('LIST_ARTICLES'),
|
||||||
|
path: '/admin/panel/articles/list-articles'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
|
||||||
|
groupName: i18n('STAFF'),
|
||||||
|
path: '/admin/panel/staff',
|
||||||
|
icon: 'users',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
name: i18n('STAFF_MEMBERS'),
|
||||||
|
path: '/admin/panel/staff/staff-members'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: i18n('DEPARTMENTS'),
|
||||||
|
path: '/admin/panel/staff/departments'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
|
||||||
|
groupName: i18n('SETTINGS'),
|
||||||
|
path: '/admin/panel/settings',
|
||||||
|
icon: 'cogs',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
name: i18n('SYSTEM_PREFERENCES'),
|
||||||
|
path: '/admin/panel/settings/system-preferences'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: i18n('USER_SYSTEM'),
|
||||||
|
path: '/admin/panel/settings/user-system'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: i18n('EMAIL_TEMPLATES'),
|
||||||
|
path: '/admin/panel/settings/email-templates'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: i18n('FILTERS_CUSTOM_FIELDS'),
|
||||||
|
path: '/admin/panel/settings/custom-fields'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AdminPanelMenu;
|
3
client/src/app/admin/panel/admin-panel-menu.scss
Normal file
3
client/src/app/admin/panel/admin-panel-menu.scss
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
.admin-panel-menu {
|
||||||
|
|
||||||
|
}
|
52
client/src/app/admin/panel/admin-panel-staff-widget.js
Normal file
52
client/src/app/admin/panel/admin-panel-staff-widget.js
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import {connect} from 'react-redux';
|
||||||
|
|
||||||
|
import i18n from 'lib-app/i18n';
|
||||||
|
import Button from 'core-components/button';
|
||||||
|
import SessionActions from 'actions/session-actions';
|
||||||
|
|
||||||
|
class AdminPanelStaffWidget extends React.Component {
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div className={this.getClass()}>
|
||||||
|
<div className="admin-panel-staff-widget__user-data">
|
||||||
|
<div className="admin-panel-staff-widget__name">{this.props.session.userName}</div>
|
||||||
|
<div className="admin-panel-staff-widget__actions">
|
||||||
|
<Button className="admin-panel-staff-widget__action" type="link" route={{to:'/admin/panel/my-account'}}>
|
||||||
|
{i18n('MY_ACCOUNT')}
|
||||||
|
</Button>
|
||||||
|
<span className="admin-panel-staff-widget__action-separator">|</span>
|
||||||
|
<Button className="admin-panel-staff-widget__action" type="link" onClick={this.closeSession.bind(this)}>
|
||||||
|
{i18n('CLOSE_SESSION')}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="admin-panel-staff-widget__profile-pic-wrapper">
|
||||||
|
<img className="admin-panel-staff-widget__profile-pic" src={this.props.session.userProfilePic} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
getClass() {
|
||||||
|
let classes = {
|
||||||
|
'admin-panel-staff-widget': true
|
||||||
|
};
|
||||||
|
|
||||||
|
classes[this.props.className] = (this.props.className);
|
||||||
|
|
||||||
|
return classNames(classes);
|
||||||
|
}
|
||||||
|
|
||||||
|
closeSession() {
|
||||||
|
this.props.dispatch(SessionActions.logout());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect((store) => {
|
||||||
|
return {
|
||||||
|
session: store.session
|
||||||
|
};
|
||||||
|
})(AdminPanelStaffWidget);
|
47
client/src/app/admin/panel/admin-panel-staff-widget.scss
Normal file
47
client/src/app/admin/panel/admin-panel-staff-widget.scss
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
@import '../../../scss/vars';
|
||||||
|
|
||||||
|
.admin-panel-staff-widget {
|
||||||
|
background-color: $secondary-blue;
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 165px;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
&__profile-pic-wrapper {
|
||||||
|
position: absolute;
|
||||||
|
top: 8px;
|
||||||
|
border: 4px solid $grey;
|
||||||
|
border-radius: 50%;
|
||||||
|
width: 90px;
|
||||||
|
height: 90px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-align: center;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
&__profile-pic {
|
||||||
|
height: 100%;
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
&__user-data {
|
||||||
|
position: absolute;
|
||||||
|
background-color: white;
|
||||||
|
bottom: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 110px;
|
||||||
|
padding-top: 48px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__name {
|
||||||
|
font-size: $font-size--md;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__actions {
|
||||||
|
font-size: $font-size--xs;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
}
|
@ -1,13 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
|
|
||||||
class AdminPanel extends React.Component {
|
|
||||||
render(){
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
Admin panel...
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default AdminPanel;
|
|
@ -0,0 +1,14 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
class AdminPanelListArticles extends React.Component {
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
/admin/panel/articles/list-articles
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AdminPanelListArticles;
|
@ -0,0 +1,14 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
class AdminPanelViewArticle extends React.Component {
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
/admin/panel/articles/view-article
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AdminPanelViewArticle;
|
14
client/src/app/admin/panel/dashboard/admin-panel-activity.js
Normal file
14
client/src/app/admin/panel/dashboard/admin-panel-activity.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
class AdminPanelActivity extends React.Component {
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
/admin/panel/activity
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AdminPanelActivity;
|
@ -0,0 +1,14 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
class AdminPanelMyAccount extends React.Component {
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
/admin/panel/my-account
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AdminPanelMyAccount;
|
14
client/src/app/admin/panel/dashboard/admin-panel-stats.js
Normal file
14
client/src/app/admin/panel/dashboard/admin-panel-stats.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
class AdminPanelStats extends React.Component {
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
/admin/panel/stats
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AdminPanelStats;
|
@ -0,0 +1,14 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
class AdminPanelCustomFields extends React.Component {
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
/admin/panel/settings/custom-fields
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AdminPanelCustomFields;
|
@ -0,0 +1,14 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
class AdminPanelEmailTemplates extends React.Component {
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
/admin/panel/settings/email-templates
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AdminPanelEmailTemplates;
|
@ -0,0 +1,14 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
class AdminPanelSystemPreferences extends React.Component {
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
/admin/panel/settings/system-preferences
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AdminPanelSystemPreferences;
|
@ -0,0 +1,14 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
class AdminPanelUserSystem extends React.Component {
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
/admin/panel/settings/user-system
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AdminPanelUserSystem;
|
14
client/src/app/admin/panel/staff/admin-panel-departments.js
Normal file
14
client/src/app/admin/panel/staff/admin-panel-departments.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
class AdminPanelDepartments extends React.Component {
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
/admin/panel/staff/departments
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AdminPanelDepartments;
|
@ -0,0 +1,14 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
class AdminPanelStaffMembers extends React.Component {
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
/admin/panel/staff/staff-members
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AdminPanelStaffMembers;
|
14
client/src/app/admin/panel/staff/admin-panel-view-staff.js
Normal file
14
client/src/app/admin/panel/staff/admin-panel-view-staff.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
class AdminPanelViewStaff extends React.Component {
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
/admin/panel/staff/view-staff
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AdminPanelViewStaff;
|
@ -0,0 +1,14 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
class AdminPanelAllTickets extends React.Component {
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
/admin/panel/tickets/all-tickets
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AdminPanelAllTickets;
|
@ -0,0 +1,14 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
class AdminPanelCustomResponses extends React.Component {
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
/admin/panel/tickets/custom-responses
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AdminPanelCustomResponses;
|
14
client/src/app/admin/panel/tickets/admin-panel-my-tickets.js
Normal file
14
client/src/app/admin/panel/tickets/admin-panel-my-tickets.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
class AdminPanelMyTickets extends React.Component {
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
/admin/panel/tickets/my-tickets
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AdminPanelMyTickets;
|
@ -0,0 +1,14 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
class AdminPanelNewTickets extends React.Component {
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
/admin/panel/tickets/new-tickets
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AdminPanelNewTickets;
|
@ -0,0 +1,14 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
class AdminPanelViewTicket extends React.Component {
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
/admin/panel/tickets/view-ticket
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AdminPanelViewTicket;
|
14
client/src/app/admin/panel/users/admin-panel-ban-users.js
Normal file
14
client/src/app/admin/panel/users/admin-panel-ban-users.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
class AdminPanelBanUsers extends React.Component {
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
/admin/panel/users/ban-users
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AdminPanelBanUsers;
|
14
client/src/app/admin/panel/users/admin-panel-list-users.js
Normal file
14
client/src/app/admin/panel/users/admin-panel-list-users.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
class AdminPanelListUsers extends React.Component {
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
/admin/panel/users/list-users
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AdminPanelListUsers;
|
14
client/src/app/admin/panel/users/admin-panel-view-user.js
Normal file
14
client/src/app/admin/panel/users/admin-panel-view-user.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
class AdminPanelViewUser extends React.Component {
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
/admin/panel/users/view-user
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AdminPanelViewUser;
|
@ -65,12 +65,6 @@ let DemoPage = React.createClass({
|
|||||||
</Widget>
|
</Widget>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
{
|
|
||||||
title: 'DropDown',
|
|
||||||
render: (
|
|
||||||
<DropDown items={dropDownItems} onChange={function (index) { console.log('changed to ' + index); }} />
|
|
||||||
)
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
title: 'Primary Menu',
|
title: 'Primary Menu',
|
||||||
render: (
|
render: (
|
||||||
@ -83,6 +77,30 @@ let DemoPage = React.createClass({
|
|||||||
<Menu items={secondaryMenuItems} type="secondary"/>
|
<Menu items={secondaryMenuItems} type="secondary"/>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: 'Navigation Menu',
|
||||||
|
render: (
|
||||||
|
<Menu items={secondaryMenuItems} type="navigation"/>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Horizontal Menu',
|
||||||
|
render: (
|
||||||
|
<Menu items={secondaryMenuItems.slice(0, 3)} type="horizontal"/>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'HorizontalList Menu',
|
||||||
|
render: (
|
||||||
|
<Menu items={dropDownItems.slice(0, 3)} type="horizontal-list"/>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'DropDown',
|
||||||
|
render: (
|
||||||
|
<DropDown items={dropDownItems} onChange={function (index) { console.log('changed to ' + index); }} />
|
||||||
|
)
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: 'Tooltip',
|
title: 'Tooltip',
|
||||||
render: (
|
render: (
|
||||||
|
@ -20,7 +20,6 @@ class DashboardEditProfilePage extends React.Component {
|
|||||||
messagePass:''
|
messagePass:''
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div className="edit-profile-page">
|
<div className="edit-profile-page">
|
||||||
|
@ -4,9 +4,7 @@ import {connect} from 'react-redux';
|
|||||||
import i18n from 'lib-app/i18n';
|
import i18n from 'lib-app/i18n';
|
||||||
|
|
||||||
import Header from 'core-components/header';
|
import Header from 'core-components/header';
|
||||||
import Table from 'core-components/table';
|
import TicketList from 'app-components/ticket-list';
|
||||||
import Button from 'core-components/button';
|
|
||||||
import Tooltip from 'core-components/tooltip';
|
|
||||||
import TicketInfo from 'app-components/ticket-info';
|
import TicketInfo from 'app-components/ticket-info';
|
||||||
|
|
||||||
class DashboardListTicketsPage extends React.Component {
|
class DashboardListTicketsPage extends React.Component {
|
||||||
@ -22,59 +20,10 @@ class DashboardListTicketsPage extends React.Component {
|
|||||||
return (
|
return (
|
||||||
<div className="dashboard-ticket-list">
|
<div className="dashboard-ticket-list">
|
||||||
<Header title={i18n('TICKET_LIST')} description={i18n('TICKET_LIST_DESCRIPTION')} />
|
<Header title={i18n('TICKET_LIST')} description={i18n('TICKET_LIST_DESCRIPTION')} />
|
||||||
<Table headers={this.getTableHeaders()} rows={this.getTableRows()} pageSize={10} />
|
<TicketList tickets={this.props.tickets} type="primary"/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
getTableHeaders() {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
key: 'number',
|
|
||||||
value: 'Number',
|
|
||||||
className: 'dashboard-ticket-list__number col-md-1'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'title',
|
|
||||||
value: 'Title',
|
|
||||||
className: 'dashboard-ticket-list__title col-md-6'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'department',
|
|
||||||
value: 'Department',
|
|
||||||
className: 'dashboard-ticket-list__department col-md-3'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'date',
|
|
||||||
value: 'Date',
|
|
||||||
className: 'dashboard-ticket-list__date col-md-2'
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
getTableRows() {
|
|
||||||
return this.props.tickets.map(this.gerTicketTableObject.bind(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
gerTicketTableObject(ticket) {
|
|
||||||
let titleText = (ticket.unread) ? ticket.title + ' (1)' : ticket.title;
|
|
||||||
|
|
||||||
return {
|
|
||||||
number: (
|
|
||||||
<Tooltip content={<TicketInfo ticket={ticket}/>} >
|
|
||||||
{'#' + ticket.ticketNumber}
|
|
||||||
</Tooltip>
|
|
||||||
),
|
|
||||||
title: (
|
|
||||||
<Button className="dashboard-ticket-list__title-link" type="clean" route={{to: '/dashboard/ticket/' + ticket.ticketNumber}}>
|
|
||||||
{titleText}
|
|
||||||
</Button>
|
|
||||||
),
|
|
||||||
department: ticket.department.name,
|
|
||||||
date: ticket.date,
|
|
||||||
highlighted: ticket.unread
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,26 +0,0 @@
|
|||||||
@import "../../../../scss/vars";
|
|
||||||
|
|
||||||
.dashboard-ticket-list {
|
|
||||||
|
|
||||||
&__number {
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__title {
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__department {
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__date {
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__title-link:hover,
|
|
||||||
&__title-link:focus {
|
|
||||||
outline: none;
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
}
|
|
@ -84,7 +84,9 @@ class Menu extends React.Component {
|
|||||||
let classes = {
|
let classes = {
|
||||||
'menu': true,
|
'menu': true,
|
||||||
'menu_secondary': (this.props.type === 'secondary'),
|
'menu_secondary': (this.props.type === 'secondary'),
|
||||||
'menu_navigation': (this.props.type === 'navigation')
|
'menu_navigation': (this.props.type === 'navigation'),
|
||||||
|
'menu_horizontal': (this.props.type === 'horizontal'),
|
||||||
|
'menu_horizontal-list': (this.props.type === 'horizontal-list')
|
||||||
};
|
};
|
||||||
|
|
||||||
classes[this.props.className] = true;
|
classes[this.props.className] = true;
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
@import "../scss/vars";
|
@import "../scss/vars";
|
||||||
|
|
||||||
|
$transition: background-color 0.3s ease, color 0.3s ease;
|
||||||
|
|
||||||
.menu {
|
.menu {
|
||||||
|
|
||||||
&__list {
|
&__list {
|
||||||
@ -13,7 +15,7 @@
|
|||||||
|
|
||||||
&__list-item {
|
&__list-item {
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
transition: background-color 0.3s ease, color 0.3s ease;
|
transition: $transition;
|
||||||
|
|
||||||
&_selected,
|
&_selected,
|
||||||
&:hover {
|
&:hover {
|
||||||
@ -78,4 +80,93 @@
|
|||||||
color: $primary-blue;
|
color: $primary-blue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&_horizontal {
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
.menu__list {
|
||||||
|
background-color: transparent;
|
||||||
|
font-size: $font-size--md;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu__icon {
|
||||||
|
display: block;
|
||||||
|
margin-right: 0;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
margin-top: 20px;
|
||||||
|
font-size: $font-size--xl;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu__list-item {
|
||||||
|
background-color: white;
|
||||||
|
color: $primary-black;
|
||||||
|
cursor: pointer;
|
||||||
|
display: inline-block;
|
||||||
|
height: 120px;
|
||||||
|
width: 16.6667%;
|
||||||
|
|
||||||
|
@media (max-width: 667px) {
|
||||||
|
width: 33.3333%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu__list-item_selected {
|
||||||
|
background-color: $secondary-blue;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu__list-item:hover,
|
||||||
|
.menu__list-item:focus {
|
||||||
|
color: $dark-grey;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu__list-item_selected:focus,
|
||||||
|
.menu__list-item_selected:hover {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&_horizontal-list {
|
||||||
|
text-align: left;
|
||||||
|
background-color: $secondary-blue;
|
||||||
|
min-height: 45px;
|
||||||
|
|
||||||
|
.menu__list {
|
||||||
|
background-color: transparent;
|
||||||
|
font-size: $font-size--sm;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu__list-item {
|
||||||
|
transition: none;
|
||||||
|
background-color: transparent;
|
||||||
|
color: white;
|
||||||
|
cursor: pointer;
|
||||||
|
display: inline-block;
|
||||||
|
margin-top: 11px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
margin-left: 20px;
|
||||||
|
padding: 2px 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu__list-item:hover {
|
||||||
|
transition: $transition;
|
||||||
|
background-color: transparent;
|
||||||
|
color: $primary-black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu__list-item:focus {
|
||||||
|
color: $grey;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu__list-item_selected,
|
||||||
|
.menu__list-item_selected:hover {
|
||||||
|
transition: $transition;
|
||||||
|
padding: 2px 13px;
|
||||||
|
border-radius: 30px;
|
||||||
|
background-color: $primary-blue;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
23
client/src/data/fixtures/staff-fixtures.js
Normal file
23
client/src/data/fixtures/staff-fixtures.js
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
module.exports = [
|
||||||
|
{
|
||||||
|
path: '/staff/get',
|
||||||
|
time: 100,
|
||||||
|
response: function () {
|
||||||
|
return {
|
||||||
|
status: 'success',
|
||||||
|
data: {
|
||||||
|
name: 'Emilia Clarke',
|
||||||
|
email: 'staff@opensupports.com',
|
||||||
|
profilePic: 'http://i65.tinypic.com/9bep95.jpg',
|
||||||
|
level: 1,
|
||||||
|
staff: true,
|
||||||
|
departments: [
|
||||||
|
{id: 1, name: 'Sales Support'},
|
||||||
|
{id: 2, name: 'Technical Issues'},
|
||||||
|
{id: 3, name: 'System and Administration'}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
@ -9,6 +9,7 @@ module.exports = [
|
|||||||
response = {
|
response = {
|
||||||
status: 'success',
|
status: 'success',
|
||||||
data: {
|
data: {
|
||||||
|
'staff': data.staff,
|
||||||
'userId': 12,
|
'userId': 12,
|
||||||
'token': 'cc6b4921e6733d6aafe284ec0d7be57e',
|
'token': 'cc6b4921e6733d6aafe284ec0d7be57e',
|
||||||
'rememberToken': (data.remember) ? 'aa41efe0a1b3eeb9bf303e4561ff8392' : null,
|
'rememberToken': (data.remember) ? 'aa41efe0a1b3eeb9bf303e4561ff8392' : null,
|
||||||
@ -147,6 +148,7 @@ module.exports = [
|
|||||||
language: 'en',
|
language: 'en',
|
||||||
unread: true,
|
unread: true,
|
||||||
closed: false,
|
closed: false,
|
||||||
|
priority: 'low',
|
||||||
author: {
|
author: {
|
||||||
id: 12,
|
id: 12,
|
||||||
name: 'Haskell Curry',
|
name: 'Haskell Curry',
|
||||||
@ -195,6 +197,47 @@ module.exports = [
|
|||||||
language: 'en',
|
language: 'en',
|
||||||
unread: false,
|
unread: false,
|
||||||
closed: false,
|
closed: false,
|
||||||
|
priority: 'medium',
|
||||||
|
author: {
|
||||||
|
name: 'Haskell Curry',
|
||||||
|
email: 'haskell@lambda.com'
|
||||||
|
},
|
||||||
|
owner: {
|
||||||
|
name: 'Steve Jobs'
|
||||||
|
},
|
||||||
|
comments: [
|
||||||
|
{
|
||||||
|
content: 'Do you have apache installed? It generally happens if you dont have apache.',
|
||||||
|
author: {
|
||||||
|
name: 'Steve Jobs',
|
||||||
|
email: 'jobs@steve.com',
|
||||||
|
staff: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
content: 'I have already installed apache, but the problem persists',
|
||||||
|
author: {
|
||||||
|
name: 'Haskell Curry',
|
||||||
|
steve: 'haskell@lambda.com',
|
||||||
|
staff: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ticketNumber: '878552',
|
||||||
|
title: 'Lorem ipsum door',
|
||||||
|
content: 'I had a problem with the installation of the php server',
|
||||||
|
department: {
|
||||||
|
id: 2,
|
||||||
|
name: 'Environment Setup'
|
||||||
|
},
|
||||||
|
date: '15 Apr 2016',
|
||||||
|
file: 'http://www.opensupports.com/some_file.zip',
|
||||||
|
language: 'en',
|
||||||
|
unread: false,
|
||||||
|
closed: false,
|
||||||
|
priority: 'high',
|
||||||
author: {
|
author: {
|
||||||
name: 'Haskell Curry',
|
name: 'Haskell Curry',
|
||||||
email: 'haskell@lambda.com'
|
email: 'haskell@lambda.com'
|
||||||
|
@ -36,8 +36,34 @@ export default {
|
|||||||
'CUSTOMER': 'Customer',
|
'CUSTOMER': 'Customer',
|
||||||
'YES': 'Yes',
|
'YES': 'Yes',
|
||||||
'CANCEL': 'Cancel',
|
'CANCEL': 'Cancel',
|
||||||
|
'MY_ACCOUNT': 'My Account',
|
||||||
|
'DASHBOARD': 'Dashboard',
|
||||||
|
'USERS': 'Users',
|
||||||
|
'SETTINGS': 'Settings',
|
||||||
|
'TICKET_STATS': 'Ticket Stats',
|
||||||
|
'LAST_ACTIVITY': 'Last Activity',
|
||||||
|
'MY_TICKETS': 'My Tickets',
|
||||||
|
'NEW_TICKETS': 'New Tickets',
|
||||||
|
'ALL_TICKETS': 'All Tickets',
|
||||||
|
'CUSTOM_RESPONSES': 'Custom Responses',
|
||||||
|
'LIST_USERS': 'List Users',
|
||||||
|
'BAN_USERS': 'Ban Users',
|
||||||
|
'LIST_ARTICLES': 'List Articles',
|
||||||
|
'STAFF_MEMBERS': 'Staff Members',
|
||||||
|
'DEPARTMENTS': 'Departments',
|
||||||
|
'SYSTEM_PREFERENCES': 'System Preferences',
|
||||||
|
'USER_SYSTEM': 'User System',
|
||||||
|
'EMAIL_TEMPLATES': 'Email Templates',
|
||||||
|
'FILTERS_CUSTOM_FIELDS': 'Filters and Custom Fields',
|
||||||
|
'PRIORITY': 'Priority',
|
||||||
|
'NUMBER': 'Number',
|
||||||
|
'HIGH': 'High',
|
||||||
|
'MEDIUM': 'Medium',
|
||||||
|
'LOW': 'Low',
|
||||||
|
'TITLE': 'Title',
|
||||||
|
|
||||||
//ERRORS
|
//ERRORS
|
||||||
|
'EMAIL_OR_PASSWORD': 'Email or password invalid',
|
||||||
'EMAIL_NOT_EXIST': 'Email does not exist',
|
'EMAIL_NOT_EXIST': 'Email does not exist',
|
||||||
'ERROR_EMPTY': 'Invalid value',
|
'ERROR_EMPTY': 'Invalid value',
|
||||||
'ERROR_PASSWORD': 'Invalid password',
|
'ERROR_PASSWORD': 'Invalid password',
|
||||||
|
@ -17,6 +17,7 @@ let fixtures = (function () {
|
|||||||
|
|
||||||
// FIXTURES
|
// FIXTURES
|
||||||
fixtures.add(require('data/fixtures/user-fixtures'));
|
fixtures.add(require('data/fixtures/user-fixtures'));
|
||||||
|
fixtures.add(require('data/fixtures/staff-fixtures'));
|
||||||
fixtures.add(require('data/fixtures/ticket-fixtures'));
|
fixtures.add(require('data/fixtures/ticket-fixtures'));
|
||||||
fixtures.add(require('data/fixtures/system-fixtures'));
|
fixtures.add(require('data/fixtures/system-fixtures'));
|
||||||
|
|
||||||
|
@ -41,7 +41,8 @@ class SessionReducer extends Reducer {
|
|||||||
return _.extend({}, state, {
|
return _.extend({}, state, {
|
||||||
logged: true,
|
logged: true,
|
||||||
pending: false,
|
pending: false,
|
||||||
failed: false
|
failed: false,
|
||||||
|
staff: payload.data.staff
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,8 +102,12 @@ class SessionReducer extends Reducer {
|
|||||||
sessionStore.storeUserData(payload.data);
|
sessionStore.storeUserData(payload.data);
|
||||||
|
|
||||||
return _.extend({}, state, {
|
return _.extend({}, state, {
|
||||||
userName: userData.name,
|
staff: userData.staff,
|
||||||
userEmail: userData.email,
|
userName: userData.name,
|
||||||
|
userEmail: userData.email,
|
||||||
|
userProfilePic: userData.profilePic,
|
||||||
|
userLevel: userData.level,
|
||||||
|
userDepartments: userData.departments,
|
||||||
userTickets: userData.tickets
|
userTickets: userData.tickets
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -113,8 +118,12 @@ class SessionReducer extends Reducer {
|
|||||||
return _.extend({}, state, {
|
return _.extend({}, state, {
|
||||||
initDone: true,
|
initDone: true,
|
||||||
logged: true,
|
logged: true,
|
||||||
|
staff: userData.staff,
|
||||||
userName: userData.name,
|
userName: userData.name,
|
||||||
userEmail: userData.email,
|
userEmail: userData.email,
|
||||||
|
userProfilePic: userData.profilePic,
|
||||||
|
userLevel: userData.level,
|
||||||
|
userDepartments: userData.departments,
|
||||||
userTickets: userData.tickets
|
userTickets: userData.tickets
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
9
server/controllers/staff.php
Normal file
9
server/controllers/staff.php
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'staff/get.php';
|
||||||
|
|
||||||
|
$systemControllerGroup = new ControllerGroup();
|
||||||
|
$systemControllerGroup->setGroupPath('/staff');
|
||||||
|
|
||||||
|
$systemControllerGroup->addController(new GetStaffController);
|
||||||
|
|
||||||
|
$systemControllerGroup->finalize();
|
36
server/controllers/staff/get.php
Normal file
36
server/controllers/staff/get.php
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
use Respect\Validation\Validator as DataValidator;
|
||||||
|
DataValidator::with('CustomValidations', true);
|
||||||
|
|
||||||
|
class GetStaffController extends Controller {
|
||||||
|
const PATH = '/get';
|
||||||
|
|
||||||
|
public function validations() {
|
||||||
|
return [
|
||||||
|
'permission' => 'staff_1',
|
||||||
|
'requestData' => []
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handler() {
|
||||||
|
$user = Controller::getLoggedUser();
|
||||||
|
$parsedDepartmentList = [];
|
||||||
|
$departmentList = $user->sharedDepartmentList;
|
||||||
|
|
||||||
|
foreach($departmentList as $department) {
|
||||||
|
$parsedDepartmentList[] = [
|
||||||
|
'id' => $department->id,
|
||||||
|
'name' => $department->name
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
Response::respondSuccess([
|
||||||
|
'name' => $user->name,
|
||||||
|
'email' => $user->email,
|
||||||
|
'profilePic' => $user->profilePic,
|
||||||
|
'level' => $user->level,
|
||||||
|
'staff' => true,
|
||||||
|
'departments' => $parsedDepartmentList
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
@ -15,6 +15,7 @@ class InitSettingsController extends Controller {
|
|||||||
$this->storeGlobalSettings();
|
$this->storeGlobalSettings();
|
||||||
$this->storeMailTemplates();
|
$this->storeMailTemplates();
|
||||||
$this->storeMockedDepartments();
|
$this->storeMockedDepartments();
|
||||||
|
$this->createMockedStaff();
|
||||||
|
|
||||||
Response::respondSuccess();
|
Response::respondSuccess();
|
||||||
} else {
|
} else {
|
||||||
@ -80,4 +81,18 @@ class InitSettingsController extends Controller {
|
|||||||
$department->store();
|
$department->store();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function createMockedStaff() {
|
||||||
|
$staff = new Staff();
|
||||||
|
$staff->setProperties([
|
||||||
|
'name' => 'Emilia Clarke',
|
||||||
|
'email' => 'staff@opensupports.com',
|
||||||
|
'password' => Hashing::hashPassword('staff'),
|
||||||
|
'profilePic' => 'http://i65.tinypic.com/9bep95.jpg',
|
||||||
|
'level' => 1,
|
||||||
|
'sharedDepartmentList' => Department::getAllDepartments(),
|
||||||
|
'sharedTicketList' => []
|
||||||
|
]);
|
||||||
|
$staff->store();
|
||||||
|
}
|
||||||
}
|
}
|
@ -44,14 +44,19 @@ class CommentController extends Controller {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private function storeComment() {
|
private function storeComment() {
|
||||||
$comment = new Comment();
|
$comment = Ticketevent::getEvent(Ticketevent::COMMENT);
|
||||||
$comment->setProperties(array(
|
$comment->setProperties(array(
|
||||||
'content' => $this->content,
|
'content' => $this->content,
|
||||||
'author' => Controller::getLoggedUser(),
|
|
||||||
'date' => Date::getCurrentDate()
|
'date' => Date::getCurrentDate()
|
||||||
));
|
));
|
||||||
|
|
||||||
$this->ticket->ownCommentList->add($comment);
|
if(Controller::isStaffLogged()) {
|
||||||
|
$comment->authorUser = Controller::getLoggedUser();
|
||||||
|
} else {
|
||||||
|
$comment->authorUser = Controller::getLoggedUser();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->ticket->addEvent($comment);
|
||||||
$this->ticket->store();
|
$this->ticket->store();
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -13,6 +13,11 @@ class GetUserController extends Controller {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function handler() {
|
public function handler() {
|
||||||
|
if (Controller::isStaffLogged()) {
|
||||||
|
Response::respondError(ERRORS::INVALID_CREDENTIALS);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
$user = Controller::getLoggedUser();
|
$user = Controller::getLoggedUser();
|
||||||
$parsedTicketList = [];
|
$parsedTicketList = [];
|
||||||
$ticketList = $user->sharedTicketList;
|
$ticketList = $user->sharedTicketList;
|
||||||
|
@ -46,7 +46,7 @@ class LoginController extends Controller {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private function createUserSession() {
|
private function createUserSession() {
|
||||||
Session::getInstance()->createSession($this->userInstance->id);
|
Session::getInstance()->createSession($this->userInstance->id, Controller::request('staff'));
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getUserData() {
|
private function getUserData() {
|
||||||
@ -55,6 +55,7 @@ class LoginController extends Controller {
|
|||||||
return array(
|
return array(
|
||||||
'userId' => $userInstance->id,
|
'userId' => $userInstance->id,
|
||||||
'userEmail' => $userInstance->email,
|
'userEmail' => $userInstance->email,
|
||||||
|
'staff' => Controller::request('staff'),
|
||||||
'token' => Session::getInstance()->getToken(),
|
'token' => Session::getInstance()->getToken(),
|
||||||
'rememberToken' => $this->rememberToken
|
'rememberToken' => $this->rememberToken
|
||||||
);
|
);
|
||||||
@ -64,7 +65,11 @@ class LoginController extends Controller {
|
|||||||
$email = Controller::request('email');
|
$email = Controller::request('email');
|
||||||
$password = Controller::request('password');
|
$password = Controller::request('password');
|
||||||
|
|
||||||
return User::authenticate($email, $password);
|
if(Controller::request('staff')) {
|
||||||
|
return Staff::authenticate($email, $password);
|
||||||
|
} else {
|
||||||
|
return User::authenticate($email, $password);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getUserByRememberToken() {
|
private function getUserByRememberToken() {
|
||||||
|
@ -15,4 +15,5 @@ class ERRORS {
|
|||||||
const INIT_SETTINGS_DONE = 'Settings already initialized';
|
const INIT_SETTINGS_DONE = 'Settings already initialized';
|
||||||
const INVALID_OLD_PASSWORD = 'Invalid old password';
|
const INVALID_OLD_PASSWORD = 'Invalid old password';
|
||||||
const INVALID_CAPTCHA = 'Invalid captcha';
|
const INVALID_CAPTCHA = 'Invalid captcha';
|
||||||
|
const INVALID_TICKET_EVENT = 'INVALID_TICKET_EVENT';
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,13 @@ abstract class Controller {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static function getLoggedUser() {
|
public static function getLoggedUser() {
|
||||||
return User::getUser((int)self::request('csrf_userid'));
|
$session = Session::getInstance();
|
||||||
|
|
||||||
|
if ($session->isStaffLogged()) {
|
||||||
|
return Staff::getUser((int)self::request('csrf_userid'));
|
||||||
|
} else {
|
||||||
|
return User::getUser((int)self::request('csrf_userid'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function isUserLogged() {
|
public static function isUserLogged() {
|
||||||
@ -48,12 +54,8 @@ abstract class Controller {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function isStaffLogged() {
|
public static function isStaffLogged($level = 1) {
|
||||||
return Controller::isUserLogged() && (Controller::getLoggedUser()->admin === 1);
|
return Controller::isUserLogged() && (Controller::getLoggedUser()->level >= $level);
|
||||||
}
|
|
||||||
|
|
||||||
public static function isAdminLogged() {
|
|
||||||
return Controller::isUserLogged() && (Controller::getLoggedUser()->admin === 2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getAppInstance() {
|
public static function getAppInstance() {
|
||||||
|
@ -16,8 +16,9 @@ class Validator {
|
|||||||
$permissions = [
|
$permissions = [
|
||||||
'any' => true,
|
'any' => true,
|
||||||
'user' => Controller::isUserLogged(),
|
'user' => Controller::isUserLogged(),
|
||||||
'staff' => Controller::isStaffLogged(),
|
'staff_1' => Controller::isStaffLogged(1),
|
||||||
'admin' => Controller::isAdminLogged()
|
'staff_2' => Controller::isStaffLogged(2),
|
||||||
|
'staff_3' => Controller::isStaffLogged(3)
|
||||||
];
|
];
|
||||||
|
|
||||||
if (!$permissions[$permission]) {
|
if (!$permissions[$permission]) {
|
||||||
|
@ -1,14 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
class Comment extends DataStore {
|
|
||||||
const TABLE = 'comment';
|
|
||||||
|
|
||||||
public static function getProps() {
|
|
||||||
return array(
|
|
||||||
'content',
|
|
||||||
'file',
|
|
||||||
'author',
|
|
||||||
'date'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -21,4 +21,15 @@ class Department extends DataStore {
|
|||||||
|
|
||||||
return $departmentsNameList;
|
return $departmentsNameList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function getAllDepartments() {
|
||||||
|
$departmentsQuantity = RedBean::count(Department::TABLE);
|
||||||
|
$departmentList = new DataStoreList();
|
||||||
|
|
||||||
|
for ($departmentIndex = 1; $departmentIndex <= $departmentsQuantity; ++$departmentIndex) {
|
||||||
|
$departmentList->add(Department::getDataStore($departmentIndex));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $departmentList;
|
||||||
|
}
|
||||||
}
|
}
|
@ -24,8 +24,9 @@ class Session {
|
|||||||
return self::$instance;
|
return self::$instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function createSession($userId) {
|
public function createSession($userId, $staff = false) {
|
||||||
$this->store('userId', $userId);
|
$this->store('userId', $userId);
|
||||||
|
$this->store('staff', $staff);
|
||||||
$this->store('token', Hashing::generateRandomToken());
|
$this->store('token', Hashing::generateRandomToken());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,6 +38,10 @@ class Session {
|
|||||||
return !!$this->getToken();
|
return !!$this->getToken();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function isStaffLogged() {
|
||||||
|
return $this->getStoredData('staff');
|
||||||
|
}
|
||||||
|
|
||||||
public function checkAuthentication($data) {
|
public function checkAuthentication($data) {
|
||||||
$userId = $this->getStoredData('userId');
|
$userId = $this->getStoredData('userId');
|
||||||
$token = $this->getStoredData('token');
|
$token = $this->getStoredData('token');
|
||||||
|
33
server/models/Staff.php
Normal file
33
server/models/Staff.php
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class Staff extends DataStore {
|
||||||
|
const TABLE = 'staff';
|
||||||
|
|
||||||
|
public static function authenticate($userEmail, $userPassword) {
|
||||||
|
$user = Staff::getUser($userEmail, 'email');
|
||||||
|
|
||||||
|
return ($user && Hashing::verifyPassword($userPassword, $user->password)) ? $user : new NullDataStore();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getProps() {
|
||||||
|
return [
|
||||||
|
'name',
|
||||||
|
'email',
|
||||||
|
'password',
|
||||||
|
'profilePic',
|
||||||
|
'level',
|
||||||
|
'sharedDepartmentList',
|
||||||
|
'sharedTicketList'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDefaultProps() {
|
||||||
|
return [
|
||||||
|
'level' => 1
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getUser($value, $property = 'id') {
|
||||||
|
return parent::getDataStore($value, $property);
|
||||||
|
}
|
||||||
|
}
|
@ -15,9 +15,10 @@ class Ticket extends DataStore {
|
|||||||
'date',
|
'date',
|
||||||
'unread',
|
'unread',
|
||||||
'closed',
|
'closed',
|
||||||
|
'priority',
|
||||||
'author',
|
'author',
|
||||||
'owner',
|
'owner',
|
||||||
'ownCommentList'
|
'ownTicketeventList'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32,6 +33,7 @@ class Ticket extends DataStore {
|
|||||||
public function getDefaultProps() {
|
public function getDefaultProps() {
|
||||||
return array(
|
return array(
|
||||||
'owner' => null,
|
'owner' => null,
|
||||||
|
'priority' => 'low',
|
||||||
'ticketNumber' => $this->generateUniqueTicketNumber()
|
'ticketNumber' => $this->generateUniqueTicketNumber()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -39,6 +41,7 @@ class Ticket extends DataStore {
|
|||||||
public function store() {
|
public function store() {
|
||||||
parent::store();
|
parent::store();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function generateUniqueTicketNumber() {
|
public function generateUniqueTicketNumber() {
|
||||||
$ticketQuantity = Ticket::count('ticket');
|
$ticketQuantity = Ticket::count('ticket');
|
||||||
$minValue = 100000;
|
$minValue = 100000;
|
||||||
@ -57,8 +60,6 @@ class Ticket extends DataStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function toArray() {
|
public function toArray() {
|
||||||
$author = $this->author;
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'ticketNumber' => $this->ticketNumber,
|
'ticketNumber' => $this->ticketNumber,
|
||||||
'title' => $this->title,
|
'title' => $this->title,
|
||||||
@ -72,9 +73,10 @@ class Ticket extends DataStore {
|
|||||||
'language' => $this->language,
|
'language' => $this->language,
|
||||||
'unread' => !!$this->unread,
|
'unread' => !!$this->unread,
|
||||||
'closed' => !!$this->closed,
|
'closed' => !!$this->closed,
|
||||||
|
'priority' => $this->priority,
|
||||||
'author' => $this->authorToArray(),
|
'author' => $this->authorToArray(),
|
||||||
'owner' => $this->ownerToArray(),
|
'owner' => $this->ownerToArray(),
|
||||||
'comments' => $this->commentsToArray()
|
'events' => $this->eventsToArray()
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,23 +108,35 @@ class Ticket extends DataStore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function commentsToArray() {
|
public function eventsToArray() {
|
||||||
$comments = [];
|
$events = [];
|
||||||
|
|
||||||
foreach ($this->ownCommentList as $comment) {
|
foreach ($this->ownTicketeventList as $ticketEvent) {
|
||||||
$comments[] = [
|
$event = [
|
||||||
'content'=> $comment->content,
|
'type' => $ticketEvent->type,
|
||||||
'author' => [
|
'content'=> $ticketEvent->content,
|
||||||
'id'=> 15,
|
'author' => [],
|
||||||
'name' => $comment->author->name,
|
'date'=> $ticketEvent->date,
|
||||||
'email' => $comment->author->email,
|
'file'=> $ticketEvent->file
|
||||||
'staff' => $comment->author->staff
|
|
||||||
],
|
|
||||||
'date'=> $comment->date,
|
|
||||||
'file'=> $comment->file
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
$author = $ticketEvent->getAuthor();
|
||||||
|
if(!$author->isNull()) {
|
||||||
|
$event['author'] = [
|
||||||
|
'id'=> $author->id,
|
||||||
|
'name' => $author->name,
|
||||||
|
'email' =>$author->email,
|
||||||
|
'staff' => $author instanceof Staff
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$events[] = $event;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $comments;
|
return $events;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addEvent(Ticketevent $event) {
|
||||||
|
$this->ownTicketeventList->add($event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
60
server/models/Ticketevent.php
Normal file
60
server/models/Ticketevent.php
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class Ticketevent extends DataStore {
|
||||||
|
const TABLE = 'ticketevent';
|
||||||
|
|
||||||
|
const COMMENT = 'COMMENT';
|
||||||
|
const ASSIGN = 'ASSIGN';
|
||||||
|
const UNASSIGN = 'UNASSIGN';
|
||||||
|
const CLOSE = 'CLOSE';
|
||||||
|
const REOPEN = 'REOPEN';
|
||||||
|
const DEPARTMENT_CHANGED = 'DEPARTMENT_CHANGED';
|
||||||
|
const PRIORITY_CHANGED = 'PRIORITY_CHANGED';
|
||||||
|
|
||||||
|
private static function getEventTypes() {
|
||||||
|
return [
|
||||||
|
'COMMENT',
|
||||||
|
'UNASSIGN',
|
||||||
|
'CLOSE',
|
||||||
|
'REOPEN',
|
||||||
|
'DEPARTMENT_CHANGED',
|
||||||
|
'PRIORITY_CHANGED',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getEvent($type) {
|
||||||
|
if (!in_array($type, Ticketevent::getEventTypes())) {
|
||||||
|
return new NullDataStore();
|
||||||
|
}
|
||||||
|
|
||||||
|
$ticketEvent = new Ticketevent();
|
||||||
|
$ticketEvent->setProperties([
|
||||||
|
'type' => $type
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $ticketEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getProps() {
|
||||||
|
return [
|
||||||
|
'type',
|
||||||
|
'content',
|
||||||
|
'file',
|
||||||
|
'authorUser',
|
||||||
|
'authorStaff',
|
||||||
|
'date'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAuthor() {
|
||||||
|
if($this->authorUser) {
|
||||||
|
return $this->authorUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
if($this->authorStaff) {
|
||||||
|
return $this->authorStaff;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new NullDataStore();
|
||||||
|
}
|
||||||
|
}
|
@ -15,16 +15,13 @@ class User extends DataStore {
|
|||||||
'email',
|
'email',
|
||||||
'password',
|
'password',
|
||||||
'name',
|
'name',
|
||||||
'admin',
|
|
||||||
'sharedTicketList',
|
'sharedTicketList',
|
||||||
'verificationToken',
|
'verificationToken',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDefaultProps() {
|
public function getDefaultProps() {
|
||||||
return [
|
return [];
|
||||||
'admin' => 0
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getUser($value, $property = 'id') {
|
public static function getUser($value, $property = 'id') {
|
||||||
|
@ -35,10 +35,11 @@ class LoginControllerTest extends PHPUnit_Framework_TestCase {
|
|||||||
|
|
||||||
$this->loginController->handler();
|
$this->loginController->handler();
|
||||||
|
|
||||||
$this->assertTrue(Session::getInstance()->createSession->hasBeenCalledWithArgs('MOCK_ID'));
|
$this->assertTrue(Session::getInstance()->createSession->hasBeenCalledWithArgs('MOCK_ID', null));
|
||||||
$this->assertTrue(Response::get('respondSuccess')->hasBeenCalledWithArgs(array(
|
$this->assertTrue(Response::get('respondSuccess')->hasBeenCalledWithArgs(array(
|
||||||
'userId' => 'MOCK_ID',
|
'userId' => 'MOCK_ID',
|
||||||
'userEmail' => 'MOCK_EMAIL',
|
'userEmail' => 'MOCK_EMAIL',
|
||||||
|
'staff' => null,
|
||||||
'token' => 'TEST_TOKEN',
|
'token' => 'TEST_TOKEN',
|
||||||
'rememberToken' => null
|
'rememberToken' => null
|
||||||
)));
|
)));
|
||||||
|
@ -21,3 +21,4 @@ require './user/get.rb'
|
|||||||
require './ticket/create.rb'
|
require './ticket/create.rb'
|
||||||
require './ticket/comment.rb'
|
require './ticket/comment.rb'
|
||||||
require './ticket/get.rb'
|
require './ticket/get.rb'
|
||||||
|
require './staff/get.rb'
|
||||||
|
@ -26,3 +26,8 @@ class Database
|
|||||||
end
|
end
|
||||||
|
|
||||||
$database = Database.new
|
$database = Database.new
|
||||||
|
|
||||||
|
$staff = {
|
||||||
|
:email => 'staff@opensupports.com',
|
||||||
|
:password => 'staff'
|
||||||
|
}
|
||||||
|
@ -11,11 +11,12 @@ class Scripts
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.login(email = 'steve@jobs.com', password = 'custompassword')
|
def self.login(email = 'steve@jobs.com', password = 'custompassword', staff = false)
|
||||||
request('/user/logout')
|
request('/user/logout')
|
||||||
response = request('/user/login', {
|
response = request('/user/login', {
|
||||||
:email => email,
|
:email => email,
|
||||||
:password => password
|
:password => password,
|
||||||
|
:staff => staff
|
||||||
})
|
})
|
||||||
|
|
||||||
if response['data'].any?
|
if response['data'].any?
|
||||||
|
15
tests/staff/get.rb
Normal file
15
tests/staff/get.rb
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
describe '/staff/get/' do
|
||||||
|
request('/user/logout')
|
||||||
|
Scripts.login($staff[:email], $staff[:password], true)
|
||||||
|
|
||||||
|
it 'should return staff member data' do
|
||||||
|
result = request('/staff/get', {
|
||||||
|
csrf_userid: $csrf_userid,
|
||||||
|
csrf_token: $csrf_token
|
||||||
|
})
|
||||||
|
|
||||||
|
(result['status']).should.equal('success')
|
||||||
|
(result['data']['name']).should.equal('Emilia Clarke')
|
||||||
|
(result['data']['staff']).should.equal(true)
|
||||||
|
end
|
||||||
|
end
|
@ -68,9 +68,10 @@ describe '/ticket/comment/' do
|
|||||||
(result['status']).should.equal('success')
|
(result['status']).should.equal('success')
|
||||||
|
|
||||||
ticket = $database.getRow('ticket', @ticketNumber, 'ticket_number')
|
ticket = $database.getRow('ticket', @ticketNumber, 'ticket_number')
|
||||||
comment = $database.getRow('comment', ticket['id'], 'ticket_id')
|
comment = $database.getRow('ticketevent', ticket['id'], 'ticket_id')
|
||||||
(comment['content']).should.equal('some comment content')
|
(comment['content']).should.equal('some comment content')
|
||||||
(comment['author_id']).should.equal($csrf_userid)
|
(comment['type']).should.equal('COMMENT')
|
||||||
|
(comment['author_user_id']).should.equal($csrf_userid)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should fail if user is not the author nor owner' do
|
it 'should fail if user is not the author nor owner' do
|
||||||
|
@ -100,6 +100,7 @@ describe '/ticket/create' do
|
|||||||
(ticket['content']).should.equal('The north remembers')
|
(ticket['content']).should.equal('The north remembers')
|
||||||
(ticket['unread']).should.equal('0')
|
(ticket['unread']).should.equal('0')
|
||||||
(ticket['closed']).should.equal('0')
|
(ticket['closed']).should.equal('0')
|
||||||
|
(ticket['priority']).should.equal('low')
|
||||||
(ticket['department_id']).should.equal('1')
|
(ticket['department_id']).should.equal('1')
|
||||||
(ticket['author_id']).should.equal($csrf_userid)
|
(ticket['author_id']).should.equal($csrf_userid)
|
||||||
(ticket['ticket_number'].size).should.equal(6)
|
(ticket['ticket_number'].size).should.equal(6)
|
||||||
|
@ -15,6 +15,13 @@ describe '/ticket/get/' do
|
|||||||
csrf_token: $csrf_token
|
csrf_token: $csrf_token
|
||||||
})
|
})
|
||||||
@ticketNumber = result['data']['ticketNumber']
|
@ticketNumber = result['data']['ticketNumber']
|
||||||
|
|
||||||
|
request('/ticket/comment', {
|
||||||
|
ticketNumber: @ticketNumber,
|
||||||
|
content: 'some valid comment made',
|
||||||
|
csrf_userid: $csrf_userid,
|
||||||
|
csrf_token: $csrf_token
|
||||||
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should fail if ticketNumber is invalid' do
|
it 'should fail if ticketNumber is invalid' do
|
||||||
@ -46,6 +53,7 @@ describe '/ticket/get/' do
|
|||||||
result = Scripts.login('cersei@os4.com', 'cersei')
|
result = Scripts.login('cersei@os4.com', 'cersei')
|
||||||
$csrf_userid = result['userId']
|
$csrf_userid = result['userId']
|
||||||
$csrf_token = result['token']
|
$csrf_token = result['token']
|
||||||
|
|
||||||
result = request('/ticket/get', {
|
result = request('/ticket/get', {
|
||||||
ticketNumber: @ticketNumber,
|
ticketNumber: @ticketNumber,
|
||||||
csrf_userid: $csrf_userid,
|
csrf_userid: $csrf_userid,
|
||||||
@ -68,6 +76,8 @@ describe '/ticket/get/' do
|
|||||||
(result['data']['author']['name']).should.equal('Cersei Lannister')
|
(result['data']['author']['name']).should.equal('Cersei Lannister')
|
||||||
(result['data']['author']['email']).should.equal('cersei@os4.com')
|
(result['data']['author']['email']).should.equal('cersei@os4.com')
|
||||||
(result['data']['owner']).should.equal([])
|
(result['data']['owner']).should.equal([])
|
||||||
(result['data']['comments']).should.equal([])
|
(result['data']['events'].size).should.equal(1)
|
||||||
|
(result['data']['events'][0]['type']).should.equal('COMMENT')
|
||||||
|
(result['data']['events'][0]['content']).should.equal('some valid comment made')
|
||||||
end
|
end
|
||||||
end
|
end
|
@ -52,6 +52,6 @@ describe '/user/get' do
|
|||||||
(ticketFromUser['author']['name']).should.equal('User Get')
|
(ticketFromUser['author']['name']).should.equal('User Get')
|
||||||
(ticketFromUser['author']['email']).should.equal('user_get@os4.com')
|
(ticketFromUser['author']['email']).should.equal('user_get@os4.com')
|
||||||
(ticketFromUser['owner']).should.equal([])
|
(ticketFromUser['owner']).should.equal([])
|
||||||
(ticketFromUser['comments']).should.equal([])
|
(ticketFromUser['events']).should.equal([])
|
||||||
end
|
end
|
||||||
end
|
end
|
@ -13,13 +13,36 @@ describe '/user/login' do
|
|||||||
(result['status']).should.equal('fail')
|
(result['status']).should.equal('fail')
|
||||||
end
|
end
|
||||||
|
|
||||||
# it 'should login correctly' do
|
it 'should login correctly' do
|
||||||
|
result = request('/user/login', {
|
||||||
|
email: @loginEmail,
|
||||||
|
password: @loginPass
|
||||||
|
})
|
||||||
|
|
||||||
# end
|
(result['status']).should.equal('success')
|
||||||
|
end
|
||||||
|
|
||||||
# it 'should fail if already logged in' do
|
it 'should fail if already logged in' do
|
||||||
|
result = request('/user/login', {
|
||||||
|
email: @loginEmail,
|
||||||
|
password: @loginPass
|
||||||
|
})
|
||||||
|
|
||||||
# end
|
(result['status']).should.equal('fail')
|
||||||
|
(result['message']).should.equal('User is already logged in')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should login staff member' do
|
||||||
|
request('/user/logout', {})
|
||||||
|
result = request('/user/login', {
|
||||||
|
email: $staff[:email],
|
||||||
|
password: $staff[:password],
|
||||||
|
staff: true
|
||||||
|
})
|
||||||
|
|
||||||
|
(result['status']).should.equal('success')
|
||||||
|
(result['data']['staff']).should.equal('true')
|
||||||
|
end
|
||||||
|
|
||||||
it 'should return remember token' do
|
it 'should return remember token' do
|
||||||
request('/user/logout', {})
|
request('/user/logout', {})
|
||||||
@ -31,7 +54,7 @@ describe '/user/login' do
|
|||||||
|
|
||||||
(result['status']).should.equal('success')
|
(result['status']).should.equal('success')
|
||||||
|
|
||||||
@rememberToken = result['data']['rememberToken']# falta comproversion
|
@rememberToken = result['data']['rememberToken']
|
||||||
@userid = result['data']['userId']
|
@userid = result['data']['userId']
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -10,7 +10,6 @@ describe '/user/signup' do
|
|||||||
|
|
||||||
(userRow['email']).should.equal('steve@jobs.com')
|
(userRow['email']).should.equal('steve@jobs.com')
|
||||||
(userRow['name']).should.equal('Steve Jobs')
|
(userRow['name']).should.equal('Steve Jobs')
|
||||||
(userRow['admin']).should.equal('0')
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should fail if name is invalid' do
|
it 'should fail if name is invalid' do
|
||||||
|
Loading…
x
Reference in New Issue
Block a user