reimbursinator/front/static/js/viewHistory.js

565 lines
20 KiB
JavaScript
Raw Normal View History

2019-02-10 06:23:08 +00:00
const reportType = {
NEW : 1,
EDIT : 2,
VIEW : 3
};
// Hack to change endpoint url
function getEndpointDomain() {
return "https://" + window.location.hostname + ":8444/";
}
2019-02-17 03:58:55 +00:00
function makeAjaxRequest(method, url, callback, optional, payload) {
2019-02-10 23:46:27 +00:00
const token = localStorage.getItem("token");
const xhr = new XMLHttpRequest();
console.log("Attempting a connection to the following endpoint: " + url);
2019-02-11 02:15:32 +00:00
xhr.open(method, url, true);
2019-02-10 23:46:27 +00:00
xhr.setRequestHeader("Authorization", "Bearer " + token);
switch (method) {
case "PUT":
break;
case "POST":
xhr.setRequestHeader("Content-Type", "application/json");
break;
default:
payload = null;
break;
}
2019-01-30 23:42:09 +00:00
2019-02-10 05:16:53 +00:00
xhr.onreadystatechange = function() {
if (this.readyState === 4) {
if (this.status === 200) {
2019-02-11 02:15:32 +00:00
console.log(method + " SUCCESS!");
2019-02-10 05:16:53 +00:00
console.log("Server response:\n" + this.response);
let parsedData = JSON.parse(this.response);
2019-02-17 03:58:55 +00:00
optional ? callback(parsedData, optional) : callback(parsedData);
2019-02-10 05:16:53 +00:00
} else {
2019-02-11 02:15:32 +00:00
console.error(method + " FAILURE!");
2019-02-10 05:16:53 +00:00
console.error("Server status: " + this.status);
console.error("Server response:\n" + this.response);
}
}
};
xhr.onerror = function() {
alert("Connection error!");
};
xhr.send(payload);
}
2019-02-20 06:42:30 +00:00
function updateSection(parsedData, saveButton) {
saveButton.innerHTML = "Save";
saveButton.disabled = false;
const sectionState = document.querySelector("#section-" + parsedData.id + "-state");
if (parsedData.completed) {
sectionState.classList = "fas fa-check-square";
} else {
sectionState.classList = "fas fa-exclamation-triangle";
}
const collapseDiv = document.querySelector("#section-" + parsedData.id + "-collapse");
const cardFooter = createCardFooter(parsedData.rule_violations);
if (collapseDiv.lastElementChild.classList.contains("card-footer")) {
collapseDiv.removeChild(collapseDiv.lastElementChild);
if (cardFooter) {
collapseDiv.appendChild(cardFooter);
}
} else {
if (cardFooter) {
collapseDiv.appendChild(cardFooter);
}
}
}
// Wraps a Bootstrap form group around a field
2019-02-14 23:58:27 +00:00
function createFormGroup(sectionIdStr, field) {
const inputId = sectionIdStr + field.field_name;
2019-02-01 00:27:29 +00:00
const formGroup = document.createElement("div")
2019-02-03 03:05:39 +00:00
formGroup.classList.add("form-group", "row");
2019-02-01 00:27:29 +00:00
const label = document.createElement("label");
2019-02-03 21:47:12 +00:00
label.classList.add("col-sm-4", "col-form");
label.innerHTML = field.label + ": ";
label.setAttribute("for", inputId);
2019-02-03 03:05:39 +00:00
const div = document.createElement("div");
2019-02-03 21:47:12 +00:00
div.classList.add("col-sm-6");
2019-02-01 00:27:29 +00:00
const input = document.createElement("input");
2019-02-10 05:16:53 +00:00
input.name = field.field_name;
input.id = inputId;
switch(field.field_type) {
case "boolean":
2019-02-14 22:17:25 +00:00
const select = document.createElement("select");
select.name = field.field_name;
select.id = inputId;
2019-02-14 22:17:25 +00:00
select.classList.add("form-control");
const yesOption = document.createElement("option");
yesOption.innerHTML = "Yes";
yesOption.value = "true";
const noOption = document.createElement("option");
noOption.innerHTML = "No";
noOption.value = "false";
if (field.value === true) {
yesOption.setAttribute("selected", "selected");
} else {
noOption.setAttribute("selected", "selected");
}
select.appendChild(yesOption);
select.appendChild(noOption);
formGroup.appendChild(label);
div.appendChild(select)
2019-02-03 03:05:39 +00:00
formGroup.appendChild(div);
break;
case "date":
2019-02-16 04:15:39 +00:00
input.type = "date";
input.placeholder = "mm-dd-yyyy";
if (field.value === "None") {
input.value = "";
} else {
input.value = field.value;
}
input.classList.add("form-control");
formGroup.appendChild(label);
div.appendChild(input)
formGroup.appendChild(div);
break;
2019-02-10 05:16:53 +00:00
case "string":
input.type = "text";
input.value = field.value;
input.classList.add("form-control");
formGroup.appendChild(label);
div.appendChild(input)
formGroup.appendChild(div);
break;
case "decimal":
input.type = "text";
2019-02-16 04:15:39 +00:00
if (field.value === "0.00") {
input.value = "";
} else {
input.value = field.value;
}
2019-02-01 01:48:36 +00:00
input.classList.add("form-control");
2019-02-10 05:16:53 +00:00
input.pattern = "\\d+(\\.\\d{2})?";
formGroup.appendChild(label);
div.appendChild(input)
formGroup.appendChild(div);
break;
case "integer":
input.type = "number";
2019-02-16 04:15:39 +00:00
if (field.value === 0) {
input.value = "";
} else {
input.value = field.value;
}
2019-02-10 05:16:53 +00:00
input.classList.add("form-control");
input.step = 1;
input.min = 0;
formGroup.appendChild(label);
2019-02-03 03:05:39 +00:00
div.appendChild(input)
formGroup.appendChild(div);
break;
case "file":
input.type = "file";
2019-02-01 01:48:36 +00:00
input.classList.add("form-control-file");
2019-02-03 03:05:39 +00:00
let uploadMessage = document.createElement("p");
uploadMessage.classList.add("form-text");
uploadMessage.innerHTML = field.value;
div.appendChild(input)
div.appendChild(uploadMessage);
formGroup.appendChild(label);
2019-02-03 03:05:39 +00:00
formGroup.appendChild(div);
break;
default:
break;
}
return formGroup;
}
function createCollapsibleCard(sectionIdStr, sectionTitle, sectionCompleted) {
// Create card and header
const card = document.createElement("div");
card.classList.add("card");
const cardHeader = document.createElement("div");
cardHeader.classList.add("card-header");
const sectionState = document.createElement("i");
sectionState.id = sectionIdStr + "state";
if (sectionCompleted) {
sectionState.classList.add("fas", "fa-check-square");
} else {
sectionState.classList.add("fas", "fa-exclamation-triangle");
}
// Create h2, button. Append button to h2, h2 to header, and header to card
const h2 = document.createElement("h2");
h2.classList.add("mb-0");
const button = document.createElement("button");
button.classList.add("btn", "btn-link");
button.type = "button";
button.setAttribute("data-toggle", "collapse");
2019-02-14 23:58:27 +00:00
button.setAttribute("data-target", "#" + sectionIdStr + "collapse");
button.innerHTML = sectionTitle;
h2.appendChild(button);
h2.appendChild(sectionState);
cardHeader.appendChild(h2);
card.appendChild(cardHeader);
return card;
}
2019-02-14 23:58:27 +00:00
function createCollapsibleCardBody(form, type, sectionIdStr, sectionDescription, sectionCompleted) {
2019-02-01 00:27:29 +00:00
// Create wrapper div
2019-02-16 20:24:19 +00:00
const collapseDiv = document.createElement("div");
collapseDiv.id = sectionIdStr + "collapse";
2019-02-04 09:39:42 +00:00
const cardBody = document.createElement("div");
cardBody.classList.add("card-body");
if (sectionCompleted) {
2019-02-16 20:24:19 +00:00
collapseDiv.classList.add("collapse");
} else {
2019-02-16 20:24:19 +00:00
collapseDiv.classList.add("collapse", "show");
}
2019-02-04 09:39:42 +00:00
if (type === reportType.EDIT) {
2019-02-16 20:24:19 +00:00
collapseDiv.setAttribute("data-parent", "#editReportAccordion");
2019-02-04 09:39:42 +00:00
} else {
2019-02-16 20:24:19 +00:00
collapseDiv.setAttribute("data-parent", "#newReportAccordion");
2019-02-04 09:39:42 +00:00
}
2019-02-01 00:27:29 +00:00
// Create card body. Append form to body, body to wrapper div
cardBody.insertAdjacentHTML("beforeend", sectionDescription);
cardBody.appendChild(form);
2019-02-16 20:24:19 +00:00
collapseDiv.appendChild(cardBody);
return collapseDiv;
}
function createCardFooter(ruleViolations) {
if (ruleViolations.length === 0) {
return null;
2019-02-16 20:24:19 +00:00
}
const cardFooter = document.createElement("div");
cardFooter.classList.add("card-footer");
2019-02-16 20:24:19 +00:00
const violationMessage = document.createElement("div");
violationMessage.classList.add("alert", "alert-danger");
const heading = document.createElement("div");
heading.innerHTML = "Rule Violations";
heading.classList.add("alert-heading");
violationMessage.appendChild(heading);
violationMessage.appendChild(document.createElement("hr"));
2019-02-16 20:24:19 +00:00
for (let i = 0; i < ruleViolations.length; i++) {
let violation = document.createElement("p");
let violationLabel = document.createElement("strong");
violationLabel.innerHTML = ruleViolations[i].label;
violation.appendChild(violationLabel);
violation.appendChild(document.createElement("br"));
let ruleBreakText = document.createTextNode(ruleViolations[i].rule_break_text);
violation.appendChild(ruleBreakText);
violationMessage.appendChild(violation);
}
cardFooter.appendChild(violationMessage);
return cardFooter;
}
2019-02-04 09:39:42 +00:00
function createReportForm(parsedData, type) {
let modalBody;
2019-02-14 22:21:43 +00:00
let modalLabel;
2019-02-04 09:39:42 +00:00
const accordion = document.createElement("div");
accordion.classList.add("accordion");
2019-02-19 04:14:48 +00:00
//submit button
const submitButton = document.querySelector(".submit-report-button");
if (submitButton) {
submitButton.setAttribute("data-rid", parsedData.report_pk);
}
2019-02-04 09:39:42 +00:00
if (type === reportType.EDIT) {
modalBody = document.querySelector("#editReportModalBody");
modalLabel = document.querySelector("#editReportModalLabel");
accordion.id = "editReportAccordion";
const deleteButton = document.querySelector(".delete-report");
if (deleteButton) {
deleteButton.setAttribute("data-rid", parsedData.report_pk);
}
2019-02-04 09:39:42 +00:00
} else if (type === reportType.NEW) {
modalBody = document.querySelector("#newReportModalBody");
modalLabel = document.querySelector("#newReportModalLabel");
accordion.id = "newReportAccordion";
} else {
return;
}
2019-01-30 23:42:09 +00:00
while (modalBody.firstChild) {
modalBody.removeChild(modalBody.firstChild);
2019-01-30 23:42:09 +00:00
}
2019-02-03 03:05:39 +00:00
// Add report title and date
2019-02-16 20:24:19 +00:00
modalLabel.innerHTML = parsedData.title;
2019-02-01 08:07:08 +00:00
// Traverse the report's sections array
2019-01-30 23:42:09 +00:00
const sections = parsedData.sections;
for (let i = 0; i < sections.length; i++) {
// Create a new form
2019-02-16 20:24:19 +00:00
let sectionIdStr = "section-" + sections[i].id + "-";
let form = document.createElement("form");
form.classList.add("form", "section-form");
2019-02-14 23:58:27 +00:00
form.id = sectionIdStr + "form";
form.setAttribute("data-rid", parsedData.report_pk);
form.setAttribute("data-sid", sections[i].id);
// Traverse the fields of this section
let fields = sections[i].fields;
for (let j = 0; j < fields.length; j++) {
2019-02-01 08:07:08 +00:00
/*
console.log("Field label: " + fields[j].label);
console.log("Field type: " + fields[j].field_type);
console.log("Field value: " + fields[j].value);
*/
2019-02-01 08:07:08 +00:00
// Create a form group for each field and add it to the form
2019-02-14 23:58:27 +00:00
form.appendChild(createFormGroup(sectionIdStr, fields[j]));
2019-01-30 23:42:09 +00:00
}
2019-02-01 08:07:08 +00:00
// Add save button to the current form
2019-02-01 01:48:36 +00:00
let saveButton = document.createElement("button");
saveButton.innerHTML = "Save";
saveButton.type = "submit";
saveButton.classList.add("btn", "btn-primary", "save-section");
2019-02-01 01:48:36 +00:00
form.appendChild(saveButton);
2019-02-01 00:27:29 +00:00
// Create collapsible card body, append form to it, append card to accordion
2019-02-16 20:24:19 +00:00
let cardBody = createCollapsibleCardBody(form, type, sectionIdStr,
sections[i].html_description, sections[i].completed);
let cardFooter = createCardFooter(sections[i].rule_violations);
if (cardFooter) {
cardBody.appendChild(cardFooter);
2019-02-16 20:24:19 +00:00
}
let collapsibleCard = createCollapsibleCard(sectionIdStr, sections[i].title, sections[i].completed)
collapsibleCard.appendChild(cardBody);
2019-02-01 08:07:08 +00:00
accordion.appendChild(collapsibleCard);
}
modalBody.appendChild(accordion);
2019-01-30 23:42:09 +00:00
}
function displayListOfReports(parsedData) {
const reports = parsedData.reports;
2019-02-17 00:41:11 +00:00
const cardBody = document.querySelector(".card-body");
2019-02-17 00:07:43 +00:00
const table = document.querySelector("table");
2019-02-17 00:41:11 +00:00
cardBody.removeChild(cardBody.firstElementChild); // remove loading spinner
2019-02-02 22:22:18 +00:00
if (reports.length === 0) {
2019-02-17 00:41:11 +00:00
cardBody.removeChild(table);
const h5 = document.createElement("h5");
h5.innerHTML = "No reports found.";
h5.classList.add("text-center");
cardBody.appendChild(h5);
} else {
2019-02-02 22:22:18 +00:00
const tbody = document.querySelector("tbody");
// Insert data into the table row
for (let i = 0; i < reports.length; i++) {
let title = reports[i].title;
let dateCreated = new Date(reports[i].date_created).toLocaleDateString("en-US");
2019-02-05 18:12:30 +00:00
let state = reports[i].submitted;
2019-02-02 22:22:18 +00:00
let dateSubmitted;
let rid = reports[i].report_pk;
let bodyRow = tbody.insertRow(i);
2019-02-02 22:22:18 +00:00
bodyRow.insertCell(0).innerHTML = title;
bodyRow.insertCell(1).innerHTML = dateCreated;
2019-02-02 22:22:18 +00:00
let stateCell = bodyRow.insertCell(2);
2019-02-05 18:12:30 +00:00
stateCell.innerHTML = state;
2019-02-02 22:22:18 +00:00
stateCell.classList.add("d-none", "d-lg-table-cell"); // Column visible only on large displays
// Create edit/view button
let actionButton = document.createElement("button");
actionButton.type = "submit";
actionButton.setAttribute("data-rid", rid);
actionButton.classList.add("btn");
2019-02-05 18:12:30 +00:00
if (state === false) {
2019-02-02 22:22:18 +00:00
// Edit button
dateSubmitted = "TBD";
actionButton.classList.add("btn-primary", "edit-report-button"); // Add event listener class
2019-02-02 22:22:18 +00:00
actionButton.innerHTML = "Edit";
actionButton.setAttribute("data-toggle", "modal");
actionButton.setAttribute("data-target", "#editReportModal");
2019-02-02 22:22:18 +00:00
} else {
// View button
dateSubmitted = new Date(reports[i].date_submitted).toLocaleDateString("en-US");
actionButton.classList.add("btn-success", "view-report-button");
2019-02-02 22:22:18 +00:00
actionButton.innerHTML = "View";
actionButton.setAttribute("data-toggle", "modal");
actionButton.setAttribute("data-target", "#viewReportModal");
2019-02-02 22:22:18 +00:00
}
let dateSubmittedCell = bodyRow.insertCell(3);
dateSubmittedCell.innerHTML = dateSubmitted;
dateSubmittedCell.classList.add("d-none", "d-md-table-cell"); // Column visible on medium and larger displays
bodyRow.insertCell(4).appendChild(actionButton);
}
table.style.visibility = "visible";
}
}
function displayReport(parsedData){
//Able to get the correct report ID now just needs to display the
//report as an modual
const modalBody = document.querySelector(".modal-view");
const modalLabel = document.querySelector("#viewReportModalLabel");
while (modalBody.firstChild) {
modalBody.removeChild(modalBody.firstChild);
}
// Add report title and date
const reportTitle = parsedData.title;
const dateCreated = new Date(parsedData.date_created).toLocaleDateString("en-US");
modalLabel.innerHTML = reportTitle + " " + dateCreated;
const card = document.createElement("div");
card.classList.add("card");
const cardHeader = document.createElement("div");
cardHeader.classList.add("card-header");
const cardBody = document.createElement("div");
cardBody.classList.add("card-body");
/*
const displayTable = document.createElement("table");
displayTable.classList.add("table table-striped table-responsive-sm");
displayTable.style.visibility = "visible";
cardBody.appendChild(displayTable);
*/
const sections = parsedData.sections;
for (let key in sections) {
let section = sections[key];
if(section.completed) {
const h4 = document.createElement("h4");
const value = document.createTextNode(section.title);
h4.appendChild(value);
cardBody.appendChild(h4);
let fields = section.fields;
for (let key in fields) {
let field = fields[key];
const p1 = document.createElement("p");
const p1Value = document.createTextNode(field.label + ": " + field.value);
p1.appendChild(p1Value);
cardBody.appendChild(p1);
}
cardHeader.appendChild(cardBody);
card.appendChild(cardHeader);
}
}
modalBody.appendChild(card);
}
document.addEventListener("DOMContentLoaded", function(event) {
2019-02-04 09:39:42 +00:00
if (window.location.pathname === "/edit_report.html") {
const url = getEndpointDomain() + "api/v1/reports";
2019-02-11 02:15:32 +00:00
makeAjaxRequest("GET", url, displayListOfReports);
2019-02-04 09:39:42 +00:00
}
});
document.addEventListener("click", function(event) {
2019-02-04 09:39:42 +00:00
if (event.target) {
if (event.target.classList.contains("edit-report-button")) {
const url = getEndpointDomain() + "api/v1/report/" + event.target.dataset.rid;
const type = reportType.EDIT;
2019-02-11 02:15:32 +00:00
makeAjaxRequest("GET", url, createReportForm, type);
2019-02-10 05:16:53 +00:00
} else if (event.target.classList.contains("view-report-button")) {
console.log("View button clicked");
2019-02-10 23:46:27 +00:00
const url = getEndpointDomain() + "api/v1/report/" + event.target.dataset.rid;
2019-02-11 02:15:32 +00:00
makeAjaxRequest("GET", url, displayReport);
2019-02-19 04:14:48 +00:00
} else if (event.target.classList.contains("submit-report-button")) {
event.preventDefault();
//const title = document.querySelector("#editReportModalLabel").textContent;
const result = confirm("Are you sure you want to submit the report ?");
if (result) {
const url = getEndpointDomain() + "api/v1/report/" + event.target.dataset.rid;
makeAjaxRequest("PUT", url, function(parsedData) {
alert(parsedData.message);
location.reload(true);
});
}
2019-02-10 23:57:05 +00:00
} else if (event.target.classList.contains("delete-report")) {
event.preventDefault();
2019-02-11 02:15:32 +00:00
const title = document.querySelector("#editReportModalLabel").textContent;
const result = confirm("Are you sure you want to delete the report \"" + title + "\"?");
2019-02-10 23:57:05 +00:00
if (result) {
const url = getEndpointDomain() + "api/v1/report/" + event.target.dataset.rid;
2019-02-11 02:15:32 +00:00
makeAjaxRequest("DELETE", url, function(parsedData) {
alert(parsedData.message);
location.reload(true);
});
2019-02-10 23:57:05 +00:00
}
2019-02-10 23:46:27 +00:00
}
}
});
2019-02-10 07:02:01 +00:00
const newReportForm = document.querySelector(".new-report-form");
if (newReportForm) {
newReportForm.addEventListener("submit", function(event) {
event.preventDefault();
2019-02-10 05:16:53 +00:00
const url = getEndpointDomain() + "api/v1/report";
const payload = JSON.stringify({ "title": event.target.elements.title.value });
console.log("Payload:\n" + payload);
const type = reportType.NEW;
2019-02-11 02:15:32 +00:00
makeAjaxRequest("POST", url, createReportForm, type, payload);
2019-02-10 07:02:01 +00:00
});
}
2019-02-16 04:15:39 +00:00
document.addEventListener("input", function(event) {
if (event.target.type === "date") {
if (!moment(event.target.value, "YYYY-MM-DD", true).isValid()) {
event.target.setCustomValidity("Invalid date format");
} else {
event.target.setCustomValidity("");
}
}
});
document.addEventListener("submit", function(event) {
if (event.target.classList.contains("section-form")) {
event.preventDefault();
2019-02-17 03:58:55 +00:00
let saveButton = event.target.lastElementChild;
saveButton.disabled = true;
saveButton.innerHTML = "";
let span = document.createElement("span");
span.classList.add("spinner-border", "spinner-border-sm");
2019-02-19 04:14:48 +00:00
saveButton.appendChild(span);
2019-02-17 03:58:55 +00:00
saveButton.appendChild(document.createTextNode(" Saving..."));
const formData = new FormData(event.target);
const url = getEndpointDomain() + "api/v1/report/" + event.target.dataset.rid + "/section/" + event.target.dataset.sid;
2019-02-20 06:42:30 +00:00
makeAjaxRequest("PUT", url, updateSection, saveButton, formData);
}
});
// Jquery is required to handle this modal event
$(document).ready(function(){
$("#newReportModal").on('hidden.bs.modal', function() {
location.reload(true);
});
});