public-typescript/contracts.ts
/* eslint-disable unicorn/prefer-module */
import type {
Contract
} from "../types/recordTypes";
import type {
DateDiff
} from "@cityssm/date-diff/types";
import type {
cityssmGlobal
} from "@cityssm/bulma-webapp-js/src/types";
import type {
BulmaJS
} from "@cityssm/bulma-js/types";
import type {
DocuShareObject
} from "@cityssm/docushare/types";
declare const cityssm: cityssmGlobal;
declare const bulmaJS: BulmaJS;
(() => {
const urlPrefix = exports.urlPrefix as string;
const canUpdate = exports.canUpdate as boolean;
/*
* Exports
*/
const contractCategoryFilterElement = document.querySelector("#filters--contractCategory") as HTMLSelectElement;
const hasBeenReplacedFilterElement = document.querySelector("#filters--hasBeenReplaced") as HTMLSelectElement;
const managingUserNameFilterElement = document.querySelector("#filters--managingUserName") as HTMLSelectElement | HTMLInputElement;
const exportAnchorElements = {
csv: document.querySelector("#export--csv") as HTMLAnchorElement,
ical: document.querySelector("#export--ical") as HTMLAnchorElement,
"feed/atom": document.querySelector("#export--atom") as HTMLAnchorElement,
"feed/rss2": document.querySelector("#export--rss") as HTMLAnchorElement
};
const setExportURL = (exportType: "csv" | "ical" | "feed/atom" | "feed/rss2") => {
const exportURLString = window.location.protocol + "//" +
window.location.host +
urlPrefix +
"/export" +
"/" + exportType +
"/" + exports.userName +
"/" + exports.guidA +
"/" + exports.guidB;
const exportURL = new URL(exportURLString);
if (contractCategoryFilterElement.value !== "") {
exportURL.searchParams.set("contractCategory", contractCategoryFilterElement.value);
}
exportURL.searchParams.set("searchString", (document.querySelector("#filters--searchString") as HTMLInputElement).value);
if (hasBeenReplacedFilterElement.value !== "") {
exportURL.searchParams.set("hasBeenReplaced", hasBeenReplacedFilterElement.value);
}
if (managingUserNameFilterElement.value !== "") {
exportURL.searchParams.set("managingUserName", managingUserNameFilterElement.value);
}
if (includeExpiredFilterElement.checked) {
exportURL.searchParams.set("includeExpired", includeExpiredFilterElement.value);
}
exportAnchorElements[exportType].href = exportURL.href;
};
const setExportURLs = () => {
setExportURL("csv");
setExportURL("ical");
setExportURL("feed/rss2");
setExportURL("feed/atom");
};
const doResetUserAccessGUIDs = () => {
cityssm.postJSON(urlPrefix + "/contracts/doResetUserAccessGUIDs", {},
(responseJSON: {
success: boolean;guidA: string;guidB: string;
}) => {
if (responseJSON.success) {
bulmaJS.alert({
title: "Export Keys Reset Successfully",
message: "Note that if your export links are used by any application like Microsoft Excel or Outlook, you will have to update those links."
});
exports.guidA = responseJSON.guidA;
exports.guidB = responseJSON.guidB;
setExportURLs();
}
});
};
document.querySelector("#navbar--resetUserAccessGUIDs").addEventListener("click", (clickEvent) => {
clickEvent.preventDefault();
bulmaJS.confirm({
contextualColorName: "warning",
title: "Are you sure you want to reset your export keys?",
message: "This should definitely be done if you think your export keys have been compromised.",
okButton: {
text: "Yes, Reset the Keys",
callbackFunction: doResetUserAccessGUIDs
}
})
})
/*
* Field Customizations
*/
const contractAlias = exports.customizations_contract_alias as string;
const contractAliasPlural = exports.customizations_contract_aliasPlural as string;
const contractCategoryAlias = exports.customizations_contractCategory_alias as string;
const contractCategoryAliasPlural = exports.customizations_contractCategory_aliasPlural as string;
const contractPartyAlias = exports.customizations_contractParty_alias as string;
const populateCustomFieldNames = (containerElement: HTMLElement) => {
const contractAliasElements = containerElement.querySelectorAll("[data-customization='contract.alias']");
for (const contractAliasElement of contractAliasElements) {
contractAliasElement.textContent = contractAlias;
}
const contractCategoryAliasElements = containerElement.querySelectorAll("[data-customization='contractCategory.alias']");
for (const contractCategoryAliasElement of contractCategoryAliasElements) {
contractCategoryAliasElement.textContent = contractCategoryAlias;
}
const contractPartyAliasElements = containerElement.querySelectorAll("[data-customization='contractParty.alias']");
for (const contractPartyAliasElement of contractPartyAliasElements) {
contractPartyAliasElement.textContent = contractPartyAlias;
}
};
/*
* Contract Categories
*/
let contractCategories: string[] = exports.contractCategories;
const renderContractCategories = () => {
const currentContractCategory = contractCategoryFilterElement.value;
let currentContractCategoryFound = false;
contractCategoryFilterElement.innerHTML = "<option value=\"\">(All Available " + cityssm.escapeHTML(contractCategoryAliasPlural) + ")</option>";
for (const contractCategory of contractCategories) {
const optionElement = document.createElement("option");
optionElement.value = contractCategory;
optionElement.textContent = contractCategory;
contractCategoryFilterElement.append(optionElement);
if (currentContractCategory === contractCategory) {
optionElement.selected = true;
currentContractCategoryFound = true;
}
}
if (currentContractCategory !== "" && !currentContractCategoryFound) {
getContracts();
}
};
const refreshContractCategories = () => {
cityssm.postJSON(urlPrefix + "/contracts/doGetContractCategories", {},
(responseJSON: {
contractCategories: string[];
}) => {
contractCategories = responseJSON.contractCategories;
exports.contractCategories = responseJSON.contractCategories;
renderContractCategories();
});
};
renderContractCategories();
/*
* Contract Search
*/
const dateDiff = exports.dateDiff as DateDiff;
const filterFormElement = document.querySelector("#form--filters") as HTMLFormElement;
const includeExpiredFilterElement = filterFormElement.querySelector("#filters--includeExpired") as HTMLInputElement;
const searchResultsElement = document.querySelector("#container--results") as HTMLDivElement;
const getContracts = () => {
const currentDate = new Date();
const currentDateString = cityssm.dateToString(currentDate);
searchResultsElement.innerHTML = "<div class=\"has-text-centered p-4\">" +
"<span class=\"icon\"><i class=\"fas fa-4x fa-spinner fa-pulse\" aria-hidden=\"true\"></i></span>" +
"</div>";
cityssm.postJSON(urlPrefix + "/contracts/doGetContracts", filterFormElement,
(responseJSON: {
contracts: Contract[]
}) => {
if (responseJSON.contracts.length === 0) {
searchResultsElement.innerHTML = "<div class=\"message is-info\">" +
"<p class=\"message-body\">There are no " + contractAliasPlural.toLowerCase() + " available.</p>" +
"</div>";
return;
}
const panelElement = document.createElement("div");
panelElement.className = "panel";
for (const contract of responseJSON.contracts) {
const panelBlockElement = document.createElement("a");
panelBlockElement.className = "panel-block is-block";
if (contract.endDate && contract.endDateString < currentDateString) {
panelBlockElement.classList.add("has-background-danger-light");
}
panelBlockElement.dataset.contractId = contract.contractId.toString();
panelBlockElement.href = "#";
panelBlockElement.addEventListener("click", openContract);
panelBlockElement.innerHTML = "<div class=\"columns is-multiline is-mobile\">" +
("<div class=\"column is-12-mobile is-8-tablet\">" +
"<h2 class=\"title is-5 mb-1\">" +
cityssm.escapeHTML(contract.contractTitle) +
"</h2>" +
"<div class=\"columns is-mobile\">" +
("<div class=\"column\">" +
(contract.hasBeenReplaced ?
"<span class=\"icon\"><i class=\"fas fa-fast-forward\" aria-hidden=\"true\"></i></span> Replaced<br />" :
"") +
(contract.contractCategory !== "" ?
"<span class=\"icon\"><i class=\"fas fa-archive\" aria-hidden=\"true\"></i></span> " + cityssm.escapeHTML(contract.contractCategory) + "<br />" :
"") +
(contract.contractParty !== "" ?
"<span class=\"icon\"><i class=\"fas fa-user-tie\" aria-hidden=\"true\"></i></span> " + cityssm.escapeHTML(contract.contractParty) + "<br />" :
"") +
"</div>") +
(contract.managingUserName && contract.managingUserName !== "" ?
"<div class=\"column is-4\">" +
"<span class=\"icon\"><i class=\"fas fa-id-card\" aria-hidden=\"true\"></i></span> " + cityssm.escapeHTML(contract.managingUserName) +
"</div>" :
"") +
"</div>" +
"</div>") +
("<div class=\"column is-6-mobile has-text-centered\">" +
"<i class=\"fas fa-play" + (contract.startDateString <= currentDateString ? " has-text-success" : "") + "\" aria-hidden=\"true\"></i><br />" +
contract.startDateString +
(contract.startDateString <= currentDateString ?
"<br /><span class=\"is-size-7\">" + dateDiff(cityssm.dateStringToDate(contract.startDateString), currentDate).formatted + " ago" :
"") +
"</div>") +
("<div class=\"column is-6-mobile has-text-centered\">" +
"<i class=\"fas fa-stop\" aria-hidden=\"true\"></i><br />" +
(contract.endDate ?
contract.endDateString :
"<span class=\"has-text-grey\">No End Date</span>") +
(contract.extensionDate ?
"<br /><span class=\"is-size-7\">Extend to " + contract.extensionDateString + "</span>" :
"") +
"</div>") +
"</div>";
panelElement.append(panelBlockElement);
}
searchResultsElement.innerHTML = "";
searchResultsElement.append(panelElement);
});
setExportURLs();
};
const openContract = (clickEvent: Event) => {
clickEvent.preventDefault();
const contractId = (clickEvent.currentTarget as HTMLAnchorElement).dataset.contractId;
cityssm.openHtmlModal("contractView", {
onshow: (modalElement) => {
populateCustomFieldNames(modalElement);
if (canUpdate) {
modalElement.querySelector("#contractEdit--privateContractDescription").closest(".field").classList.remove("is-hidden");
}
},
onshown: (modalElement, closeModalFunction) => {
bulmaJS.toggleHtmlClipped();
cityssm.postJSON(urlPrefix + "/contracts/doGetContract", {
contractId
}, (responseJSON: {
contract: Contract;
}) => {
const contract = responseJSON.contract;
if (!contract || !contract.contractId) {
closeModalFunction();
cityssm.alertModal(contractAlias + " Not Found", "Please try again.", "OK", "danger");
getContracts();
return;
}
(modalElement.querySelector("#contractEdit--contractId") as HTMLInputElement).value = contract.contractId.toString();
(modalElement.querySelector("#contractEdit--contractTitle") as HTMLInputElement).value = contract.contractTitle;
(modalElement.querySelector("#contractEdit--contractCategory") as HTMLInputElement).value = contract.contractCategory;
(modalElement.querySelector("#contractEdit--contractParty") as HTMLInputElement).value = contract.contractParty;
if (contract.hasBeenReplaced) {
(modalElement.querySelector("#contractEdit--hasBeenReplaced") as HTMLInputElement).checked = true;
}
const managingUserNameElement = modalElement.querySelector("#contractEdit--managingUserName") as HTMLSelectElement;
let managingUserNameFound = false;
if (canUpdate) {
for (const userName of (exports.canUpdateUserNames as string[])) {
const optionElement = document.createElement("option");
optionElement.textContent = userName;
optionElement.value = userName;
managingUserNameElement.append(optionElement);
if (contract.managingUserName && contract.managingUserName === userName) {
optionElement.selected = true;
managingUserNameFound = true;
}
}
}
if (contract.managingUserName && contract.managingUserName !== "" && !managingUserNameFound) {
const optionElement = document.createElement("option");
optionElement.textContent = contract.managingUserName;
optionElement.value = contract.managingUserName;
managingUserNameElement.append(optionElement);
optionElement.selected = true;
}
(modalElement.querySelector("#contractEdit--contractDescription") as HTMLInputElement).value = contract.contractDescription;
if (canUpdate) {
(modalElement.querySelector("#contractEdit--privateContractDescription") as HTMLInputElement).value = contract.privateContractDescription;
}
(modalElement.querySelector("#contractEdit--startDateString") as HTMLInputElement).value = contract.startDateString;
(modalElement.querySelector("#contractEdit--endDateString") as HTMLInputElement).value = contract.endDateString;
(modalElement.querySelector("#contractEdit--extensionDateString") as HTMLInputElement).value = contract.extensionDateString;
});
if (exports.docuShare_isEnabled) {
modalElement.querySelector("#section--contractDocuShare").classList.remove("is-hidden");
cityssm.postJSON(urlPrefix + "/docuShare/doGetContractDocuments", {
contractId
}, (responseJSON: {
rootURL: string;
handle: string;
documents: DocuShareObject[];
}) => {
const containerElement = modalElement.querySelector("#container--contractDocuShare") as HTMLElement;
if (responseJSON.documents.length === 0) {
containerElement.innerHTML = "<div class=\"message is-info\">" +
"<p class=\"message-body\">There are no related documents.</p>" +
"</div>";
} else {
const panelElement = document.createElement("div");
panelElement.className = "panel";
for (const docuShareDocument of responseJSON.documents) {
const panelBlockElement = document.createElement("a");
panelBlockElement.className = "panel-block is-block";
panelBlockElement.href = responseJSON.rootURL + "/dsweb/View/" + docuShareDocument.handle;
panelBlockElement.target = "_blank";
panelBlockElement.rel = "noopener";
panelBlockElement.innerHTML = "<strong>" + cityssm.escapeHTML(docuShareDocument.title) + "</strong><br />" +
cityssm.escapeHTML(docuShareDocument.summary);
panelElement.append(panelBlockElement);
}
containerElement.innerHTML = "";
containerElement.append(panelElement);
}
containerElement.insertAdjacentHTML("afterbegin",
"<a class=\"button is-fullwidth is-link is-light mb-2\" href=\"" + responseJSON.rootURL + "/dsweb/View/" + responseJSON.handle + "\" target=\"_blank\" rel=\"noopener\">" +
"Open Collection in DocuShare" +
"</a>");
});
}
if (canUpdate) {
const editModeButtonElement = modalElement.querySelector("#button--switchToEditMode") as HTMLButtonElement;
editModeButtonElement.classList.remove("is-hidden");
editModeButtonElement.addEventListener("click", () => {
switchContractToEditMode(closeModalFunction);
});
}
},
onremoved: () => {
bulmaJS.toggleHtmlClipped();
}
});
};
filterFormElement.addEventListener("submit", (formEvent) => {
formEvent.preventDefault();
});
contractCategoryFilterElement.addEventListener("change", getContracts);
document.querySelector("#filters--searchString").addEventListener("change", getContracts);
hasBeenReplacedFilterElement.addEventListener("change", getContracts);
includeExpiredFilterElement.addEventListener("change", getContracts);
managingUserNameFilterElement.addEventListener("change", getContracts);
getContracts();
/*
* Contract Maintenance
*/
if (!canUpdate) {
return;
}
// UPDATE ONLY
document.querySelector("#button--addContract").addEventListener("click", () => {
let addContractCloseModalFunction: () => void;
let formElement: HTMLFormElement;
const submitFunction = (formEvent: Event) => {
formEvent.preventDefault();
cityssm.postJSON(urlPrefix + "/contracts/doAddContract", formElement,
(responseJSON: {
success: boolean
}) => {
if (responseJSON.success) {
addContractCloseModalFunction();
if ((formElement.querySelector("#contractAdd--contractCategoryIsNew") as HTMLSelectElement).value === "1") {
refreshContractCategories();
}
getContracts();
} else {
cityssm.alertModal("Error Adding " + contractAlias,
"Please try again",
"OK",
"danger");
}
});
};
cityssm.openHtmlModal("contractAdd", {
onshow: (modalElement) => {
populateCustomFieldNames(modalElement);
const existingContactCategoryElement = modalElement.querySelector("#contractAdd--contactCategory-existing");
for (const contractCategory of contractCategories) {
const optionElement = document.createElement("option");
optionElement.textContent = contractCategory;
optionElement.value = contractCategory;
existingContactCategoryElement.append(optionElement);
}
const managingUserNameElement = modalElement.querySelector("#contractAdd--managingUserName");
for (const managingUserName of (exports.canUpdateUserNames as string[])) {
const optionElement = document.createElement("option");
optionElement.textContent = managingUserName;
optionElement.value = managingUserName;
managingUserNameElement.append(optionElement);
if (managingUserName === exports.userName) {
optionElement.selected = true;
}
}
},
onshown: (modalElement, closeModalFunction) => {
bulmaJS.toggleHtmlClipped();
addContractCloseModalFunction = closeModalFunction;
formElement = modalElement.querySelector("form");
formElement.addEventListener("submit", submitFunction);
const contractCategoryIsNewElement = modalElement.querySelector("#contractAdd--contractCategoryIsNew") as HTMLSelectElement;
contractCategoryIsNewElement.addEventListener("change", () => {
const contractCategoryIsNew = contractCategoryIsNewElement.value === "1";
if (contractCategoryIsNew) {
modalElement.querySelector("#field--contractAdd--contractCategory-existing").classList.add("is-hidden");
modalElement.querySelector("#field--contractAdd--contractCategory-new").classList.remove("is-hidden");
} else {
modalElement.querySelector("#field--contractAdd--contractCategory-new").classList.add("is-hidden");
modalElement.querySelector("#field--contractAdd--contractCategory-existing").classList.remove("is-hidden");
}
});
},
onremoved: () => {
bulmaJS.toggleHtmlClipped();
}
});
});
const switchContractToEditMode = (closeModalFunction: () => void) => {
bulmaJS.init();
// Set up form
const editFormElement = document.querySelector("#form--contractEdit");
editFormElement.querySelector("fieldset").disabled = false;
editFormElement.addEventListener("submit", (formEvent) => {
formEvent.preventDefault();
cityssm.postJSON(urlPrefix + "/contracts/doUpdateContract",
editFormElement,
(responseJSON: {
success: boolean;
}) => {
if (responseJSON.success) {
closeModalFunction();
getContracts();
}
});
});
// Toggle the button visibility
//
const modalElement = editFormElement.closest(".modal");
modalElement.querySelector("#button--switchToEditMode").remove();
modalElement.querySelector("button[type='submit']").classList.remove("is-hidden");
modalElement.querySelector("#contractEdit--optionsButton").classList.remove("is-hidden");
// Set up remove
const removeContract = () => {
const contractId = (editFormElement.querySelector("#contractEdit--contractId") as HTMLInputElement).value;
cityssm.postJSON(urlPrefix + "/contracts/doRemoveContract", {
contractId
}, (responseJSON: {
success: boolean;
}) => {
if (responseJSON.success) {
closeModalFunction();
refreshContractCategories();
getContracts();
}
});
};
modalElement.querySelector("#contractEdit--removeContractButton").addEventListener("click", (clickEvent) => {
clickEvent.preventDefault();
bulmaJS.confirm({
message: "Are you sure you want to remove this contract record?",
okButton: {
text: "Yes, Remove the Contract",
callbackFunction: removeContract
}
});
});
};
})();