[DEV-279] Make ticket table show more tickets overview (#1164)
* make ticket table show more tickets overview * allow user to choose ticket quantity * add styles * fix New Tickets section dropdown * add commented changes * correct some code issues
This commit is contained in:
parent
86cad910ec
commit
b3c8819d83
|
@ -12,22 +12,22 @@ export default {
|
|||
};
|
||||
},
|
||||
|
||||
retrieveMyTickets(page, closed = 0, departmentId = 0) {
|
||||
retrieveMyTickets({page, closed = 0, departmentId = 0, pageSize = 10}) {
|
||||
return {
|
||||
type: 'MY_TICKETS',
|
||||
payload: API.call({
|
||||
path: '/staff/get-tickets',
|
||||
data: {page, closed, departmentId}
|
||||
data: {page, closed, departmentId, pageSize}
|
||||
})
|
||||
};
|
||||
},
|
||||
|
||||
retrieveNewTickets(page = 1, departmentId = 0) {
|
||||
retrieveNewTickets({page, departmentId = 0, pageSize = 10}) {
|
||||
return {
|
||||
type: 'NEW_TICKETS',
|
||||
payload: API.call({
|
||||
path: '/staff/get-new-tickets',
|
||||
data: {page, departmentId}
|
||||
data: {page, departmentId, pageSize}
|
||||
})
|
||||
};
|
||||
},
|
||||
|
|
|
@ -9,14 +9,15 @@ export default {
|
|||
payload: {}
|
||||
}
|
||||
},
|
||||
retrieveSearchTickets(ticketQueryListState, filters = {}) {
|
||||
retrieveSearchTickets(ticketQueryListState, filters = {}, pageSize = 10) {
|
||||
return {
|
||||
type: 'SEARCH_TICKETS',
|
||||
payload: API.call({
|
||||
path: '/ticket/search',
|
||||
data: {
|
||||
...filters,
|
||||
page: ticketQueryListState.page
|
||||
page: ticketQueryListState.page,
|
||||
pageSize
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
import React from 'react';
|
||||
|
||||
import DropDown from 'core-components/drop-down';
|
||||
import i18n from 'lib-app/i18n';
|
||||
|
||||
class PageSizeDropdown extends React.Component {
|
||||
static propTypes = {
|
||||
value: React.PropTypes.number,
|
||||
onChange: React.PropTypes.func,
|
||||
pages: React.PropTypes.array
|
||||
}
|
||||
|
||||
state = {
|
||||
selectedIndex: 1
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<DropDown {...this.props} onChange={this.onChange.bind(this)} items={this.getPages()} selectedIndex={this.state.selectedIndex} />
|
||||
)
|
||||
}
|
||||
|
||||
getPages() {
|
||||
return this.props.pages.map((page) => {
|
||||
return {content: `${page} / ${i18n('TICKETS')}`}
|
||||
});
|
||||
}
|
||||
|
||||
onChange(event) {
|
||||
this.setState({
|
||||
selectedIndex: event.index
|
||||
})
|
||||
if(this.props.onChange) {
|
||||
this.props.onChange({
|
||||
pageSize: this.props.pages[event.index]
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default PageSizeDropdown;
|
|
@ -16,6 +16,7 @@ import Tag from 'core-components/tag';
|
|||
import Icon from 'core-components/icon';
|
||||
import Message from 'core-components/message';
|
||||
import history from 'lib-app/history';
|
||||
import PageSizeDropdown from './page-size-dropdown';
|
||||
|
||||
class TicketList extends React.Component {
|
||||
static propTypes = {
|
||||
|
@ -31,7 +32,8 @@ class TicketList extends React.Component {
|
|||
]),
|
||||
closedTicketsShown: React.PropTypes.bool,
|
||||
onClosedTicketsShownChange: React.PropTypes.func,
|
||||
onDepartmentChange: React.PropTypes.func
|
||||
onDepartmentChange: React.PropTypes.func,
|
||||
showPageSizeDropdown: React.PropTypes.bool
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
|
@ -41,7 +43,8 @@ class TicketList extends React.Component {
|
|||
departments: [],
|
||||
ticketPath: '/dashboard/ticket/',
|
||||
type: 'primary',
|
||||
closedTicketsShown: false
|
||||
closedTicketsShown: false,
|
||||
showPageSizeDropdown: true
|
||||
};
|
||||
|
||||
state = {
|
||||
|
@ -49,25 +52,32 @@ class TicketList extends React.Component {
|
|||
};
|
||||
|
||||
render() {
|
||||
const { type, showDepartmentDropdown, onClosedTicketsShownChange } = this.props;
|
||||
const { type, showDepartmentDropdown, onClosedTicketsShownChange, showPageSizeDropdown } = this.props;
|
||||
const pages = [5, 10, 20, 50];
|
||||
|
||||
return (
|
||||
<div className="ticket-list">
|
||||
<div className="ticket-list__filters">
|
||||
{(type === 'primary') ? this.renderMessage() : null}
|
||||
<div className="ticket-list__main-filters">
|
||||
{(type === 'primary') ? this.renderMessage() : null}
|
||||
{
|
||||
((type === 'secondary') && showDepartmentDropdown) ?
|
||||
this.renderDepartmentsDropDown() :
|
||||
null
|
||||
}
|
||||
{onClosedTicketsShownChange ? this.renderFilterCheckbox() : null}
|
||||
</div>
|
||||
{
|
||||
((type === 'secondary') && showDepartmentDropdown) ?
|
||||
this.renderDepartmentsDropDown() :
|
||||
showPageSizeDropdown ?
|
||||
<PageSizeDropdown className="ticket-list__page-dropdown" pages={pages} onChange={(event) => this.pageSizeChange(event)} /> :
|
||||
null
|
||||
}
|
||||
{onClosedTicketsShownChange ? this.renderFilterCheckbox() : null}
|
||||
</div>
|
||||
<Table {...this.getTableProps()} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
renderFilterCheckbox() {
|
||||
return (
|
||||
<Checkbox
|
||||
|
@ -113,6 +123,12 @@ class TicketList extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
pageSizeChange(event) {
|
||||
const { onPageSizeChange } = this.props;
|
||||
|
||||
onPageSizeChange && onPageSizeChange(event.pageSize);
|
||||
}
|
||||
|
||||
getDepartmentDropdownProps() {
|
||||
const { departments, onDepartmentChange } = this.props;
|
||||
|
||||
|
@ -138,7 +154,7 @@ class TicketList extends React.Component {
|
|||
loading,
|
||||
headers: this.getTableHeaders(),
|
||||
rows: this.getTableRows(),
|
||||
pageSize: 10,
|
||||
pageSize: this.state.tickets,
|
||||
page,
|
||||
pages,
|
||||
onPageChange
|
||||
|
|
|
@ -7,16 +7,30 @@
|
|||
}
|
||||
|
||||
&__filters {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 25px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
&__main-filters {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&__department-selector {
|
||||
display: inline-block;
|
||||
margin-right: 25px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
&__page-dropdown {
|
||||
display: inline-block;
|
||||
margin-right: 25px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
&__checkbox {
|
||||
display: inline-block;
|
||||
}
|
||||
|
|
|
@ -8,6 +8,8 @@ import TicketList from 'app-components/ticket-list';
|
|||
import Message from 'core-components/message';
|
||||
import searchFiltersActions from '../actions/search-filters-actions';
|
||||
import queryString from 'query-string';
|
||||
import searchTicketsUtils from 'lib-app/search-tickets-utils';
|
||||
import history from 'lib-app/history';
|
||||
|
||||
class TicketQueryList extends React.Component {
|
||||
|
||||
|
@ -65,6 +67,7 @@ class TicketQueryList extends React.Component {
|
|||
orderBy: filters.orderBy ? JSON.parse(filters.orderBy) : filters.orderBy,
|
||||
showOrderArrows: true,
|
||||
onChangeOrderBy: onChangeOrderBy,
|
||||
showPageSizeDropdown: false
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -26,10 +26,11 @@ class AdminPanelMyTickets extends React.Component {
|
|||
state = {
|
||||
closedTicketsShown: false,
|
||||
departmentId: null,
|
||||
pageSize: 10
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this.retrieveMyTickets();
|
||||
this.retrieveMyTickets({});
|
||||
}
|
||||
|
||||
render() {
|
||||
|
@ -68,10 +69,14 @@ class AdminPanelMyTickets extends React.Component {
|
|||
onClosedTicketsShownChange: this.onClosedTicketsShownChange.bind(this),
|
||||
pages,
|
||||
page,
|
||||
onPageChange: event => this.retrieveMyTickets(event.target.value),
|
||||
onPageChange: event => this.retrieveMyTickets({page: event.target.value}),
|
||||
onDepartmentChange: departmentId => {
|
||||
this.setState({departmentId});
|
||||
this.retrieveMyTickets(1, closedTicketsShown, departmentId);
|
||||
this.setState({departmentId})
|
||||
this.retrieveMyTickets({page: 1, departmentId});
|
||||
},
|
||||
onPageSizeChange: pageSize => {
|
||||
this.setState({pageSize});
|
||||
this.retrieveMyTickets({page: 1, pageSize});
|
||||
},
|
||||
};
|
||||
}
|
||||
|
@ -81,7 +86,7 @@ class AdminPanelMyTickets extends React.Component {
|
|||
return {
|
||||
closedTicketsShown: !state.closedTicketsShown
|
||||
};
|
||||
}, () => this.retrieveMyTickets());
|
||||
}, () => this.retrieveMyTickets({}));
|
||||
}
|
||||
|
||||
onCreateTicket() {
|
||||
|
@ -100,11 +105,11 @@ class AdminPanelMyTickets extends React.Component {
|
|||
|
||||
onCreateTicketSuccess() {
|
||||
ModalContainer.closeModal();
|
||||
this.retrieveMyTickets();
|
||||
this.retrieveMyTickets({});
|
||||
}
|
||||
|
||||
retrieveMyTickets(page = this.props.page, closed = this.state.closedTicketsShown, departmentId = this.state.departmentId) {
|
||||
this.props.dispatch(AdminDataAction.retrieveMyTickets(page, closed * 1, departmentId));
|
||||
retrieveMyTickets({page = this.props.page, closed = this.state.closedTicketsShown, departmentId = this.state.departmentId, pageSize = this.state.pageSize}) {
|
||||
this.props.dispatch(AdminDataAction.retrieveMyTickets({page, closed: closed * 1, departmentId, pageSize}));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,10 +20,11 @@ class AdminPanelNewTickets extends React.Component {
|
|||
|
||||
state = {
|
||||
departmentId: null,
|
||||
pageSize: 10
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this.retrieveNewTickets();
|
||||
this.retrieveNewTickets({});
|
||||
}
|
||||
|
||||
render() {
|
||||
|
@ -32,7 +33,7 @@ class AdminPanelNewTickets extends React.Component {
|
|||
<div className="admin-panel-new-tickets">
|
||||
<Header title={i18n('NEW_TICKETS')} description={i18n('NEW_TICKETS_DESCRIPTION')} />
|
||||
{(noDepartments) ? <Message showCloseButton={false} className="admin-panel-new-tickets__department-warning" type="warning">{i18n('NO_DEPARTMENT_ASSIGNED')}</Message> : null}
|
||||
{(this.props.error) ? <Message showCloseButton={false} type="error">{i18n('ERROR_RETRIEVING_TICKETS')}</Message> : <TicketList {...this.getProps()}/>}
|
||||
{(this.props.error) ? <Message showCloseButton={false} type="error">{i18n('ERROR_RETRIEVING_TICKETS')}</Message> : <TicketList {...this.getProps()} />}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -47,16 +48,20 @@ class AdminPanelNewTickets extends React.Component {
|
|||
ticketPath: '/admin/panel/tickets/view-ticket/',
|
||||
page: this.props.page,
|
||||
pages: this.props.pages,
|
||||
onPageChange: event => this.retrieveNewTickets(event.target.value),
|
||||
onPageChange: event => this.retrieveNewTickets({page: event.target.value}),
|
||||
onDepartmentChange: departmentId => {
|
||||
this.setState({departmentId});
|
||||
this.retrieveNewTickets(1, departmentId);
|
||||
this.retrieveNewTickets({page: 1, departmentId});
|
||||
},
|
||||
onPageSizeChange: pageSize => {
|
||||
this.setState({pageSize});
|
||||
this.retrieveNewTickets({page: 1, pageSize});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
retrieveNewTickets(page = this.props.page, departmentId = this.state.departmentId) {
|
||||
this.props.dispatch(AdminDataAction.retrieveNewTickets(page, departmentId));
|
||||
retrieveNewTickets({page = this.props.page, departmentId = this.state.departmentId, pageSize = this.state.pageSize }) {
|
||||
this.props.dispatch(AdminDataAction.retrieveNewTickets({page, departmentId, pageSize}));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -38,7 +38,8 @@ export function updateSearchTicketsFromURL() {
|
|||
...store.getState().searchFilters.ticketQueryListState,
|
||||
page: (currentSearchParams.page || INITIAL_PAGE)*1
|
||||
},
|
||||
searchTicketsUtils.prepareFiltersForAPI(listConfig.filters)
|
||||
searchTicketsUtils.prepareFiltersForAPI(listConfig.filters),
|
||||
currentSearchParams.pageSize
|
||||
));
|
||||
});
|
||||
}
|
||||
|
|
|
@ -411,6 +411,7 @@ export default {
|
|||
'INVALID_SUPERVISED_USERS': 'Invalid supervised users',
|
||||
'SUPERVISOR_CAN_NOT_SUPERVISE_HIMSELF': 'Supervisor can not supervise himself',
|
||||
'NAME_ALREADY_USED': 'Name already used',
|
||||
'PAGESIZE_ERROR': 'Invalid page size',
|
||||
|
||||
//MESSAGES
|
||||
'SIGNUP_SUCCESS': 'You have registered successfully in our support system.',
|
||||
|
|
|
@ -38,6 +38,10 @@ class GetNewTicketsStaffController extends Controller {
|
|||
'page' => [
|
||||
'validation' => DataValidator::numeric(),
|
||||
'error' => ERRORS::INVALID_PAGE
|
||||
],
|
||||
'pageSize' => [
|
||||
'validation' => DataValidator::intVal()->between(5, 50),
|
||||
'error' => ERRORS::PAGESIZE_ERROR
|
||||
]
|
||||
]
|
||||
];
|
||||
|
@ -45,6 +49,7 @@ class GetNewTicketsStaffController extends Controller {
|
|||
public function handler() {
|
||||
$page = Controller::request('page');
|
||||
$departmentId = Controller::request('departmentId');
|
||||
$pageSize = Controller::request('pageSize');
|
||||
|
||||
if (Ticket::isTableEmpty()) {
|
||||
Response::respondSuccess([
|
||||
|
@ -77,14 +82,14 @@ class GetNewTicketsStaffController extends Controller {
|
|||
$countTotal = Ticket::count($query);
|
||||
|
||||
$query .= ' ORDER BY unread_staff DESC';
|
||||
$query .= ' LIMIT 10 OFFSET ' . ($page-1)*10;
|
||||
$query .= ' LIMIT ' . $pageSize . ' OFFSET ' . ($page-1)*10;
|
||||
|
||||
$ticketList = Ticket::find($query);
|
||||
|
||||
Response::respondSuccess([
|
||||
'tickets' => $ticketList->toArray(true),
|
||||
'page' => $page,
|
||||
'pages' => ceil($countTotal / 10)
|
||||
'pages' => ceil($countTotal / $pageSize)
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,6 +38,10 @@ class GetTicketStaffController extends Controller {
|
|||
'page' => [
|
||||
'validation' => DataValidator::numeric(),
|
||||
'error' => ERRORS::INVALID_PAGE
|
||||
],
|
||||
'pageSize' => [
|
||||
'validation' => DataValidator::intVal()->between(5, 50),
|
||||
'error' => ERRORS::PAGESIZE_ERROR
|
||||
]
|
||||
]
|
||||
];
|
||||
|
@ -48,7 +52,8 @@ class GetTicketStaffController extends Controller {
|
|||
$closed = Controller::request('closed');
|
||||
$page = Controller::request('page');
|
||||
$departmentId = Controller::request('departmentId');
|
||||
$offset = ($page-1)*10;
|
||||
$pageSize = Controller::request('pageSize');
|
||||
$offset = ($page-1)*$pageSize;
|
||||
|
||||
$condition = 'TRUE';
|
||||
$bindings = [];
|
||||
|
@ -65,7 +70,7 @@ class GetTicketStaffController extends Controller {
|
|||
|
||||
$countTotal = $user->withCondition($condition, $bindings)->countShared('ticket');
|
||||
|
||||
$condition .= ' LIMIT 10 OFFSET ?';
|
||||
$condition .= ' LIMIT ' . $pageSize . ' OFFSET ?';
|
||||
$bindings[] = $offset;
|
||||
|
||||
$tickets = $user->withCondition($condition, $bindings)->sharedTicketList->toArray(true);
|
||||
|
@ -73,7 +78,7 @@ class GetTicketStaffController extends Controller {
|
|||
Response::respondSuccess([
|
||||
'tickets' => $tickets,
|
||||
'page' => $page,
|
||||
'pages' => ceil($countTotal / 10)
|
||||
'pages' => ceil($countTotal / $pageSize)
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -99,6 +99,10 @@ class SearchController extends Controller {
|
|||
'validation' => DataValidator::oneOf(DataValidator::validOrderBy(),DataValidator::nullType()),
|
||||
'error' => ERRORS::INVALID_ORDER_BY
|
||||
],
|
||||
'pageSize' => [
|
||||
'validation' => DataValidator::intVal()->between(5, 50),
|
||||
'error' => ERRORS::PAGESIZE_ERROR
|
||||
]
|
||||
]
|
||||
];
|
||||
}
|
||||
|
@ -124,7 +128,8 @@ class SearchController extends Controller {
|
|||
'orderBy' => json_decode(Controller::request('orderBy'),true),
|
||||
'page' => Controller::request('page'),
|
||||
'allowedDepartments' => $allowedDepartmentsId,
|
||||
'staffId' => Controller::getLoggedUser()->id
|
||||
'staffId' => Controller::getLoggedUser()->id,
|
||||
'pageSize' => Controller::request('pageSize')
|
||||
];
|
||||
$query = $this->getSQLQuery($inputs);
|
||||
$queryWithOrder = $this->getSQLQueryWithOrder($inputs, $query);
|
||||
|
@ -137,7 +142,7 @@ class SearchController extends Controller {
|
|||
}
|
||||
Response::respondSuccess([
|
||||
'tickets' => $ticketList,
|
||||
'pages' => ceil($totalCount / 10),
|
||||
'pages' => ceil($totalCount / $inputs['pageSize']),
|
||||
'page' => $inputs['page'] ? ($inputs['page']*1) : 1
|
||||
]);
|
||||
}
|
||||
|
@ -154,12 +159,14 @@ class SearchController extends Controller {
|
|||
}
|
||||
|
||||
public function getSQLQueryWithOrder($inputs, $query) {
|
||||
$pageSize = $inputs['pageSize'];
|
||||
$order = "";
|
||||
$query = "SELECT ticket.id " . $query;
|
||||
|
||||
$this->setQueryOrder($inputs, $order);
|
||||
$inputs['page'] ? $page = $inputs['page'] : $page = 1 ;
|
||||
$query .= $order ." LIMIT 10 OFFSET " . (($page-1)*10);
|
||||
$query .= $order . ' LIMIT ' . $pageSize . ' OFFSET ' . ($page-1)*10;
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
|
|
|
@ -415,4 +415,5 @@ class ERRORS {
|
|||
const INVALID_SUPERVISED_USERS = 'INVALID_SUPERVISED_USERS';
|
||||
const INVALID_USER_SEARCH_OPTION = 'INVALID_USER_SEARCH_OPTION';
|
||||
const TICKET_CONTENT_CANNOT_BE_EDITED = 'TICKET_CONTENT_CANNOT_BE_EDITED';
|
||||
const PAGESIZE_ERROR = 'PAGESIZE_ERROR';
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue