{% extends "@UVDeskCoreFramework//Templates//layout.html.twig" %}
{% block title %}{{ 'Tickets'|trans }}{% endblock %}
{% block templateCSS %}
<style>
.pagination {
display: flex;
justify-content: center;
margin-top: 10px;
}
.pagination a,
.pagination span {
display: inline-block;
padding: 5px 10px;
margin-right: 5px;
color: #333;
text-decoration: none;
background-color: #eee;
border-radius: 3px;
cursor: pointer;
}
.pagination a:hover {
background-color: #ccc;
}
.pagination span.current {
font-weight: bold;
}
.pagination a.disabled,
.pagination span.disabled {
cursor: not-allowed;
opacity: 0.6;
}
.pagination .dots {
margin-right: 10px;
}
.modal {
display: none;
position: fixed;
z-index: 9999;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
}
.modal-content {
background-color: white;
margin: 0 auto;
margin-top: 10%;
padding: 20px;
border: 1px solid #888;
width: 60%;
max-height: 80%;
overflow-y: auto;
position: relative;
}
.close {
color: #aaa;
position: absolute;
top: 10px;
right: 20px;
font-size: 28px;
font-weight: bold;
}
.close:hover,
.close:focus {
color: black;
text-decoration: none;
cursor: pointer;
}
table {
width: 100%;
border-collapse: collapse;
}
th, td {
padding: 8px;
text-align: left;
border-bottom: 1px solid #ddd;
}
.icon-container {
width: 40px;
height: 40px;
position: relative;
}
.status-circle {
width: 15px;
height: 15px;
border-radius: 50%;
background-color: green;
border: 2px solid white;
bottom: 0;
right: 0;
position: absolute;
}
.userOnlineImg{
height: 100%;
width: 100%;
border-radius: 50%;
}
.uv-dropdown.asset-visibility li input {
z-index: 100;
}
.uv-dropdown.asset-visibility ul li label {
color: #333333;
font-size: 17px;
font-weight: 500;
text-transform: capitalize;
cursor: pointer;
margin: auto;
}
.uv-table td a {
color: #333333;
}
.uv-table.uv-list-view table tbody td.uv-width-100 {
width: 100px !important;
}
.uv-table.uv-list-view td[data-index="agent"] {
white-space: nowrap;
}
.uv-view:not(.uv-stack-view) .uv-table td a {
display: inline-block;
width: 100%;
}
.uv-action-bar-col-lt.uv-width-100 {
width: 100% !important;
}
#quick-view-modal .uv-view {
padding: 0;
overflow-y: visible;
display: inline-block;
position: relative;
}
#quick-view-modal .uv-view .uv-ticket-section {
margin-top: 0;
}
#quick-view-modal .uv-ticket-head {
border-top: 1px solid #d3d3d3;
padding-top: 10px;
padding-bottom: 10px;
}
#quick-view-modal .uv-ticket-strip {
padding-bottom: 0;
}
#quick-view-modal .uv-ticket-strip .uv-btn-tag {
margin-bottom: 0;
}
#quick-view-modal .quick-view-navigation {
position: absolute;
right: 50px;
top: 9px;
}
#quick-view-modal .quick-view-navigation ~ a {
width: calc(100% - 100px);
display: inline-block;
}
#quick-view-modal .uv-btn-tag[disabled="disabled"] {
opacity: .4;
cursor: not-allowed;
border-color: #B1B1AE !important;
}
#quick-view-modal .uv-loader {
transform: scale(0.5);
top: 14px;
right: 60px;
}
tr.unread {
background: #f1f1f1;
}
.uv-table table tbody tr.not-assigned td {
border-bottom: 1px solid #ffcacc;
}
@media screen and (max-width: 500px) {
.uv-action-bar label {
display: inline-block;
}
}
/* Estilos para el sistema de alertas de tickets */
.ticket-alert-overlay {
display: none;
position: fixed;
z-index: 10000;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
}
.ticket-alert-modal {
background-color: white;
margin: 5% auto;
padding: 0;
border-radius: 8px;
width: 80%;
max-width: 600px;
max-height: 80%;
overflow-y: auto;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
}
.ticket-alert-header {
background: linear-gradient(135deg, #ff6b6b, #ee5a24);
color: white;
padding: 20px;
border-radius: 8px 8px 0 0;
position: relative;
}
.ticket-alert-header h3 {
margin: 0;
font-size: 1.5em;
font-weight: 600;
}
.ticket-alert-close {
position: absolute;
top: 15px;
right: 20px;
background: none;
border: none;
color: white;
font-size: 24px;
cursor: pointer;
font-weight: bold;
}
.ticket-alert-close:hover {
opacity: 0.8;
}
.ticket-alert-body {
padding: 20px;
}
.ticket-alert-section {
margin-bottom: 25px;
}
.ticket-alert-section h4 {
color: #333;
margin-bottom: 15px;
font-size: 1.2em;
font-weight: 600;
border-bottom: 2px solid #ff6b6b;
padding-bottom: 8px;
}
.ticket-alert-section h4::before {
content: "⚠️";
margin-right: 8px;
}
.ticket-alert-list {
list-style: none;
padding: 0;
margin: 0;
}
.ticket-alert-item {
background: #f8f9fa;
border: 1px solid #e9ecef;
border-radius: 6px;
padding: 15px;
margin-bottom: 10px;
display: flex;
justify-content: space-between;
align-items: center;
transition: all 0.3s ease;
}
.ticket-alert-item:hover {
background: #e9ecef;
border-color: #ff6b6b;
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(255, 107, 107, 0.2);
}
.ticket-alert-info {
flex: 1;
}
.ticket-alert-id {
display: block;
font-weight: 600;
color: #333;
margin-bottom: 5px;
}
.ticket-alert-subject {
display: block;
color: #666;
font-size: 0.9em;
}
.ticket-alert-days {
background: #ff6b6b;
color: white;
padding: 5px 12px;
border-radius: 20px;
font-weight: 600;
font-size: 0.9em;
white-space: nowrap;
}
.ticket-alert-actions {
display: flex;
gap: 10px;
justify-content: flex-end;
margin-top: 20px;
padding-top: 20px;
border-top: 1px solid #e9ecef;
}
.ticket-alert-btn {
padding: 10px 20px;
border: none;
border-radius: 6px;
cursor: pointer;
font-weight: 600;
transition: all 0.3s ease;
text-decoration: none;
display: inline-block;
}
.ticket-alert-btn-primary {
background: #ff6b6b;
color: white;
}
.ticket-alert-btn-primary:hover {
background: #ee5a24;
transform: translateY(-2px);
}
.ticket-alert-btn-secondary {
background: #6c757d;
color: white;
}
.ticket-alert-btn-secondary:hover {
background: #5a6268;
}
.ticket-alert-btn-remind {
background: #ffc107;
color: #212529;
}
.ticket-alert-btn-remind:hover {
background: #e0a800;
}
.ticket-alert-empty {
text-align: center;
color: #666;
font-style: italic;
padding: 40px 20px;
}
/* Indicador de alerta en el sidebar */
.alert-indicator {
position: absolute;
top: -5px;
right: -5px;
background: #ff6b6b;
color: white;
border-radius: 50%;
width: 20px;
height: 20px;
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
font-weight: bold;
animation: pulse 2s infinite;
}
@keyframes pulse {
0% {
transform: scale(1);
box-shadow: 0 0 0 0 rgba(255, 107, 107, 0.7);
}
70% {
transform: scale(1.1);
box-shadow: 0 0 0 10px rgba(255, 107, 107, 0);
}
100% {
transform: scale(1);
box-shadow: 0 0 0 0 rgba(255, 107, 107, 0);
}
}
</style>
{% endblock %}
{% block pageContent %}
{# Quick View Popup #}
<div class="uv-pop-up-overlay" id="quick-view-modal">
<div class="uv-pop-up-box uv-pop-up-wide"></div>
</div>
<div class="uv-inner-section">
{# Ticket Sidebar #}
<div class="uv-aside" {% if app.request.cookies and app.request.cookies.get('uv-asideView') %} style="display: none;" {% endif %} >
<div class="uv-aside-default">
<div class="uv-aside-head">
<div class="uv-aside-title">
<h6>{{ 'Tickets'|trans }}</h6>
</div>
<div class="uv-aside-back">
<span onclick="history.length > 1 ? history.go(-1) : window.location = '{{ path("helpdesk_member_dashboard") }}';">{{ 'Back'|trans }}</span>
</div>
</div>
<div class="uv-aside-nav">
<ul>
{# Predefined Label List #}
<ul class="predefined-label-list uv-aside-list">
<li>
<a href="#" class="uv-aside-active">{{ 'All'|trans }} <span class="uv-flag-gray uv-flag-dark">0</span></a>
{# Status ticket count list #}
<ul class="status-list">
<li>
<a href="#" data-id="1" class="uv-aside-nav-active"><span class="name">{{ 'Open'|trans }}</span><span class="uv-flag-gray">0</span></a>
</li>
<li>
<a href="#" data-id="2"><span class="name">{{ 'Pending'|trans }}</span><span class="uv-flag-gray">0</span></a>
</li>
<li>
<a href="#" data-id="6"><span class="name">{{ 'Answered'|trans }}</span><span class="uv-flag-gray">0</span></a>
</li>
<li>
<a href="#" data-id="3"><span class="name">{{ 'Resolved'|trans }}</span><span class="uv-flag-gray">0</span></a>
</li>
<li>
<a href="#" data-id="4"><span class="name">{{ 'Closed'|trans }}</span><span class="uv-flag-gray">0</span></a>
</li>
<li>
<a href="#" data-id="5"><span class="name">{{ 'Spam'|trans }}</span><span class="uv-flag-gray">0</span></a>
</li>
</ul>
</li>
<li>
<a href="#new">{{ 'New'|trans }} <span class="uv-flag-gray uv-flag-dark">0</span></a>
</li>
<li>
<a href="#unassigned">{{ 'UnAssigned'|trans }} <span class="uv-flag-gray uv-flag-dark">0</span></a>
</li>
<li>
<a href="#notreplied">{{ 'UnAnswered'|trans }} <span class="uv-flag-gray uv-flag-dark">0</span></a>
</li>
<li>
<a href="#mine">{{ 'My Tickets'|trans }} <span class="uv-flag-gray uv-flag-dark">0</span></a>
</li>
<li>
<a href="#starred">{{ 'Starred'|trans }} <span class="uv-flag-gray uv-flag-dark">0</span></a>
</li>
<li>
<a href="#trashed" style="border-bottom: none">{{ 'Trashed'|trans }} <span class="uv-flag-gray uv-flag-dark">0</span></a>
</li>
</ul>
{# Custom Label List #}
<ul class="uv-aside-custom"></ul>
</ul>
</div>
{#<a class="uv-btn-small add-new-label" href="#"><span class="uv-icon-add"></span> {{ 'Label'|trans }}</a>#}
</div>
<!-- Label add and edit -->
<div class="uv-add-edit-label" style="display: block"></div>
<label>{{ 'Users Online'|trans }}</label>
<ul style="list-style-type: none; padding:5px" >
{% for user in user_service.getUsersOnline %}
<li data-id="{{user.id}}" >
<div class="icon-container">
{% if user.imagePath != null %}
<img class="userOnlineImg" src="{{ app.request.scheme ~'://' ~ app.request.httpHost ~ asset('') }}{{ user.imagePath}}"/>
{% else %}
<img class="userOnlineImg" src="{{ asset(default_agent_image_path) }}" alt=""/>
{% endif %}
<div class='status-circle'></div>
</div>
<span > {{ user.firstName }}</span>
<span> <p style="color:blue;font-size:12px;"> ({{ user.team }}) - <span style="color:green;font-size:12px;"> Open Tickets: {{ user.countTicket }} </span> </p> </span>
</li>
{% endfor %}
</ul>
</div>
{# Ticket List #}
<div class="uv-view {% if app.request.cookies and app.request.cookies.get('uv-asideView') %} uv-aside-view {% endif %}">
<h1>{{ 'Tickets'|trans }}</h1>
<ul style="list-style-type: none; padding:5px">
{% set page = app.request.query.get('page', 1) %}
{% set perPage = 10 %} <!-- Número de tickets por página -->
{% set ticketsData = user_service.getAnsweredTickets(page, perPage) %}
{% set tickets = ticketsData.result %}
{% set totalRows = ticketsData.totalRows %}
{% set totalPages = (totalRows / perPage)|round(0, 'ceil') %}
{% if user_service.isAccessAuthorized('ROLE_ADMIN') %}
<label>{{ 'Tickets answered more than 15 days ago'|trans }}: <a href="#" onclick="showTicketModal()">{{ totalRows }} tickets</a></label>
{% endif %}
<!-- Modal -->
<div id="ticketModal" class="modal">
<div class="modal-content">
<span class="close" onclick="closeTicketModal()">×</span>
<div class="modal-body">
<table>
<thead>
<tr>
<th>ID</th>
<th>UPDATED</th>
<th>DAYS</th>
<th>CLOSE TICKET</th>
</tr>
</thead>
<tbody>
{% for ticket in tickets %}
<tr>
<td><a target="_blank" href="https://softguard.com/tks/public/es/member/ticket/view/{{ ticket.id }}">{{ ticket.id }}-{{ticket.numeracion}}</a></td>
<td>{{ ticket.updated_at|date("d-m-Y") }}</td>
<td>{{ ticket.dias_diferencia }}</td>
<td>
<form enctype="multipart/form-data" method="post" action="{{ path('helpdesk_member_add_ticket_thread', {'ticketId': ticket.id }) }}">
<input name="threadType" value="reply" type="hidden">
<input name="status" value="Closed by autoclose" type="hidden" {% if user_service.isAccessAuthorized('ROLE_AGENT_UPDATE_TICKET_STATUS') %}class="reply-status"{% endif %}>
<div class="uv-element-block uv-element-block-textarea" style="display: none !important;">
<label class="uv-field-label">{{ 'Write a reply'|trans }}</label>
<div class="uv-field-block">
<textarea class="uv-field" name="reply" id="note-area">Closed by autoclose</textarea>
</div>
</div>
<div class="uv-dropdown next-view">
<input type="hidden" name="nextView" value="redirect"/>
</div>
{% if user_service.isAccessAuthorized('ROLE_AGENT_UPDATE_TICKET_STATUS') %}
<button style="background-color:#767676; color:#FFF; margin:5px; padding: 10px !important;" type="submit" data-id="closed">{{ 'Closed by autoclose'|trans }}</button>
{% endif %}
</form>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<!-- Paginación -->
<div class="pagination">
{% if totalPages > 1 %}
{% for p in 1..totalPages %}
{% if p == page %}
<span>{{ p }}</span>
{% else %}
<a href="?page={{ p }}">{{ p }}</a>
{% endif %}
{% endfor %}
{% endif %}
</div>
</div>
</div>
</ul>
<div class="ticket-alert-overlay" id="ticketAlertModal">
<div class="ticket-alert-modal">
<div class="ticket-alert-header">
<h3>⚠️ {{ 'Ticket Alerts'|trans }}</h3>
<button class="ticket-alert-close" onclick="closeTicketAlert()">×</button>
</div>
<div class="ticket-alert-body" id="ticketAlertBody">
<!-- El contenido se cargará dinámicamente -->
</div>
<div class="ticket-alert-actions">
<button class="ticket-alert-btn ticket-alert-btn-secondary" onclick="closeTicketAlert()">
{{ 'Close'|trans }}
</button>
</div>
</div>
</div>
{# Action Bar #}
<div class="uv-action-bar">
{# Select all checkbox #}
<div class="uv-action-select-wrapper">
<label class="uv-vertical-align uv-margin-left-27">
<div class="uv-checkbox">
<input type="checkbox" class="select-all-checkbox"><span class="uv-checkbox-view"></span>
</div>
</label>
</div>
{# Filter Options #}
<div class="uv-action-col-wrapper">
{# Ticket Sort | Asset Visibility #}
<div class="uv-action-bar-col-lt">
<div class="filter">
{# Sort By #}
<div class="uv-dropdown sort">
<div class="uv-dropdown-btn uv-vertical-align uv-margin-right-5">{{ 'Sort By:'|trans }} {{ 'Last Replied'|trans }}</div>
<div class="uv-dropdown-list uv-bottom-left">
<div class="uv-dropdown-container">
<label>{{ 'Sort By'|trans }}</label>
<ul></ul>
</div>
</div>
</div>
{# Assets Visibilities #}
<div class="uv-dropdown asset-visibility">
<div class="uv-dropdown-btn uv-vertical-align uv-margin-right-5">{{ 'Assets Visibility'|trans }}</div>
<div class="uv-dropdown-list uv-bottom-left" style="width: 215px;">
<div class="uv-dropdown-container">
<label>{{ 'Assets Visibility'|trans }}</label>
<ul>
{# Subject #}
<li class="uv-dropdown-checkbox">
<label>
<div class="uv-checkbox">
<input type="checkbox" id="subject" name="assetVisibility[]" value="subject" checked>
<span class="uv-checkbox-view uv-checkbox-dwn"></span>
</div>
</label>
<label for="subject">{{ 'Subject'|trans }}</label>
</li>
{# Reference #}
<li class="uv-dropdown-checkbox">
<label>
<div class="uv-checkbox">
<input type="checkbox" id="reference" name="assetVisibility[]" value="reference" checked>
<span class="uv-checkbox-view uv-checkbox-dwn"></span>
</div>
</label>
<label for="reference">{{ 'Reference'|trans }}</label>
</li>
{# Ticket Source #}
<li class="uv-dropdown-checkbox">
<label>
<div class="uv-checkbox">
<input type="checkbox" id="source" name="assetVisibility[]" value="source" checked>
<span class="uv-checkbox-view uv-checkbox-dwn"></span>
</div>
</label>
<label for="source">{{ 'Channel/Source'|trans }}</label>
</li>
{# Ticket Customer Name #}
<li class="uv-dropdown-checkbox">
<label>
<div class="uv-checkbox">
<input type="checkbox" id="customer-name" name="assetVisibility[]" value="customer-name" checked>
<span class="uv-checkbox-view uv-checkbox-dwn"></span>
</div>
</label>
<label for="customer-name">{{ 'Customer Name'|trans }}</label>
</li>
{# Ticket Customer Email #}
<li class="uv-dropdown-checkbox">
<label>
<div class="uv-checkbox">
<input type="checkbox" id="customer-email" name="assetVisibility[]" value="customer-email" checked>
<span class="uv-checkbox-view uv-checkbox-dwn"></span>
</div>
</label>
<label for="customer-email">{{ 'Customer Email'|trans }}</label>
</li>
{# Ticket Timestamp #}
<li class="uv-dropdown-checkbox">
<label>
<div class="uv-checkbox">
<input type="checkbox" id="timestamp" name="assetVisibility[]" value="timestamp" checked>
<span class="uv-checkbox-view uv-checkbox-dwn"></span>
</div>
</label>
<label for="timestamp">{{ 'Timestamp'|trans }}</label>
</li>
{# Ticket Group #}
<li class="uv-dropdown-checkbox">
<label>
<div class="uv-checkbox">
<input type="checkbox" id="group" name="assetVisibility[]" value="group" checked>
<span class="uv-checkbox-view uv-checkbox-dwn"></span>
</div>
</label>
<label for="group">{{ 'Group'|trans }}</label>
</li>
{# Ticket Team #}
<li class="uv-dropdown-checkbox">
<label>
<div class="uv-checkbox">
<input type="checkbox" id="team" name="assetVisibility[]" value="team" checked>
<span class="uv-checkbox-view uv-checkbox-dwn"></span>
</div>
</label>
<label for="team">{{ 'Team'|trans }}</label>
</li>
{# Ticket Type #}
<li class="uv-dropdown-checkbox">
<label>
<div class="uv-checkbox">
<input type="checkbox" id="type1" name="assetVisibility[]" value="type1" checked>
<span class="uv-checkbox-view uv-checkbox-dwn"></span>
</div>
</label>
<label for="type1">{{ 'Type'|trans }}</label>
</li>
{# Ticket Replies #}
<li class="uv-dropdown-checkbox">
<label>
<div class="uv-checkbox">
<input type="checkbox" id="replies" name="assetVisibility[]" value="replies" checked>
<span class="uv-checkbox-view uv-checkbox-dwn"></span>
</div>
</label>
<label for="replies">{{ 'Replies'|trans }}</label>
</li>
{# Ticket Agent #}
<li class="uv-dropdown-checkbox">
<label>
<div class="uv-checkbox">
<input type="checkbox" id="agent" name="assetVisibility[]" value="agent" checked>
<span class="uv-checkbox-view uv-checkbox-dwn"></span>
</div>
</label>
<label for="agent">{{ 'Agent'|trans }}</label>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
{# Ticket Mass Action #}
<div class="uv-action-bar-col-lt" style="display: none">
<!-- Mass action -->
<div class="mass-action">
<div class="property-block">
{# Update Assigned Support Agent #}
{% if user_service.isAccessAuthorized('ROLE_AGENT_ASSIGN_TICKET') %}
<div class="uv-dropdown">
<div class="uv-dropdown-btn uv-vertical-align uv-margin-right-5">{{ 'Agent'|trans }}</div>
<div class="uv-dropdown-list uv-bottom-left">
<div class="uv-dropdown-container">
<label>{{ 'Agent'|trans }}</label>
<div class="uv-search-sm">
<input type="text" class="uv-search-field" placeholder="Search">
</div>
</div>
<ul class="uv-agents-list agent" data-action="agent">
<li data-index="-1">
{{ 'Not Assigned'|trans }}
</li>
{% for agent in user_service.getAgentPartialDataCollection() %}
<li data-index="{{ agent.id }}">
{% if agent.smallThumbnail != null %}
<img src="{{ app.request.scheme ~'://' ~ app.request.httpHost ~ asset('') }}{{ agent.smallThumbnail }}"/>
{% else %}
<img src="{{ asset(default_agent_image_path) }}" alt=""/>
{% endif %}
{{ agent.name }}
</li>
{% endfor %}
</ul>
</div>
</div>
{% endif %}
{# Update Assigned Support Group #}
{% if user_service.isAccessAuthorized('ROLE_AGENT_ASSIGN_TICKET_GROUP') %}
<div class="uv-dropdown">
<div class="uv-dropdown-btn uv-vertical-align uv-margin-right-5">{{ 'Group'|trans }}</div>
<div class="uv-dropdown-list uv-bottom-left">
<div class="uv-dropdown-container">
<label>{{ 'Group'|trans }}</label>
<div class="uv-search-sm">
<input type="text" class="uv-search-field" placeholder="Search">
</div>
</div>
<ul class="uv-search-list group" data-action="group">
{% for group in user_service.getSupportGroups() %}
<li data-index="{{ group.id }}"><a href="#">{{ group.name }}</a></li>
{% endfor %}
</ul>
</div>
</div>
{% endif %}
{# Update Assigned Support Team #}
{% if user_service.isAccessAuthorized('ROLE_AGENT_ASSIGN_TICKET_GROUP') %}
<div class="uv-dropdown">
<div class="uv-dropdown-btn uv-vertical-align uv-margin-right-5">{{ 'Team'|trans }}</div>
<div class="uv-dropdown-list uv-bottom-left">
<div class="uv-dropdown-container">
<label>{{ 'Team'|trans }}</label>
<div class="uv-search-sm">
<input type="text" class="uv-search-field" placeholder="Search">
</div>
</div>
<ul class="uv-search-list team" data-action="team">
{% for team in user_service.getSupportTeams() %}
<li data-index="{{ team.id }}"><a href="#">{{ team.name }}</a></li>
{% endfor %}
</ul>
</div>
</div>
{% endif %}
{# Update Ticket Status #}
{% if user_service.isAccessAuthorized('ROLE_AGENT_UPDATE_TICKET_STATUS') %}
<div class="uv-dropdown">
<div class="uv-dropdown-btn uv-vertical-align uv-margin-right-5">{{ 'Status'|trans }}</div>
<div class="uv-dropdown-list uv-bottom-left">
<div class="uv-dropdown-container">
<label>{{ 'Status'|trans }}</label>
<ul class="status" data-action="status">
{% for status in ticketStatusCollection %}
<li data-index="{{ status.id }}">
<a href="#" >{{ status.description|trans }}</a>
</li>
{% endfor %}
</ul>
</div>
</div>
</div>
{% endif %}
{# Update Ticket Type #}
{% if user_service.isAccessAuthorized('ROLE_AGENT_UPDATE_TICKET_TYPE') %}
<div class="uv-dropdown">
<div class="uv-dropdown-btn uv-vertical-align uv-margin-right-5">{{ 'Type'|trans }}</div>
<div class="uv-dropdown-list uv-bottom-left">
<div class="uv-dropdown-container">
<label>{{ 'Type'|trans }}</label>
<div class="uv-search-sm">
<input type="text" class="uv-search-field" placeholder="{{ 'Search'|trans }}">
</div>
</div>
<ul class="uv-search-list type" data-action="type">
{% for type in ticketTypeCollection %}
<li data-index="{{ type.id }}"><a href="#">{{ type.description }}</a></li>
{% endfor %}
</ul>
</div>
</div>
{% endif %}
{# Update Priority #}
{% if user_service.isAccessAuthorized('ROLE_AGENT_UPDATE_TICKET_PRIORITY') %}
<div class="uv-dropdown">
<div class="uv-dropdown-btn uv-vertical-align uv-margin-right-5">{{ 'Priority'|trans }}</div>
<div class="uv-dropdown-list uv-bottom-left">
<div class="uv-dropdown-container">
<label>{{ 'Priority'|trans }}</label>
<ul class="priority" data-action="priority">
{% for priority in ticketPriorityCollection %}
<li data-index="{{ priority.id }}"><a href="#">{{ priority.description|trans }}</a></li>
{% endfor %}
</ul>
</div>
</div>
</div>
{% endif %}
{# Update Label #}
<div class="uv-dropdown">
<div class="uv-dropdown-btn uv-vertical-align uv-margin-right-5">{{ 'Label'|trans }}</div>
<div class="uv-dropdown-list uv-bottom-left">
<div class="uv-dropdown-container">
<label>{{ 'Label'|trans }}</label>
<div class="uv-search-sm">
<input type="text" class="uv-search-field" placeholder="Search">
</div>
</div>
<ul class="uv-search-list label" data-action="label"></ul>
</div>
</div>
{# Trashe Tickets #}
{% if user_service.isAccessAuthorized('ROLE_AGENT_DELETE_TICKET') %}
<a class="uv-btn-stroke uv-margin-right-5" id="mass-delete" data-action="trashed" style="margin-left: 5px;">{{ 'Delete'|trans }}</a>
{% endif %}
</div>
{# For Trashed Tickets #}
<div class="trashed-block" style="display: none">
{# Restore Tickets #}
{% if user_service.isAccessAuthorized('ROLE_AGENT_RESTORE_TICKET') %}
<a class="uv-btn-stroke uv-margin-right-5" id="mass-restore" data-action="restore" style="margin-left: 5px;">{{ 'Restore'|trans }}</a>
{% endif %}
{# Delete Tickets Forever #}
{% if user_service.isAccessAuthorized('ROLE_AGENT_DELETE_TICKET') %}
<a class="uv-btn-stroke uv-margin-right-5" id="mass-delete-forever" data-action="delete" style="margin-left: 5px;">{{ 'Delete Forever'|trans }}</a>
{% endif %}
</div>
</div>
</div>
{# Ticket Search | Filter Extras #}
<div class="uv-action-bar-col-rt">
<!-- Search Tickets -->
<input type="text" class="uv-search-inline" placeholder="{{ 'Search'|trans }}">
<!-- Extra Filters -->
<div class="uv-btn-stroke uv-margin-left-15 filter-view-trigger" data-target="uv-filter-view"><span class="uv-icon-filter"></span>{{ 'Filter View'|trans }}</div>
</div>
</div>
</div>
{# Ticket List #}
<div class="uv-table uv-list-view">
<table>
<thead>
<tr>
<th class="uv-width-140"></th>
<th>{{ 'ID'|trans }}</th>
<th class="uv-min-width-300" data-index="subject">{{ 'Subject'|trans }}</th>
<th class="uv-min-width-300" data-index="reference">{{ 'Reference'|trans }}</th>
<th data-index="customer-name">{{ 'Customer Name'|trans }}</th>
<th data-index="customer-email">{{ 'Customer Email'|trans }}</th>
<th data-index="timestamp">{{ 'Timestamp'|trans }}</th>
<th data-index="group">{{ 'Group'|trans }}</th>
<th data-index="team">{{ 'Team'|trans }}</th>
<th data-index="type1">{{ 'Type'|trans }}</th>
<th data-index="replies">{{ 'Replies'|trans }}</th>
<th data-index="agent">{{ 'Agent'|trans }}</th>
</tr>
</thead>
<tbody></tbody>
</table>
<div class="navigation"></div>
</div>
</div>
{# Extra Filters #}
<div class="uv-filter-view" id="uv-filter-view">
{# Filter Head #}
<div class="uv-filter-head">
<div class="uv-filter-title">
<h6>{{ 'Tickets'|trans }}</h6>
<span>{{ 'Save set of filters as a preset to stay more productive'|trans }}</span>
</div>
<div class="uv-filter-toggle" id="filter-close-trigger"><span></span></div>
</div>
{# Filter Content #}
<div class="uv-filter-paper">
{# Filters #}
<div class="uv-filter-options">
<script>
var userFilters = {};
</script>
{# Saved Filters #}
<div class="uv-element-block" style="border-bottom: 1px solid #D3D3D3; padding-bottom: 5px;">
<label class="uv-field-label">{{ 'Saved Filters'|trans }}</label>
<div class="uv-field-block">
<div class="uv-customize-wrapper">
<select class="uv-select uv-select-70" id="saved-filter">
{% set filters = app.user.agentInstance.userSavedFilters %}
{% if filters|length %}
<option value="">-- Saved Filter --</option>
{% for userFilter in filters %}
<option value="{{userFilter.id}}">{{userFilter.name}}</option>
{% endfor %}
{% else %}
<option value="">{{ 'No saved filter created'|trans }}</option>
{% endif %}
</select>
{% for userFilter in app.user.agentInstance.userSavedFilters %}
<script>
{% set isDefault = 0 %}
{% if app.user.agentInstance.defaultFiltering == userFilter.id %}
{% set isDefault = 1 %}
{% endif %}
userFilters[{{userFilter.id}}] = {{ {'id': userFilter.id, 'name': userFilter.name, 'route': userFilter.route, 'is_default': isDefault}|json_encode|raw }};
</script>
{% endfor %}
<span class="uv-customize" style="display: none" data-toggle="tooltip" title="{{ 'Edit Saved Filter'|trans }}"></span>
</div>
</div>
</div>
{% set filterContext = {} %}
{# agent #}
<div class="uv-element-block">
<label class="uv-field-label">{{ 'Agent'|trans }}</label>
<div class="uv-field-block" id="agent-filter">
<input class="uv-field uv-dropdown-other preloaded" type="text" data-filter-type="agent" id="agent-filter-input">
<div class="uv-dropdown-list uv-bottom-left">
<div class="uv-dropdown-container">
<label>{{ 'Filter With'|trans }}</label>
</div>
<ul class="uv-agents-list">
{% set options = [] %}
{% for agent in user_service.getAgentsPartialDetails %}
{% set options = options|merge([{'id': agent.id, 'name': agent.name}]) %}
<li data-id="{{agent.id}}">
{% if agent.smallThumbnail != null %}
<img src="{{ app.request.scheme ~'://' ~ app.request.httpHost ~ asset('') }}{{ agent.smallThumbnail }}"/>
{% else %}
<img src="{{ asset(default_agent_image_path) }}"/>
{% endif %}
{{agent.name}}
</li>
{% endfor %}
<li class="uv-no-results" style="display: none;">
{{ 'No result found'|trans }}
</li>
{% set filterContext = filterContext|merge({'agent':options}) %}
</ul>
</div>
<div class="uv-filtered-tags"></div>
</div>
</div>
<div class="uv-element-block">
<label class="uv-field-label">{{ 'Customer'|trans }}</label>
<div class="uv-field-block" id="customer-filter">
<input class="uv-field uv-dropdown-other" type="text" data-filter-type="customer" id="customer-filter-input">
<div class="uv-dropdown-list uv-bottom-left">
<div class="uv-dropdown-container">
<label>{{ 'Filter With'|trans }}</label>
</div>
<ul class="uv-agents-list">
<li class="uv-filter-info">
{{ 'Type atleast 2 letters'|trans }}
</li>
<li class="uv-no-results" style="display: none;">
{{ 'No result found'|trans }}
</li>
</ul>
</div>
<div class="uv-filtered-tags"></div>
</div>
</div>
<div class="uv-element-block">
<label class="uv-field-label">{{ 'Group'|trans }}</label>
<div class="uv-field-block" id="group-filter">
<input class="uv-field uv-dropdown-other preloaded" type="text" data-filter-type="group" id="group-filter-input">
<div class="uv-dropdown-list uv-bottom-left">
<div class="uv-dropdown-container">
<label>{{ 'Filter With'|trans }}</label>
<ul class="">
{% set options = [] %}
{% for group in user_service.getSupportGroups() %}
{% set options = options|merge([{'id': group.id, 'name': group.name}]) %}
<li data-id="{{group.id}}">
{{group.name}}
</li>
{% endfor %}
<li class="uv-no-results" style="display: none;">
{{ 'No result found'|trans }}
</li>
{% set filterContext = filterContext|merge({'group':options}) %}
</ul>
</div>
</div>
<div class="uv-filtered-tags"></div>
</div>
</div>
<div class="uv-element-block">
<label class="uv-field-label">{{ 'Team'|trans }}</label>
<div class="uv-field-block" id="team-filter">
<input class="uv-field uv-dropdown-other preloaded" type="text" data-filter-type="team" id="team-filter-input">
<div class="uv-dropdown-list uv-bottom-left">
<div class="uv-dropdown-container">
<label>{{ 'Filter With'|trans }}</label>
<ul class="">
{% set options = [] %}
{% for team in user_service.getSupportTeams() %}
{% set options = options|merge([{'id': team.id, 'name': team.name}]) %}
<li data-id="{{team.id}}">
{{team.name}}
</li>
{% endfor %}
<li class="uv-no-results" style="display: none;">
{{ 'No result found'|trans }}
</li>
{% set filterContext = filterContext|merge({'team':options}) %}
</ul>
</div>
</div>
<div class="uv-filtered-tags"></div>
</div>
</div>
<div class="uv-element-block">
<label class="uv-field-label">{{ 'Type'|trans }}</label>
<div class="uv-field-block" id="type-filter">
<input class="uv-field uv-dropdown-other preloaded" type="text" data-filter-type="type" id="type-filter-input">
<div class="uv-dropdown-list uv-bottom-left">
<div class="uv-dropdown-container">
<label>{{ 'Filter With'|trans }}</label>
<ul class="">
{% set options = [] %}
{% for type in ticket_service.getTypes() %}
{% set options = options|merge([{'id': type.id, 'name': type.name}]) %}
<li data-id="{{type.id}}">
{{type.name}}
</li>
{% endfor %}
<li class="uv-no-results" style="display: none;">
{{ 'No result found'|trans }}
</li>
{% set filterContext = filterContext|merge({'type':options}) %}
</ul>
</div>
</div>
<div class="uv-filtered-tags"></div>
</div>
</div>
<div class="uv-element-block">
<label class="uv-field-label">{{ 'Priority'|trans }}</label>
<div class="uv-field-block" id="priority-filter">
<input class="uv-field uv-dropdown-other preloaded" type="text" data-filter-type="priority" id="priority-filter-input">
<div class="uv-dropdown-list uv-bottom-left">
<div class="uv-dropdown-container">
<label>{{ 'Filter With'|trans }}</label>
<ul class="">
{% set options = [] %}
{% for priority in ticket_service.getPriorities() %}
{% set options = options|merge([{'id': priority.id, 'name': priority.code, 'color': priority.colorCode}]) %}
<li data-id="{{priority.id}}">
{{ priority.code|trans }}
</li>
{% endfor %}
<li class="uv-no-results" style="display: none;">
{{ 'No result found'|trans }}
</li>
{% set filterContext = filterContext|merge({'priority':options}) %}
</ul>
</div>
</div>
<div class="uv-filtered-tags"></div>
</div>
</div>
<div class="uv-element-block">
<label class="uv-field-label">{{ 'Tag'|trans }}</label>
<div class="uv-field-block" id="tag-filter">
<input class="uv-field uv-dropdown-other" type="text" data-filter-type="tag" id="tag-filter-input">
<div class="uv-dropdown-list uv-bottom-left">
<div class="uv-dropdown-container">
<label>{{ 'Filter With'|trans }}</label>
<ul class="">
<li class="uv-filter-info">
{{ 'Type atleast 2 letters'|trans }}
</li>
<li class="uv-no-results" style="display: none;">
{{ 'No result found'|trans }}
</li>
</ul>
</div>
</div>
<div class="uv-filtered-tags"></div>
</div>
</div>
<div class="uv-element-block">
<label class="uv-field-label">{{ 'Source'|trans }}</label>
<div class="uv-field-block" id="source-filter">
<input class="uv-field uv-dropdown-other preloaded" type="text" data-filter-type="source" id="source-filter-input">
<div class="uv-dropdown-list uv-bottom-left">
<div class="uv-dropdown-container">
<label>{{ 'Filter With'|trans }}</label>
<ul class="">
{% set options = [] %}
{% for key, source in ticket_service.getAllSources() %}
{% set options = options|merge([{'id': key, 'name': source}]) %}
<li data-id="{{key}}">
{{ source|trans }}
</li>
{% endfor %}
<li class="uv-no-results" style="display: none;">
{{ 'No result found'|trans }}
</li>
{% set filterContext = filterContext|merge({'source': options}) %}
</ul>
</div>
</div>
<div class="uv-filtered-tags"></div>
</div>
</div>
<div class="uv-element-block">
<label class="uv-field-label">{{ 'Before'|trans }}</label>
<div class="uv-field-block range" id="before-filter">
<input class="uv-field uv-date-picker" type="text" data-filter-type="before" id="before-filter-input">
</div>
</div>
<div class="uv-element-block">
<label class="uv-field-label">{{ 'After'|trans }}</label>
<div class="uv-field-block range" id="after-filter">
<input class="uv-field uv-date-picker" type="text" data-filter-type="after" id="after-filter-input">
</div>
</div>
<div class="uv-element-block">
<label class="uv-field-label">{{ 'Replies less than'|trans }}</label>
<div class="uv-field-block" id="reply-filter">
<input class="uv-field" type="number" min="1" data-filter-type="replies-less" id="repliesLess-filter-input">
</div>
</div>
<div class="uv-element-block">
<label class="uv-field-label">{{ 'Replies more than'|trans }}</label>
<div class="uv-field-block" id="reply-filter">
<input class="uv-field" type="number" min="0" data-filter-type="replies-more" id="repliesMore-filter-input">
</div>
</div>
<div class="uv-action-buttons">
</div>
{# Clear Filters #}
<a class="uv-btn-remove" href="#"><span class="uv-icon-discard"></span> {{ 'Clear All'|trans }}</a>
</div>
{# Add|Edit Filter #}
<div class="uv-filter-edit" style="display: none;"></div>
</div>
<script type="text/javascript">
var filterContext = {{ filterContext|json_encode|raw }}
</script>
</div>
</div>
{% endblock %}
{% block footer %}
{{ parent() }}
{# Sort Ticket View Template #}
<script id="ticket_list_sorting_tmp" type="text/template">
<li class="<% if(sort == 'ticket.id') { %>uv-drop-list-active<% } %>">
<a href="#<% if(queryString != '') { %><%= queryString %>/<% } %><% if(page) { %>page/<%= page %><% } else { %>page/1<% } %>/sort/ticket.id/<% if(sort == 'ticket.id') { %><% if(direction) { %>direction/<%= direction %><% } else { %>direction/desc<% } %><% } else { %>direction/asc<% } %>" data-field="ticket.id">
{% trans %}Ticket Id{% endtrans %}
<% if(sort == 'ticket.id') { %>
<span class="uv-sorting <% if(direction == 'asc') { %> descend <% } else { %> ascend <% } %>"></span>
<% } %>
</a>
</li>
<li class="<% if(sort == 'ticket.updatedAt') { %>uv-drop-list-active<% } %>">
<a href="#<% if(queryString != '') { %><%= queryString %>/<% } %><% if(page) { %>page/<%= page %><% } else { %>page/1<% } %>/sort/ticket.updatedAt/<% if(sort == 'ticket.updatedAt') { %><% if(direction) { %>direction/<%= direction %><% } else { %>direction/desc<% } %><% } else { %>direction/asc<% } %>" data-field="ticket.updatedAt">
{% trans %}Last Replied{% endtrans %}
<% if(sort == 'ticket.updatedAt') { %>
<span class="uv-sorting <% if(direction == 'asc') { %> descend <% } else { %> ascend <% } %>"></span>
<% } %>
</a>
</li>
<li class="<% if(sort == 'agentName') { %>uv-drop-list-active<% } %>">
<a href="#<% if(queryString != '') { %><%= queryString %>/<% } %><% if(page) { %>page/<%= page %><% } else { %>page/1<% } %>/sort/agentName/<% if(sort == 'agentName') { %><% if(direction) { %>direction/<%= direction %><% } else { %>direction/desc<% } %><% } else { %>direction/asc<% } %>" data-field="agentName">
{% trans %}Assign To{% endtrans %}
<% if(sort == 'agentName') { %>
<span class="uv-sorting <% if(direction == 'asc') { %> descend <% } else { %> ascend <% } %>"></span>
<% } %>
</a>
</li>
<li class="<% if(sort == 'customerEmail') { %>uv-drop-list-active<% } %>">
<a href="#<% if(queryString != '') { %><%= queryString %>/<% } %><% if(page) { %>page/<%= page %><% } else { %>page/1<% } %>/sort/customerEmail/<% if(sort == 'customerEmail') { %><% if(direction) { %>direction/<%= direction %><% } else { %>direction/desc<% } %><% } else { %>direction/asc<% } %>" data-field="customerEmail">
{% trans %}Customer Email{% endtrans %}
<% if(sort == 'customerEmail') { %>
<span class="uv-sorting <% if(direction == 'asc') { %> descend <% } else { %> ascend <% } %>"></span>
<% } %>
</a>
</li>
<li class="<% if(sort == 'customerName') { %>uv-drop-list-active<% } %>">
<a href="#<% if(queryString != '') { %><%= queryString %>/<% } %><% if(page) { %>page/<%= page %><% } else { %>page/1<% } %>/sort/customerName/<% if(sort == 'customerName') { %><% if(direction) { %>direction/<%= direction %><% } else { %>direction/desc<% } %><% } else { %>direction/asc<% } %>" data-field="customerName">
{% trans %}Customer Name{% endtrans %}
<% if(sort == 'customerName') { %>
<span class="uv-sorting <% if(direction == 'asc') { %> descend <% } else { %> ascend <% } %>"></span>
<% } %>
</a>
</li>
</script>
{# Ticket Status List Template #}
<script id="ticket_status_list_tmp" type="text/template">
<ul class="status-list">
{% for status in ticketStatusCollection %}
{#} {% if status.id== 1 or status.id== 3 or status.id== 5 %}{#}
<li>
<a href="#"
class="<% if(active == {{ status.id }} {% if status.id == 1 %} || active == 0{% endif %}) { %>uv-aside-nav-active<% } %>" data-id="{{ status.id }}">
<% if(status && status[1] != undefined && status[{{ status.id }}] > 0 && ( {{ status.id }} === 7 || {{ status.id }} === 8 ) ) { %>
<span class="name" style="background-color: #f10808;color: white;">{{ status.description|trans }}</span>
<% } else { %>
<span class="name">{{ status.description|trans }}</span>
<% } %>
<span class="uv-flag-gray">
<% if(status && status[1] != undefined) { %>
<%= status[{{ status.id }}] %>
<% } else { %>
0
<% } %>
</span>
</a>
</li>
{#} {% endif %}{#}
{% endfor %}
</ul>
</script>
{# Default Ticket Label View Template #}
<script id="predefined_label_tmp" type="text/template">
{% if user_service.isAccessAuthorized('ROLE_ADMIN') %}
<li>
<a href="#" <% if (active == '') { %> class="uv-aside-active" <% } %>>
{{ 'All'|trans }}
<span class="uv-flag-gray uv-flag-dark"><%= labelDetails.predefind.all %></span>
</a>
</li>
{#}
<li>
<a href="#new" <% if(active == 'new') { %> class="uv-aside-active" <% } %> >
{{ 'New'|trans }}
<span class="uv-flag-gray uv-flag-dark">
<%= labelDetails.predefind.new %>
</span>
</a>
</li>
<li>
<a href="#unassigned" <% if(active == 'unassigned') { %> class="uv-aside-active" <% } %> >
{{ 'UnAssigned'|trans }}
<span class="uv-flag-gray uv-flag-dark">
<%= labelDetails.predefind.unassigned %>
</span>
</a>
</li>
<li>
<a href="#notreplied" <% if(active == 'notreplied') { %> class="uv-aside-active" <% } %> >
{{ 'UnAnswered'|trans }}
<span class="uv-flag-gray uv-flag-dark">
<%= labelDetails.predefind.notreplied %>
</span>
</a>
</li>
<li>
<a href="#mine" <% if(active == 'mine') { %> class="uv-aside-active" <% } %> >
{{ 'My Tickets'|trans }}
<span class="uv-flag-gray uv-flag-dark">
<%= labelDetails.predefind.mine %>
</span>
</a>
</li>
<li>
<a href="#starred" <% if(active == 'starred') { %> class="uv-aside-active" <% } %> >
{{ 'Starred'|trans }}
<span class="uv-flag-gray uv-flag-dark">
<%= labelDetails.predefind.starred %>
</span>
</a>
</li>
<li>
<a href="#trashed" <% if(active == 'trashed') { %> class="uv-aside-active" <% } %>>
{{ 'Trashed'|trans }}
<span class="uv-flag-gray uv-flag-dark">
<%= labelDetails.predefind.trashed %>
</span>
</a>
</li>
{#}
{% else %}
<li>
<a href="#" <% if (active == '') { %> class="uv-aside-active" <% } %>>
{{ 'All'|trans }}
<span class="uv-flag-gray uv-flag-dark"><%= labelDetails.predefind.all %></span>
</a>
</li>
{# <li>
<a href="#mine" <% if(active == 'mine') { %> class="uv-aside-active" <% } %> >
{{ 'My Tickets'|trans }}
<span class="uv-flag-gray uv-flag-dark">
<%= labelDetails.predefind.mine %>
</span>
</a>
</li>#}
{% endif %}
</script>
{# Custom Ticket Label View Template #}
<script id="custom_label_tmp" type="text/template">
<a href="#label/<%= id %>" data-id="<%= id %>">
<%- name %>
<span class="uv-flag-gray" style="<% if(colorCode) { %>background-color:<%= colorCode %><% } %>">
<%= count %>
</span>
</a>
<span class="uv-customize" data-target="uv-task-view" data-toggle="tooltip" title="{{ 'Edit Label'|trans }}"></span>
</script>
{# Add|Edit Ticket Label View Template #}
<script id="add_edit_label_tmp" type="text/template">
<div class="uv-aside-head">
<div class="uv-aside-title">
<% if(id) { %>
<h6>{{ 'Edit Label'|trans }}</h6>
<% } else { %>
<h6>{{ 'Add Label'|trans }}</h6>
<% } %>
</div>
<div class="uv-aside-back" id="back-to-labels">
<span>{{ 'Back'|trans }}</span>
</div>
</div>
<div class="uv-aside-option" data-id="<%= id %>">
<div class="uv-element-block">
<label class="uv-field-label">{{ 'Name'|trans }}</label>
<div class="uv-field-block">
<input class="uv-field" type="text" value="<%- name %>" />
</div>
</div>
<div class="uv-element-block">
<label class="uv-field-label">{{ 'Choose a Color'|trans }}</label>
<div class="uv-field-block">
<% colors = ['#337CFF','#FEBF00','#E5549F','#27B6BB','#FB8A3F','#43AF52'] %>
<% for(var colorTemp in colors) { %>
<span class="uv-color-block <% if(colorCode == colors[colorTemp]) { %>uv-color-active<% } %>" data-color="<%- colors[colorTemp] %>" style="background:<%- colors[colorTemp] %>"></span>
<% } %>
</div>
</div>
<div>
<a class="uv-btn add-update-btn" href="#">
<% if(id) { %>
{{ 'Update'|trans }}
<% } else { %>
{{ 'Create'|trans }}
<% } %>
</a>
</div>
<% if(id) { %>
<a class="uv-btn-remove"><span class="uv-icon-discard"></span>{{ 'Remove Label'|trans }}</a>
<% } %>
</div>
</script>
{# Add|Edit Saved Ticket Filter View Template #}
<script id="add_edit_saved_filter_tmp" type="text/template">
<form>
<div class="uv-filter-edit-head">
<div class="uv-filter-edit-title">
<h6>
<% if(id) { %>
<input type="hidden" name="id" id="filter-id" value="<%= id %>"/>
{{ 'Edit Saved Filter'|trans }}
<% } else { %>
{{ 'New Saved Filter'|trans }}
<% } %>
</h6>
</div>
<div class="uv-filter-edit-back back-to-filter">
<span>{{ 'Back'|trans }}</span>
</div>
</div>
<div class="uv-element-block">
<label class="uv-field-label">{{ 'Name'|trans }}</label>
<div class="uv-field-block">
<input class="uv-field name" name="name" type="text" value="<%- name %>" />
</div>
</div>
<div class="uv-element-block">
<label>
<div class="uv-checkbox">
<input type="checkbox" name="is_default" <% if(is_default) { %>checked<% } %> />
<span class="uv-checkbox-view"></span>
</div>
<span class="uv-checkbox-label">{{ 'Is Default'|trans }}</span>
</label>
</div>
<div class="uv-filters-group">
<% _.each(filters, function(filter, key){ %>
<div class="uv-element-block" data-filter="<%= key %>">
<label class="uv-field-label"><%- filter.name %></label>
<div class="uv-field-block">
<% _.each(filter.options, function(option){ %>
<a class="uv-btn-tag" href="#" data-id="<%= option.id %>">
<%- option.name %>
<span class="uv-icon-remove-dark"></span>
</a>
<% }); %>
</div>
</div>
<% }); %>
<div class="uv-action-buttons">
<% if(id) { %>
<a class="uv-btn-remove"><span class="uv-icon-discard"></span>{{ 'Remove Saved Filter'|trans }}</a>
<% } %>
</div>
</div>
<div class="uv-action-buttons">
<a class="uv-btn <% if(id) { %>update-filter<% } else { %>save-filter<% } %>" href="#">
<% if(id) { %>
{{ 'Update'|trans }}
<% } else { %>
{{ 'Create'|trans }}
<% } %>
</a>
<a class="uv-btn back-to-filter" href="#">{{ 'Cancel'|trans }}</a>
</div>
</form>
</script>
{# Quick View Ticket View Template #}
<script id="ticket_quick_view_tmp" type="text/template">
<div class="uv-pull-right quick-view-navigation">
<div class="uv-loader" style="display: none">
<span></span>
<span></span>
<span></span>
</div>
<% if(previous) { %>
<span class="uv-btn-tag uv-icon-nav-pre" data-id="<%= previous %>">
</span>
<% } else { %>
<span class="uv-btn-tag uv-icon-nav-pre" disabled="disabled">
</span>
<% } %>
<% if(next) { %>
<span class="uv-btn-tag uv-icon-nav-nxt" data-id="<%= next %>">
</span>
<% } else { %>
<span class="uv-btn-tag uv-icon-nav-nxt" disabled="disabled">
</span>
<% } %>
</div>
<span class="uv-pop-up-close"></span>
<a href="<%= path %>"><h2>{{ 'Ticket Info'|trans }} #<%= id %></h2></a>
<div class="uv-pop-up-body uv-inner-section">
<div class="uv-view">
<div class="uv-ticket-head">
<div class="uv-ticket-strip">
<span>
<span class="uv-ticket-strip-label">
{{ 'Timestamp'|trans }} -
</span>
<span class="uv-margin-0">
<%= formatedCreatedAt %>
</span>
</span>
<span>
<span class="uv-ticket-strip-label">
{{ 'By'|trans }} -
</span>
<%- createThread.user.name %>
</span>
<% if(agent) { %>
<span class="agent-info" style="">
<span class="uv-ticket-strip-label">
{{ 'Agent'|trans }} -
</span>
<span class="name"><%- agent.name %></span>
</span>
<% } %>
</div>
<div class="uv-ticket-strip">
<span class="uv-btn-tag">
{{ 'Priority'|trans }}
- <%- priority.description %>
</span>
<span class="uv-btn-tag">
{{ 'Status'|trans }}
- <%- status.description %>
</span>
<% if(lastReplyAgentName) { %>
<span class="uv-btn-tag">
{{ 'Last Replied Agent'|trans }}
- <%- lastReplyAgentName.name.split(" ")[0] %>
</span>
<% } %>
</div>
</div>
<div class="uv-ticket-head">
<h1><%- subject %></h1>
</div>
<div class="uv-ticket-section">
<div class="uv-ticket-main create">
<div class="uv-ticket-strip">
<span>
<span class="uv-margin-0 timeago" data-timestamp="<%= createThread.timestamp %>" title="<%= createThread.formatedCreatedAt %>"><%= createThread.formatedCreatedAt %></span>
- <%- createThread.user.name %>
<span class="uv-ticket-strip-label">
{{ 'created Ticket'|trans }}
</span>
</span>
</div>
<div class="uv-ticket-main-lt">
<% if (createThread.user.smallThumbnail != null) { %>
<img class='border' src="{{ app.request.scheme ~'://' ~ app.request.httpHost ~ asset('') }}<%= createThread.user.smallThumbnail %>"/>
<% } else { %>
<% if (createThread.createdBy == 'customer') { %>
<img class='border' src="{{ asset(default_customer_image_path) }}"/>
<% } else { %>
<img class='border' src="{{ asset(default_agent_image_path) }}"/>
<% } %>
<% } %>
</div>
<div class="uv-ticket-main-rt">
<% if(createThread.createdBy == 'customer') { %>
<a href="{{ path('helpdesk_member_manage_customer_account') }}/<%= createThread.user.id %>" class="uv-ticket-member-name">
<% } else { %>
<% if(createThread.user) { %>
<a href="{{ path('helpdesk_member_account') }}/<%= createThread.user.id %>" class="uv-ticket-member-name">
<% } else { %>
<a class="uv-ticket-member-name">
<% } %>
<% } %>
<%- createThread.user.name %>
</a>
<div class="message">
<p>
<%= createThread.reply %>
</p>
</div>
<!-- Attachment Block -->
<% if(createThread.attachments.length) { %>
<div class="uv-ticket-uploads">
<h4>{{ 'Uploaded Files'|trans }}</h4>
<div class="uv-ticket-uploads-strip">
<% _.each(createThread.attachments, function(file) { %>
<a href="<%-file.downloadURL %>" target ="_blank" class="uv-ticket-uploads-brick uv-no-pointer-events" data-toggle="tooltip" title="<%- file.name %>">
<img src="<%-file.iconURL %>" class="uv-auto-pointer-events">
</a>
<% }) %>
</div>
<% if(createThread.attachments.length >1) { %>
<div class="thread-attachments-zip pull-left">
<div class="uv-upload-actions">
<a href="{{ path('helpdesk_member_ticket_download_attachment_zip') }}/<%= createThread.id %>" target="_blank"><span class="uv-icon-attachment"></span> {{ 'Download (as .zip)'|trans }}</a>
</div>
</div>
<% } %>
</div>
<% } %>
<!-- //Attachment Block -->
</div>
</div>
<% if(lastReply) { %>
<div class="uv-ticket-main">
<div class="uv-ticket-strip">
<span>
<span class="uv-margin-0 timeago" data-timestamp="<%= lastReply.timestamp %>" title="<%= lastReply.formatedCreatedAt %>"><%= lastReply.formatedCreatedAt %></span>
- <%- lastReply.user.name %>
<span class="uv-ticket-strip-label">
{{ 'made last reply'|trans }}
</span>
</span>
</div>
<div class="uv-ticket-main-lt">
<% if (lastReply.user.smallThumbnail != null) { %>
<img class='border' src="{{ app.request.scheme ~'://' ~ app.request.httpHost ~ asset('') }}<%= lastReply.user.smallThumbnail %>"/>
<% } else { %>
<% if (lastReply.createdBy == 'customer') { %>
<img class='border' src="{{ asset(default_customer_image_path) }}"/>
<% } else { %>
<img class='border' src="{{ asset(default_agent_image_path) }}"/>
<% } %>
<% } %>
</div>
<div class="uv-ticket-main-rt">
<% if(lastReply.createdBy == 'customer') { %>
<a href="{{ path('helpdesk_member_manage_customer_account') }}/<%= lastReply.user.id %>" class="uv-ticket-member-name">
<% } else { %>
<% if(lastReply.user) { %>
<a href="{{ path('helpdesk_member_account') }}/<%= lastReply.user.id %>" class="uv-ticket-member-name">
<% } else { %>
<a class="uv-ticket-member-name">
<% } %>
<% } %>
<%- lastReply.user.name %>
</a>
<div class="message">
<p>
<%= lastReply.reply %>
</p>
</div>
<!-- Attachment Block -->
<% if(lastReply.attachments.length) { %>
<div class="uv-ticket-uploads">
<h4>{{ 'Uploaded Files'|trans }}</h4>
<div class="uv-ticket-uploads-strip">
<% _.each(lastReply.attachments, function(file) { %>
<a href="<%-file.downloadURL %>" target ="_blank" class="uv-ticket-uploads-brick uv-no-pointer-events" data-toggle="tooltip" title="<%- file.name %>">
<img src="<%-file.iconURL %>" class="uv-auto-pointer-events">
</a>
<% }) %>
</div>
<% if(lastReply.attachments.length> 1) { %>
<div class="thread-attachments-zip pull-left">
<div class="uv-upload-actions">
<a href="{{ path('helpdesk_member_ticket_download_attachment_zip') }}/<%= lastReply.id %>" target="_blank"><span class="uv-icon-attachment"></span> {{ 'Download (as .zip)'|trans }}</a>
</div>
</div>
<% } %>
</div>
<% } %>
<!-- //Attachment Block -->
</div>
</div>
<% } %>
</div>
</div>
</div>
</script>
{# Ticket List Item View Template #}
<script id="ticket_list_item_tmp" type="text/template">
<td class="uv-width-200 uv-no-content">
<span class="uv-list-ticket-priority" style="<% if(priority) { %>background: <%=priority.colorCode %><% } %>;">
<%- priority.description %>
</span>
<label class="uv-vertical-align uv-margin-right-5">
<div class="uv-checkbox">
<input type="checkbox" class="mass-action-checkbox" value="<%= id %>"/>
<span class="uv-checkbox-view"></span>
</div>
</label>
<% if(customer.esUltra) { %>
<span style="font-size:10px;background:gray;color:white;padding:2px;margin:2px;border-radius:5px;">
<%- customer.esUltra ? 'U':'' %>
</span>
<% } %>
<% if(customer.timezone) { %>
<span style="font-size:10px;background:gray;color:white;padding:2px;margin:2px;border-radius:5px;">
<%- customer.timezone %>
</span>
<% } %>
</td>
<td data-value="{{ 'ID'|trans }}" class="uv-width-100">
<a href="<%= path %>">
#<%= id %>
</a>
</td>
<td style="<%- subtype?.code === 'Incident with signal reception' ? 'background: red;' : '' %>" data-index="subject" role="tooltip" data-placement="bottom" title=" <%- lastReply && lastReply.length <= 300 ? lastReply : lastReply.substr(0, 300) + '...' %>" data-value="{{ 'Subject'|trans }}">
<a href="<%= path %>">
<%- subject && subject.length <= 300 ? subject : subject.substr(0, 300) + '...' %>
</a>
</td>
<td data-index="reference" role="tooltip" data-placement="bottom" title=" <%- lastReply && lastReply.length <= 300 ? lastReply : lastReply.substr(0, 300) + '...' %>" data-value="{{ 'Reference'|trans }}">
<a href="<%= path %>">
<%- reference %>
</a>
</td>
<td data-value="{{ 'Customer Name'|trans }}" data-index="customer-name">
<a href="<%= path %>">
<%- customer.name %>
</a>
</td>
<td data-value="{{ 'Customer Email'|trans }}" data-index="customer-email">
<a href="<%= path %>">
<%- customer.email %>
</a>
</td>
<td data-value="{{ 'Timestamp'|trans }}" data-index="timestamp">
<a href="<%= path %>" class="timeago" data-timestamp="<%= timestamp %>" title="<%= formatedCreatedAt %>">
<%= formatedCreatedAt %>
</a>
</td>
<td data-value="{{ 'Group'|trans }}" data-index="group">
<a href="<%= path %>">
<% if(group) { %>
<%- group %>
<% } else { %>
{{ 'N/A'|trans }}
<% } %>
</a>
</td>
<td data-value="{{ 'Team'|trans }}" data-index="team">
<a href="<%= path %>">
<% if(team) { %>
<%- team %>
<% } else { %>
{{ 'N/A'|trans }}
<% } %>
</a>
</td>
<td data-value="{{ 'Type'|trans }}" data-index="type1">
<a href="<%= path %>">
<% if(type) { %>
<%- type %>
<% } else { %>
{{ 'N/A'|trans }}
<% } %>
</a>
</td>
<td data-value="{{ 'Replies'|trans }}" data-index="replies">
<a href="<%= path %>">
<%= totalThreads %>
</a>
</td>
<td data-value="{{ 'Agent'|trans }}" data-index="agent">
<a href="<%= path %>">
<% if(agent) { %>
<% if(agent.smallThumbnail != null) { %>
<img src="{{ app.request.scheme ~'://' ~ app.request.httpHost ~ asset('') }}<%= agent.smallThumbnail %>" alt=""/>
<% } else { %>
<img src="{{ asset(default_agent_image_path) }}" alt=""/>
<% } %>
<%- agent.name %>
<% } else { %>
{{ 'Unassigned'|trans }}
<% } %>
</a>
</td>
</script>
<script type="text/javascript">
refresh();
function refresh(){
function reload() {
location.reload()
}
setInterval(reload, 60000);
};
var isPageJustLoaded = true;
var globalMessageResponse = "";
var currentUserId = "{{ user_service.getCurrentUser().id }}";
var pathToTicket = "{{ path('helpdesk_member_ticket', {'ticketId': 'replaceId' }) }}";
$(() => {
$('#before-filter-input').datetimepicker({
format: 'DD-MM-YYYY',
maxDate: 'now',
useCurrent: false,
});
$('#after-filter-input').datetimepicker({
format: 'DD-MM-YYYY',
maxDate: 'now',
useCurrent: false,
});
// Ticket Model
var TicketModel = Backbone.Model.extend({
idAttribute: "id",
defaults: {
path: "",
},
urlRoot: "{{ path('helpdesk_member_ticket_xhr') }}"
});
// Ticket Label Model
var LabelModel = Backbone.Model.extend({
idAttribute: "id",
defaults: {
count: 0,
},
parse: function (resp, options) {
return JSON.parse(resp.label);
},
urlRoot: "{{ path('helpdesk_member_ticket_label_xhr') }}"
});
// Ticket Quick View Model
var TicketQuickViewModel = Backbone.Model.extend({
idAttribute: "id",
defaults: {
path: "",
isSynced: false
}
});
// Side Filter Model
var SideFilterModel = Backbone.Model.extend({
updateModel: function(type,json) {
if(this.has(type)) {
context = this.get(type)
savedOptionsIds = [];
_.each(context, function (option) {
savedOptionsIds.push(parseInt(option.id))
})
if(jQuery.inArray(parseInt(json.id), savedOptionsIds) == -1) {
context.push(json);
this.set(type, context)
}
} else {
this.set(type, [json])
}
},
loadFilterOptions: function(data) {
var self = this;
$.ajax({
url : "{{ path('helpdesk_member_ticket_collection_load_filter_options_xhr') }}",
type : 'POST',
data: data,
dataType : 'json',
success : function(response) {
_.each(response,function(filter,key) {
_.each(filter, function (item) {
self.updateModel(key,item)
})
})
sideFilter.render();
},
error: function (xhr) {
if(url = xhr.getResponseHeader('Location'))
window.location = url;
}
});
}
});
// Ticket Label Collection
var LabelCollection = Backbone.Collection.extend({
model: LabelModel,
isLabelExist: function(labelName, labelId) {
var flag = 1;
_.each(this.models, function (item) {
if(item.get('name').toUpperCase() == labelName.toUpperCase() && item.id != labelId)
flag = 0;
}, this);
return flag;
}
});
// Ticket Collection
var TicketCollection = AppCollection.extend({
model: TicketModel,
url: "{{ path('helpdesk_member_ticket_collection_xhr') }}",
filterParameters: {
label: "",
new: "",
unassigned: "",
notreplied: "",
mine: "",
starred: "",
trashed: "",
label: "",
status: "",
search: "",
agent: "",
customer: "",
priority: "",
type: "",
group: "",
team: "",
tag: "",
mailbox : "",
source : "",
after: "",
before: "",
repliesLess: "",
repliesMore: "",
},
parseRecords: function (response, options) {
return response.tickets;
},
syncData: function() {
app.appView.showLoader();
$('.select-all-checkbox').prop('checked', false);
this.fetch({
data: this.getValidParameters(),
reset: true,
success: function(model, response) {
ticketQuickViewCollection.reset()
app.appView.hideLoader();
var ticketListView = new TicketList();
app.pager.paginationData = response.pagination;
var url = app.pager.paginationData.url;
if(ticketCollection.length == 0 && app.pager.paginationData.current != "0")
router.navigate(url.replace('replacePage', app.pager.paginationData.last),{trigger: true});
else {
app.pager.render();
statusListDetails = response.tabs;
labelDetails = response.labels;
labelListView.render();
}
if (globalMessageResponse) {
app.appView.renderResponseAlert(globalMessageResponse);
}
globalMessageResponse = null;
sideFilter.backToFilter()
},
error: function (model, xhr, options) {
app.appView.hideLoader();
if(url = xhr.getResponseHeader('Location'))
window.location = url;
}
});
},
batchOperation: function(data) {
var self = this;
app.appView.showLoader();
$.ajax({
url : "{{ path('helpdesk_member_ticket_collection_mass_action_xhr') }}",
type : 'POST',
data : {data : data},
dataType : 'json',
success : function(response) {
app.appView.hideLoader();
globalMessageResponse = response;
self.syncData();
},
error: function (xhr) {
if(url = xhr.getResponseHeader('Location'))
window.location = url;
var response = warningResponse;
if(xhr.responseJSON)
response = xhr.responseJSON;
app.appView.hideLoader();
app.appView.renderResponseAlert(response);
$('.mass-action-checkbox').prop('checked', false);
}
});
}
});
// Ticket Quick View Collection
var TicketQuickViewCollection = Backbone.Collection.extend({
model: TicketQuickViewModel,
isModelSynced: function(id) {
if (model = this.get(id)) {
if (parseInt(model.attributes.isSynced)) {
return model;
}
}
return false;
},
initialize: function() {
_.bindAll(this, 'getNextPrev', 'nextElement', 'previousElement');
},
getNextPrev : function(id) {
var data = {};
currentModel = ticketQuickViewCollection.get(id)
data['next'] = (model = this.nextElement(currentModel)) ? model.id : 0;
data['previous'] = (model = this.previousElement(currentModel)) ? model.id : 0;
return data;
},
nextElement: function(model) {
var index = ticketQuickViewCollection.indexOf(model);
if ((index + 1) === ticketQuickViewCollection.length)
return 0;
return ticketQuickViewCollection.at(index + 1);
},
previousElement: function(model) {
var index = ticketQuickViewCollection.indexOf(model);
if (index === 0 )
return 0;
return ticketQuickViewCollection.at(index - 1);
}
});
// Filter
var Filter = app.Filter.extend({
defaultSortIndex: 'ticket.updatedAt',
sortText: "{% trans %}Sort By:{% endtrans %} ",
defaultSortText: "{% trans %}Sort By:{% endtrans %} {% trans %}Last Replied{% endtrans %}",
template : _.template($("#ticket_list_sorting_tmp").html()),
events : {
'keyup .uv-search-inline' : 'search',
'change .asset-visibility input[type="checkbox"]': 'filterAssetsVisibility'
},
filterAssetsVisibilityOnLoad: function() {
if(localStorage.getItem('assets-visibility')) {
var assets = JSON.parse(localStorage.getItem('assets-visibility'));
$.each(assets, function(asset, assetVal) {
if(assetVal) {
$('span[data-index="' + asset + '"], td[data-index="' +asset + '"], th[data-index="' + asset + '"]').show()
$('#' + asset).prop('checked', true);
} else {
$('span[data-index="' + asset + '"], td[data-index="' +asset + '"], th[data-index="' + asset + '"]').hide()
$('#' + asset).prop('checked', false);
}
})
}
},
filterAssetsVisibility: function(e) {
var assets = {};
$('.asset-visibility input').each(function() {
var asset = $(this).val();
if($(this).is(':checked')) {
assets[asset] = 1;
$('span[data-index="' + asset + '"], td[data-index="' + asset + '"], th[data-index="' + asset + '"]').show()
} else {
assets[asset] = 0;
$('span[data-index="' + asset + '"], td[data-index="' + asset + '"], th[data-index="' + asset + '"]').hide()
}
});
localStorage.setItem('assets-visibility', JSON.stringify(assets));
},
search : _.debounce(function(e) {
this.collection.reset();
this.collection.state.currentPage = null;
this.collection.filterParameters.search = Backbone.$(e.target).val();
var queryString = app.appView.buildQuery($.param(this.collection.getValidParameters()));
router.navigate(queryString,{trigger: true});
}, 1000)
});
// Side Filter View
var SideFilter = Backbone.View.extend({
el: $(".uv-filter-view"),
isRecurrsiveCalls: 0,
isReadyFlag: 0,
appliedFilterOptions: {},
tempAppliedFilterOptions: {},
events: {
'change #saved-filter': 'applySavedFilter',
'input .uv-field-block input' : 'searchFilterOption',
'click .uv-dropdown-list li' : 'applyFilter',
'dp.change .range input': 'applyFilter',
'click .uv-filtered-tags .uv-btn-tag' : 'removeFilter',
'change .custom-filter' : 'filterByCustom',
'change #repliesLess-filter-input' : 'filterByRepliesLessThan',
'change #repliesMore-filter-input' : 'filterByRepliesMoreThan',
'keyup .search-custom, change .search-custom' : 'filterByCustom',
'click .new-saved-reply, .edit-saved-reply, .uv-filter-paper .uv-customize': 'addEditSavedReply',
'click .back-to-filter': 'backToFilter',
'click .uv-filter-edit .uv-btn-tag': 'removeSavedFilterOption',
'click .uv-filter-edit .save-filter, .uv-filter-edit .update-filter' : "saveSavedFilter",
'click .uv-filter-edit .uv-action-buttons .uv-btn-remove': 'removeSavedFilter'
},
loaderTemplate: _.template($("#loader-tmp").html()),
addEditSavedReplyTemplate: _.template($("#add_edit_saved_filter_tmp").html()),
checkOptionAvailable: function() {
this.isReadyFlag = 0;
var self = this;
var fetchOptions = {};
_.each(ticketCollection.filterParameters, function (filter,key) {
if(jQuery.inArray(key, ['customer','tag','label']) !== -1) {
if(filter != null && filter != '') {
filter = filter.split(',');
if(typeof fetchOptions[key] === 'undefined')
fetchOptions[key] = [];
savedOptionsIds = [];
if(sideFilterModel.has(key)) {
_.each(sideFilterModel.get(key), function (option) {
savedOptionsIds.push(parseInt(option.id))
})
}
_.each(filter, function (item) {
if(jQuery.inArray(parseInt(item), savedOptionsIds) == -1) {
fetchOptions[key].push(parseInt(item));
self.isReadyFlag = 1;
}
})
}
}
});
return fetchOptions;
},
render: function() {
fetchOptions = this.checkOptionAvailable();
if(this.isReadyFlag && !this.isRecurrsiveCalls) {
this.isReadyFlag = 0;
this.isRecurrsiveCalls = 1;
sideFilterModel.loadFilterOptions(fetchOptions)
} else {
var appliedFilterOptions = {};
$('.uv-filtered-tags').html("")
var self = this;
var displayFlag = 0;
_.each(ticketCollection.filterParameters, function (filter, key) {
if(jQuery.inArray(key, ['customer', 'agent', 'priority', 'type', 'group', 'team', 'tag', 'mailbox', 'source', 'after', 'before', 'repliesLess', 'repliesMore']) !== -1) {
if(filter != null && filter != '') {
displayFlag = 1;
filter = filter.split(',');
appliedFilterOptions[key] = {'name': key.charAt(0).toUpperCase() + key.slice(1)};
appliedFilterOptions[key]['options'] = [];
_.each(filter, function (value) {
if(key == 'after' || key == 'before' || key == 'repliesLess' || key == 'repliesMore') {
$("#" + key + "-filter-input").val(filter)
appliedFilterOptions[key]['options'].push({'id': filter, 'name': filter});
} else {
savedOptions = sideFilterModel.get(key)
_.each(savedOptions, function (item) {
if(item.id == value) {
appliedFilterOptions[key]['options'].push({'id': item.id, 'name': item.name});
parent = $('#'+key+'-filter')
parent.find('.uv-filtered-tags').append("<a class='uv-btn-tag' href='#' data-id='" + item.id + "'>" + item.name + "<span class='uv-icon-remove-dark'></span></a>")
parent.find('input').val('')
}
})
}
});
}
} else if(jQuery.inArray(key, ['new','unassigned','notreplied','mine','starred','trashed']) !== -1) {
if(filter != null && filter != '') {
displayFlag = 1;
appliedFilterOptions[key] = {'name': "{{ 'Label'|trans }}"};
appliedFilterOptions[key]['options'] = [];
var optionName = (key == 'mine') ? "{% trans %}Assigned to me{% endtrans %}" : key.charAt(0).toUpperCase() + key.slice(1);
appliedFilterOptions[key]['options'].push({'id': key, 'name': optionName});
} else {
if(!ticketCollection.filterParameters.new && !ticketCollection.filterParameters.unassigned && !ticketCollection.filterParameters.notreplied && !ticketCollection.filterParameters.mine && !ticketCollection.filterParameters.starred && !ticketCollection.filterParameters.trashed &&! ticketCollection.filterParameters.label) {
appliedFilterOptions['all'] = {'name': "{{ 'Label'|trans }}"};
appliedFilterOptions['all']['options'] = [];
appliedFilterOptions['all']['options'].push({'id': 1, 'name': "{{ 'All'|trans }}"});
}
}
} else if(key == 'label') {
if(filter != null && filter != '') {
displayFlag = 1;
var labelModel = labelCollection.get(filter);
appliedFilterOptions[key] = {'name': "{{ 'Label'|trans }}"};
appliedFilterOptions[key]['options'] = [];
if(labelModel) {
appliedFilterOptions[key]['options'] = [];
appliedFilterOptions[key]['options'].push({'id': labelModel.attributes.id, 'name': labelModel.attributes.name});
} else {
savedOptions = sideFilterModel.get(key)
_.each(savedOptions, function (item) {
if(item.id == filter) {
appliedFilterOptions[key]['options'].push({'id': item.id, 'name': item.name});
}
});
}
} else {
if(!ticketCollection.filterParameters.new && !ticketCollection.filterParameters.unassigned && !ticketCollection.filterParameters.notreplied && !ticketCollection.filterParameters.mine && !ticketCollection.filterParameters.starred && !ticketCollection.filterParameters.trashed &&! ticketCollection.filterParameters.label) {
appliedFilterOptions['all'] = {'name': "{{ 'Label'|trans }}"};
appliedFilterOptions['all']['options'] = [];
appliedFilterOptions['all']['options'].push({'id': 1, 'name': "{{ 'All'|trans }}"});
}
}
} else if(key == 'status') {
appliedFilterOptions[key] = {'name': "{{ 'Status'|trans }}"};
appliedFilterOptions[key]['options'] = []
if(filter != null && filter != '' && filter != 1) {
displayFlag = 1;
appliedFilterOptions[key]['options'].push({'id': filter, 'name': $(".status-list li a[data-id='" + filter + "'] .name").text().trim()});
} else {
appliedFilterOptions[key]['options'].push({'id': 1,'name': "{{ 'Open'|trans }}"});
}
} else if(key == 'search') {
if(filter != null && filter != '') {
displayFlag = 1;
appliedFilterOptions[key] = {'name': "{{ 'Search Query'|trans }}"};
appliedFilterOptions[key]['options'] = [];
appliedFilterOptions[key]['options'].push({'id': filter, 'name': filter});
}
} else if(key == 'custom') {
if(filter != null && filter != '') {
self.$el.find('[data-filter="custom"]').remove();
displayFlag = 1;
var realKey = key;
var checkBoxStore = Array();
var dataValueValueSeprator = '_';
var columnSeperator = '|';
var multiOptions = filter.split(columnSeperator);
var multiKeyValue, multiKeyValueValue, ele, newEle;
_.each(multiOptions, function(valueData, indexData) {
if(!valueData)
return;
multiKeyValue = valueData.split(dataValueValueSeprator);
multiKeyValueValue = multiKeyValue[1].split(',');
eleSelector = '[data-value="' + multiKeyValue[0] + '"]';
ele = $(eleSelector);
if(ele[0].type == 'radio') {
var dataValue = multiKeyValue[0];
name = ele.parents('.uv-element-block:not(.radio)').find('label:first').text().trim()
value = $(eleSelector + '[value="' + multiKeyValue[1] + '"]').parent().next().text();
appliedFilterOptions['z-'+dataValue] = {'name': name, 'type': 'radio'};
appliedFilterOptions['z-'+dataValue]['options'] = [];
appliedFilterOptions['z-'+dataValue]['options'].push({'id': multiKeyValue[1], 'name': value});
} else if(ele[0].type == 'checkbox') {
var dataValue = multiKeyValue[0];
if($.inArray(dataValue, checkBoxStore) >= 0)
return;
checkBoxStore.push(dataValue);
name = ele.parents('.uv-element-block:not(.checkbox)').find('label:first').text().trim()
appliedFilterOptions['z-'+dataValue] = {'name': name, 'type': 'checkbox'};
appliedFilterOptions['z-'+dataValue]['options'] = [];
var optionName, optionValue;
_.each(multiKeyValueValue, function(value) {
newEle = $(eleSelector + '[value="' + value + '"]')
optionValue = dataValue + dataValueValueSeprator + newEle.val();
optionName = newEle.parent().next().text();
if(optionValue && optionName) {
appliedFilterOptions['z-'+dataValue]['options'].push({'id': value, 'name': optionName});
}
});
} else if(ele[0].type == 'select-multiple') {
var dataValue = multiKeyValue[0];
filter = multiKeyValueValue;
key = ele.attr('id');
name = ele.parents('.uv-element-block').find('label:first').text().trim()
appliedFilterOptions['z-'+dataValue] = {'name': name, 'type': 'select-multiple'};
appliedFilterOptions['z-'+dataValue]['options'] = [];
_.each(filter, function (value) {
var optionName;
if(optionName = $("#"+key+" option[value='" + value + "']").text()) {
appliedFilterOptions['z-'+dataValue]['options'].push({'id': value, 'name': optionName});
}
});
} else if(ele[0].type == 'text' || ele[0].type == 'number') {
filter = multiKeyValue[1];
if(filter != null && filter != '') {
filter = filter.replace(/\+/g,' ');
displayFlag = 1;
var dataValue = ele.attr('data-value');
name = ele.parents('.uv-element-block').find('label:first').text().trim()
appliedFilterOptions['z-'+dataValue] = {'name': name, 'type': ele[0].type};
appliedFilterOptions['z-'+dataValue]['options'] = [];
appliedFilterOptions['z-'+dataValue]['options'].push({'id': 1, 'name': filter});
}
}
})
}
}
if('after' == key || 'before' == key || 'repliesLess' == key || 'repliesMore' == key) {
$('#'+ key +'-filter-input').val(filter);
}
})
if(displayFlag) {
self.$el.find('.uv-filter-options .uv-action-buttons').html("")
if($("#saved-filter").val() != null && $("#saved-filter").val() != '' && Backbone.history.getFragment() == userFilters[$("#saved-filter").val()]['route']) {
self.$el.find('.uv-filter-options .uv-action-buttons').append("<a class='uv-btn edit-saved-reply' href='#'>{{ 'Edit'|trans }}</a>").show();
$('.uv-filter-paper .uv-customize').show()
} else {
self.$el.find('.uv-filter-options .uv-action-buttons').append("<a class='uv-btn new-saved-reply' href='#'>{{ 'New'|trans }}</a>").show();
if($("#saved-filter").val() != null && $("#saved-filter").val() != '') {
self.$el.find('.uv-filter-options .uv-action-buttons').append("<a class='uv-btn edit-saved-reply' href='#'>{{ 'Update'|trans }}</a>").show();
$('.uv-filter-paper .uv-customize').show()
} else {
$('.uv-filter-paper .uv-customize').hide()
}
}
} else {
$('.uv-filter-paper .uv-customize').hide()
}
this.appliedFilterOptions = appliedFilterOptions;
this.tempAppliedFilterOptions = jQuery.extend(true, {}, appliedFilterOptions);
}
},
searchFilterOption: function(e) {
self = this;
currentElement = Backbone.$(e.currentTarget);
dropdown = currentElement.siblings('.uv-dropdown-list');
var filterType = currentElement.attr('data-filter-type');
if(jQuery.inArray(filterType, ['customer', 'tag']) !== -1) {
self.searchFilterXhr(currentElement);
}
},
searchFilterXhr: _.debounce(function(currentElement) {
var parent = currentElement.parent();
if($('.uv-dropdown-other.uv-dropdown-btn-active').parent().attr('id') != parent.attr('id'))
return;
parent.find("li:not(.uv-no-results, .uv-filter-info)").remove();
parent.find(".uv-filter-info").show()
if(currentElement.val().length > 1) {
parent.append(this.loaderTemplate())
parent.find('.uv-filter-info').text("{% trans %}Searching{% endtrans %} ...")
if(self.xhrReq)
self.xhrReq.abort();
self.xhrReq = $.ajax({
url : "{{ path('helpdesk_member_ticket_collection_search_filter_options_xhr') }}",
type : 'GET',
data: {"type" : currentElement.attr('data-filter-type'), "query" : currentElement.val(), 'not' : ticketCollection.filterParameters[currentElement.attr('data-filter-type')]},
dataType : 'json',
success : function(response) {
self.xhrReq = 0;
parent.find('.uv-loader').remove()
parent.find('.uv-filter-info').text("{{ 'Type atleast 2 letters'|trans }}").hide();
if(response.length == 0) {
parent.find('.uv-no-results').show()
} else {
parent.find('.uv-no-results').hide();
_.each(response, function(item) {
if(currentElement.attr('data-filter-type') == 'customer') {
var img = item.smallThumbnail ? item.smallThumbnail : "{{ asset(default_customer_image_path) }}";
parent.find('.uv-dropdown-list ul').append("<li data-id='" + item.id + "'><img src='" + img + "'/>" + item.name + "</li>")
} else
parent.find('.uv-dropdown-list ul').append("<li data-id='" + item.id + "'>" + item.name + "</li>")
});
}
},
error: function (xhr) {
self.xhrReq = 0;
parent.find('.uv-loader').remove()
parent.find('.uv-no-results').hide();
parent.find('.uv-filter-info').text("{{ 'Type atleast 2 letters'|trans }}").show();
if(url = xhr.getResponseHeader('Location'))
window.location = url;
}
});
} else {
parent.find('.uv-no-results').hide();
}
},1000),
applySavedFilter: function(e) {
var element = Backbone.$(e.currentTarget);
if(element.val() != "") {
var element = Backbone.$(e.currentTarget);
router.navigate(userFilters[element.val()]['route'], {trigger: true});
} else {
router.navigate('', {trigger: true});
}
},
applyFilter: function(e) {
currentElement = Backbone.$(e.currentTarget);
if(currentElement.attr("data-id")) {
var flag = 1;
parent = currentElement.parents(".uv-field-block");
filterType = parent.find('input').attr('data-filter-type');
if(filterType == "customer" || filterType == 'tag') {
sideFilterModel.updateModel(filterType, {'id': currentElement.attr('data-id'), 'name': currentElement.text()})
parent.find(".uv-no-results").hide()
parent.find(".uv-filter-info").show().text("{{ 'Type atleast 2 letters'|trans }}")
parent.find("li:not(.uv-no-results, .uv-filter-info)").remove();
} else {
if(ticketCollection.filterParameters[filterType]) {
ids = ticketCollection.filterParameters[filterType].split(',')
if(jQuery.inArray(currentElement.attr('data-id'), ids) !== -1)
flag = 0;
}
}
parent.find('input').val('')
if(jQuery.inArray(filterType, ['agent', 'priority', 'type', 'group', 'team', 'mailbox', 'source']) !== -1) {
parent.find("li:not(.uv-no-results)").show()
}
if(flag) {
parent.find('.uv-filtered-tags').append("<a class='uv-btn-tag' href='#' data-id='" + currentElement.attr('data-id') + "'>"+currentElement.text()+"<span class='uv-icon-remove-dark'></span></a>")
ticketCollection.state.order = null;
ticketCollection.state.sortKey = null;
ticketCollection.state.currentPage = null;
ticketCollection.filterParameters[filterType] = this.joinTagValues(parent.find(".uv-filtered-tags"));
var queryString = app.appView.buildQuery($.param(ticketCollection.getValidParameters()));
router.navigate(queryString, {trigger: true});
}
} else {
filterType = currentElement.attr('data-filter-type');
if(filterType == 'before' || filterType == "after") {
ticketCollection.state.order = null;
ticketCollection.state.sortKey = null;
ticketCollection.state.currentPage = null;
ticketCollection.filterParameters[filterType] = currentElement.val();
var queryString = app.appView.buildQuery($.param(ticketCollection.getValidParameters()));
router.navigate(queryString, {trigger: true});
}
}
},
removeFilter: function(e) {
e.preventDefault()
currentElement = Backbone.$(e.currentTarget);
filterType = currentElement.parents('.uv-field-block').find('input').attr('data-filter-type')
var options = ticketCollection.filterParameters[filterType];
options = options.split(',');
var index = options.indexOf(currentElement.attr('data-id'));
options.splice(index, 1);
ticketCollection.state.order = null;
ticketCollection.state.sortKey = null;
ticketCollection.state.currentPage = null;
ticketCollection.filterParameters[filterType] = options.join(',');
currentElement.remove()
var queryString = app.appView.buildQuery($.param(ticketCollection.getValidParameters()));
router.navigate(queryString, {trigger: true});
},
joinTagValues: function(parent) {
var ids = new Array();
parent.find('.uv-btn-tag').each(function() {
ids.push($(this).attr('data-id'))
});
return ids.join();
},
filterByRepliesMoreThan: _.debounce(function(e) {
ticketCollection.state.order = null;
ticketCollection.state.sortKey = null;
ticketCollection.state.currentPage = null;
ticketCollection.filterParameters.repliesMore = $(e.target).val();
var queryString = app.appView.buildQuery($.param(ticketCollection.getValidParameters()));
router.navigate(queryString, { trigger: true });
}, 1000),
filterByRepliesLessThan: _.debounce(function(e) {
ticketCollection.state.order = null;
ticketCollection.state.sortKey = null;
ticketCollection.state.currentPage = null;
ticketCollection.filterParameters.repliesLess = $(e.target).val();
var queryString = app.appView.buildQuery($.param(ticketCollection.getValidParameters()));
router.navigate(queryString, { trigger: true });
}, 1000),
filterByCustom: _.debounce(function(e) {
var custom = '';
var checkBoxStore = Array();
var indexValueSeperator = '_';
var columnSeperator = '|';
Backbone.$('.custom-filter').each(function(){
if($(this).context.type == 'radio' && $(this).is(':checked')) {
custom += $(this).attr('data-value') + indexValueSeperator + $(this).val() + columnSeperator;
} else if($(this).context.type == 'checkbox' && $(this).is(':checked')) {
var checkboxValue = Array();
var dataValue = $(this).attr('data-value');
if($.inArray(dataValue, checkBoxStore) >= 0)
return;
$.each($('[data-value="'+ dataValue +'"]:checked'), function() {
checkboxValue.push($(this).val());
});
checkBoxStore.push(dataValue);
custom += dataValue + indexValueSeperator + checkboxValue.join() + columnSeperator;
} else if($(this).context.type == 'select-multiple' && $(this).val()) {
custom += $(this).attr('data-value') + indexValueSeperator + $(this).val().join() + columnSeperator;
}
})
Backbone.$('.search-custom').each(function(){
if($(this).val()){
custom += $(this).attr('data-value') + indexValueSeperator + $(this).val() + columnSeperator;
}
})
custom = custom.replace(/\|$/, '');
ticketCollection.state.order = null;
ticketCollection.state.sortKey = null;
ticketCollection.state.currentPage = null;
ticketCollection.filterParameters.custom = custom;
var queryString = app.appView.buildQuery($.param(ticketCollection.getValidParameters()));
router.navigate(queryString,{trigger: true});
}, 1000),
backToFilter: function(e) {
console.log('backtofilter');
if(e)
e.preventDefault()
this.$el.find('.uv-filter-options').show()
this.$el.find('.uv-filter-edit').hide()
},
addEditSavedReply: function(e) {
e.preventDefault()
var context = {};
this.tempAppliedFilterOptions = jQuery.extend(true, {}, this.appliedFilterOptions);
if(Backbone.$(e.currentTarget).is('.new-saved-reply')) {
context = {'id': 0, 'name': '', 'is_default': 0, 'filters': this.tempAppliedFilterOptions};
} else {
context = userFilters[$("#saved-filter").val()];
context.filters = this.tempAppliedFilterOptions;
userFilters[$("#saved-filter").val()]
}
$('.uv-filter-edit').html('')
$('.uv-filter-edit').append(this.addEditSavedReplyTemplate(context));
this.$el.find('.uv-filter-options').hide()
this.$el.find('.uv-filter-edit').show()
},
removeSavedFilterOption: function(e) {
e.preventDefault()
var parent = Backbone.$(e.currentTarget).parents('.uv-element-block');
var elementIndex = Backbone.$(e.currentTarget).index();
var filterType = parent.attr('data-filter');
var filterId = Backbone.$(e.currentTarget).attr('data-id');
delete this.tempAppliedFilterOptions[filterType]['options'][elementIndex]
Backbone.$(e.currentTarget).remove()
if(!parent.find('.uv-btn-tag').length) {
parent.remove()
delete this.tempAppliedFilterOptions[filterType];
}
if(this.getSavedFilterRoute() == '') {
this.backToFilter();
}
},
saveSavedFilter: function(e) {
e.preventDefault()
if(Backbone.$(e.currentTarget).hasClass('save-filter'))
this.saveFilterAjax('POST')
else {
this.saveFilterAjax('PUT')
}
},
saveFilterAjax: function(method) {
var inputElement = $('.uv-filter-edit input.name');
inputElement.removeClass('uv-field-error');
$('.uv-field-message').remove()
if(inputElement.val() != undefined && inputElement.val() == '') {
inputElement.addClass('uv-field-error');
inputElement.parent().after("<span class='uv-field-message'>{{ 'This field is mandatory'|trans }}</span>");
} else {
var data = $('.uv-filter-edit form').serializeObject();
data['route'] = this.getSavedFilterRoute();
app.appView.showLoader();
self = this;
$.ajax({
url : "{{ path('helpdesk_member_saved_filters_xhr') }}",
type : method,
data: data,
dataType : 'json',
success : function(response) {
app.appView.hideLoader();
userFilters[response.filter.id] = response.filter;
$("#saved-filter").html("<option value=''>-- {{ 'Saved Filter'|trans }} --</option>")
_.each(userFilters, function(filter, key) {
if(response.filter.is_default && filter.id != response.filter.id)
userFilters[key]['is_default'] = 0;
var selected = '';
if(response.filter.id == filter.id)
selected = "selected";
$("#saved-filter").append("<option value='" + filter.id + "' selected='" + selected + "''>" + filter.name + "</option>")
})
$("#saved-filter").val(response.filter.id)
app.appView.renderResponseAlert(response);
self.render();
self.backToFilter();
},
error: function (xhr) {
app.appView.hideLoader();
if(url = xhr.getResponseHeader('Location'))
window.location = url;
}
});
}
},
getSavedFilterRoute: function() {
var filterParameters = {};
temp = [];
_.each(this.tempAppliedFilterOptions, function (filter, key) {
if(jQuery.inArray(key, ['customer', 'agent', 'priority', 'type', 'group', 'team', 'tag', 'mailbox', 'source', 'after', 'before', 'repliesLess', 'repliesMore']) !== -1) {
var ids = [];
_.each(filter['options'], function (item) {
ids.push(item.id)
});
filterParameters[key] = ids.join(',')
} else if(jQuery.inArray(key, ['new','unassigned','notreplied','mine','starred','trashed']) !== -1) {
filterParameters[key] = 1;
} else if(jQuery.inArray(key, ['label', 'status', 'search']) !== -1) {
_.each(filter['options'], function (item) {
filterParameters[key] = item.id;
});
} else {
custom = key.split("z-")
tempKey = custom[1];
if(filter.type == 'text' || filter.type == 'number') {
_.each(filter['options'], function (item) {
temp.push(tempKey + '_' + item.name)
});
} else if(filter.type == 'radio') {
var ids = [];
_.each(filter['options'], function (item) {
ids.push(item.id)
});
temp.push(tempKey + '_' + ids.join(','))
} else if(filter.type == 'checkbox' || filter.type == 'select-multiple') {
var ids = [];
_.each(filter['options'], function (item) {
ids.push(item.id)
});
temp.push(tempKey + '_' + ids.join(','))
}
}
})
if(temp.length)
filterParameters['custom'] = temp.join('|');
return app.appView.buildQuery($.param(filterParameters));
},
removeSavedFilter: function(e) {
e.preventDefault()
self = this;
app.appView.showLoader();
$.ajax({
url : "{{ path('helpdesk_member_saved_filters_xhr') }}/" + $("#saved-filter").val(),
type : 'DELETE',
dataType : 'json',
success : function(response) {
app.appView.hideLoader();
delete userFilters[$("#saved-filter").val()];
$("#saved-filter").html("<option value=''>-- {{ 'Saved Filter'|trans }} --</option>")
_.each(userFilters, function(filter, key) {
$("#saved-filter").append("<option value='" + filter.id + "'>" + filter.name + "</option>")
})
$("#saved-filter").val('')
app.appView.renderResponseAlert(response);
self.render();
self.backToFilter();
},
error: function (xhr) {
app.appView.hideLoader();
if(url = xhr.getResponseHeader('Location'))
window.location = url;
}
});
}
});
// Ticket Label Item View
var LabelItemView = Backbone.View.extend({
tagName: 'li',
className: 'uv-customize-wrapper',
template: _.template($("#custom_label_tmp").html()),
events: {
'click .delete': 'confirmRemove',
'click .label-color.dropdown .fa-caret-down' : 'showUpdateLabelPopup'
},
render: function() {
this.$el.html(this.template(this.model.toJSON()));
if (ticketCollection.filterParameters.label != '') {
if (ticketCollection.filterParameters.label == this.model.id) {
this.$el.find('a').addClass('uv-aside-active');
}
}
return this;
}
});
// Ticket List Item View
var TicketItem = Backbone.View.extend({
tagName: "tr",
template: _.template($("#ticket_list_item_tmp").html()),
events: {
'click .uv-star': "updateStar",
},
render: function () {
this.model.set({
path: pathToTicket.replace('replaceId', this.model.attributes.id + '-' + this.model.attributes.numeracion)
});
if(this.model.attributes.numeracion){
this.model.set('id', this.model.attributes.id + '-' + this.model.attributes.numeracion)
}
this.$el.html(this.template(this.model.toJSON()));
if (this.model.attributes.status.id == 1) {
this.$el.addClass('unread')
}
if (!this.model.attributes.agent) {
this.$el.addClass('not-assigned')
}
return this;
},
updateStar: function(e) {
e.preventDefault();
if (Backbone.$(e.currentTarget).hasClass('uv-star-active')) {
Backbone.$(e.currentTarget).removeClass('uv-star-active');
} else {
Backbone.$(e.currentTarget).addClass('uv-star-active');
}
this.model.save({
id: this.model.id
}, {
patch: true,
url: "{{ path('helpdesk_member_bookmark_ticket_xhr') }}",
success: function (model, response, options) {},
error: function (model, xhr, options) {
if (url = xhr.getResponseHeader('Location')) {
window.location = url;
}
}
});
}
});
// Ticket List View
var TicketList = Backbone.View.extend({
el: $(".uv-table table"),
initialize: function() {
this.render();
},
events: {
'change .mass-action-checkbox' : 'showBulkOptions',
},
showBulkOptions: function() {
var count = 0;
this.$el.find('.mass-action-checkbox').each(function() {
if ($(this).is(':checked')) {
count++;
}
});
if (count == $('.mass-action-checkbox').length) {
$('.select-all-checkbox').prop('checked', true);
} else {
$('.select-all-checkbox').prop('checked', false);
}
if (count) {
$('.uv-action-bar .filter').parent().hide();
$('.uv-action-bar .mass-action').parent().addClass("uv-width-100").show();
$('.uv-action-bar-col-rt').hide()
} else {
$('.uv-action-bar .mass-action').parent().removeClass("uv-width-100").hide();
$('.uv-action-bar .filter').parent().show();
$('.uv-action-bar-col-rt').show();
}
},
render: function () {
this.$el.find('tbody').html('');
if (ticketCollection.length) {
$('.select-all-checkbox').prop( "disabled", false );
_.each(ticketCollection.models, function (item) {
ticketQuickViewCollection.add(new TicketQuickViewModel({id: item.id}))
this.renderTicket(item);
}, this);
} else {
$('.select-all-checkbox').prop( "disabled", true );
this.$el.find('tbody').append("<tr style='text-align: center;'><td colspan='11'>{% trans %}No Record Found{% endtrans %}</td></tr>")
}
filter.filterAssetsVisibilityOnLoad()
app.appView.relativeTime()
},
renderTicket: function (item) {
var ticketItem = new TicketItem({
model: item
});
this.$el.find('tbody').append(ticketItem.render().el);
}
});
// Ticket Label List View
var LabelListView = Backbone.View.extend({
el: $(".uv-aside"),
template: _.template($("#predefined_label_tmp").html()),
statusTemplate: _.template($("#ticket_status_list_tmp").html()),
addEditLabelTemplate: _.template($("#add_edit_label_tmp").html()),
events: {
'click .status-list li a': "filterByStatus",
'click .add-new-label, .uv-customize': 'addEditLabel',
'click #back-to-labels': 'backToLabels',
'click .uv-color-block': 'setLabelColor',
'click .add-update-btn': 'saveLabel',
'click .uv-add-edit-label .uv-btn-remove': 'removeLabel'
},
render: function() {
var active = "";
if (ticketCollection.filterParameters.new != '') {
active = "new";
} else if (ticketCollection.filterParameters.unassigned != '') {
active = "unassigned";
} else if (ticketCollection.filterParameters.notreplied != '') {
active = "notreplied";
}
if (ticketCollection.filterParameters.mine != '') {
active = "mine";
} else if (ticketCollection.filterParameters.starred != '') {
active = "starred";
} else if (ticketCollection.filterParameters.trashed != '') {
active = "trashed";
} else if (ticketCollection.filterParameters.label != '') {
active = "label";
}
var data = {
'labelDetails' : labelDetails,
'active' : active
}
this.$el.find('.predefined-label-list').html(this.template(data));
labelCollection.reset();
labelCollection.set(labelDetails.custom);
this.updateMassLabelList()
},
updateMassLabelList: function() {
this.$el.find('.uv-aside-custom').html('');
var labelOptionHtml = "";
if(labelCollection.length) {
_.each(labelCollection.models, function (item) {
this.renderLabelItem(item);
labelOptionHtml = labelOptionHtml + "<li data-index='" + item.id + "'><a href='#'>" + item.attributes.name + "</a></li>";
}, this);
}
labelOptionHtml = labelOptionHtml ? labelOptionHtml : "<li data-index='0'>{{ 'No Label Created'|trans }}</li>";
$(".mass-action ul.label").html(labelOptionHtml);
this.renderStatus();
},
renderLabelItem : function (item) {
var labelItem = new LabelItemView({
model: item
});
this.$el.find('.uv-aside-custom').append(labelItem.render().el);
},
renderStatus : function() {
if(typeof ticketCollection.filterParameters.status == "undefined" || ticketCollection.filterParameters.status == null)
var active = 0;
else
var active = ticketCollection.filterParameters.status;
this.$el.find('.uv-aside-active').parent().find('.status-list').remove()
this.$el.find('.uv-aside-active').parent().append(this.statusTemplate({status : statusListDetails, active : active}));
},
filterByStatus : function(e) {
e.preventDefault()
ticketCollection.reset();
ticketCollection.state.order = null;
ticketCollection.state.sortKey = null;
ticketCollection.state.currentPage = null;
ticketCollection.filterParameters.status = Backbone.$(e.currentTarget).attr('data-id');
var queryString = app.appView.buildQuery($.param(ticketCollection.getValidParameters()));
router.navigate(queryString, {trigger: true});
},
addEditLabel: function(e) {
e.preventDefault()
currentElement = Backbone.$(e.currentTarget);
if(currentElement.hasClass('add-new-label'))
$('.uv-add-edit-label').html(this.addEditLabelTemplate({id : 0, name : '', colorCode: ''}))
else
$('.uv-add-edit-label').html(this.addEditLabelTemplate(labelCollection.get(currentElement.siblings('a').attr('data-id')).toJSON()))
$('.uv-aside-default').hide()
$('.uv-add-edit-label').show()
},
backToLabels: function(e) {
if(e)
e.preventDefault()
$('.uv-aside-default').show()
$('.uv-add-edit-label').hide()
},
setLabelColor: function(e) {
$('.uv-color-block').removeClass('uv-color-active');
Backbone.$(e.currentTarget).addClass('uv-color-active');
},
saveLabel : function(e) {
e.preventDefault()
var inputElement = $('.uv-add-edit-label input');
inputElement.removeClass('uv-field-error');
$('.uv-field-message').remove()
var labelName = app.appView.stripHTML(inputElement.val());
if(labelName == "") {
inputElement.addClass('uv-field-error');
inputElement.parent().after("<span class='uv-field-message'>{{ 'This field is mandatory'|trans }}</span>");
} else {
var labelId = parseInt($('.uv-aside-option').attr('data-id'))
model = labelId ? labelCollection.get(labelId) : new LabelModel()
model.set({name: labelName, colorCode: $('.uv-color-block.uv-color-active').attr('data-color')});
self = this;
var flag = labelCollection.isLabelExist(labelName, labelId);
if(flag) {
app.appView.showLoader();
model.save({}, {
success: function (model, response, options) {
app.appView.hideLoader();
if(response.alertClass == "success") {
if(!labelId) {
labelCollection.add(model);
}
self.updateMassLabelList()
app.appView.renderResponseAlert(response);
} else {
inputElement.addClass('uv-field-error');
inputElement.parent().after("<span class='uv-field-message'>" + response.alertMessage + "</span>");
}
self.backToLabels();
},
error: function (model, xhr, options) {
if(url = xhr.getResponseHeader('Location'))
window.location = url;
app.appView.hideLoader();
app.appView.renderResponseAlert(warningResponse);
}
});
} else {
inputElement.parent().after("<span class='uv-field-message'>{{ 'Label with same name already exist.'|trans }}</span>");
}
}
},
removeLabel: function(e) {
e.preventDefault()
self = this;
app.appView.showLoader();
model = labelCollection.get($('.uv-aside-option').attr('data-id'))
model.destroy({
success : function (model, response, options) {
app.appView.hideLoader();
self.updateMassLabelList()
app.appView.renderResponseAlert(response);
self.backToLabels();
},
error: function (model, xhr, options) {
if(url = xhr.getResponseHeader('Location'))
window.location = url;
app.appView.hideLoader();
app.appView.renderResponseAlert(warningResponse);
}
});
}
});
// Bulk Action View
var BulkActionView = Backbone.View.extend({
el: $(".mass-action"),
currentEvent: null,
events: {
'click ul li, #mass-restore': 'massAction',
'click #mass-delete, #mass-delete-forever': 'confirmRemove',
'click #mass-restore': 'confirmRestore'
},
massAction: function(e) {
e.preventDefault();
if(!parseInt(Backbone.$(e.currentTarget).attr('data-index')))
return;
var data = {};
data['actionType'] = Backbone.$(e.currentTarget).parents('ul').attr('data-action') ? Backbone.$(e.currentTarget).parents('ul').attr('data-action') : Backbone.$(e.currentTarget).attr('data-action');
data['targetId'] = Backbone.$(e.currentTarget).attr('data-index');
data['ids'] = this.getCheckedTicketIds();
ticketCollection.batchOperation(data);
this.hideBulkOptions();
},
removeItem: function(e) {
var data = {};
if(Backbone.$(this.currentEvent.currentTarget).is("#mass-delete"))
data['actionType'] = "trashed";
else if(Backbone.$(this.currentEvent.currentTarget).is("#mass-delete-forever"))
data['actionType'] = "delete";
data['ids'] = this.getCheckedTicketIds();
ticketCollection.batchOperation(data);
this.hideBulkOptions();
},
restoreItem: function(e) {
var data = {};
data['actionType'] = "restored";
data['ids'] = this.getCheckedTicketIds();
ticketCollection.batchOperation(data);
this.hideBulkOptions();
},
getCheckedTicketIds: function() {
var ids = new Array();
$('.mass-action-checkbox').each(function() {
if($(this).is(':checked')) {
ids.push($(this).val());
}
});
return ids;
},
confirmRemove: function(e) {
e.preventDefault();
this.currentEvent = e;
app.appView.openConfirmModal(this)
},
confirmRestore: function(e) {
e.preventDefault();
app.appView.openConfirmModal(this, 'restoreItem')
},
hideBulkOptions : function() {
$('.uv-action-bar .mass-action').parent().removeClass("uv-width-100").hide();
$('.uv-action-bar .filter').parent().show();
$('.uv-action-bar-col-rt').show()
}
});
var PageView = Backbone.View.extend({
el: '.uv-paper',
events : {
'change .select-all-checkbox' : 'selectAll',
'click .uv-quick-view-trigger, .quick-view-navigation .uv-btn-tag': 'navigateQuickView',
},
quickViewTemplate: _.template($("#ticket_quick_view_tmp").html()),
navigateQuickView : function(e) {
e.preventDefault();
//$("#quick-view-modal .uv-loader").hide()
var currentElement = Backbone.$(e.currentTarget);
ticketId = currentElement.attr('data-id');
if(ticketId) {
if(model = ticketQuickViewCollection.isModelSynced(ticketId)) {
this.renderQuickView(model.toJSON())
} else {
var self = this;
if(currentElement.hasClass("uv-quick-view-trigger"))
app.appView.showLoader();
if(ticketQuickViewCollection.get(ticketId)) {
navData = ticketQuickViewCollection.getNextPrev(ticketId);
requiredNext = (!navData.next && app.pager.paginationData.next) ? 1 : 0;
requiredPrev = (!navData.previous && app.pager.paginationData.previous) ? 1 : 0;
} else
requiredNext = requiredPrev = 1;
if(self.xhrReq)
self.xhrReq.abort();
$("#quick-view-modal .uv-loader").show()
self.xhrReq = $.ajax({
url : "{{ path('helpdesk_member_ticket_quick_view_xhr') }}",
type : 'GET',
data : {ticketId : ticketId, next: requiredNext, previous: requiredPrev},
dataType : 'json',
success : function(response) {
self.xhrReq = 0;
if(currentElement.hasClass("uv-quick-view-trigger"))
app.appView.hideLoader();
if(response.next == undefined)
response.next = navData.next
if(response.previous == undefined)
response.previous = navData.previous
response.isSynced = 1
response.path = pathToTicket.replace('replaceId', response.incrementId);
if(ticketQuickViewCollection.get(ticketId))
ticketQuickViewCollection.set(response,{remove: false})
else
ticketQuickViewCollection.add(new TicketQuickViewModel(response))
self.renderQuickView(response)
},
error: function (xhr) {
self.xhrReq = 0;
if(url = xhr.getResponseHeader('Location'))
window.location = url;
app.appView.hideLoader();
}
});
}
}
},
renderQuickView: function(response) {
$('#quick-view-modal .uv-pop-up-box').html(this.quickViewTemplate(response));
app.appView.openModal('quick-view-modal')
$('#quick-view-modal .message').find('img').removeAttr('crossorigin');
$('#quick-view-modal .message').find('.uv-icon-ellipsis').remove();
$('#quick-view-modal .message').find('.helpdesk_blockquote').eq(0).before("<span class='uv-icon-ellipsis uv-ellipsis-mirror'></span>").hide();
app.appView.relativeTime();
},
selectAll : function(e) {
if(Backbone.$(e.currentTarget).is(':checked')) {
$('.mass-action-checkbox').prop('checked', true);
$('.uv-action-bar .filter').parent().hide();
$('.uv-action-bar .mass-action').parent().addClass("uv-width-100").show();
$('.uv-action-bar-col-rt').hide()
} else {
var count = 0;
$('.mass-action-checkbox').each(function() {
if($(this).is(':checked'))
count++;
});
if(count == $('.mass-action-checkbox').length) {
$('.mass-action-checkbox').prop('checked', false);
$('.uv-action-bar .filter').parent().show();
$('.uv-action-bar .mass-action').parent().removeClass("uv-width-100").hide();
$('.uv-action-bar-col-rt').show()
}
}
},
});
// Ticket Router
Router = Backbone.Router.extend({
routes: {
'page/:number(/sort/:sortField)(/direction/:order)' : 'paginate',
'status/:status(/search/:query)(/agent/:agent)(/customer/:customer)(/priority/:priority)(/type/:type)(/group/:group)(/team/:team)(/tag/:tag)(/mailbox/:mailbox)(/source/:source)(/after/:after)(/before/:before)(/repliesLess/:repliesLess)(/repliesMore/:repliesMore)(/custom/:custom)(/page/:number)(/sort/:sortField)(/direction/:order)': 'filterByStatus',
'search/:query(/agent/:agent)(/customer/:customer)(/priority/:priority)(/type/:type)(/group/:group)(/team/:team)(/tag/:tag)(/mailbox/:mailbox)(/source/:source)(/after/:after)(/before/:before)(/repliesLess/:repliesLess)(/repliesMore/:repliesMore)(/custom/:custom)(/page/:number)(/sort/:sortField)(/direction/:order)': 'filterByQuery',
'agent/:agent(/customer/:customer)(/priority/:priority)(/type/:type)(/group/:group)(/team/:team)(/tag/:tag)(/mailbox/:mailbox)(/source/:source)(/after/:after)(/before/:before)(/repliesLess/:repliesLess)(/repliesMore/:repliesMore)(/custom/:custom)(/page/:number)(/sort/:sortField)(/direction/:order)': 'filterByAgent',
'customer/:customer(/priority/:priority)(/type/:type)(/group/:group)(/team/:team)(/tag/:tag)(/mailbox/:mailbox)(/source/:source)(/after/:after)(/before/:before)(/repliesLess/:repliesLess)(/repliesMore/:repliesMore)(/custom/:custom)(/page/:number)(/sort/:sortField)(/direction/:order)': 'filterByCustomer',
'priority/:priority(/type/:type)(/group/:group)(/team/:team)(/tag/:tag)(/mailbox/:mailbox)(/source/:source)(/after/:after)(/before/:before)(/repliesLess/:repliesLess)(/repliesMore/:repliesMore)(/custom/:custom)(/page/:number)(/sort/:sortField)(/direction/:order)': 'filterByPriority',
'type/:type(/group/:group)(/team/:team)(/tag/:tag)(/mailbox/:mailbox)(/source/:source)(/after/:after)(/before/:before)(/repliesLess/:repliesLess)(/repliesMore/:repliesMore)(/custom/:custom)(/page/:number)(/sort/:sortField)(/direction/:order)': 'filterByType',
'group/:group(/team/:team)(/tag/:tag)(/mailbox/:mailbox)(/source/:source)(/after/:after)(/before/:before)(/repliesLess/:repliesLess)(/repliesMore/:repliesMore)(/custom/:custom)(/page/:number)(/sort/:sortField)(/direction/:order)': 'filterByGroup',
'team/:team(/tag/:tag)(/mailbox/:mailbox)(/source/:source)(/after/:after)(/before/:before)(/repliesLess/:repliesLess)(/repliesMore/:repliesMore)(/custom/:custom)(/page/:number)(/sort/:sortField)(/direction/:order)': 'filterBySubGroup',
'tag/:tag(/mailbox/:mailbox)(/source/:source)(/after/:after)(/before/:before)(/repliesLess/:repliesLess)(/repliesMore/:repliesMore)(/custom/:custom)(/page/:number)(/sort/:sortField)(/direction/:order)': 'filterByTags',
'mailbox/:mailbox(/source/:source)(/after/:after)(/before/:before)(/repliesLess/:repliesLess)(/repliesMore/:repliesMore)(/custom/:custom)(/page/:number)(/sort/:sortField)(/direction/:order)': 'filterByMailbox',
'source/:source(/after/:after)(/before/:before)(/repliesLess/:repliesLess)(/repliesMore/:repliesMore)(/custom/:custom)(/page/:number)(/sort/:sortField)(/direction/:order)': 'filterBySource',
'after/:after(/before/:before)(/repliesLess/:repliesLess)(/repliesMore/:repliesMore)(/custom/:custom)(/page/:number)(/sort/:sortField)(/direction/:order)': 'filterByAfter',
'before/:before(/repliesLess/:repliesLess)(/repliesMore/:repliesMore)(/custom/:custom)(/page/:number)(/sort/:sortField)(/direction/:order)': 'filterByBefore',
'repliesLess/:repliesLess(/repliesMore/:repliesMore)(/custom/:custom)(/page/:number)(/sort/:sortField)(/direction/:order)': 'filterByRepliesLesserCount',
'repliesMore/:repliesMore(/custom/:custom)(/page/:number)(/sort/:sortField)(/direction/:order)': 'filterByRepliesGreaterCount',
'custom/:custom(/page/:number)(/sort/:sortField)(/direction/:order)': 'filterByCustom',
'label/:labelId(/status/:status)(/search/:query)(/agent/:agent)(/customer/:customer)(/priority/:priority)(/type/:type)(/group/:group)(/team/:team)(/tag/:tag)(/mailbox/:mailbox)(/source/:source)(/after/:after)(/before/:before)(/repliesLess/:repliesLess)(/repliesMore/:repliesMore)(/custom/:custom)(/page/:number)(/sort/:sortField)(/direction/:order)': 'filterByLabel',
'new(/status/:status)(/search/:query)(/agent/:agent)(/customer/:customer)(/priority/:priority)(/type/:type)(/group/:group)(/team/:team)(/tag/:tag)(/mailbox/:mailbox)(/source/:source)(/after/:after)(/before/:before)(/repliesLess/:repliesLess)(/repliesMore/:repliesMore)(/custom/:custom)(/page/:number)(/sort/:sortField)(/direction/:order)': 'filterNew',
'unassigned(/status/:status)(/search/:query)(/agent/:agent)(/customer/:customer)(/priority/:priority)(/type/:type)(/group/:group)(/team/:team)(/tag/:tag)(/mailbox/:mailbox)(/source/:source)(/after/:after)(/before/:before)(/repliesLess/:repliesLess)(/repliesMore/:repliesMore)(/custom/:custom)(/page/:number)(/sort/:sortField)(/direction/:order)': 'filterUnassigned',
'notreplied(/status/:status)(/search/:query)(/agent/:agent)(/customer/:customer)(/priority/:priority)(/type/:type)(/group/:group)(/team/:team)(/tag/:tag)(/mailbox/:mailbox)(/source/:source)(/after/:after)(/before/:before)(/repliesLess/:repliesLess)(/repliesMore/:repliesMore)(/custom/:custom)(/page/:number)(/sort/:sortField)(/direction/:order)': 'filterNotReplied',
'mine(/status/:status)(/search/:query)(/agent/:agent)(/customer/:customer)(/priority/:priority)(/type/:type)(/group/:group)(/team/:team)(/tag/:tag)(/mailbox/:mailbox)(/source/:source)(/after/:after)(/before/:before)(/repliesLess/:repliesLess)(/repliesMore/:repliesMore)(/custom/:custom)(/page/:number)(/sort/:sortField)(/direction/:order)': 'filterMine',
'starred(/status/:status)(/search/:query)(/agent/:agent)(/customer/:customer)(/priority/:priority)(/type/:type)(/group/:group)(/team/:team)(/tag/:tag)(/mailbox/:mailbox)(/source/:source)(/after/:after)(/before/:before)(/repliesLess/:repliesLess)(/repliesMore/:repliesMore)(/custom/:custom)(/page/:number)(/sort/:sortField)(/direction/:order)': 'filterstarred',
'trashed(/status/:status)(/search/:query)(/agent/:agent)(/customer/:customer)(/priority/:priority)(/type/:type)(/group/:group)(/team/:team)(/tag/:tag)(/mailbox/:mailbox)(/source/:source)(/after/:after)(/before/:before)(/repliesLess/:repliesLess)(/repliesMore/:repliesMore)(/custom/:custom)(/page/:number)(/sort/:sortField)(/direction/:order)': 'filterTrashed',
'': 'initializeList'
},
initializeList : function() {
$("#saved-filter").val('');
this.resetParams('', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '');
this.fetch(null, null, null);
},
paginate : function(number,sortField,order) {
this.resetParams('','','','','','','','','','','','','','','','','','','','','', '');
this.fetch(number,sortField,order);
},
filterByLabel : function(labelId,status,query,agent,customer,priority,type,group,team,tag,mailbox,source,after,before,repliesLess,repliesMore,custom,number,sortField,order) {
this.resetParams(labelId,'','','','','','',status,query,agent,customer,priority,type,group,team,tag,mailbox,source,after,before,repliesLess,repliesMore,custom);
this.fetch(number,sortField,order);
},
filterNew : function(status,query,agent,customer,priority,type,group,team,tag,mailbox,source,after,before,repliesLess,repliesMore,custom,number,sortField,order) {
this.resetParams('',1,'','','','','',status,query,agent,customer,priority,type,group,team,tag,mailbox,source,after,before,repliesLess,repliesMore,custom);
this.fetch(number,sortField,order);
},
filterUnassigned : function(status,query,agent,customer,priority,type,group,team,tag,mailbox,source,after,before,repliesLess,repliesMore,custom,number,sortField,order) {
this.resetParams('','',1,'','','','',status,query,agent,customer,priority,type,group,team,tag,mailbox,source,after,before,repliesLess,repliesMore,custom);
this.fetch(number,sortField,order);
},
filterNotReplied: function(status,query,agent,customer,priority,type,group,team,tag,mailbox,source,after,before,repliesLess,repliesMore,custom,number,sortField,order) {
this.resetParams('','','',1,'','','',status,query,agent,customer,priority,type,group,team,tag,mailbox,source,after,before,repliesLess,repliesMore,custom);
this.fetch(number,sortField,order);
},
filterMine : function(status,query,agent,customer,priority,type,group,team,tag,mailbox,source,after,before,repliesLess,repliesMore,custom,number,sortField,order) {
this.resetParams('','','','',currentUserId,'','',status,query,agent,customer,priority,type,group,team,tag,mailbox,source,after,before,repliesLess,repliesMore,custom);
this.fetch(number,sortField,order);
},
filterstarred : function(status,query,agent,customer,priority,type,group,team,tag,mailbox,source,after,before,repliesLess,repliesMore,custom,number,sortField,order) {
this.resetParams('','','','','',1,'',status,query,agent,customer,priority,type,group,team,tag,mailbox,source,after,before,repliesLess,repliesMore,custom);
this.fetch(number,sortField,order);
},
filterTrashed : function(status,query,agent,customer,priority,type,group,team,tag,mailbox,source,after,before,repliesLess,repliesMore,custom,number,sortField,order) {
this.resetParams('','','','','','',1,status,query,agent,customer,priority,type,group,team,tag,mailbox,source,custom);
this.fetch(number,sortField,order);
},
filterByStatus : function(status,query,agent,customer,priority,type,group,team,tag,mailbox,source,after,before,repliesLess,repliesMore,custom,number,sortField,order) {
this.resetParams('','','','','','','',status,query,agent,customer,priority,type,group,team,tag,mailbox,source,after,before,repliesLess,repliesMore,custom);
this.fetch(number,sortField,order);
},
filterByQuery : function(query,agent,customer,priority,type,group,team,tag,mailbox,source,after,before,repliesLess,repliesMore,custom,number,sortField,order) {
this.resetParams('','','','','','','','',query,agent,customer,priority,type,group,team,tag,mailbox,source,after,before,repliesLess,repliesMore,custom);
this.fetch(number,sortField,order);
},
filterByAgent : function(agent,customer,priority,type,group,team,tag,mailbox,source,after,before,repliesLess,repliesMore,custom,number,sortField,order) {
this.resetParams('','','','','','','','','',agent,customer,priority,type,group,team,tag,mailbox,source,after,before,repliesLess,repliesMore,custom);
this.fetch(number,sortField,order);
},
filterByCustomer : function(customer,priority,type,group,team,tag,mailbox,source,after,before,repliesLess,repliesMore,custom,number,sortField,order) {
this.resetParams('','','','','','','','','','',customer,priority,type,group,team,tag,mailbox,source,after,before,repliesLess,repliesMore,custom);
this.fetch(number,sortField,order);
},
filterByPriority : function(priority,type,group,team,tag,mailbox,source,after,before,repliesLess,repliesMore,custom,number,sortField,order) {
this.resetParams('','','','','','','','','','','',priority,type,group,team,tag,mailbox,source,after,before,repliesLess,repliesMore,custom);
this.fetch(number,sortField,order);
},
filterByType : function(type,group,team,tag,mailbox,source,after,before,repliesLess,repliesMore,custom,number,sortField,order) {
this.resetParams('','','','','','','','','','','','',type,group,team,tag,mailbox,source,after,before,repliesLess,repliesMore,custom);
this.fetch(number,sortField,order);
},
filterByGroup : function(group,team,tag,mailbox,source,after,before,repliesLess,repliesMore,custom,number,sortField,order) {
this.resetParams('','','','','','','','','','','','','',group,team,tag,mailbox,source,after,before,repliesLess,repliesMore,custom);
this.fetch(number,sortField,order);
},
filterBySubGroup : function(team,tag,mailbox,source,after,before,repliesLess,repliesMore,custom,number,sortField,order) {
this.resetParams('','','','','','','','','','','','','','',team,tag,mailbox,source,after,before,repliesLess,repliesMore,custom);
this.fetch(number,sortField,order);
},
filterByTags : function(tag,mailbox,source,after,before,repliesLess,repliesMore,custom,number,sortField,order) {
this.resetParams('','','','','','','','','','','','','','','',tag,mailbox,source,after,before,repliesLess,repliesMore,custom);
this.fetch(number,sortField,order);
},
filterByMailbox : function(mailbox,source,after,before,repliesLess,repliesMore,custom,number,sortField,order) {
this.resetParams('','','','','','','','','','','','','','','','',mailbox,source,after,before,repliesLess,repliesMore,custom);
this.fetch(number,sortField,order);
},
filterBySource: function(source,after,before,repliesLess,repliesMore,custom,number,sortField,order) {
this.resetParams('','','','','','','','','','','','','','','','','',source,after,before,repliesLess,repliesMore,custom);
this.fetch(number,sortField,order);
},
filterByAfter: function(after,before,repliesLess,repliesMore,custom,number,sortField,order) {
this.resetParams('','','','','','','','','','','','','','','','','','',after,before,repliesLess,repliesMore,custom);
this.fetch(number,sortField,order);
},
filterByBefore: function(before,repliesLess,repliesMore,custom,number,sortField,order) {
this.resetParams('','','','','','','','','','','','','','','','','','','',before,repliesLess,repliesMore,custom);
this.fetch(number,sortField,order);
},
filterByRepliesLesserCount: function(repliesLess, repliesMore, custom, number, sortField, order) {
this.resetParams('','','','','','','','','','','','','','','','','','','','',repliesLess,repliesMore,custom);
this.fetch(number,sortField,order);
},
filterByRepliesGreaterCount: function(repliesMore, custom, number, sortField, order) {
this.resetParams('','','','','','','','','','','','','','','','','','','','','',repliesMore,custom);
this.fetch(number,sortField,order);
},
filterByCustom : function(custom, number, sortField, order) {
this.resetParams('','','','','','','','','','','','','','','','','','','','','','',custom);
this.fetch(number,sortField,order);
},
fetch: function(number, sortField, order) {
ticketCollection.state.currentPage = number;
filter.sortCollection(sortField, order);
ticketCollection.syncData();
},
resetParams : function(labelId,newLabel,unassigned,notreplied,mine,starred,trashed,status,query,agent,customer,priority,type,group,team,tag,mailbox,source,after,before,repliesLess,repliesMore,custom) {
_.each(userFilters, function(filter, index) {
if(Backbone.history.getFragment() == filter['route']) {
$("#saved-filter").val(index);
}
});
isPageJustLoaded = false;
if(query != null)
query = query.replace(/\+/g,' ');
bulkAction.hideBulkOptions();
ticketCollection.filterParameters.label = labelId;
ticketCollection.filterParameters.new = newLabel;
ticketCollection.filterParameters.unassigned = unassigned;
ticketCollection.filterParameters.notreplied = notreplied;
ticketCollection.filterParameters.mine = mine;
ticketCollection.filterParameters.starred = starred;
ticketCollection.filterParameters.trashed = trashed;
ticketCollection.filterParameters.search = query;
$(".uv-search-inline").val(query);
ticketCollection.filterParameters.status = status;
ticketCollection.filterParameters.agent = agent;
ticketCollection.filterParameters.customer = customer;
ticketCollection.filterParameters.priority = priority;
ticketCollection.filterParameters.type = type;
ticketCollection.filterParameters.group = group;
ticketCollection.filterParameters.team = team;
ticketCollection.filterParameters.tag = tag;
ticketCollection.filterParameters.mailbox = mailbox;
ticketCollection.filterParameters.source = source;
ticketCollection.filterParameters.after = after;
ticketCollection.filterParameters.before = before;
ticketCollection.filterParameters.repliesLess = repliesLess;
ticketCollection.filterParameters.repliesMore = repliesMore;
ticketCollection.filterParameters.custom = custom;
$('.custom-fields').find('input[type="text"]').val('');
$('.custom-fields').find('select').val('');
$('.custom-fields').find('input[type="radio"]').prop('checked', false);
$('.custom-fields').find('input[type="checkbox"]').prop('checked', false);
if(custom) {
custom = custom.replace(/\+/g,' ');
var indexValueSeperator = '_';
var columnSeperator = '|';
var multiOptions = custom.split(columnSeperator);
var multiKeyValue, multiKeyValueValue, ele;
_.each(multiOptions, function(valueData, indexData) {
if(!valueData)
return;
multiKeyValue = valueData.split(indexValueSeperator);
multiKeyValueValue = multiKeyValue[1].split(',');
ele = $('[data-value="' + multiKeyValue[0] + '"]');
if(ele[0].type == 'radio') {
$('[data-value="' + multiKeyValue[0] + '"][value="' + multiKeyValue[1] + '"]').prop('checked', true);
} else if(ele[0].type == 'checkbox') {
_.each(ele, function(eleElements) {
if(multiKeyValueValue.indexOf(eleElements.value) > -1) {
$(eleElements).prop('checked', true);
}
});
} else if(ele[0].type == 'select-multiple') {
ele.val(multiKeyValueValue);
} else if(ele[0].type == 'text') {
ele.val(multiKeyValue[1]);
}
})
}
if(trashed) {
$('.property-block').hide();
$('.trashed-block').show();
} else {
$('.property-block').show();
$('.trashed-block').hide();
}
sideFilter.isRecurrsiveCalls = 0;
sideFilter.render();
}
});
var router = new Router();
var pageview = new PageView;
var bulkAction = new BulkActionView();
var sideFilterModel = new SideFilterModel(filterContext)
var sideFilter = new SideFilter();
var ticketCollection = new TicketCollection();
var ticketQuickViewCollection = new TicketQuickViewCollection();
var labelCollection = new LabelCollection();
var labelListView = new LabelListView()
var filter = new Filter({collection : ticketCollection});
Backbone.history.start({
push_state:true
});
});
</script>
<script>
document.addEventListener("DOMContentLoaded", function() {
// Verifica si existe una cookie que indica que el modal debe mantenerse abierto
var modalOpenCookie = getCookie("modalOpen");
if (modalOpenCookie === "true") {
showTicketModal();
// Elimina la cookie para que el modal no se abra automáticamente en futuras visitas
document.cookie = "modalOpen=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
}
});
function getCookie(name) {
var cookieName = name + "=";
var cookieArray = document.cookie.split(";");
for (var i = 0; i < cookieArray.length; i++) {
var cookie = cookieArray[i].trim();
if (cookie.indexOf(cookieName) === 0) {
return cookie.substring(cookieName.length, cookie.length);
}
}
return "";
}
function showTicketModal() {
document.cookie = "modalOpen=true";
var modal = document.getElementById("ticketModal");
modal.style.display = "block";
}
function closeTicketModal() {
document.cookie = "modalOpen=false";
var modal = document.getElementById("ticketModal");
modal.style.display = "none";
history.replaceState({}, document.title, window.location.pathname);
}
</script>
<script>
// Traducciones para el sistema de alertas
const ticketAlertTranslations = {
overdueMessage: '{{ "There are overdue tickets!"|trans }}',
ticketStatus: '{{ "ticket(s) have been in status"|trans }}',
forMoreThan: '{{ "for more than"|trans }}',
days: '{{ "days"|trans }}',
noTicketsRequireAttention: '{{ "No tickets require attention"|trans }}'
};
// Sistema de Alertas de Tickets con comparación de fechas
class TicketAlertSystem {
constructor() {
this.currentUserId = "{{ user_service.getCurrentUser().id }}";
this.checkInterval = null;
this.reminderTimeout = null;
this.overdueData = {};
this.config = {
interval: 1800000, // valor por defecto 30 min
enabled: true,
days_threshold: 3
};
this.storageKey = 'ticket_alert_last_shown_' + this.currentUserId;
this.init();
}
async init() {
await this.loadConfig();
this.startPeriodicCheck();
this.setupModalEvents();
document.addEventListener('DOMContentLoaded', () => {
setTimeout(() => {
this.checkAlerts();
}, 2000);
});
}
setupModalEvents() {
// Prevenir que el modal se cierre al hacer clic en el overlay
const modal = document.getElementById('ticketAlertModal');
if (modal) {
modal.addEventListener('click', (e) => {
// Si el clic fue en el overlay (no en el modal), prevenir el cierre
if (e.target === modal) {
e.preventDefault();
e.stopPropagation();
return false;
}
});
// Prevenir que el modal se cierre con la tecla Escape
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape' && modal.style.display === 'block') {
e.preventDefault();
e.stopPropagation();
return false;
}
});
}
}
async loadConfig() {
try {
const response = await fetch('{{ path("helpdesk_member_ticket_alert_config_api") }}', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'X-Requested-With': 'XMLHttpRequest'
}
});
if (response.ok) {
const data = await response.json();
this.config = data;
}
} catch (e) {
// Si falla, usa valores por defecto
}
}
startPeriodicCheck() {
// Verificar cada 30 segundos si debe mostrar la alerta
this.checkInterval = setInterval(() => {
this.checkAlerts();
}, 30000); // 30 segundos
}
shouldShowAlert() {
const lastShown = localStorage.getItem(this.storageKey);
if (!lastShown) {
return true; // Primera vez, mostrar alerta
}
// Detectar si es formato antiguo (español) y limpiarlo
if (lastShown.includes('/') && lastShown.includes(',')) {
console.log('Formato de fecha antiguo detectado, limpiando localStorage...');
localStorage.removeItem(this.storageKey);
return true; // Mostrar alerta inmediatamente después de limpiar
}
const lastShownDate = new Date(lastShown);
const currentDate = new Date();
const timeDiff = currentDate.getTime() - lastShownDate.getTime();
console.log('Última alerta mostrada:', lastShown);
console.log('Fecha actual:', currentDate.toISOString());
console.log('Diferencia de tiempo (ms):', timeDiff);
console.log('Intervalo configurado (ms):', this.config.interval);
console.log('¿Debe mostrar alerta?:', timeDiff >= this.config.interval);
// Si ha pasado más tiempo que el intervalo configurado, mostrar alerta
return timeDiff >= this.config.interval;
}
markAlertAsShown() {
const now = new Date();
// Usar formato ISO 8601 para máxima compatibilidad
const dateString = now.toISOString();
localStorage.setItem(this.storageKey, dateString);
console.log('Alerta marcada como mostrada:', dateString);
}
async checkAlerts() {
// Solo verificar si debe mostrar la alerta
if (!this.shouldShowAlert()) {
return;
}
try {
const response = await fetch('{{ path("helpdesk_member_ticket_alerts_xhr") }}', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'X-Requested-With': 'XMLHttpRequest'
}
});
if (response.ok) {
const data = await response.json();
this.overdueData = data.overdue || {};
} else {
console.error('Error fetching ticket alerts:', response.status);
this.overdueData = {};
}
} catch (error) {
console.error('Error fetching ticket alerts:', error);
this.overdueData = {};
}
this.updateIndicators();
if (this.hasAlerts()) {
this.showAlert();
this.markAlertAsShown(); // Marcar como mostrada
}
}
hasAlerts() {
return Object.keys(this.overdueData).length > 0;
}
updateIndicators() {
const pendingIndicator = document.getElementById('pending-alert-indicator');
const resolvedIndicator = document.getElementById('resolved-alert-indicator');
if (pendingIndicator) pendingIndicator.style.display = 'none';
if (resolvedIndicator) resolvedIndicator.style.display = 'none';
}
showAlert() {
const modal = document.getElementById('ticketAlertModal');
const body = document.getElementById('ticketAlertBody');
const aside = document.querySelector('.uv-inner-section .uv-aside');
if (aside) aside.style.zIndex = '1';
if (!modal || !body) return;
let html = '';
if (this.hasAlerts()) {
html += `<div style="font-size:1.2em;font-weight:bold;margin-bottom:10px;">${ticketAlertTranslations.overdueMessage}</div>`;
html += '<ul style="padding-left:20px;">';
for (const [status, count] of Object.entries(this.overdueData)) {
const ticketText = count > 1 ? 'tickets' : 'ticket';
html += `<li>${count} ${ticketText} ${ticketAlertTranslations.ticketStatus} "${status}" ${ticketAlertTranslations.forMoreThan} ${this.config.days_threshold} ${ticketAlertTranslations.days}.</li>`;
}
html += '</ul>';
} else {
html = `<div class="ticket-alert-empty">${ticketAlertTranslations.noTicketsRequireAttention}</div>`;
}
body.innerHTML = html;
modal.style.display = 'block';
}
setReminder() {
this.closeAlert();
this.reminderTimeout = setTimeout(() => {
if (this.hasAlerts()) {
this.showAlert();
}
}, 60 * 60 * 1000);
}
closeAlert() {
const modal = document.getElementById('ticketAlertModal');
const aside = document.querySelector('.uv-inner-section .uv-aside');
if (aside) aside.style.zIndex = '4';
if (modal) {
modal.style.display = 'none';
}
}
viewAllTickets() {
this.closeAlert();
router.navigate('mine', {trigger: true});
}
destroy() {
if (this.checkInterval) {
clearInterval(this.checkInterval);
}
if (this.reminderTimeout) {
clearTimeout(this.reminderTimeout);
}
}
}
function closeTicketAlert() {
if (window.ticketAlertSystem) {
window.ticketAlertSystem.closeAlert();
}
}
function setReminder() {
if (window.ticketAlertSystem) {
window.ticketAlertSystem.setReminder();
}
}
function viewAllTickets() {
if (window.ticketAlertSystem) {
window.ticketAlertSystem.viewAllTickets();
}
}
document.addEventListener('DOMContentLoaded', function() {
window.ticketAlertSystem = new TicketAlertSystem();
});
window.addEventListener('beforeunload', function() {
if (window.ticketAlertSystem) {
window.ticketAlertSystem.destroy();
}
});
// Función para limpiar manualmente el localStorage (útil para debugging)
function clearTicketAlertStorage() {
const userId = "{{ user_service.getCurrentUser().id }}";
const storageKey = 'ticket_alert_last_shown_' + userId;
localStorage.removeItem(storageKey);
console.log('localStorage limpiado para usuario:', userId);
}
// Función para verificar el estado del localStorage
function checkTicketAlertStorage() {
const userId = "{{ user_service.getCurrentUser().id }}";
const storageKey = 'ticket_alert_last_shown_' + userId;
const lastShown = localStorage.getItem(storageKey);
console.log('Estado del localStorage:', {
storageKey: storageKey,
lastShown: lastShown,
hasValue: !!lastShown,
isOldFormat: lastShown ? (lastShown.includes('/') && lastShown.includes(',')) : false
});
}
</script>
{% endblock %}