mirror of
https://github.com/opensupports/opensupports.git
synced 2025-07-31 01:35:15 +02:00
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';
|
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 {
|
|||||||
})
|
})
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -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']
|
||||||
};
|
};
|
||||||
|
@ -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);
|
||||||
|
@ -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: [
|
||||||
|
@ -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();
|
||||||
|
@ -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);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user