307 lines
10 KiB
JavaScript

var filters = {"order": "-edit_timestamp"};
global_loadingTickets = false;
searchTimeout = null;
pagination = {};
$(document).ready(function() {
initSearchBar();
setupFilter("#filterSidebar .filter-department", "author__department");
setupFilter("#filterSidebar .filter-tags", "tags");
setupFilter("#filterSidebar .filter-priority", "priority");
loadFilterCounts();
loadTicketItems();
});
function updateInterfaceState(state) {
console.debug(`updating interface state to '${state}'`);
switch (state) {
case "content":
$("#ticketsContainer .none-found").hide();
$("#ticketsContainer .loading").hide();
break;
case "loading":
$("#ticketsContainer .content").empty();
$("#ticketsContainer .none-found").hide();
$("#ticketsContainer .loading").show();
break;
case "no-content":
$("#ticketsContainer .content").empty();
$("#ticketsContainer .none-found").show();
$("#ticketsContainer .loading").hide();
break;
default:
throw new Error(`Invalid Interface State '${state}'`);
}
}
function initSearchBar() {
$("#searchTickets").keyup(() => {
updateInterfaceState("loading");
clearTimeout(searchTimeout);
searchTimeout = setTimeout(() => {
console.debug("searching");
value = $("#searchTickets").val();
if (value === "") {
console.debug("deleted search filters");
delete filters["search"];
}
else {
console.debug("updated search filters");
filters["search"] = value;
}
loadTicketItems();
}, 500);
})
}
function setupFilter(selector, key) {
$(selector).each(function () {
var input = $(this).find("input[type=checkbox], input[type=radio]");
var uuid = input.val();
input.on("change", function () {
if (input.is(":checkbox")) {
if ($(this).is(":checked")) {
filters[key] = filters[key] || [];
filters[key].push(uuid);
}
else {
filters[key] = filters[key].filter(id => id !== uuid);
if (filters[key].length === 0) delete filters[key];
}
}
else if (input.is(":radio") && input.is(":checked")) {
if (uuid === "all") delete filters[key];
else filters[key] = [uuid];
}
console.debug(`Filter applied '${key}' as '${uuid}'`)
loadTicketItems();
});
});
}
function getOrdinalSuffix(day) {
if (day >= 11 && day <= 13) {
return day + 'th';
} else {
switch (day % 10) {
case 1: return day + 'st';
case 2: return day + 'nd';
case 3: return day + 'rd';
default: return day + 'th';
}
}
}
function timestampToHumanDate(timestamp, wasYesterday) {
if (wasYesterday) {
var day = getOrdinalSuffix(timestamp.getDate());
var month = timestamp.toLocaleString('en-GB', { month: 'short' });
var year = timestamp.toLocaleString('en-GB', { year: 'numeric' });
var time = timestamp.toLocaleString('en-GB', { hour: 'numeric', minute: 'numeric' });
return time + ', ' + day + ' ' + month + ' ' + year;
}
var hours = timestamp.getUTCHours();
var minutes = timestamp.getUTCMinutes();
return hours.toString().padStart(2, '0') + ':' + minutes.toString().padStart(2, '0');
}
function updateFilterCounts(filterType, data) {
$("#filterSidebar .filter-" + filterType).each(function() {
var uuid = $(this).find("input[type=checkbox],input[type=radio]").val();
var count = data[filterType][uuid];
$(this).find(".badge").text(count);
});
}
function loadFilterCounts() {
$.ajax({
url: URL_FilterCounts,
type: "GET",
success: function(data) {
updateFilterCounts('priority', data);
updateFilterCounts('tags', data);
updateFilterCounts('department', data);
$("#filterPriorityAll .badge").text(data.tickets);
$("#filterDepartmentAll .badge").text(data.tickets)
// $("#ticketCounts .total").text(data.tickets)
},
error: function(data) {
console.error(JSON.stringify(data, null, 4))
}
});
}
function applyTicketClickFunction() {
$(".ticket-item").on("click", function(e) {
e.preventDefault();
loadTicketContent($(this).data("uuid"));
$('.email-app').removeClass('side-active');
$('.email-content').toggleClass('open');
});
}
function reloadCurrentTicket() {
loadTicketContent($(".ticket-item.bgc-grey-100").data("uuid"));
}
function changeTicket(next=true) {
var selectedTicket = $(".ticket-item.bgc-grey-100");
var uuid;
if (!selectedTicket.length) {
uuid = $(".ticket-item").first().data("uuid");
loadTicketContent(uuid);
return;
}
if (next) {
uuid = selectedTicket.next().data("uuid");
loadTicketContent(uuid);
}
else {
uuid = selectedTicket.prev().data("uuid");
loadTicketContent(uuid);
}
if (!$('.email-content').hasClass('open')) {
$('.email-content').addClass('open');
}
}
function changeItemsPage(next) {
$("#ticketItemsNextPage").prop("disabled", true);
$("#ticketItemsPrevPage").prop("disabled", true);
var page = pagination.page;
if (next && pagination.next) page ++;
else if (!next && pagination.prev) page --;
else return;
filters["page"] = page;
loadTicketItems();
}
function loadTicketItems() {
updateInterfaceState("loading");
fetchTicketsPromise(filters).then((response) => {
// Update the counts to show how many tickets were found
$("#ticketCounts .current").text(response.results.length);
$("#ticketCounts .total").text(response.count);
// If there are no tickets
if (!response.count) {
updateInterfaceState("no-content");
return;
}
const ticketHasNextPage = typeof response.next === "string";
const ticketHasPrevPage = typeof response.previous === "string";
$("#ticketItemsNextPage").prop("disabled", !ticketHasNextPage);
$("#ticketItemsPrevPage").prop("disabled", !ticketHasPrevPage);
const pageNumber = filters["page"] || 1;
pagination = {
"page": pageNumber,
"next": ticketHasNextPage,
"prev": ticketHasPrevPage
}
// Iterate over and handle each ticket
response.results.forEach(function(ticket) {
// Create a formatted version of the ticket's timestamp
const timestamp = new Date(ticket.timestamp);
var formattedTime = timestampToHumanDate(timestamp, ticket.was_yesterday);
// Mark the ticket if it is edited
if (ticket.is_edited) formattedTime += " • edited";
// Create a copy of the template using the ticket data
var template = $($("#ticketItemTemplate").html());
template.find(".ticket-item-author").text(`${ticket.author.forename} ${ticket.author.surname}`);
template.find(".ticket-item-datetime").text(formattedTime);
template.find(".ticket-item-title").text(ticket.title);
template.find(".ticket-item-desc").text(ticket.description);
template.find(".ticket-item-icon").attr("src", ticket.author.icon);
template.attr("data-uuid", ticket.uuid);
// Add the content to the interface
$("#ticketsContainer .content").append(template);
});
// Make tickets clickable
applyTicketClickFunction();
updateInterfaceState("content");
});
}
function loadTicketContent(uuid) {
// updateInterfaceState("loading-content");
if (global_loadingTickets) {
console.debug("Spam prevention\nStopped loadTicketContent because already loading.");
return;
}
$("#ticketContent").empty();
fetchTicketsPromise({uuid: uuid}).then((response) => {
ticket = response.results[0];
// Create a formatted version of the ticket's timestamp
const timestamp = new Date(ticket.timestamp);
var formattedTime = timestampToHumanDate(timestamp, ticket.was_yesterday);
// Mark the ticket if it is edited
if (ticket.is_edited) formattedTime += " • edited";
// Create a copy of the template using the ticket data
var template = $($("#ticketContentTemplate").html())
template.find(".ticket-content-author").text(`${ticket.author.forename} ${ticket.author.surname}`);
template.find(".ticket-content-datetime").text(formattedTime);
template.find(".ticket-content-title").text(ticket.title);
template.find(".ticket-content-desc").text(ticket.description);
template.find(".ticket-content-icon").attr("src", ticket.author.icon);
$("#ticketContent").append(template);
});
// $("#ticketContent").empty();
// updateInterfaceState("showing-content");
}
function fetchTicketsPromise(queryFilters) {
return new Promise(function(resolve, reject) {
global_loadingTickets = true;
$.ajax({
url: URL_Tickets,
type: "GET",
dataType: "JSON",
data: $.param(queryFilters, true),
success: function(response) {
global_loadingTickets = false;
resolve(response);
},
error: function(response) {
global_loadingTickets = false;
if (response.status === 429) {
alert(`
HTTP ${response.status} - ${response.statusText}\n
${response.responseJSON.detail}
`);
}
reject(response);
}
});
});
}