diff --git a/handlers/admin-post/doUpdateOccupancyType.d.ts b/handlers/admin-post/doUpdateOccupancyType.d.ts new file mode 100644 index 00000000..9621c611 --- /dev/null +++ b/handlers/admin-post/doUpdateOccupancyType.d.ts @@ -0,0 +1,3 @@ +import type { RequestHandler } from "express"; +export declare const handler: RequestHandler; +export default handler; diff --git a/handlers/admin-post/doUpdateOccupancyType.js b/handlers/admin-post/doUpdateOccupancyType.js new file mode 100644 index 00000000..952a3280 --- /dev/null +++ b/handlers/admin-post/doUpdateOccupancyType.js @@ -0,0 +1,11 @@ +import { updateOccupancyType } from "../../helpers/lotOccupancyDB/updateOccupancyType.js"; +import { getOccupancyTypes } from "../../helpers/functions.cache.js"; +export const handler = async (request, response) => { + const success = updateOccupancyType(request.body, request.session); + const occupancyTypes = getOccupancyTypes(); + response.json({ + success, + occupancyTypes + }); +}; +export default handler; diff --git a/handlers/admin-post/doUpdateOccupancyType.ts b/handlers/admin-post/doUpdateOccupancyType.ts new file mode 100644 index 00000000..ee27dd38 --- /dev/null +++ b/handlers/admin-post/doUpdateOccupancyType.ts @@ -0,0 +1,18 @@ +import type { RequestHandler } from "express"; + +import { updateOccupancyType } from "../../helpers/lotOccupancyDB/updateOccupancyType.js"; + +import { getOccupancyTypes } from "../../helpers/functions.cache.js"; + +export const handler: RequestHandler = async (request, response) => { + const success = updateOccupancyType(request.body, request.session); + + const occupancyTypes = getOccupancyTypes(); + + response.json({ + success, + occupancyTypes + }); +}; + +export default handler; diff --git a/helpers/lotOccupancyDB/updateOccupancyType.d.ts b/helpers/lotOccupancyDB/updateOccupancyType.d.ts new file mode 100644 index 00000000..eb2a313a --- /dev/null +++ b/helpers/lotOccupancyDB/updateOccupancyType.d.ts @@ -0,0 +1,7 @@ +import type * as recordTypes from "../../types/recordTypes"; +interface UpdateOccupancyTypeForm { + occupancyTypeId: number | string; + occupancyType: string; +} +export declare const updateOccupancyType: (occupancyTypeForm: UpdateOccupancyTypeForm, requestSession: recordTypes.PartialSession) => boolean; +export default updateOccupancyType; diff --git a/helpers/lotOccupancyDB/updateOccupancyType.js b/helpers/lotOccupancyDB/updateOccupancyType.js new file mode 100644 index 00000000..9b024797 --- /dev/null +++ b/helpers/lotOccupancyDB/updateOccupancyType.js @@ -0,0 +1,19 @@ +import sqlite from "better-sqlite3"; +import { lotOccupancyDB as databasePath } from "../../data/databasePaths.js"; +import { clearOccupancyTypesCache } from "../functions.cache.js"; +export const updateOccupancyType = (occupancyTypeForm, requestSession) => { + const database = sqlite(databasePath); + const rightNowMillis = Date.now(); + const result = database + .prepare("update OccupancyTypes" + + " set occupancyType = ?," + + " recordUpdate_userName = ?," + + " recordUpdate_timeMillis = ?" + + " where occupancyTypeId = ?" + + " and recordDelete_timeMillis is null") + .run(occupancyTypeForm.occupancyType, requestSession.user.userName, rightNowMillis, occupancyTypeForm.occupancyTypeId); + database.close(); + clearOccupancyTypesCache(); + return result.changes > 0; +}; +export default updateOccupancyType; diff --git a/helpers/lotOccupancyDB/updateOccupancyType.ts b/helpers/lotOccupancyDB/updateOccupancyType.ts new file mode 100644 index 00000000..8fe7a5e6 --- /dev/null +++ b/helpers/lotOccupancyDB/updateOccupancyType.ts @@ -0,0 +1,45 @@ +import sqlite from "better-sqlite3"; + +import { lotOccupancyDB as databasePath } from "../../data/databasePaths.js"; + +import { clearOccupancyTypesCache } from "../functions.cache.js"; + +import type * as recordTypes from "../../types/recordTypes"; + +interface UpdateOccupancyTypeForm { + occupancyTypeId: number | string; + occupancyType: string; +} + +export const updateOccupancyType = ( + occupancyTypeForm: UpdateOccupancyTypeForm, + requestSession: recordTypes.PartialSession +): boolean => { + const database = sqlite(databasePath); + + const rightNowMillis = Date.now(); + + const result = database + .prepare( + "update OccupancyTypes" + + " set occupancyType = ?," + + " recordUpdate_userName = ?," + + " recordUpdate_timeMillis = ?" + + " where occupancyTypeId = ?" + + " and recordDelete_timeMillis is null" + ) + .run( + occupancyTypeForm.occupancyType, + requestSession.user.userName, + rightNowMillis, + occupancyTypeForm.occupancyTypeId + ); + + database.close(); + + clearOccupancyTypesCache(); + + return result.changes > 0; +}; + +export default updateOccupancyType; diff --git a/public-typescript/adminOccupancyTypes.js b/public-typescript/adminOccupancyTypes.js index 0bd4224b..1f37992e 100644 --- a/public-typescript/adminOccupancyTypes.js +++ b/public-typescript/adminOccupancyTypes.js @@ -25,6 +25,50 @@ Object.defineProperty(exports, "__esModule", { value: true }); panelBlockElement.classList.toggle("is-hidden"); } }; + const openEditOccupancyType = (clickEvent) => { + const occupancyTypeId = Number.parseInt(clickEvent.currentTarget.closest(".container--occupancyType").dataset.occupancyTypeId, 10); + const occupancyType = occupancyTypes.find((currentOccupancyType) => { + return occupancyTypeId === currentOccupancyType.occupancyTypeId; + }); + let editCloseModalFunction; + const doEdit = (submitEvent) => { + submitEvent.preventDefault(); + cityssm.postJSON(urlPrefix + "/admin/doUpdateOccupancyType", submitEvent.currentTarget, (responseJSON) => { + if (responseJSON.success) { + editCloseModalFunction(); + occupancyTypes = responseJSON.occupancyTypes; + renderOccupancyTypes(); + } + else { + bulmaJS.alert({ + title: "Error Updating " + + exports.aliases.occupancy + + " Type", + message: responseJSON.errorMessage, + contextualColorName: "danger" + }); + } + }); + }; + cityssm.openHtmlModal("adminOccupancyTypes-editOccupancyType", { + onshow: (modalElement) => { + los.populateAliases(modalElement); + modalElement.querySelector("#occupancyTypeEdit--occupancyTypeId").value = occupancyTypeId.toString(); + modalElement.querySelector("#occupancyTypeEdit--occupancyType").value = occupancyType.occupancyType; + }, + onshown: (modalElement, closeModalFunction) => { + editCloseModalFunction = closeModalFunction; + modalElement.querySelector("#occupancyTypeEdit--occupancyType").focus(); + modalElement + .querySelector("form") + .addEventListener("submit", doEdit); + bulmaJS.toggleHtmlClipped(); + }, + onremoved: () => { + bulmaJS.toggleHtmlClipped(); + } + }); + }; const moveOccupancyTypeUp = (clickEvent) => { clickEvent.preventDefault(); const occupancyTypeId = clickEvent.currentTarget.closest(".container--occupancyType").dataset.occupancyTypeId; @@ -185,6 +229,9 @@ Object.defineProperty(exports, "__esModule", { value: true }); occupancyTypeContainer .querySelector(".button--toggleOccupancyTypeFields") .addEventListener("click", toggleOccupancyTypeFields); + occupancyTypeContainer + .querySelector(".button--editOccupancyType") + .addEventListener("click", openEditOccupancyType); occupancyTypeContainer .querySelector(".button--moveOccupancyTypeUp") .addEventListener("click", moveOccupancyTypeUp); diff --git a/public-typescript/adminOccupancyTypes.ts b/public-typescript/adminOccupancyTypes.ts index 60fd68b8..4ef24a90 100644 --- a/public-typescript/adminOccupancyTypes.ts +++ b/public-typescript/adminOccupancyTypes.ts @@ -57,6 +57,88 @@ declare const bulmaJS: BulmaJS; } }; + const openEditOccupancyType = (clickEvent: Event) => { + const occupancyTypeId = Number.parseInt( + ( + (clickEvent.currentTarget as HTMLElement).closest( + ".container--occupancyType" + ) as HTMLElement + ).dataset.occupancyTypeId, + 10 + ); + + const occupancyType = occupancyTypes.find((currentOccupancyType) => { + return occupancyTypeId === currentOccupancyType.occupancyTypeId; + }); + + let editCloseModalFunction: () => void; + + const doEdit = (submitEvent: SubmitEvent) => { + submitEvent.preventDefault(); + + cityssm.postJSON( + urlPrefix + "/admin/doUpdateOccupancyType", + submitEvent.currentTarget, + (responseJSON: { + success: boolean; + errorMessage?: string; + occupancyTypes?: recordTypes.OccupancyType[]; + }) => { + if (responseJSON.success) { + editCloseModalFunction(); + occupancyTypes = responseJSON.occupancyTypes; + renderOccupancyTypes(); + } else { + bulmaJS.alert({ + title: + "Error Updating " + + exports.aliases.occupancy + + " Type", + message: responseJSON.errorMessage, + contextualColorName: "danger" + }); + } + } + ); + }; + + cityssm.openHtmlModal("adminOccupancyTypes-editOccupancyType", { + onshow: (modalElement) => { + los.populateAliases(modalElement); + + ( + modalElement.querySelector( + "#occupancyTypeEdit--occupancyTypeId" + ) as HTMLInputElement + ).value = occupancyTypeId.toString(); + + ( + modalElement.querySelector( + "#occupancyTypeEdit--occupancyType" + ) as HTMLInputElement + ).value = occupancyType.occupancyType; + }, + onshown: (modalElement, closeModalFunction) => { + editCloseModalFunction = closeModalFunction; + + ( + modalElement.querySelector( + "#occupancyTypeEdit--occupancyType" + ) as HTMLInputElement + ).focus(); + + modalElement + .querySelector("form") + .addEventListener("submit", doEdit); + + bulmaJS.toggleHtmlClipped(); + }, + onremoved: () => { + bulmaJS.toggleHtmlClipped(); + } + }); + }; + const moveOccupancyTypeUp = (clickEvent: Event) => { clickEvent.preventDefault(); @@ -270,6 +352,10 @@ declare const bulmaJS: BulmaJS; .querySelector(".button--toggleOccupancyTypeFields") .addEventListener("click", toggleOccupancyTypeFields); + occupancyTypeContainer + .querySelector(".button--editOccupancyType") + .addEventListener("click", openEditOccupancyType); + occupancyTypeContainer .querySelector(".button--moveOccupancyTypeUp") .addEventListener("click", moveOccupancyTypeUp); diff --git a/public/html/adminOccupancyTypes-editOccupancyType.html b/public/html/adminOccupancyTypes-editOccupancyType.html new file mode 100644 index 00000000..f1e473d5 --- /dev/null +++ b/public/html/adminOccupancyTypes-editOccupancyType.html @@ -0,0 +1,29 @@ + \ No newline at end of file diff --git a/public/javascripts/adminOccupancyTypes.min.js b/public/javascripts/adminOccupancyTypes.min.js index 49d0bd39..5d965765 100644 --- a/public/javascripts/adminOccupancyTypes.min.js +++ b/public/javascripts/adminOccupancyTypes.min.js @@ -1 +1 @@ -"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),(()=>{const e=exports.los,a=document.querySelector("main").dataset.urlPrefix,s=document.querySelector("#container--occupancyTypes");let c=exports.occupancyTypes;delete exports.occupancyTypes;const t=new Set,o=e=>{const a=e.currentTarget,s=a.closest(".container--occupancyType"),c=Number.parseInt(s.dataset.occupancyTypeId,10);t.has(c)?t.delete(c):t.add(c),a.innerHTML=t.has(c)?'':'';const o=s.querySelectorAll(".panel-block");for(const e of o)e.classList.toggle("is-hidden")},n=e=>{e.preventDefault();const s=e.currentTarget.closest(".container--occupancyType").dataset.occupancyTypeId;cityssm.postJSON(a+"/admin/doMoveOccupancyTypeUp",{occupancyTypeId:s},e=>{e.success?(c=e.occupancyTypes,i()):bulmaJS.alert({title:"Error Moving "+exports.aliases.occupancy+" Type",message:e.errorMessage,contextualColorName:"danger"})})},l=e=>{e.preventDefault();const s=e.currentTarget.closest(".container--occupancyType").dataset.occupancyTypeId;cityssm.postJSON(a+"/admin/doMoveOccupancyTypeDown",{occupancyTypeId:s},e=>{e.success?(c=e.occupancyTypes,i()):bulmaJS.alert({title:"Error Moving "+exports.aliases.occupancy+" Type",message:e.errorMessage,contextualColorName:"danger"})})},i=()=>{if(0!==c.length){s.innerHTML="";for(const e of c){const a=document.createElement("div");if(a.className="panel container--occupancyType",a.dataset.occupancyTypeId=e.occupancyTypeId.toString(),a.innerHTML='

'+cityssm.escapeHTML(e.occupancyType)+'

',0===e.occupancyTypeFields.length)a.insertAdjacentHTML("beforeend",'

There are no additional fields.

');else for(const s of e.occupancyTypeFields){const c=document.createElement("div");c.className="panel-block is-block container--occupancyTypeField",t.has(e.occupancyTypeId)||c.classList.add("is-hidden"),c.dataset.occupancyTypeFieldId=s.occupancyTypeFieldId.toString(),c.innerHTML='
',a.append(c)}a.querySelector(".button--toggleOccupancyTypeFields").addEventListener("click",o),a.querySelector(".button--moveOccupancyTypeUp").addEventListener("click",n),a.querySelector(".button--moveOccupancyTypeDown").addEventListener("click",l),s.append(a)}}else s.innerHTML='
There are no active '+exports.aliases.occupancy.toLowerCase()+" types.

"};document.querySelector("#button--addOccupancyType").addEventListener("click",()=>{let s;const t=e=>{e.preventDefault(),cityssm.postJSON(a+"/admin/doAddOccupancyType",e.currentTarget,e=>{e.success?(s(),c=e.occupancyTypes,i()):bulmaJS.alert({title:"Error Adding "+exports.aliases.occupancy+" Type",message:e.errorMessage,contextualColorName:"danger"})})};cityssm.openHtmlModal("adminOccupancyTypes-addOccupancyType",{onshow:a=>{e.populateAliases(a)},onshown:(e,a)=>{s=a,e.querySelector("#occupancyTypeAdd--occupancyType").focus(),e.querySelector("form").addEventListener("submit",t),bulmaJS.toggleHtmlClipped()},onremoved:()=>{bulmaJS.toggleHtmlClipped()}})}),i()})(); \ No newline at end of file +"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),(()=>{const e=exports.los,c=document.querySelector("main").dataset.urlPrefix,a=document.querySelector("#container--occupancyTypes");let t=exports.occupancyTypes;delete exports.occupancyTypes;const s=new Set,o=e=>{const c=e.currentTarget,a=c.closest(".container--occupancyType"),t=Number.parseInt(a.dataset.occupancyTypeId,10);s.has(t)?s.delete(t):s.add(t),c.innerHTML=s.has(t)?'':'';const o=a.querySelectorAll(".panel-block");for(const e of o)e.classList.toggle("is-hidden")},n=a=>{const s=Number.parseInt(a.currentTarget.closest(".container--occupancyType").dataset.occupancyTypeId,10),o=t.find(e=>s===e.occupancyTypeId);let n;const l=e=>{e.preventDefault(),cityssm.postJSON(c+"/admin/doUpdateOccupancyType",e.currentTarget,e=>{e.success?(n(),t=e.occupancyTypes,p()):bulmaJS.alert({title:"Error Updating "+exports.aliases.occupancy+" Type",message:e.errorMessage,contextualColorName:"danger"})})};cityssm.openHtmlModal("adminOccupancyTypes-editOccupancyType",{onshow:c=>{e.populateAliases(c),c.querySelector("#occupancyTypeEdit--occupancyTypeId").value=s.toString(),c.querySelector("#occupancyTypeEdit--occupancyType").value=o.occupancyType},onshown:(e,c)=>{n=c,e.querySelector("#occupancyTypeEdit--occupancyType").focus(),e.querySelector("form").addEventListener("submit",l),bulmaJS.toggleHtmlClipped()},onremoved:()=>{bulmaJS.toggleHtmlClipped()}})},l=e=>{e.preventDefault();const a=e.currentTarget.closest(".container--occupancyType").dataset.occupancyTypeId;cityssm.postJSON(c+"/admin/doMoveOccupancyTypeUp",{occupancyTypeId:a},e=>{e.success?(t=e.occupancyTypes,p()):bulmaJS.alert({title:"Error Moving "+exports.aliases.occupancy+" Type",message:e.errorMessage,contextualColorName:"danger"})})},i=e=>{e.preventDefault();const a=e.currentTarget.closest(".container--occupancyType").dataset.occupancyTypeId;cityssm.postJSON(c+"/admin/doMoveOccupancyTypeDown",{occupancyTypeId:a},e=>{e.success?(t=e.occupancyTypes,p()):bulmaJS.alert({title:"Error Moving "+exports.aliases.occupancy+" Type",message:e.errorMessage,contextualColorName:"danger"})})},p=()=>{if(0!==t.length){a.innerHTML="";for(const e of t){const c=document.createElement("div");if(c.className="panel container--occupancyType",c.dataset.occupancyTypeId=e.occupancyTypeId.toString(),c.innerHTML='

'+cityssm.escapeHTML(e.occupancyType)+'

',0===e.occupancyTypeFields.length)c.insertAdjacentHTML("beforeend",'

There are no additional fields.

');else for(const a of e.occupancyTypeFields){const t=document.createElement("div");t.className="panel-block is-block container--occupancyTypeField",s.has(e.occupancyTypeId)||t.classList.add("is-hidden"),t.dataset.occupancyTypeFieldId=a.occupancyTypeFieldId.toString(),t.innerHTML='
',c.append(t)}c.querySelector(".button--toggleOccupancyTypeFields").addEventListener("click",o),c.querySelector(".button--editOccupancyType").addEventListener("click",n),c.querySelector(".button--moveOccupancyTypeUp").addEventListener("click",l),c.querySelector(".button--moveOccupancyTypeDown").addEventListener("click",i),a.append(c)}}else a.innerHTML='
There are no active '+exports.aliases.occupancy.toLowerCase()+" types.

"};document.querySelector("#button--addOccupancyType").addEventListener("click",()=>{let a;const s=e=>{e.preventDefault(),cityssm.postJSON(c+"/admin/doAddOccupancyType",e.currentTarget,e=>{e.success?(a(),t=e.occupancyTypes,p()):bulmaJS.alert({title:"Error Adding "+exports.aliases.occupancy+" Type",message:e.errorMessage,contextualColorName:"danger"})})};cityssm.openHtmlModal("adminOccupancyTypes-addOccupancyType",{onshow:c=>{e.populateAliases(c)},onshown:(e,c)=>{a=c,e.querySelector("#occupancyTypeAdd--occupancyType").focus(),e.querySelector("form").addEventListener("submit",s),bulmaJS.toggleHtmlClipped()},onremoved:()=>{bulmaJS.toggleHtmlClipped()}})}),p()})(); \ No newline at end of file diff --git a/routes/admin.js b/routes/admin.js index 642e4a93..20cc8d87 100644 --- a/routes/admin.js +++ b/routes/admin.js @@ -13,6 +13,7 @@ import handler_doMoveFeeDown from "../handlers/admin-post/doMoveFeeDown.js"; import handler_doDeleteFee from "../handlers/admin-post/doDeleteFee.js"; import handler_occupancyTypes from "../handlers/admin-get/occupancyTypes.js"; import handler_doAddOccupancyType from "../handlers/admin-post/doAddOccupancyType.js"; +import handler_doUpdateOccupancyType from "../handlers/admin-post/doUpdateOccupancyType.js"; import handler_doMoveOccupancyTypeUp from "../handlers/admin-post/doMoveOccupancyTypeUp.js"; import handler_doMoveOccupancyTypeDown from "../handlers/admin-post/doMoveOccupancyTypeDown.js"; import handler_tables from "../handlers/admin-get/tables.js"; @@ -45,6 +46,7 @@ router.post("/doMoveFeeDown", permissionHandlers.adminPostHandler, handler_doMov router.post("/doDeleteFee", permissionHandlers.adminPostHandler, handler_doDeleteFee); router.get("/occupancyTypes", permissionHandlers.adminGetHandler, handler_occupancyTypes); router.post("/doAddOccupancyType", permissionHandlers.adminPostHandler, handler_doAddOccupancyType); +router.post("/doUpdateOccupancyType", permissionHandlers.adminPostHandler, handler_doUpdateOccupancyType); router.post("/doMoveOccupancyTypeUp", permissionHandlers.adminPostHandler, handler_doMoveOccupancyTypeUp); router.post("/doMoveOccupancyTypeDown", permissionHandlers.adminPostHandler, handler_doMoveOccupancyTypeDown); router.get("/tables", permissionHandlers.adminGetHandler, handler_tables); diff --git a/routes/admin.ts b/routes/admin.ts index 733c56fa..2f7271a8 100644 --- a/routes/admin.ts +++ b/routes/admin.ts @@ -23,6 +23,7 @@ import handler_doDeleteFee from "../handlers/admin-post/doDeleteFee.js"; import handler_occupancyTypes from "../handlers/admin-get/occupancyTypes.js"; import handler_doAddOccupancyType from "../handlers/admin-post/doAddOccupancyType.js"; +import handler_doUpdateOccupancyType from "../handlers/admin-post/doUpdateOccupancyType.js"; import handler_doMoveOccupancyTypeUp from "../handlers/admin-post/doMoveOccupancyTypeUp.js"; import handler_doMoveOccupancyTypeDown from "../handlers/admin-post/doMoveOccupancyTypeDown.js"; @@ -128,6 +129,12 @@ router.post( handler_doAddOccupancyType ); +router.post( + "/doUpdateOccupancyType", + permissionHandlers.adminPostHandler, + handler_doUpdateOccupancyType +); + router.post( "/doMoveOccupancyTypeUp", permissionHandlers.adminPostHandler,