Add staff dropdown for assignment
This commit is contained in:
parent
99ea7e0f8a
commit
dda8e28e93
|
@ -1,7 +1,7 @@
|
|||
import API from 'lib-app/api-call';
|
||||
|
||||
export default {
|
||||
|
||||
|
||||
retrieveCustomResponses() {
|
||||
return {
|
||||
type: 'CUSTOM_RESPONSES',
|
||||
|
@ -42,6 +42,16 @@ export default {
|
|||
};
|
||||
},
|
||||
|
||||
retrieveStaffMembers() {
|
||||
return {
|
||||
type: 'STAFF_MEMBERS',
|
||||
payload: API.call({
|
||||
path: '/staff/get-all',
|
||||
data: {}
|
||||
})
|
||||
};
|
||||
},
|
||||
|
||||
searchTickets(query, page = 1) {
|
||||
return {
|
||||
type: 'ALL_TICKETS',
|
||||
|
@ -51,4 +61,4 @@ export default {
|
|||
})
|
||||
};
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
|
@ -2,6 +2,8 @@ import React from 'react';
|
|||
import _ from 'lodash';
|
||||
import {connect} from 'react-redux';
|
||||
|
||||
import AdminDataActions from 'actions/admin-data-actions';
|
||||
|
||||
import i18n from 'lib-app/i18n';
|
||||
import API from 'lib-app/api-call';
|
||||
import SessionStore from 'lib-app/session-store';
|
||||
|
@ -24,7 +26,9 @@ class TicketViewer extends React.Component {
|
|||
onChange: React.PropTypes.func,
|
||||
editable: React.PropTypes.bool,
|
||||
customResponses: React.PropTypes.array,
|
||||
assignmentAllowed: React.PropTypes.bool
|
||||
assignmentAllowed: React.PropTypes.bool,
|
||||
staffMembers: React.PropTypes.array,
|
||||
staffMembersLoaded: React.PropTypes.bool,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
|
@ -42,6 +46,12 @@ class TicketViewer extends React.Component {
|
|||
commentEdited: false
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
if(!this.props.staffMembersLoaded && this.props.editable) {
|
||||
this.props.dispatch(AdminDataActions.retrieveStaffMembers());
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const ticket = this.props.ticket;
|
||||
|
||||
|
@ -84,7 +94,7 @@ class TicketViewer extends React.Component {
|
|||
<div className="ticket-viewer__headers">
|
||||
<div className="ticket-viewer__info-row-header row">
|
||||
<div className="col-md-4">{i18n('DEPARTMENT')}</div>
|
||||
<div className=" col-md-4">{i18n('AUTHOR')}</div>
|
||||
<div className="col-md-4">{i18n('AUTHOR')}</div>
|
||||
<div className="col-md-4">{i18n('DATE')}</div>
|
||||
</div>
|
||||
<div className="ticket-viewer__info-row-values row">
|
||||
|
@ -165,11 +175,7 @@ class TicketViewer extends React.Component {
|
|||
let {ticket, userId} = this.props;
|
||||
|
||||
if (_.isEmpty(ticket.owner) || ticket.owner.id == userId) {
|
||||
ownerNode = (
|
||||
<Button type={(ticket.owner) ? 'primary' : 'secondary'} size="extra-small" onClick={this.onAssignClick.bind(this)}>
|
||||
{i18n(ticket.owner ? 'UN_ASSIGN' : 'ASSIGN_TO_ME')}
|
||||
</Button>
|
||||
);
|
||||
ownerNode = this.renderAssignStaffList();
|
||||
} else {
|
||||
ownerNode = (this.props.ticket.owner) ? this.props.ticket.owner.name : i18n('NONE')
|
||||
}
|
||||
|
@ -193,6 +199,18 @@ class TicketViewer extends React.Component {
|
|||
return ownerNode;
|
||||
}
|
||||
|
||||
renderAssignStaffList() {
|
||||
const items = this.getStaffAssignmentItems();
|
||||
const ownerId = this.props.ticket.owner && this.props.ticket.owner.id;
|
||||
return (
|
||||
<DropDown
|
||||
className="ticket-viewer__editable-dropdown" items={items}
|
||||
selectedIndex={ownerId && _.findIndex(items, {id: ownerId})}
|
||||
onChange={this.onAssignmentChange.bind(this)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
renderTicketEvent(options, index) {
|
||||
return (
|
||||
<TicketEvent {...options} author={(!_.isEmpty(options.author)) ? options.author : this.props.ticket.author} key={index} />
|
||||
|
@ -265,6 +283,23 @@ class TicketViewer extends React.Component {
|
|||
};
|
||||
}
|
||||
|
||||
getStaffAssignmentItems() {
|
||||
const {staffMembers, userId} = this.props;
|
||||
let staffAssignmentItems = [
|
||||
{content: 'None', id: 0},
|
||||
{content: 'Assign to me', id: userId}
|
||||
];
|
||||
|
||||
staffAssignmentItems = staffAssignmentItems.concat(
|
||||
_.map(
|
||||
_.filter(staffMembers, ({id}) => (id != userId)),
|
||||
({id, name}) => ({content: name, id})
|
||||
)
|
||||
);
|
||||
|
||||
return staffAssignmentItems;
|
||||
}
|
||||
|
||||
onDepartmentDropdownChanged(event) {
|
||||
AreYouSure.openModal(null, this.changeDepartment.bind(this, event.index));
|
||||
}
|
||||
|
@ -273,12 +308,17 @@ class TicketViewer extends React.Component {
|
|||
AreYouSure.openModal(null, this.changePriority.bind(this, event.index));
|
||||
}
|
||||
|
||||
onAssignClick() {
|
||||
onAssignmentChange(event) {
|
||||
AreYouSure.openModal(null, this.assingTo.bind(this, event.index));
|
||||
}
|
||||
|
||||
assingTo(index) {
|
||||
const id = this.getStaffAssignmentItems()[index].id;
|
||||
const {ticketNumber} = this.props.ticket;
|
||||
|
||||
API.call({
|
||||
path: (this.props.ticket.owner) ? '/staff/un-assign-ticket' : '/staff/assign-ticket',
|
||||
data: {
|
||||
ticketNumber: this.props.ticket.ticketNumber
|
||||
}
|
||||
path: (index == 0) ? '/staff/un-assign-ticket' : '/staff/assign-ticket',
|
||||
data: { ticketNumber, staffId: id }
|
||||
}).then(this.onTicketModification.bind(this));
|
||||
}
|
||||
|
||||
|
@ -387,6 +427,8 @@ class TicketViewer extends React.Component {
|
|||
export default connect((store) => {
|
||||
return {
|
||||
userId: store.session.userId,
|
||||
staffMembers: store.adminData.staffMembers,
|
||||
staffMembersLoaded: store.adminData.staffMembersLoaded,
|
||||
allowAttachments: store.config['allow-attachments'],
|
||||
userSystemEnabled: store.config['user-system-enabled']
|
||||
};
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
import React from 'react';
|
||||
import {Link} from 'react-router';
|
||||
import _ from 'lodash';
|
||||
import {connect} from 'react-redux';
|
||||
|
||||
import AdminDataActions from 'actions/admin-data-actions';
|
||||
|
||||
import i18n from 'lib-app/i18n';
|
||||
import API from 'lib-app/api-call';
|
||||
|
@ -18,15 +21,23 @@ import Loading from 'core-components/loading';
|
|||
|
||||
class AdminPanelStaffMembers extends React.Component {
|
||||
|
||||
state = {
|
||||
selectedDepartment: 0,
|
||||
static propTypes = {
|
||||
staffList: React.PropTypes.array,
|
||||
loading: React.PropTypes.boolean,
|
||||
}
|
||||
|
||||
static defaultProps = {
|
||||
staffList: [],
|
||||
loading: true,
|
||||
};
|
||||
|
||||
state = {
|
||||
selectedDepartment: 0,
|
||||
page: 1
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this.retrieveStaffMembers();
|
||||
this.props.dispatch(AdminDataActions.retrieveStaffMembers());
|
||||
}
|
||||
|
||||
render() {
|
||||
|
@ -39,7 +50,7 @@ class AdminPanelStaffMembers extends React.Component {
|
|||
<Icon name="user-plus" className=""/> {i18n('ADD_NEW_STAFF')}
|
||||
</Button>
|
||||
</div>
|
||||
{(this.state.loading) ? <Loading backgrounded /> : <PeopleList list={this.getStaffList()} page={this.state.page} onPageSelect={(index) => this.setState({page: index+1})} />}
|
||||
{(this.props.loading) ? <Loading backgrounded /> : <PeopleList list={this.getStaffList()} page={this.state.page} onPageSelect={(index) => this.setState({page: index+1})} />}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -66,9 +77,9 @@ class AdminPanelStaffMembers extends React.Component {
|
|||
let staffList;
|
||||
|
||||
if(!this.state.selectedDepartment) {
|
||||
staffList = this.state.staffList;
|
||||
staffList = this.props.staffList;
|
||||
} else {
|
||||
staffList = _.filter(this.state.staffList, (staff) => {
|
||||
staffList = _.filter(this.props.staffList, (staff) => {
|
||||
return _.findIndex(staff.departments, {id: this.state.selectedDepartment}) !== -1;
|
||||
});
|
||||
}
|
||||
|
@ -96,22 +107,12 @@ class AdminPanelStaffMembers extends React.Component {
|
|||
|
||||
return departments;
|
||||
}
|
||||
|
||||
retrieveStaffMembers() {
|
||||
API.call({
|
||||
path: '/staff/get-all',
|
||||
data: {}
|
||||
}).then(this.onStaffRetrieved.bind(this));
|
||||
}
|
||||
|
||||
onStaffRetrieved(result) {
|
||||
if(result.status == 'success'){
|
||||
this.setState({
|
||||
loading: false,
|
||||
staffList: result.data
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default AdminPanelStaffMembers;
|
||||
export default connect((store) => {
|
||||
return {
|
||||
staffList: store.adminData.staffMembers,
|
||||
loading: !store.adminData.staffMembersLoaded,
|
||||
error: store.adminData.staffMembersError
|
||||
};
|
||||
})(AdminPanelStaffMembers);
|
||||
|
|
|
@ -99,7 +99,7 @@ module.exports = [
|
|||
title: 'Lorem ipsum door',
|
||||
content: 'I had a problem with the installation of the php server',
|
||||
department: {
|
||||
id: 1,
|
||||
id: '1',
|
||||
name: 'Sales Support'
|
||||
},
|
||||
date: '201604151155',
|
||||
|
@ -110,12 +110,12 @@ module.exports = [
|
|||
closed: false,
|
||||
priority: 'medium',
|
||||
author: {
|
||||
id: 3,
|
||||
id: '3',
|
||||
name: 'Haskell Curry',
|
||||
email: 'haskell@lambda.com'
|
||||
},
|
||||
owner: {
|
||||
id: 1,
|
||||
id: '12',
|
||||
name: 'Steve Jobs'
|
||||
},
|
||||
events: [
|
||||
|
|
|
@ -9,6 +9,7 @@ class AdminDataReducer extends Reducer {
|
|||
return {
|
||||
customResponses: [],
|
||||
customResponsesLoaded: false,
|
||||
|
||||
myTickets: [],
|
||||
myTicketsLoaded: false,
|
||||
myTicketsError: false,
|
||||
|
@ -19,7 +20,11 @@ class AdminDataReducer extends Reducer {
|
|||
|
||||
allTickets: [],
|
||||
allTicketsLoaded: false,
|
||||
allTicketsError: false
|
||||
allTicketsError: false,
|
||||
|
||||
staffMembers: [],
|
||||
staffMembersLoaded: false,
|
||||
staffMembersError: false,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -37,7 +42,11 @@ class AdminDataReducer extends Reducer {
|
|||
|
||||
'ALL_TICKETS_FULFILLED': this.onAllTicketsRetrieved,
|
||||
'ALL_TICKETS_REJECTED': this.onAllTicketsRejected,
|
||||
'ALL_TICKETS_PENDING': this.onAllTicketsPending
|
||||
'ALL_TICKETS_PENDING': this.onAllTicketsPending,
|
||||
|
||||
'STAFF_MEMBERS_FULFILLED': this.onStaffMembersRetrieved,
|
||||
'STAFF_MEMBERS_REJECTED': this.onStaffMembersRejected,
|
||||
'STAFF_MEMBERS_PENDING': this.onStaffMembersPending
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -102,7 +111,7 @@ class AdminDataReducer extends Reducer {
|
|||
|
||||
onAllTicketsRejected(state) {
|
||||
return _.extend({}, state, {
|
||||
allTicketsError: false,
|
||||
allTicketsError: true,
|
||||
allTicketsLoaded: false
|
||||
});
|
||||
}
|
||||
|
@ -113,6 +122,27 @@ class AdminDataReducer extends Reducer {
|
|||
allTicketsLoaded: false
|
||||
});
|
||||
}
|
||||
|
||||
onStaffMembersRetrieved(state, payload) {
|
||||
return _.extend({}, state, {
|
||||
staffMembers: payload.data,
|
||||
staffMembersLoaded: true
|
||||
});
|
||||
}
|
||||
|
||||
onStaffMembersRejected(state) {
|
||||
return _.extend({}, state, {
|
||||
staffMembersError: true,
|
||||
staffMembersLoaded: false
|
||||
});
|
||||
}
|
||||
|
||||
onStaffMembersPending(state) {
|
||||
return _.extend({}, state, {
|
||||
staffMembersError: false,
|
||||
staffMembersLoaded: false
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default AdminDataReducer.getInstance();
|
||||
export default AdminDataReducer.getInstance();
|
||||
|
|
|
@ -12,7 +12,7 @@ use Respect\Validation\Validator as DataValidator;
|
|||
* @apiDescription This path retrieves information about all the staff member.
|
||||
*
|
||||
* @apiPermission staff3
|
||||
*
|
||||
*
|
||||
* @apiUse NO_PERMISSION
|
||||
*
|
||||
* @apiSuccess {[Staff](#api-Data_Structures-ObjectStaff)[]} data Array of staff members.
|
||||
|
@ -25,7 +25,7 @@ class GetAllStaffController extends Controller {
|
|||
|
||||
public function validations() {
|
||||
return [
|
||||
'permission' => 'staff_3',
|
||||
'permission' => 'staff_1',
|
||||
'requestData' => []
|
||||
];
|
||||
}
|
||||
|
@ -58,6 +58,6 @@ class GetAllStaffController extends Controller {
|
|||
}
|
||||
|
||||
Response::respondSuccess($staffArray);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue