Add staff dropdown for assignment

This commit is contained in:
Ivan Diaz 2018-07-27 20:36:35 -03:00
parent 99ea7e0f8a
commit dda8e28e93
6 changed files with 131 additions and 48 deletions

View File

@ -1,7 +1,7 @@
import API from 'lib-app/api-call'; import API from 'lib-app/api-call';
export default { export default {
retrieveCustomResponses() { retrieveCustomResponses() {
return { return {
type: 'CUSTOM_RESPONSES', 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) { searchTickets(query, page = 1) {
return { return {
type: 'ALL_TICKETS', type: 'ALL_TICKETS',
@ -51,4 +61,4 @@ export default {
}) })
}; };
} }
}; };

View File

@ -2,6 +2,8 @@ import React from 'react';
import _ from 'lodash'; import _ from 'lodash';
import {connect} from 'react-redux'; import {connect} from 'react-redux';
import AdminDataActions from 'actions/admin-data-actions';
import i18n from 'lib-app/i18n'; import i18n from 'lib-app/i18n';
import API from 'lib-app/api-call'; import API from 'lib-app/api-call';
import SessionStore from 'lib-app/session-store'; import SessionStore from 'lib-app/session-store';
@ -24,7 +26,9 @@ class TicketViewer extends React.Component {
onChange: React.PropTypes.func, onChange: React.PropTypes.func,
editable: React.PropTypes.bool, editable: React.PropTypes.bool,
customResponses: React.PropTypes.array, customResponses: React.PropTypes.array,
assignmentAllowed: React.PropTypes.bool assignmentAllowed: React.PropTypes.bool,
staffMembers: React.PropTypes.array,
staffMembersLoaded: React.PropTypes.bool,
}; };
static defaultProps = { static defaultProps = {
@ -42,6 +46,12 @@ class TicketViewer extends React.Component {
commentEdited: false commentEdited: false
}; };
componentDidMount() {
if(!this.props.staffMembersLoaded && this.props.editable) {
this.props.dispatch(AdminDataActions.retrieveStaffMembers());
}
}
render() { render() {
const ticket = this.props.ticket; const ticket = this.props.ticket;
@ -84,7 +94,7 @@ class TicketViewer extends React.Component {
<div className="ticket-viewer__headers"> <div className="ticket-viewer__headers">
<div className="ticket-viewer__info-row-header row"> <div className="ticket-viewer__info-row-header row">
<div className="col-md-4">{i18n('DEPARTMENT')}</div> <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 className="col-md-4">{i18n('DATE')}</div>
</div> </div>
<div className="ticket-viewer__info-row-values row"> <div className="ticket-viewer__info-row-values row">
@ -165,11 +175,7 @@ class TicketViewer extends React.Component {
let {ticket, userId} = this.props; let {ticket, userId} = this.props;
if (_.isEmpty(ticket.owner) || ticket.owner.id == userId) { if (_.isEmpty(ticket.owner) || ticket.owner.id == userId) {
ownerNode = ( ownerNode = this.renderAssignStaffList();
<Button type={(ticket.owner) ? 'primary' : 'secondary'} size="extra-small" onClick={this.onAssignClick.bind(this)}>
{i18n(ticket.owner ? 'UN_ASSIGN' : 'ASSIGN_TO_ME')}
</Button>
);
} else { } else {
ownerNode = (this.props.ticket.owner) ? this.props.ticket.owner.name : i18n('NONE') ownerNode = (this.props.ticket.owner) ? this.props.ticket.owner.name : i18n('NONE')
} }
@ -193,6 +199,18 @@ class TicketViewer extends React.Component {
return ownerNode; 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) { renderTicketEvent(options, index) {
return ( return (
<TicketEvent {...options} author={(!_.isEmpty(options.author)) ? options.author : this.props.ticket.author} key={index} /> <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) { onDepartmentDropdownChanged(event) {
AreYouSure.openModal(null, this.changeDepartment.bind(this, event.index)); 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)); 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({ API.call({
path: (this.props.ticket.owner) ? '/staff/un-assign-ticket' : '/staff/assign-ticket', path: (index == 0) ? '/staff/un-assign-ticket' : '/staff/assign-ticket',
data: { data: { ticketNumber, staffId: id }
ticketNumber: this.props.ticket.ticketNumber
}
}).then(this.onTicketModification.bind(this)); }).then(this.onTicketModification.bind(this));
} }
@ -387,6 +427,8 @@ class TicketViewer extends React.Component {
export default connect((store) => { export default connect((store) => {
return { return {
userId: store.session.userId, userId: store.session.userId,
staffMembers: store.adminData.staffMembers,
staffMembersLoaded: store.adminData.staffMembersLoaded,
allowAttachments: store.config['allow-attachments'], allowAttachments: store.config['allow-attachments'],
userSystemEnabled: store.config['user-system-enabled'] userSystemEnabled: store.config['user-system-enabled']
}; };

View File

@ -1,6 +1,9 @@
import React from 'react'; import React from 'react';
import {Link} from 'react-router'; import {Link} from 'react-router';
import _ from 'lodash'; import _ from 'lodash';
import {connect} from 'react-redux';
import AdminDataActions from 'actions/admin-data-actions';
import i18n from 'lib-app/i18n'; import i18n from 'lib-app/i18n';
import API from 'lib-app/api-call'; import API from 'lib-app/api-call';
@ -18,15 +21,23 @@ import Loading from 'core-components/loading';
class AdminPanelStaffMembers extends React.Component { class AdminPanelStaffMembers extends React.Component {
state = { static propTypes = {
selectedDepartment: 0, staffList: React.PropTypes.array,
loading: React.PropTypes.boolean,
}
static defaultProps = {
staffList: [], staffList: [],
loading: true, loading: true,
};
state = {
selectedDepartment: 0,
page: 1 page: 1
}; };
componentDidMount() { componentDidMount() {
this.retrieveStaffMembers(); this.props.dispatch(AdminDataActions.retrieveStaffMembers());
} }
render() { render() {
@ -39,7 +50,7 @@ class AdminPanelStaffMembers extends React.Component {
<Icon name="user-plus" className=""/> {i18n('ADD_NEW_STAFF')} <Icon name="user-plus" className=""/> {i18n('ADD_NEW_STAFF')}
</Button> </Button>
</div> </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> </div>
); );
} }
@ -66,9 +77,9 @@ class AdminPanelStaffMembers extends React.Component {
let staffList; let staffList;
if(!this.state.selectedDepartment) { if(!this.state.selectedDepartment) {
staffList = this.state.staffList; staffList = this.props.staffList;
} else { } else {
staffList = _.filter(this.state.staffList, (staff) => { staffList = _.filter(this.props.staffList, (staff) => {
return _.findIndex(staff.departments, {id: this.state.selectedDepartment}) !== -1; return _.findIndex(staff.departments, {id: this.state.selectedDepartment}) !== -1;
}); });
} }
@ -96,22 +107,12 @@ class AdminPanelStaffMembers extends React.Component {
return departments; 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);

View File

@ -99,7 +99,7 @@ module.exports = [
title: 'Lorem ipsum door', title: 'Lorem ipsum door',
content: 'I had a problem with the installation of the php server', content: 'I had a problem with the installation of the php server',
department: { department: {
id: 1, id: '1',
name: 'Sales Support' name: 'Sales Support'
}, },
date: '201604151155', date: '201604151155',
@ -110,12 +110,12 @@ module.exports = [
closed: false, closed: false,
priority: 'medium', priority: 'medium',
author: { author: {
id: 3, id: '3',
name: 'Haskell Curry', name: 'Haskell Curry',
email: 'haskell@lambda.com' email: 'haskell@lambda.com'
}, },
owner: { owner: {
id: 1, id: '12',
name: 'Steve Jobs' name: 'Steve Jobs'
}, },
events: [ events: [

View File

@ -9,6 +9,7 @@ class AdminDataReducer extends Reducer {
return { return {
customResponses: [], customResponses: [],
customResponsesLoaded: false, customResponsesLoaded: false,
myTickets: [], myTickets: [],
myTicketsLoaded: false, myTicketsLoaded: false,
myTicketsError: false, myTicketsError: false,
@ -19,7 +20,11 @@ class AdminDataReducer extends Reducer {
allTickets: [], allTickets: [],
allTicketsLoaded: false, 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_FULFILLED': this.onAllTicketsRetrieved,
'ALL_TICKETS_REJECTED': this.onAllTicketsRejected, '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) { onAllTicketsRejected(state) {
return _.extend({}, state, { return _.extend({}, state, {
allTicketsError: false, allTicketsError: true,
allTicketsLoaded: false allTicketsLoaded: false
}); });
} }
@ -113,6 +122,27 @@ class AdminDataReducer extends Reducer {
allTicketsLoaded: false 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();

View File

@ -12,7 +12,7 @@ use Respect\Validation\Validator as DataValidator;
* @apiDescription This path retrieves information about all the staff member. * @apiDescription This path retrieves information about all the staff member.
* *
* @apiPermission staff3 * @apiPermission staff3
* *
* @apiUse NO_PERMISSION * @apiUse NO_PERMISSION
* *
* @apiSuccess {[Staff](#api-Data_Structures-ObjectStaff)[]} data Array of staff members. * @apiSuccess {[Staff](#api-Data_Structures-ObjectStaff)[]} data Array of staff members.
@ -25,7 +25,7 @@ class GetAllStaffController extends Controller {
public function validations() { public function validations() {
return [ return [
'permission' => 'staff_3', 'permission' => 'staff_1',
'requestData' => [] 'requestData' => []
]; ];
} }
@ -58,6 +58,6 @@ class GetAllStaffController extends Controller {
} }
Response::respondSuccess($staffArray); Response::respondSuccess($staffArray);
} }
} }