/* eslint-disable @typescript-eslint/no-non-null-assertion, unicorn/prefer-module */
import type * as globalTypes from "../../types/globalTypes";
import type * as recordTypes from "../../types/recordTypes";
import type { cityssmGlobal } from "@cityssm/bulma-webapp-js/src/types";
import type { BulmaJS } from "@cityssm/bulma-js/types";
declare const cityssm: cityssmGlobal;
declare const bulmaJS: BulmaJS;
declare const los: globalTypes.LOS;
declare const lotOccupancyId: string;
declare const hasUnsavedChanges: boolean;
let lotOccupancyFees: recordTypes.LotOccupancyFee[] = exports.lotOccupancyFees;
delete exports.lotOccupancyFees;
const lotOccupancyFeesContainerElement = document.querySelector(
"#container--lotOccupancyFees"
) as HTMLElement;
const getFeeGrandTotal = (): number => {
let feeGrandTotal = 0;
for (const lotOccupancyFee of lotOccupancyFees) {
feeGrandTotal +=
(lotOccupancyFee.feeAmount! + lotOccupancyFee.taxAmount!) * lotOccupancyFee.quantity!;
}
return feeGrandTotal;
};
const deleteLotOccupancyFee = (clickEvent: Event) => {
const feeId = (
(clickEvent.currentTarget as HTMLElement).closest(
".container--lotOccupancyFee"
) as HTMLElement
).dataset.feeId;
const doDelete = () => {
cityssm.postJSON(
los.urlPrefix + "/lotOccupancies/doDeleteLotOccupancyFee",
{
lotOccupancyId,
feeId
},
(responseJSON: {
success: boolean;
errorMessage?: string;
lotOccupancyFees?: recordTypes.LotOccupancyFee[];
}) => {
if (responseJSON.success) {
lotOccupancyFees = responseJSON.lotOccupancyFees!;
renderLotOccupancyFees();
} else {
bulmaJS.alert({
title: "Error Deleting Fee",
message: responseJSON.errorMessage || "",
contextualColorName: "danger"
});
}
}
);
};
bulmaJS.confirm({
title: "Delete Fee",
message: "Are you sure you want to delete this fee?",
contextualColorName: "warning",
okButton: {
text: "Yes, Delete Fee",
callbackFunction: doDelete
}
});
};
const renderLotOccupancyFees = () => {
if (lotOccupancyFees.length === 0) {
lotOccupancyFeesContainerElement.innerHTML =
'
' +
'
There are no fees associated with this record.
' +
"
";
renderLotOccupancyTransactions();
return;
}
lotOccupancyFeesContainerElement.innerHTML =
'' +
("" +
"| Fee | " +
'Unit Cost | ' +
'× | ' +
'Quantity | ' +
'equals | ' +
'Total | ' +
'Options | ' +
"
") +
"" +
("" +
'| Subtotal | | |
' +
'| Tax | | |
' +
'| Grand Total | | |
' +
"") +
"
";
let feeAmountTotal = 0;
let taxAmountTotal = 0;
for (const lotOccupancyFee of lotOccupancyFees) {
const tableRowElement = document.createElement("tr");
tableRowElement.className = "container--lotOccupancyFee";
tableRowElement.dataset.feeId = lotOccupancyFee.feeId!.toString();
tableRowElement.dataset.includeQuantity = lotOccupancyFee.includeQuantity ? "1" : "0";
tableRowElement.innerHTML =
'' +
cityssm.escapeHTML(lotOccupancyFee.feeName || "") +
" | " +
(lotOccupancyFee.quantity === 1
? ""
: '$' +
lotOccupancyFee.feeAmount!.toFixed(2) +
" | " +
"× | " +
'' +
lotOccupancyFee.quantity +
" | " +
"= | ") +
'$' +
(lotOccupancyFee.feeAmount! * lotOccupancyFee.quantity!).toFixed(2) +
" | " +
('' +
'" +
" | ");
tableRowElement.querySelector("button")!.addEventListener("click", deleteLotOccupancyFee);
lotOccupancyFeesContainerElement.querySelector("tbody")!.append(tableRowElement);
feeAmountTotal += lotOccupancyFee.feeAmount! * lotOccupancyFee.quantity!;
taxAmountTotal += lotOccupancyFee.taxAmount! * lotOccupancyFee.quantity!;
}
(
lotOccupancyFeesContainerElement.querySelector(
"#lotOccupancyFees--feeAmountTotal"
) as HTMLElement
).textContent = "$" + feeAmountTotal.toFixed(2);
(
lotOccupancyFeesContainerElement.querySelector(
"#lotOccupancyFees--taxAmountTotal"
) as HTMLElement
).textContent = "$" + taxAmountTotal.toFixed(2);
(
lotOccupancyFeesContainerElement.querySelector(
"#lotOccupancyFees--grandTotal"
) as HTMLElement
).textContent = "$" + (feeAmountTotal + taxAmountTotal).toFixed(2);
renderLotOccupancyTransactions();
};
(document.querySelector("#button--addFee") as HTMLButtonElement).addEventListener("click", () => {
if (hasUnsavedChanges) {
bulmaJS.alert({
message: "Please save all unsaved changes before adding fees.",
contextualColorName: "warning"
});
return;
}
let feeCategories: recordTypes.FeeCategory[];
let feeFilterElement: HTMLInputElement;
let feeFilterResultsElement: HTMLElement;
const doAddFee = (feeId: number, quantity: number | string = 1) => {
cityssm.postJSON(
los.urlPrefix + "/lotOccupancies/doAddLotOccupancyFee",
{
lotOccupancyId,
feeId,
quantity
},
(responseJSON: {
success: boolean;
errorMessage?: string;
lotOccupancyFees?: recordTypes.LotOccupancyFee[];
}) => {
if (responseJSON.success) {
lotOccupancyFees = responseJSON.lotOccupancyFees!;
renderLotOccupancyFees();
filterFees();
} else {
bulmaJS.alert({
title: "Error Adding Fee",
message: responseJSON.errorMessage || "",
contextualColorName: "danger"
});
}
}
);
};
const doSetQuantityAndAddFee = (fee: recordTypes.Fee) => {
let quantityElement: HTMLInputElement;
let quantityCloseModalFunction: () => void;
const doSetQuantity = (submitEvent: SubmitEvent) => {
submitEvent.preventDefault();
doAddFee(fee.feeId!, quantityElement.value);
quantityCloseModalFunction();
};
cityssm.openHtmlModal("lotOccupancy-setFeeQuantity", {
onshow: (modalElement) => {
(
modalElement.querySelector(
"#lotOccupancyFeeQuantity--quantityUnit"
) as HTMLElement
).textContent = fee.quantityUnit!;
},
onshown: (modalElement, closeModalFunction) => {
quantityCloseModalFunction = closeModalFunction;
quantityElement = modalElement.querySelector(
"#lotOccupancyFeeQuantity--quantity"
) as HTMLInputElement;
modalElement.querySelector("form")!.addEventListener("submit", doSetQuantity);
}
});
};
const tryAddFee = (clickEvent: Event) => {
clickEvent.preventDefault();
const feeId = Number.parseInt((clickEvent.currentTarget as HTMLElement).dataset.feeId!, 10);
const feeCategoryId = Number.parseInt(
(
(clickEvent.currentTarget as HTMLElement).closest(
".container--feeCategory"
) as HTMLElement
).dataset.feeCategoryId!,
10
);
const feeCategory = feeCategories.find((currentFeeCategory) => {
return currentFeeCategory.feeCategoryId === feeCategoryId;
})!;
const fee = feeCategory.fees!.find((currentFee) => {
return currentFee.feeId === feeId;
})!;
if (fee.includeQuantity) {
doSetQuantityAndAddFee(fee);
} else {
doAddFee(feeId);
}
};
const filterFees = () => {
const filterStringPieces = feeFilterElement.value.trim().toLowerCase().split(" ");
feeFilterResultsElement.innerHTML = "";
for (const feeCategory of feeCategories) {
const categoryContainerElement = document.createElement("div");
categoryContainerElement.className = "container--feeCategory";
categoryContainerElement.dataset.feeCategoryId = feeCategory.feeCategoryId!.toString();
categoryContainerElement.innerHTML =
'' +
cityssm.escapeHTML(feeCategory.feeCategory || "") +
"
" +
'';
let hasFees = false;
for (const fee of feeCategory.fees!) {
if (
lotOccupancyFeesContainerElement.querySelector(
".container--lotOccupancyFee[data-fee-id='" +
fee.feeId +
"'][data-include-quantity='0']"
)
) {
continue;
}
let includeFee = true;
for (const filterStringPiece of filterStringPieces) {
if (!fee.feeName!.toLowerCase().includes(filterStringPiece)) {
includeFee = false;
break;
}
}
if (!includeFee) {
continue;
}
hasFees = true;
const panelBlockElement = document.createElement("a");
panelBlockElement.className = "panel-block is-block container--fee";
panelBlockElement.dataset.feeId = fee.feeId!.toString();
panelBlockElement.href = "#";
panelBlockElement.innerHTML =
"" +
cityssm.escapeHTML(fee.feeName || "") +
"
" +
"" +
cityssm.escapeHTML(fee.feeDescription || "").replace(/\n/g, "
") +
"";
panelBlockElement.addEventListener("click", tryAddFee);
(categoryContainerElement.querySelector(".panel") as HTMLElement).append(
panelBlockElement
);
}
if (hasFees) {
feeFilterResultsElement.append(categoryContainerElement);
}
}
};
cityssm.openHtmlModal("lotOccupancy-addFee", {
onshow: (modalElement) => {
feeFilterElement = modalElement.querySelector(
"#feeSelect--feeName"
) as HTMLInputElement;
feeFilterResultsElement = modalElement.querySelector(
"#resultsContainer--feeSelect"
) as HTMLElement;
cityssm.postJSON(
los.urlPrefix + "/lotOccupancies/doGetFees",
{
lotOccupancyId
},
(responseJSON: { feeCategories: recordTypes.FeeCategory[] }) => {
feeCategories = responseJSON.feeCategories;
feeFilterElement.disabled = false;
feeFilterElement.addEventListener("keyup", filterFees);
feeFilterElement.focus();
filterFees();
}
);
},
onshown: () => {
bulmaJS.toggleHtmlClipped();
},
onhidden: () => {
renderLotOccupancyFees();
},
onremoved: () => {
bulmaJS.toggleHtmlClipped();
}
});
});
let lotOccupancyTransactions: recordTypes.LotOccupancyTransaction[] =
exports.lotOccupancyTransactions;
delete exports.lotOccupancyTransactions;
const lotOccupancyTransactionsContainerElement = document.querySelector(
"#container--lotOccupancyTransactions"
) as HTMLElement;
const getTransactionGrandTotal = (): number => {
let transactionGrandTotal = 0;
for (const lotOccupancyTransaction of lotOccupancyTransactions) {
transactionGrandTotal += lotOccupancyTransaction.transactionAmount;
}
return transactionGrandTotal;
};
const deleteLotOccupancyTransaction = (clickEvent: Event) => {
const transactionIndex = (
(clickEvent.currentTarget as HTMLElement).closest(
".container--lotOccupancyTransaction"
) as HTMLElement
).dataset.transactionIndex;
const doDelete = () => {
cityssm.postJSON(
los.urlPrefix + "/lotOccupancies/doDeleteLotOccupancyTransaction",
{
lotOccupancyId,
transactionIndex
},
(responseJSON: {
success: boolean;
errorMessage?: string;
lotOccupancyTransactions?: recordTypes.LotOccupancyTransaction[];
}) => {
if (responseJSON.success) {
lotOccupancyTransactions = responseJSON.lotOccupancyTransactions!;
renderLotOccupancyTransactions();
} else {
bulmaJS.alert({
title: "Error Deleting Transaction",
message: responseJSON.errorMessage || "",
contextualColorName: "danger"
});
}
}
);
};
bulmaJS.confirm({
title: "Delete Trasnaction",
message: "Are you sure you want to delete this transaction?",
contextualColorName: "warning",
okButton: {
text: "Yes, Delete Transaction",
callbackFunction: doDelete
}
});
};
const renderLotOccupancyTransactions = () => {
if (lotOccupancyTransactions.length === 0) {
lotOccupancyTransactionsContainerElement.innerHTML =
'' +
'
There are no transactions associated with this record.
' +
"
";
return;
}
lotOccupancyTransactionsContainerElement.innerHTML =
'' +
"" +
'| Date | ' +
"" +
cityssm.escapeHTML(exports.aliases.externalReceiptNumber) +
" | " +
'Amount | ' +
'Options | ' +
"
" +
"" +
("" +
'| Transaction Total | ' +
' | ' +
' | ' +
"
") +
"
";
let transactionGrandTotal = 0;
for (const lotOccupancyTransaction of lotOccupancyTransactions) {
transactionGrandTotal += lotOccupancyTransaction.transactionAmount;
const tableRowElement = document.createElement("tr");
tableRowElement.className = "container--lotOccupancyTransaction";
tableRowElement.dataset.transactionIndex =
lotOccupancyTransaction.transactionIndex!.toString();
tableRowElement.innerHTML =
"" +
lotOccupancyTransaction.transactionDateString +
" | " +
("" +
cityssm.escapeHTML(lotOccupancyTransaction.externalReceiptNumber || "") +
" " +
"" +
cityssm.escapeHTML(lotOccupancyTransaction.transactionNote || "") +
"" +
" | ") +
('$' +
lotOccupancyTransaction.transactionAmount.toFixed(2) +
" | ") +
('' +
'" +
" | ");
tableRowElement
.querySelector("button")!
.addEventListener("click", deleteLotOccupancyTransaction);
lotOccupancyTransactionsContainerElement.querySelector("tbody")!.append(tableRowElement);
}
(
lotOccupancyTransactionsContainerElement.querySelector(
"#lotOccupancyTransactions--grandTotal"
) as HTMLElement
).textContent = "$" + transactionGrandTotal.toFixed(2);
const feeGrandTotal = getFeeGrandTotal();
if (feeGrandTotal > transactionGrandTotal) {
lotOccupancyTransactionsContainerElement.insertAdjacentHTML(
"afterbegin",
'' +
'
' +
'
' +
'
' +
'
$' +
(feeGrandTotal - transactionGrandTotal).toFixed(2) +
"
" +
"
" +
"
" +
"
"
);
}
};
(document.querySelector("#button--addTransaction") as HTMLButtonElement).addEventListener(
"click",
() => {
let addCloseModalFunction: () => void;
const doAddTransaction = (submitEvent: SubmitEvent) => {
submitEvent.preventDefault();
cityssm.postJSON(
los.urlPrefix + "/lotOccupancies/doAddLotOccupancyTransaction",
submitEvent.currentTarget,
(responseJSON: {
success: boolean;
errorMessage?: string;
lotOccupancyTransactions?: recordTypes.LotOccupancyTransaction[];
}) => {
if (responseJSON.success) {
lotOccupancyTransactions = responseJSON.lotOccupancyTransactions!;
addCloseModalFunction();
renderLotOccupancyTransactions();
} else {
bulmaJS.confirm({
title: "Error Adding Transaction",
message: responseJSON.errorMessage || "",
contextualColorName: "danger"
});
}
}
);
};
cityssm.openHtmlModal("lotOccupancy-addTransaction", {
onshow: (modalElement) => {
los.populateAliases(modalElement);
(
modalElement.querySelector(
"#lotOccupancyTransactionAdd--lotOccupancyId"
) as HTMLInputElement
).value = lotOccupancyId.toString();
const feeGrandTotal = getFeeGrandTotal();
const transactionGrandTotal = getTransactionGrandTotal();
const transactionAmountElement = modalElement.querySelector(
"#lotOccupancyTransactionAdd--transactionAmount"
) as HTMLInputElement;
transactionAmountElement.min = (-1 * transactionGrandTotal).toFixed(2);
transactionAmountElement.max = Math.max(
feeGrandTotal - transactionGrandTotal,
0
).toFixed(2);
transactionAmountElement.value = Math.max(
feeGrandTotal - transactionGrandTotal,
0
).toFixed(2);
},
onshown: (modalElement, closeModalFunction) => {
bulmaJS.toggleHtmlClipped();
addCloseModalFunction = closeModalFunction;
modalElement.querySelector("form")!.addEventListener("submit", doAddTransaction);
},
onremoved: () => {
bulmaJS.toggleHtmlClipped();
}
});
}
);
renderLotOccupancyFees();