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 { return {
type: 'MY_TICKETS', type: 'MY_TICKETS',
payload: API.call({ payload: API.call({
path: '/staff/get-tickets', path: '/staff/get-tickets',
data: {} data: {closed}
}) })
}; };
}, },
@ -32,12 +32,12 @@ export default {
}; };
}, },
retrieveAllTickets(page = 1) { retrieveAllTickets(page = 1, query = '', closed = 0) {
return { return {
type: 'ALL_TICKETS', type: 'ALL_TICKETS',
payload: API.call({ payload: API.call({
path: '/staff/get-all-tickets', 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 Button from 'core-components/button';
import Tooltip from 'core-components/tooltip'; import Tooltip from 'core-components/tooltip';
import DropDown from 'core-components/drop-down'; import DropDown from 'core-components/drop-down';
import Checkbox from 'core-components/checkbox';
class TicketList extends React.Component { class TicketList extends React.Component {
static propTypes = { static propTypes = {
@ -21,7 +22,9 @@ class TicketList extends React.Component {
type: React.PropTypes.oneOf([ type: React.PropTypes.oneOf([
'primary', 'primary',
'secondary' 'secondary'
]) ]),
closedTicketsShown: React.PropTypes.bool,
onClosedTicketsShownChange: React.PropTypes.func
}; };
static defaultProps = { static defaultProps = {
@ -30,7 +33,8 @@ class TicketList extends React.Component {
tickets: [], tickets: [],
departments: [], departments: [],
ticketPath: '/dashboard/ticket/', ticketPath: '/dashboard/ticket/',
type: 'primary' type: 'primary',
closedTicketsShown: false
}; };
state = { state = {
@ -40,12 +44,20 @@ class TicketList extends React.Component {
render() { render() {
return ( return (
<div className="ticket-list"> <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()} /> <Table {...this.getTableProps()} />
</div> </div>
); );
} }
renderFilterCheckbox() {
return <Checkbox className="ticket-list__checkbox" label={i18n("SHOW_CLOSED_TICKETS")} value={this.props.closedTicketsShown} onChange={this.props.onClosedTicketsShownChange} wrapInLabel/>
}
renderDepartmentsDropDown() { renderDepartmentsDropDown() {
return ( return (
<div className="ticket-list__department-selector"> <div className="ticket-list__department-selector">

View File

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

View File

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

View File

@ -21,6 +21,10 @@ class AdminPanelMyTickets extends React.Component {
tickets: [] tickets: []
}; };
state = {
closedTicketsShown: false
};
componentDidMount() { componentDidMount() {
this.props.dispatch(AdminDataAction.retrieveMyTickets()); this.props.dispatch(AdminDataAction.retrieveMyTickets());
} }
@ -46,10 +50,22 @@ class AdminPanelMyTickets 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/',
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() { onCreateTicket() {
ModalContainer.openModal( ModalContainer.openModal(
<div> <div>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -2,18 +2,20 @@
use Respect\Validation\Validator as DataValidator; 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 * @apiVersion 4.3.0
* *
* @apiName Get all tickets * @apiName Get all tickets
* *
* @apiGroup Staff * @apiGroup Staff
* *
* @apiDescription This path retrieves all tickets. * @apiDescription This path retrieves all tickets according to search and opened/closed filters.
* *
* @apiPermission staff1 * @apiPermission staff1
* *
* @apiParam {Number} page The page number. * @apiParam {Number} page The page number.
* @apiParam {String} query Query string to search.
* @apiParam {Boolean} closed Include closed tickets.
* *
* @apiUse NO_PERMISSION * @apiUse NO_PERMISSION
* @apiUse INVALID_PAGE * @apiUse INVALID_PAGE
@ -58,10 +60,24 @@ class GetAllTicketsStaffController extends Controller {
private function getTicketList() { private function getTicketList() {
$page = Controller::request('page'); $page = Controller::request('page');
$query = $this->getStaffDepartmentsQueryFilter(); $query = $this->getSearchQuery();
$query .= 'ORDER BY id DESC LIMIT 10 OFFSET ' . (($page-1)*10); $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() { private function getTotalPages() {
@ -81,4 +97,13 @@ class GetAllTicketsStaffController extends Controller {
return $query; 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 * @apiPermission staff1
* *
* @apiParam {bool} closed Include closed tickets in the response.
*
* @apiUse NO_PERMISSION * @apiUse NO_PERMISSION
* *
* @apiSuccess {[Ticket](#api-Data_Structures-ObjectTicket)[]} data Array of tickets assigned to the staff * @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() { public function handler() {
$user = Controller::getLoggedUser(); $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) { private function updateBeanProp($key, $value) {
if ($value instanceof DataStoreList) { if ($value instanceof DataStoreList) {
$this->_bean[$key] = $value->toBeanList(); $this->_bean[$key] = $value->toBeanList();