Merge pull request #342 from mredigonda/closed-tickets-filter

Adds a button to filter opened/closed tickets
This commit is contained in:
Ivan Diaz 2018-11-15 16:32:06 -03:00 committed by GitHub
commit 4d2d0eac31
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 136 additions and 34 deletions

View File

@ -12,12 +12,12 @@ export default {
};
},
retrieveMyTickets() {
retrieveMyTickets(closed = 0) {
return {
type: 'MY_TICKETS',
payload: API.call({
path: '/staff/get-tickets',
data: {}
data: {closed}
})
};
},
@ -32,12 +32,12 @@ export default {
};
},
retrieveAllTickets(page = 1) {
retrieveAllTickets(page = 1, query = '', closed = 0) {
return {
type: 'ALL_TICKETS',
payload: API.call({
path: '/staff/get-all-tickets',
data: {page}
data: {page, query, closed}
})
};
},

View File

@ -9,6 +9,7 @@ import Table from 'core-components/table';
import Button from 'core-components/button';
import Tooltip from 'core-components/tooltip';
import DropDown from 'core-components/drop-down';
import Checkbox from 'core-components/checkbox';
class TicketList extends React.Component {
static propTypes = {
@ -21,7 +22,9 @@ class TicketList extends React.Component {
type: React.PropTypes.oneOf([
'primary',
'secondary'
])
]),
closedTicketsShown: React.PropTypes.bool,
onClosedTicketsShownChange: React.PropTypes.func
};
static defaultProps = {
@ -30,7 +33,8 @@ class TicketList extends React.Component {
tickets: [],
departments: [],
ticketPath: '/dashboard/ticket/',
type: 'primary'
type: 'primary',
closedTicketsShown: false
};
state = {
@ -40,12 +44,20 @@ class TicketList extends React.Component {
render() {
return (
<div className="ticket-list">
{(this.props.type === 'secondary' && this.props.showDepartmentDropdown) ? this.renderDepartmentsDropDown() : null}
<div className="ticket-list__filters">
{(this.props.type === 'secondary' && this.props.showDepartmentDropdown) ? this.renderDepartmentsDropDown() : null}
{this.props.onClosedTicketsShownChange ? this.renderFilterCheckbox() : null}
</div>
<Table {...this.getTableProps()} />
</div>
);
}
renderFilterCheckbox() {
return <Checkbox className="ticket-list__checkbox" label={i18n("SHOW_CLOSED_TICKETS")} value={this.props.closedTicketsShown} onChange={this.props.onClosedTicketsShownChange} wrapInLabel/>
}
renderDepartmentsDropDown() {
return (
<div className="ticket-list__department-selector">

View File

@ -2,8 +2,19 @@
.ticket-list {
&__department-selector {
&__filters {
margin-bottom: 25px;
text-align: left;
}
&__department-selector {
display: inline-block;
margin-right: 25px;
text-align: center;
}
&__checkbox {
display: inline-block;
}
&__number {

View File

@ -20,11 +20,12 @@ class AdminPanelAllTickets extends React.Component {
state = {
page: 1,
query: ''
query: '',
closedTicketsShown: false
};
componentDidMount() {
this.props.dispatch(AdminDataAction.retrieveAllTickets());
this.updateTicketList();
}
render() {
@ -41,6 +42,14 @@ class AdminPanelAllTickets extends React.Component {
);
}
updateTicketList() {
this.props.dispatch(AdminDataAction.retrieveAllTickets(
this.state.page,
this.state.query,
this.state.closedTicketsShown*1
));
}
getTicketListProps() {
return {
userId: this.props.userId,
@ -52,28 +61,32 @@ class AdminPanelAllTickets extends React.Component {
ticketPath: '/admin/panel/tickets/view-ticket/',
onPageChange: this.onPageChange.bind(this),
page: this.state.page,
pages: this.props.pages
pages: this.props.pages,
closedTicketsShown: this.state.closedTicketsShown,
onClosedTicketsShownChange: this.onClosedTicketsShownChange.bind(this)
};
}
onSearch(query) {
this.setState({query, page: 1});
onClosedTicketsShownChange() {
this.setState(function(state) {
return {
closedTicketsShown: !state.closedTicketsShown
};
}, () => {
this.updateTicketList();
});
}
if(query) {
this.props.dispatch(AdminDataAction.searchTickets(query));
} else {
this.props.dispatch(AdminDataAction.retrieveAllTickets());
}
onSearch(query) {
this.setState({query, page: 1}, () => {
this.updateTicketList();
});
}
onPageChange(event) {
this.setState({page: event.target.value});
if(this.state.query) {
this.props.dispatch(AdminDataAction.searchTickets(this.state.query, event.target.value));
} else {
this.props.dispatch(AdminDataAction.retrieveAllTickets(event.target.value));
}
this.setState({page: event.target.value}, () => {
this.updateTicketList();
});
}
}

View File

@ -21,6 +21,10 @@ class AdminPanelMyTickets extends React.Component {
tickets: []
};
state = {
closedTicketsShown: false
};
componentDidMount() {
this.props.dispatch(AdminDataAction.retrieveMyTickets());
}
@ -46,10 +50,22 @@ class AdminPanelMyTickets extends React.Component {
tickets: this.props.tickets,
type: 'secondary',
loading: this.props.loading,
ticketPath: '/admin/panel/tickets/view-ticket/'
ticketPath: '/admin/panel/tickets/view-ticket/',
closedTicketsShown: this.state.closedTicketsShown,
onClosedTicketsShownChange: this.onClosedTicketsShownChange.bind(this)
};
}
onClosedTicketsShownChange() {
this.setState(function(state) {
return {
closedTicketsShown: !state.closedTicketsShown
};
}, () => {
this.props.dispatch(AdminDataAction.retrieveMyTickets(this.state.closedTicketsShown * 1));
});
}
onCreateTicket() {
ModalContainer.openModal(
<div>

View File

@ -188,6 +188,7 @@ export default {
'PRIVATE': 'privado',
'ENABLE_USER': 'Ativar usuário',
'DISABLE_USER': 'Desativar usuário',
'SHOW_CLOSED_TICKETS': 'Mostrar ingressos fechados',
'CHART_CREATE_TICKET': 'Chamados criados',
'CHART_CLOSE': 'Chamados fechados',

View File

@ -188,6 +188,7 @@ export default {
'PRIVATE': '私人的',
'ENABLE_USER': '启用用户',
'DISABLE_USER': '禁用用户',
'SHOW_CLOSED_TICKETS': '显示已关闭的门票',
'CHART_CREATE_TICKET': '已創建門票',
'CHART_CLOSE': '門票已關閉',

View File

@ -188,6 +188,7 @@ export default {
'PRIVATE': 'Privatgelände',
'ENABLE_USER': 'Benutzer aktivieren',
'DISABLE_USER': 'Benutzer deaktivieren',
'SHOW_CLOSED_TICKETS': 'Geschlossene Tickets anzeigen',
'CHART_CREATE_TICKET': 'Tickets erstellt',
'CHART_CLOSE': 'Tickets geschlossen',

View File

@ -188,6 +188,7 @@ export default {
'PRIVATE': 'Private',
'ENABLE_USER': 'Enable User',
'DISABLE_USER': 'Disable User',
'SHOW_CLOSED_TICKETS': 'Show Closed Tickets',
'CHART_CREATE_TICKET': 'Tickets created',
'CHART_CLOSE': 'Tickets closed',

View File

@ -188,6 +188,7 @@ export default {
'PRIVATE': 'privado',
'ENABLE_USER': 'Habilitar usuario',
'DISABLE_USER': 'Deshabilitar usuario',
'SHOW_CLOSED_TICKETS': 'Mostrar Tickets Cerrados',
'CHART_CREATE_TICKET': 'Tickets creados',
'CHART_CLOSE': 'Tickets cerrados',

View File

@ -188,6 +188,7 @@ export default {
'PRIVATE': 'privé',
'ENABLE_USER': 'Activer l\'utilisateur',
'DISABLE_USER': 'Désactiver l\'utilisateur',
'SHOW_CLOSED_TICKETS': 'Afficher les billets fermés',
'CHART_CREATE_TICKET': 'Tickets créés',
'CHART_CLOSE': 'Tickets fermés',

View File

@ -188,6 +188,7 @@
'PRIVATE': 'ιδιωτικός',
'ENABLE_USER': 'Ενεργοποίηση χρήστη',
'DISABLE_USER': 'Απενεργοποίηση χρήστη',
'SHOW_CLOSED_TICKETS': 'Εμφάνιση κλειστών εισιτηρίων',
'CHART_CREATE_TICKET': 'Τα εισιτήρια δημιουργήθηκαν',
'CHART_CLOSE': 'Τα εισιτήρια κλείσανε',

View File

@ -188,6 +188,7 @@ export default {
'PRIVATE': 'निजी',
'ENABLE_USER': 'उपयोगकर्ता सक्षम करें',
'DISABLE_USER': 'उपयोगकर्ता को अक्षम करें',
'SHOW_CLOSED_TICKETS': 'बंद टिकट दिखाएं',
'CHART_CREATE_TICKET': 'टिकट बनाया',
'CHART_CLOSE': 'टिकट बंद कर दिया',

View File

@ -188,6 +188,7 @@ export default {
'PRIVATE': 'privato',
'ENABLE_USER': 'Abilita utente',
'DISABLE_USER': 'Disabilita utente',
'SHOW_CLOSED_TICKETS': 'Mostra biglietti chiusi',
'CHART_CREATE_TICKET': 'Tickets creato',
'CHART_CLOSE': 'Tickets chiuso',

View File

@ -188,6 +188,7 @@ export default {
'PRIVATE': 'プライベート',
'ENABLE_USER': 'ユーザーを有効にする',
'DISABLE_USER': 'ユーザーを無効にする',
'SHOW_CLOSED_TICKETS': 'クローズドチケットを表示する',
'CHART_CREATE_TICKET': '作成されたチケット',
'CHART_CLOSE': 'チケットが閉じられました',

View File

@ -188,6 +188,7 @@ export default {
'PRIVATE': 'privaat',
'ENABLE_USER': 'Schakel gebruiker in',
'DISABLE_USER': 'Gebruiker uitschakelen',
'SHOW_CLOSED_TICKETS': 'Toon gesloten tickets',
'CHART_CREATE_TICKET': 'Aangemaakte incidenten',
'CHART_CLOSE': 'Gesloten incidenten',

View File

@ -188,6 +188,7 @@ export default {
'PRIVATE': 'privado',
'ENABLE_USER': 'Ativar usuário',
'DISABLE_USER': 'Desativar usuário',
'SHOW_CLOSED_TICKETS': 'Mostrar ingressos fechados',
'CHART_CREATE_TICKET': 'Ingressos criados',
'CHART_CLOSE': 'Ingressos fechados',

View File

@ -188,6 +188,7 @@ export default {
'PRIVATE': 'частный',
'ENABLE_USER': 'Включить пользователя',
'DISABLE_USER': 'Отключить пользователя',
'SHOW_CLOSED_TICKETS': 'Показать закрытые билеты',
'CHART_CREATE_TICKET': 'Билеты создано',
'CHART_CLOSE': ' Билеты закрыты',

View File

@ -188,6 +188,7 @@ export default {
'PRIVATE': 'gizli',
'ENABLE_USER': 'Kullanıcıyı Etkinleştir',
'DISABLE_USER': 'Kullanıcıyı Devre Dışı Bırak',
'SHOW_CLOSED_TICKETS': 'Kapalı Biletleri Göster',
'CHART_CREATE_TICKET': 'Biletler oluşturuldu',
'CHART_CLOSE': 'Biletler kapandı',

View File

@ -2,18 +2,20 @@
use Respect\Validation\Validator as DataValidator;
/**
* @api {post} /staff/get-all-tickets Get all tickets
* @api {post} /staff/get-all-tickets Get all tickets according to search
* @apiVersion 4.3.0
*
* @apiName Get all tickets
*
* @apiGroup Staff
*
* @apiDescription This path retrieves all tickets.
* @apiDescription This path retrieves all tickets according to search and opened/closed filters.
*
* @apiPermission staff1
*
* @apiParam {Number} page The page number.
* @apiParam {String} query Query string to search.
* @apiParam {Boolean} closed Include closed tickets.
*
* @apiUse NO_PERMISSION
* @apiUse INVALID_PAGE
@ -58,10 +60,24 @@ class GetAllTicketsStaffController extends Controller {
private function getTicketList() {
$page = Controller::request('page');
$query = $this->getStaffDepartmentsQueryFilter();
$query .= 'ORDER BY id DESC LIMIT 10 OFFSET ' . (($page-1)*10);
$query = $this->getSearchQuery();
$query .= $this->getStaffDepartmentsQueryFilter();
$query .= $this->getClosedFilter();
$query .= "ORDER BY CASE WHEN (title LIKE ?) THEN 1 ELSE 2 END ASC, id DESC LIMIT 10 OFFSET " . (($page-1)*10);
return Ticket::find($query);
return Ticket::find($query, [
Controller::request('query') . '%',
'%' . Controller::request('query') . '%',
Controller::request('query') . '%'
]);
}
private function getSearchQuery() {
$page = Controller::request('page');
$query = " (title LIKE ? OR title LIKE ?) AND ";
return $query;
}
private function getTotalPages() {
@ -81,4 +97,13 @@ class GetAllTicketsStaffController extends Controller {
return $query;
}
private function getClosedFilter() {
$closed = Controller::request('closed')*1;
if ($closed) {
return '';
} else {
return " AND (closed = '0')";
}
}
}

View File

@ -13,6 +13,8 @@ use Respect\Validation\Validator as DataValidator;
*
* @apiPermission staff1
*
* @apiParam {bool} closed Include closed tickets in the response.
*
* @apiUse NO_PERMISSION
*
* @apiSuccess {[Ticket](#api-Data_Structures-ObjectTicket)[]} data Array of tickets assigned to the staff
@ -32,6 +34,11 @@ class GetTicketStaffController extends Controller {
public function handler() {
$user = Controller::getLoggedUser();
Response::respondSuccess($user->sharedTicketList->toArray());
$closed = Controller::request('closed');
if ($closed) {
Response::respondSuccess($user->sharedTicketList->toArray());
} else {
Response::respondSuccess($user->withCondition('closed = ?', ['0'])->sharedTicketList->toArray());
}
}
}

View File

@ -150,6 +150,10 @@ abstract class DataStore {
}
}
public function withCondition($condition, $values) {
return new static($this->_bean->withCondition($condition, $values));
}
private function updateBeanProp($key, $value) {
if ($value instanceof DataStoreList) {
$this->_bean[$key] = $value->toBeanList();