Paginate all ticket list request, avoid returting too much data

This commit is contained in:
Ivan Diaz 2018-11-15 20:33:08 -03:00
parent 5f0996f243
commit e8848d898e
12 changed files with 135 additions and 50 deletions

View File

@ -12,22 +12,22 @@ export default {
}; };
}, },
retrieveMyTickets(closed = 0) { retrieveMyTickets(page, closed = 0) {
return { return {
type: 'MY_TICKETS', type: 'MY_TICKETS',
payload: API.call({ payload: API.call({
path: '/staff/get-tickets', path: '/staff/get-tickets',
data: {closed} data: {page, closed}
}) })
}; };
}, },
retrieveNewTickets() { retrieveNewTickets(page = 1) {
return { return {
type: 'NEW_TICKETS', type: 'NEW_TICKETS',
payload: API.call({ payload: API.call({
path: '/staff/get-new-tickets', path: '/staff/get-new-tickets',
data: {} data: {page}
}) })
}; };
}, },

View File

@ -21,7 +21,7 @@ class AdminPanelAllTickets extends React.Component {
state = { state = {
page: 1, page: 1,
query: '', query: '',
closedTicketsShown: false closedTicketsShown: 0
}; };
componentDidMount() { componentDidMount() {
@ -46,7 +46,7 @@ class AdminPanelAllTickets extends React.Component {
this.props.dispatch(AdminDataAction.retrieveAllTickets( this.props.dispatch(AdminDataAction.retrieveAllTickets(
this.state.page, this.state.page,
this.state.query, this.state.query,
this.state.closedTicketsShown*1 this.state.closedTicketsShown * 1
)); ));
} }
@ -63,7 +63,7 @@ class AdminPanelAllTickets extends React.Component {
page: this.state.page, page: this.state.page,
pages: this.props.pages, pages: this.props.pages,
closedTicketsShown: this.state.closedTicketsShown, closedTicketsShown: this.state.closedTicketsShown,
onClosedTicketsShownChange: this.onClosedTicketsShownChange.bind(this) onClosedTicketsShownChange: this.onClosedTicketsShownChange.bind(this)
}; };
} }

View File

@ -18,15 +18,17 @@ class AdminPanelMyTickets extends React.Component {
static defaultProps = { static defaultProps = {
userId: 0, userId: 0,
departments: [], departments: [],
tickets: [] tickets: [],
page: 1,
pages: 0,
}; };
state = { state = {
closedTicketsShown: false closedTicketsShown: false,
}; };
componentDidMount() { componentDidMount() {
this.props.dispatch(AdminDataAction.retrieveMyTickets()); this.retrieveMyTickets()
} }
render() { render() {
@ -52,7 +54,10 @@ class AdminPanelMyTickets extends React.Component {
loading: this.props.loading, loading: this.props.loading,
ticketPath: '/admin/panel/tickets/view-ticket/', ticketPath: '/admin/panel/tickets/view-ticket/',
closedTicketsShown: this.state.closedTicketsShown, closedTicketsShown: this.state.closedTicketsShown,
onClosedTicketsShownChange: this.onClosedTicketsShownChange.bind(this) onClosedTicketsShownChange: this.onClosedTicketsShownChange.bind(this),
pages: this.props.pages,
page: this.props.page,
onPageChange: event => this.retrieveMyTickets(event.target.value)
}; };
} }
@ -61,9 +66,7 @@ class AdminPanelMyTickets extends React.Component {
return { return {
closedTicketsShown: !state.closedTicketsShown closedTicketsShown: !state.closedTicketsShown
}; };
}, () => { }, () => this.retrieveMyTickets());
this.props.dispatch(AdminDataAction.retrieveMyTickets(this.state.closedTicketsShown * 1));
});
} }
onCreateTicket() { onCreateTicket() {
@ -79,7 +82,11 @@ class AdminPanelMyTickets extends React.Component {
onCreateTicketSuccess() { onCreateTicketSuccess() {
ModalContainer.closeModal(); ModalContainer.closeModal();
this.props.dispatch(AdminDataAction.retrieveMyTickets()); this.retrieveMyTickets();
}
retrieveMyTickets(page = this.props.page, closed = this.state.closedTicketsShown) {
this.props.dispatch(AdminDataAction.retrieveMyTickets(page, closed * 1));
} }
} }
@ -88,6 +95,8 @@ export default connect((store) => {
userId: store.session.userId, userId: store.session.userId,
departments: store.session.userDepartments, departments: store.session.userDepartments,
tickets: store.adminData.myTickets, tickets: store.adminData.myTickets,
page: store.adminData.myTicketsPage,
pages: store.adminData.myTicketsPages,
loading: !store.adminData.myTicketsLoaded, loading: !store.adminData.myTicketsLoaded,
error: store.adminData.myTicketsError error: store.adminData.myTicketsError
}; };

View File

@ -18,7 +18,7 @@ class AdminPanelNewTickets extends React.Component {
}; };
componentDidMount() { componentDidMount() {
this.props.dispatch(AdminDataAction.retrieveNewTickets()); this.retrieveNewTickets()
} }
render() { render() {
@ -39,9 +39,16 @@ class AdminPanelNewTickets extends React.Component {
tickets: this.props.tickets, tickets: this.props.tickets,
type: 'secondary', type: 'secondary',
loading: this.props.loading, loading: this.props.loading,
ticketPath: '/admin/panel/tickets/view-ticket/' ticketPath: '/admin/panel/tickets/view-ticket/',
page: this.props.page,
pages: this.props.pages,
onPageChange: event => this.retrieveNewTickets(event.target.value)
}; };
} }
retrieveNewTickets(page = this.props.page) {
this.props.dispatch(AdminDataAction.retrieveNewTickets(page));
}
} }
export default connect((store) => { export default connect((store) => {
@ -49,6 +56,8 @@ export default connect((store) => {
userId: store.session.userId, userId: store.session.userId,
departments: store.session.userDepartments, departments: store.session.userDepartments,
tickets: store.adminData.newTickets, tickets: store.adminData.newTickets,
page: store.adminData.newTicketsPage,
pages: store.adminData.newTicketsPages,
loading: !store.adminData.newTicketsLoaded, loading: !store.adminData.newTicketsLoaded,
error: store.adminData.newTicketsError error: store.adminData.newTicketsError
}; };

View File

@ -11,14 +11,20 @@ class AdminDataReducer extends Reducer {
customResponsesLoaded: false, customResponsesLoaded: false,
myTickets: [], myTickets: [],
myTicketsPage: 1,
myTicketsPages: 1,
myTicketsLoaded: false, myTicketsLoaded: false,
myTicketsError: false, myTicketsError: false,
newTickets: [], newTickets: [],
newTicketsPage: 1,
newTicketsPages: 1,
newTicketsLoaded: false, newTicketsLoaded: false,
newTicketsError: false, newTicketsError: false,
allTickets: [], allTickets: [],
allTicketsPage: 1,
allTicketsPages: 1,
allTicketsLoaded: false, allTicketsLoaded: false,
allTicketsError: false, allTicketsError: false,
@ -61,7 +67,9 @@ class AdminDataReducer extends Reducer {
onMyTicketsRetrieved(state, payload) { onMyTicketsRetrieved(state, payload) {
return _.extend({}, state, { return _.extend({}, state, {
myTickets: payload.data, myTickets: payload.data.tickets,
myTicketsPage: payload.data.page * 1,
myTicketsPages: payload.data.pages * 1,
myTicketsLoaded: true myTicketsLoaded: true
}); });
} }
@ -82,7 +90,9 @@ class AdminDataReducer extends Reducer {
onNewTicketsRetrieved(state, payload) { onNewTicketsRetrieved(state, payload) {
return _.extend({}, state, { return _.extend({}, state, {
newTickets: payload.data, newTickets: payload.data.tickets,
newTicketsPage: payload.data.page * 1,
newTicketsPages: payload.data.pages * 1,
newTicketsLoaded: true newTicketsLoaded: true
}); });
} }
@ -104,7 +114,8 @@ class AdminDataReducer extends Reducer {
onAllTicketsRetrieved(state, payload) { onAllTicketsRetrieved(state, payload) {
return _.extend({}, state, { return _.extend({}, state, {
allTickets: payload.data.tickets, allTickets: payload.data.tickets,
allTicketsPages: payload.data.pages, allTicketsPage: payload.data.page * 1,
allTicketsPages: payload.data.pages * 1,
allTicketsLoaded: true allTicketsLoaded: true
}); });
} }

View File

@ -52,7 +52,7 @@ class GetAllTicketsStaffController extends Controller {
} }
Response::respondSuccess([ Response::respondSuccess([
'tickets' => $this->getTicketList()->toArray(), 'tickets' => $this->getTicketList()->toArray(true),
'pages' => $this->getTotalPages() 'pages' => $this->getTotalPages()
]); ]);
} }
@ -81,9 +81,14 @@ class GetAllTicketsStaffController extends Controller {
} }
private function getTotalPages() { private function getTotalPages() {
$query = $this->getStaffDepartmentsQueryFilter(); $query = $this->getSearchQuery();
$query .= $this->getStaffDepartmentsQueryFilter();
$query .= $this->getClosedFilter();
return ceil(Ticket::count($query) / 10); return ceil(Ticket::count($query, [
Controller::request('query') . '%',
'%' . Controller::request('query') . '%'
]) / 10);
} }
private function getStaffDepartmentsQueryFilter() { private function getStaffDepartmentsQueryFilter() {

View File

@ -14,9 +14,15 @@ use Respect\Validation\Validator as DataValidator;
* *
* @apiPermission staff1 * @apiPermission staff1
* *
* @apiUse NO_PERMISSION * @apiParam {Number} page The page number.
* *
* @apiSuccess {[Ticket](#api-Data_Structures-ObjectTicket)[]} data Array of new tickets. * @apiUse NO_PERMISSION
* @apiUse INVALID_PAGE
*
* @apiSuccess {Object} data Information about a tickets and quantity of pages.
* @apiSuccess {[Ticket](#api-Data_Structures-ObjectTicket)[]} data.tickets Array of new tickets of the current page.
* @apiSuccess {Number} data.page Number of current page.
* @apiSuccess {Number} data.pages Quantity of pages.
* *
*/ */
@ -27,7 +33,12 @@ class GetNewTicketsStaffController extends Controller {
public function validations() { public function validations() {
return[ return[
'permission' => 'staff_1', 'permission' => 'staff_1',
'requestData' => [] 'requestData' => [
'page' => [
'validation' => DataValidator::numeric(),
'error' => ERRORS::INVALID_PAGE
]
]
]; ];
} }
public function handler() { public function handler() {
@ -37,6 +48,8 @@ class GetNewTicketsStaffController extends Controller {
} }
$user = Controller::getLoggedUser(); $user = Controller::getLoggedUser();
$page = Controller::request('page');
$query = ' ('; $query = ' (';
foreach ($user->sharedDepartmentList as $department) { foreach ($user->sharedDepartmentList as $department) {
$query .= 'department_id=' . $department->id . ' OR '; $query .= 'department_id=' . $department->id . ' OR ';
@ -45,13 +58,22 @@ class GetNewTicketsStaffController extends Controller {
$ownerExists = RedBean::exec('SHOW COLUMNS FROM ticket LIKE \'owner_id\''); $ownerExists = RedBean::exec('SHOW COLUMNS FROM ticket LIKE \'owner_id\'');
if($ownerExists != 0) { if($ownerExists != 0) {
$query .= 'FALSE) AND owner_id IS NULL'; $query .= 'FALSE) AND closed = 0 AND owner_id IS NULL';
} else { } else {
$query .= 'FALSE)'; $query .= 'FALSE) AND closed = 0';
} }
$countTotal = Ticket::count($query);
$query .= ' ORDER BY unread_staff DESC';
$query .= ' LIMIT 10 OFFSET ' . ($page-1)*10;
$ticketList = Ticket::find($query); $ticketList = Ticket::find($query);
Response::respondSuccess($ticketList->toArray()); Response::respondSuccess([
'tickets' => $ticketList->toArray(true),
'page' => $page,
'pages' => ceil($countTotal / 10)
]);
} }
} }

View File

@ -13,11 +13,16 @@ use Respect\Validation\Validator as DataValidator;
* *
* @apiPermission staff1 * @apiPermission staff1
* *
* @apiParam {Number} page The page number.
* @apiParam {bool} closed Include closed tickets in the response. * @apiParam {bool} closed Include closed tickets in the response.
* *
* @apiUse NO_PERMISSION * @apiUse NO_PERMISSION
* * @apiUse INVALID_PAGE
* @apiSuccess {[Ticket](#api-Data_Structures-ObjectTicket)[]} data Array of tickets assigned to the staff *
* @apiSuccess {Object} data Information about a tickets and quantity of pages.
* @apiSuccess {[Ticket](#api-Data_Structures-ObjectTicket)[]} data.tickets Array of tickets assigned to the staff of the current page.
* @apiSuccess {Number} data.page Number of current page.
* @apiSuccess {Number} data.pages Quantity of pages.
* *
*/ */
@ -28,17 +33,33 @@ class GetTicketStaffController extends Controller {
public function validations() { public function validations() {
return [ return [
'permission' => 'staff_1', 'permission' => 'staff_1',
'requestData' => [] 'requestData' => [
'page' => [
'validation' => DataValidator::numeric(),
'error' => ERRORS::INVALID_PAGE
]
]
]; ];
} }
public function handler() { public function handler() {
$user = Controller::getLoggedUser(); $user = Controller::getLoggedUser();
$closed = Controller::request('closed'); $closed = Controller::request('closed');
$page = Controller::request('page');
$offset = ($page-1)*10;
if ($closed) { if ($closed) {
Response::respondSuccess($user->sharedTicketList->toArray()); $tickets = $user->withCondition(' TRUE LIMIT 10 OFFSET ?', [$offset])->sharedTicketList->toArray(true);
$countTotal = $user->countShared('ticket');
} else { } else {
Response::respondSuccess($user->withCondition('closed = ?', ['0'])->sharedTicketList->toArray()); $tickets = $user->withCondition(' closed = ? LIMIT 10 OFFSET ?', ['0', $offset])->sharedTicketList->toArray(true);
$countTotal = $user->withCondition(' closed = ?', ['0'])->countShared('ticket');
} }
Response::respondSuccess([
'tickets' => $tickets,
'page' => $page,
'pages' => ceil($countTotal / 10)
]);
} }
} }

View File

@ -3,14 +3,14 @@ require_once 'models/DataStore.php';
class DataStoreList implements IteratorAggregate { class DataStoreList implements IteratorAggregate {
private $list = []; private $list = [];
public static function getList($type, $beanList) { public static function getList($type, $beanList) {
$dataStoreList = new DataStoreList(); $dataStoreList = new DataStoreList();
foreach ($beanList as $bean) { foreach ($beanList as $bean) {
$dataStoreList->add(new $type($bean)); $dataStoreList->add(new $type($bean));
} }
return $dataStoreList; return $dataStoreList;
} }
@ -51,21 +51,21 @@ class DataStoreList implements IteratorAggregate {
public function toBeanList() { public function toBeanList() {
$beanList = []; $beanList = [];
foreach($this->list as $item) { foreach($this->list as $item) {
$item->updateBeanProperties(); $item->updateBeanProperties();
$beanList[] = $item->getBeanInstance(); $beanList[] = $item->getBeanInstance();
} }
return $beanList; return $beanList;
} }
public function toArray() { public function toArray($minimized = false) {
$array = []; $array = [];
foreach($this->list as $item) { foreach($this->list as $item) {
$item->updateBeanProperties(); $item->updateBeanProperties();
$array[] = $item->toArray(); $array[] = $item->toArray($minimized);
} }
return $array; return $array;
@ -80,4 +80,4 @@ class DataStoreList implements IteratorAggregate {
return -1; return -1;
} }
} }

View File

@ -33,13 +33,13 @@ abstract class DataStore {
} }
public static function find($query = '', $matches = []) { public static function find($query = '', $matches = []) {
$beanList = RedBean::find(static::TABLE, $query, $matches); $beanList = RedBean::find(static::TABLE, $query, $matches);
return DataStoreList::getList(ucfirst(static::TABLE), $beanList); return DataStoreList::getList(ucfirst(static::TABLE), $beanList);
} }
public static function findOne($query = '', $matches = []) { public static function findOne($query = '', $matches = []) {
$bean = RedBean::findOne(static::TABLE, $query, $matches); $bean = RedBean::findOne(static::TABLE, $query, $matches);
return ($bean) ? new static($bean) : new NullDataStore(); return ($bean) ? new static($bean) : new NullDataStore();
} }
@ -151,7 +151,11 @@ abstract class DataStore {
} }
public function withCondition($condition, $values) { public function withCondition($condition, $values) {
return new static($this->_bean->withCondition($condition, $values)); return new static($this->_bean->withCondition($condition, $values));
}
public function countShared($shared) {
return $this->_bean->countShared($shared);
} }
private function updateBeanProp($key, $value) { private function updateBeanProp($key, $value) {

View File

@ -2,13 +2,14 @@ describe '/staff/get-new-tickets' do
request('/user/logout') request('/user/logout')
Scripts.login($staff[:email], $staff[:password], true) Scripts.login($staff[:email], $staff[:password], true)
it 'should get news tickets' do it 'should get new tickets' do
result = request('/staff/get-new-tickets', { result = request('/staff/get-new-tickets', {
page: 1,
csrf_userid: $csrf_userid, csrf_userid: $csrf_userid,
csrf_token: $csrf_token csrf_token: $csrf_token
}) })
(result['status']).should.equal('success') (result['status']).should.equal('success')
(result['data'].size).should.equal(9) (result['data']['tickets'].size).should.equal(8)
end end
end end

View File

@ -7,21 +7,24 @@ describe '/staff/get-tickets' do
ticket = $database.getRow('ticket', 1 , 'id') ticket = $database.getRow('ticket', 1 , 'id')
request('/staff/assign-ticket', { request('/staff/assign-ticket', {
ticketNumber: ticket['ticket_number'], ticketNumber: ticket['ticket_number'],
page: 1,
csrf_userid: $csrf_userid, csrf_userid: $csrf_userid,
csrf_token: $csrf_token csrf_token: $csrf_token
}) })
ticket = $database.getRow('ticket', 2 , 'id') ticket = $database.getRow('ticket', 2 , 'id')
request('/staff/assign-ticket', { request('/staff/assign-ticket', {
ticketNumber: ticket['ticket_number'], ticketNumber: ticket['ticket_number'],
page: 1,
csrf_userid: $csrf_userid, csrf_userid: $csrf_userid,
csrf_token: $csrf_token csrf_token: $csrf_token
}) })
result = request('/staff/get-tickets', { result = request('/staff/get-tickets', {
page: 1,
csrf_userid: $csrf_userid, csrf_userid: $csrf_userid,
csrf_token: $csrf_token csrf_token: $csrf_token
}) })
(result['status']).should.equal('success') (result['status']).should.equal('success')
(result['data'].size).should.equal(5) (result['data']['tickets'].size).should.equal(5)
end end
end end