diff --git a/handlers/lotOccupancies-get/new.d.ts b/handlers/lotOccupancies-get/new.d.ts new file mode 100644 index 00000000..9621c611 --- /dev/null +++ b/handlers/lotOccupancies-get/new.d.ts @@ -0,0 +1,3 @@ +import type { RequestHandler } from "express"; +export declare const handler: RequestHandler; +export default handler; diff --git a/handlers/lotOccupancies-get/new.js b/handlers/lotOccupancies-get/new.js new file mode 100644 index 00000000..8249fcff --- /dev/null +++ b/handlers/lotOccupancies-get/new.js @@ -0,0 +1,13 @@ +import { getOccupancyTypes } from "../../helpers/functions.cache.js"; +import * as configFunctions from "../../helpers/functions.config.js"; +export const handler = (request, response) => { + const lotOccupancy = {}; + const occupancyTypes = getOccupancyTypes(); + return response.render("lotOccupancy-edit", { + headTitle: "Create a New " + configFunctions.getProperty("aliases.lot") + " " + configFunctions.getProperty("aliases.occupancy") + " Record", + lotOccupancy, + occupancyTypes, + isCreate: true + }); +}; +export default handler; diff --git a/handlers/lotOccupancies-get/new.ts b/handlers/lotOccupancies-get/new.ts new file mode 100644 index 00000000..2554ae1a --- /dev/null +++ b/handlers/lotOccupancies-get/new.ts @@ -0,0 +1,33 @@ +import type { + RequestHandler +} from "express"; + +import { + getLotOccupantTypes, + getOccupancyTypes +} from "../../helpers/functions.cache.js"; + +import * as configFunctions from "../../helpers/functions.config.js"; + +import type * as recordTypes from "../../types/recordTypes"; + + +export const handler: RequestHandler = (request, response) => { + + const lotOccupancy: recordTypes.LotOccupancy = { + + }; + + const occupancyTypes = getOccupancyTypes(); + + return response.render("lotOccupancy-edit", { + headTitle: "Create a New " + configFunctions.getProperty("aliases.lot") + " " + configFunctions.getProperty("aliases.occupancy") + " Record", + lotOccupancy, + + occupancyTypes, + isCreate: true + }); +}; + + +export default handler; \ No newline at end of file diff --git a/handlers/lotOccupancies-post/doCreateLotOccupancy.d.ts b/handlers/lotOccupancies-post/doCreateLotOccupancy.d.ts new file mode 100644 index 00000000..9621c611 --- /dev/null +++ b/handlers/lotOccupancies-post/doCreateLotOccupancy.d.ts @@ -0,0 +1,3 @@ +import type { RequestHandler } from "express"; +export declare const handler: RequestHandler; +export default handler; diff --git a/handlers/lotOccupancies-post/doCreateLotOccupancy.js b/handlers/lotOccupancies-post/doCreateLotOccupancy.js new file mode 100644 index 00000000..51d25141 --- /dev/null +++ b/handlers/lotOccupancies-post/doCreateLotOccupancy.js @@ -0,0 +1,9 @@ +import { addLotOccupancy } from "../../helpers/lotOccupancyDB/addLotOccupancy.js"; +export const handler = async (request, response) => { + const lotOccupancyId = addLotOccupancy(request.body, request.session); + response.json({ + success: true, + lotOccupancyId + }); +}; +export default handler; diff --git a/handlers/lotOccupancies-post/doCreateLotOccupancy.ts b/handlers/lotOccupancies-post/doCreateLotOccupancy.ts new file mode 100644 index 00000000..33ec0ac3 --- /dev/null +++ b/handlers/lotOccupancies-post/doCreateLotOccupancy.ts @@ -0,0 +1,21 @@ +import type { + RequestHandler +} from "express"; + +import { + addLotOccupancy +} from "../../helpers/lotOccupancyDB/addLotOccupancy.js"; + + +export const handler: RequestHandler = async (request, response) => { + + const lotOccupancyId = addLotOccupancy(request.body, request.session); + + response.json({ + success: true, + lotOccupancyId + }); +}; + + +export default handler; \ No newline at end of file diff --git a/handlers/lotOccupancies-post/doGetOccupancyTypeFields.d.ts b/handlers/lotOccupancies-post/doGetOccupancyTypeFields.d.ts new file mode 100644 index 00000000..9621c611 --- /dev/null +++ b/handlers/lotOccupancies-post/doGetOccupancyTypeFields.d.ts @@ -0,0 +1,3 @@ +import type { RequestHandler } from "express"; +export declare const handler: RequestHandler; +export default handler; diff --git a/handlers/lotOccupancies-post/doGetOccupancyTypeFields.js b/handlers/lotOccupancies-post/doGetOccupancyTypeFields.js new file mode 100644 index 00000000..a42925e4 --- /dev/null +++ b/handlers/lotOccupancies-post/doGetOccupancyTypeFields.js @@ -0,0 +1,8 @@ +import { getOccupancyTypeById } from "../../helpers/functions.cache.js"; +export const handler = async (request, response) => { + const result = getOccupancyTypeById(Number.parseInt(request.body.occupancyTypeId, 10)); + response.json({ + occupancyTypeFields: result.occupancyTypeFields + }); +}; +export default handler; diff --git a/handlers/lotOccupancies-post/doGetOccupancyTypeFields.ts b/handlers/lotOccupancies-post/doGetOccupancyTypeFields.ts new file mode 100644 index 00000000..fc20dc12 --- /dev/null +++ b/handlers/lotOccupancies-post/doGetOccupancyTypeFields.ts @@ -0,0 +1,18 @@ +import type { + RequestHandler +} from "express"; + +import { getOccupancyTypeById } from "../../helpers/functions.cache.js"; + + +export const handler: RequestHandler = async (request, response) => { + + const result = getOccupancyTypeById(Number.parseInt(request.body.occupancyTypeId, 10)); + + response.json({ + occupancyTypeFields: result.occupancyTypeFields + }); +}; + + +export default handler; \ No newline at end of file diff --git a/helpers/lotOccupancyDB/addLotOccupancy.d.ts b/helpers/lotOccupancyDB/addLotOccupancy.d.ts index 8a5625ca..0ad517ce 100644 --- a/helpers/lotOccupancyDB/addLotOccupancy.d.ts +++ b/helpers/lotOccupancyDB/addLotOccupancy.d.ts @@ -4,6 +4,8 @@ interface AddLotOccupancyForm { lotId: string | number; occupancyStartDateString: string; occupancyEndDateString: string; + occupancyTypeFieldIds: string; + [lotOccupancyFieldValue_occupancyTypeFieldId: string]: unknown; } export declare const addLotOccupancy: (lotOccupancyForm: AddLotOccupancyForm, requestSession: recordTypes.PartialSession) => number; export default addLotOccupancy; diff --git a/helpers/lotOccupancyDB/addLotOccupancy.js b/helpers/lotOccupancyDB/addLotOccupancy.js index 7e2d2f5b..70400084 100644 --- a/helpers/lotOccupancyDB/addLotOccupancy.js +++ b/helpers/lotOccupancyDB/addLotOccupancy.js @@ -1,6 +1,7 @@ import sqlite from "better-sqlite3"; import { lotOccupancyDB as databasePath } from "../../data/databasePaths.js"; import * as dateTimeFunctions from "@cityssm/expressjs-server-js/dateTimeFns.js"; +import { addOrUpdateLotOccupancyField } from "./addOrUpdateLotOccupancyField.js"; export const addLotOccupancy = (lotOccupancyForm, requestSession) => { const database = sqlite(databasePath); const rightNowMillis = Date.now(); @@ -20,7 +21,19 @@ export const addLotOccupancy = (lotOccupancyForm, requestSession) => { lotOccupancyForm.lotId), occupancyStartDate, (lotOccupancyForm.occupancyEndDateString === "" ? undefined : dateTimeFunctions.dateStringToInteger(lotOccupancyForm.occupancyEndDateString)), requestSession.user.userName, rightNowMillis, requestSession.user.userName, rightNowMillis); + const lotOccupancyId = result.lastInsertRowid; + const occupancyTypeFieldIds = lotOccupancyForm.occupancyTypeFieldIds.split(","); + for (const occupancyTypeFieldId of occupancyTypeFieldIds) { + const lotOccupancyFieldValue = lotOccupancyForm["lotOccupancyFieldValue_" + occupancyTypeFieldId]; + if (lotOccupancyFieldValue && lotOccupancyFieldValue !== "") { + addOrUpdateLotOccupancyField({ + lotOccupancyId, + occupancyTypeFieldId, + lotOccupancyFieldValue + }, requestSession, database); + } + } database.close(); - return result.lastInsertRowid; + return lotOccupancyId; }; export default addLotOccupancy; diff --git a/helpers/lotOccupancyDB/addLotOccupancy.ts b/helpers/lotOccupancyDB/addLotOccupancy.ts index 2ad72f64..cee7078b 100644 --- a/helpers/lotOccupancyDB/addLotOccupancy.ts +++ b/helpers/lotOccupancyDB/addLotOccupancy.ts @@ -1,59 +1,85 @@ import sqlite from "better-sqlite3"; + import { - lotOccupancyDB as databasePath + lotOccupancyDB as databasePath } from "../../data/databasePaths.js"; import * as dateTimeFunctions from "@cityssm/expressjs-server-js/dateTimeFns.js"; +import { + addOrUpdateLotOccupancyField +} from "./addOrUpdateLotOccupancyField.js"; + import type * as recordTypes from "../../types/recordTypes"; interface AddLotOccupancyForm { - occupancyTypeId: string | number; - lotId: string | number; + occupancyTypeId: string | number; + lotId: string | number; - occupancyStartDateString: string; - occupancyEndDateString: string; + occupancyStartDateString: string; + occupancyEndDateString: string; + + occupancyTypeFieldIds: string; + [lotOccupancyFieldValue_occupancyTypeFieldId: string]: unknown; } export const addLotOccupancy = - (lotOccupancyForm: AddLotOccupancyForm, requestSession: recordTypes.PartialSession): number => { + (lotOccupancyForm: AddLotOccupancyForm, requestSession: recordTypes.PartialSession): number => { - const database = sqlite(databasePath); + const database = sqlite(databasePath); - const rightNowMillis = Date.now(); + const rightNowMillis = Date.now(); - const occupancyStartDate = dateTimeFunctions.dateStringToInteger(lotOccupancyForm.occupancyStartDateString); + const occupancyStartDate = dateTimeFunctions.dateStringToInteger(lotOccupancyForm.occupancyStartDateString); - if (occupancyStartDate <= 0) { - console.error(lotOccupancyForm); - } + if (occupancyStartDate <= 0) { + console.error(lotOccupancyForm); + } - const result = database - .prepare("insert into LotOccupancies (" + - "occupancyTypeId, lotId," + - " occupancyStartDate, occupancyEndDate," + - " recordCreate_userName, recordCreate_timeMillis," + - " recordUpdate_userName, recordUpdate_timeMillis)" + - " values (?, ?, ?, ?, ?, ?, ?, ?)") - .run(lotOccupancyForm.occupancyTypeId, - (lotOccupancyForm.lotId === "" ? - undefined : - lotOccupancyForm.lotId), - occupancyStartDate, - (lotOccupancyForm.occupancyEndDateString === "" ? - undefined : - dateTimeFunctions.dateStringToInteger(lotOccupancyForm.occupancyEndDateString)), - requestSession.user.userName, - rightNowMillis, - requestSession.user.userName, - rightNowMillis); + const result = database + .prepare("insert into LotOccupancies (" + + "occupancyTypeId, lotId," + + " occupancyStartDate, occupancyEndDate," + + " recordCreate_userName, recordCreate_timeMillis," + + " recordUpdate_userName, recordUpdate_timeMillis)" + + " values (?, ?, ?, ?, ?, ?, ?, ?)") + .run(lotOccupancyForm.occupancyTypeId, + (lotOccupancyForm.lotId === "" ? + undefined : + lotOccupancyForm.lotId), + occupancyStartDate, + (lotOccupancyForm.occupancyEndDateString === "" ? + undefined : + dateTimeFunctions.dateStringToInteger(lotOccupancyForm.occupancyEndDateString)), + requestSession.user.userName, + rightNowMillis, + requestSession.user.userName, + rightNowMillis); - database.close(); + const lotOccupancyId = result.lastInsertRowid as number; - return result.lastInsertRowid as number; - }; + const occupancyTypeFieldIds = lotOccupancyForm.occupancyTypeFieldIds.split(","); + + for (const occupancyTypeFieldId of occupancyTypeFieldIds) { + + const lotOccupancyFieldValue = lotOccupancyForm["lotOccupancyFieldValue_" + occupancyTypeFieldId] as string; + + if (lotOccupancyFieldValue && lotOccupancyFieldValue !== "") { + addOrUpdateLotOccupancyField({ + lotOccupancyId, + occupancyTypeFieldId, + lotOccupancyFieldValue + }, requestSession, database); + } + } + + + database.close(); + + return lotOccupancyId; + }; export default addLotOccupancy; \ No newline at end of file diff --git a/helpers/lotOccupancyDB/updateLotOccupancy.ts b/helpers/lotOccupancyDB/updateLotOccupancy.ts index dffacdb3..e41a4876 100644 --- a/helpers/lotOccupancyDB/updateLotOccupancy.ts +++ b/helpers/lotOccupancyDB/updateLotOccupancy.ts @@ -11,6 +11,7 @@ import { import { addOrUpdateLotOccupancyField } from "./addOrUpdateLotOccupancyField.js"; + import { deleteLotOccupancyField } from "./deleteLotOccupancyField.js"; diff --git a/public-typescript/lotOccupancyEdit.js b/public-typescript/lotOccupancyEdit.js index 6c815de5..59fb5df6 100644 --- a/public-typescript/lotOccupancyEdit.js +++ b/public-typescript/lotOccupancyEdit.js @@ -46,8 +46,53 @@ Object.defineProperty(exports, "__esModule", { value: true }); for (const formInputElement of formInputElements) { formInputElement.addEventListener("change", setUnsavedChanges); } - if (!isCreate) { - const occupancyTypeIdElement = document.querySelector("#lotOccupancy--occupancyTypeId"); + const occupancyTypeIdElement = document.querySelector("#lotOccupancy--occupancyTypeId"); + if (isCreate) { + const lotOccupancyFieldsContainerElement = document.querySelector("#container--lotOccupancyFields"); + occupancyTypeIdElement.addEventListener("change", () => { + if (occupancyTypeIdElement.value === "") { + lotOccupancyFieldsContainerElement.innerHTML = "
" + + "

Select the " + exports.aliases.occupancy.toLowerCase() + " type to load the available fields.

" + + "
"; + return; + } + cityssm.postJSON(urlPrefix + "/lotOccupancies/doGetOccupancyTypeFields", { + occupancyTypeId: occupancyTypeIdElement.value + }, (responseJSON) => { + if (responseJSON.occupancyTypeFields.length === 0) { + lotOccupancyFieldsContainerElement.innerHTML = "
" + + "

There are no additional fields for this " + exports.aliases.occupancy.toLowerCase() + " type.

" + + "
"; + return; + } + lotOccupancyFieldsContainerElement.innerHTML = ""; + let occupancyTypeFieldIds = ""; + for (const occupancyTypeField of responseJSON.occupancyTypeFields) { + occupancyTypeFieldIds += "," + occupancyTypeField.occupancyTypeFieldId; + const fieldElement = document.createElement("div"); + fieldElement.className = "field"; + fieldElement.innerHTML = "" + + "
"; + fieldElement.querySelector("label").textContent = occupancyTypeField.occupancyTypeField; + const inputElement = document.createElement("input"); + inputElement.className = "input"; + inputElement.id = "lotOccupancy--lotOccupancyFieldValue_" + occupancyTypeField.occupancyTypeFieldId; + inputElement.name = "lotOccupancyFieldValue_" + occupancyTypeField.occupancyTypeFieldId; + inputElement.type = "text"; + inputElement.required = occupancyTypeField.isRequired; + inputElement.minLength = occupancyTypeField.minimumLength; + inputElement.maxLength = occupancyTypeField.maximumLength; + if (occupancyTypeField.pattern && occupancyTypeField.pattern !== "") { + inputElement.pattern = occupancyTypeField.pattern; + } + fieldElement.querySelector(".control").append(inputElement); + lotOccupancyFieldsContainerElement.append(fieldElement); + } + lotOccupancyFieldsContainerElement.insertAdjacentHTML("beforeend", ""); + }); + }); + } + else { const originalOccupancyTypeId = occupancyTypeIdElement.value; occupancyTypeIdElement.addEventListener("change", () => { if (occupancyTypeIdElement.value !== originalOccupancyTypeId) { diff --git a/public-typescript/lotOccupancyEdit.ts b/public-typescript/lotOccupancyEdit.ts index cf438f00..ac14237b 100644 --- a/public-typescript/lotOccupancyEdit.ts +++ b/public-typescript/lotOccupancyEdit.ts @@ -8,7 +8,8 @@ import type { } from "@cityssm/bulma-webapp-js/src/types"; import type { - BulmaJS, StringConfigProperties + BulmaJS, + StringConfigProperties } from "@cityssm/bulma-js/types"; declare const cityssm: cityssmGlobal; @@ -86,9 +87,77 @@ declare const bulmaJS: BulmaJS; // Occupancy Type - if (!isCreate) { + const occupancyTypeIdElement = document.querySelector("#lotOccupancy--occupancyTypeId") as HTMLSelectElement; - const occupancyTypeIdElement = document.querySelector("#lotOccupancy--occupancyTypeId") as HTMLSelectElement; + if (isCreate) { + + const lotOccupancyFieldsContainerElement = document.querySelector("#container--lotOccupancyFields") as HTMLElement; + + occupancyTypeIdElement.addEventListener("change", () => { + + if (occupancyTypeIdElement.value === "") { + lotOccupancyFieldsContainerElement.innerHTML = "
" + + "

Select the " + exports.aliases.occupancy.toLowerCase() + " type to load the available fields.

" + + "
"; + + return + } + + cityssm.postJSON(urlPrefix + "/lotOccupancies/doGetOccupancyTypeFields", { + occupancyTypeId: occupancyTypeIdElement.value + }, + (responseJSON: { + occupancyTypeFields: recordTypes.OccupancyTypeField[] + }) => { + + if (responseJSON.occupancyTypeFields.length === 0) { + lotOccupancyFieldsContainerElement.innerHTML = "
" + + "

There are no additional fields for this " + exports.aliases.occupancy.toLowerCase() + " type.

" + + "
"; + + return + } + + lotOccupancyFieldsContainerElement.innerHTML = ""; + + let occupancyTypeFieldIds = ""; + + for (const occupancyTypeField of responseJSON.occupancyTypeFields) { + + occupancyTypeFieldIds += "," + occupancyTypeField.occupancyTypeFieldId; + + const fieldElement = document.createElement("div"); + fieldElement.className = "field"; + fieldElement.innerHTML = "" + + "
"; + + fieldElement.querySelector("label").textContent = occupancyTypeField.occupancyTypeField; + + const inputElement = document.createElement("input"); + inputElement.className = "input"; + inputElement.id = "lotOccupancy--lotOccupancyFieldValue_" + occupancyTypeField.occupancyTypeFieldId; + inputElement.name = "lotOccupancyFieldValue_" + occupancyTypeField.occupancyTypeFieldId; + inputElement.type = "text"; + + inputElement.required = occupancyTypeField.isRequired; + inputElement.minLength = occupancyTypeField.minimumLength; + inputElement.maxLength = occupancyTypeField.maximumLength; + + if (occupancyTypeField.pattern && occupancyTypeField.pattern !== "") { + inputElement.pattern = occupancyTypeField.pattern; + } + + fieldElement.querySelector(".control").append(inputElement); + + lotOccupancyFieldsContainerElement.append(fieldElement); + } + + lotOccupancyFieldsContainerElement.insertAdjacentHTML("beforeend", + ""); + }); + }); + + } else { const originalOccupancyTypeId = occupancyTypeIdElement.value; @@ -264,8 +333,10 @@ declare const bulmaJS: BulmaJS; submitEvent.preventDefault(); cityssm.postJSON(urlPrefix + "/lotOccupancies/doUpdateLotOccupancyOccupant", - editFormElement, - (responseJSON: { success: boolean; errorMessage?: string; lotOccupancyOccupants?: recordTypes.LotOccupancyOccupant[]; }) => { + editFormElement, + (responseJSON: { + success: boolean;errorMessage ? : string;lotOccupancyOccupants ? : recordTypes.LotOccupancyOccupant[]; + }) => { if (responseJSON.success) { lotOccupancyOccupants = responseJSON.lotOccupancyOccupants; @@ -344,21 +415,23 @@ declare const bulmaJS: BulmaJS; const doDelete = () => { cityssm.postJSON(urlPrefix + "/lotOccupancies/doDeleteLotOccupancyOccupant", { - lotOccupancyId, - lotOccupantIndex - }, - (responseJSON: { success: boolean; errorMessage?: string; lotOccupancyOccupants: recordTypes.LotOccupancyOccupant[];}) => { - if (responseJSON.success) { - lotOccupancyOccupants = responseJSON.lotOccupancyOccupants; - renderLotOccupancyOccupants(); - } else { - bulmaJS.alert({ - title: "Error Removing " + exports.aliases.occupant, - message: responseJSON.errorMessage, - contextualColorName: "danger" - }); - } - }); + lotOccupancyId, + lotOccupantIndex + }, + (responseJSON: { + success: boolean;errorMessage ? : string;lotOccupancyOccupants: recordTypes.LotOccupancyOccupant[]; + }) => { + if (responseJSON.success) { + lotOccupancyOccupants = responseJSON.lotOccupancyOccupants; + renderLotOccupancyOccupants(); + } else { + bulmaJS.alert({ + title: "Error Removing " + exports.aliases.occupant, + message: responseJSON.errorMessage, + contextualColorName: "danger" + }); + } + }); }; bulmaJS.confirm({ @@ -444,7 +517,9 @@ declare const bulmaJS: BulmaJS; cityssm.postJSON(urlPrefix + "/lotOccupancies/doAddLotOccupancyOccupant", addFormElement, - (responseJSON: { success: boolean; errorMessage?: string; lotOccupancyOccupants?: recordTypes.LotOccupancyOccupant[]; }) => { + (responseJSON: { + success: boolean;errorMessage ? : string;lotOccupancyOccupants ? : recordTypes.LotOccupancyOccupant[]; + }) => { if (responseJSON.success) { lotOccupancyOccupants = responseJSON.lotOccupancyOccupants; diff --git a/public/javascripts/lotOccupancyEdit.min.js b/public/javascripts/lotOccupancyEdit.min.js index 11ef1f09..eaa45e35 100644 --- a/public/javascripts/lotOccupancyEdit.min.js +++ b/public/javascripts/lotOccupancyEdit.min.js @@ -1 +1 @@ -"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),(()=>{const e=exports.los,t=document.querySelector("main").dataset.urlPrefix,c=document.querySelector("#lotOccupancy--lotOccupancyId").value,a=""===c;let o=!1,n=a;const s=()=>{o||(o=!0,cityssm.enableNavBlocker())},l=document.querySelector("#form--lotOccupancy");l.addEventListener("submit",e=>{e.preventDefault(),cityssm.postJSON(t+"/lotOccupancies/"+(a?"doCreateLotOccupancy":"doUpdateLotOccupancy"),l,e=>{e.success?(o=!1,cityssm.disableNavBlocker(),a||n?window.location.href=t+"/lotOccupancies/"+e.lotOccupancyId+"/edit?t="+Date.now():bulmaJS.alert({message:exports.aliases.occupancy+" Updated Successfully",contextualColorName:"success"})):bulmaJS.alert({title:"Error Saving "+exports.aliases.occupancy,message:e.errorMessage,contextualColorName:"danger"})})});const u=l.querySelectorAll("input, select");for(const e of u)e.addEventListener("change",s);if(!a){const e=document.querySelector("#lotOccupancy--occupancyTypeId"),t=e.value;e.addEventListener("change",()=>{e.value!==t&&bulmaJS.confirm({title:"Confirm Change",message:"Are you sure you want to change the "+exports.aliases.occupancy.toLowerCase()+" type?\nThis change affects the additional fields associated with this record, and may also affect the available fees.",contextualColorName:"warning",okButton:{text:"Yes, Keep the Change",callbackFunction:()=>{n=!0}},cancelButton:{text:"Revert the Change",callbackFunction:()=>{e.value=t}}})})}if(document.querySelector("#lotOccupancy--lotName").addEventListener("click",c=>{const a=c.currentTarget.value;let o,n,l;const u=e=>{e.preventDefault();const t=e.currentTarget;document.querySelector("#lotOccupancy--lotId").value=t.dataset.lotId,document.querySelector("#lotOccupancy--lotName").value=t.dataset.lotName,s(),o()},r=()=>{l.innerHTML='


Searching...

',cityssm.postJSON(t+"/lots/doSearchLots",n,e=>{if(0===e.count)return void(l.innerHTML='

No results.

');const t=document.createElement("div");t.className="panel";for(const c of e.lots){const e=document.createElement("a");e.className="panel-block is-block",e.href="#",e.dataset.lotId=c.lotId.toString(),e.dataset.lotName=c.lotName,e.innerHTML='
'+cityssm.escapeHTML(c.lotName)+'
'+cityssm.escapeHTML(c.mapName)+'
'+cityssm.escapeHTML(c.lotStatus)+'
'+(c.lotOccupancyCount>0?"Currently Occupied":"")+"
",e.addEventListener("click",u),t.append(e)}l.innerHTML="",l.append(t)})};cityssm.openHtmlModal("lotOccupancy-selectLot",{onshow:t=>{e.populateAliases(t)},onshown:(e,t)=>{bulmaJS.toggleHtmlClipped(),o=t;const c=e.querySelector("#lotSelect--lotName");c.value=a,c.focus(),c.addEventListener("change",r),e.querySelector("#lotSelect--occupancyStatus").addEventListener("change",r),n=e.querySelector("#form--lotSelect"),l=e.querySelector("#resultsContainer--lotSelect"),n.addEventListener("submit",e=>{e.preventDefault()}),r()},onremoved:()=>{bulmaJS.toggleHtmlClipped()}})}),document.querySelector("#lotOccupancy--occupancyStartDateString").addEventListener("change",()=>{document.querySelector("#lotOccupancy--occupancyEndDateString").min=document.querySelector("#lotOccupancy--occupancyStartDateString").value}),e.initializeUnlockFieldButtons(l),!a){let a=exports.lotOccupancyOccupants;const o=o=>{const n=Number.parseInt(o.currentTarget.closest("tr").dataset.lotOccupantIndex,10),l=a.find(e=>e.lotOccupantIndex===n);let u,r;const p=e=>{e.preventDefault(),cityssm.postJSON(t+"/lotOccupancies/doUpdateLotOccupancyOccupant",u,e=>{e.success?(a=e.lotOccupancyOccupants,r(),s()):bulmaJS.alert({title:"Error Updating "+exports.aliases.occupant,message:e.errorMessage,contextualColorName:"danger"})})};cityssm.openHtmlModal("lotOccupancy-editOccupant",{onshow:t=>{e.populateAliases(t),t.querySelector("#lotOccupancyOccupantEdit--lotOccupancyId").value=c,t.querySelector("#lotOccupancyOccupantEdit--lotOccupantIndex").value=n.toString();const a=t.querySelector("#lotOccupancyOccupantEdit--lotOccupantTypeId");let o=!1;for(const e of exports.lotOccupantTypes){const t=document.createElement("option");t.value=e.lotOccupantTypeId.toString(),t.textContent=e.lotOccupantType,e.lotOccupantTypeId===l.lotOccupantTypeId&&(t.selected=!0,o=!0),a.append(t)}if(!o){const e=document.createElement("option");e.value=l.lotOccupantTypeId.toString(),e.textContent=l.lotOccupantType,e.selected=!0,a.append(e)}t.querySelector("#lotOccupancyOccupantEdit--occupantName").value=l.occupantName,t.querySelector("#lotOccupancyOccupantEdit--occupantAddress1").value=l.occupantAddress1,t.querySelector("#lotOccupancyOccupantEdit--occupantAddress2").value=l.occupantAddress2,t.querySelector("#lotOccupancyOccupantEdit--occupantCity").value=l.occupantCity,t.querySelector("#lotOccupancyOccupantEdit--occupantProvince").value=l.occupantProvince,t.querySelector("#lotOccupancyOccupantEdit--occupantPostalCode").value=l.occupantPostalCode,t.querySelector("#lotOccupancyOccupantEdit--occupantPhoneNumber").value=l.occupantPhoneNumber},onshown:(e,t)=>{bulmaJS.toggleHtmlClipped(),(u=e.querySelector("form")).addEventListener("submit",p),r=t},onremoved:()=>{bulmaJS.toggleHtmlClipped()}})},n=e=>{const o=e.currentTarget.closest("tr").dataset.lotOccupantIndex;bulmaJS.confirm({title:"Remove "+exports.aliases.occupant+"?",message:"Are you sure you want to remove this "+exports.aliases.occupant.toLowerCase()+"?",okButton:{text:"Yes, Remove "+exports.aliases.occupant,callbackFunction:()=>{cityssm.postJSON(t+"/lotOccupancies/doDeleteLotOccupancyOccupant",{lotOccupancyId:c,lotOccupantIndex:o},e=>{e.success?(a=e.lotOccupancyOccupants,s()):bulmaJS.alert({title:"Error Removing "+exports.aliases.occupant,message:e.errorMessage,contextualColorName:"danger"})})}},contextualColorName:"warning"})},s=()=>{const e=document.querySelector("#container--lotOccupancyOccupants");if(cityssm.clearElement(e),0===a.length)return void(e.innerHTML='

There are no '+exports.aliases.occupants.toLowerCase()+" associated with this record.

");const t=document.createElement("table");t.className="table is-fullwidth is-striped is-hoverable",t.innerHTML=""+exports.aliases.occupant+" Type"+exports.aliases.occupant+"AddressPhone Number";for(const e of a){const c=document.createElement("tr");c.dataset.lotOccupantIndex=e.lotOccupantIndex.toString(),c.innerHTML=""+cityssm.escapeHTML(e.lotOccupantType)+""+cityssm.escapeHTML(e.occupantName)+""+cityssm.escapeHTML(e.occupantAddress1)+"
"+(e.occupantAddress2?cityssm.escapeHTML(e.occupantAddress2)+"
":"")+cityssm.escapeHTML(e.occupantCity)+", "+cityssm.escapeHTML(e.occupantProvince)+"
"+cityssm.escapeHTML(e.occupantPostalCode)+""+cityssm.escapeHTML(e.occupantPhoneNumber)+'
',c.querySelector(".button--edit").addEventListener("click",o),c.querySelector(".button--delete").addEventListener("click",n),t.querySelector("tbody").append(c)}e.append(t)};document.querySelector("#button--addOccupant").addEventListener("click",()=>{let o,n;const l=e=>{e.preventDefault(),cityssm.postJSON(t+"/lotOccupancies/doAddLotOccupancyOccupant",o,e=>{e.success?(a=e.lotOccupancyOccupants,n(),s()):bulmaJS.alert({title:"Error Adding "+exports.aliases.occupant,message:e.errorMessage,contextualColorName:"danger"})})};cityssm.openHtmlModal("lotOccupancy-addOccupant",{onshow:t=>{e.populateAliases(t),t.querySelector("#lotOccupancyOccupantAdd--lotOccupancyId").value=c;const a=t.querySelector("#lotOccupancyOccupantAdd--lotOccupantTypeId");for(const e of exports.lotOccupantTypes){const t=document.createElement("option");t.value=e.lotOccupantTypeId.toString(),t.textContent=e.lotOccupantType,a.append(t)}t.querySelector("#lotOccupancyOccupantAdd--occupantCity").value=exports.occupantCityDefault,t.querySelector("#lotOccupancyOccupantAdd--occupantProvince").value=exports.occupantProvinceDefault},onshown:(e,t)=>{bulmaJS.toggleHtmlClipped(),(o=e.querySelector("form")).addEventListener("submit",l),n=t},onremoved:()=>{bulmaJS.toggleHtmlClipped()}})}),s()}})(); \ No newline at end of file +"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),(()=>{const e=exports.los,t=document.querySelector("main").dataset.urlPrefix,c=document.querySelector("#lotOccupancy--lotOccupancyId").value,a=""===c;let o=!1,n=a;const s=()=>{o||(o=!0,cityssm.enableNavBlocker())},l=document.querySelector("#form--lotOccupancy");l.addEventListener("submit",e=>{e.preventDefault(),cityssm.postJSON(t+"/lotOccupancies/"+(a?"doCreateLotOccupancy":"doUpdateLotOccupancy"),l,e=>{e.success?(o=!1,cityssm.disableNavBlocker(),a||n?window.location.href=t+"/lotOccupancies/"+e.lotOccupancyId+"/edit?t="+Date.now():bulmaJS.alert({message:exports.aliases.occupancy+" Updated Successfully",contextualColorName:"success"})):bulmaJS.alert({title:"Error Saving "+exports.aliases.occupancy,message:e.errorMessage,contextualColorName:"danger"})})});const u=l.querySelectorAll("input, select");for(const e of u)e.addEventListener("change",s);const r=document.querySelector("#lotOccupancy--occupancyTypeId");if(a){const e=document.querySelector("#container--lotOccupancyFields");r.addEventListener("change",()=>{""!==r.value?cityssm.postJSON(t+"/lotOccupancies/doGetOccupancyTypeFields",{occupancyTypeId:r.value},t=>{if(0===t.occupancyTypeFields.length)return void(e.innerHTML='

There are no additional fields for this '+exports.aliases.occupancy.toLowerCase()+" type.

");e.innerHTML="";let c="";for(const a of t.occupancyTypeFields){c+=","+a.occupancyTypeFieldId;const t=document.createElement("div");t.className="field",t.innerHTML='
',t.querySelector("label").textContent=a.occupancyTypeField;const o=document.createElement("input");o.className="input",o.id="lotOccupancy--lotOccupancyFieldValue_"+a.occupancyTypeFieldId,o.name="lotOccupancyFieldValue_"+a.occupancyTypeFieldId,o.type="text",o.required=a.isRequired,o.minLength=a.minimumLength,o.maxLength=a.maximumLength,a.pattern&&""!==a.pattern&&(o.pattern=a.pattern),t.querySelector(".control").append(o),e.append(t)}e.insertAdjacentHTML("beforeend",'')}):e.innerHTML='

Select the '+exports.aliases.occupancy.toLowerCase()+" type to load the available fields.

"})}else{const e=r.value;r.addEventListener("change",()=>{r.value!==e&&bulmaJS.confirm({title:"Confirm Change",message:"Are you sure you want to change the "+exports.aliases.occupancy.toLowerCase()+" type?\nThis change affects the additional fields associated with this record, and may also affect the available fees.",contextualColorName:"warning",okButton:{text:"Yes, Keep the Change",callbackFunction:()=>{n=!0}},cancelButton:{text:"Revert the Change",callbackFunction:()=>{r.value=e}}})})}if(document.querySelector("#lotOccupancy--lotName").addEventListener("click",c=>{const a=c.currentTarget.value;let o,n,l;const u=e=>{e.preventDefault();const t=e.currentTarget;document.querySelector("#lotOccupancy--lotId").value=t.dataset.lotId,document.querySelector("#lotOccupancy--lotName").value=t.dataset.lotName,s(),o()},r=()=>{l.innerHTML='


Searching...

',cityssm.postJSON(t+"/lots/doSearchLots",n,e=>{if(0===e.count)return void(l.innerHTML='

No results.

');const t=document.createElement("div");t.className="panel";for(const c of e.lots){const e=document.createElement("a");e.className="panel-block is-block",e.href="#",e.dataset.lotId=c.lotId.toString(),e.dataset.lotName=c.lotName,e.innerHTML='
'+cityssm.escapeHTML(c.lotName)+'
'+cityssm.escapeHTML(c.mapName)+'
'+cityssm.escapeHTML(c.lotStatus)+'
'+(c.lotOccupancyCount>0?"Currently Occupied":"")+"
",e.addEventListener("click",u),t.append(e)}l.innerHTML="",l.append(t)})};cityssm.openHtmlModal("lotOccupancy-selectLot",{onshow:t=>{e.populateAliases(t)},onshown:(e,t)=>{bulmaJS.toggleHtmlClipped(),o=t;const c=e.querySelector("#lotSelect--lotName");c.value=a,c.focus(),c.addEventListener("change",r),e.querySelector("#lotSelect--occupancyStatus").addEventListener("change",r),n=e.querySelector("#form--lotSelect"),l=e.querySelector("#resultsContainer--lotSelect"),n.addEventListener("submit",e=>{e.preventDefault()}),r()},onremoved:()=>{bulmaJS.toggleHtmlClipped()}})}),document.querySelector("#lotOccupancy--occupancyStartDateString").addEventListener("change",()=>{document.querySelector("#lotOccupancy--occupancyEndDateString").min=document.querySelector("#lotOccupancy--occupancyStartDateString").value}),e.initializeUnlockFieldButtons(l),!a){let a=exports.lotOccupancyOccupants;const o=o=>{const n=Number.parseInt(o.currentTarget.closest("tr").dataset.lotOccupantIndex,10),l=a.find(e=>e.lotOccupantIndex===n);let u,r;const p=e=>{e.preventDefault(),cityssm.postJSON(t+"/lotOccupancies/doUpdateLotOccupancyOccupant",u,e=>{e.success?(a=e.lotOccupancyOccupants,r(),s()):bulmaJS.alert({title:"Error Updating "+exports.aliases.occupant,message:e.errorMessage,contextualColorName:"danger"})})};cityssm.openHtmlModal("lotOccupancy-editOccupant",{onshow:t=>{e.populateAliases(t),t.querySelector("#lotOccupancyOccupantEdit--lotOccupancyId").value=c,t.querySelector("#lotOccupancyOccupantEdit--lotOccupantIndex").value=n.toString();const a=t.querySelector("#lotOccupancyOccupantEdit--lotOccupantTypeId");let o=!1;for(const e of exports.lotOccupantTypes){const t=document.createElement("option");t.value=e.lotOccupantTypeId.toString(),t.textContent=e.lotOccupantType,e.lotOccupantTypeId===l.lotOccupantTypeId&&(t.selected=!0,o=!0),a.append(t)}if(!o){const e=document.createElement("option");e.value=l.lotOccupantTypeId.toString(),e.textContent=l.lotOccupantType,e.selected=!0,a.append(e)}t.querySelector("#lotOccupancyOccupantEdit--occupantName").value=l.occupantName,t.querySelector("#lotOccupancyOccupantEdit--occupantAddress1").value=l.occupantAddress1,t.querySelector("#lotOccupancyOccupantEdit--occupantAddress2").value=l.occupantAddress2,t.querySelector("#lotOccupancyOccupantEdit--occupantCity").value=l.occupantCity,t.querySelector("#lotOccupancyOccupantEdit--occupantProvince").value=l.occupantProvince,t.querySelector("#lotOccupancyOccupantEdit--occupantPostalCode").value=l.occupantPostalCode,t.querySelector("#lotOccupancyOccupantEdit--occupantPhoneNumber").value=l.occupantPhoneNumber},onshown:(e,t)=>{bulmaJS.toggleHtmlClipped(),(u=e.querySelector("form")).addEventListener("submit",p),r=t},onremoved:()=>{bulmaJS.toggleHtmlClipped()}})},n=e=>{const o=e.currentTarget.closest("tr").dataset.lotOccupantIndex;bulmaJS.confirm({title:"Remove "+exports.aliases.occupant+"?",message:"Are you sure you want to remove this "+exports.aliases.occupant.toLowerCase()+"?",okButton:{text:"Yes, Remove "+exports.aliases.occupant,callbackFunction:()=>{cityssm.postJSON(t+"/lotOccupancies/doDeleteLotOccupancyOccupant",{lotOccupancyId:c,lotOccupantIndex:o},e=>{e.success?(a=e.lotOccupancyOccupants,s()):bulmaJS.alert({title:"Error Removing "+exports.aliases.occupant,message:e.errorMessage,contextualColorName:"danger"})})}},contextualColorName:"warning"})},s=()=>{const e=document.querySelector("#container--lotOccupancyOccupants");if(cityssm.clearElement(e),0===a.length)return void(e.innerHTML='

There are no '+exports.aliases.occupants.toLowerCase()+" associated with this record.

");const t=document.createElement("table");t.className="table is-fullwidth is-striped is-hoverable",t.innerHTML=""+exports.aliases.occupant+" Type"+exports.aliases.occupant+"AddressPhone Number";for(const e of a){const c=document.createElement("tr");c.dataset.lotOccupantIndex=e.lotOccupantIndex.toString(),c.innerHTML=""+cityssm.escapeHTML(e.lotOccupantType)+""+cityssm.escapeHTML(e.occupantName)+""+cityssm.escapeHTML(e.occupantAddress1)+"
"+(e.occupantAddress2?cityssm.escapeHTML(e.occupantAddress2)+"
":"")+cityssm.escapeHTML(e.occupantCity)+", "+cityssm.escapeHTML(e.occupantProvince)+"
"+cityssm.escapeHTML(e.occupantPostalCode)+""+cityssm.escapeHTML(e.occupantPhoneNumber)+'
',c.querySelector(".button--edit").addEventListener("click",o),c.querySelector(".button--delete").addEventListener("click",n),t.querySelector("tbody").append(c)}e.append(t)};document.querySelector("#button--addOccupant").addEventListener("click",()=>{let o,n;const l=e=>{e.preventDefault(),cityssm.postJSON(t+"/lotOccupancies/doAddLotOccupancyOccupant",o,e=>{e.success?(a=e.lotOccupancyOccupants,n(),s()):bulmaJS.alert({title:"Error Adding "+exports.aliases.occupant,message:e.errorMessage,contextualColorName:"danger"})})};cityssm.openHtmlModal("lotOccupancy-addOccupant",{onshow:t=>{e.populateAliases(t),t.querySelector("#lotOccupancyOccupantAdd--lotOccupancyId").value=c;const a=t.querySelector("#lotOccupancyOccupantAdd--lotOccupantTypeId");for(const e of exports.lotOccupantTypes){const t=document.createElement("option");t.value=e.lotOccupantTypeId.toString(),t.textContent=e.lotOccupantType,a.append(t)}t.querySelector("#lotOccupancyOccupantAdd--occupantCity").value=exports.occupantCityDefault,t.querySelector("#lotOccupancyOccupantAdd--occupantProvince").value=exports.occupantProvinceDefault},onshown:(e,t)=>{bulmaJS.toggleHtmlClipped(),(o=e.querySelector("form")).addEventListener("submit",l),n=t},onremoved:()=>{bulmaJS.toggleHtmlClipped()}})}),s()}})(); \ No newline at end of file diff --git a/routes/lotOccupancies.js b/routes/lotOccupancies.js index e5b27771..7dfaa929 100644 --- a/routes/lotOccupancies.js +++ b/routes/lotOccupancies.js @@ -2,6 +2,9 @@ import { Router } from "express"; import handler_search from "../handlers/lotOccupancies-get/search.js"; import handler_doSearchLotOccupancies from "../handlers/lotOccupancies-post/doSearchLotOccupancies.js"; import handler_view from "../handlers/lotOccupancies-get/view.js"; +import handler_new from "../handlers/lotOccupancies-get/new.js"; +import handler_doGetOccupancyTypeFields from "../handlers/lotOccupancies-post/doGetOccupancyTypeFields.js"; +import handler_doCreateLotOccupancy from "../handlers/lotOccupancies-post/doCreateLotOccupancy.js"; import handler_edit from "../handlers/lotOccupancies-get/edit.js"; import handler_doUpdateLotOccupancy from "../handlers/lotOccupancies-post/doUpdateLotOccupancy.js"; import handler_doAddLotOccupancyOccupant from "../handlers/lotOccupancies-post/doAddLotOccupancyOccupant.js"; @@ -11,6 +14,9 @@ import * as permissionHandlers from "../handlers/permissions.js"; export const router = Router(); router.get("/", handler_search); router.post("/doSearchLotOccupancies", handler_doSearchLotOccupancies); +router.get("/new", permissionHandlers.updateGetHandler, handler_new); +router.post("/doGetOccupancyTypeFields", permissionHandlers.updatePostHandler, handler_doGetOccupancyTypeFields); +router.post("/doCreateLotOccupancy", permissionHandlers.updatePostHandler, handler_doCreateLotOccupancy); router.get("/:lotOccupancyId", handler_view); router.get("/:lotOccupancyId/edit", permissionHandlers.updateGetHandler, handler_edit); router.post("/doUpdateLotOccupancy", permissionHandlers.updatePostHandler, handler_doUpdateLotOccupancy); diff --git a/routes/lotOccupancies.ts b/routes/lotOccupancies.ts index 77b89f4e..0afd766d 100644 --- a/routes/lotOccupancies.ts +++ b/routes/lotOccupancies.ts @@ -7,6 +7,10 @@ import handler_doSearchLotOccupancies from "../handlers/lotOccupancies-post/doSe import handler_view from "../handlers/lotOccupancies-get/view.js"; +import handler_new from "../handlers/lotOccupancies-get/new.js"; +import handler_doGetOccupancyTypeFields from "../handlers/lotOccupancies-post/doGetOccupancyTypeFields.js"; +import handler_doCreateLotOccupancy from "../handlers/lotOccupancies-post/doCreateLotOccupancy.js"; + import handler_edit from "../handlers/lotOccupancies-get/edit.js"; import handler_doUpdateLotOccupancy from "../handlers/lotOccupancies-post/doUpdateLotOccupancy.js"; @@ -28,6 +32,19 @@ router.post("/doSearchLotOccupancies", handler_doSearchLotOccupancies); +router.get("/new", + permissionHandlers.updateGetHandler, + handler_new); + +router.post("/doGetOccupancyTypeFields", + permissionHandlers.updatePostHandler, + handler_doGetOccupancyTypeFields); + +router.post("/doCreateLotOccupancy", + permissionHandlers.updatePostHandler, + handler_doCreateLotOccupancy); + + router.get("/:lotOccupancyId", handler_view); diff --git a/views/lotOccupancy-edit.ejs b/views/lotOccupancy-edit.ejs index eddb6251..6443b644 100644 --- a/views/lotOccupancy-edit.ejs +++ b/views/lotOccupancy-edit.ejs @@ -14,30 +14,34 @@ <%= configFunctions.getProperty("aliases.lots") %> <%= configFunctions.getProperty("aliases.occupancies") %> + <% if (!isCreate) { %>
  • <%= configFunctions.getProperty("aliases.occupancy") %>: <%= lotOccupancy.lotName %>
  • + <% } %>
  • - Update <%= configFunctions.getProperty("aliases.occupancy") %> + <% if (isCreate) { %> + Create a New <%= configFunctions.getProperty("aliases.occupancy") %> Record + <% } else { %> + Update <%= configFunctions.getProperty("aliases.occupancy") %> + <% } %>
  • - <%= configFunctions.getProperty("aliases.occupancy") %> Update + <% if (isCreate) { %> + Create a New <%= configFunctions.getProperty("aliases.occupancy") %> Record + <% } else { %> + Update <%= configFunctions.getProperty("aliases.occupancy") %> + <% } %>

    -
    - -
    @@ -52,11 +56,11 @@ - + <% } %> + +
    - +
    + +
    <% if (isCreate) { %> @@ -205,16 +218,18 @@ <%- include('_footerA'); -%> - + exports.lotOccupancyOccupants = <%- JSON.stringify(lotOccupancy.lotOccupancyOccupants) %>; + exports.lotOccupancyComments = <%- JSON.stringify(lotOccupancy.lotOccupancyComments) %>; + exports.lotOccupancyFees = <%- JSON.stringify(lotOccupancy.lotOccupancyFees) %>; + exports.lotOccupancyTransactions = <%- JSON.stringify(lotOccupancy.lotOccupancyTransactions) %>; + +<% } %>