diff --git a/data/config.defaultValues.js b/data/config.defaultValues.js index 1cf77d7b..c176db9a 100644 --- a/data/config.defaultValues.js +++ b/data/config.defaultValues.js @@ -3,7 +3,7 @@ export const configDefaultValues = { activeDirectory: undefined, 'application.applicationName': 'Sunrise CMS', 'application.backgroundURL': '/images/cemetery-background.jpg', - 'application.logoURL': '/images/cemetery-logo.png', + 'application.logoURL': '/images/sunrise-cms.png', 'application.httpPort': 7000, 'application.userDomain': '', 'application.useTestDatabases': false, diff --git a/data/config.defaultValues.ts b/data/config.defaultValues.ts index b990b70e..a4f83559 100644 --- a/data/config.defaultValues.ts +++ b/data/config.defaultValues.ts @@ -13,7 +13,7 @@ export const configDefaultValues = { 'application.applicationName': 'Sunrise CMS', 'application.backgroundURL': '/images/cemetery-background.jpg', - 'application.logoURL': '/images/cemetery-logo.png', + 'application.logoURL': '/images/sunrise-cms.png', 'application.httpPort': 7000, 'application.userDomain': '', 'application.useTestDatabases': false, diff --git a/database/addBurialSite.d.ts b/database/addBurialSite.d.ts index e01f6910..3e434f12 100644 --- a/database/addBurialSite.d.ts +++ b/database/addBurialSite.d.ts @@ -13,4 +13,4 @@ export interface AddBurialSiteForm { burialSiteTypeFieldIds?: string; [fieldValue_burialSiteTypeFieldId: string]: unknown; } -export default function addLot(burialSiteForm: AddBurialSiteForm, user: User): Promise; +export default function addBurialSite(burialSiteForm: AddBurialSiteForm, user: User): Promise; diff --git a/database/addBurialSite.js b/database/addBurialSite.js index 28f3eb62..11acfb84 100644 --- a/database/addBurialSite.js +++ b/database/addBurialSite.js @@ -1,7 +1,7 @@ import { buildBurialSiteName } from '../helpers/burialSites.helpers.js'; import addOrUpdateBurialSiteField from './addOrUpdateBurialSiteField.js'; import { acquireConnection } from './pool.js'; -export default async function addLot(burialSiteForm, user) { +export default async function addBurialSite(burialSiteForm, user) { const database = await acquireConnection(); const rightNowMillis = Date.now(); const burialSiteName = buildBurialSiteName(burialSiteForm); diff --git a/database/addBurialSite.ts b/database/addBurialSite.ts index ed85c4c4..d66f29ec 100644 --- a/database/addBurialSite.ts +++ b/database/addBurialSite.ts @@ -23,7 +23,7 @@ export interface AddBurialSiteForm { [fieldValue_burialSiteTypeFieldId: string]: unknown } -export default async function addLot( +export default async function addBurialSite( burialSiteForm: AddBurialSiteForm, user: User ): Promise { diff --git a/database/addBurialSiteContract.js b/database/addBurialSiteContract.js index 1ff5f145..079c8219 100644 --- a/database/addBurialSiteContract.js +++ b/database/addBurialSiteContract.js @@ -1,14 +1,10 @@ import { dateStringToInteger } from '@cityssm/utils-datetime'; -import addBurialSiteContractOccupant from './addBurialSiteContractOccupant.js'; import addOrUpdateBurialSiteContractField from './addOrUpdateBurialSiteContractField.js'; import { acquireConnection } from './pool.js'; export default async function addBurialSiteContract(addForm, user, connectedDatabase) { const database = connectedDatabase ?? (await acquireConnection()); const rightNowMillis = Date.now(); const contractStartDate = dateStringToInteger(addForm.contractStartDateString); - if (contractStartDate <= 0) { - console.error(addForm); - } const result = database .prepare(`insert into BurialSiteContracts ( contractTypeId, lotId, @@ -22,31 +18,15 @@ export default async function addBurialSiteContract(addForm, user, connectedData const burialSiteContractId = result.lastInsertRowid; const contractTypeFieldIds = (addForm.contractTypeFieldIds ?? '').split(','); for (const contractTypeFieldId of contractTypeFieldIds) { - const burialSiteContractFieldValue = addForm[`burialSiteContractFieldValue_${contractTypeFieldId}`]; - if ((burialSiteContractFieldValue ?? '') !== '') { + const fieldValue = addForm[`fieldValue_${contractTypeFieldId}`]; + if ((fieldValue ?? '') !== '') { await addOrUpdateBurialSiteContractField({ burialSiteContractId, contractTypeFieldId, - burialSiteContractFieldValue: burialSiteContractFieldValue ?? '' + fieldValue: fieldValue ?? '' }, user, database); } } - if ((addForm.lotOccupantTypeId ?? '') !== '') { - await addBurialSiteContractOccupant({ - burialSiteContractId, - lotOccupantTypeId: addForm.lotOccupantTypeId ?? '', - occupantName: addForm.occupantName ?? '', - occupantFamilyName: addForm.occupantFamilyName ?? '', - occupantAddress1: addForm.occupantAddress1 ?? '', - occupantAddress2: addForm.occupantAddress2 ?? '', - occupantCity: addForm.occupantCity ?? '', - occupantProvince: addForm.occupantProvince ?? '', - occupantPostalCode: addForm.occupantPostalCode ?? '', - occupantPhoneNumber: addForm.occupantPhoneNumber ?? '', - occupantEmailAddress: addForm.occupantEmailAddress ?? '', - occupantComment: addForm.occupantComment ?? '' - }, user, database); - } if (connectedDatabase === undefined) { database.release(); } diff --git a/database/addBurialSiteContract.ts b/database/addBurialSiteContract.ts index 1c85e497..73d0c5c5 100644 --- a/database/addBurialSiteContract.ts +++ b/database/addBurialSiteContract.ts @@ -1,7 +1,6 @@ import { type DateString, dateStringToInteger } from '@cityssm/utils-datetime' import type { PoolConnection } from 'better-sqlite-pool' -import addBurialSiteContractOccupant from './addBurialSiteContractOccupant.js' import addOrUpdateBurialSiteContractField from './addOrUpdateBurialSiteContractField.js' import { acquireConnection } from './pool.js' @@ -41,10 +40,6 @@ export default async function addBurialSiteContract( addForm.contractStartDateString as DateString ) - if (contractStartDate <= 0) { - console.error(addForm) - } - const result = database .prepare( `insert into BurialSiteContracts ( @@ -60,9 +55,7 @@ export default async function addBurialSiteContract( contractStartDate, addForm.contractEndDateString === '' ? undefined - : dateStringToInteger( - addForm.contractEndDateString as DateString - ), + : dateStringToInteger(addForm.contractEndDateString as DateString), user.userName, rightNowMillis, user.userName, @@ -71,21 +64,19 @@ export default async function addBurialSiteContract( const burialSiteContractId = result.lastInsertRowid as number - const contractTypeFieldIds = ( - addForm.contractTypeFieldIds ?? '' - ).split(',') + const contractTypeFieldIds = (addForm.contractTypeFieldIds ?? '').split(',') for (const contractTypeFieldId of contractTypeFieldIds) { - const burialSiteContractFieldValue = addForm[ - `burialSiteContractFieldValue_${contractTypeFieldId}` - ] as string | undefined + const fieldValue = addForm[`fieldValue_${contractTypeFieldId}`] as + | string + | undefined - if ((burialSiteContractFieldValue ?? '') !== '') { + if ((fieldValue ?? '') !== '') { await addOrUpdateBurialSiteContractField( { burialSiteContractId, contractTypeFieldId, - burialSiteContractFieldValue: burialSiteContractFieldValue ?? '' + fieldValue: fieldValue ?? '' }, user, database @@ -93,27 +84,6 @@ export default async function addBurialSiteContract( } } - if ((addForm.lotOccupantTypeId ?? '') !== '') { - await addBurialSiteContractOccupant( - { - burialSiteContractId, - lotOccupantTypeId: addForm.lotOccupantTypeId ?? '', - occupantName: addForm.occupantName ?? '', - occupantFamilyName: addForm.occupantFamilyName ?? '', - occupantAddress1: addForm.occupantAddress1 ?? '', - occupantAddress2: addForm.occupantAddress2 ?? '', - occupantCity: addForm.occupantCity ?? '', - occupantProvince: addForm.occupantProvince ?? '', - occupantPostalCode: addForm.occupantPostalCode ?? '', - occupantPhoneNumber: addForm.occupantPhoneNumber ?? '', - occupantEmailAddress: addForm.occupantEmailAddress ?? '', - occupantComment: addForm.occupantComment ?? '' - }, - user, - database - ) - } - if (connectedDatabase === undefined) { database.release() } diff --git a/database/addCemetery.d.ts b/database/addCemetery.d.ts index 50178e6c..008a545a 100644 --- a/database/addCemetery.d.ts +++ b/database/addCemetery.d.ts @@ -1,5 +1,6 @@ export interface AddCemeteryForm { cemeteryName: string; + cemeteryKey: string; cemeteryDescription: string; cemeterySvg: string; cemeteryLatitude: string; diff --git a/database/addCemetery.js b/database/addCemetery.js index 93ab4baa..315fd088 100644 --- a/database/addCemetery.js +++ b/database/addCemetery.js @@ -4,15 +4,15 @@ export default async function addCemetery(addForm, user) { const rightNowMillis = Date.now(); const result = database .prepare(`insert into Cemeteries ( - cemeteryName, cemeteryDescription, + cemeteryName, cemeteryKey, cemeteryDescription, cemeterySvg, cemeteryLatitude, cemeteryLongitude, cemeteryAddress1, cemeteryAddress2, cemeteryCity, cemeteryProvince, cemeteryPostalCode, cemeteryPhoneNumber, recordCreate_userName, recordCreate_timeMillis, recordUpdate_userName, recordUpdate_timeMillis) - values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`) - .run(addForm.cemeteryName, addForm.cemeteryDescription, addForm.cemeterySvg, addForm.cemeteryLatitude === '' ? undefined : addForm.cemeteryLatitude, addForm.cemeteryLongitude === '' ? undefined : addForm.cemeteryLongitude, addForm.cemeteryAddress1, addForm.cemeteryAddress2, addForm.cemeteryCity, addForm.cemeteryProvince, addForm.cemeteryPostalCode, addForm.cemeteryPhoneNumber, user.userName, rightNowMillis, user.userName, rightNowMillis); + values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`) + .run(addForm.cemeteryName, addForm.cemeteryKey, addForm.cemeteryDescription, addForm.cemeterySvg, addForm.cemeteryLatitude === '' ? undefined : addForm.cemeteryLatitude, addForm.cemeteryLongitude === '' ? undefined : addForm.cemeteryLongitude, addForm.cemeteryAddress1, addForm.cemeteryAddress2, addForm.cemeteryCity, addForm.cemeteryProvince, addForm.cemeteryPostalCode, addForm.cemeteryPhoneNumber, user.userName, rightNowMillis, user.userName, rightNowMillis); database.release(); return result.lastInsertRowid; } diff --git a/database/addCemetery.ts b/database/addCemetery.ts index 8d17271a..9388407b 100644 --- a/database/addCemetery.ts +++ b/database/addCemetery.ts @@ -2,6 +2,7 @@ import { acquireConnection } from './pool.js' export interface AddCemeteryForm { cemeteryName: string + cemeteryKey: string cemeteryDescription: string cemeterySvg: string @@ -27,17 +28,18 @@ export default async function addCemetery( const result = database .prepare( `insert into Cemeteries ( - cemeteryName, cemeteryDescription, + cemeteryName, cemeteryKey, cemeteryDescription, cemeterySvg, cemeteryLatitude, cemeteryLongitude, cemeteryAddress1, cemeteryAddress2, cemeteryCity, cemeteryProvince, cemeteryPostalCode, cemeteryPhoneNumber, recordCreate_userName, recordCreate_timeMillis, recordUpdate_userName, recordUpdate_timeMillis) - values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` + values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` ) .run( addForm.cemeteryName, + addForm.cemeteryKey, addForm.cemeteryDescription, addForm.cemeterySvg, addForm.cemeteryLatitude === '' ? undefined : addForm.cemeteryLatitude, diff --git a/database/addWorkOrderBurialSite.d.ts b/database/addWorkOrderBurialSite.d.ts index f48ba043..2f84e34b 100644 --- a/database/addWorkOrderBurialSite.d.ts +++ b/database/addWorkOrderBurialSite.d.ts @@ -2,4 +2,4 @@ export interface AddWorkOrderLotForm { workOrderId: number | string; burialSiteId: number | string; } -export default function addWorkOrderLot(workOrderLotForm: AddWorkOrderLotForm, user: User): Promise; +export default function addWorkOrderBurialSite(workOrderLotForm: AddWorkOrderLotForm, user: User): Promise; diff --git a/database/addWorkOrderBurialSite.js b/database/addWorkOrderBurialSite.js index 0d1c1796..c7ed6ec2 100644 --- a/database/addWorkOrderBurialSite.js +++ b/database/addWorkOrderBurialSite.js @@ -1,5 +1,5 @@ import { acquireConnection } from './pool.js'; -export default async function addWorkOrderLot(workOrderLotForm, user) { +export default async function addWorkOrderBurialSite(workOrderLotForm, user) { const database = await acquireConnection(); const rightNowMillis = Date.now(); const row = database diff --git a/database/addWorkOrderBurialSite.ts b/database/addWorkOrderBurialSite.ts index 72e11e10..72682563 100644 --- a/database/addWorkOrderBurialSite.ts +++ b/database/addWorkOrderBurialSite.ts @@ -5,7 +5,7 @@ export interface AddWorkOrderLotForm { burialSiteId: number | string } -export default async function addWorkOrderLot( +export default async function addWorkOrderBurialSite( workOrderLotForm: AddWorkOrderLotForm, user: User ): Promise { diff --git a/database/getCemetery.d.ts b/database/getCemetery.d.ts index 91c36727..83cfca22 100644 --- a/database/getCemetery.d.ts +++ b/database/getCemetery.d.ts @@ -1,2 +1,2 @@ import type { Cemetery } from '../types/recordTypes.js'; -export default function getMap(cemeteryId: number | string): Promise; +export default function getCemetery(cemeteryId: number | string): Promise; diff --git a/database/getCemetery.js b/database/getCemetery.js index 41c556b1..6712be9b 100644 --- a/database/getCemetery.js +++ b/database/getCemetery.js @@ -1,8 +1,8 @@ import { acquireConnection } from './pool.js'; -export default async function getMap(cemeteryId) { +export default async function getCemetery(cemeteryId) { const database = await acquireConnection(); const map = database - .prepare(`select m.cemeteryId, m.cemeteryName, m.cemeteryDescription, + .prepare(`select m.cemeteryId, m.cemeteryName, m.cemeteryKey, m.cemeteryDescription, m.cemeteryLatitude, m.cemeteryLongitude, m.cemeterySvg, m.cemeteryAddress1, m.cemeteryAddress2, m.cemeteryCity, m.cemeteryProvince, m.cemeteryPostalCode, m.cemeteryPhoneNumber, diff --git a/database/getCemetery.ts b/database/getCemetery.ts index 8790abec..1f7e0622 100644 --- a/database/getCemetery.ts +++ b/database/getCemetery.ts @@ -2,14 +2,14 @@ import type { Cemetery } from '../types/recordTypes.js' import { acquireConnection } from './pool.js' -export default async function getMap( +export default async function getCemetery( cemeteryId: number | string ): Promise { const database = await acquireConnection() const map = database .prepare( - `select m.cemeteryId, m.cemeteryName, m.cemeteryDescription, + `select m.cemeteryId, m.cemeteryName, m.cemeteryKey, m.cemeteryDescription, m.cemeteryLatitude, m.cemeteryLongitude, m.cemeterySvg, m.cemeteryAddress1, m.cemeteryAddress2, m.cemeteryCity, m.cemeteryProvince, m.cemeteryPostalCode, m.cemeteryPhoneNumber, diff --git a/database/initializeDatabase.js b/database/initializeDatabase.js index a9e4afd2..28a9c152 100644 --- a/database/initializeDatabase.js +++ b/database/initializeDatabase.js @@ -23,7 +23,7 @@ const createStatements = [ orderNumber smallint not null default 0, ${recordColumns})`, `create index if not exists idx_BurialSiteTypes_orderNumber - on LotTypes (orderNumber, burialSiteType)`, + on BurialSiteTypes (orderNumber, burialSiteType)`, `create table if not exists BurialSiteTypeFields ( burialSiteTypeFieldId integer not null primary key autoincrement, burialSiteTypeId integer not null, @@ -110,7 +110,7 @@ const createStatements = [ commentTime integer not null check (commentTime >= 0), comment text not null, ${recordColumns}, - foreign key (lotId) references BurialSites (burialSiteId))`, + foreign key (burialSiteId) references BurialSites (burialSiteId))`, `create index if not exists idx_BurialSiteComments_datetime on BurialSiteComments (burialSiteId, commentDate, commentTime)`, /* @@ -221,9 +221,9 @@ const createStatements = [ `create table if not exists BurialSiteContractInterments ( burialSiteContractId integer not null, intermentNumber integer not null, - isCremated bit not null default 0, - + deceasedName varchar(50) not null, + isCremated bit not null default 0, birthDate integer, birthPlace varchar(100), @@ -239,7 +239,7 @@ const createStatements = [ ${recordColumns}, primary key (burialSiteContractId, intermentNumber), - foreign key (burialSiteId) references BurialSites (burialSiteId), + foreign key (burialSiteContractId) references BurialSiteContracts (burialSiteContractId), foreign key (intermentContainerTypeId) references IntermentContainerTypes (intermentContainerTypeId), foreign key (intermentCommittalTypeId) references IntermentCommittalTypes (intermentCommittalTypeId)) without rowid`, /* diff --git a/database/initializeDatabase.ts b/database/initializeDatabase.ts index 3c0a6fa7..741fdb5b 100644 --- a/database/initializeDatabase.ts +++ b/database/initializeDatabase.ts @@ -31,7 +31,7 @@ const createStatements = [ ${recordColumns})`, `create index if not exists idx_BurialSiteTypes_orderNumber - on LotTypes (orderNumber, burialSiteType)`, + on BurialSiteTypes (orderNumber, burialSiteType)`, `create table if not exists BurialSiteTypeFields ( burialSiteTypeFieldId integer not null primary key autoincrement, @@ -129,7 +129,7 @@ const createStatements = [ commentTime integer not null check (commentTime >= 0), comment text not null, ${recordColumns}, - foreign key (lotId) references BurialSites (burialSiteId))`, + foreign key (burialSiteId) references BurialSites (burialSiteId))`, `create index if not exists idx_BurialSiteComments_datetime on BurialSiteComments (burialSiteId, commentDate, commentTime)`, @@ -260,9 +260,9 @@ const createStatements = [ `create table if not exists BurialSiteContractInterments ( burialSiteContractId integer not null, intermentNumber integer not null, - isCremated bit not null default 0, - + deceasedName varchar(50) not null, + isCremated bit not null default 0, birthDate integer, birthPlace varchar(100), @@ -278,7 +278,7 @@ const createStatements = [ ${recordColumns}, primary key (burialSiteContractId, intermentNumber), - foreign key (burialSiteId) references BurialSites (burialSiteId), + foreign key (burialSiteContractId) references BurialSiteContracts (burialSiteContractId), foreign key (intermentContainerTypeId) references IntermentContainerTypes (intermentContainerTypeId), foreign key (intermentCommittalTypeId) references IntermentCommittalTypes (intermentCommittalTypeId)) without rowid`, diff --git a/database/updateCemetery.d.ts b/database/updateCemetery.d.ts index 0b67f27f..c4c03f9b 100644 --- a/database/updateCemetery.d.ts +++ b/database/updateCemetery.d.ts @@ -1,6 +1,7 @@ export interface UpdateCemeteryForm { cemeteryId: string; cemeteryName: string; + cemeteryKey: string; cemeteryDescription: string; cemeterySvg: string; cemeteryLatitude: string; diff --git a/database/updateCemetery.js b/database/updateCemetery.js index 41845aec..b309a02e 100644 --- a/database/updateCemetery.js +++ b/database/updateCemetery.js @@ -2,23 +2,28 @@ import { acquireConnection } from './pool.js'; export default async function updateCemetery(updateForm, user) { const database = await acquireConnection(); const result = database - .prepare(`update Maps + .prepare(`update Cemeteries set cemeteryName = ?, - mapDescription = ?, - mapSVG = ?, - mapLatitude = ?, - mapLongitude = ?, - mapAddress1 = ?, - mapAddress2 = ?, - mapCity = ?, - mapProvince = ?, - mapPostalCode = ?, - mapPhoneNumber = ?, + cemeteryKey = ?, + cemeteryDescription = ?, + cemeterySvg = ?, + cemeteryLatitude = ?, + cemeteryLongitude = ?, + cemeteryAddress1 = ?, + cemeteryAddress2 = ?, + cemeteryCity = ?, + cemeteryProvince = ?, + cemeteryPostalCode = ?, + cemeteryPhoneNumber = ?, recordUpdate_userName = ?, recordUpdate_timeMillis = ? where cemeteryId = ? and recordDelete_timeMillis is null`) - .run(updateForm.cemeteryName, updateForm.cemeteryDescription, updateForm.cemeterySvg, updateForm.cemeteryLatitude === '' ? undefined : updateForm.cemeteryLatitude, updateForm.cemeteryLongitude === '' ? undefined : updateForm.cemeteryLongitude, updateForm.cemeteryAddress1, updateForm.cemeteryAddress2, updateForm.cemeteryCity, updateForm.cemeteryProvince, updateForm.cemeteryPostalCode, updateForm.cemeteryPhoneNumber, user.userName, Date.now(), updateForm.cemeteryId); + .run(updateForm.cemeteryName, updateForm.cemeteryKey, updateForm.cemeteryDescription, updateForm.cemeterySvg, updateForm.cemeteryLatitude === '' + ? undefined + : updateForm.cemeteryLatitude, updateForm.cemeteryLongitude === '' + ? undefined + : updateForm.cemeteryLongitude, updateForm.cemeteryAddress1, updateForm.cemeteryAddress2, updateForm.cemeteryCity, updateForm.cemeteryProvince, updateForm.cemeteryPostalCode, updateForm.cemeteryPhoneNumber, user.userName, Date.now(), updateForm.cemeteryId); database.release(); return result.changes > 0; } diff --git a/database/updateCemetery.ts b/database/updateCemetery.ts index a1ca213a..424b76d9 100644 --- a/database/updateCemetery.ts +++ b/database/updateCemetery.ts @@ -3,6 +3,7 @@ import { acquireConnection } from './pool.js' export interface UpdateCemeteryForm { cemeteryId: string cemeteryName: string + cemeteryKey: string cemeteryDescription: string cemeterySvg: string cemeteryLatitude: string @@ -23,18 +24,19 @@ export default async function updateCemetery( const result = database .prepare( - `update Maps + `update Cemeteries set cemeteryName = ?, - mapDescription = ?, - mapSVG = ?, - mapLatitude = ?, - mapLongitude = ?, - mapAddress1 = ?, - mapAddress2 = ?, - mapCity = ?, - mapProvince = ?, - mapPostalCode = ?, - mapPhoneNumber = ?, + cemeteryKey = ?, + cemeteryDescription = ?, + cemeterySvg = ?, + cemeteryLatitude = ?, + cemeteryLongitude = ?, + cemeteryAddress1 = ?, + cemeteryAddress2 = ?, + cemeteryCity = ?, + cemeteryProvince = ?, + cemeteryPostalCode = ?, + cemeteryPhoneNumber = ?, recordUpdate_userName = ?, recordUpdate_timeMillis = ? where cemeteryId = ? @@ -42,10 +44,15 @@ export default async function updateCemetery( ) .run( updateForm.cemeteryName, + updateForm.cemeteryKey, updateForm.cemeteryDescription, updateForm.cemeterySvg, - updateForm.cemeteryLatitude === '' ? undefined : updateForm.cemeteryLatitude, - updateForm.cemeteryLongitude === '' ? undefined : updateForm.cemeteryLongitude, + updateForm.cemeteryLatitude === '' + ? undefined + : updateForm.cemeteryLatitude, + updateForm.cemeteryLongitude === '' + ? undefined + : updateForm.cemeteryLongitude, updateForm.cemeteryAddress1, updateForm.cemeteryAddress2, updateForm.cemeteryCity, diff --git a/helpers/burialSites.helpers.js b/helpers/burialSites.helpers.js index e0cd50a8..c770ce01 100644 --- a/helpers/burialSites.helpers.js +++ b/helpers/burialSites.helpers.js @@ -5,7 +5,7 @@ import { minutesToSeconds } from '@cityssm/to-millis'; import Debug from 'debug'; import NodeCache from 'node-cache'; import getNextBurialSiteIdFromDatabase from '../database/getNextBurialSiteId.js'; -import getPreviousLotIdFromDatabase from '../database/getPreviousLotId.js'; +import getPreviousBurialSiteIdFromDatabase from '../database/getPreviousBurialSiteId.js'; import { DEBUG_NAMESPACE } from '../debug.config.js'; import { getConfigProperty } from './config.helpers.js'; const debug = Debug(`${DEBUG_NAMESPACE}:burialSites.helpers:${process.pid}`); @@ -46,7 +46,7 @@ export async function getNextBurialSiteId(burialSiteId) { export async function getPreviousBurialSiteId(burialSiteId) { let previousBurialSiteId = previousBurialSiteIdCache.get(burialSiteId); if (previousBurialSiteId === undefined) { - previousBurialSiteId = await getPreviousLotIdFromDatabase(burialSiteId); + previousBurialSiteId = await getPreviousBurialSiteIdFromDatabase(burialSiteId); if (previousBurialSiteId !== undefined) { cacheBurialSiteIds(previousBurialSiteId, burialSiteId); } diff --git a/helpers/burialSites.helpers.ts b/helpers/burialSites.helpers.ts index 7bedf1a5..9ad438fc 100644 --- a/helpers/burialSites.helpers.ts +++ b/helpers/burialSites.helpers.ts @@ -8,7 +8,7 @@ import Debug from 'debug' import NodeCache from 'node-cache' import getNextBurialSiteIdFromDatabase from '../database/getNextBurialSiteId.js' -import getPreviousLotIdFromDatabase from '../database/getPreviousLotId.js' +import getPreviousBurialSiteIdFromDatabase from '../database/getPreviousBurialSiteId.js' import { DEBUG_NAMESPACE } from '../debug.config.js' import type { CacheBurialSiteIdsWorkerMessage, @@ -79,7 +79,7 @@ export async function getPreviousBurialSiteId( previousBurialSiteIdCache.get(burialSiteId) if (previousBurialSiteId === undefined) { - previousBurialSiteId = await getPreviousLotIdFromDatabase(burialSiteId) + previousBurialSiteId = await getPreviousBurialSiteIdFromDatabase(burialSiteId) if (previousBurialSiteId !== undefined) { cacheBurialSiteIds(previousBurialSiteId, burialSiteId) diff --git a/helpers/functions.authentication.js b/helpers/functions.authentication.js index f3d6ae14..62bde639 100644 --- a/helpers/functions.authentication.js +++ b/helpers/functions.authentication.js @@ -29,15 +29,15 @@ export async function authenticate(userName, password) { const safeRedirects = new Set([ '/admin/cleanup', '/admin/fees', - '/admin/lottypes', - '/admin/occupancytypes', + '/admin/burialsitetypes', + '/admin/contracttypes', '/admin/tables', - '/lotoccupancies', + '/contracts', '/contracts/new', - '/lots', - '/lots/new', - '/maps', - '/maps/new', + '/burialSites', + '/burialSites/new', + '/cemeteries', + '/cemeteries/new', '/workorders', '/workorders/new', '/workorders/milestonecalendar', @@ -45,7 +45,7 @@ const safeRedirects = new Set([ '/reports' ]); /* eslint-enable @cspell/spellchecker */ -const recordUrl = /^\/(?:maps|lots|lotoccupancies|workorders)\/\d+(?:\/edit)?$/; +const recordUrl = /^\/(?:cemeteries|burialSites|contracts|workorders)\/\d+(?:\/edit)?$/; const printUrl = /^\/print\/(?:pdf|screen)\/[\d/=?A-Za-z-]+$/; export function getSafeRedirectURL(possibleRedirectURL = '') { const urlPrefix = getConfigProperty('reverseProxy.urlPrefix'); diff --git a/helpers/functions.authentication.ts b/helpers/functions.authentication.ts index 24ceb9c7..6e82974d 100644 --- a/helpers/functions.authentication.ts +++ b/helpers/functions.authentication.ts @@ -45,15 +45,15 @@ export async function authenticate( const safeRedirects = new Set([ '/admin/cleanup', '/admin/fees', - '/admin/lottypes', - '/admin/occupancytypes', + '/admin/burialsitetypes', + '/admin/contracttypes', '/admin/tables', - '/lotoccupancies', + '/contracts', '/contracts/new', - '/lots', - '/lots/new', - '/maps', - '/maps/new', + '/burialSites', + '/burialSites/new', + '/cemeteries', + '/cemeteries/new', '/workorders', '/workorders/new', '/workorders/milestonecalendar', @@ -63,7 +63,7 @@ const safeRedirects = new Set([ /* eslint-enable @cspell/spellchecker */ -const recordUrl = /^\/(?:maps|lots|lotoccupancies|workorders)\/\d+(?:\/edit)?$/ +const recordUrl = /^\/(?:cemeteries|burialSites|contracts|workorders)\/\d+(?:\/edit)?$/ const printUrl = /^\/print\/(?:pdf|screen)\/[\d/=?A-Za-z-]+$/ diff --git a/helpers/functions.cache.d.ts b/helpers/functions.cache.d.ts index e03d2586..46667cb3 100644 --- a/helpers/functions.cache.d.ts +++ b/helpers/functions.cache.d.ts @@ -17,6 +17,6 @@ export declare function getWorkOrderMilestoneTypeById(workOrderMilestoneTypeId: export declare function getWorkOrderMilestoneTypeByWorkOrderMilestoneType(workOrderMilestoneTypeString: string): Promise; export declare function preloadCaches(): Promise; export declare function clearCaches(): void; -type CacheTableNames = 'BurialSiteStatuses' | 'BurialSiteTypes' | 'BurialSiteTypeFields' | 'ContractTypes' | 'ContractTypeFields' | 'ContractTypePrints' | 'WorkOrderMilestoneTypes' | 'WorkOrderTypes'; +type CacheTableNames = 'BurialSiteStatuses' | 'BurialSiteTypes' | 'BurialSiteTypeFields' | 'ContractTypes' | 'ContractTypeFields' | 'ContractTypePrints' | 'WorkOrderMilestoneTypes' | 'WorkOrderTypes' | 'FeeCategories'; export declare function clearCacheByTableName(tableName: CacheTableNames, relayMessage?: boolean): void; export {}; diff --git a/helpers/functions.cache.js b/helpers/functions.cache.js index 4683897d..bab645eb 100644 --- a/helpers/functions.cache.js +++ b/helpers/functions.cache.js @@ -177,7 +177,6 @@ export function clearCacheByTableName(tableName, relayMessage = true) { clearWorkOrderTypesCache(); break; } - // eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check default: { return; } diff --git a/helpers/functions.cache.ts b/helpers/functions.cache.ts index 9ff0c8da..08900004 100644 --- a/helpers/functions.cache.ts +++ b/helpers/functions.cache.ts @@ -280,6 +280,7 @@ type CacheTableNames = | 'ContractTypePrints' | 'WorkOrderMilestoneTypes' | 'WorkOrderTypes' + | 'FeeCategories' export function clearCacheByTableName( tableName: CacheTableNames, @@ -314,7 +315,6 @@ export function clearCacheByTableName( break } - // eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check default: { return } diff --git a/helpers/functions.print.js b/helpers/functions.print.js index 0108044e..d7300f07 100644 --- a/helpers/functions.print.js +++ b/helpers/functions.print.js @@ -1,3 +1,5 @@ +// eslint-disable-next-line @eslint-community/eslint-comments/disable-enable-pair +/* eslint-disable security/detect-object-injection */ import * as dateTimeFunctions from '@cityssm/utils-datetime'; import getBurialSite from '../database/getBurialSite.js'; import getBurialSiteContract from '../database/getBurialSiteContract.js'; diff --git a/helpers/functions.print.ts b/helpers/functions.print.ts index bbce6ea2..d2baf2d7 100644 --- a/helpers/functions.print.ts +++ b/helpers/functions.print.ts @@ -1,3 +1,6 @@ +// eslint-disable-next-line @eslint-community/eslint-comments/disable-enable-pair +/* eslint-disable security/detect-object-injection */ + import * as dateTimeFunctions from '@cityssm/utils-datetime' import getBurialSite from '../database/getBurialSite.js' diff --git a/public/images/cemetery-logo.svg b/public/images/cemetery-logo.svg deleted file mode 100644 index a398f291..00000000 --- a/public/images/cemetery-logo.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/images/sunrise-cms.png b/public/images/sunrise-cms.png new file mode 100644 index 00000000..c2325259 Binary files /dev/null and b/public/images/sunrise-cms.png differ diff --git a/public/javascripts/burialSite.edit.d.ts b/public/javascripts/burialSite.edit.d.ts new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/public/javascripts/burialSite.edit.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/public/javascripts/burialSite.edit.js b/public/javascripts/burialSite.edit.js new file mode 100644 index 00000000..c82a997a --- /dev/null +++ b/public/javascripts/burialSite.edit.js @@ -0,0 +1,367 @@ +"use strict"; +// eslint-disable-next-line @eslint-community/eslint-comments/disable-enable-pair +/* eslint-disable unicorn/prefer-module */ +Object.defineProperty(exports, "__esModule", { value: true }); +(() => { + const los = exports.los; + const lotId = document.querySelector('#lot--lotId') + .value; + const isCreate = lotId === ''; + // Main form + let refreshAfterSave = isCreate; + function setUnsavedChanges() { + los.setUnsavedChanges(); + document + .querySelector("button[type='submit'][form='form--lot']") + ?.classList.remove('is-light'); + } + function clearUnsavedChanges() { + los.clearUnsavedChanges(); + document + .querySelector("button[type='submit'][form='form--lot']") + ?.classList.add('is-light'); + } + const formElement = document.querySelector('#form--lot'); + function updateBurialSite(formEvent) { + formEvent.preventDefault(); + cityssm.postJSON(`${los.urlPrefix}/lots/${isCreate ? 'doCreateBurialSite' : 'doUpdateBurialSite'}`, formElement, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + clearUnsavedChanges(); + if (isCreate || refreshAfterSave) { + window.location.href = los.getBurialSiteURL(responseJSON.lotId, true, true); + } + else { + bulmaJS.alert({ + message: `${los.escapedAliases.Lot} Updated Successfully`, + contextualColorName: 'success' + }); + } + } + else { + bulmaJS.alert({ + title: `Error Updating ${los.escapedAliases.Lot}`, + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + }); + } + formElement.addEventListener('submit', updateBurialSite); + const formInputElements = formElement.querySelectorAll('input, select'); + for (const formInputElement of formInputElements) { + formInputElement.addEventListener('change', setUnsavedChanges); + } + los.initializeUnlockFieldButtons(formElement); + document + .querySelector('#button--deleteLot') + ?.addEventListener('click', (clickEvent) => { + clickEvent.preventDefault(); + function doDelete() { + cityssm.postJSON(`${los.urlPrefix}/lots/doDeleteBurialSite`, { + lotId + }, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + clearUnsavedChanges(); + window.location.href = los.getBurialSiteURL(); + } + else { + bulmaJS.alert({ + title: `Error Deleting ${los.escapedAliases.Lot}`, + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + }); + } + bulmaJS.confirm({ + title: `Delete ${los.escapedAliases.Lot}`, + message: `Are you sure you want to delete this ${los.escapedAliases.lot}?`, + contextualColorName: 'warning', + okButton: { + text: `Yes, Delete ${los.escapedAliases.Lot}`, + callbackFunction: doDelete + } + }); + }); + // Lot Type + const burialSiteTypeIdElement = document.querySelector('#lot--burialSiteTypeId'); + if (isCreate) { + const lotFieldsContainerElement = document.querySelector('#container--lotFields'); + burialSiteTypeIdElement.addEventListener('change', () => { + if (burialSiteTypeIdElement.value === '') { + // eslint-disable-next-line no-unsanitized/property + lotFieldsContainerElement.innerHTML = `
+

Select the ${los.escapedAliases.lot} type to load the available fields.

+
`; + return; + } + cityssm.postJSON(`${los.urlPrefix}/lots/doGetBurialSiteTypeFields`, { + burialSiteTypeId: burialSiteTypeIdElement.value + }, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.BurialSiteTypeFields.length === 0) { + // eslint-disable-next-line no-unsanitized/property + lotFieldsContainerElement.innerHTML = `
+

+ There are no additional fields for this ${los.escapedAliases.lot} type. +

+
`; + return; + } + lotFieldsContainerElement.innerHTML = ''; + let lotTypeFieldIds = ''; + for (const lotTypeField of responseJSON.BurialSiteTypeFields) { + lotTypeFieldIds += `,${lotTypeField.lotTypeFieldId.toString()}`; + const fieldName = `lotFieldValue_${lotTypeField.lotTypeFieldId.toString()}`; + const fieldId = `lot--${fieldName}`; + const fieldElement = document.createElement('div'); + fieldElement.className = 'field'; + // eslint-disable-next-line no-unsanitized/property + fieldElement.innerHTML = ` +
`; + fieldElement.querySelector('label').textContent = lotTypeField.lotTypeField; + if (lotTypeField.lotTypeFieldValues === '') { + const inputElement = document.createElement('input'); + inputElement.className = 'input'; + inputElement.id = fieldId; + inputElement.name = fieldName; + inputElement.type = 'text'; + inputElement.required = lotTypeField.isRequired; + inputElement.minLength = lotTypeField.minimumLength; + inputElement.maxLength = lotTypeField.maximumLength; + if ((lotTypeField.pattern ?? '') !== '') { + inputElement.pattern = lotTypeField.pattern ?? ''; + } + fieldElement.querySelector('.control')?.append(inputElement); + } + else { + // eslint-disable-next-line no-unsanitized/property + ; + fieldElement.querySelector('.control').innerHTML = `
+ +
`; + const selectElement = fieldElement.querySelector('select'); + selectElement.required = lotTypeField.isRequired; + const optionValues = lotTypeField.lotTypeFieldValues.split('\n'); + for (const optionValue of optionValues) { + const optionElement = document.createElement('option'); + optionElement.value = optionValue; + optionElement.textContent = optionValue; + selectElement.append(optionElement); + } + } + lotFieldsContainerElement.append(fieldElement); + } + lotFieldsContainerElement.insertAdjacentHTML('beforeend', ``); + }); + }); + } + else { + const originalburialSiteTypeId = burialSiteTypeIdElement.value; + burialSiteTypeIdElement.addEventListener('change', () => { + if (burialSiteTypeIdElement.value !== originalburialSiteTypeId) { + bulmaJS.confirm({ + title: 'Confirm Change', + message: `Are you sure you want to change the ${los.escapedAliases.lot} type?\n + This change affects the additional fields associated with this record.`, + contextualColorName: 'warning', + okButton: { + text: 'Yes, Keep the Change', + callbackFunction() { + refreshAfterSave = true; + } + }, + cancelButton: { + text: 'Revert the Change', + callbackFunction() { + burialSiteTypeIdElement.value = originalburialSiteTypeId; + } + } + }); + } + }); + } + // Comments + let lotComments = exports.lotComments; + delete exports.lotComments; + function openEditLotComment(clickEvent) { + const lotCommentId = Number.parseInt(clickEvent.currentTarget.closest('tr')?.dataset + .lotCommentId ?? '', 10); + const lotComment = lotComments.find((currentLotComment) => { + return currentLotComment.lotCommentId === lotCommentId; + }); + let editFormElement; + let editCloseModalFunction; + function editComment(submitEvent) { + submitEvent.preventDefault(); + cityssm.postJSON(`${los.urlPrefix}/lots/doUpdateBurialSiteComment`, editFormElement, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + lotComments = responseJSON.lotComments; + editCloseModalFunction(); + renderLotComments(); + } + else { + bulmaJS.alert({ + title: 'Error Updating Comment', + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + }); + } + cityssm.openHtmlModal('lot-editComment', { + onshow(modalElement) { + los.populateAliases(modalElement); + modalElement.querySelector('#lotCommentEdit--lotId').value = lotId; + modalElement.querySelector('#lotCommentEdit--lotCommentId').value = lotCommentId.toString(); + modalElement.querySelector('#lotCommentEdit--lotComment').value = lotComment.lotComment ?? ''; + const lotCommentDateStringElement = modalElement.querySelector('#lotCommentEdit--lotCommentDateString'); + lotCommentDateStringElement.value = + lotComment.lotCommentDateString ?? ''; + const currentDateString = cityssm.dateToString(new Date()); + lotCommentDateStringElement.max = + lotComment.lotCommentDateString <= currentDateString + ? currentDateString + : lotComment.lotCommentDateString ?? ''; + modalElement.querySelector('#lotCommentEdit--lotCommentTimeString').value = lotComment.lotCommentTimeString ?? ''; + }, + onshown(modalElement, closeModalFunction) { + bulmaJS.toggleHtmlClipped(); + los.initializeDatePickers(modalElement); + modalElement.querySelector('#lotCommentEdit--lotComment').focus(); + editFormElement = modalElement.querySelector('form'); + editFormElement.addEventListener('submit', editComment); + editCloseModalFunction = closeModalFunction; + }, + onremoved() { + bulmaJS.toggleHtmlClipped(); + } + }); + } + function deleteLotComment(clickEvent) { + const lotCommentId = Number.parseInt(clickEvent.currentTarget.closest('tr')?.dataset + .lotCommentId ?? '', 10); + function doDelete() { + cityssm.postJSON(`${los.urlPrefix}/lots/doDeleteBurialSiteComment`, { + lotId, + lotCommentId + }, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + lotComments = responseJSON.lotComments; + renderLotComments(); + } + else { + bulmaJS.alert({ + title: 'Error Removing Comment', + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + }); + } + bulmaJS.confirm({ + title: 'Remove Comment?', + message: 'Are you sure you want to remove this comment?', + okButton: { + text: 'Yes, Remove Comment', + callbackFunction: doDelete + }, + contextualColorName: 'warning' + }); + } + function renderLotComments() { + const containerElement = document.querySelector('#container--lotComments'); + if (lotComments.length === 0) { + containerElement.innerHTML = `
+

There are no comments to display.

+
`; + return; + } + const tableElement = document.createElement('table'); + tableElement.className = 'table is-fullwidth is-striped is-hoverable'; + tableElement.innerHTML = ` + Commentor + Comment Date + Comment + Options + + `; + for (const lotComment of lotComments) { + const tableRowElement = document.createElement('tr'); + tableRowElement.dataset.lotCommentId = lotComment.lotCommentId?.toString(); + // eslint-disable-next-line no-unsanitized/property + tableRowElement.innerHTML = ` + ${cityssm.escapeHTML(lotComment.recordCreate_userName ?? '')} + + ${lotComment.lotCommentDateString} + ${lotComment.lotCommentTime === 0 + ? '' + : ` ${lotComment.lotCommentTimePeriodString}`} + + ${cityssm.escapeHTML(lotComment.lotComment ?? '')} + +
+ + +
+ `; + tableRowElement + .querySelector('.button--edit') + ?.addEventListener('click', openEditLotComment); + tableRowElement + .querySelector('.button--delete') + ?.addEventListener('click', deleteLotComment); + tableElement.querySelector('tbody')?.append(tableRowElement); + } + containerElement.innerHTML = ''; + containerElement.append(tableElement); + } + function openAddCommentModal() { + let addCommentCloseModalFunction; + function doAddComment(formEvent) { + formEvent.preventDefault(); + cityssm.postJSON(`${los.urlPrefix}/lots/doAddBurialSiteComment`, formEvent.currentTarget, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + lotComments = responseJSON.lotComments; + renderLotComments(); + addCommentCloseModalFunction(); + } + }); + } + cityssm.openHtmlModal('lot-addComment', { + onshow(modalElement) { + los.populateAliases(modalElement); + modalElement.querySelector('#lotCommentAdd--lotId').value = lotId; + modalElement + .querySelector('form') + ?.addEventListener('submit', doAddComment); + }, + onshown(modalElement, closeModalFunction) { + bulmaJS.toggleHtmlClipped(); + addCommentCloseModalFunction = closeModalFunction; + modalElement.querySelector('#lotCommentAdd--lotComment').focus(); + }, + onremoved() { + bulmaJS.toggleHtmlClipped(); + document.querySelector('#lotComments--add').focus(); + } + }); + } + if (!isCreate) { + document + .querySelector('#lotComments--add') + ?.addEventListener('click', openAddCommentModal); + renderLotComments(); + } +})(); diff --git a/public/javascripts/burialSite.edit.ts b/public/javascripts/burialSite.edit.ts index c8561d86..f2ca2763 100644 --- a/public/javascripts/burialSite.edit.ts +++ b/public/javascripts/burialSite.edit.ts @@ -55,7 +55,7 @@ declare const exports: Record clearUnsavedChanges() if (isCreate || refreshAfterSave) { - window.location.href = los.getLotURL(responseJSON.lotId, true, true) + window.location.href = los.getBurialSiteURL(responseJSON.lotId, true, true) } else { bulmaJS.alert({ message: `${los.escapedAliases.Lot} Updated Successfully`, @@ -102,7 +102,7 @@ declare const exports: Record if (responseJSON.success) { clearUnsavedChanges() - window.location.href = los.getLotURL() + window.location.href = los.getBurialSiteURL() } else { bulmaJS.alert({ title: `Error Deleting ${los.escapedAliases.Lot}`, diff --git a/public/javascripts/burialSite.search.d.ts b/public/javascripts/burialSite.search.d.ts new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/public/javascripts/burialSite.search.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/public/javascripts/burialSite.search.js b/public/javascripts/burialSite.search.js index ecbc4be6..c1390029 100644 --- a/public/javascripts/burialSite.search.js +++ b/public/javascripts/burialSite.search.js @@ -20,13 +20,13 @@ Object.defineProperty(exports, "__esModule", { value: true }); // eslint-disable-next-line no-unsanitized/method resultsTbodyElement.insertAdjacentHTML('beforeend', ` - + ${cityssm.escapeHTML(lot.lotName ?? '')} - - ${lot.mapName - ? cityssm.escapeHTML(lot.mapName) + + ${lot.cemeteryName + ? cityssm.escapeHTML(lot.cemeteryName) : '(No Name)'} @@ -35,7 +35,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); ${lot.burialSiteStatusId ? cityssm.escapeHTML(lot.lotStatus ?? '') : '(No Status)'}
- ${(lot.lotOccupancyCount ?? 0) > 0 + ${(lot.burialSiteContractCount ?? 0) > 0 ? 'Currently Occupied' : ''} @@ -62,22 +62,22 @@ Object.defineProperty(exports, "__esModule", { value: true }); .querySelector("button[data-page='next']") ?.addEventListener('click', nextAndGetLots); } - function getLots() { + function getBurialSites() { // eslint-disable-next-line no-unsanitized/property searchResultsContainerElement.innerHTML = los.getLoadingParagraphHTML(`Loading ${los.escapedAliases.Lots}...`); - cityssm.postJSON(`${los.urlPrefix}/lots/doSearchLots`, searchFilterFormElement, renderLots); + cityssm.postJSON(`${los.urlPrefix}/lots/doSearchBurialSites`, searchFilterFormElement, renderLots); } function resetOffsetAndGetLots() { offsetElement.value = '0'; - getLots(); + getBurialSites(); } function previousAndGetLots() { offsetElement.value = Math.max(Number.parseInt(offsetElement.value, 10) - limit, 0).toString(); - getLots(); + getBurialSites(); } function nextAndGetLots() { offsetElement.value = (Number.parseInt(offsetElement.value, 10) + limit).toString(); - getLots(); + getBurialSites(); } const filterElements = searchFilterFormElement.querySelectorAll('input, select'); for (const filterElement of filterElements) { @@ -86,5 +86,5 @@ Object.defineProperty(exports, "__esModule", { value: true }); searchFilterFormElement.addEventListener('submit', (formEvent) => { formEvent.preventDefault(); }); - getLots(); + getBurialSites(); })(); diff --git a/public/javascripts/burialSite.search.ts b/public/javascripts/burialSite.search.ts index 323db3b0..c13bee25 100644 --- a/public/javascripts/burialSite.search.ts +++ b/public/javascripts/burialSite.search.ts @@ -49,11 +49,11 @@ declare const exports: Record 'beforeend', ` - + ${cityssm.escapeHTML(lot.lotName ?? '')} - + ${ lot.cemeteryName ? cityssm.escapeHTML(lot.cemeteryName) diff --git a/public/javascripts/burialSite.view.d.ts b/public/javascripts/burialSite.view.d.ts new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/public/javascripts/burialSite.view.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/public/javascripts/burialSite.view.js b/public/javascripts/burialSite.view.js new file mode 100644 index 00000000..b5a2727d --- /dev/null +++ b/public/javascripts/burialSite.view.js @@ -0,0 +1,9 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +(() => { + const mapContainerElement = document.querySelector('#lot--map'); + if (mapContainerElement !== null) { + ; + exports.los.highlightMap(mapContainerElement, mapContainerElement.dataset.mapKey ?? '', 'success'); + } +})(); diff --git a/public/javascripts/burialSiteContract.edit.d.ts b/public/javascripts/burialSiteContract.edit.d.ts new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/public/javascripts/burialSiteContract.edit.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/public/javascripts/burialSiteContract.edit.js b/public/javascripts/burialSiteContract.edit.js new file mode 100644 index 00000000..c321572c --- /dev/null +++ b/public/javascripts/burialSiteContract.edit.js @@ -0,0 +1,1735 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +(() => { + const los = exports.los; + const burialSiteContractId = document.querySelector('#burialSiteContract--burialSiteContractId').value; + const isCreate = burialSiteContractId === ''; + /* + * Main form + */ + let refreshAfterSave = isCreate; + function setUnsavedChanges() { + los.setUnsavedChanges(); + document + .querySelector("button[type='submit'][form='form--burialSiteContract']") + ?.classList.remove('is-light'); + } + function clearUnsavedChanges() { + los.clearUnsavedChanges(); + document + .querySelector("button[type='submit'][form='form--burialSiteContract']") + ?.classList.add('is-light'); + } + const formElement = document.querySelector('#form--burialSiteContract'); + formElement.addEventListener('submit', (formEvent) => { + formEvent.preventDefault(); + cityssm.postJSON(`${los.urlPrefix}/contracts/${isCreate ? 'doCreateBurialSiteOccupancy' : 'doUpdateBurialSiteContract'}`, formElement, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + clearUnsavedChanges(); + if (isCreate || refreshAfterSave) { + globalThis.location.href = los.getBurialSiteContractURL(responseJSON.burialSiteContractId, true, true); + } + else { + bulmaJS.alert({ + message: `${los.escapedAliases.Occupancy} Updated Successfully`, + contextualColorName: 'success' + }); + } + } + else { + bulmaJS.alert({ + title: `Error Saving ${los.escapedAliases.Occupancy}`, + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + }); + }); + const formInputElements = formElement.querySelectorAll('input, select'); + for (const formInputElement of formInputElements) { + formInputElement.addEventListener('change', setUnsavedChanges); + } + function doCopy() { + cityssm.postJSON(`${los.urlPrefix}/contracts/doCopyBurialSiteContract`, { + burialSiteContractId + }, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + clearUnsavedChanges(); + globalThis.location.href = los.getBurialSiteContractURL(responseJSON.burialSiteContractId, true); + } + else { + bulmaJS.alert({ + title: 'Error Copying Record', + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + }); + } + document + .querySelector('#button--copyBurialSiteContract') + ?.addEventListener('click', (clickEvent) => { + clickEvent.preventDefault(); + if (los.hasUnsavedChanges()) { + bulmaJS.alert({ + title: 'Unsaved Changes', + message: 'Please save all unsaved changes before continuing.', + contextualColorName: 'warning' + }); + } + else { + bulmaJS.confirm({ + title: `Copy ${los.escapedAliases.Occupancy} Record as New`, + message: 'Are you sure you want to copy this record to a new record?', + contextualColorName: 'info', + okButton: { + text: 'Yes, Copy', + callbackFunction: doCopy + } + }); + } + }); + document + .querySelector('#button--deleteLotOccupancy') + ?.addEventListener('click', (clickEvent) => { + clickEvent.preventDefault(); + function doDelete() { + cityssm.postJSON(`${los.urlPrefix}/contracts/doDeleteBurialSiteContract`, { + burialSiteContractId + }, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + clearUnsavedChanges(); + globalThis.location.href = los.getBurialSiteContractURL(); + } + else { + bulmaJS.alert({ + title: 'Error Deleting Record', + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + }); + } + bulmaJS.confirm({ + title: `Delete ${los.escapedAliases.Occupancy} Record`, + message: 'Are you sure you want to delete this record?', + contextualColorName: 'warning', + okButton: { + text: 'Yes, Delete', + callbackFunction: doDelete + } + }); + }); + document + .querySelector('#button--createWorkOrder') + ?.addEventListener('click', (clickEvent) => { + clickEvent.preventDefault(); + let createCloseModalFunction; + function doCreate(formEvent) { + formEvent.preventDefault(); + cityssm.postJSON(`${los.urlPrefix}/workOrders/doCreateWorkOrder`, formEvent.currentTarget, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + createCloseModalFunction(); + bulmaJS.confirm({ + title: 'Work Order Created Successfully', + message: 'Would you like to open the work order now?', + contextualColorName: 'success', + okButton: { + text: 'Yes, Open the Work Order', + callbackFunction: () => { + globalThis.location.href = los.getWorkOrderURL(responseJSON.workOrderId, true); + } + } + }); + } + else { + bulmaJS.alert({ + title: 'Error Creating Work Order', + message: responseJSON.errorMessage, + contextualColorName: 'danger' + }); + } + }); + } + cityssm.openHtmlModal('burialSiteContract-createWorkOrder', { + onshow(modalElement) { + ; + modalElement.querySelector('#workOrderCreate--burialSiteContractId').value = burialSiteContractId; + modalElement.querySelector('#workOrderCreate--workOrderOpenDateString').value = cityssm.dateToString(new Date()); + const workOrderTypeSelectElement = modalElement.querySelector('#workOrderCreate--workOrderTypeId'); + const workOrderTypes = exports + .workOrderTypes; + if (workOrderTypes.length === 1) { + workOrderTypeSelectElement.innerHTML = ''; + } + for (const workOrderType of workOrderTypes) { + const optionElement = document.createElement('option'); + optionElement.value = workOrderType.workOrderTypeId.toString(); + optionElement.textContent = workOrderType.workOrderType ?? ''; + workOrderTypeSelectElement.append(optionElement); + } + }, + onshown(modalElement, closeModalFunction) { + createCloseModalFunction = closeModalFunction; + bulmaJS.toggleHtmlClipped(); + modalElement.querySelector('#workOrderCreate--workOrderTypeId').focus(); + modalElement + .querySelector('form') + ?.addEventListener('submit', doCreate); + }, + onremoved() { + bulmaJS.toggleHtmlClipped(); + document.querySelector('#button--createWorkOrder').focus(); + } + }); + }); + // Occupancy Type + const contractTypeIdElement = document.querySelector('#burialSiteContract--contractTypeId'); + if (isCreate) { + const burialSiteContractFieldsContainerElement = document.querySelector('#container--burialSiteContractFields'); + contractTypeIdElement.addEventListener('change', () => { + if (contractTypeIdElement.value === '') { + // eslint-disable-next-line no-unsanitized/property + burialSiteContractFieldsContainerElement.innerHTML = `
+

Select the ${los.escapedAliases.occupancy} type to load the available fields.

+
`; + return; + } + cityssm.postJSON(`${los.urlPrefix}/contracts/doGetContractTypeFields`, { + contractTypeId: contractTypeIdElement.value + }, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.ContractTypeFields.length === 0) { + // eslint-disable-next-line no-unsanitized/property + burialSiteContractFieldsContainerElement.innerHTML = `
+

There are no additional fields for this ${los.escapedAliases.occupancy} type.

+
`; + return; + } + burialSiteContractFieldsContainerElement.innerHTML = ''; + let contractTypeFieldIds = ''; + for (const occupancyTypeField of responseJSON.ContractTypeFields) { + contractTypeFieldIds += `,${occupancyTypeField.contractTypeFieldId.toString()}`; + const fieldName = `burialSiteContractFieldValue_${occupancyTypeField.contractTypeFieldId.toString()}`; + const fieldId = `burialSiteContract--${fieldName}`; + const fieldElement = document.createElement('div'); + fieldElement.className = 'field'; + fieldElement.innerHTML = `
`; + fieldElement.querySelector('label').textContent = occupancyTypeField.occupancyTypeField; + if (occupancyTypeField.fieldType === 'select' || + (occupancyTypeField.occupancyTypeFieldValues ?? '') !== '') { + ; + fieldElement.querySelector('.control').innerHTML = `
+ +
`; + const selectElement = fieldElement.querySelector('select'); + selectElement.required = occupancyTypeField.isRequired; + const optionValues = occupancyTypeField.occupancyTypeFieldValues.split('\n'); + for (const optionValue of optionValues) { + const optionElement = document.createElement('option'); + optionElement.value = optionValue; + optionElement.textContent = optionValue; + selectElement.append(optionElement); + } + } + else { + const inputElement = document.createElement('input'); + inputElement.className = 'input'; + inputElement.id = fieldId; + inputElement.name = fieldName; + inputElement.type = occupancyTypeField.fieldType; + inputElement.required = occupancyTypeField.isRequired; + inputElement.minLength = + occupancyTypeField.minimumLength; + inputElement.maxLength = + occupancyTypeField.maximumLength; + if ((occupancyTypeField.pattern ?? '') !== '') { + inputElement.pattern = occupancyTypeField.pattern; + } + ; + fieldElement.querySelector('.control').append(inputElement); + } + console.log(fieldElement); + burialSiteContractFieldsContainerElement.append(fieldElement); + } + burialSiteContractFieldsContainerElement.insertAdjacentHTML('beforeend', + // eslint-disable-next-line no-secrets/no-secrets + ``); + }); + }); + } + else { + const originalcontractTypeId = contractTypeIdElement.value; + contractTypeIdElement.addEventListener('change', () => { + if (contractTypeIdElement.value !== originalcontractTypeId) { + bulmaJS.confirm({ + title: 'Confirm Change', + message: `Are you sure you want to change the ${los.escapedAliases.occupancy} type?\n + This 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: () => { + refreshAfterSave = true; + } + }, + cancelButton: { + text: 'Revert the Change', + callbackFunction: () => { + contractTypeIdElement.value = originalcontractTypeId; + } + } + }); + } + }); + } + // Lot Selector + const lotNameElement = document.querySelector('#burialSiteContract--lotName'); + lotNameElement.addEventListener('click', (clickEvent) => { + const currentLotName = clickEvent.currentTarget.value; + let lotSelectCloseModalFunction; + let lotSelectModalElement; + let lotSelectFormElement; + let lotSelectResultsElement; + function renderSelectedLotAndClose(lotId, lotName) { + ; + document.querySelector('#burialSiteContract--lotId').value = lotId.toString(); + document.querySelector('#burialSiteContract--lotName').value = lotName; + setUnsavedChanges(); + lotSelectCloseModalFunction(); + } + function selectExistingLot(clickEvent) { + clickEvent.preventDefault(); + const selectedLotElement = clickEvent.currentTarget; + renderSelectedLotAndClose(selectedLotElement.dataset.lotId ?? '', selectedLotElement.dataset.lotName ?? ''); + } + function searchLots() { + // eslint-disable-next-line no-unsanitized/property + lotSelectResultsElement.innerHTML = + los.getLoadingParagraphHTML('Searching...'); + cityssm.postJSON(`${los.urlPrefix}/lots/doSearchBurialSites`, lotSelectFormElement, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.count === 0) { + lotSelectResultsElement.innerHTML = `
+

No results.

+
`; + return; + } + const panelElement = document.createElement('div'); + panelElement.className = 'panel'; + for (const lot of responseJSON.lots) { + const panelBlockElement = document.createElement('a'); + panelBlockElement.className = 'panel-block is-block'; + panelBlockElement.href = '#'; + panelBlockElement.dataset.lotId = lot.lotId.toString(); + panelBlockElement.dataset.lotName = lot.lotName; + // eslint-disable-next-line no-unsanitized/property + panelBlockElement.innerHTML = `
+
+ ${cityssm.escapeHTML(lot.lotName ?? '')}
+ ${cityssm.escapeHTML(lot.cemeteryName ?? '')} +
+
+ ${cityssm.escapeHTML(lot.lotStatus)}
+ + ${lot.burialSiteContractCount > 0 ? 'Currently Occupied' : ''} + +
+
`; + panelBlockElement.addEventListener('click', selectExistingLot); + panelElement.append(panelBlockElement); + } + lotSelectResultsElement.innerHTML = ''; + lotSelectResultsElement.append(panelElement); + }); + } + function createLotAndSelect(submitEvent) { + submitEvent.preventDefault(); + const lotName = lotSelectModalElement.querySelector('#lotCreate--lotName').value; + cityssm.postJSON(`${los.urlPrefix}/lots/doCreateBurialSite`, submitEvent.currentTarget, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + renderSelectedLotAndClose(responseJSON.lotId ?? '', lotName); + } + else { + bulmaJS.alert({ + title: `Error Creating ${los.escapedAliases.Lot}`, + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + }); + } + cityssm.openHtmlModal('burialSiteContract-selectLot', { + onshow(modalElement) { + los.populateAliases(modalElement); + }, + onshown(modalElement, closeModalFunction) { + bulmaJS.toggleHtmlClipped(); + lotSelectModalElement = modalElement; + lotSelectCloseModalFunction = closeModalFunction; + bulmaJS.init(modalElement); + // search Tab + const lotNameFilterElement = modalElement.querySelector('#lotSelect--lotName'); + if (document.querySelector('#burialSiteContract--lotId') + .value !== '') { + lotNameFilterElement.value = currentLotName; + } + lotNameFilterElement.focus(); + lotNameFilterElement.addEventListener('change', searchLots); + const occupancyStatusFilterElement = modalElement.querySelector('#lotSelect--occupancyStatus'); + occupancyStatusFilterElement.addEventListener('change', searchLots); + if (currentLotName !== '') { + occupancyStatusFilterElement.value = ''; + } + lotSelectFormElement = modalElement.querySelector('#form--lotSelect'); + lotSelectResultsElement = modalElement.querySelector('#resultsContainer--lotSelect'); + lotSelectFormElement.addEventListener('submit', (submitEvent) => { + submitEvent.preventDefault(); + }); + searchLots(); + // Create Tab + if (exports.lotNamePattern) { + const regex = exports.lotNamePattern; + modalElement.querySelector('#lotCreate--lotName').pattern = regex.source; + } + const lotTypeElement = modalElement.querySelector('#lotCreate--burialSiteTypeId'); + for (const lotType of exports.lotTypes) { + const optionElement = document.createElement('option'); + optionElement.value = lotType.burialSiteTypeId.toString(); + optionElement.textContent = lotType.lotType; + lotTypeElement.append(optionElement); + } + const lotStatusElement = modalElement.querySelector('#lotCreate--burialSiteStatusId'); + for (const lotStatus of exports.lotStatuses) { + const optionElement = document.createElement('option'); + optionElement.value = lotStatus.burialSiteStatusId.toString(); + optionElement.textContent = lotStatus.lotStatus; + lotStatusElement.append(optionElement); + } + const mapElement = modalElement.querySelector('#lotCreate--cemeteryId'); + for (const map of exports.maps) { + const optionElement = document.createElement('option'); + optionElement.value = map.cemeteryId.toString(); + optionElement.textContent = + (map.cemeteryName ?? '') === '' ? '(No Name)' : map.cemeteryName ?? ''; + mapElement.append(optionElement); + } + ; + modalElement.querySelector('#form--lotCreate').addEventListener('submit', createLotAndSelect); + }, + onremoved() { + bulmaJS.toggleHtmlClipped(); + } + }); + }); + document + .querySelector('.is-lot-view-button') + ?.addEventListener('click', () => { + const lotId = document.querySelector('#burialSiteContract--lotId').value; + if (lotId === '') { + bulmaJS.alert({ + message: `No ${los.escapedAliases.lot} selected.`, + contextualColorName: 'info' + }); + } + else { + window.open(`${los.urlPrefix}/lots/${lotId}`); + } + }); + document + .querySelector('.is-clear-lot-button') + ?.addEventListener('click', () => { + if (lotNameElement.disabled) { + bulmaJS.alert({ + message: 'You need to unlock the field before clearing it.', + contextualColorName: 'info' + }); + } + else { + lotNameElement.value = `(No ${los.escapedAliases.Lot})`; + document.querySelector('#burialSiteContract--lotId').value = ''; + setUnsavedChanges(); + } + }); + // Start Date + los.initializeDatePickers(formElement); + document + .querySelector('#burialSiteContract--contractStartDateString') + ?.addEventListener('change', () => { + const endDatePicker = document.querySelector('#burialSiteContract--contractEndDateString').bulmaCalendar.datePicker; + endDatePicker.min = document.querySelector('#burialSiteContract--contractStartDateString').value; + endDatePicker.refresh(); + }); + los.initializeUnlockFieldButtons(formElement); + (() => { + let burialSiteContractOccupants = exports.burialSiteContractOccupants; + delete exports.burialSiteContractOccupants; + function openEditLotOccupancyOccupant(clickEvent) { + const lotOccupantIndex = Number.parseInt(clickEvent.currentTarget.closest('tr')?.dataset + .lotOccupantIndex ?? '', 10); + const burialSiteContractOccupant = burialSiteContractOccupants.find((currentLotOccupancyOccupant) => { + return (currentLotOccupancyOccupant.lotOccupantIndex === lotOccupantIndex); + }); + let editFormElement; + let editCloseModalFunction; + function editOccupant(submitEvent) { + submitEvent.preventDefault(); + cityssm.postJSON(`${los.urlPrefix}/contracts/doUpdateBurialSiteContractOccupant`, editFormElement, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + burialSiteContractOccupants = responseJSON.burialSiteContractOccupants; + editCloseModalFunction(); + renderLotOccupancyOccupants(); + } + else { + bulmaJS.alert({ + title: `Error Updating ${los.escapedAliases.Occupant}`, + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + }); + } + cityssm.openHtmlModal('burialSiteContract-editOccupant', { + onshow(modalElement) { + los.populateAliases(modalElement); + modalElement.querySelector('#burialSiteContractOccupantEdit--burialSiteContractId').value = burialSiteContractId; + modalElement.querySelector('#burialSiteContractOccupantEdit--lotOccupantIndex').value = lotOccupantIndex.toString(); + const lotOccupantTypeSelectElement = modalElement.querySelector('#burialSiteContractOccupantEdit--lotOccupantTypeId'); + let lotOccupantTypeSelected = false; + for (const lotOccupantType of exports.lotOccupantTypes) { + const optionElement = document.createElement('option'); + optionElement.value = lotOccupantType.lotOccupantTypeId.toString(); + optionElement.textContent = lotOccupantType.lotOccupantType; + optionElement.dataset.occupantCommentTitle = + lotOccupantType.occupantCommentTitle; + optionElement.dataset.fontAwesomeIconClass = + lotOccupantType.fontAwesomeIconClass; + if (lotOccupantType.lotOccupantTypeId === + burialSiteContractOccupant.lotOccupantTypeId) { + optionElement.selected = true; + lotOccupantTypeSelected = true; + } + lotOccupantTypeSelectElement.append(optionElement); + } + if (!lotOccupantTypeSelected) { + const optionElement = document.createElement('option'); + optionElement.value = + burialSiteContractOccupant.lotOccupantTypeId?.toString() ?? ''; + optionElement.textContent = + burialSiteContractOccupant.lotOccupantType ?? ''; + optionElement.dataset.occupantCommentTitle = + burialSiteContractOccupant.occupantCommentTitle; + optionElement.dataset.fontAwesomeIconClass = + burialSiteContractOccupant.fontAwesomeIconClass; + optionElement.selected = true; + lotOccupantTypeSelectElement.append(optionElement); + } + ; + modalElement.querySelector('#burialSiteContractOccupantEdit--fontAwesomeIconClass').innerHTML = + ``; + modalElement.querySelector('#burialSiteContractOccupantEdit--occupantName').value = burialSiteContractOccupant.occupantName ?? ''; + modalElement.querySelector('#burialSiteContractOccupantEdit--occupantFamilyName').value = burialSiteContractOccupant.occupantFamilyName ?? ''; + modalElement.querySelector('#burialSiteContractOccupantEdit--occupantAddress1').value = burialSiteContractOccupant.occupantAddress1 ?? ''; + modalElement.querySelector('#burialSiteContractOccupantEdit--occupantAddress2').value = burialSiteContractOccupant.occupantAddress2 ?? ''; + modalElement.querySelector('#burialSiteContractOccupantEdit--occupantCity').value = burialSiteContractOccupant.occupantCity ?? ''; + modalElement.querySelector('#burialSiteContractOccupantEdit--occupantProvince').value = burialSiteContractOccupant.occupantProvince ?? ''; + modalElement.querySelector('#burialSiteContractOccupantEdit--occupantPostalCode').value = burialSiteContractOccupant.occupantPostalCode ?? ''; + modalElement.querySelector('#burialSiteContractOccupantEdit--occupantPhoneNumber').value = burialSiteContractOccupant.occupantPhoneNumber ?? ''; + modalElement.querySelector('#burialSiteContractOccupantEdit--occupantEmailAddress').value = burialSiteContractOccupant.occupantEmailAddress ?? ''; + modalElement.querySelector('#burialSiteContractOccupantEdit--occupantCommentTitle').textContent = + (burialSiteContractOccupant.occupantCommentTitle ?? '') === '' + ? 'Comment' + : burialSiteContractOccupant.occupantCommentTitle ?? ''; + modalElement.querySelector('#burialSiteContractOccupantEdit--occupantComment').value = burialSiteContractOccupant.occupantComment ?? ''; + }, + onshown(modalElement, closeModalFunction) { + bulmaJS.toggleHtmlClipped(); + const lotOccupantTypeIdElement = modalElement.querySelector('#burialSiteContractOccupantEdit--lotOccupantTypeId'); + lotOccupantTypeIdElement.focus(); + lotOccupantTypeIdElement.addEventListener('change', () => { + const fontAwesomeIconClass = lotOccupantTypeIdElement.selectedOptions[0].dataset + .fontAwesomeIconClass ?? 'user'; + modalElement.querySelector('#burialSiteContractOccupantEdit--fontAwesomeIconClass').innerHTML = + ``; + let occupantCommentTitle = lotOccupantTypeIdElement.selectedOptions[0].dataset + .occupantCommentTitle ?? ''; + if (occupantCommentTitle === '') { + occupantCommentTitle = 'Comment'; + } + ; + modalElement.querySelector('#burialSiteContractOccupantEdit--occupantCommentTitle').textContent = occupantCommentTitle; + }); + editFormElement = modalElement.querySelector('form'); + editFormElement.addEventListener('submit', editOccupant); + editCloseModalFunction = closeModalFunction; + }, + onremoved() { + bulmaJS.toggleHtmlClipped(); + } + }); + } + function deleteLotOccupancyOccupant(clickEvent) { + const lotOccupantIndex = clickEvent.currentTarget.closest('tr')?.dataset.lotOccupantIndex; + function doDelete() { + cityssm.postJSON(`${los.urlPrefix}/contracts/doDeleteBurialSiteContractOccupant`, { + burialSiteContractId, + lotOccupantIndex + }, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + burialSiteContractOccupants = responseJSON.burialSiteContractOccupants; + renderLotOccupancyOccupants(); + } + else { + bulmaJS.alert({ + title: `Error Removing ${los.escapedAliases.Occupant}`, + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + }); + } + bulmaJS.confirm({ + title: `Remove ${los.escapedAliases.Occupant}?`, + message: `Are you sure you want to remove this ${los.escapedAliases.occupant}?`, + okButton: { + text: `Yes, Remove ${los.escapedAliases.Occupant}`, + callbackFunction: doDelete + }, + contextualColorName: 'warning' + }); + } + function renderLotOccupancyOccupants() { + const occupantsContainer = document.querySelector('#container--burialSiteContractOccupants'); + cityssm.clearElement(occupantsContainer); + if (burialSiteContractOccupants.length === 0) { + // eslint-disable-next-line no-unsanitized/property + occupantsContainer.innerHTML = `
+

There are no ${los.escapedAliases.occupants} associated with this record.

+
`; + return; + } + const tableElement = document.createElement('table'); + tableElement.className = 'table is-fullwidth is-striped is-hoverable'; + // eslint-disable-next-line no-unsanitized/property + tableElement.innerHTML = ` + ${los.escapedAliases.Occupant} + Address + Other Contact + Comment + Options + + `; + for (const burialSiteContractOccupant of burialSiteContractOccupants) { + const tableRowElement = document.createElement('tr'); + tableRowElement.dataset.lotOccupantIndex = + burialSiteContractOccupant.lotOccupantIndex?.toString(); + // eslint-disable-next-line no-unsanitized/property + tableRowElement.innerHTML = ` + ${cityssm.escapeHTML((burialSiteContractOccupant.occupantName ?? '') === '' && + (burialSiteContractOccupant.occupantFamilyName ?? '') === '' + ? '(No Name)' + : `${burialSiteContractOccupant.occupantName} ${burialSiteContractOccupant.occupantFamilyName}`)}
+ + + ${cityssm.escapeHTML(burialSiteContractOccupant.lotOccupantType ?? '')} + + + ${(burialSiteContractOccupant.occupantAddress1 ?? '') === '' + ? '' + : `${cityssm.escapeHTML(burialSiteContractOccupant.occupantAddress1 ?? '')}
`} + ${(burialSiteContractOccupant.occupantAddress2 ?? '') === '' + ? '' + : `${cityssm.escapeHTML(burialSiteContractOccupant.occupantAddress2 ?? '')}
`} + ${(burialSiteContractOccupant.occupantCity ?? '') === '' + ? '' + : `${cityssm.escapeHTML(burialSiteContractOccupant.occupantCity ?? '')}, `} + ${cityssm.escapeHTML(burialSiteContractOccupant.occupantProvince ?? '')}
+ ${cityssm.escapeHTML(burialSiteContractOccupant.occupantPostalCode ?? '')} + + ${(burialSiteContractOccupant.occupantPhoneNumber ?? '') === '' + ? '' + : `${cityssm.escapeHTML(burialSiteContractOccupant.occupantPhoneNumber ?? '')}
`} + ${(burialSiteContractOccupant.occupantEmailAddress ?? '') === '' + ? '' + : cityssm.escapeHTML(burialSiteContractOccupant.occupantEmailAddress ?? '')} + + + ${cityssm.escapeHTML(burialSiteContractOccupant.occupantComment ?? '')} + + +
+ + +
+ `; + tableRowElement + .querySelector('.button--edit') + ?.addEventListener('click', openEditLotOccupancyOccupant); + tableRowElement + .querySelector('.button--delete') + ?.addEventListener('click', deleteLotOccupancyOccupant); + tableElement.querySelector('tbody')?.append(tableRowElement); + } + occupantsContainer.append(tableElement); + } + if (isCreate) { + const lotOccupantTypeIdElement = document.querySelector('#burialSiteContract--lotOccupantTypeId'); + lotOccupantTypeIdElement.addEventListener('change', () => { + const occupantFields = formElement.querySelectorAll("[data-table='LotOccupancyOccupant']"); + for (const occupantField of occupantFields) { + occupantField.disabled = lotOccupantTypeIdElement.value === ''; + } + let occupantCommentTitle = lotOccupantTypeIdElement.selectedOptions[0].dataset + .occupantCommentTitle ?? ''; + if (occupantCommentTitle === '') { + occupantCommentTitle = 'Comment'; + } + ; + formElement.querySelector('#burialSiteContract--occupantCommentTitle').textContent = occupantCommentTitle; + }); + } + else { + renderLotOccupancyOccupants(); + } + document + .querySelector('#button--addOccupant') + ?.addEventListener('click', () => { + let addCloseModalFunction; + let addFormElement; + let searchFormElement; + let searchResultsElement; + function addOccupant(formOrObject) { + cityssm.postJSON(`${los.urlPrefix}/contracts/doAddLotOccupancyOccupant`, formOrObject, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + burialSiteContractOccupants = responseJSON.burialSiteContractOccupants; + addCloseModalFunction(); + renderLotOccupancyOccupants(); + } + else { + bulmaJS.alert({ + title: `Error Adding ${los.escapedAliases.Occupant}`, + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + }); + } + function addOccupantFromForm(submitEvent) { + submitEvent.preventDefault(); + addOccupant(addFormElement); + } + let pastOccupantSearchResults = []; + function addOccupantFromCopy(clickEvent) { + clickEvent.preventDefault(); + const panelBlockElement = clickEvent.currentTarget; + const occupant = pastOccupantSearchResults[Number.parseInt(panelBlockElement.dataset.index ?? '', 10)]; + const lotOccupantTypeId = (panelBlockElement + .closest('.modal') + ?.querySelector('#burialSiteContractOccupantCopy--lotOccupantTypeId')).value; + if (lotOccupantTypeId === '') { + bulmaJS.alert({ + title: `No ${los.escapedAliases.Occupant} Type Selected`, + message: `Select a type to apply to the newly added ${los.escapedAliases.occupant}.`, + contextualColorName: 'warning' + }); + } + else { + occupant.lotOccupantTypeId = Number.parseInt(lotOccupantTypeId, 10); + occupant.burialSiteContractId = Number.parseInt(burialSiteContractId, 10); + addOccupant(occupant); + } + } + function searchOccupants(event) { + event.preventDefault(); + if (searchFormElement.querySelector('#burialSiteContractOccupantCopy--searchFilter').value === '') { + searchResultsElement.innerHTML = `
+

Enter a partial name or address in the search field above.

+
`; + return; + } + // eslint-disable-next-line no-unsanitized/property + searchResultsElement.innerHTML = + los.getLoadingParagraphHTML('Searching...'); + cityssm.postJSON(`${los.urlPrefix}/contracts/doSearchPastOccupants`, searchFormElement, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + pastOccupantSearchResults = responseJSON.occupants; + const panelElement = document.createElement('div'); + panelElement.className = 'panel'; + for (const [index, occupant] of pastOccupantSearchResults.entries()) { + const panelBlockElement = document.createElement('a'); + panelBlockElement.className = 'panel-block is-block'; + panelBlockElement.href = '#'; + panelBlockElement.dataset.index = index.toString(); + // eslint-disable-next-line no-unsanitized/property + panelBlockElement.innerHTML = ` + ${cityssm.escapeHTML(occupant.occupantName ?? '')} ${cityssm.escapeHTML(occupant.occupantFamilyName ?? '')} +
+
+
+ ${cityssm.escapeHTML(occupant.occupantAddress1 ?? '')}
+ ${(occupant.occupantAddress2 ?? '') === '' + ? '' + : `${cityssm.escapeHTML(occupant.occupantAddress2 ?? '')}
`}${cityssm.escapeHTML(occupant.occupantCity ?? '')}, ${cityssm.escapeHTML(occupant.occupantProvince ?? '')}
+ ${cityssm.escapeHTML(occupant.occupantPostalCode ?? '')} +
+
+ ${(occupant.occupantPhoneNumber ?? '') === '' + ? '' + : `${cityssm.escapeHTML(occupant.occupantPhoneNumber ?? '')}
`} + ${cityssm.escapeHTML(occupant.occupantEmailAddress ?? '')}
+
+
`; + panelBlockElement.addEventListener('click', addOccupantFromCopy); + panelElement.append(panelBlockElement); + } + searchResultsElement.innerHTML = ''; + searchResultsElement.append(panelElement); + }); + } + cityssm.openHtmlModal('burialSiteContract-addOccupant', { + onshow(modalElement) { + los.populateAliases(modalElement); + modalElement.querySelector('#burialSiteContractOccupantAdd--burialSiteContractId').value = burialSiteContractId; + const lotOccupantTypeSelectElement = modalElement.querySelector('#burialSiteContractOccupantAdd--lotOccupantTypeId'); + const lotOccupantTypeCopySelectElement = modalElement.querySelector('#burialSiteContractOccupantCopy--lotOccupantTypeId'); + for (const lotOccupantType of exports.lotOccupantTypes) { + const optionElement = document.createElement('option'); + optionElement.value = lotOccupantType.lotOccupantTypeId.toString(); + optionElement.textContent = lotOccupantType.lotOccupantType; + optionElement.dataset.occupantCommentTitle = + lotOccupantType.occupantCommentTitle; + optionElement.dataset.fontAwesomeIconClass = + lotOccupantType.fontAwesomeIconClass; + lotOccupantTypeSelectElement.append(optionElement); + lotOccupantTypeCopySelectElement.append(optionElement.cloneNode(true)); + } + ; + modalElement.querySelector('#burialSiteContractOccupantAdd--occupantCity').value = exports.occupantCityDefault; + modalElement.querySelector('#burialSiteContractOccupantAdd--occupantProvince').value = exports.occupantProvinceDefault; + }, + onshown(modalElement, closeModalFunction) { + bulmaJS.toggleHtmlClipped(); + bulmaJS.init(modalElement); + const lotOccupantTypeIdElement = modalElement.querySelector('#burialSiteContractOccupantAdd--lotOccupantTypeId'); + lotOccupantTypeIdElement.focus(); + lotOccupantTypeIdElement.addEventListener('change', () => { + const fontAwesomeIconClass = lotOccupantTypeIdElement.selectedOptions[0].dataset + .fontAwesomeIconClass ?? 'user'; + modalElement.querySelector('#burialSiteContractOccupantAdd--fontAwesomeIconClass').innerHTML = + ``; + let occupantCommentTitle = lotOccupantTypeIdElement.selectedOptions[0].dataset + .occupantCommentTitle ?? ''; + if (occupantCommentTitle === '') { + occupantCommentTitle = 'Comment'; + } + ; + modalElement.querySelector('#burialSiteContractOccupantAdd--occupantCommentTitle').textContent = occupantCommentTitle; + }); + addFormElement = modalElement.querySelector('#form--burialSiteContractOccupantAdd'); + addFormElement.addEventListener('submit', addOccupantFromForm); + searchResultsElement = modalElement.querySelector('#burialSiteContractOccupantCopy--searchResults'); + searchFormElement = modalElement.querySelector('#form--burialSiteContractOccupantCopy'); + searchFormElement.addEventListener('submit', (formEvent) => { + formEvent.preventDefault(); + }); + modalElement.querySelector('#burialSiteContractOccupantCopy--searchFilter').addEventListener('change', searchOccupants); + addCloseModalFunction = closeModalFunction; + }, + onremoved() { + bulmaJS.toggleHtmlClipped(); + document.querySelector('#button--addOccupant').focus(); + } + }); + }); + })(); + if (!isCreate) { + /** + * Comments + */ + ; + (() => { + let burialSiteContractComments = exports.burialSiteContractComments; + delete exports.burialSiteContractComments; + function openEditLotOccupancyComment(clickEvent) { + const burialSiteContractCommentId = Number.parseInt(clickEvent.currentTarget.closest('tr')?.dataset + .burialSiteContractCommentId ?? '', 10); + const burialSiteContractComment = burialSiteContractComments.find((currentLotOccupancyComment) => { + return (currentLotOccupancyComment.burialSiteContractCommentId === + burialSiteContractCommentId); + }); + let editFormElement; + let editCloseModalFunction; + function editComment(submitEvent) { + submitEvent.preventDefault(); + cityssm.postJSON(`${los.urlPrefix}/contracts/doUpdateBurialSiteContractComment`, editFormElement, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + burialSiteContractComments = responseJSON.burialSiteContractComments ?? []; + editCloseModalFunction(); + renderLotOccupancyComments(); + } + else { + bulmaJS.alert({ + title: 'Error Updating Comment', + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + }); + } + cityssm.openHtmlModal('burialSiteContract-editComment', { + onshow(modalElement) { + los.populateAliases(modalElement); + modalElement.querySelector('#burialSiteContractCommentEdit--burialSiteContractId').value = burialSiteContractId; + modalElement.querySelector('#burialSiteContractCommentEdit--burialSiteContractCommentId').value = burialSiteContractCommentId.toString(); + modalElement.querySelector('#burialSiteContractCommentEdit--burialSiteContractComment').value = burialSiteContractComment.burialSiteContractComment ?? ''; + const burialSiteContractCommentDateStringElement = modalElement.querySelector('#burialSiteContractCommentEdit--burialSiteContractCommentDateString'); + burialSiteContractCommentDateStringElement.value = + burialSiteContractComment.burialSiteContractCommentDateString ?? ''; + const currentDateString = cityssm.dateToString(new Date()); + burialSiteContractCommentDateStringElement.max = + burialSiteContractComment.burialSiteContractCommentDateString <= + currentDateString + ? currentDateString + : burialSiteContractComment.burialSiteContractCommentDateString ?? ''; + modalElement.querySelector('#burialSiteContractCommentEdit--burialSiteContractCommentTimeString').value = burialSiteContractComment.burialSiteContractCommentTimeString ?? ''; + }, + onshown(modalElement, closeModalFunction) { + bulmaJS.toggleHtmlClipped(); + los.initializeDatePickers(modalElement); + modalElement.querySelector('#burialSiteContractCommentEdit--burialSiteContractComment').focus(); + editFormElement = modalElement.querySelector('form'); + editFormElement.addEventListener('submit', editComment); + editCloseModalFunction = closeModalFunction; + }, + onremoved() { + bulmaJS.toggleHtmlClipped(); + } + }); + } + function deleteLotOccupancyComment(clickEvent) { + const burialSiteContractCommentId = Number.parseInt(clickEvent.currentTarget.closest('tr')?.dataset + .burialSiteContractCommentId ?? '', 10); + function doDelete() { + cityssm.postJSON(`${los.urlPrefix}/contracts/doDeleteBurialSiteContractComment`, { + burialSiteContractId, + burialSiteContractCommentId + }, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + burialSiteContractComments = responseJSON.burialSiteContractComments; + renderLotOccupancyComments(); + } + else { + bulmaJS.alert({ + title: 'Error Removing Comment', + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + }); + } + bulmaJS.confirm({ + title: 'Remove Comment?', + message: 'Are you sure you want to remove this comment?', + okButton: { + text: 'Yes, Remove Comment', + callbackFunction: doDelete + }, + contextualColorName: 'warning' + }); + } + function renderLotOccupancyComments() { + const containerElement = document.querySelector('#container--burialSiteContractComments'); + if (burialSiteContractComments.length === 0) { + containerElement.innerHTML = `
+

There are no comments associated with this record.

+
`; + return; + } + const tableElement = document.createElement('table'); + tableElement.className = 'table is-fullwidth is-striped is-hoverable'; + tableElement.innerHTML = ` + Commentor + Comment Date + Comment + Options + + `; + for (const burialSiteContractComment of burialSiteContractComments) { + const tableRowElement = document.createElement('tr'); + tableRowElement.dataset.burialSiteContractCommentId = + burialSiteContractComment.burialSiteContractCommentId?.toString(); + tableRowElement.innerHTML = `${cityssm.escapeHTML(burialSiteContractComment.recordCreate_userName ?? '')} + + ${cityssm.escapeHTML(burialSiteContractComment.burialSiteContractCommentDateString ?? '')} + ${cityssm.escapeHTML(burialSiteContractComment.burialSiteContractCommentTime === 0 + ? '' + : burialSiteContractComment.burialSiteContractCommentTimePeriodString ?? '')} + + ${cityssm.escapeHTML(burialSiteContractComment.burialSiteContractComment ?? '')} + +
+ + +
+ `; + tableRowElement + .querySelector('.button--edit') + ?.addEventListener('click', openEditLotOccupancyComment); + tableRowElement + .querySelector('.button--delete') + ?.addEventListener('click', deleteLotOccupancyComment); + tableElement.querySelector('tbody')?.append(tableRowElement); + } + containerElement.innerHTML = ''; + containerElement.append(tableElement); + } + document + .querySelector('#button--addComment') + ?.addEventListener('click', () => { + let addFormElement; + let addCloseModalFunction; + function addComment(submitEvent) { + submitEvent.preventDefault(); + cityssm.postJSON(`${los.urlPrefix}/contracts/doAddBurialSiteContractComment`, addFormElement, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + burialSiteContractComments = responseJSON.burialSiteContractComments; + addCloseModalFunction(); + renderLotOccupancyComments(); + } + else { + bulmaJS.alert({ + title: 'Error Adding Comment', + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + }); + } + cityssm.openHtmlModal('burialSiteContract-addComment', { + onshow(modalElement) { + los.populateAliases(modalElement); + modalElement.querySelector('#burialSiteContractCommentAdd--burialSiteContractId').value = burialSiteContractId; + }, + onshown(modalElement, closeModalFunction) { + bulmaJS.toggleHtmlClipped(); + modalElement.querySelector('#burialSiteContractCommentAdd--burialSiteContractComment').focus(); + addFormElement = modalElement.querySelector('form'); + addFormElement.addEventListener('submit', addComment); + addCloseModalFunction = closeModalFunction; + }, + onremoved: () => { + bulmaJS.toggleHtmlClipped(); + document.querySelector('#button--addComment').focus(); + } + }); + }); + renderLotOccupancyComments(); + })(); + (() => { + let burialSiteContractFees = exports.burialSiteContractFees; + delete exports.burialSiteContractFees; + const burialSiteContractFeesContainerElement = document.querySelector('#container--burialSiteContractFees'); + function getFeeGrandTotal() { + let feeGrandTotal = 0; + for (const burialSiteContractFee of burialSiteContractFees) { + feeGrandTotal += + ((burialSiteContractFee.feeAmount ?? 0) + + (burialSiteContractFee.taxAmount ?? 0)) * + (burialSiteContractFee.quantity ?? 0); + } + return feeGrandTotal; + } + function editLotOccupancyFeeQuantity(clickEvent) { + const feeId = Number.parseInt(clickEvent.currentTarget.closest('tr')?.dataset + .feeId ?? '', 10); + const fee = burialSiteContractFees.find((possibleFee) => { + return possibleFee.feeId === feeId; + }); + let updateCloseModalFunction; + function doUpdateQuantity(formEvent) { + formEvent.preventDefault(); + cityssm.postJSON(`${los.urlPrefix}/contracts/doUpdateBurialSiteContractFeeQuantity`, formEvent.currentTarget, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + burialSiteContractFees = responseJSON.burialSiteContractFees; + renderLotOccupancyFees(); + updateCloseModalFunction(); + } + else { + bulmaJS.alert({ + title: 'Error Updating Quantity', + message: 'Please try again.', + contextualColorName: 'danger' + }); + } + }); + } + cityssm.openHtmlModal('burialSiteContract-editFeeQuantity', { + onshow(modalElement) { + ; + modalElement.querySelector('#burialSiteContractFeeQuantity--burialSiteContractId').value = burialSiteContractId; + modalElement.querySelector('#burialSiteContractFeeQuantity--feeId').value = fee.feeId.toString(); + modalElement.querySelector('#burialSiteContractFeeQuantity--quantity').valueAsNumber = fee.quantity ?? 0; + modalElement.querySelector('#burialSiteContractFeeQuantity--quantityUnit').textContent = fee.quantityUnit ?? ''; + }, + onshown(modalElement, closeModalFunction) { + bulmaJS.toggleHtmlClipped(); + updateCloseModalFunction = closeModalFunction; + modalElement.querySelector('#burialSiteContractFeeQuantity--quantity').focus(); + modalElement + .querySelector('form') + ?.addEventListener('submit', doUpdateQuantity); + }, + onremoved() { + bulmaJS.toggleHtmlClipped(); + } + }); + } + function deleteBurialSiteContractFee(clickEvent) { + const feeId = clickEvent.currentTarget.closest('.container--burialSiteContractFee').dataset.feeId; + function doDelete() { + cityssm.postJSON(`${los.urlPrefix}/contracts/doDeleteBurialSiteContractFee`, { + burialSiteContractId, + feeId + }, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + burialSiteContractFees = responseJSON.burialSiteContractFees; + 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 + } + }); + } + function renderLotOccupancyFees() { + if (burialSiteContractFees.length === 0) { + burialSiteContractFeesContainerElement.innerHTML = `
+

There are no fees associated with this record.

+
`; + renderLotOccupancyTransactions(); + return; + } + // eslint-disable-next-line no-secrets/no-secrets + burialSiteContractFeesContainerElement.innerHTML = ` + + + + + + + + + + + + + + + + + + + + + + +
FeeUnit Cost×QuantityequalsTotalOptions
Subtotal
Tax
Grand Total
`; + let feeAmountTotal = 0; + let taxAmountTotal = 0; + for (const burialSiteContractFee of burialSiteContractFees) { + const tableRowElement = document.createElement('tr'); + tableRowElement.className = 'container--burialSiteContractFee'; + tableRowElement.dataset.feeId = burialSiteContractFee.feeId.toString(); + tableRowElement.dataset.includeQuantity = + burialSiteContractFee.includeQuantity ?? false ? '1' : '0'; + // eslint-disable-next-line no-unsanitized/property + tableRowElement.innerHTML = ` + ${cityssm.escapeHTML(burialSiteContractFee.feeName ?? '')}
+ ${cityssm.escapeHTML(burialSiteContractFee.feeCategory ?? '')} + + ${burialSiteContractFee.quantity === 1 + ? '' + : ` + $${burialSiteContractFee.feeAmount?.toFixed(2)} + + × + ${burialSiteContractFee.quantity?.toString()} + =`} + + $${((burialSiteContractFee.feeAmount ?? 0) * (burialSiteContractFee.quantity ?? 0)).toFixed(2)} + + +
+ ${burialSiteContractFee.includeQuantity ?? false + ? `` + : ''} + +
+ `; + tableRowElement + .querySelector('.button--editQuantity') + ?.addEventListener('click', editLotOccupancyFeeQuantity); + tableRowElement + .querySelector('.button--delete') + ?.addEventListener('click', deleteBurialSiteContractFee); + burialSiteContractFeesContainerElement + .querySelector('tbody') + ?.append(tableRowElement); + feeAmountTotal += + (burialSiteContractFee.feeAmount ?? 0) * (burialSiteContractFee.quantity ?? 0); + taxAmountTotal += + (burialSiteContractFee.taxAmount ?? 0) * (burialSiteContractFee.quantity ?? 0); + } + ; + burialSiteContractFeesContainerElement.querySelector('#burialSiteContractFees--feeAmountTotal').textContent = `$${feeAmountTotal.toFixed(2)}`; + burialSiteContractFeesContainerElement.querySelector('#burialSiteContractFees--taxAmountTotal').textContent = `$${taxAmountTotal.toFixed(2)}`; + burialSiteContractFeesContainerElement.querySelector('#burialSiteContractFees--grandTotal').textContent = `$${(feeAmountTotal + taxAmountTotal).toFixed(2)}`; + renderLotOccupancyTransactions(); + } + const addFeeButtonElement = document.querySelector('#button--addFee'); + addFeeButtonElement.addEventListener('click', () => { + if (los.hasUnsavedChanges()) { + bulmaJS.alert({ + message: 'Please save all unsaved changes before adding fees.', + contextualColorName: 'warning' + }); + return; + } + let feeCategories; + let feeFilterElement; + let feeFilterResultsElement; + function doAddFeeCategory(clickEvent) { + clickEvent.preventDefault(); + const feeCategoryId = Number.parseInt(clickEvent.currentTarget.dataset.feeCategoryId ?? + '', 10); + cityssm.postJSON(`${los.urlPrefix}/contracts/doAddBurialSiteContractFeeCategory`, { + burialSiteContractId, + feeCategoryId + }, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + burialSiteContractFees = responseJSON.burialSiteContractFees; + renderLotOccupancyFees(); + bulmaJS.alert({ + message: 'Fee Group Added Successfully', + contextualColorName: 'success' + }); + } + else { + bulmaJS.alert({ + title: 'Error Adding Fee', + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + }); + } + function doAddFee(feeId, quantity = 1) { + cityssm.postJSON(`${los.urlPrefix}/contracts/doAddLotOccupancyFee`, { + burialSiteContractId, + feeId, + quantity + }, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + burialSiteContractFees = responseJSON.burialSiteContractFees; + renderLotOccupancyFees(); + filterFees(); + } + else { + bulmaJS.alert({ + title: 'Error Adding Fee', + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + }); + } + function doSetQuantityAndAddFee(fee) { + let quantityElement; + let quantityCloseModalFunction; + function doSetQuantity(submitEvent) { + submitEvent.preventDefault(); + doAddFee(fee.feeId, quantityElement.value); + quantityCloseModalFunction(); + } + cityssm.openHtmlModal('burialSiteContract-setFeeQuantity', { + onshow(modalElement) { + ; + modalElement.querySelector('#burialSiteContractFeeQuantity--quantityUnit').textContent = fee.quantityUnit ?? ''; + }, + onshown(modalElement, closeModalFunction) { + quantityCloseModalFunction = closeModalFunction; + quantityElement = modalElement.querySelector('#burialSiteContractFeeQuantity--quantity'); + modalElement + .querySelector('form') + ?.addEventListener('submit', doSetQuantity); + } + }); + } + function tryAddFee(clickEvent) { + clickEvent.preventDefault(); + const feeId = Number.parseInt(clickEvent.currentTarget.dataset.feeId ?? '', 10); + const feeCategoryId = Number.parseInt(clickEvent.currentTarget.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 ?? false) { + doSetQuantityAndAddFee(fee); + } + else { + doAddFee(feeId); + } + } + function 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 ?? '')} +

+
+
+
`; + if (feeCategory.isGroupedFee) { + // eslint-disable-next-line no-unsanitized/method + categoryContainerElement + .querySelector('.columns') + ?.insertAdjacentHTML('beforeend', `
+ +
`); + categoryContainerElement + .querySelector('button') + ?.addEventListener('click', doAddFeeCategory); + } + let hasFees = false; + for (const fee of feeCategory.fees) { + // Don't include already applied fees that limit quantity + if (burialSiteContractFeesContainerElement.querySelector(`.container--burialSiteContractFee[data-fee-id='${fee.feeId}'][data-include-quantity='0']`) !== null) { + continue; + } + let includeFee = true; + const feeSearchString = `${feeCategory.feeCategory ?? ''} ${fee.feeName ?? ''} ${fee.feeDescription ?? ''}`.toLowerCase(); + for (const filterStringPiece of filterStringPieces) { + if (!feeSearchString.includes(filterStringPiece)) { + includeFee = false; + break; + } + } + if (!includeFee) { + continue; + } + hasFees = true; + const panelBlockElement = document.createElement(feeCategory.isGroupedFee ? 'div' : 'a'); + panelBlockElement.className = + 'panel-block is-block container--fee'; + panelBlockElement.dataset.feeId = fee.feeId.toString(); + panelBlockElement.dataset.feeCategoryId = + feeCategory.feeCategoryId.toString(); + // eslint-disable-next-line no-unsanitized/property + panelBlockElement.innerHTML = `${cityssm.escapeHTML(fee.feeName ?? '')}
+ + ${ + // eslint-disable-next-line @typescript-eslint/no-unsafe-call + cityssm + .escapeHTML(fee.feeDescription ?? '') + .replaceAll('\n', '
')} +
`; + if (!feeCategory.isGroupedFee) { + ; + panelBlockElement.href = '#'; + panelBlockElement.addEventListener('click', tryAddFee); + } + ; + categoryContainerElement.querySelector('.panel').append(panelBlockElement); + } + if (hasFees) { + feeFilterResultsElement.append(categoryContainerElement); + } + } + } + cityssm.openHtmlModal('burialSiteContract-addFee', { + onshow(modalElement) { + feeFilterElement = modalElement.querySelector('#feeSelect--feeName'); + feeFilterResultsElement = modalElement.querySelector('#resultsContainer--feeSelect'); + cityssm.postJSON(`${los.urlPrefix}/contracts/doGetFees`, { + burialSiteContractId + }, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + feeCategories = responseJSON.feeCategories; + feeFilterElement.disabled = false; + feeFilterElement.addEventListener('keyup', filterFees); + feeFilterElement.focus(); + filterFees(); + }); + }, + onshown() { + bulmaJS.toggleHtmlClipped(); + }, + onhidden() { + renderLotOccupancyFees(); + }, + onremoved() { + bulmaJS.toggleHtmlClipped(); + addFeeButtonElement.focus(); + } + }); + }); + let burialSiteContractTransactions = exports.burialSiteContractTransactions; + delete exports.burialSiteContractTransactions; + const burialSiteContractTransactionsContainerElement = document.querySelector('#container--burialSiteContractTransactions'); + function getTransactionGrandTotal() { + let transactionGrandTotal = 0; + for (const burialSiteContractTransaction of burialSiteContractTransactions) { + transactionGrandTotal += burialSiteContractTransaction.transactionAmount; + } + return transactionGrandTotal; + } + function editLotOccupancyTransaction(clickEvent) { + const transactionIndex = Number.parseInt(clickEvent.currentTarget.closest('tr')?.dataset + .transactionIndex ?? '', 10); + const transaction = burialSiteContractTransactions.find((possibleTransaction) => { + return possibleTransaction.transactionIndex === transactionIndex; + }); + let editCloseModalFunction; + function doEdit(formEvent) { + formEvent.preventDefault(); + cityssm.postJSON(`${los.urlPrefix}/contracts/doUpdateBurialSiteContractTransaction`, formEvent.currentTarget, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + burialSiteContractTransactions = responseJSON.burialSiteContractTransactions; + renderLotOccupancyTransactions(); + editCloseModalFunction(); + } + else { + bulmaJS.alert({ + title: 'Error Updating Transaction', + message: 'Please try again.', + contextualColorName: 'danger' + }); + } + }); + } + cityssm.openHtmlModal('burialSiteContract-editTransaction', { + onshow(modalElement) { + los.populateAliases(modalElement); + modalElement.querySelector('#burialSiteContractTransactionEdit--burialSiteContractId').value = burialSiteContractId; + modalElement.querySelector('#burialSiteContractTransactionEdit--transactionIndex').value = transaction.transactionIndex?.toString() ?? ''; + modalElement.querySelector('#burialSiteContractTransactionEdit--transactionAmount').value = transaction.transactionAmount.toFixed(2); + modalElement.querySelector('#burialSiteContractTransactionEdit--externalReceiptNumber').value = transaction.externalReceiptNumber ?? ''; + modalElement.querySelector('#burialSiteContractTransactionEdit--transactionNote').value = transaction.transactionNote ?? ''; + modalElement.querySelector('#burialSiteContractTransactionEdit--transactionDateString').value = transaction.transactionDateString ?? ''; + modalElement.querySelector('#burialSiteContractTransactionEdit--transactionTimeString').value = transaction.transactionTimeString ?? ''; + }, + onshown(modalElement, closeModalFunction) { + bulmaJS.toggleHtmlClipped(); + los.initializeDatePickers(modalElement); + modalElement.querySelector('#burialSiteContractTransactionEdit--transactionAmount').focus(); + modalElement + .querySelector('form') + ?.addEventListener('submit', doEdit); + editCloseModalFunction = closeModalFunction; + }, + onremoved() { + bulmaJS.toggleHtmlClipped(); + } + }); + } + function deleteBurialSiteContractTransaction(clickEvent) { + const transactionIndex = clickEvent.currentTarget.closest('.container--burialSiteContractTransaction').dataset.transactionIndex; + function doDelete() { + cityssm.postJSON(`${los.urlPrefix}/contracts/doDeleteBurialSiteContractTransaction`, { + burialSiteContractId, + transactionIndex + }, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + burialSiteContractTransactions = responseJSON.burialSiteContractTransactions; + renderLotOccupancyTransactions(); + } + else { + bulmaJS.alert({ + title: 'Error Deleting Transaction', + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + }); + } + bulmaJS.confirm({ + title: 'Delete Transaction', + message: 'Are you sure you want to delete this transaction?', + contextualColorName: 'warning', + okButton: { + text: 'Yes, Delete Transaction', + callbackFunction: doDelete + } + }); + } + function renderLotOccupancyTransactions() { + if (burialSiteContractTransactions.length === 0) { + // eslint-disable-next-line no-unsanitized/property + burialSiteContractTransactionsContainerElement.innerHTML = `
+

There are no transactions associated with this record.

+
`; + return; + } + // eslint-disable-next-line no-unsanitized/property + burialSiteContractTransactionsContainerElement.innerHTML = ` + + + + + + + + + + + + +
Date${los.escapedAliases.ExternalReceiptNumber}AmountOptions
Transaction Total
`; + let transactionGrandTotal = 0; + for (const burialSiteContractTransaction of burialSiteContractTransactions) { + transactionGrandTotal += burialSiteContractTransaction.transactionAmount; + const tableRowElement = document.createElement('tr'); + tableRowElement.className = 'container--burialSiteContractTransaction'; + tableRowElement.dataset.transactionIndex = + burialSiteContractTransaction.transactionIndex?.toString(); + let externalReceiptNumberHTML = ''; + if (burialSiteContractTransaction.externalReceiptNumber !== '') { + externalReceiptNumberHTML = cityssm.escapeHTML(burialSiteContractTransaction.externalReceiptNumber ?? ''); + if (los.dynamicsGPIntegrationIsEnabled) { + if (burialSiteContractTransaction.dynamicsGPDocument === undefined) { + externalReceiptNumberHTML += ` + + `; + } + else if (burialSiteContractTransaction.dynamicsGPDocument.documentTotal.toFixed(2) === burialSiteContractTransaction.transactionAmount.toFixed(2)) { + externalReceiptNumberHTML += ` + + `; + } + else { + externalReceiptNumberHTML += ` + + `; + } + } + externalReceiptNumberHTML += '
'; + } + // eslint-disable-next-line no-unsanitized/property + tableRowElement.innerHTML = ` + ${cityssm.escapeHTML(burialSiteContractTransaction.transactionDateString ?? '')} + + + ${externalReceiptNumberHTML} + ${cityssm.escapeHTML(burialSiteContractTransaction.transactionNote ?? '')} + + + $${cityssm.escapeHTML(burialSiteContractTransaction.transactionAmount.toFixed(2))} + + +
+ + +
+ `; + tableRowElement + .querySelector('.button--edit') + ?.addEventListener('click', editLotOccupancyTransaction); + tableRowElement + .querySelector('.button--delete') + ?.addEventListener('click', deleteBurialSiteContractTransaction); + burialSiteContractTransactionsContainerElement + .querySelector('tbody') + ?.append(tableRowElement); + } + ; + burialSiteContractTransactionsContainerElement.querySelector('#burialSiteContractTransactions--grandTotal').textContent = `$${transactionGrandTotal.toFixed(2)}`; + const feeGrandTotal = getFeeGrandTotal(); + if (feeGrandTotal.toFixed(2) !== transactionGrandTotal.toFixed(2)) { + burialSiteContractTransactionsContainerElement.insertAdjacentHTML('afterbegin', `
+
+
+
+
Outstanding Balance
+
+
+
+ $${cityssm.escapeHTML((feeGrandTotal - transactionGrandTotal).toFixed(2))} +
+
+
+
`); + } + } + const addTransactionButtonElement = document.querySelector('#button--addTransaction'); + addTransactionButtonElement.addEventListener('click', () => { + let transactionAmountElement; + let externalReceiptNumberElement; + let addCloseModalFunction; + function doAddTransaction(submitEvent) { + submitEvent.preventDefault(); + cityssm.postJSON(`${los.urlPrefix}/contracts/doAddLotOccupancyTransaction`, submitEvent.currentTarget, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + burialSiteContractTransactions = responseJSON.burialSiteContractTransactions; + addCloseModalFunction(); + renderLotOccupancyTransactions(); + } + else { + bulmaJS.confirm({ + title: 'Error Adding Transaction', + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + }); + } + // eslint-disable-next-line @typescript-eslint/naming-convention + function dynamicsGP_refreshExternalReceiptNumberIcon() { + const externalReceiptNumber = externalReceiptNumberElement.value; + const iconElement = externalReceiptNumberElement + .closest('.control') + ?.querySelector('.icon'); + const helpTextElement = externalReceiptNumberElement + .closest('.field') + ?.querySelector('.help'); + if (externalReceiptNumber === '') { + helpTextElement.innerHTML = ' '; + iconElement.innerHTML = + ''; + return; + } + cityssm.postJSON(`${los.urlPrefix}/contracts/doGetDynamicsGPDocument`, { + externalReceiptNumber + }, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (!responseJSON.success || + responseJSON.dynamicsGPDocument === undefined) { + helpTextElement.textContent = 'No Matching Document Found'; + iconElement.innerHTML = + ''; + } + else if (transactionAmountElement.valueAsNumber === + responseJSON.dynamicsGPDocument.documentTotal) { + helpTextElement.textContent = 'Matching Document Found'; + iconElement.innerHTML = + ''; + } + else { + helpTextElement.textContent = `Matching Document: $${responseJSON.dynamicsGPDocument.documentTotal.toFixed(2)}`; + iconElement.innerHTML = + ''; + } + }); + } + cityssm.openHtmlModal('burialSiteContract-addTransaction', { + onshow(modalElement) { + los.populateAliases(modalElement); + modalElement.querySelector('#burialSiteContractTransactionAdd--burialSiteContractId').value = burialSiteContractId.toString(); + const feeGrandTotal = getFeeGrandTotal(); + const transactionGrandTotal = getTransactionGrandTotal(); + transactionAmountElement = modalElement.querySelector('#burialSiteContractTransactionAdd--transactionAmount'); + transactionAmountElement.min = (-1 * transactionGrandTotal).toFixed(2); + transactionAmountElement.max = Math.max(feeGrandTotal - transactionGrandTotal, 0).toFixed(2); + transactionAmountElement.value = Math.max(feeGrandTotal - transactionGrandTotal, 0).toFixed(2); + if (los.dynamicsGPIntegrationIsEnabled) { + externalReceiptNumberElement = modalElement.querySelector( + // eslint-disable-next-line no-secrets/no-secrets + '#burialSiteContractTransactionAdd--externalReceiptNumber'); + const externalReceiptNumberControlElement = externalReceiptNumberElement.closest('.control'); + externalReceiptNumberControlElement.classList.add('has-icons-right'); + externalReceiptNumberControlElement.insertAdjacentHTML('beforeend', ''); + externalReceiptNumberControlElement.insertAdjacentHTML('afterend', '

'); + externalReceiptNumberElement.addEventListener('change', dynamicsGP_refreshExternalReceiptNumberIcon); + transactionAmountElement.addEventListener('change', dynamicsGP_refreshExternalReceiptNumberIcon); + dynamicsGP_refreshExternalReceiptNumberIcon(); + } + }, + onshown(modalElement, closeModalFunction) { + bulmaJS.toggleHtmlClipped(); + transactionAmountElement.focus(); + addCloseModalFunction = closeModalFunction; + modalElement + .querySelector('form') + ?.addEventListener('submit', doAddTransaction); + }, + onremoved() { + bulmaJS.toggleHtmlClipped(); + addTransactionButtonElement.focus(); + } + }); + }); + renderLotOccupancyFees(); + })(); + } +})(); diff --git a/public/javascripts/burialSiteContract.search.d.ts b/public/javascripts/burialSiteContract.search.d.ts new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/public/javascripts/burialSiteContract.search.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/public/javascripts/burialSiteContract.search.js b/public/javascripts/burialSiteContract.search.js new file mode 100644 index 00000000..d0a01d3d --- /dev/null +++ b/public/javascripts/burialSiteContract.search.js @@ -0,0 +1,152 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +(() => { + const los = exports.los; + const searchFilterFormElement = document.querySelector('#form--searchFilters'); + const searchResultsContainerElement = document.querySelector('#container--searchResults'); + const limit = Number.parseInt(document.querySelector('#searchFilter--limit').value, 10); + const offsetElement = document.querySelector('#searchFilter--offset'); + function renderLotOccupancies(rawResponseJSON) { + const responseJSON = rawResponseJSON; + if (responseJSON.lotOccupancies.length === 0) { + // eslint-disable-next-line no-unsanitized/property + searchResultsContainerElement.innerHTML = `
+

+ There are no ${los.escapedAliases.occupancy} records that meet the search criteria. +

+
`; + return; + } + const resultsTbodyElement = document.createElement('tbody'); + const nowDateString = cityssm.dateToString(new Date()); + for (const burialSiteContract of responseJSON.lotOccupancies) { + let occupancyTimeHTML = ''; + if (burialSiteContract.contractStartDateString <= nowDateString && + (burialSiteContract.contractEndDateString === '' || + burialSiteContract.contractEndDateString >= nowDateString)) { + occupancyTimeHTML = ` + + `; + } + else if (burialSiteContract.contractStartDateString > nowDateString) { + occupancyTimeHTML = ` + + `; + } + else { + occupancyTimeHTML = ` + + `; + } + let occupantsHTML = ''; + for (const occupant of burialSiteContract.burialSiteContractOccupants ?? []) { + occupantsHTML += `
  • + + + + ${cityssm.escapeHTML(occupant.occupantName ?? '')} + ${cityssm.escapeHTML(occupant.occupantFamilyName ?? '')} +
  • `; + } + const feeTotal = (burialSiteContract.burialSiteContractFees?.reduce((soFar, currentFee) => soFar + + ((currentFee.feeAmount ?? 0) + (currentFee.taxAmount ?? 0)) * + (currentFee.quantity ?? 0), 0) ?? 0).toFixed(2); + const transactionTotal = (burialSiteContract.burialSiteContractTransactions?.reduce((soFar, currentTransaction) => soFar + currentTransaction.transactionAmount, 0) ?? 0).toFixed(2); + let feeIconHTML = ''; + if (feeTotal !== '0.00' || transactionTotal !== '0.00') { + feeIconHTML = ` + + `; + } + // eslint-disable-next-line no-unsanitized/method + resultsTbodyElement.insertAdjacentHTML('beforeend', ` + + ${occupancyTimeHTML} + +
    + ${cityssm.escapeHTML(burialSiteContract.occupancyType ?? '')} +
    + #${burialSiteContract.burialSiteContractId} + + ${(burialSiteContract.lotId ?? -1) === -1 + ? `(No ${los.escapedAliases.Lot})` + : `${cityssm.escapeHTML(burialSiteContract.lotName ?? '')}`}
    + ${cityssm.escapeHTML(burialSiteContract.cemeteryName ?? '')} + + ${burialSiteContract.contractStartDateString} + + ${burialSiteContract.contractEndDate + ? burialSiteContract.contractEndDateString + : '(No End Date)'} + + ${occupantsHTML === '' + ? '' + : `
      ${occupantsHTML}
    `} + + ${feeIconHTML} + + ${burialSiteContract.printEJS + ? ` + + ` + : ''}`); + } + // eslint-disable-next-line no-unsanitized/property + searchResultsContainerElement.innerHTML = ` + + + + + + + + + + +
    ${los.escapedAliases.Occupancy} Type${los.escapedAliases.Lot}${los.escapedAliases.contractStartDate}End Date${los.escapedAliases.Occupants}Fees and TransactionsPrint
    `; + searchResultsContainerElement + .querySelector('table') + ?.append(resultsTbodyElement); + // eslint-disable-next-line no-unsanitized/method + searchResultsContainerElement.insertAdjacentHTML('beforeend', los.getSearchResultsPagerHTML(limit, responseJSON.offset, responseJSON.count)); + searchResultsContainerElement + .querySelector("button[data-page='previous']") + ?.addEventListener('click', previousAndGetLotOccupancies); + searchResultsContainerElement + .querySelector("button[data-page='next']") + ?.addEventListener('click', nextAndGetLotOccupancies); + } + function getBurialSiteContracts() { + // eslint-disable-next-line no-unsanitized/property + searchResultsContainerElement.innerHTML = los.getLoadingParagraphHTML(`Loading ${los.escapedAliases.Occupancies}...`); + cityssm.postJSON(`${los.urlPrefix}/contracts/doSearchLotOccupancies`, searchFilterFormElement, renderLotOccupancies); + } + function resetOffsetAndGetLotOccupancies() { + offsetElement.value = '0'; + getBurialSiteContracts(); + } + function previousAndGetLotOccupancies() { + offsetElement.value = Math.max(Number.parseInt(offsetElement.value, 10) - limit, 0).toString(); + getBurialSiteContracts(); + } + function nextAndGetLotOccupancies() { + offsetElement.value = (Number.parseInt(offsetElement.value, 10) + limit).toString(); + getBurialSiteContracts(); + } + const filterElements = searchFilterFormElement.querySelectorAll('input, select'); + for (const filterElement of filterElements) { + filterElement.addEventListener('change', resetOffsetAndGetLotOccupancies); + } + searchFilterFormElement.addEventListener('submit', (formEvent) => { + formEvent.preventDefault(); + }); + getBurialSiteContracts(); +})(); diff --git a/public/javascripts/burialSiteContract.search.ts b/public/javascripts/burialSiteContract.search.ts index f95c347d..91ab2d0a 100644 --- a/public/javascripts/burialSiteContract.search.ts +++ b/public/javascripts/burialSiteContract.search.ts @@ -133,7 +133,7 @@ declare const exports: Record ${ (burialSiteContract.lotId ?? -1) === -1 ? `(No ${los.escapedAliases.Lot})` - : `${cityssm.escapeHTML(burialSiteContract.lotName ?? '')}` + : `${cityssm.escapeHTML(burialSiteContract.lotName ?? '')}` }
    ${cityssm.escapeHTML(burialSiteContract.cemeteryName ?? '')}
    + + `); + } + searchResultsContainerElement.innerHTML = ''; + if (searchResultCount === 0) { + // eslint-disable-next-line no-unsanitized/property + searchResultsContainerElement.innerHTML = `
    +

    There are no cemeteries that meet the search criteria.

    +
    `; + } + else { + const searchResultsTableElement = document.createElement('table'); + searchResultsTableElement.className = + 'table is-fullwidth is-striped is-hoverable has-sticky-header'; + // eslint-disable-next-line no-unsanitized/property + searchResultsTableElement.innerHTML = ` + + + + + + + `; + searchResultsTableElement.append(searchResultsTbodyElement); + searchResultsContainerElement.append(searchResultsTableElement); + } + } + searchFilterElement.addEventListener('keyup', renderResults); + document + .querySelector('#form--searchFilters') + ?.addEventListener('submit', (formEvent) => { + formEvent.preventDefault(); + renderResults(); + }); + renderResults(); +})(); diff --git a/public/javascripts/cemetery.search.ts b/public/javascripts/cemetery.search.ts index eaff5002..18f38484 100644 --- a/public/javascripts/cemetery.search.ts +++ b/public/javascripts/cemetery.search.ts @@ -1,7 +1,8 @@ import type { cityssmGlobal } from '@cityssm/bulma-webapp-js/src/types.js' -import type { LOS } from '../../types/globalTypes.js' -import type { MapRecord } from '../../types/recordTypes.js' +import type { Cemetery } from '../../types/recordTypes.js' + +import type { LOS } from './types.js' declare const cityssm: cityssmGlobal @@ -9,20 +10,21 @@ declare const exports: Record ;(() => { const los = exports.los as LOS - const maps = exports.maps as MapRecord[] + const cemeteries = exports.cemeteries as Cemetery[] const searchFilterElement = document.querySelector( - '#searchFilter--map' + '#searchFilter--cemetery' ) as HTMLInputElement const searchResultsContainerElement = document.querySelector( '#container--searchResults' ) as HTMLElement + // eslint-disable-next-line complexity function renderResults(): void { // eslint-disable-next-line no-unsanitized/property searchResultsContainerElement.innerHTML = los.getLoadingParagraphHTML( - `Loading ${los.escapedAliases.Maps}...` + `Loading Cemeteries...` ) let searchResultCount = 0 @@ -33,21 +35,21 @@ declare const exports: Record .toLowerCase() .split(' ') - for (const map of maps) { - const mapSearchString = `${map.cemeteryName ?? ''} ${ - map.mapDescription ?? '' - } ${map.mapAddress1 ?? ''} ${map.mapAddress2 ?? ''}`.toLowerCase() + for (const cemetery of cemeteries) { + const cemeterySearchString = `${cemetery.cemeteryName ?? ''} ${ + cemetery.cemeteryDescription ?? '' + } ${cemetery.cemeteryAddress1 ?? ''} ${cemetery.cemeteryAddress2 ?? ''}`.toLowerCase() - let showMap = true + let showCemetery = true for (const filterStringPiece of filterStringSplit) { - if (!mapSearchString.includes(filterStringPiece)) { - showMap = false + if (!cemeterySearchString.includes(filterStringPiece)) { + showCemetery = false break } } - if (!showMap) { + if (!showCemetery) { continue } @@ -58,40 +60,40 @@ declare const exports: Record 'beforeend', `` ) @@ -115,7 +117,7 @@ declare const exports: Record if (searchResultCount === 0) { // eslint-disable-next-line no-unsanitized/property searchResultsContainerElement.innerHTML = `
    -

    There are no ${los.escapedAliases.maps} that meet the search criteria.

    +

    There are no cemeteries that meet the search criteria.

    ` } else { const searchResultsTableElement = document.createElement('table') @@ -125,12 +127,12 @@ declare const exports: Record // eslint-disable-next-line no-unsanitized/property searchResultsTableElement.innerHTML = `
    - + - + ` searchResultsTableElement.append(searchResultsTbodyElement) diff --git a/public/javascripts/cemetery.view.d.ts b/public/javascripts/cemetery.view.d.ts new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/public/javascripts/cemetery.view.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/public/javascripts/cemetery.view.js b/public/javascripts/cemetery.view.js new file mode 100644 index 00000000..b58e5b8c --- /dev/null +++ b/public/javascripts/cemetery.view.js @@ -0,0 +1,20 @@ +"use strict"; +// eslint-disable-next-line @eslint-community/eslint-comments/disable-enable-pair +/* eslint-disable @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call */ +Object.defineProperty(exports, "__esModule", { value: true }); +(() => { + const mapContainerElement = document.querySelector('#map--leaflet'); + if (mapContainerElement !== null) { + const mapLatitude = Number.parseFloat(mapContainerElement.dataset.mapLatitude ?? ''); + const mapLongitude = Number.parseFloat(mapContainerElement.dataset.mapLongitude ?? ''); + const mapCoordinates = [mapLatitude, mapLongitude]; + // eslint-disable-next-line unicorn/no-array-callback-reference + const map = L.map(mapContainerElement); + map.setView(mapCoordinates, 15); + L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { + maxZoom: 19, + attribution: '© OpenStreetMap' + }).addTo(map); + L.marker(mapCoordinates).addTo(map); + } +})(); diff --git a/public/javascripts/contractTypes.admin.d.ts b/public/javascripts/contractTypes.admin.d.ts new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/public/javascripts/contractTypes.admin.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/public/javascripts/contractTypes.admin.js b/public/javascripts/contractTypes.admin.js new file mode 100644 index 00000000..780134fa --- /dev/null +++ b/public/javascripts/contractTypes.admin.js @@ -0,0 +1,602 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +(() => { + const los = exports.los; + const occupancyTypesContainerElement = document.querySelector('#container--occupancyTypes'); + const ContractTypePrintsContainerElement = document.querySelector('#container--ContractTypePrints'); + let occupancyTypes = exports.occupancyTypes; + delete exports.occupancyTypes; + let allContractTypeFields = exports.allContractTypeFields; + delete exports.allContractTypeFields; + const expandedOccupancyTypes = new Set(); + function toggleContractTypeFields(clickEvent) { + const toggleButtonElement = clickEvent.currentTarget; + const occupancyTypeElement = toggleButtonElement.closest('.container--occupancyType'); + const contractTypeId = Number.parseInt(occupancyTypeElement.dataset.contractTypeId ?? '', 10); + if (expandedOccupancyTypes.has(contractTypeId)) { + expandedOccupancyTypes.delete(contractTypeId); + } + else { + expandedOccupancyTypes.add(contractTypeId); + } + // eslint-disable-next-line no-unsanitized/property + toggleButtonElement.innerHTML = expandedOccupancyTypes.has(contractTypeId) + ? '' + : ''; + const panelBlockElements = occupancyTypeElement.querySelectorAll('.panel-block'); + for (const panelBlockElement of panelBlockElements) { + panelBlockElement.classList.toggle('is-hidden'); + } + } + function occupancyTypeResponseHandler(rawResponseJSON) { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + occupancyTypes = responseJSON.occupancyTypes; + allContractTypeFields = responseJSON.allContractTypeFields; + renderOccupancyTypes(); + } + else { + bulmaJS.alert({ + title: `Error Updating ${los.escapedAliases.Occupancy} Type`, + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + } + function deleteOccupancyType(clickEvent) { + const contractTypeId = Number.parseInt(clickEvent.currentTarget.closest('.container--occupancyType').dataset.contractTypeId ?? '', 10); + function doDelete() { + cityssm.postJSON(`${los.urlPrefix}/admin/doDeleteContractType`, { + contractTypeId + }, occupancyTypeResponseHandler); + } + bulmaJS.confirm({ + title: `Delete ${los.escapedAliases.Occupancy} Type`, + message: `Are you sure you want to delete this ${los.escapedAliases.occupancy} type?`, + contextualColorName: 'warning', + okButton: { + text: `Yes, Delete ${los.escapedAliases.Occupancy} Type`, + callbackFunction: doDelete + } + }); + } + function openEditOccupancyType(clickEvent) { + const contractTypeId = Number.parseInt(clickEvent.currentTarget.closest('.container--occupancyType').dataset.contractTypeId ?? '', 10); + const occupancyType = occupancyTypes.find((currentOccupancyType) => contractTypeId === currentOccupancyType.contractTypeId); + let editCloseModalFunction; + function doEdit(submitEvent) { + submitEvent.preventDefault(); + cityssm.postJSON(`${los.urlPrefix}/admin/doUpdateContractType`, submitEvent.currentTarget, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + occupancyTypeResponseHandler(responseJSON); + if (responseJSON.success) { + editCloseModalFunction(); + } + }); + } + cityssm.openHtmlModal('adminOccupancyTypes-editOccupancyType', { + onshow(modalElement) { + los.populateAliases(modalElement); + modalElement.querySelector('#occupancyTypeEdit--contractTypeId').value = contractTypeId.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(); + } + }); + } + function openAddOccupancyTypeField(clickEvent) { + const contractTypeId = Number.parseInt(clickEvent.currentTarget.closest('.container--occupancyType').dataset.contractTypeId ?? '', 10); + let addCloseModalFunction; + function doAdd(submitEvent) { + submitEvent.preventDefault(); + cityssm.postJSON(`${los.urlPrefix}/admin/doAddContractTypeField`, submitEvent.currentTarget, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + expandedOccupancyTypes.add(contractTypeId); + occupancyTypeResponseHandler(responseJSON); + if (responseJSON.success) { + addCloseModalFunction(); + openEditOccupancyTypeField(contractTypeId, responseJSON.contractTypeFieldId ?? 0); + } + }); + } + cityssm.openHtmlModal('adminOccupancyTypes-addOccupancyTypeField', { + onshow(modalElement) { + los.populateAliases(modalElement); + if (contractTypeId) { + ; + modalElement.querySelector('#occupancyTypeFieldAdd--contractTypeId').value = contractTypeId.toString(); + } + }, + onshown(modalElement, closeModalFunction) { + addCloseModalFunction = closeModalFunction; + modalElement.querySelector('#occupancyTypeFieldAdd--occupancyTypeField').focus(); + modalElement.querySelector('form')?.addEventListener('submit', doAdd); + bulmaJS.toggleHtmlClipped(); + }, + onremoved() { + bulmaJS.toggleHtmlClipped(); + } + }); + } + function moveOccupancyType(clickEvent) { + const buttonElement = clickEvent.currentTarget; + const contractTypeId = clickEvent.currentTarget.closest('.container--occupancyType').dataset.contractTypeId; + cityssm.postJSON(`${los.urlPrefix}/admin/${buttonElement.dataset.direction === 'up' + ? 'doMoveContractTypeUp' + : 'doMoveContractTypeDown'}`, { + contractTypeId, + moveToEnd: clickEvent.shiftKey ? '1' : '0' + }, occupancyTypeResponseHandler); + } + function openEditOccupancyTypeField(contractTypeId, contractTypeFieldId) { + let occupancyType; + if (contractTypeId) { + occupancyType = occupancyTypes.find((currentOccupancyType) => currentOccupancyType.contractTypeId === contractTypeId); + } + const occupancyTypeField = (occupancyType + ? occupancyType.ContractTypeFields ?? [] + : allContractTypeFields).find((currentOccupancyTypeField) => currentOccupancyTypeField.contractTypeFieldId === contractTypeFieldId); + let fieldTypeElement; + let minimumLengthElement; + let maximumLengthElement; + let patternElement; + let occupancyTypeFieldValuesElement; + let editCloseModalFunction; + function updateMaximumLengthMin() { + maximumLengthElement.min = minimumLengthElement.value; + } + function toggleInputFields() { + switch (fieldTypeElement.value) { + case 'date': { + minimumLengthElement.disabled = true; + maximumLengthElement.disabled = true; + patternElement.disabled = true; + occupancyTypeFieldValuesElement.disabled = true; + break; + } + case 'select': { + minimumLengthElement.disabled = true; + maximumLengthElement.disabled = true; + patternElement.disabled = true; + occupancyTypeFieldValuesElement.disabled = false; + break; + } + default: { + minimumLengthElement.disabled = false; + maximumLengthElement.disabled = false; + patternElement.disabled = false; + occupancyTypeFieldValuesElement.disabled = true; + break; + } + } + } + function doUpdate(submitEvent) { + submitEvent.preventDefault(); + cityssm.postJSON(`${los.urlPrefix}/admin/doUpdateContractTypeField`, submitEvent.currentTarget, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + occupancyTypeResponseHandler(responseJSON); + if (responseJSON.success) { + editCloseModalFunction(); + } + }); + } + function doDelete() { + cityssm.postJSON(`${los.urlPrefix}/admin/doDeleteContractTypeField`, { + contractTypeFieldId + }, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + occupancyTypeResponseHandler(responseJSON); + if (responseJSON.success) { + editCloseModalFunction(); + } + }); + } + function confirmDoDelete() { + bulmaJS.confirm({ + title: 'Delete Field', + message: 'Are you sure you want to delete this field? Note that historical records that make use of this field will not be affected.', + contextualColorName: 'warning', + okButton: { + text: 'Yes, Delete Field', + callbackFunction: doDelete + } + }); + } + cityssm.openHtmlModal('adminOccupancyTypes-editOccupancyTypeField', { + onshow: (modalElement) => { + los.populateAliases(modalElement); + modalElement.querySelector('#occupancyTypeFieldEdit--contractTypeFieldId').value = occupancyTypeField.contractTypeFieldId.toString(); + modalElement.querySelector('#occupancyTypeFieldEdit--occupancyTypeField').value = occupancyTypeField.occupancyTypeField ?? ''; + modalElement.querySelector('#occupancyTypeFieldEdit--isRequired').value = occupancyTypeField.isRequired ?? false ? '1' : '0'; + fieldTypeElement = modalElement.querySelector('#occupancyTypeFieldEdit--fieldType'); + fieldTypeElement.value = occupancyTypeField.fieldType; + minimumLengthElement = modalElement.querySelector('#occupancyTypeFieldEdit--minimumLength'); + minimumLengthElement.value = + occupancyTypeField.minimumLength?.toString() ?? ''; + maximumLengthElement = modalElement.querySelector('#occupancyTypeFieldEdit--maximumLength'); + maximumLengthElement.value = + occupancyTypeField.maximumLength?.toString() ?? ''; + patternElement = modalElement.querySelector('#occupancyTypeFieldEdit--pattern'); + patternElement.value = occupancyTypeField.pattern ?? ''; + occupancyTypeFieldValuesElement = modalElement.querySelector('#occupancyTypeFieldEdit--occupancyTypeFieldValues'); + occupancyTypeFieldValuesElement.value = + occupancyTypeField.occupancyTypeFieldValues ?? ''; + toggleInputFields(); + }, + onshown: (modalElement, closeModalFunction) => { + editCloseModalFunction = closeModalFunction; + bulmaJS.init(modalElement); + bulmaJS.toggleHtmlClipped(); + cityssm.enableNavBlocker(); + modalElement.querySelector('form')?.addEventListener('submit', doUpdate); + minimumLengthElement.addEventListener('keyup', updateMaximumLengthMin); + updateMaximumLengthMin(); + fieldTypeElement.addEventListener('change', toggleInputFields); + modalElement + .querySelector('#button--deleteOccupancyTypeField') + ?.addEventListener('click', confirmDoDelete); + }, + onremoved: () => { + bulmaJS.toggleHtmlClipped(); + cityssm.disableNavBlocker(); + } + }); + } + function openEditOccupancyTypeFieldByClick(clickEvent) { + clickEvent.preventDefault(); + const contractTypeFieldId = Number.parseInt(clickEvent.currentTarget.closest('.container--occupancyTypeField').dataset.contractTypeFieldId ?? '', 10); + const contractTypeId = Number.parseInt(clickEvent.currentTarget.closest('.container--occupancyType').dataset.contractTypeId ?? '', 10); + openEditOccupancyTypeField(contractTypeId, contractTypeFieldId); + } + function moveOccupancyTypeField(clickEvent) { + const buttonElement = clickEvent.currentTarget; + const contractTypeFieldId = clickEvent.currentTarget.closest('.container--occupancyTypeField').dataset.contractTypeFieldId; + cityssm.postJSON(`${los.urlPrefix}/admin/${buttonElement.dataset.direction === 'up' + ? 'doMoveContractTypeFieldUp' + : // eslint-disable-next-line no-secrets/no-secrets + 'doMoveContractTypeFieldDown'}`, { + contractTypeFieldId, + moveToEnd: clickEvent.shiftKey ? '1' : '0' + }, occupancyTypeResponseHandler); + } + function renderContractTypeFields(panelElement, contractTypeId, ContractTypeFields) { + if (ContractTypeFields.length === 0) { + // eslint-disable-next-line no-unsanitized/method + panelElement.insertAdjacentHTML('beforeend', `
    +

    There are no additional fields.

    +
    `); + } + else { + for (const occupancyTypeField of ContractTypeFields) { + const panelBlockElement = document.createElement('div'); + panelBlockElement.className = + 'panel-block is-block container--occupancyTypeField'; + if (contractTypeId && !expandedOccupancyTypes.has(contractTypeId)) { + panelBlockElement.classList.add('is-hidden'); + } + panelBlockElement.dataset.contractTypeFieldId = + occupancyTypeField.contractTypeFieldId.toString(); + // eslint-disable-next-line no-unsanitized/property + panelBlockElement.innerHTML = `
    + +
    +
    + ${los.getMoveUpDownButtonFieldHTML('button--moveOccupancyTypeFieldUp', 'button--moveOccupancyTypeFieldDown')} +
    +
    +
    `; + panelBlockElement + .querySelector('.button--editOccupancyTypeField') + ?.addEventListener('click', openEditOccupancyTypeFieldByClick); + panelBlockElement.querySelector('.button--moveOccupancyTypeFieldUp').addEventListener('click', moveOccupancyTypeField); + panelBlockElement.querySelector('.button--moveOccupancyTypeFieldDown').addEventListener('click', moveOccupancyTypeField); + panelElement.append(panelBlockElement); + } + } + } + function openAddOccupancyTypePrint(clickEvent) { + const contractTypeId = clickEvent.currentTarget.closest('.container--occupancyTypePrintList').dataset.contractTypeId ?? ''; + let closeAddModalFunction; + function doAdd(formEvent) { + formEvent.preventDefault(); + cityssm.postJSON(`${los.urlPrefix}/admin/doAddContractTypePrint`, formEvent.currentTarget, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + closeAddModalFunction(); + } + occupancyTypeResponseHandler(responseJSON); + }); + } + cityssm.openHtmlModal('adminOccupancyTypes-addOccupancyTypePrint', { + onshow(modalElement) { + los.populateAliases(modalElement); + modalElement.querySelector('#occupancyTypePrintAdd--contractTypeId').value = contractTypeId; + const printSelectElement = modalElement.querySelector('#occupancyTypePrintAdd--printEJS'); + for (const [printEJS, printTitle] of Object.entries(exports.occupancyTypePrintTitles)) { + const optionElement = document.createElement('option'); + optionElement.value = printEJS; + optionElement.textContent = printTitle; + printSelectElement.append(optionElement); + } + }, + onshown(modalElement, closeModalFunction) { + closeAddModalFunction = closeModalFunction; + modalElement.querySelector('form')?.addEventListener('submit', doAdd); + } + }); + } + function moveOccupancyTypePrint(clickEvent) { + const buttonElement = clickEvent.currentTarget; + const printEJS = buttonElement.closest('.container--occupancyTypePrint').dataset.printEJS; + const contractTypeId = buttonElement.closest('.container--occupancyTypePrintList').dataset.contractTypeId; + cityssm.postJSON(`${los.urlPrefix}/admin/${buttonElement.dataset.direction === 'up' + ? // eslint-disable-next-line no-secrets/no-secrets + 'doMoveContractTypePrintUp' + : // eslint-disable-next-line no-secrets/no-secrets + 'doMoveContractTypePrintDown'}`, { + contractTypeId, + printEJS, + moveToEnd: clickEvent.shiftKey ? '1' : '0' + }, occupancyTypeResponseHandler); + } + function deleteOccupancyTypePrint(clickEvent) { + clickEvent.preventDefault(); + const printEJS = clickEvent.currentTarget.closest('.container--occupancyTypePrint').dataset.printEJS; + const contractTypeId = clickEvent.currentTarget.closest('.container--occupancyTypePrintList').dataset.contractTypeId; + function doDelete() { + cityssm.postJSON(`${los.urlPrefix}/admin/doDeleteContractTypePrint`, { + contractTypeId, + printEJS + }, occupancyTypeResponseHandler); + } + bulmaJS.confirm({ + title: 'Delete Print', + message: 'Are you sure you want to remove this print option?', + contextualColorName: 'warning', + okButton: { + text: 'Yes, Remove Print', + callbackFunction: doDelete + } + }); + } + function renderContractTypePrints(panelElement, contractTypeId, ContractTypePrints) { + if (ContractTypePrints.length === 0) { + panelElement.insertAdjacentHTML('beforeend', `
    +
    +

    There are no prints associated with this record.

    +
    +
    `); + } + else { + for (const printEJS of ContractTypePrints) { + const panelBlockElement = document.createElement('div'); + panelBlockElement.className = + 'panel-block is-block container--occupancyTypePrint'; + panelBlockElement.dataset.printEJS = printEJS; + const printTitle = printEJS === '*' + ? '(All Available Prints)' + : exports.occupancyTypePrintTitles[printEJS]; + let printIconClass = 'fa-star'; + if (printEJS.startsWith('pdf/')) { + printIconClass = 'fa-file-pdf'; + } + else if (printEJS.startsWith('screen/')) { + printIconClass = 'fa-file'; + } + // eslint-disable-next-line no-unsanitized/property + panelBlockElement.innerHTML = `
    +
    +
    + +
    +
    + ${cityssm.escapeHTML(printTitle || printEJS)} +
    +
    +
    +
    + ${los.getMoveUpDownButtonFieldHTML('button--moveOccupancyTypePrintUp', 'button--moveOccupancyTypePrintDown')} +
    +
    + +
    +
    +
    `; + panelBlockElement.querySelector('.button--moveOccupancyTypePrintUp').addEventListener('click', moveOccupancyTypePrint); + panelBlockElement.querySelector('.button--moveOccupancyTypePrintDown').addEventListener('click', moveOccupancyTypePrint); + panelBlockElement + .querySelector('.button--deleteOccupancyTypePrint') + ?.addEventListener('click', deleteOccupancyTypePrint); + panelElement.append(panelBlockElement); + } + } + } + function renderOccupancyTypes() { + // eslint-disable-next-line no-unsanitized/property + occupancyTypesContainerElement.innerHTML = `
    +
    +
    +
    +
    +

    (All ${los.escapedAliases.Occupancy} Types)

    +
    +
    +
    +
    + +
    +
    +
    +
    +
    `; + ContractTypePrintsContainerElement.innerHTML = ''; + renderContractTypeFields(occupancyTypesContainerElement.querySelector('#container--allContractTypeFields'), undefined, allContractTypeFields); + occupancyTypesContainerElement + .querySelector('.button--addOccupancyTypeField') + ?.addEventListener('click', openAddOccupancyTypeField); + if (occupancyTypes.length === 0) { + // eslint-disable-next-line no-unsanitized/method + occupancyTypesContainerElement.insertAdjacentHTML('afterbegin', `
    There are no active ${los.escapedAliases.occupancy} types.

    +
    `); + // eslint-disable-next-line no-unsanitized/method + ContractTypePrintsContainerElement.insertAdjacentHTML('afterbegin', `
    There are no active ${los.escapedAliases.occupancy} types.

    +
    `); + return; + } + for (const occupancyType of occupancyTypes) { + /* + * Types and Fields + */ + const occupancyTypeContainer = document.createElement('div'); + occupancyTypeContainer.className = 'panel container--occupancyType'; + occupancyTypeContainer.dataset.contractTypeId = + occupancyType.contractTypeId.toString(); + // eslint-disable-next-line no-unsanitized/property + occupancyTypeContainer.innerHTML = `
    +
    +
    +
    + +
    +
    +

    ${cityssm.escapeHTML(occupancyType.occupancyType)}

    +
    +
    +
    +
    + +
    +
    + +
    +
    + +
    +
    + ${los.getMoveUpDownButtonFieldHTML('button--moveOccupancyTypeUp', 'button--moveOccupancyTypeDown')} +
    +
    +
    +
    `; + renderContractTypeFields(occupancyTypeContainer, occupancyType.contractTypeId, occupancyType.ContractTypeFields ?? []); + occupancyTypeContainer + .querySelector('.button--toggleContractTypeFields') + ?.addEventListener('click', toggleContractTypeFields); + occupancyTypeContainer + .querySelector('.button--deleteOccupancyType') + ?.addEventListener('click', deleteOccupancyType); + occupancyTypeContainer + .querySelector('.button--editOccupancyType') + ?.addEventListener('click', openEditOccupancyType); + occupancyTypeContainer + .querySelector('.button--addOccupancyTypeField') + ?.addEventListener('click', openAddOccupancyTypeField); + occupancyTypeContainer.querySelector('.button--moveOccupancyTypeUp').addEventListener('click', moveOccupancyType); + occupancyTypeContainer.querySelector('.button--moveOccupancyTypeDown').addEventListener('click', moveOccupancyType); + occupancyTypesContainerElement.append(occupancyTypeContainer); + /* + * Prints + */ + const occupancyTypePrintContainer = document.createElement('div'); + occupancyTypePrintContainer.className = + 'panel container--occupancyTypePrintList'; + occupancyTypePrintContainer.dataset.contractTypeId = + occupancyType.contractTypeId.toString(); + occupancyTypePrintContainer.innerHTML = `
    +
    +
    +
    +

    ${cityssm.escapeHTML(occupancyType.occupancyType)}

    +
    +
    +
    +
    + +
    +
    +
    +
    `; + renderContractTypePrints(occupancyTypePrintContainer, occupancyType.contractTypeId, occupancyType.ContractTypePrints ?? []); + occupancyTypePrintContainer + .querySelector('.button--addOccupancyTypePrint') + ?.addEventListener('click', openAddOccupancyTypePrint); + ContractTypePrintsContainerElement.append(occupancyTypePrintContainer); + } + } + document + .querySelector('#button--addOccupancyType') + ?.addEventListener('click', () => { + let addCloseModalFunction; + function doAdd(submitEvent) { + submitEvent.preventDefault(); + cityssm.postJSON(`${los.urlPrefix}/admin/doAddContractType`, submitEvent.currentTarget, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + addCloseModalFunction(); + occupancyTypes = responseJSON.occupancyTypes; + renderOccupancyTypes(); + } + else { + bulmaJS.alert({ + title: `Error Adding ${los.escapedAliases.Occupancy} Type`, + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + }); + } + cityssm.openHtmlModal('adminOccupancyTypes-addOccupancyType', { + onshow(modalElement) { + los.populateAliases(modalElement); + }, + onshown(modalElement, closeModalFunction) { + addCloseModalFunction = closeModalFunction; + modalElement.querySelector('#occupancyTypeAdd--occupancyType').focus(); + modalElement.querySelector('form')?.addEventListener('submit', doAdd); + bulmaJS.toggleHtmlClipped(); + }, + onremoved() { + bulmaJS.toggleHtmlClipped(); + } + }); + }); + renderOccupancyTypes(); +})(); diff --git a/public/javascripts/database.admin.d.ts b/public/javascripts/database.admin.d.ts new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/public/javascripts/database.admin.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/public/javascripts/database.admin.js b/public/javascripts/database.admin.js new file mode 100644 index 00000000..29220e32 --- /dev/null +++ b/public/javascripts/database.admin.js @@ -0,0 +1,70 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +(() => { + const los = exports.los; + function doBackup() { + cityssm.postJSON(`${los.urlPrefix}/admin/doBackupDatabase`, {}, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + bulmaJS.alert({ + title: 'Database Backed Up Successfully', + message: `Backed up to ${responseJSON.fileName}
    + To request a copy of the backup, contact your application administrator.`, + messageIsHtml: true, + contextualColorName: 'success' + }); + } + else { + bulmaJS.alert({ + title: 'Error Backing Up Database', + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + }); + } + function doCleanup() { + cityssm.postJSON(`${los.urlPrefix}/admin/doCleanupDatabase`, {}, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + bulmaJS.alert({ + title: 'Database Cleaned Up Successfully', + message: `${responseJSON.inactivatedRecordCount} records inactivated, + ${responseJSON.purgedRecordCount} permanently deleted.`, + contextualColorName: 'success' + }); + } + else { + bulmaJS.alert({ + title: 'Error Cleaning Database', + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + }); + } + document + .querySelector('#button--cleanupDatabase') + ?.addEventListener('click', () => { + bulmaJS.confirm({ + title: 'Cleanup Database', + message: 'Are you sure you want to cleanup up the database?', + okButton: { + text: 'Yes, Cleanup Database', + callbackFunction: doCleanup + } + }); + }); + document + .querySelector('#button--backupDatabase') + ?.addEventListener('click', () => { + bulmaJS.confirm({ + title: 'Backup Database', + message: 'Are you sure you want to backup up the database?', + okButton: { + text: 'Yes, Backup Database', + callbackFunction: doBackup + } + }); + }); +})(); diff --git a/public/javascripts/fees.admin.d.ts b/public/javascripts/fees.admin.d.ts new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/public/javascripts/fees.admin.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/public/javascripts/fees.admin.js b/public/javascripts/fees.admin.js new file mode 100644 index 00000000..9daae9f7 --- /dev/null +++ b/public/javascripts/fees.admin.js @@ -0,0 +1,659 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +(() => { + const los = exports.los; + const feeCategoriesContainerElement = document.querySelector('#container--feeCategories'); + let feeCategories = exports.feeCategories; + delete exports.feeCategories; + function getFeeCategory(feeCategoryId) { + return feeCategories.find((currentFeeCategory) => currentFeeCategory.feeCategoryId === feeCategoryId); + } + function getFee(feeCategory, feeId) { + return feeCategory.fees.find((currentFee) => currentFee.feeId === feeId); + } + function renderFeeCategories() { + if (feeCategories.length === 0) { + feeCategoriesContainerElement.innerHTML = `
    +

    There are no available fees.

    +
    `; + return; + } + feeCategoriesContainerElement.innerHTML = ''; + for (const feeCategory of feeCategories) { + const feeCategoryContainerElement = document.createElement('section'); + feeCategoryContainerElement.className = 'panel container--feeCategory'; + feeCategoryContainerElement.dataset.feeCategoryId = + feeCategory.feeCategoryId.toString(); + // eslint-disable-next-line no-unsanitized/property + feeCategoryContainerElement.innerHTML = `
    +
    +
    +

    ${cityssm.escapeHTML(feeCategory.feeCategory ?? '')}

    + ${feeCategory.isGroupedFee + ? 'Grouped Fee' + : ''} +
    +
    +
    + ${feeCategory.fees.length === 0 + ? `
    + +
    ` + : ''} +
    + +
    +
    + +
    +
    + ${los.getMoveUpDownButtonFieldHTML('button--moveFeeCategoryUp', 'button--moveFeeCategoryDown')} +
    +
    +
    +
    `; + if (feeCategory.fees.length === 0) { + feeCategoryContainerElement.insertAdjacentHTML('beforeend', `
    +
    +

    + There are no fees in the + "${cityssm.escapeHTML(feeCategory.feeCategory ?? '')}" + category. +

    +
    +
    `); + feeCategoryContainerElement + .querySelector('.button--deleteFeeCategory') + ?.addEventListener('click', confirmDeleteFeeCategory); + } + for (const fee of feeCategory.fees) { + const panelBlockElement = document.createElement('div'); + panelBlockElement.className = 'panel-block is-block container--fee'; + panelBlockElement.dataset.feeId = fee.feeId.toString(); + const hasTagsBlock = (fee.isRequired ?? false) || + fee.contractTypeId !== undefined || + fee.burialSiteTypeId !== undefined; + // eslint-disable-next-line no-unsanitized/property + panelBlockElement.innerHTML = `
    +
    +

    + ${cityssm.escapeHTML(fee.feeName ?? '')}
    + + ${ + // eslint-disable-next-line @typescript-eslint/no-unsafe-call + cityssm + .escapeHTML(fee.feeDescription ?? '') + .replaceAll('\n', '
    ')} +
    +

    + ${hasTagsBlock + ? `

    + ${fee.isRequired ?? false + ? 'Required' + : ''} + ${(fee.contractTypeId ?? -1) === -1 + ? '' + : ` + + ${cityssm.escapeHTML(fee.occupancyType ?? '')} + `} + ${(fee.burialSiteTypeId ?? -1) === -1 + ? '' + : ` + + ${cityssm.escapeHTML(fee.lotType ?? '')} + `} +

    ` + : ''} +
    +
    +
    +
    + ${fee.feeFunction + ? `${cityssm.escapeHTML(fee.feeFunction)}
    + Fee Function` + : ` + $${(fee.feeAmount ?? 0).toFixed(2)}
    + Fee +
    `} +
    +
    + ${fee.taxPercentage + ? `${fee.taxPercentage.toString()}%` + : `$${(fee.taxAmount ?? 0).toFixed(2)}`}
    + Tax +
    +
    + ${fee.includeQuantity + ? `${cityssm.escapeHTML(fee.quantityUnit ?? '')}
    + Quantity` + : ''} +
    +
    +
    +
    + ${los.getMoveUpDownButtonFieldHTML('button--moveFeeUp', 'button--moveFeeDown')} +
    +
    `; + panelBlockElement + .querySelector('.a--editFee') + ?.addEventListener('click', openEditFee); + panelBlockElement + .querySelector('.a--editFeeAmount') + ?.addEventListener('click', openEditFeeAmount); + panelBlockElement.querySelector('.button--moveFeeUp').addEventListener('click', moveFee); + panelBlockElement.querySelector('.button--moveFeeDown').addEventListener('click', moveFee); + feeCategoryContainerElement.append(panelBlockElement); + } + feeCategoryContainerElement + .querySelector('.button--editFeeCategory') + ?.addEventListener('click', openEditFeeCategory); + feeCategoryContainerElement + .querySelector('.button--addFee') + ?.addEventListener('click', openAddFee); + feeCategoryContainerElement.querySelector('.button--moveFeeCategoryUp').addEventListener('click', moveFeeCategory); + feeCategoryContainerElement.querySelector('.button--moveFeeCategoryDown').addEventListener('click', moveFeeCategory); + feeCategoriesContainerElement.append(feeCategoryContainerElement); + } + } + /* + * Fee Categories + */ + document + .querySelector('#button--addFeeCategory') + ?.addEventListener('click', () => { + let addCloseModalFunction; + function doAddFeeCategory(submitEvent) { + submitEvent.preventDefault(); + cityssm.postJSON(`${los.urlPrefix}/admin/doAddFeeCategory`, submitEvent.currentTarget, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + feeCategories = responseJSON.feeCategories; + addCloseModalFunction(); + renderFeeCategories(); + } + else { + bulmaJS.alert({ + title: 'Error Creating Fee Category', + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + }); + } + cityssm.openHtmlModal('adminFees-addFeeCategory', { + onshown(modalElement, closeModalFunction) { + bulmaJS.toggleHtmlClipped(); + modalElement.querySelector('#feeCategoryAdd--feeCategory').focus(); + addCloseModalFunction = closeModalFunction; + modalElement + .querySelector('form') + ?.addEventListener('submit', doAddFeeCategory); + }, + onremoved() { + bulmaJS.toggleHtmlClipped(); + document.querySelector('#button--addFeeCategory').focus(); + } + }); + }); + function openEditFeeCategory(clickEvent) { + const feeCategoryId = Number.parseInt(clickEvent.currentTarget.closest('.container--feeCategory').dataset.feeCategoryId ?? '', 10); + const feeCategory = getFeeCategory(feeCategoryId); + let editCloseModalFunction; + function doUpdateFeeCategory(submitEvent) { + submitEvent.preventDefault(); + cityssm.postJSON(`${los.urlPrefix}/admin/doUpdateFeeCategory`, submitEvent.currentTarget, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + feeCategories = responseJSON.feeCategories; + editCloseModalFunction(); + renderFeeCategories(); + } + else { + bulmaJS.alert({ + title: 'Error Updating Fee Category', + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + }); + } + cityssm.openHtmlModal('adminFees-editFeeCategory', { + onshow(modalElement) { + ; + modalElement.querySelector('#feeCategoryEdit--feeCategoryId').value = feeCategory.feeCategoryId.toString(); + modalElement.querySelector('#feeCategoryEdit--feeCategory').value = feeCategory.feeCategory; + if (feeCategory.isGroupedFee) { + ; + modalElement.querySelector('#feeCategoryEdit--isGroupedFee').checked = true; + } + }, + onshown(modalElement, closeModalFunction) { + bulmaJS.toggleHtmlClipped(); + editCloseModalFunction = closeModalFunction; + modalElement + .querySelector('form') + ?.addEventListener('submit', doUpdateFeeCategory); + modalElement.querySelector('#feeCategoryEdit--feeCategory').focus(); + }, + onremoved: () => { + bulmaJS.toggleHtmlClipped(); + } + }); + } + function confirmDeleteFeeCategory(clickEvent) { + const feeCategoryId = Number.parseInt(clickEvent.currentTarget.closest('.container--feeCategory').dataset.feeCategoryId ?? '', 10); + function doDelete() { + cityssm.postJSON(`${los.urlPrefix}/admin/doDeleteFeeCategory`, { + feeCategoryId + }, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + feeCategories = responseJSON.feeCategories; + renderFeeCategories(); + } + else { + bulmaJS.alert({ + title: 'Error Updating Fee Category', + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + }); + } + bulmaJS.confirm({ + title: 'Delete Fee Category?', + message: 'Are you sure you want to delete this fee category?', + contextualColorName: 'warning', + okButton: { + text: 'Yes, Delete the Fee Category', + callbackFunction: doDelete + } + }); + } + function moveFeeCategory(clickEvent) { + const buttonElement = clickEvent.currentTarget; + const feeCategoryId = buttonElement.closest('.container--feeCategory').dataset + .feeCategoryId ?? ''; + cityssm.postJSON(`${los.urlPrefix}/admin/${buttonElement.dataset.direction === 'up' + ? 'doMoveFeeCategoryUp' + : 'doMoveFeeCategoryDown'}`, { + feeCategoryId, + moveToEnd: clickEvent.shiftKey ? '1' : '0' + }, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + feeCategories = responseJSON.feeCategories; + renderFeeCategories(); + } + else { + bulmaJS.alert({ + title: 'Error Moving Fee Category', + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + }); + } + /* + * Fees + */ + function openAddFee(clickEvent) { + const feeCategoryId = Number.parseInt(clickEvent.currentTarget.closest('.container--feeCategory').dataset.feeCategoryId ?? '', 10); + let addCloseModalFunction; + function doAddFee(submitEvent) { + submitEvent.preventDefault(); + cityssm.postJSON(`${los.urlPrefix}/admin/doAddFee`, submitEvent.currentTarget, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + feeCategories = responseJSON.feeCategories; + addCloseModalFunction(); + renderFeeCategories(); + } + else { + bulmaJS.alert({ + title: 'Error Adding Fee', + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + }); + } + cityssm.openHtmlModal('adminFees-addFee', { + onshow(modalElement) { + const feeCategoryElement = modalElement.querySelector('#feeAdd--feeCategoryId'); + for (const feeCategory of feeCategories) { + const optionElement = document.createElement('option'); + optionElement.value = feeCategory.feeCategoryId.toString(); + optionElement.textContent = feeCategory.feeCategory; + if (feeCategory.feeCategoryId === feeCategoryId) { + optionElement.selected = true; + } + feeCategoryElement.append(optionElement); + } + const occupancyTypeElement = modalElement.querySelector('#feeAdd--contractTypeId'); + for (const occupancyType of exports.occupancyTypes) { + const optionElement = document.createElement('option'); + optionElement.value = occupancyType.contractTypeId.toString(); + optionElement.textContent = occupancyType.occupancyType; + occupancyTypeElement.append(optionElement); + } + const lotTypeElement = modalElement.querySelector('#feeAdd--burialSiteTypeId'); + for (const lotType of exports.lotTypes) { + const optionElement = document.createElement('option'); + optionElement.value = lotType.burialSiteTypeId.toString(); + optionElement.textContent = lotType.lotType; + lotTypeElement.append(optionElement); + } + ; + modalElement.querySelector('#feeAdd--taxPercentage').value = exports.taxPercentageDefault.toString(); + los.populateAliases(modalElement); + }, + onshown(modalElement, closeModalFunction) { + bulmaJS.toggleHtmlClipped(); + addCloseModalFunction = closeModalFunction; + modalElement.querySelector('form')?.addEventListener('submit', doAddFee); + modalElement.querySelector('#feeAdd--feeName').focus(); + modalElement.querySelector('#feeAdd--feeFunction').addEventListener('change', () => { + const feeAmountElement = modalElement.querySelector('#feeAdd--feeAmount'); + const feeFunctionElement = modalElement.querySelector('#feeAdd--feeFunction'); + if (feeFunctionElement.value === '') { + feeFunctionElement + .closest('.select') + ?.classList.remove('is-success'); + feeAmountElement.classList.add('is-success'); + feeAmountElement.disabled = false; + } + else { + feeFunctionElement.closest('.select')?.classList.add('is-success'); + feeAmountElement.classList.remove('is-success'); + feeAmountElement.disabled = true; + } + }); + modalElement + .querySelector('#feeAdd--taxPercentage') + ?.addEventListener('keyup', () => { + const taxAmountElement = modalElement.querySelector('#feeAdd--taxAmount'); + const taxPercentageElement = modalElement.querySelector('#feeAdd--taxPercentage'); + if (taxPercentageElement.value === '') { + taxPercentageElement.classList.remove('is-success'); + taxAmountElement.classList.add('is-success'); + taxAmountElement.disabled = false; + } + else { + taxPercentageElement.classList.add('is-success'); + taxAmountElement.classList.remove('is-success'); + taxAmountElement.disabled = true; + } + }); + modalElement + .querySelector('#feeAdd--includeQuantity') + ?.addEventListener('change', () => { + ; + modalElement.querySelector('#feeAdd--quantityUnit').disabled = + modalElement.querySelector('#feeAdd--includeQuantity').value === ''; + }); + }, + onremoved() { + bulmaJS.toggleHtmlClipped(); + } + }); + } + function openEditFeeAmount(clickEvent) { + clickEvent.preventDefault(); + const feeContainerElement = clickEvent.currentTarget.closest('.container--fee'); + const feeId = Number.parseInt(feeContainerElement.dataset.feeId ?? '', 10); + const feeCategoryId = Number.parseInt(feeContainerElement.closest('.container--feeCategory') + .dataset.feeCategoryId ?? ''); + const feeCategory = getFeeCategory(feeCategoryId); + const fee = getFee(feeCategory, feeId); + let editCloseModalFunction; + function doUpdateFeeAmount(submitEvent) { + submitEvent.preventDefault(); + cityssm.postJSON(`${los.urlPrefix}/admin/doUpdateFeeAmount`, submitEvent.currentTarget, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + feeCategories = responseJSON.feeCategories; + editCloseModalFunction(); + renderFeeCategories(); + } + else { + bulmaJS.alert({ + title: 'Error Updating Fee Amount', + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + }); + } + cityssm.openHtmlModal('adminFees-editFeeAmount', { + onshow(modalElement) { + ; + modalElement.querySelector('#feeAmountEdit--feeId').value = fee.feeId.toString(); + modalElement.querySelector('#feeAmountEdit--feeCategory').textContent = feeCategory.feeCategory; + modalElement.querySelector('#feeAmountEdit--feeName').textContent = fee.feeName ?? ''; + modalElement.querySelector('#feeAmountEdit--feeAmount').value = fee.feeAmount?.toFixed(2) ?? '0'; + }, + onshown(modalElement, closeModalFunction) { + ; + modalElement.querySelector('#feeAmountEdit--feeAmount').select(); + editCloseModalFunction = closeModalFunction; + modalElement + .querySelector('form') + ?.addEventListener('submit', doUpdateFeeAmount); + } + }); + } + function openEditFee(clickEvent) { + clickEvent.preventDefault(); + const feeContainerElement = clickEvent.currentTarget.closest('.container--fee'); + const feeId = Number.parseInt(feeContainerElement.dataset.feeId ?? '', 10); + const feeCategoryId = Number.parseInt(feeContainerElement.closest('.container--feeCategory') + .dataset.feeCategoryId ?? ''); + const feeCategory = getFeeCategory(feeCategoryId); + const fee = getFee(feeCategory, feeId); + let editCloseModalFunction; + let editModalElement; + function doUpdateFee(submitEvent) { + submitEvent.preventDefault(); + cityssm.postJSON(`${los.urlPrefix}/admin/doUpdateFee`, submitEvent.currentTarget, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + feeCategories = responseJSON.feeCategories; + editCloseModalFunction(); + renderFeeCategories(); + } + else { + bulmaJS.alert({ + title: 'Error Updating Fee', + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + }); + } + function confirmDeleteFee(clickEvent) { + clickEvent.preventDefault(); + function doDelete() { + cityssm.postJSON(`${los.urlPrefix}/admin/doDeleteFee`, { + feeId + }, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + feeCategories = responseJSON.feeCategories; + editCloseModalFunction(); + renderFeeCategories(); + } + 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 the Fee', + callbackFunction: doDelete + } + }); + } + function toggleFeeFields() { + const feeAmountElement = editModalElement.querySelector('#feeEdit--feeAmount'); + const feeFunctionElement = editModalElement.querySelector('#feeEdit--feeFunction'); + if (feeFunctionElement.value === '') { + feeFunctionElement.closest('.select')?.classList.remove('is-success'); + feeAmountElement.classList.add('is-success'); + feeAmountElement.disabled = false; + } + else { + feeFunctionElement.closest('.select')?.classList.add('is-success'); + feeAmountElement.classList.remove('is-success'); + feeAmountElement.disabled = true; + } + } + function toggleTaxFields() { + const taxAmountElement = editModalElement.querySelector('#feeEdit--taxAmount'); + const taxPercentageElement = editModalElement.querySelector('#feeEdit--taxPercentage'); + if (taxPercentageElement.value === '') { + taxPercentageElement.classList.remove('is-success'); + taxAmountElement.classList.add('is-success'); + taxAmountElement.disabled = false; + } + else { + taxPercentageElement.classList.add('is-success'); + taxAmountElement.classList.remove('is-success'); + taxAmountElement.disabled = true; + } + } + function toggleQuantityFields() { + const includeQuantityValue = editModalElement.querySelector('#feeEdit--includeQuantity').value; + editModalElement.querySelector('#feeEdit--quantityUnit').disabled = includeQuantityValue === ''; + } + cityssm.openHtmlModal('adminFees-editFee', { + onshow(modalElement) { + editModalElement = modalElement; + modalElement.querySelector('#feeEdit--feeId').value = fee.feeId.toString(); + const feeCategoryElement = modalElement.querySelector('#feeEdit--feeCategoryId'); + for (const feeCategory of feeCategories) { + const optionElement = document.createElement('option'); + optionElement.value = feeCategory.feeCategoryId.toString(); + optionElement.textContent = feeCategory.feeCategory; + if (feeCategory.feeCategoryId === feeCategoryId) { + optionElement.selected = true; + } + feeCategoryElement.append(optionElement); + } + ; + modalElement.querySelector('#feeEdit--feeName').value = fee.feeName ?? ''; + modalElement.querySelector('#feeEdit--feeAccount').value = fee.feeAccount ?? ''; + modalElement.querySelector('#feeEdit--feeDescription').value = fee.feeDescription ?? ''; + const occupancyTypeElement = modalElement.querySelector('#feeEdit--contractTypeId'); + for (const occupancyType of exports.occupancyTypes) { + const optionElement = document.createElement('option'); + optionElement.value = occupancyType.contractTypeId.toString(); + optionElement.textContent = occupancyType.occupancyType; + if (occupancyType.contractTypeId === fee.contractTypeId) { + optionElement.selected = true; + } + occupancyTypeElement.append(optionElement); + } + const lotTypeElement = modalElement.querySelector('#feeEdit--burialSiteTypeId'); + for (const lotType of exports.lotTypes) { + const optionElement = document.createElement('option'); + optionElement.value = lotType.burialSiteTypeId.toString(); + optionElement.textContent = lotType.lotType; + if (lotType.burialSiteTypeId === fee.burialSiteTypeId) { + optionElement.selected = true; + } + lotTypeElement.append(optionElement); + } + ; + modalElement.querySelector('#feeEdit--feeAmount').value = fee.feeAmount ? fee.feeAmount.toFixed(2) : ''; + modalElement + .querySelector('#feeEdit--feeFunction') + ?.addEventListener('change', toggleFeeFields); + toggleFeeFields(); + modalElement.querySelector('#feeEdit--taxAmount').value = fee.taxAmount ? fee.taxAmount.toFixed(2) : ''; + const taxPercentageElement = modalElement.querySelector('#feeEdit--taxPercentage'); + taxPercentageElement.value = fee.taxPercentage + ? fee.taxPercentage.toString() + : ''; + taxPercentageElement.addEventListener('keyup', toggleTaxFields); + toggleTaxFields(); + const includeQuantityElement = modalElement.querySelector('#feeEdit--includeQuantity'); + if (fee.includeQuantity ?? false) { + includeQuantityElement.value = '1'; + } + includeQuantityElement.addEventListener('change', toggleQuantityFields); + modalElement.querySelector('#feeEdit--quantityUnit').value = fee.quantityUnit ?? ''; + toggleQuantityFields(); + if (fee.isRequired ?? false) { + ; + modalElement.querySelector('#feeEdit--isRequired').value = '1'; + } + los.populateAliases(modalElement); + }, + onshown(modalElement, closeModalFunction) { + bulmaJS.toggleHtmlClipped(); + editCloseModalFunction = closeModalFunction; + modalElement + .querySelector('form') + ?.addEventListener('submit', doUpdateFee); + bulmaJS.init(modalElement); + modalElement + .querySelector('.button--deleteFee') + ?.addEventListener('click', confirmDeleteFee); + }, + onremoved() { + bulmaJS.toggleHtmlClipped(); + } + }); + } + function moveFee(clickEvent) { + const buttonElement = clickEvent.currentTarget; + const feeContainerElement = buttonElement.closest('.container--fee'); + const feeId = feeContainerElement.dataset.feeId ?? ''; + cityssm.postJSON(`${los.urlPrefix}/admin/${buttonElement.dataset.direction === 'up' + ? 'doMoveFeeUp' + : 'doMoveFeeDown'}`, { + feeId, + moveToEnd: clickEvent.shiftKey ? '1' : '0' + }, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + feeCategories = responseJSON.feeCategories; + renderFeeCategories(); + } + else { + bulmaJS.alert({ + title: 'Error Moving Fee', + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + }); + } + /* + * Initialize + */ + renderFeeCategories(); +})(); diff --git a/public/javascripts/main.js b/public/javascripts/main.js index 62a9c809..cd63d226 100644 --- a/public/javascripts/main.js +++ b/public/javascripts/main.js @@ -25,7 +25,6 @@ Object.defineProperty(exports, "__esModule", { value: true }); // Search for ID let svgId = mapKey; let svgElementToHighlight; - // eslint-disable-next-line no-constant-condition while (true) { svgElementToHighlight = mapContainerElement.querySelector(`#${svgId}`); if (svgElementToHighlight !== null || !svgId.includes('-')) { @@ -44,7 +43,6 @@ Object.defineProperty(exports, "__esModule", { value: true }); } function unlockField(clickEvent) { const fieldElement = clickEvent.currentTarget.closest('.field'); - // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion const inputOrSelectElement = fieldElement.querySelector('input, select'); inputOrSelectElement.classList.remove('is-readonly'); if (inputOrSelectElement.tagName === 'INPUT') { @@ -141,63 +139,15 @@ Object.defineProperty(exports, "__esModule", { value: true }); function populateAliases(containerElement) { const aliasElements = containerElement.querySelectorAll('.alias'); for (const aliasElement of aliasElements) { - switch (aliasElement.dataset.alias) { - case 'Map': { - aliasElement.textContent = exports.aliases.map; - break; - } - case 'Lot': { - aliasElement.textContent = exports.aliases.lot; - break; - } - case 'lot': { - aliasElement.textContent = exports.aliases.lot.toLowerCase(); - break; - } - case 'Occupancy': { - aliasElement.textContent = exports.aliases.occupancy; - break; - } - case 'occupancy': { - aliasElement.textContent = exports.aliases.occupancy.toLowerCase(); - break; - } - case 'Occupant': { - aliasElement.textContent = exports.aliases.occupant; - break; - } - case 'occupant': { - aliasElement.textContent = exports.aliases.occupant.toLowerCase(); - break; - } - case 'ExternalReceiptNumber': { - aliasElement.textContent = exports.aliases.externalReceiptNumber; - break; - } + if (aliasElement.dataset.alias === 'ExternalReceiptNumber') { + aliasElement.textContent = exports.aliases.externalReceiptNumber; + break; } } } const escapedAliases = Object.freeze({ - Map: cityssm.escapeHTML(exports.aliases.map), - map: cityssm.escapeHTML(exports.aliases.map.toLowerCase()), - Maps: cityssm.escapeHTML(exports.aliases.maps), - maps: cityssm.escapeHTML(exports.aliases.maps.toLowerCase()), - Lot: cityssm.escapeHTML(exports.aliases.lot), - lot: cityssm.escapeHTML(exports.aliases.lot.toLowerCase()), - Lots: cityssm.escapeHTML(exports.aliases.lots), - lots: cityssm.escapeHTML(exports.aliases.lots.toLowerCase()), - Occupancy: cityssm.escapeHTML(exports.aliases.occupancy), - occupancy: cityssm.escapeHTML(exports.aliases.occupancy.toLowerCase()), - Occupancies: cityssm.escapeHTML(exports.aliases.occupancies), - occupancies: cityssm.escapeHTML(exports.aliases.occupancies.toLowerCase()), - Occupant: cityssm.escapeHTML(exports.aliases.occupant), - occupant: cityssm.escapeHTML(exports.aliases.occupant.toLowerCase()), - Occupants: cityssm.escapeHTML(exports.aliases.occupants), - occupants: cityssm.escapeHTML(exports.aliases.occupants.toLowerCase()), ExternalReceiptNumber: cityssm.escapeHTML(exports.aliases.externalReceiptNumber), externalReceiptNumber: cityssm.escapeHTML(exports.aliases.externalReceiptNumber.toLowerCase()), - OccupancyStartDate: cityssm.escapeHTML(exports.aliases.occupancyStartDate), - occupancyStartDate: cityssm.escapeHTML(exports.aliases.occupancyStartDate.toLowerCase()), WorkOrderOpenDate: cityssm.escapeHTML(exports.aliases.workOrderOpenDate), workOrderOpenDate: cityssm.escapeHTML(exports.aliases.workOrderOpenDate.toLowerCase()), WorkOrderCloseDate: cityssm.escapeHTML(exports.aliases.workOrderCloseDate), @@ -298,14 +248,14 @@ Object.defineProperty(exports, "__esModule", { value: true }); (recordId && edit ? '/edit' : '') + (time ? `/?t=${Date.now().toString()}` : '')); } - function getMapURL(mapId = '', edit = false, time = false) { - return getRecordURL('maps', mapId, edit, time); + function getCemeteryURL(cemeteryId = '', edit = false, time = false) { + return getRecordURL('cemeteries', cemeteryId, edit, time); } - function getLotURL(lotId = '', edit = false, time = false) { - return getRecordURL('lots', lotId, edit, time); + function getBurialSiteURL(burialSiteId = '', edit = false, time = false) { + return getRecordURL('burialSites', burialSiteId, edit, time); } - function getLotOccupancyURL(lotOccupancyId = '', edit = false, time = false) { - return getRecordURL('lotOccupancies', lotOccupancyId, edit, time); + function getBurialSiteContractURL(burialSiteContractId = '', edit = false, time = false) { + return getRecordURL('contracts', burialSiteContractId, edit, time); } function getWorkOrderURL(workOrderId = '', edit = false, time = false) { return getRecordURL('workOrders', workOrderId, edit, time); @@ -333,9 +283,9 @@ Object.defineProperty(exports, "__esModule", { value: true }); getMoveUpDownButtonFieldHTML, getLoadingParagraphHTML, getSearchResultsPagerHTML, - getMapURL, - getLotURL, - getLotOccupancyURL, + getCemeteryURL, + getBurialSiteURL, + getBurialSiteContractURL, getWorkOrderURL }; exports.los = los; diff --git a/public/javascripts/main.ts b/public/javascripts/main.ts index 5907c5d9..1d81e24a 100644 --- a/public/javascripts/main.ts +++ b/public/javascripts/main.ts @@ -2,7 +2,7 @@ import type { BulmaJS } from '@cityssm/bulma-js/types.js' import type { cityssmGlobal } from '@cityssm/bulma-webapp-js/src/types.js' import type { Options as BulmaCalendarOptions } from 'bulma-calendar' -import type { LOS } from '../../types/globalTypes.js' +import type { LOS } from './types.js' type RandomColorHue = | 'red' @@ -64,7 +64,6 @@ declare const exports: Record & { let svgId = mapKey let svgElementToHighlight: SVGElement | null - // eslint-disable-next-line no-constant-condition while (true) { svgElementToHighlight = mapContainerElement.querySelector(`#${svgId}`) @@ -92,7 +91,6 @@ declare const exports: Record & { '.field' ) as HTMLElement - // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion const inputOrSelectElement = fieldElement.querySelector( 'input, select' ) as HTMLElement @@ -230,64 +228,14 @@ declare const exports: Record & { containerElement.querySelectorAll('.alias') for (const aliasElement of aliasElements) { - switch (aliasElement.dataset.alias) { - case 'Map': { - aliasElement.textContent = exports.aliases.map - break - } - case 'Lot': { - aliasElement.textContent = exports.aliases.lot - break - } - case 'lot': { - aliasElement.textContent = exports.aliases.lot.toLowerCase() - break - } - case 'Occupancy': { - aliasElement.textContent = exports.aliases.occupancy - break - } - case 'occupancy': { - aliasElement.textContent = exports.aliases.occupancy.toLowerCase() - break - } - case 'Occupant': { - aliasElement.textContent = exports.aliases.occupant - break - } - case 'occupant': { - aliasElement.textContent = exports.aliases.occupant.toLowerCase() - break - } - case 'ExternalReceiptNumber': { - aliasElement.textContent = exports.aliases.externalReceiptNumber - break - } + if (aliasElement.dataset.alias === 'ExternalReceiptNumber') { + aliasElement.textContent = exports.aliases.externalReceiptNumber + break } } } const escapedAliases = Object.freeze({ - Map: cityssm.escapeHTML(exports.aliases.map), - map: cityssm.escapeHTML(exports.aliases.map.toLowerCase()), - Maps: cityssm.escapeHTML(exports.aliases.maps), - maps: cityssm.escapeHTML(exports.aliases.maps.toLowerCase()), - - Lot: cityssm.escapeHTML(exports.aliases.lot), - lot: cityssm.escapeHTML(exports.aliases.lot.toLowerCase()), - Lots: cityssm.escapeHTML(exports.aliases.lots), - lots: cityssm.escapeHTML(exports.aliases.lots.toLowerCase()), - - Occupancy: cityssm.escapeHTML(exports.aliases.occupancy), - occupancy: cityssm.escapeHTML(exports.aliases.occupancy.toLowerCase()), - Occupancies: cityssm.escapeHTML(exports.aliases.occupancies), - occupancies: cityssm.escapeHTML(exports.aliases.occupancies.toLowerCase()), - - Occupant: cityssm.escapeHTML(exports.aliases.occupant), - occupant: cityssm.escapeHTML(exports.aliases.occupant.toLowerCase()), - Occupants: cityssm.escapeHTML(exports.aliases.occupants), - occupants: cityssm.escapeHTML(exports.aliases.occupants.toLowerCase()), - ExternalReceiptNumber: cityssm.escapeHTML( exports.aliases.externalReceiptNumber ), @@ -295,11 +243,6 @@ declare const exports: Record & { exports.aliases.externalReceiptNumber.toLowerCase() ), - contractStartDate: cityssm.escapeHTML(exports.aliases.contractStartDate), - contractStartDate: cityssm.escapeHTML( - exports.aliases.contractStartDate.toLowerCase() - ), - WorkOrderOpenDate: cityssm.escapeHTML(exports.aliases.workOrderOpenDate), workOrderOpenDate: cityssm.escapeHTML( exports.aliases.workOrderOpenDate.toLowerCase() @@ -429,7 +372,7 @@ declare const exports: Record & { const urlPrefix = document.querySelector('main')?.dataset.urlPrefix ?? '' function getRecordURL( - recordTypePlural: 'maps' | 'lots' | 'lotOccupancies' | 'workOrders', + recordTypePlural: 'cemeteries' | 'burialSites' | 'contracts' | 'workOrders', recordId: number | string, edit: boolean, time: boolean @@ -444,20 +387,20 @@ declare const exports: Record & { ) } - function getMapURL( + function getCemeteryURL( cemeteryId: number | string = '', edit = false, time = false ): string { - return getRecordURL('maps', cemeteryId, edit, time) + return getRecordURL('cemeteries', cemeteryId, edit, time) } - function getLotURL( - lotId: number | string = '', + function getBurialSiteURL( + burialSiteId: number | string = '', edit = false, time = false ): string { - return getRecordURL('lots', lotId, edit, time) + return getRecordURL('burialSites', burialSiteId, edit, time) } function getBurialSiteContractURL( @@ -465,7 +408,7 @@ declare const exports: Record & { edit = false, time = false ): string { - return getRecordURL('lotOccupancies', burialSiteContractId, edit, time) + return getRecordURL('contracts', burialSiteContractId, edit, time) } function getWorkOrderURL( @@ -508,8 +451,8 @@ declare const exports: Record & { getLoadingParagraphHTML, getSearchResultsPagerHTML, - getMapURL, - getLotURL, + getCemeteryURL, + getBurialSiteURL, getBurialSiteContractURL, getWorkOrderURL } diff --git a/public/javascripts/report.search.d.ts b/public/javascripts/report.search.d.ts new file mode 100644 index 00000000..e69de29b diff --git a/public/javascripts/report.search.js b/public/javascripts/report.search.js new file mode 100644 index 00000000..ba0bae8e --- /dev/null +++ b/public/javascripts/report.search.js @@ -0,0 +1,28 @@ +; +(() => { + const menuTabElements = document.querySelectorAll('.menu a'); + const tabContainerElements = document.querySelectorAll('.tabs-container > div'); + function selectTab(clickEvent) { + clickEvent.preventDefault(); + // Remove .is-active from all tabs + for (const menuTabElement of menuTabElements) { + menuTabElement.classList.remove('is-active'); + } + // Set .is-active on clicked tab + const selectedTabElement = clickEvent.currentTarget; + selectedTabElement.classList.add('is-active'); + // Hide all but selected tab + const selectedTabContainerId = selectedTabElement.href.slice(Math.max(0, selectedTabElement.href.indexOf('#') + 1)); + for (const tabContainerElement of tabContainerElements) { + if (tabContainerElement.id === selectedTabContainerId) { + tabContainerElement.classList.remove('is-hidden'); + } + else { + tabContainerElement.classList.add('is-hidden'); + } + } + } + for (const menuTabElement of menuTabElements) { + menuTabElement.addEventListener('click', selectTab); + } +})(); diff --git a/public/javascripts/tables.admin.d.ts b/public/javascripts/tables.admin.d.ts new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/public/javascripts/tables.admin.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/public/javascripts/tables.admin.js b/public/javascripts/tables.admin.js new file mode 100644 index 00000000..9e40ee02 --- /dev/null +++ b/public/javascripts/tables.admin.js @@ -0,0 +1,716 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +(() => { + const los = exports.los; + function refreshFontAwesomeIcon(changeEvent) { + const inputElement = changeEvent.currentTarget; + const fontAwesomeIconClass = inputElement.value; + (inputElement + .closest('.field') + ?.querySelectorAll('.button.is-static'))[1].innerHTML = + ``; + } + /** + * Work Order Types + */ + ; + (() => { + let workOrderTypes = exports.workOrderTypes; + delete exports.workOrderTypes; + function updateWorkOrderType(submitEvent) { + submitEvent.preventDefault(); + cityssm.postJSON(`${los.urlPrefix}/admin/doUpdateWorkOrderType`, submitEvent.currentTarget, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + workOrderTypes = responseJSON.workOrderTypes; + bulmaJS.alert({ + message: 'Work Order Type Updated Successfully', + contextualColorName: 'success' + }); + } + else { + bulmaJS.alert({ + title: 'Error Updating Work Order Type', + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + }); + } + function deleteWorkOrderType(clickEvent) { + const tableRowElement = clickEvent.currentTarget.closest('tr'); + const workOrderTypeId = tableRowElement.dataset.workOrderTypeId; + function doDelete() { + cityssm.postJSON(`${los.urlPrefix}/admin/doDeleteWorkOrderType`, { + workOrderTypeId + }, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + workOrderTypes = responseJSON.workOrderTypes; + if (workOrderTypes.length === 0) { + renderWorkOrderTypes(); + } + else { + tableRowElement.remove(); + } + bulmaJS.alert({ + message: 'Work Order Type Deleted Successfully', + contextualColorName: 'success' + }); + } + else { + bulmaJS.alert({ + title: 'Error Deleting Work Order Type', + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + }); + } + bulmaJS.confirm({ + title: 'Delete Work Order Type', + message: `Are you sure you want to delete this work order type?
    + Note that no work orders will be removed.`, + messageIsHtml: true, + contextualColorName: 'warning', + okButton: { + text: 'Yes, Delete Work Order Type', + callbackFunction: doDelete + } + }); + } + function moveWorkOrderType(clickEvent) { + const buttonElement = clickEvent.currentTarget; + const tableRowElement = buttonElement.closest('tr'); + const workOrderTypeId = tableRowElement.dataset.workOrderTypeId; + cityssm.postJSON(`${los.urlPrefix}/admin/${buttonElement.dataset.direction === 'up' + ? 'doMoveWorkOrderTypeUp' + : 'doMoveWorkOrderTypeDown'}`, { + workOrderTypeId, + moveToEnd: clickEvent.shiftKey ? '1' : '0' + }, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + workOrderTypes = responseJSON.workOrderTypes; + renderWorkOrderTypes(); + } + else { + bulmaJS.alert({ + title: 'Error Moving Work Order Type', + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + }); + } + function renderWorkOrderTypes() { + const containerElement = document.querySelector('#container--workOrderTypes'); + if (workOrderTypes.length === 0) { + containerElement.innerHTML = `
    `; + return; + } + containerElement.innerHTML = ''; + for (const workOrderType of workOrderTypes) { + const tableRowElement = document.createElement('tr'); + tableRowElement.dataset.workOrderTypeId = + workOrderType.workOrderTypeId.toString(); + // eslint-disable-next-line no-unsanitized/property + tableRowElement.innerHTML = ``; + tableRowElement + .querySelector('form') + ?.addEventListener('submit', updateWorkOrderType); + tableRowElement.querySelector('.button--moveWorkOrderTypeUp').addEventListener('click', moveWorkOrderType); + tableRowElement.querySelector('.button--moveWorkOrderTypeDown').addEventListener('click', moveWorkOrderType); + tableRowElement + .querySelector('.button--deleteWorkOrderType') + ?.addEventListener('click', deleteWorkOrderType); + containerElement.append(tableRowElement); + } + } + ; + document.querySelector('#form--addWorkOrderType').addEventListener('submit', (submitEvent) => { + submitEvent.preventDefault(); + const formElement = submitEvent.currentTarget; + cityssm.postJSON(`${los.urlPrefix}/admin/doAddWorkOrderType`, formElement, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + workOrderTypes = responseJSON.workOrderTypes; + renderWorkOrderTypes(); + formElement.reset(); + formElement.querySelector('input')?.focus(); + } + else { + bulmaJS.alert({ + title: 'Error Adding Work Order Type', + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + }); + }); + renderWorkOrderTypes(); + })(); + (() => { + let workOrderMilestoneTypes = exports.workOrderMilestoneTypes; + delete exports.workOrderMilestoneTypes; + function updateWorkOrderMilestoneType(submitEvent) { + submitEvent.preventDefault(); + cityssm.postJSON(`${los.urlPrefix}/admin/doUpdateWorkOrderMilestoneType`, submitEvent.currentTarget, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + workOrderMilestoneTypes = responseJSON.workOrderMilestoneTypes; + bulmaJS.alert({ + message: 'Work Order Milestone Type Updated Successfully', + contextualColorName: 'success' + }); + } + else { + bulmaJS.alert({ + title: 'Error Updating Work Order Milestone Type', + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + }); + } + function deleteWorkOrderMilestoneType(clickEvent) { + const tableRowElement = clickEvent.currentTarget.closest('tr'); + const workOrderMilestoneTypeId = tableRowElement.dataset.workOrderMilestoneTypeId; + function doDelete() { + cityssm.postJSON(`${los.urlPrefix}/admin/doDeleteWorkOrderMilestoneType`, { + workOrderMilestoneTypeId + }, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + workOrderMilestoneTypes = responseJSON.workOrderMilestoneTypes; + if (workOrderMilestoneTypes.length === 0) { + renderWorkOrderMilestoneTypes(); + } + else { + tableRowElement.remove(); + } + bulmaJS.alert({ + message: 'Work Order Milestone Type Deleted Successfully', + contextualColorName: 'success' + }); + } + else { + bulmaJS.alert({ + title: 'Error Deleting Work Order Milestone Type', + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + }); + } + bulmaJS.confirm({ + title: 'Delete Work Order Milestone Type', + message: `Are you sure you want to delete this work order milestone type?
    + Note that no work orders will be removed.`, + messageIsHtml: true, + contextualColorName: 'warning', + okButton: { + text: 'Yes, Delete Work Order Milestone Type', + callbackFunction: doDelete + } + }); + } + function moveWorkOrderMilestoneType(clickEvent) { + const buttonElement = clickEvent.currentTarget; + const tableRowElement = buttonElement.closest('tr'); + const workOrderMilestoneTypeId = tableRowElement.dataset.workOrderMilestoneTypeId; + cityssm.postJSON(`${los.urlPrefix}/admin/${buttonElement.dataset.direction === 'up' + ? 'doMoveWorkOrderMilestoneTypeUp' + : 'doMoveWorkOrderMilestoneTypeDown'}`, { + workOrderMilestoneTypeId, + moveToEnd: clickEvent.shiftKey ? '1' : '0' + }, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + workOrderMilestoneTypes = responseJSON.workOrderMilestoneTypes; + renderWorkOrderMilestoneTypes(); + } + else { + bulmaJS.alert({ + title: 'Error Moving Work Order Milestone Type', + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + }); + } + function renderWorkOrderMilestoneTypes() { + const containerElement = document.querySelector('#container--workOrderMilestoneTypes'); + if (workOrderMilestoneTypes.length === 0) { + containerElement.innerHTML = ``; + return; + } + containerElement.innerHTML = ''; + for (const workOrderMilestoneType of workOrderMilestoneTypes) { + const tableRowElement = document.createElement('tr'); + tableRowElement.dataset.workOrderMilestoneTypeId = + workOrderMilestoneType.workOrderMilestoneTypeId.toString(); + // eslint-disable-next-line no-unsanitized/property, no-secrets/no-secrets + tableRowElement.innerHTML = ``; + tableRowElement + .querySelector('form') + ?.addEventListener('submit', updateWorkOrderMilestoneType); + tableRowElement.querySelector('.button--moveWorkOrderMilestoneTypeUp').addEventListener('click', moveWorkOrderMilestoneType); + tableRowElement.querySelector('.button--moveWorkOrderMilestoneTypeDown').addEventListener('click', moveWorkOrderMilestoneType); + tableRowElement + .querySelector('.button--deleteWorkOrderMilestoneType') + ?.addEventListener('click', deleteWorkOrderMilestoneType); + containerElement.append(tableRowElement); + } + } + ; + document.querySelector('#form--addWorkOrderMilestoneType').addEventListener('submit', (submitEvent) => { + submitEvent.preventDefault(); + const formElement = submitEvent.currentTarget; + cityssm.postJSON(`${los.urlPrefix}/admin/doAddWorkOrderMilestoneType`, formElement, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + workOrderMilestoneTypes = responseJSON.workOrderMilestoneTypes; + renderWorkOrderMilestoneTypes(); + formElement.reset(); + formElement.querySelector('input')?.focus(); + } + else { + bulmaJS.alert({ + title: 'Error Adding Work Order Milestone Type', + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + }); + }); + renderWorkOrderMilestoneTypes(); + })(); + (() => { + let lotStatuses = exports.lotStatuses; + delete exports.lotStatuses; + function updateBurialSiteStatus(submitEvent) { + submitEvent.preventDefault(); + cityssm.postJSON(`${los.urlPrefix}/admin/doUpdateBurialSiteStatus`, submitEvent.currentTarget, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + lotStatuses = responseJSON.lotStatuses; + bulmaJS.alert({ + message: `${los.escapedAliases.Lot} Status Updated Successfully`, + contextualColorName: 'success' + }); + } + else { + bulmaJS.alert({ + title: `Error Updating ${los.escapedAliases.Lot} Status`, + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + }); + } + function deleteLotStatus(clickEvent) { + const tableRowElement = clickEvent.currentTarget.closest('tr'); + const burialSiteStatusId = tableRowElement.dataset.burialSiteStatusId; + function doDelete() { + cityssm.postJSON(`${los.urlPrefix}/admin/doDeleteBurialSiteStatus`, { + burialSiteStatusId + }, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + lotStatuses = responseJSON.lotStatuses; + if (lotStatuses.length === 0) { + renderLotStatuses(); + } + else { + tableRowElement.remove(); + } + bulmaJS.alert({ + message: `${los.escapedAliases.Lot} Status Deleted Successfully`, + contextualColorName: 'success' + }); + } + else { + bulmaJS.alert({ + title: `Error Deleting ${los.escapedAliases.Lot} Status`, + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + }); + } + bulmaJS.confirm({ + title: `Delete ${los.escapedAliases.Lot} Status`, + message: `Are you sure you want to delete this status?
    + Note that no ${los.escapedAliases.lot} will be removed.`, + messageIsHtml: true, + contextualColorName: 'warning', + okButton: { + text: 'Yes, Delete Status', + callbackFunction: doDelete + } + }); + } + function moveLotStatus(clickEvent) { + const buttonElement = clickEvent.currentTarget; + const tableRowElement = buttonElement.closest('tr'); + const burialSiteStatusId = tableRowElement.dataset.burialSiteStatusId; + cityssm.postJSON(`${los.urlPrefix}/admin/${buttonElement.dataset.direction === 'up' + ? 'doMoveBurialSiteStatusUp' + : 'doMoveBurialSiteStatusDown'}`, { + burialSiteStatusId, + moveToEnd: clickEvent.shiftKey ? '1' : '0' + }, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + lotStatuses = responseJSON.lotStatuses; + renderLotStatuses(); + } + else { + bulmaJS.alert({ + title: `Error Moving ${los.escapedAliases.Lot} Status`, + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + }); + } + function renderLotStatuses() { + const containerElement = document.querySelector('#container--lotStatuses'); + if (lotStatuses.length === 0) { + // eslint-disable-next-line no-unsanitized/property + containerElement.innerHTML = ``; + return; + } + containerElement.innerHTML = ''; + for (const lotStatus of lotStatuses) { + const tableRowElement = document.createElement('tr'); + tableRowElement.dataset.burialSiteStatusId = lotStatus.burialSiteStatusId.toString(); + // eslint-disable-next-line no-unsanitized/property + tableRowElement.innerHTML = ``; + tableRowElement + .querySelector('form') + ?.addEventListener('submit', updateBurialSiteStatus); + tableRowElement.querySelector('.button--moveLotStatusUp').addEventListener('click', moveLotStatus); + tableRowElement.querySelector('.button--moveLotStatusDown').addEventListener('click', moveLotStatus); + tableRowElement + .querySelector('.button--deleteLotStatus') + ?.addEventListener('click', deleteLotStatus); + containerElement.append(tableRowElement); + } + } + ; + document.querySelector('#form--addBurialSiteStatus').addEventListener('submit', (submitEvent) => { + submitEvent.preventDefault(); + const formElement = submitEvent.currentTarget; + cityssm.postJSON(`${los.urlPrefix}/admin/doAddBurialSiteStatus`, formElement, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + lotStatuses = responseJSON.lotStatuses; + renderLotStatuses(); + formElement.reset(); + formElement.querySelector('input')?.focus(); + } + else { + bulmaJS.alert({ + title: `Error Adding ${los.escapedAliases.Lot} Status`, + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + }); + }); + renderLotStatuses(); + })(); + (() => { + let lotOccupantTypes = exports.lotOccupantTypes; + delete exports.lotOccupantTypes; + function updateBurialSiteOccupantType(submitEvent) { + submitEvent.preventDefault(); + cityssm.postJSON(`${los.urlPrefix}/admin/doUpdateBurialSiteOccupantType`, submitEvent.currentTarget, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + lotOccupantTypes = responseJSON.lotOccupantTypes; + bulmaJS.alert({ + message: `${los.escapedAliases.Lot} ${los.escapedAliases.Occupant} Type Updated Successfully`, + contextualColorName: 'success' + }); + } + else { + bulmaJS.alert({ + title: `Error Updating ${los.escapedAliases.Lot} ${los.escapedAliases.Occupant} Type`, + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + }); + } + function deleteLotOccupantType(clickEvent) { + const tableRowElement = clickEvent.currentTarget.closest('tr'); + const lotOccupantTypeId = tableRowElement.dataset.lotOccupantTypeId; + function doDelete() { + cityssm.postJSON(`${los.urlPrefix}/admin/doDeleteBurialSiteOccupantType`, { + lotOccupantTypeId + }, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + lotOccupantTypes = responseJSON.lotOccupantTypes; + if (lotOccupantTypes.length === 0) { + renderLotOccupantTypes(); + } + else { + tableRowElement.remove(); + } + bulmaJS.alert({ + message: `${los.escapedAliases.Lot} ${los.escapedAliases.Occupant} Type Deleted Successfully`, + contextualColorName: 'success' + }); + } + else { + bulmaJS.alert({ + title: `Error Deleting ${los.escapedAliases.Lot} ${los.escapedAliases.Occupant} Type`, + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + }); + } + bulmaJS.confirm({ + title: `Delete ${los.escapedAliases.Lot} ${los.escapedAliases.Occupant} Type`, + message: `Are you sure you want to delete this ${los.escapedAliases.lot} ${los.escapedAliases.occupant} type?
    + Note that no ${los.escapedAliases.lot} ${los.escapedAliases.occupants} will be removed.`, + messageIsHtml: true, + contextualColorName: 'warning', + okButton: { + text: `Yes, Delete ${los.escapedAliases.Lot} ${los.escapedAliases.Occupant} Type`, + callbackFunction: doDelete + } + }); + } + function moveLotOccupantType(clickEvent) { + const buttonElement = clickEvent.currentTarget; + const tableRowElement = buttonElement.closest('tr'); + const lotOccupantTypeId = tableRowElement.dataset.lotOccupantTypeId; + cityssm.postJSON(`${los.urlPrefix}/admin/${buttonElement.dataset.direction === 'up' + ? 'doMoveLotOccupantTypeUp' + : 'doMoveLotOccupantTypeDown'}`, { + lotOccupantTypeId, + moveToEnd: clickEvent.shiftKey ? '1' : '0' + }, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + lotOccupantTypes = responseJSON.lotOccupantTypes; + renderLotOccupantTypes(); + } + else { + bulmaJS.alert({ + title: `Error Moving ${los.escapedAliases.Lot} ${los.escapedAliases.Occupant} Type`, + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + }); + } + function renderLotOccupantTypes() { + const containerElement = document.querySelector('#container--lotOccupantTypes'); + if (lotOccupantTypes.length === 0) { + // eslint-disable-next-line no-unsanitized/property + containerElement.innerHTML = ``; + return; + } + containerElement.innerHTML = ''; + for (const lotOccupantType of lotOccupantTypes) { + const tableRowElement = document.createElement('tr'); + tableRowElement.dataset.lotOccupantTypeId = + lotOccupantType.lotOccupantTypeId.toString(); + const formId = `form--lotOccupantType-${lotOccupantType.lotOccupantTypeId.toString()}`; + // eslint-disable-next-line no-unsanitized/property + tableRowElement.innerHTML = ``; + const fontAwesomeInputElement = tableRowElement.querySelector("input[name='fontAwesomeIconClass']"); + fontAwesomeInputElement.addEventListener('keyup', refreshFontAwesomeIcon); + fontAwesomeInputElement.addEventListener('change', refreshFontAwesomeIcon); + tableRowElement + .querySelector('form') + ?.addEventListener('submit', updateBurialSiteOccupantType); + tableRowElement.querySelector('.button--moveLotOccupantTypeUp').addEventListener('click', moveLotOccupantType); + tableRowElement.querySelector('.button--moveLotOccupantTypeDown').addEventListener('click', moveLotOccupantType); + tableRowElement + .querySelector('.button--deleteLotOccupantType') + ?.addEventListener('click', deleteLotOccupantType); + containerElement.append(tableRowElement); + } + } + ; + document.querySelector('#form--addBurialSiteOccupantType').addEventListener('submit', (submitEvent) => { + submitEvent.preventDefault(); + const formElement = submitEvent.currentTarget; + cityssm.postJSON(`${los.urlPrefix}/admin/doAddLotOccupantType`, formElement, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + lotOccupantTypes = responseJSON.lotOccupantTypes; + renderLotOccupantTypes(); + formElement.reset(); + formElement.querySelector('input')?.focus(); + } + else { + bulmaJS.alert({ + title: `Error Adding ${los.escapedAliases.Lot} ${los.escapedAliases.Occupant} Type`, + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + }); + }); + renderLotOccupantTypes(); + })(); +})(); diff --git a/public/javascripts/tables.admin.ts b/public/javascripts/tables.admin.ts index c9d9604c..9104526c 100644 --- a/public/javascripts/tables.admin.ts +++ b/public/javascripts/tables.admin.ts @@ -723,7 +723,7 @@ declare const bulmaJS: BulmaJS } } ;( - document.querySelector('#form--addLotStatus') as HTMLFormElement + document.querySelector('#form--addBurialSiteStatus') as HTMLFormElement ).addEventListener('submit', (submitEvent: SubmitEvent) => { submitEvent.preventDefault() @@ -1010,7 +1010,7 @@ declare const bulmaJS: BulmaJS } } ;( - document.querySelector('#form--addLotOccupantType') as HTMLFormElement + document.querySelector('#form--addBurialSiteOccupantType') as HTMLFormElement ).addEventListener('submit', (submitEvent: SubmitEvent) => { submitEvent.preventDefault() diff --git a/public/javascripts/types.d.ts b/public/javascripts/types.d.ts new file mode 100644 index 00000000..686a35ad --- /dev/null +++ b/public/javascripts/types.d.ts @@ -0,0 +1,28 @@ +export interface LOS { + urlPrefix: string; + apiKey: string; + highlightMap: (mapContainerElement: HTMLElement, mapKey: string, contextualClass: 'success' | 'danger') => void; + initializeDatePickers: (containerElement: HTMLElement) => void; + initializeUnlockFieldButtons: (containerElement: HTMLElement) => void; + populateAliases: (containerElement: HTMLElement) => void; + escapedAliases: { + ExternalReceiptNumber: string; + externalReceiptNumber: string; + WorkOrderOpenDate: string; + workOrderOpenDate: string; + WorkOrderCloseDate: string; + workOrderCloseDate: string; + }; + dynamicsGPIntegrationIsEnabled: boolean; + getRandomColor: (seedString: string) => string; + setUnsavedChanges: () => void; + clearUnsavedChanges: () => void; + hasUnsavedChanges: () => boolean; + getMoveUpDownButtonFieldHTML: (upButtonClassNames: string, downButtonClassNames: string, isSmall?: boolean) => string; + getLoadingParagraphHTML: (captionText?: string) => string; + getSearchResultsPagerHTML: (limit: number, offset: number, count: number) => string; + getCemeteryURL: (cemeteryId?: number | string, edit?: boolean, time?: boolean) => string; + getBurialSiteURL: (burialSiteId?: number | string, edit?: boolean, time?: boolean) => string; + getBurialSiteContractURL: (burialSiteContractId?: number | string, edit?: boolean, time?: boolean) => string; + getWorkOrderURL: (workOrderId?: number | string, edit?: boolean, time?: boolean) => string; +} diff --git a/public/javascripts/types.js b/public/javascripts/types.js new file mode 100644 index 00000000..c8ad2e54 --- /dev/null +++ b/public/javascripts/types.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/public/javascripts/types.ts b/public/javascripts/types.ts index e0d48fb0..0d0a1582 100644 --- a/public/javascripts/types.ts +++ b/public/javascripts/types.ts @@ -18,8 +18,6 @@ export interface LOS { escapedAliases: { ExternalReceiptNumber: string externalReceiptNumber: string - contractStartDate: string - contractStartDate: string WorkOrderOpenDate: string workOrderOpenDate: string WorkOrderCloseDate: string @@ -46,8 +44,8 @@ export interface LOS { count: number ) => string - getMapURL: (cemeteryId?: number | string, edit?: boolean, time?: boolean) => string - getLotURL: (lotId?: number | string, edit?: boolean, time?: boolean) => string + getCemeteryURL: (cemeteryId?: number | string, edit?: boolean, time?: boolean) => string + getBurialSiteURL: (burialSiteId?: number | string, edit?: boolean, time?: boolean) => string getBurialSiteContractURL: ( burialSiteContractId?: number | string, edit?: boolean, diff --git a/public/javascripts/workOrder.edit.d.ts b/public/javascripts/workOrder.edit.d.ts new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/public/javascripts/workOrder.edit.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/public/javascripts/workOrder.edit.js b/public/javascripts/workOrder.edit.js new file mode 100644 index 00000000..8bac72b5 --- /dev/null +++ b/public/javascripts/workOrder.edit.js @@ -0,0 +1,1243 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +(() => { + const los = exports.los; + const workOrderId = document.querySelector('#workOrderEdit--workOrderId').value; + const isCreate = workOrderId === ''; + const workOrderFormElement = document.querySelector('#form--workOrderEdit'); + los.initializeDatePickers(workOrderFormElement + .querySelector('#workOrderEdit--workOrderOpenDateString') + ?.closest('.field')); + los.initializeUnlockFieldButtons(workOrderFormElement); + function setUnsavedChanges() { + los.setUnsavedChanges(); + document + .querySelector("button[type='submit'][form='form--workOrderEdit']") + ?.classList.remove('is-light'); + } + function clearUnsavedChanges() { + los.clearUnsavedChanges(); + document + .querySelector("button[type='submit'][form='form--workOrderEdit']") + ?.classList.add('is-light'); + } + workOrderFormElement.addEventListener('submit', (submitEvent) => { + submitEvent.preventDefault(); + cityssm.postJSON(`${los.urlPrefix}/workOrders/${isCreate ? 'doCreateWorkOrder' : 'doUpdateWorkOrder'}`, submitEvent.currentTarget, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + clearUnsavedChanges(); + if (isCreate) { + globalThis.location.href = los.getWorkOrderURL(responseJSON.workOrderId, true); + } + else { + bulmaJS.alert({ + message: 'Work Order Updated Successfully', + contextualColorName: 'success' + }); + } + } + else { + bulmaJS.alert({ + title: 'Error Updating Work Order', + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + }); + }); + const inputElements = workOrderFormElement.querySelectorAll('input, select, textarea'); + for (const inputElement of inputElements) { + inputElement.addEventListener('change', setUnsavedChanges); + } + /* + * Work Order Options + */ + function doClose() { + cityssm.postJSON(`${los.urlPrefix}/workOrders/doCloseWorkOrder`, { + workOrderId + }, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + clearUnsavedChanges(); + globalThis.location.href = los.getWorkOrderURL(workOrderId); + } + else { + bulmaJS.alert({ + title: 'Error Closing Work Order', + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + }); + } + function doDelete() { + cityssm.postJSON(`${los.urlPrefix}/workOrders/doDeleteWorkOrder`, { + workOrderId + }, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + clearUnsavedChanges(); + globalThis.location.href = `${los.urlPrefix}/workOrders`; + } + else { + bulmaJS.alert({ + title: 'Error Deleting Work Order', + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + }); + } + let workOrderMilestones; + document + .querySelector('#button--closeWorkOrder') + ?.addEventListener('click', () => { + const hasOpenMilestones = workOrderMilestones.some((milestone) => !milestone.workOrderMilestoneCompletionDate); + if (hasOpenMilestones) { + bulmaJS.alert({ + title: 'Outstanding Milestones', + message: `You cannot close a work order with outstanding milestones. + Either complete the outstanding milestones, or remove them from the work order.`, + contextualColorName: 'warning' + }); + /* + // Disable closing work orders with open milestones + bulmaJS.confirm({ + title: "Close Work Order with Outstanding Milestones", + message: + "Are you sure you want to close this work order with outstanding milestones?", + contextualColorName: "danger", + okButton: { + text: "Yes, Close Work Order", + callbackFunction: doClose + } + }); + */ + } + else { + bulmaJS.confirm({ + title: 'Close Work Order', + message: los.hasUnsavedChanges() + ? 'Are you sure you want to close this work order with unsaved changes?' + : 'Are you sure you want to close this work order?', + contextualColorName: los.hasUnsavedChanges() ? 'warning' : 'info', + okButton: { + text: 'Yes, Close Work Order', + callbackFunction: doClose + } + }); + } + }); + document + .querySelector('#button--deleteWorkOrder') + ?.addEventListener('click', (clickEvent) => { + clickEvent.preventDefault(); + bulmaJS.confirm({ + title: 'Delete Work Order', + message: 'Are you sure you want to delete this work order?', + contextualColorName: 'warning', + okButton: { + text: 'Yes, Delete Work Order', + callbackFunction: doDelete + } + }); + }); + /** + * Related Lots + */ + if (!isCreate) { + ; + (() => { + let workOrderLots = exports.workOrderLots; + delete exports.workOrderLots; + let workOrderBurialSiteContracts = exports.workOrderBurialSiteContracts; + delete exports.workOrderBurialSiteContracts; + function deleteLotOccupancy(clickEvent) { + const burialSiteContractId = clickEvent.currentTarget.closest('.container--burialSiteContract').dataset.burialSiteContractId; + function doDelete() { + cityssm.postJSON(`${los.urlPrefix}/workOrders/doDeleteWorkOrderBurialSiteContract`, { + workOrderId, + burialSiteContractId + }, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + workOrderBurialSiteContracts = responseJSON.workOrderBurialSiteContracts; + renderRelatedLotsAndOccupancies(); + } + else { + bulmaJS.alert({ + title: 'Error Deleting Relationship', + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + }); + } + bulmaJS.confirm({ + title: `Delete ${los.escapedAliases.Occupancy} Relationship`, + message: `Are you sure you want to remove the relationship to this ${los.escapedAliases.occupancy} record from this work order? Note that the record will remain.`, + contextualColorName: 'warning', + okButton: { + text: 'Yes, Delete Relationship', + callbackFunction: doDelete + } + }); + } + function addBurialSite(lotId, callbackFunction) { + cityssm.postJSON(`${los.urlPrefix}/workOrders/doAddWorkOrderBurialSite`, { + workOrderId, + lotId + }, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + workOrderLots = responseJSON.workOrderLots; + renderRelatedLotsAndOccupancies(); + } + else { + bulmaJS.alert({ + title: `Error Adding ${los.escapedAliases.Lot}`, + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + if (callbackFunction !== undefined) { + callbackFunction(responseJSON.success); + } + }); + } + function addBurialSiteContract(burialSiteContractId, callbackFunction) { + cityssm.postJSON(`${los.urlPrefix}/workOrders/doAddWorkOrderBurialSiteContract`, { + workOrderId, + burialSiteContractId + }, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + workOrderBurialSiteContracts = responseJSON.workOrderBurialSiteContracts; + renderRelatedLotsAndOccupancies(); + } + else { + bulmaJS.alert({ + title: `Error Adding ${los.escapedAliases.Occupancy}`, + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + if (callbackFunction !== undefined) { + callbackFunction(responseJSON.success); + } + }); + } + function addBurialSiteFromLotOccupancy(clickEvent) { + const lotId = clickEvent.currentTarget.dataset.lotId ?? ''; + addBurialSite(lotId); + } + function renderRelatedOccupancies() { + const occupanciesContainerElement = document.querySelector('#container--lotOccupancies'); + document.querySelector(".tabs a[href='#relatedTab--lotOccupancies'] .tag").textContent = workOrderBurialSiteContracts.length.toString(); + if (workOrderBurialSiteContracts.length === 0) { + // eslint-disable-next-line no-unsanitized/property + occupanciesContainerElement.innerHTML = `
    +

    There are no ${los.escapedAliases.occupancies} associated with this work order.

    +
    `; + return; + } + // eslint-disable-next-line no-unsanitized/property + occupanciesContainerElement.innerHTML = `
    diff --git a/public/javascripts/burialSiteTypes.admin.d.ts b/public/javascripts/burialSiteTypes.admin.d.ts new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/public/javascripts/burialSiteTypes.admin.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/public/javascripts/burialSiteTypes.admin.js b/public/javascripts/burialSiteTypes.admin.js new file mode 100644 index 00000000..070e8366 --- /dev/null +++ b/public/javascripts/burialSiteTypes.admin.js @@ -0,0 +1,409 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +(() => { + const los = exports.los; + const containerElement = document.querySelector('#container--lotTypes'); + let lotTypes = exports.lotTypes; + delete exports.lotTypes; + const expandedLotTypes = new Set(); + function toggleBurialSiteTypeFields(clickEvent) { + const toggleButtonElement = clickEvent.currentTarget; + const lotTypeElement = toggleButtonElement.closest('.container--lotType'); + const burialSiteTypeId = Number.parseInt(lotTypeElement.dataset.burialSiteTypeId ?? '', 10); + if (expandedLotTypes.has(burialSiteTypeId)) { + expandedLotTypes.delete(burialSiteTypeId); + } + else { + expandedLotTypes.add(burialSiteTypeId); + } + // eslint-disable-next-line no-unsanitized/property + toggleButtonElement.innerHTML = expandedLotTypes.has(burialSiteTypeId) + ? '' + : ''; + const panelBlockElements = lotTypeElement.querySelectorAll('.panel-block'); + for (const panelBlockElement of panelBlockElements) { + panelBlockElement.classList.toggle('is-hidden'); + } + } + function lotTypeResponseHandler(rawResponseJSON) { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + lotTypes = responseJSON.lotTypes; + renderLotTypes(); + } + else { + bulmaJS.alert({ + title: `Error Updating ${los.escapedAliases.Lot} Type`, + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + } + function deleteLotType(clickEvent) { + const burialSiteTypeId = Number.parseInt(clickEvent.currentTarget.closest('.container--lotType').dataset.burialSiteTypeId ?? '', 10); + function doDelete() { + cityssm.postJSON(`${los.urlPrefix}/admin/doDeleteBurialSiteType`, { + burialSiteTypeId + }, lotTypeResponseHandler); + } + bulmaJS.confirm({ + title: `Delete ${los.escapedAliases.Lot} Type`, + message: `Are you sure you want to delete this ${los.escapedAliases.lot} type?`, + contextualColorName: 'warning', + okButton: { + text: `Yes, Delete ${los.escapedAliases.Lot} Type`, + callbackFunction: doDelete + } + }); + } + function openEditLotType(clickEvent) { + const burialSiteTypeId = Number.parseInt(clickEvent.currentTarget.closest('.container--lotType').dataset.burialSiteTypeId ?? '', 10); + const lotType = lotTypes.find((currentLotType) => burialSiteTypeId === currentLotType.burialSiteTypeId); + let editCloseModalFunction; + function doEdit(submitEvent) { + submitEvent.preventDefault(); + cityssm.postJSON(`${los.urlPrefix}/admin/doUpdateBurialSiteType`, submitEvent.currentTarget, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + lotTypeResponseHandler(responseJSON); + if (responseJSON.success) { + editCloseModalFunction(); + } + }); + } + cityssm.openHtmlModal('adminLotTypes-editLotType', { + onshow(modalElement) { + los.populateAliases(modalElement); + modalElement.querySelector('#lotTypeEdit--burialSiteTypeId').value = burialSiteTypeId.toString(); + modalElement.querySelector('#lotTypeEdit--lotType').value = lotType.lotType; + }, + onshown(modalElement, closeModalFunction) { + editCloseModalFunction = closeModalFunction; + modalElement.querySelector('#lotTypeEdit--lotType').focus(); + modalElement.querySelector('form')?.addEventListener('submit', doEdit); + bulmaJS.toggleHtmlClipped(); + }, + onremoved() { + bulmaJS.toggleHtmlClipped(); + } + }); + } + function openAddLotTypeField(clickEvent) { + const burialSiteTypeId = Number.parseInt(clickEvent.currentTarget.closest('.container--lotType').dataset.burialSiteTypeId ?? '', 10); + let addCloseModalFunction; + function doAdd(submitEvent) { + submitEvent.preventDefault(); + cityssm.postJSON(`${los.urlPrefix}/admin/doAddBurialSiteTypeField`, submitEvent.currentTarget, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + expandedLotTypes.add(burialSiteTypeId); + lotTypeResponseHandler(responseJSON); + if (responseJSON.success) { + addCloseModalFunction(); + openEditLotTypeField(burialSiteTypeId, responseJSON.lotTypeFieldId); + } + }); + } + cityssm.openHtmlModal('adminLotTypes-addBurialSiteTypeField', { + onshow(modalElement) { + los.populateAliases(modalElement); + if (burialSiteTypeId) { + ; + modalElement.querySelector('#lotTypeFieldAdd--burialSiteTypeId').value = burialSiteTypeId.toString(); + } + }, + onshown(modalElement, closeModalFunction) { + addCloseModalFunction = closeModalFunction; + modalElement.querySelector('#lotTypeFieldAdd--lotTypeField').focus(); + modalElement.querySelector('form')?.addEventListener('submit', doAdd); + bulmaJS.toggleHtmlClipped(); + }, + onremoved() { + bulmaJS.toggleHtmlClipped(); + } + }); + } + function moveLotType(clickEvent) { + const buttonElement = clickEvent.currentTarget; + const burialSiteTypeId = buttonElement.closest('.container--lotType').dataset.burialSiteTypeId; + cityssm.postJSON(`${los.urlPrefix}/admin/${buttonElement.dataset.direction === 'up' + ? 'doMoveBurialSiteTypeUp' + : 'doMoveBurialSiteTypeDown'}`, { + burialSiteTypeId, + moveToEnd: clickEvent.shiftKey ? '1' : '0' + }, lotTypeResponseHandler); + } + function openEditLotTypeField(burialSiteTypeId, lotTypeFieldId) { + const lotType = lotTypes.find((currentLotType) => currentLotType.burialSiteTypeId === burialSiteTypeId); + const lotTypeField = (lotType.BurialSiteTypeFields ?? []).find((currentLotTypeField) => currentLotTypeField.lotTypeFieldId === lotTypeFieldId); + let fieldTypeElement; + let minimumLengthElement; + let maximumLengthElement; + let patternElement; + let lotTypeFieldValuesElement; + let editCloseModalFunction; + function updateMaximumLengthMin() { + maximumLengthElement.min = minimumLengthElement.value; + } + function toggleInputFields() { + switch (fieldTypeElement.value) { + case 'date': { + minimumLengthElement.disabled = true; + maximumLengthElement.disabled = true; + patternElement.disabled = true; + lotTypeFieldValuesElement.disabled = true; + break; + } + case 'select': { + minimumLengthElement.disabled = true; + maximumLengthElement.disabled = true; + patternElement.disabled = true; + lotTypeFieldValuesElement.disabled = false; + break; + } + default: { + minimumLengthElement.disabled = false; + maximumLengthElement.disabled = false; + patternElement.disabled = false; + lotTypeFieldValuesElement.disabled = true; + break; + } + } + } + function doUpdate(submitEvent) { + submitEvent.preventDefault(); + cityssm.postJSON(`${los.urlPrefix}/admin/doUpdateBurialSiteTypeField`, submitEvent.currentTarget, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + lotTypeResponseHandler(responseJSON); + if (responseJSON.success) { + editCloseModalFunction(); + } + }); + } + function doDelete() { + cityssm.postJSON(`${los.urlPrefix}/admin/doDeleteBurialSiteTypeField`, { + lotTypeFieldId + }, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + lotTypeResponseHandler(responseJSON); + if (responseJSON.success) { + editCloseModalFunction(); + } + }); + } + function confirmDoDelete() { + bulmaJS.confirm({ + title: 'Delete Field', + message: 'Are you sure you want to delete this field? Note that historical records that make use of this field will not be affected.', + contextualColorName: 'warning', + okButton: { + text: 'Yes, Delete Field', + callbackFunction: doDelete + } + }); + } + cityssm.openHtmlModal('adminLotTypes-editLotTypeField', { + onshow(modalElement) { + los.populateAliases(modalElement); + modalElement.querySelector('#lotTypeFieldEdit--lotTypeFieldId').value = lotTypeField.lotTypeFieldId.toString(); + modalElement.querySelector('#lotTypeFieldEdit--lotTypeField').value = lotTypeField.lotTypeField ?? ''; + modalElement.querySelector('#lotTypeFieldEdit--isRequired').value = lotTypeField.isRequired ? '1' : '0'; + fieldTypeElement = modalElement.querySelector('#lotTypeFieldEdit--fieldType'); + fieldTypeElement.value = lotTypeField.fieldType; + minimumLengthElement = modalElement.querySelector('#lotTypeFieldEdit--minimumLength'); + minimumLengthElement.value = + lotTypeField.minimumLength?.toString() ?? ''; + maximumLengthElement = modalElement.querySelector('#lotTypeFieldEdit--maximumLength'); + maximumLengthElement.value = + lotTypeField.maximumLength?.toString() ?? ''; + patternElement = modalElement.querySelector('#lotTypeFieldEdit--pattern'); + patternElement.value = lotTypeField.pattern ?? ''; + lotTypeFieldValuesElement = modalElement.querySelector('#lotTypeFieldEdit--lotTypeFieldValues'); + lotTypeFieldValuesElement.value = lotTypeField.lotTypeFieldValues ?? ''; + toggleInputFields(); + }, + onshown(modalElement, closeModalFunction) { + editCloseModalFunction = closeModalFunction; + bulmaJS.init(modalElement); + bulmaJS.toggleHtmlClipped(); + cityssm.enableNavBlocker(); + modalElement.querySelector('form')?.addEventListener('submit', doUpdate); + minimumLengthElement.addEventListener('keyup', updateMaximumLengthMin); + updateMaximumLengthMin(); + fieldTypeElement.addEventListener('change', toggleInputFields); + modalElement + .querySelector('#button--deleteLotTypeField') + ?.addEventListener('click', confirmDoDelete); + }, + onremoved() { + bulmaJS.toggleHtmlClipped(); + cityssm.disableNavBlocker(); + } + }); + } + function openEditLotTypeFieldByClick(clickEvent) { + clickEvent.preventDefault(); + const lotTypeFieldId = Number.parseInt(clickEvent.currentTarget.closest('.container--lotTypeField').dataset.lotTypeFieldId ?? '', 10); + const burialSiteTypeId = Number.parseInt(clickEvent.currentTarget.closest('.container--lotType').dataset.burialSiteTypeId ?? '', 10); + openEditLotTypeField(burialSiteTypeId, lotTypeFieldId); + } + function moveLotTypeField(clickEvent) { + const buttonElement = clickEvent.currentTarget; + const lotTypeFieldId = buttonElement.closest('.container--lotTypeField').dataset.lotTypeFieldId; + cityssm.postJSON(`${los.urlPrefix}/admin/${buttonElement.dataset.direction === 'up' + ? 'doMoveBurialSiteTypeFieldUp' + : 'doMoveBurialSiteTypeFieldDown'}`, { + lotTypeFieldId, + moveToEnd: clickEvent.shiftKey ? '1' : '0' + }, lotTypeResponseHandler); + } + function renderBurialSiteTypeFields(panelElement, burialSiteTypeId, BurialSiteTypeFields) { + if (BurialSiteTypeFields.length === 0) { + // eslint-disable-next-line no-unsanitized/method + panelElement.insertAdjacentHTML('beforeend', `
    +

    There are no additional fields.

    +
    `); + } + else { + for (const lotTypeField of BurialSiteTypeFields) { + const panelBlockElement = document.createElement('div'); + panelBlockElement.className = + 'panel-block is-block container--lotTypeField'; + if (!expandedLotTypes.has(burialSiteTypeId)) { + panelBlockElement.classList.add('is-hidden'); + } + panelBlockElement.dataset.lotTypeFieldId = + lotTypeField.lotTypeFieldId.toString(); + // eslint-disable-next-line no-unsanitized/property + panelBlockElement.innerHTML = `
    + +
    +
    + ${los.getMoveUpDownButtonFieldHTML('button--moveLotTypeFieldUp', 'button--moveLotTypeFieldDown')} +
    +
    +
    `; + panelBlockElement + .querySelector('.button--editLotTypeField') + ?.addEventListener('click', openEditLotTypeFieldByClick); + panelBlockElement.querySelector('.button--moveLotTypeFieldUp').addEventListener('click', moveLotTypeField); + panelBlockElement.querySelector('.button--moveLotTypeFieldDown').addEventListener('click', moveLotTypeField); + panelElement.append(panelBlockElement); + } + } + } + function renderLotTypes() { + containerElement.innerHTML = ''; + if (lotTypes.length === 0) { + // eslint-disable-next-line no-unsanitized/method + containerElement.insertAdjacentHTML('afterbegin', `
    There are no active ${los.escapedAliases.lot} types.

    +
    `); + return; + } + for (const lotType of lotTypes) { + const lotTypeContainer = document.createElement('div'); + lotTypeContainer.className = 'panel container--lotType'; + lotTypeContainer.dataset.burialSiteTypeId = lotType.burialSiteTypeId.toString(); + // eslint-disable-next-line no-unsanitized/property + lotTypeContainer.innerHTML = `
    +
    +
    +
    + +
    +
    +

    ${cityssm.escapeHTML(lotType.lotType)}

    +
    +
    +
    +
    + +
    +
    + +
    +
    + +
    +
    + ${los.getMoveUpDownButtonFieldHTML('button--moveLotTypeUp', 'button--moveLotTypeDown')} +
    +
    +
    +
    `; + renderBurialSiteTypeFields(lotTypeContainer, lotType.burialSiteTypeId, lotType.BurialSiteTypeFields ?? []); + lotTypeContainer + .querySelector('.button--toggleBurialSiteTypeFields') + ?.addEventListener('click', toggleBurialSiteTypeFields); + lotTypeContainer + .querySelector('.button--deleteLotType') + ?.addEventListener('click', deleteLotType); + lotTypeContainer + .querySelector('.button--editLotType') + ?.addEventListener('click', openEditLotType); + lotTypeContainer + .querySelector('.button--addBurialSiteTypeField') + ?.addEventListener('click', openAddLotTypeField); + lotTypeContainer.querySelector('.button--moveLotTypeUp').addEventListener('click', moveLotType); + lotTypeContainer.querySelector('.button--moveLotTypeDown').addEventListener('click', moveLotType); + containerElement.append(lotTypeContainer); + } + } + document + .querySelector('#button--addBurialSiteType') + ?.addEventListener('click', () => { + let addCloseModalFunction; + function doAdd(submitEvent) { + submitEvent.preventDefault(); + cityssm.postJSON(`${los.urlPrefix}/admin/doAddLotType`, submitEvent.currentTarget, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + addCloseModalFunction(); + lotTypes = responseJSON.lotTypes; + renderLotTypes(); + } + else { + bulmaJS.alert({ + title: `Error Adding ${los.escapedAliases.Lot} Type`, + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + }); + } + cityssm.openHtmlModal('adminLotTypes-addBurialSiteType', { + onshow(modalElement) { + los.populateAliases(modalElement); + }, + onshown(modalElement, closeModalFunction) { + addCloseModalFunction = closeModalFunction; + modalElement.querySelector('#lotTypeAdd--lotType').focus(); + modalElement.querySelector('form')?.addEventListener('submit', doAdd); + bulmaJS.toggleHtmlClipped(); + }, + onremoved() { + bulmaJS.toggleHtmlClipped(); + } + }); + }); + renderLotTypes(); +})(); diff --git a/public/javascripts/burialSiteTypes.admin.ts b/public/javascripts/burialSiteTypes.admin.ts index f807463f..bcf96652 100644 --- a/public/javascripts/burialSiteTypes.admin.ts +++ b/public/javascripts/burialSiteTypes.admin.ts @@ -208,7 +208,7 @@ type ResponseJSON = ) } - cityssm.openHtmlModal('adminLotTypes-addLotTypeField', { + cityssm.openHtmlModal('adminLotTypes-addBurialSiteTypeField', { onshow(modalElement) { los.populateAliases(modalElement) @@ -598,7 +598,7 @@ type ResponseJSON =
    - @@ -632,7 +632,7 @@ type ResponseJSON = ?.addEventListener('click', openEditLotType) lotTypeContainer - .querySelector('.button--addLotTypeField') + .querySelector('.button--addBurialSiteTypeField') ?.addEventListener('click', openAddLotTypeField) ;( lotTypeContainer.querySelector( @@ -650,7 +650,7 @@ type ResponseJSON = } document - .querySelector('#button--addLotType') + .querySelector('#button--addBurialSiteType') ?.addEventListener('click', () => { let addCloseModalFunction: () => void @@ -678,7 +678,7 @@ type ResponseJSON = ) } - cityssm.openHtmlModal('adminLotTypes-addLotType', { + cityssm.openHtmlModal('adminLotTypes-addBurialSiteType', { onshow(modalElement) { los.populateAliases(modalElement) }, diff --git a/public/javascripts/cemetery.edit.d.ts b/public/javascripts/cemetery.edit.d.ts new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/public/javascripts/cemetery.edit.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/public/javascripts/cemetery.edit.js b/public/javascripts/cemetery.edit.js new file mode 100644 index 00000000..e1589133 --- /dev/null +++ b/public/javascripts/cemetery.edit.js @@ -0,0 +1,81 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +(() => { + const los = exports.los; + const cemeteryId = document.querySelector('#cemetery--cemeteryId').value; + const isCreate = cemeteryId === ''; + const cemeteryForm = document.querySelector('#form--cemetery'); + function setUnsavedChanges() { + los.setUnsavedChanges(); + document + .querySelector("button[type='submit'][form='form--cemetery']") + ?.classList.remove('is-light'); + } + function clearUnsavedChanges() { + los.clearUnsavedChanges(); + document + .querySelector("button[type='submit'][form='form--cemetery']") + ?.classList.add('is-light'); + } + function updateCemetery(formEvent) { + formEvent.preventDefault(); + cityssm.postJSON(`${los.urlPrefix}/cemeteries/${isCreate ? 'doCreateCemetery' : 'doUpdateCemetery'}`, cemeteryForm, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + clearUnsavedChanges(); + if (isCreate) { + globalThis.location.href = los.getCemeteryURL(responseJSON.cemeteryId, true); + } + else { + bulmaJS.alert({ + message: `Cemetery Updated Successfully`, + contextualColorName: 'success' + }); + } + } + else { + bulmaJS.alert({ + title: `Error Updating Cemetery`, + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + }); + } + cemeteryForm.addEventListener('submit', updateCemetery); + const inputElements = cemeteryForm.querySelectorAll('input, select'); + for (const inputElement of inputElements) { + inputElement.addEventListener('change', setUnsavedChanges); + } + document + .querySelector('#button--deleteCemetery') + ?.addEventListener('click', (clickEvent) => { + clickEvent.preventDefault(); + function doDelete() { + cityssm.postJSON(`${los.urlPrefix}/cemeteries/doDeleteCemetery`, { + cemeteryId + }, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + globalThis.location.href = los.getCemeteryURL(); + } + else { + bulmaJS.alert({ + title: `Error Deleting Cemetery`, + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + }); + } + bulmaJS.confirm({ + title: `Delete Cemetery`, + message: `Are you sure you want to delete this cemetery and all related burial sites?`, + contextualColorName: 'warning', + okButton: { + text: `Yes, Delete Cemetery`, + callbackFunction: doDelete + } + }); + }); +})(); diff --git a/public/javascripts/cemetery.edit.ts b/public/javascripts/cemetery.edit.ts index 4d6b33e6..cb7f1b6d 100644 --- a/public/javascripts/cemetery.edit.ts +++ b/public/javascripts/cemetery.edit.ts @@ -1,7 +1,7 @@ import type { BulmaJS } from '@cityssm/bulma-js/types.js' import type { cityssmGlobal } from '@cityssm/bulma-webapp-js/src/types.js' -import type { LOS } from '../../types/globalTypes.js' +import type { LOS } from './types.js' declare const cityssm: cityssmGlobal declare const bulmaJS: BulmaJS @@ -10,32 +10,35 @@ declare const exports: Record ;(() => { const los = exports.los as LOS - const cemeteryId = (document.querySelector('#map--cemeteryId') as HTMLInputElement) - .value + const cemeteryId = ( + document.querySelector('#cemetery--cemeteryId') as HTMLInputElement + ).value const isCreate = cemeteryId === '' - const mapForm = document.querySelector('#form--map') as HTMLFormElement + const cemeteryForm = document.querySelector( + '#form--cemetery' + ) as HTMLFormElement function setUnsavedChanges(): void { los.setUnsavedChanges() document - .querySelector("button[type='submit'][form='form--map']") + .querySelector("button[type='submit'][form='form--cemetery']") ?.classList.remove('is-light') } function clearUnsavedChanges(): void { los.clearUnsavedChanges() document - .querySelector("button[type='submit'][form='form--map']") + .querySelector("button[type='submit'][form='form--cemetery']") ?.classList.add('is-light') } - function updateMap(formEvent: SubmitEvent): void { + function updateCemetery(formEvent: SubmitEvent): void { formEvent.preventDefault() cityssm.postJSON( - `${los.urlPrefix}/maps/${isCreate ? 'doCreateMap' : 'doUpdateMap'}`, - mapForm, + `${los.urlPrefix}/cemeteries/${isCreate ? 'doCreateCemetery' : 'doUpdateCemetery'}`, + cemeteryForm, (rawResponseJSON) => { const responseJSON = rawResponseJSON as { success: boolean @@ -47,16 +50,19 @@ declare const exports: Record clearUnsavedChanges() if (isCreate) { - globalThis.location.href = los.getMapURL(responseJSON.cemeteryId, true) + globalThis.location.href = los.getCemeteryURL( + responseJSON.cemeteryId, + true + ) } else { bulmaJS.alert({ - message: `${los.escapedAliases.Map} Updated Successfully`, + message: `Cemetery Updated Successfully`, contextualColorName: 'success' }) } } else { bulmaJS.alert({ - title: `Error Updating ${los.escapedAliases.Map}`, + title: `Error Updating Cemetery`, message: responseJSON.errorMessage ?? '', contextualColorName: 'danger' }) @@ -65,23 +71,23 @@ declare const exports: Record ) } - mapForm.addEventListener('submit', updateMap) + cemeteryForm.addEventListener('submit', updateCemetery) const inputElements: NodeListOf = - mapForm.querySelectorAll('input, select') + cemeteryForm.querySelectorAll('input, select') for (const inputElement of inputElements) { inputElement.addEventListener('change', setUnsavedChanges) } document - .querySelector('#button--deleteMap') + .querySelector('#button--deleteCemetery') ?.addEventListener('click', (clickEvent) => { clickEvent.preventDefault() function doDelete(): void { cityssm.postJSON( - `${los.urlPrefix}/maps/doDeleteMap`, + `${los.urlPrefix}/cemeteries/doDeleteCemetery`, { cemeteryId }, @@ -92,10 +98,10 @@ declare const exports: Record } if (responseJSON.success) { - globalThis.location.href = los.getMapURL() + globalThis.location.href = los.getCemeteryURL() } else { bulmaJS.alert({ - title: `Error Deleting ${los.escapedAliases.Map}`, + title: `Error Deleting Cemetery`, message: responseJSON.errorMessage ?? '', contextualColorName: 'danger' }) @@ -105,11 +111,11 @@ declare const exports: Record } bulmaJS.confirm({ - title: `Delete ${los.escapedAliases.Map}`, - message: `Are you sure you want to delete this ${los.escapedAliases.map} and all related ${los.escapedAliases.lots}?`, + title: `Delete Cemetery`, + message: `Are you sure you want to delete this cemetery and all related burial sites?`, contextualColorName: 'warning', okButton: { - text: `Yes, Delete ${los.escapedAliases.Map}`, + text: `Yes, Delete Cemetery`, callbackFunction: doDelete } }) diff --git a/public/javascripts/cemetery.search.d.ts b/public/javascripts/cemetery.search.d.ts new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/public/javascripts/cemetery.search.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/public/javascripts/cemetery.search.js b/public/javascripts/cemetery.search.js new file mode 100644 index 00000000..e00340de --- /dev/null +++ b/public/javascripts/cemetery.search.js @@ -0,0 +1,102 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +(() => { + const los = exports.los; + const cemeteries = exports.cemeteries; + const searchFilterElement = document.querySelector('#searchFilter--cemetery'); + const searchResultsContainerElement = document.querySelector('#container--searchResults'); + // eslint-disable-next-line complexity + function renderResults() { + // eslint-disable-next-line no-unsanitized/property + searchResultsContainerElement.innerHTML = los.getLoadingParagraphHTML(`Loading Cemeteries...`); + let searchResultCount = 0; + const searchResultsTbodyElement = document.createElement('tbody'); + const filterStringSplit = searchFilterElement.value + .trim() + .toLowerCase() + .split(' '); + for (const cemetery of cemeteries) { + const cemeterySearchString = `${cemetery.cemeteryName ?? ''} ${cemetery.cemeteryDescription ?? ''} ${cemetery.cemeteryAddress1 ?? ''} ${cemetery.cemeteryAddress2 ?? ''}`.toLowerCase(); + let showCemetery = true; + for (const filterStringPiece of filterStringSplit) { + if (!cemeterySearchString.includes(filterStringPiece)) { + showCemetery = false; + break; + } + } + if (!showCemetery) { + continue; + } + searchResultCount += 1; + // eslint-disable-next-line no-unsanitized/method + searchResultsTbodyElement.insertAdjacentHTML('beforeend', `
    + + ${cityssm.escapeHTML((cemetery.cemeteryName ?? '') === '' ? '(No Name)' : cemetery.cemeteryName ?? '')} +
    + + ${cityssm.escapeHTML(cemetery.cemeteryDescription ?? '')} + +
    + ${(cemetery.cemeteryAddress1 ?? '') === '' + ? '' + : `${cityssm.escapeHTML(cemetery.cemeteryAddress1 ?? '')}
    `} + ${(cemetery.cemeteryAddress2 ?? '') === '' + ? '' + : `${cityssm.escapeHTML(cemetery.cemeteryAddress2 ?? '')}
    `} + ${cemetery.cemeteryCity || cemetery.cemeteryProvince + ? `${cityssm.escapeHTML(cemetery.cemeteryCity ?? '')}, ${cityssm.escapeHTML(cemetery.cemeteryProvince ?? '')}
    ` + : ''} + ${(cemetery.cemeteryPostalCode ?? '') === '' + ? '' + : cityssm.escapeHTML(cemetery.cemeteryPostalCode ?? '')} +
    + ${cityssm.escapeHTML(cemetery.cemeteryPhoneNumber ?? '')} + + ${cemetery.cemeteryLatitude && cemetery.cemeteryLongitude + ? ` + + ` + : ''} + + ${(cemetery.cemeterySvg ?? '') === '' + ? '' + : ''} + + ${cemetery.burialSiteCount} +
    CemeteryAddressPhone NumberCoordinatesImageBurial Site Count
    - + ${cityssm.escapeHTML( - (map.cemeteryName ?? '') === '' ? '(No Name)' : map.cemeteryName ?? '' + (cemetery.cemeteryName ?? '') === '' ? '(No Name)' : cemetery.cemeteryName ?? '' )}
    - ${cityssm.escapeHTML(map.mapDescription ?? '')} + ${cityssm.escapeHTML(cemetery.cemeteryDescription ?? '')}
    ${ - (map.mapAddress1 ?? '') === '' + (cemetery.cemeteryAddress1 ?? '') === '' ? '' - : `${cityssm.escapeHTML(map.mapAddress1 ?? '')}
    ` + : `${cityssm.escapeHTML(cemetery.cemeteryAddress1 ?? '')}
    ` } ${ - (map.mapAddress2 ?? '') === '' + (cemetery.cemeteryAddress2 ?? '') === '' ? '' - : `${cityssm.escapeHTML(map.mapAddress2 ?? '')}
    ` + : `${cityssm.escapeHTML(cemetery.cemeteryAddress2 ?? '')}
    ` } ${ - map.mapCity || map.mapProvince - ? `${cityssm.escapeHTML(map.mapCity ?? '')}, ${cityssm.escapeHTML(map.mapProvince ?? '')}
    ` + cemetery.cemeteryCity || cemetery.cemeteryProvince + ? `${cityssm.escapeHTML(cemetery.cemeteryCity ?? '')}, ${cityssm.escapeHTML(cemetery.cemeteryProvince ?? '')}
    ` : '' } ${ - (map.mapPostalCode ?? '') === '' + (cemetery.cemeteryPostalCode ?? '') === '' ? '' - : cityssm.escapeHTML(map.mapPostalCode ?? '') + : cityssm.escapeHTML(cemetery.cemeteryPostalCode ?? '') }
    - ${cityssm.escapeHTML(map.mapPhoneNumber ?? '')} + ${cityssm.escapeHTML(cemetery.cemeteryPhoneNumber ?? '')} ${ - map.mapLatitude && map.mapLongitude + cemetery.cemeteryLatitude && cemetery.cemeteryLongitude ? ` ` @@ -99,12 +101,12 @@ declare const exports: Record } ${ - (map.mapSVG ?? '') === '' + (cemetery.cemeterySvg ?? '') === '' ? '' : '' } - ${map.lotCount} + ${cemetery.burialSiteCount}
    ${los.escapedAliases.Map}Cemetery Address Phone Number Coordinates Image${los.escapedAliases.Lot} CountBurial Site Count
    +

    There are no active work order types.

    +
    +
    + +
    +
    + +
    +
    + +
    +
    +
    +
    +
    +
    + ${los.getMoveUpDownButtonFieldHTML('button--moveWorkOrderTypeUp', 'button--moveWorkOrderTypeDown', false)} +
    +
    + +
    +
    +
    +
    +

    There are no active work order milestone types.

    +
    +
    +
    + +
    +
    + +
    +
    + +
    +
    +
    +
    +
    +
    + ${los.getMoveUpDownButtonFieldHTML('button--moveWorkOrderMilestoneTypeUp', 'button--moveWorkOrderMilestoneTypeDown', false)} +
    +
    + +
    +
    +
    +
    +

    There are no active ${los.escapedAliases.lot} statuses.

    +
    +
    +
    + +
    +
    + +
    +
    + +
    +
    +
    +
    +
    +
    + ${los.getMoveUpDownButtonFieldHTML('button--moveLotStatusUp', 'button--moveLotStatusDown', false)} +
    +
    + +
    +
    +
    +
    +

    There are no active ${los.escapedAliases.lot} ${los.escapedAliases.occupant} types.

    +
    +
    +
    +
    + +
    +
    +
    +
    +
    + fa- +
    +
    + +
    +
    + + + +
    +
    +
    +
    +
    + +
    +
    +
    +
    + + +
    +
    +
    +
    + ${los.getMoveUpDownButtonFieldHTML('button--moveLotOccupantTypeUp', 'button--moveLotOccupantTypeDown', false)} +
    +
    + +
    +
    +
    + + + + + + + + + + +
    ${los.escapedAliases.Occupancy} Type${los.escapedAliases.Lot}${los.escapedAliases.contractStartDate}End Date${los.escapedAliases.Occupants}
    `; + const currentDateString = cityssm.dateToString(new Date()); + for (const burialSiteContract of workOrderBurialSiteContracts) { + const rowElement = document.createElement('tr'); + rowElement.className = 'container--burialSiteContract'; + rowElement.dataset.burialSiteContractId = + burialSiteContract.burialSiteContractId.toString(); + const isActive = !(burialSiteContract.contractEndDate && + burialSiteContract.contractEndDateString < currentDateString); + const hasLotRecord = burialSiteContract.lotId && + workOrderLots.some((lot) => burialSiteContract.lotId === lot.lotId); + // eslint-disable-next-line no-unsanitized/property + rowElement.innerHTML = ` + ${isActive + ? `` + : ``} + + + ${cityssm.escapeHTML(burialSiteContract.occupancyType ?? '')} +
    + #${burialSiteContract.burialSiteContractId} + `; + if (burialSiteContract.lotId) { + // eslint-disable-next-line no-unsanitized/method + rowElement.insertAdjacentHTML('beforeend', ` + ${cityssm.escapeHTML(burialSiteContract.lotName ?? '')} + ${hasLotRecord + ? '' + : ` `} + `); + } + else { + // eslint-disable-next-line no-unsanitized/method + rowElement.insertAdjacentHTML('beforeend', `(No ${los.escapedAliases.Lot})`); + } + let occupantsHTML = ''; + for (const occupant of burialSiteContract.burialSiteContractOccupants) { + occupantsHTML += `
  • + + + + ${cityssm.escapeHTML(occupant.occupantName ?? '')} + ${cityssm.escapeHTML(occupant.occupantFamilyName ?? '')} +
  • `; + } + // eslint-disable-next-line no-unsanitized/method + rowElement.insertAdjacentHTML('beforeend', ` + ${burialSiteContract.contractStartDateString} + + ${burialSiteContract.contractEndDate + ? burialSiteContract.contractEndDateString + : '(No End Date)'} + + ${burialSiteContract.burialSiteContractOccupants.length === 0 + ? `(No ${los.escapedAliases.Occupants})` + : `
      ${occupantsHTML}
    `} + + + `); + rowElement + .querySelector('.button--addBurialSite') + ?.addEventListener('click', addBurialSiteFromLotOccupancy); + rowElement + .querySelector('.button--deleteLotOccupancy') + ?.addEventListener('click', deleteLotOccupancy); + occupanciesContainerElement.querySelector('tbody')?.append(rowElement); + } + } + function openEditLotStatus(clickEvent) { + const lotId = Number.parseInt(clickEvent.currentTarget.closest('.container--lot').dataset.lotId ?? '', 10); + const lot = workOrderLots.find((possibleLot) => possibleLot.lotId === lotId); + let editCloseModalFunction; + function doUpdateBurialSiteStatus(submitEvent) { + submitEvent.preventDefault(); + cityssm.postJSON(`${los.urlPrefix}/workOrders/doUpdateBurialSiteStatus`, submitEvent.currentTarget, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + workOrderLots = responseJSON.workOrderLots; + renderRelatedLotsAndOccupancies(); + editCloseModalFunction(); + } + else { + bulmaJS.alert({ + title: 'Error Deleting Relationship', + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + }); + } + cityssm.openHtmlModal('lot-editLotStatus', { + onshow(modalElement) { + los.populateAliases(modalElement); + modalElement.querySelector('#lotStatusEdit--lotId').value = lotId.toString(); + modalElement.querySelector('#lotStatusEdit--lotName').value = lot.lotName ?? ''; + const lotStatusElement = modalElement.querySelector('#lotStatusEdit--burialSiteStatusId'); + let lotStatusFound = false; + for (const lotStatus of exports.lotStatuses) { + const optionElement = document.createElement('option'); + optionElement.value = lotStatus.burialSiteStatusId.toString(); + optionElement.textContent = lotStatus.lotStatus; + if (lotStatus.burialSiteStatusId === lot.burialSiteStatusId) { + lotStatusFound = true; + } + lotStatusElement.append(optionElement); + } + if (!lotStatusFound && lot.burialSiteStatusId) { + const optionElement = document.createElement('option'); + optionElement.value = lot.burialSiteStatusId.toString(); + optionElement.textContent = lot.lotStatus ?? ''; + lotStatusElement.append(optionElement); + } + if (lot.burialSiteStatusId) { + lotStatusElement.value = lot.burialSiteStatusId.toString(); + } + // eslint-disable-next-line no-unsanitized/method + modalElement + .querySelector('form') + ?.insertAdjacentHTML('beforeend', ``); + }, + onshown(modalElement, closeModalFunction) { + editCloseModalFunction = closeModalFunction; + bulmaJS.toggleHtmlClipped(); + modalElement + .querySelector('form') + ?.addEventListener('submit', doUpdateBurialSiteStatus); + }, + onremoved() { + bulmaJS.toggleHtmlClipped(); + } + }); + } + function deleteLot(clickEvent) { + const lotId = clickEvent.currentTarget.closest('.container--lot').dataset.lotId; + function doDelete() { + cityssm.postJSON(`${los.urlPrefix}/workOrders/doDeleteWorkOrderBurialSite`, { + workOrderId, + lotId + }, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + workOrderLots = responseJSON.workOrderLots; + renderRelatedLotsAndOccupancies(); + } + else { + bulmaJS.alert({ + title: 'Error Deleting Relationship', + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + }); + } + bulmaJS.confirm({ + title: `Delete ${los.escapedAliases.Occupancy} Relationship`, + message: `Are you sure you want to remove the relationship to this ${los.escapedAliases.occupancy} record from this work order? Note that the record will remain.`, + contextualColorName: 'warning', + okButton: { + text: 'Yes, Delete Relationship', + callbackFunction: doDelete + } + }); + } + function renderRelatedLots() { + const lotsContainerElement = document.querySelector('#container--lots'); + document.querySelector(".tabs a[href='#relatedTab--lots'] .tag").textContent = workOrderLots.length.toString(); + if (workOrderLots.length === 0) { + // eslint-disable-next-line no-unsanitized/property + lotsContainerElement.innerHTML = `
    +

    There are no ${los.escapedAliases.lots} associated with this work order.

    +
    `; + return; + } + // eslint-disable-next-line no-unsanitized/property + lotsContainerElement.innerHTML = ` + + + + + + + + +
    ${los.escapedAliases.Lot}${los.escapedAliases.Map}${los.escapedAliases.Lot} TypeStatus
    `; + for (const lot of workOrderLots) { + const rowElement = document.createElement('tr'); + rowElement.className = 'container--lot'; + rowElement.dataset.lotId = lot.lotId.toString(); + // eslint-disable-next-line no-unsanitized/property + rowElement.innerHTML = ` + + ${cityssm.escapeHTML(lot.lotName ?? '')} + + + ${cityssm.escapeHTML(lot.cemeteryName ?? '')} + + ${cityssm.escapeHTML(lot.lotType ?? '')} + + ${lot.burialSiteStatusId + ? cityssm.escapeHTML(lot.lotStatus ?? '') + : '(No Status)'} + + + + `; + rowElement + .querySelector('.button--editLotStatus') + ?.addEventListener('click', openEditLotStatus); + rowElement + .querySelector('.button--deleteLot') + ?.addEventListener('click', deleteLot); + lotsContainerElement.querySelector('tbody')?.append(rowElement); + } + } + function renderRelatedLotsAndOccupancies() { + renderRelatedOccupancies(); + renderRelatedLots(); + } + renderRelatedLotsAndOccupancies(); + function doAddLotOccupancy(clickEvent) { + const rowElement = clickEvent.currentTarget.closest('tr'); + const burialSiteContractId = rowElement.dataset.burialSiteContractId ?? ''; + addBurialSiteContract(burialSiteContractId, (success) => { + if (success) { + rowElement.remove(); + } + }); + } + document + .querySelector('#button--addBurialSiteContract') + ?.addEventListener('click', () => { + let searchFormElement; + let searchResultsContainerElement; + function doSearch(event) { + if (event) { + event.preventDefault(); + } + // eslint-disable-next-line no-unsanitized/property + searchResultsContainerElement.innerHTML = + los.getLoadingParagraphHTML('Searching...'); + cityssm.postJSON(`${los.urlPrefix}/contracts/doSearchLotOccupancies`, searchFormElement, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.lotOccupancies.length === 0) { + searchResultsContainerElement.innerHTML = `
    +

    There are no records that meet the search criteria.

    +
    `; + return; + } + // eslint-disable-next-line no-unsanitized/property + searchResultsContainerElement.innerHTML = ` + + + + + + + + + +
    ${los.escapedAliases.Occupancy} Type${los.escapedAliases.Lot}${los.escapedAliases.contractStartDate}End Date${los.escapedAliases.Occupants}
    `; + for (const burialSiteContract of responseJSON.lotOccupancies) { + const rowElement = document.createElement('tr'); + rowElement.className = 'container--burialSiteContract'; + rowElement.dataset.burialSiteContractId = + burialSiteContract.burialSiteContractId.toString(); + rowElement.innerHTML = ` + + + + ${cityssm.escapeHTML(burialSiteContract.occupancyType ?? '')} + `; + if (burialSiteContract.lotId) { + rowElement.insertAdjacentHTML('beforeend', `${cityssm.escapeHTML(burialSiteContract.lotName ?? '')}`); + } + else { + // eslint-disable-next-line no-unsanitized/method + rowElement.insertAdjacentHTML('beforeend', `(No ${los.escapedAliases.Lot})`); + } + // eslint-disable-next-line no-unsanitized/method + rowElement.insertAdjacentHTML('beforeend', ` + ${burialSiteContract.contractStartDateString} + + ${burialSiteContract.contractEndDate + ? burialSiteContract.contractEndDateString + : '(No End Date)'} + + ${burialSiteContract.burialSiteContractOccupants.length === 0 + ? ` + (No ${cityssm.escapeHTML(los.escapedAliases.Occupants)}) + ` + : cityssm.escapeHTML(`${burialSiteContract.burialSiteContractOccupants[0].occupantName} + ${burialSiteContract.burialSiteContractOccupants[0] + .occupantFamilyName}`) + + (burialSiteContract.burialSiteContractOccupants.length > 1 + ? ` plus + ${(burialSiteContract.burialSiteContractOccupants.length - 1).toString()}` + : '')}`); + rowElement + .querySelector('.button--addBurialSiteContract') + ?.addEventListener('click', doAddLotOccupancy); + searchResultsContainerElement + .querySelector('tbody') + ?.append(rowElement); + } + }); + } + cityssm.openHtmlModal('workOrder-addBurialSiteContract', { + onshow(modalElement) { + los.populateAliases(modalElement); + searchFormElement = modalElement.querySelector('form'); + searchResultsContainerElement = modalElement.querySelector('#resultsContainer--burialSiteContractAdd'); + modalElement.querySelector('#burialSiteContractSearch--notWorkOrderId').value = workOrderId; + modalElement.querySelector('#burialSiteContractSearch--occupancyEffectiveDateString').value = document.querySelector('#workOrderEdit--workOrderOpenDateString').value; + doSearch(); + }, + onshown(modalElement) { + bulmaJS.toggleHtmlClipped(); + const occupantNameElement = modalElement.querySelector('#burialSiteContractSearch--occupantName'); + occupantNameElement.addEventListener('change', doSearch); + occupantNameElement.focus(); + modalElement.querySelector('#burialSiteContractSearch--lotName').addEventListener('change', doSearch); + searchFormElement.addEventListener('submit', doSearch); + }, + onremoved() { + bulmaJS.toggleHtmlClipped(); + document.querySelector('#button--addBurialSiteContract').focus(); + } + }); + }); + function doAddLot(clickEvent) { + const rowElement = clickEvent.currentTarget.closest('tr'); + const lotId = rowElement.dataset.lotId ?? ''; + addBurialSite(lotId, (success) => { + if (success) { + rowElement.remove(); + } + }); + } + document + .querySelector('#button--addBurialSite') + ?.addEventListener('click', () => { + let searchFormElement; + let searchResultsContainerElement; + function doSearch(event) { + if (event) { + event.preventDefault(); + } + // eslint-disable-next-line no-unsanitized/property + searchResultsContainerElement.innerHTML = + los.getLoadingParagraphHTML('Searching...'); + cityssm.postJSON(`${los.urlPrefix}/lots/doSearchBurialSites`, searchFormElement, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.lots.length === 0) { + searchResultsContainerElement.innerHTML = `
    +

    There are no records that meet the search criteria.

    +
    `; + return; + } + // eslint-disable-next-line no-unsanitized/property + searchResultsContainerElement.innerHTML = ` + + + + + + + + +
    ${los.escapedAliases.Lot}${los.escapedAliases.Map}${los.escapedAliases.Lot} TypeStatus
    `; + for (const lot of responseJSON.lots) { + const rowElement = document.createElement('tr'); + rowElement.className = 'container--lot'; + rowElement.dataset.lotId = lot.lotId.toString(); + rowElement.innerHTML = ` + + + ${cityssm.escapeHTML(lot.lotName ?? '')} + + ${cityssm.escapeHTML(lot.cemeteryName ?? '')} + + ${cityssm.escapeHTML(lot.lotType ?? '')} + + ${cityssm.escapeHTML(lot.lotStatus ?? '')} + `; + rowElement + .querySelector('.button--addBurialSite') + ?.addEventListener('click', doAddLot); + searchResultsContainerElement + .querySelector('tbody') + ?.append(rowElement); + } + }); + } + cityssm.openHtmlModal('workOrder-addBurialSite', { + onshow(modalElement) { + los.populateAliases(modalElement); + searchFormElement = modalElement.querySelector('form'); + searchResultsContainerElement = modalElement.querySelector('#resultsContainer--lotAdd'); + modalElement.querySelector('#lotSearch--notWorkOrderId').value = workOrderId; + const lotStatusElement = modalElement.querySelector('#lotSearch--burialSiteStatusId'); + for (const lotStatus of exports.lotStatuses) { + const optionElement = document.createElement('option'); + optionElement.value = lotStatus.burialSiteStatusId.toString(); + optionElement.textContent = lotStatus.lotStatus; + lotStatusElement.append(optionElement); + } + doSearch(); + }, + onshown(modalElement) { + bulmaJS.toggleHtmlClipped(); + const lotNameElement = modalElement.querySelector('#lotSearch--lotName'); + lotNameElement.addEventListener('change', doSearch); + lotNameElement.focus(); + modalElement + .querySelector('#lotSearch--burialSiteStatusId') + ?.addEventListener('change', doSearch); + searchFormElement.addEventListener('submit', doSearch); + }, + onremoved() { + bulmaJS.toggleHtmlClipped(); + document.querySelector('#button--addBurialSite').focus(); + } + }); + }); + })(); + } + /** + * Comments + */ + ; + (() => { + let workOrderComments = exports.workOrderComments; + delete exports.workOrderComments; + function openEditWorkOrderComment(clickEvent) { + const workOrderCommentId = Number.parseInt(clickEvent.currentTarget.closest('tr')?.dataset + .workOrderCommentId ?? '', 10); + const workOrderComment = workOrderComments.find((currentComment) => currentComment.workOrderCommentId === workOrderCommentId); + let editFormElement; + let editCloseModalFunction; + function editComment(submitEvent) { + submitEvent.preventDefault(); + cityssm.postJSON(`${los.urlPrefix}/workOrders/doUpdateWorkOrderComment`, editFormElement, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + workOrderComments = responseJSON.workOrderComments; + editCloseModalFunction(); + renderWorkOrderComments(); + } + else { + bulmaJS.alert({ + title: 'Error Updating Comment', + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + }); + } + cityssm.openHtmlModal('workOrder-editComment', { + onshow(modalElement) { + ; + modalElement.querySelector('#workOrderCommentEdit--workOrderId').value = workOrderId; + modalElement.querySelector('#workOrderCommentEdit--workOrderCommentId').value = workOrderCommentId.toString(); + modalElement.querySelector('#workOrderCommentEdit--workOrderComment').value = workOrderComment.workOrderComment ?? ''; + const workOrderCommentDateStringElement = modalElement.querySelector('#workOrderCommentEdit--workOrderCommentDateString'); + workOrderCommentDateStringElement.value = + workOrderComment.workOrderCommentDateString ?? ''; + const currentDateString = cityssm.dateToString(new Date()); + workOrderCommentDateStringElement.max = + workOrderComment.workOrderCommentDateString <= currentDateString + ? currentDateString + : workOrderComment.workOrderCommentDateString ?? ''; + modalElement.querySelector('#workOrderCommentEdit--workOrderCommentTimeString').value = workOrderComment.workOrderCommentTimeString ?? ''; + }, + onshown(modalElement, closeModalFunction) { + bulmaJS.toggleHtmlClipped(); + los.initializeDatePickers(modalElement); + modalElement.querySelector('#workOrderCommentEdit--workOrderComment').focus(); + editFormElement = modalElement.querySelector('form'); + editFormElement.addEventListener('submit', editComment); + editCloseModalFunction = closeModalFunction; + }, + onremoved() { + bulmaJS.toggleHtmlClipped(); + } + }); + } + function deleteWorkOrderComment(clickEvent) { + const workOrderCommentId = Number.parseInt(clickEvent.currentTarget.closest('tr')?.dataset + .workOrderCommentId ?? '', 10); + function doDelete() { + cityssm.postJSON(`${los.urlPrefix}/workOrders/doDeleteWorkOrderComment`, { + workOrderId, + workOrderCommentId + }, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + workOrderComments = responseJSON.workOrderComments; + renderWorkOrderComments(); + } + else { + bulmaJS.alert({ + title: 'Error Removing Comment', + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + }); + } + bulmaJS.confirm({ + title: 'Remove Comment?', + message: 'Are you sure you want to remove this comment?', + okButton: { + text: 'Yes, Remove Comment', + callbackFunction: doDelete + }, + contextualColorName: 'warning' + }); + } + function renderWorkOrderComments() { + const containerElement = document.querySelector('#container--workOrderComments'); + if (workOrderComments.length === 0) { + containerElement.innerHTML = `
    +

    There are no comments to display.

    +
    `; + return; + } + const tableElement = document.createElement('table'); + tableElement.className = 'table is-fullwidth is-striped is-hoverable'; + tableElement.innerHTML = ` + Commentor + Comment Date + Comment + Options + + `; + for (const workOrderComment of workOrderComments) { + const tableRowElement = document.createElement('tr'); + tableRowElement.dataset.workOrderCommentId = + workOrderComment.workOrderCommentId?.toString(); + // eslint-disable-next-line no-unsanitized/property + tableRowElement.innerHTML = ` + ${cityssm.escapeHTML(workOrderComment.recordCreate_userName ?? '')} + + ${workOrderComment.workOrderCommentDateString} + ${workOrderComment.workOrderCommentTime === 0 + ? '' + : workOrderComment.workOrderCommentTimePeriodString} + + ${cityssm.escapeHTML(workOrderComment.workOrderComment ?? '')} + +
    + + +
    + `; + tableRowElement + .querySelector('.button--edit') + ?.addEventListener('click', openEditWorkOrderComment); + tableRowElement + .querySelector('.button--delete') + ?.addEventListener('click', deleteWorkOrderComment); + tableElement.querySelector('tbody')?.append(tableRowElement); + } + containerElement.innerHTML = ''; + containerElement.append(tableElement); + } + function openAddCommentModal() { + let addCommentCloseModalFunction; + function doAddComment(formEvent) { + formEvent.preventDefault(); + cityssm.postJSON(`${los.urlPrefix}/workOrders/doAddWorkOrderComment`, formEvent.currentTarget, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + workOrderComments = responseJSON.workOrderComments; + renderWorkOrderComments(); + addCommentCloseModalFunction(); + } + }); + } + cityssm.openHtmlModal('workOrder-addComment', { + onshow(modalElement) { + los.populateAliases(modalElement); + modalElement.querySelector('#workOrderCommentAdd--workOrderId').value = workOrderId; + modalElement + .querySelector('form') + ?.addEventListener('submit', doAddComment); + }, + onshown(modalElement, closeModalFunction) { + bulmaJS.toggleHtmlClipped(); + addCommentCloseModalFunction = closeModalFunction; + modalElement.querySelector('#workOrderCommentAdd--workOrderComment').focus(); + }, + onremoved() { + bulmaJS.toggleHtmlClipped(); + document.querySelector('#workOrderComments--add').focus(); + } + }); + } + document + .querySelector('#workOrderComments--add') + ?.addEventListener('click', openAddCommentModal); + if (!isCreate) { + renderWorkOrderComments(); + } + })(); + /* + * Milestones + */ + function clearPanelBlockElements(panelElement) { + for (const panelBlockElement of panelElement.querySelectorAll('.panel-block')) { + panelBlockElement.remove(); + } + } + function refreshConflictingMilestones(workOrderMilestoneDateString, targetPanelElement) { + // Clear panel-block elements + clearPanelBlockElements(targetPanelElement); + // eslint-disable-next-line no-unsanitized/method + targetPanelElement.insertAdjacentHTML('beforeend', `
    + ${los.getLoadingParagraphHTML('Loading conflicting milestones...')} +
    `); + cityssm.postJSON(`${los.urlPrefix}/workOrders/doGetWorkOrderMilestones`, { + workOrderMilestoneDateFilter: 'date', + workOrderMilestoneDateString + }, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + const workOrderMilestones = responseJSON.workOrderMilestones.filter((possibleMilestone) => possibleMilestone.workOrderId.toString() !== workOrderId); + clearPanelBlockElements(targetPanelElement); + for (const milestone of workOrderMilestones) { + targetPanelElement.insertAdjacentHTML('beforeend', `
    +
    +
    + ${cityssm.escapeHTML(milestone.workOrderMilestoneTime === 0 ? 'No Time' : milestone.workOrderMilestoneTimePeriodString ?? '')}
    + ${cityssm.escapeHTML(milestone.workOrderMilestoneType ?? '')} +
    +
    + ${cityssm.escapeHTML(milestone.workOrderNumber ?? '')}
    + + ${cityssm.escapeHTML(milestone.workOrderDescription ?? '')} + +
    +
    +
    `); + } + if (workOrderMilestones.length === 0) { + targetPanelElement.insertAdjacentHTML('beforeend', `
    +
    +

    + There are no milestones on other work orders scheduled for + ${cityssm.escapeHTML(workOrderMilestoneDateString)}. +

    +
    +
    `); + } + }); + } + function processMilestoneResponse(rawResponseJSON) { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + workOrderMilestones = responseJSON.workOrderMilestones; + renderMilestones(); + } + else { + bulmaJS.alert({ + title: 'Error Reopening Milestone', + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + } + function completeMilestone(clickEvent) { + clickEvent.preventDefault(); + const currentDateString = cityssm.dateToString(new Date()); + const workOrderMilestoneId = Number.parseInt(clickEvent.currentTarget.closest('.container--milestone').dataset.workOrderMilestoneId ?? '', 10); + const workOrderMilestone = workOrderMilestones.find((currentMilestone) => currentMilestone.workOrderMilestoneId === workOrderMilestoneId); + function doComplete() { + cityssm.postJSON(`${los.urlPrefix}/workOrders/doCompleteWorkOrderMilestone`, { + workOrderId, + workOrderMilestoneId + }, processMilestoneResponse); + } + bulmaJS.confirm({ + title: 'Complete Milestone', + message: `Are you sure you want to complete this milestone? + ${workOrderMilestone.workOrderMilestoneDateString !== undefined && + workOrderMilestone.workOrderMilestoneDateString !== '' && + workOrderMilestone.workOrderMilestoneDateString > currentDateString + ? '
    Note that this milestone is expected to be completed in the future.' + : ''}`, + messageIsHtml: true, + contextualColorName: 'warning', + okButton: { + text: 'Yes, Complete Milestone', + callbackFunction: doComplete + } + }); + } + function reopenMilestone(clickEvent) { + clickEvent.preventDefault(); + const workOrderMilestoneId = clickEvent.currentTarget.closest('.container--milestone').dataset.workOrderMilestoneId; + function doReopen() { + cityssm.postJSON(`${los.urlPrefix}/workOrders/doReopenWorkOrderMilestone`, { + workOrderId, + workOrderMilestoneId + }, processMilestoneResponse); + } + bulmaJS.confirm({ + title: 'Reopen Milestone', + message: 'Are you sure you want to remove the completion status from this milestone, and reopen it?', + contextualColorName: 'warning', + okButton: { + text: 'Yes, Reopen Milestone', + callbackFunction: doReopen + } + }); + } + function deleteMilestone(clickEvent) { + clickEvent.preventDefault(); + const workOrderMilestoneId = clickEvent.currentTarget.closest('.container--milestone').dataset.workOrderMilestoneId; + function doDelete() { + cityssm.postJSON(`${los.urlPrefix}/workOrders/doDeleteWorkOrderMilestone`, { + workOrderMilestoneId, + workOrderId + }, processMilestoneResponse); + } + bulmaJS.confirm({ + title: 'Delete Milestone', + message: 'Are you sure you want to delete this milestone?', + contextualColorName: 'warning', + okButton: { + text: 'Yes, Delete Milestone', + callbackFunction: doDelete + } + }); + } + function editMilestone(clickEvent) { + clickEvent.preventDefault(); + const workOrderMilestoneId = Number.parseInt(clickEvent.currentTarget.closest('.container--milestone').dataset.workOrderMilestoneId ?? '', 10); + const workOrderMilestone = workOrderMilestones.find((currentMilestone) => currentMilestone.workOrderMilestoneId === workOrderMilestoneId); + let editCloseModalFunction; + let workOrderMilestoneDateStringElement; + function doEdit(submitEvent) { + submitEvent.preventDefault(); + cityssm.postJSON(`${los.urlPrefix}/workOrders/doUpdateWorkOrderMilestone`, submitEvent.currentTarget, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + processMilestoneResponse(responseJSON); + if (responseJSON.success) { + editCloseModalFunction(); + } + }); + } + cityssm.openHtmlModal('workOrder-editMilestone', { + onshow(modalElement) { + ; + modalElement.querySelector('#milestoneEdit--workOrderId').value = workOrderId; + modalElement.querySelector('#milestoneEdit--workOrderMilestoneId').value = workOrderMilestone.workOrderMilestoneId?.toString() ?? ''; + const milestoneTypeElement = modalElement.querySelector('#milestoneEdit--workOrderMilestoneTypeId'); + let milestoneTypeFound = false; + for (const milestoneType of exports.workOrderMilestoneTypes) { + const optionElement = document.createElement('option'); + optionElement.value = + milestoneType.workOrderMilestoneTypeId.toString(); + optionElement.textContent = milestoneType.workOrderMilestoneType; + if (milestoneType.workOrderMilestoneTypeId === + workOrderMilestone.workOrderMilestoneTypeId) { + optionElement.selected = true; + milestoneTypeFound = true; + } + milestoneTypeElement.append(optionElement); + } + if (!milestoneTypeFound && + workOrderMilestone.workOrderMilestoneTypeId) { + const optionElement = document.createElement('option'); + optionElement.value = + workOrderMilestone.workOrderMilestoneTypeId.toString(); + optionElement.textContent = + workOrderMilestone.workOrderMilestoneType ?? ''; + optionElement.selected = true; + milestoneTypeElement.append(optionElement); + } + workOrderMilestoneDateStringElement = modalElement.querySelector('#milestoneEdit--workOrderMilestoneDateString'); + workOrderMilestoneDateStringElement.value = + workOrderMilestone.workOrderMilestoneDateString ?? ''; + if (workOrderMilestone.workOrderMilestoneTime) { + ; + modalElement.querySelector('#milestoneEdit--workOrderMilestoneTimeString').value = workOrderMilestone.workOrderMilestoneTimeString ?? ''; + } + ; + modalElement.querySelector('#milestoneEdit--workOrderMilestoneDescription').value = workOrderMilestone.workOrderMilestoneDescription ?? ''; + }, + onshown(modalElement, closeModalFunction) { + editCloseModalFunction = closeModalFunction; + bulmaJS.toggleHtmlClipped(); + los.initializeDatePickers(modalElement); + // los.initializeTimePickers(modalElement); + modalElement.querySelector('form')?.addEventListener('submit', doEdit); + const conflictingMilestonePanelElement = document.querySelector('#milestoneEdit--conflictingMilestonesPanel'); + workOrderMilestoneDateStringElement.addEventListener('change', () => { + refreshConflictingMilestones(workOrderMilestoneDateStringElement.value, conflictingMilestonePanelElement); + }); + refreshConflictingMilestones(workOrderMilestoneDateStringElement.value, conflictingMilestonePanelElement); + }, + onremoved() { + bulmaJS.toggleHtmlClipped(); + } + }); + } + function renderMilestones() { + // Clear milestones panel + const milestonesPanelElement = document.querySelector('#panel--milestones'); + const panelBlockElementsToDelete = milestonesPanelElement.querySelectorAll('.panel-block'); + for (const panelBlockToDelete of panelBlockElementsToDelete) { + panelBlockToDelete.remove(); + } + for (const milestone of workOrderMilestones) { + const panelBlockElement = document.createElement('div'); + panelBlockElement.className = 'panel-block is-block container--milestone'; + panelBlockElement.dataset.workOrderMilestoneId = + milestone.workOrderMilestoneId?.toString(); + // eslint-disable-next-line no-unsanitized/property + panelBlockElement.innerHTML = `
    +
    + ${milestone.workOrderMilestoneCompletionDate + ? ` + + ` + : ``} +
    + ${milestone.workOrderMilestoneTypeId + ? `${cityssm.escapeHTML(milestone.workOrderMilestoneType ?? '')}
    ` + : ''} + ${milestone.workOrderMilestoneDate === 0 + ? '(No Set Date)' + : milestone.workOrderMilestoneDateString} + ${milestone.workOrderMilestoneTime + ? ` ${milestone.workOrderMilestoneTimePeriodString}` + : ''}
    + + ${cityssm.escapeHTML(milestone.workOrderMilestoneDescription ?? '')} + +
    + +
    `; + panelBlockElement + .querySelector('.button--reopenMilestone') + ?.addEventListener('click', reopenMilestone); + panelBlockElement + .querySelector('.button--editMilestone') + ?.addEventListener('click', editMilestone); + panelBlockElement + .querySelector('.button--completeMilestone') + ?.addEventListener('click', completeMilestone); + panelBlockElement + .querySelector('.button--deleteMilestone') + ?.addEventListener('click', deleteMilestone); + milestonesPanelElement.append(panelBlockElement); + } + bulmaJS.init(milestonesPanelElement); + } + if (!isCreate) { + workOrderMilestones = exports.workOrderMilestones; + delete exports.workOrderMilestones; + renderMilestones(); + document + .querySelector('#button--addMilestone') + ?.addEventListener('click', () => { + let addFormElement; + let workOrderMilestoneDateStringElement; + let addCloseModalFunction; + function doAdd(submitEvent) { + if (submitEvent) { + submitEvent.preventDefault(); + } + const currentDateString = cityssm.dateToString(new Date()); + function _doAdd() { + cityssm.postJSON(`${los.urlPrefix}/workOrders/doAddWorkOrderMilestone`, addFormElement, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + processMilestoneResponse(responseJSON); + if (responseJSON.success) { + addCloseModalFunction(); + } + }); + } + const milestoneDateString = workOrderMilestoneDateStringElement.value; + if (milestoneDateString !== '' && + milestoneDateString < currentDateString) { + bulmaJS.confirm({ + title: 'Milestone Date in the Past', + message: 'Are you sure you want to create a milestone with a date in the past?', + contextualColorName: 'warning', + okButton: { + text: 'Yes, Create a Past Milestone', + callbackFunction: _doAdd + } + }); + } + else { + _doAdd(); + } + } + cityssm.openHtmlModal('workOrder-addMilestone', { + onshow(modalElement) { + ; + modalElement.querySelector('#milestoneAdd--workOrderId').value = workOrderId; + const milestoneTypeElement = modalElement.querySelector('#milestoneAdd--workOrderMilestoneTypeId'); + for (const milestoneType of exports.workOrderMilestoneTypes) { + const optionElement = document.createElement('option'); + optionElement.value = + milestoneType.workOrderMilestoneTypeId.toString(); + optionElement.textContent = milestoneType.workOrderMilestoneType; + milestoneTypeElement.append(optionElement); + } + workOrderMilestoneDateStringElement = modalElement.querySelector('#milestoneAdd--workOrderMilestoneDateString'); + workOrderMilestoneDateStringElement.valueAsDate = new Date(); + }, + onshown(modalElement, closeModalFunction) { + addCloseModalFunction = closeModalFunction; + los.initializeDatePickers(modalElement); + // los.initializeTimePickers(modalElement); + bulmaJS.toggleHtmlClipped(); + modalElement.querySelector('#milestoneAdd--workOrderMilestoneTypeId').focus(); + addFormElement = modalElement.querySelector('form'); + addFormElement.addEventListener('submit', doAdd); + const conflictingMilestonePanelElement = document.querySelector('#milestoneAdd--conflictingMilestonesPanel'); + workOrderMilestoneDateStringElement.addEventListener('change', () => { + refreshConflictingMilestones(workOrderMilestoneDateStringElement.value, conflictingMilestonePanelElement); + }); + refreshConflictingMilestones(workOrderMilestoneDateStringElement.value, conflictingMilestonePanelElement); + }, + onremoved() { + bulmaJS.toggleHtmlClipped(); + document.querySelector('#button--addMilestone').focus(); + } + }); + }); + } +})(); diff --git a/public/javascripts/workOrder.edit.ts b/public/javascripts/workOrder.edit.ts index f6141e42..ceb8f1e5 100644 --- a/public/javascripts/workOrder.edit.ts +++ b/public/javascripts/workOrder.edit.ts @@ -270,7 +270,7 @@ declare const exports: Record }) } - function addLot( + function addBurialSite( lotId: number | string, callbackFunction?: (success: boolean) => void ): void { @@ -340,10 +340,10 @@ declare const exports: Record ) } - function addLotFromLotOccupancy(clickEvent: Event): void { + function addBurialSiteFromLotOccupancy(clickEvent: Event): void { const lotId = (clickEvent.currentTarget as HTMLElement).dataset.lotId ?? '' - addLot(lotId) + addBurialSite(lotId) } function renderRelatedOccupancies(): void { @@ -420,7 +420,7 @@ declare const exports: Record ${ hasLotRecord ? '' - : ` @@ -991,7 +991,7 @@ declare const exports: Record ` rowElement - .querySelector('.button--addLot') + .querySelector('.button--addBurialSite') ?.addEventListener('click', doAddLot) searchResultsContainerElement @@ -1002,7 +1002,7 @@ declare const exports: Record ) } - cityssm.openHtmlModal('workOrder-addLot', { + cityssm.openHtmlModal('workOrder-addBurialSite', { onshow(modalElement) { los.populateAliases(modalElement) @@ -1051,7 +1051,7 @@ declare const exports: Record onremoved() { bulmaJS.toggleHtmlClipped() ;( - document.querySelector('#button--addLot') as HTMLButtonElement + document.querySelector('#button--addBurialSite') as HTMLButtonElement ).focus() } }) diff --git a/public/javascripts/workOrder.milestoneCalendar.d.ts b/public/javascripts/workOrder.milestoneCalendar.d.ts new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/public/javascripts/workOrder.milestoneCalendar.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/public/javascripts/workOrder.milestoneCalendar.js b/public/javascripts/workOrder.milestoneCalendar.js new file mode 100644 index 00000000..6180f0b4 --- /dev/null +++ b/public/javascripts/workOrder.milestoneCalendar.js @@ -0,0 +1,118 @@ +"use strict"; +// eslint-disable-next-line @eslint-community/eslint-comments/disable-enable-pair +/* eslint-disable unicorn/prefer-module */ +Object.defineProperty(exports, "__esModule", { value: true }); +(() => { + const los = exports.los; + const workOrderSearchFiltersFormElement = document.querySelector('#form--searchFilters'); + const workOrderMilestoneDateFilterElement = workOrderSearchFiltersFormElement.querySelector('#searchFilter--workOrderMilestoneDateFilter'); + const workOrderMilestoneDateStringElement = workOrderSearchFiltersFormElement.querySelector('#searchFilter--workOrderMilestoneDateString'); + const milestoneCalendarContainerElement = document.querySelector('#container--milestoneCalendar'); + function renderMilestones(workOrderMilestones) { + if (workOrderMilestones.length === 0) { + milestoneCalendarContainerElement.innerHTML = `
    +

    There are no milestones that meet the search criteria.

    +
    `; + return; + } + milestoneCalendarContainerElement.innerHTML = ''; + const currentDate = cityssm.dateToString(new Date()); + let currentPanelElement; + let currentPanelDateString = 'x'; + for (const milestone of workOrderMilestones) { + if (currentPanelDateString !== milestone.workOrderMilestoneDateString) { + if (currentPanelElement) { + milestoneCalendarContainerElement.append(currentPanelElement); + } + currentPanelElement = document.createElement('div'); + currentPanelElement.className = 'panel'; + currentPanelElement.innerHTML = `

    + ${cityssm.escapeHTML(milestone.workOrderMilestoneDate === 0 + ? 'No Set Date' + : milestone.workOrderMilestoneDateString ?? '')} +

    `; + currentPanelDateString = milestone.workOrderMilestoneDateString ?? ''; + } + const panelBlockElement = document.createElement('div'); + panelBlockElement.className = 'panel-block is-block'; + if (!milestone.workOrderMilestoneCompletionDate && + milestone.workOrderMilestoneDateString !== '' && + milestone.workOrderMilestoneDateString < currentDate) { + panelBlockElement.classList.add('has-background-warning-light'); + } + let burialSiteContractHTML = ''; + for (const lot of milestone.workOrderLots ?? []) { + burialSiteContractHTML += `
  • + + + + ${cityssm.escapeHTML(lot.lotName ?? '')} +
  • `; + } + for (const burialSiteContract of milestone.workOrderBurialSiteContracts ?? []) { + for (const occupant of burialSiteContract.burialSiteContractOccupants ?? []) { + burialSiteContractHTML += `
  • + + + + ${cityssm.escapeHTML(occupant.occupantName ?? '')} + ${cityssm.escapeHTML(occupant.occupantFamilyName ?? '')} +
  • `; + } + } + // eslint-disable-next-line no-unsanitized/property + panelBlockElement.innerHTML = `
    +
    + + ${milestone.workOrderMilestoneCompletionDate + ? '' + : ''} + +
    + ${milestone.workOrderMilestoneTime === 0 + ? '' + : `${milestone.workOrderMilestoneTimePeriodString}
    `} + ${milestone.workOrderMilestoneTypeId + ? `${cityssm.escapeHTML(milestone.workOrderMilestoneType ?? '')}
    ` + : ''} + + ${cityssm.escapeHTML(milestone.workOrderMilestoneDescription ?? '')} + +
    + + + ${cityssm.escapeHTML(milestone.workOrderNumber ?? '')} +
    + ${cityssm.escapeHTML(milestone.workOrderDescription ?? '')} +
    + ${burialSiteContractHTML === '' + ? '' + : `
      ${burialSiteContractHTML}
    `}
    `; + currentPanelElement.append(panelBlockElement); + } + milestoneCalendarContainerElement.append(currentPanelElement); + } + function getMilestones(event) { + if (event) { + event.preventDefault(); + } + // eslint-disable-next-line no-unsanitized/property + milestoneCalendarContainerElement.innerHTML = los.getLoadingParagraphHTML('Loading Milestones...'); + cityssm.postJSON(`${los.urlPrefix}/workOrders/doGetWorkOrderMilestones`, workOrderSearchFiltersFormElement, (responseJSON) => { + renderMilestones(responseJSON.workOrderMilestones); + }); + } + workOrderMilestoneDateFilterElement.addEventListener('change', () => { + ; + workOrderMilestoneDateStringElement.closest('fieldset').disabled = workOrderMilestoneDateFilterElement.value !== 'date'; + getMilestones(); + }); + los.initializeDatePickers(workOrderSearchFiltersFormElement); + workOrderMilestoneDateStringElement.addEventListener('change', getMilestones); + workOrderSearchFiltersFormElement.addEventListener('submit', getMilestones); + getMilestones(); +})(); diff --git a/public/javascripts/workOrder.outlook.d.ts b/public/javascripts/workOrder.outlook.d.ts new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/public/javascripts/workOrder.outlook.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/public/javascripts/workOrder.outlook.js b/public/javascripts/workOrder.outlook.js new file mode 100644 index 00000000..2313ce94 --- /dev/null +++ b/public/javascripts/workOrder.outlook.js @@ -0,0 +1,46 @@ +"use strict"; +// eslint-disable-next-line @eslint-community/eslint-comments/disable-enable-pair +/* eslint-disable unicorn/prefer-module */ +Object.defineProperty(exports, "__esModule", { value: true }); +(() => { + const los = exports.los; + const workOrderTypeIdsElement = document.querySelector('#icsFilters--workOrderTypeIds'); + const workOrderMilestoneTypeIdsElement = document.querySelector('#icsFilters--workOrderMilestoneTypeIds'); + const calendarLinkElement = document.querySelector('#icsFilters--calendarURL'); + function updateCalendarURL() { + let url = `${window.location.href.slice(0, Math.max(0, window.location.href.indexOf(window.location.pathname) + 1)) + los.urlPrefix}api/${los.apiKey}/milestoneICS/?`; + if (!workOrderTypeIdsElement.disabled && + workOrderTypeIdsElement.selectedOptions.length > 0) { + url += 'workOrderTypeIds='; + for (const optionElement of workOrderTypeIdsElement.selectedOptions) { + url += `${optionElement.value},`; + } + url = `${url.slice(0, -1)}&`; + } + if (!workOrderMilestoneTypeIdsElement.disabled && + workOrderMilestoneTypeIdsElement.selectedOptions.length > 0) { + url += 'workOrderMilestoneTypeIds='; + for (const optionElement of workOrderMilestoneTypeIdsElement.selectedOptions) { + url += `${optionElement.value},`; + } + url = `${url.slice(0, -1)}&`; + } + calendarLinkElement.value = url.slice(0, -1); + } + ; + document.querySelector('#icsFilters--workOrderTypeIds-all').addEventListener('change', (changeEvent) => { + workOrderTypeIdsElement.disabled = changeEvent.currentTarget.checked; + }); + document.querySelector('#icsFilters--workOrderMilestoneTypeIds-all').addEventListener('change', (changeEvent) => { + workOrderMilestoneTypeIdsElement.disabled = changeEvent.currentTarget.checked; + }); + const inputSelectElements = document.querySelector('#panel--icsFilters').querySelectorAll('input, select'); + for (const element of inputSelectElements) { + element.addEventListener('change', updateCalendarURL); + } + updateCalendarURL(); + calendarLinkElement.addEventListener('click', () => { + calendarLinkElement.focus(); + calendarLinkElement.select(); + }); +})(); diff --git a/public/javascripts/workOrder.search.d.ts b/public/javascripts/workOrder.search.d.ts new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/public/javascripts/workOrder.search.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/public/javascripts/workOrder.search.js b/public/javascripts/workOrder.search.js new file mode 100644 index 00000000..91d921ec --- /dev/null +++ b/public/javascripts/workOrder.search.js @@ -0,0 +1,180 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +(() => { + const los = exports.los; + const workOrderPrints = exports.workOrderPrints; + const searchFilterFormElement = document.querySelector('#form--searchFilters'); + los.initializeDatePickers(searchFilterFormElement); + const searchResultsContainerElement = document.querySelector('#container--searchResults'); + const limit = Number.parseInt(document.querySelector('#searchFilter--limit').value, 10); + const offsetElement = document.querySelector('#searchFilter--offset'); + function renderWorkOrders(rawResponseJSON) { + const responseJSON = rawResponseJSON; + if (responseJSON.workOrders.length === 0) { + searchResultsContainerElement.innerHTML = `
    +

    There are no work orders that meet the search criteria.

    +
    `; + return; + } + const resultsTbodyElement = document.createElement('tbody'); + for (const workOrder of responseJSON.workOrders) { + let relatedHTML = ''; + for (const lot of workOrder.workOrderLots ?? []) { + relatedHTML += `
  • + + + + ${cityssm.escapeHTML((lot.lotName ?? '') === '' + ? `(No ${los.escapedAliases.Lot} Name)` + : lot.lotName ?? '')} +
  • `; + } + for (const occupancy of workOrder.workOrderBurialSiteContracts ?? []) { + for (const occupant of occupancy.burialSiteContractOccupants ?? []) { + relatedHTML += `
  • + + + + ${cityssm.escapeHTML((occupant.occupantName ?? '') === '' && + (occupant.occupantFamilyName ?? '') === '' + ? '(No Name)' + : `${occupant.occupantName} ${occupant.occupantFamilyName}`)} +
  • `; + } + } + // eslint-disable-next-line no-unsanitized/method + resultsTbodyElement.insertAdjacentHTML('beforeend', ` + + + ${workOrder.workOrderNumber?.trim() === '' + ? '(No Number)' + : cityssm.escapeHTML(workOrder.workOrderNumber ?? '')} + + + ${cityssm.escapeHTML(workOrder.workOrderType ?? '')}
    + + ${cityssm.escapeHTML(workOrder.workOrderDescription ?? '')} + + + ${relatedHTML === '' + ? '' + : `
      ${relatedHTML}
    `} + +
      +
    • + + + + ${workOrder.workOrderOpenDateString} +
    • +
    • + + + + ${workOrder.workOrderCloseDate + ? workOrder.workOrderCloseDateString + : `(No ${los.escapedAliases.WorkOrderCloseDate})`} +
    • +
    + + ${workOrder.workOrderMilestoneCount === 0 + ? '-' + : `${(workOrder.workOrderMilestoneCompletionCount ?? '').toString()} + / + ${(workOrder.workOrderMilestoneCount ?? '').toString()}`} + + ${workOrderPrints.length > 0 + ? ` + + + + ` + : ''}`); + } + // eslint-disable-next-line no-unsanitized/property + searchResultsContainerElement.innerHTML = ` + + + + + + + ${workOrderPrints.length > 0 ? '' : ''} + +
    Work Order NumberDescriptionRelatedDateProgress
    `; + // eslint-disable-next-line no-unsanitized/method + searchResultsContainerElement.insertAdjacentHTML('beforeend', los.getSearchResultsPagerHTML(limit, responseJSON.offset, responseJSON.count)); + searchResultsContainerElement + .querySelector('table') + ?.append(resultsTbodyElement); + searchResultsContainerElement + .querySelector("button[data-page='previous']") + ?.addEventListener('click', previousAndGetWorkOrders); + searchResultsContainerElement + .querySelector("button[data-page='next']") + ?.addEventListener('click', nextAndGetWorkOrders); + } + function getWorkOrders() { + // eslint-disable-next-line no-unsanitized/property + searchResultsContainerElement.innerHTML = los.getLoadingParagraphHTML('Loading Work Orders...'); + cityssm.postJSON(`${los.urlPrefix}/workOrders/doSearchWorkOrders`, searchFilterFormElement, renderWorkOrders); + } + function resetOffsetAndGetWorkOrders() { + offsetElement.value = '0'; + getWorkOrders(); + } + function previousAndGetWorkOrders() { + offsetElement.value = Math.max(Number.parseInt(offsetElement.value, 10) - limit, 0).toString(); + getWorkOrders(); + } + function nextAndGetWorkOrders() { + offsetElement.value = (Number.parseInt(offsetElement.value, 10) + limit).toString(); + getWorkOrders(); + } + const filterElements = searchFilterFormElement.querySelectorAll('input, select'); + for (const filterElement of filterElements) { + filterElement.addEventListener('change', resetOffsetAndGetWorkOrders); + } + searchFilterFormElement.addEventListener('submit', (formEvent) => { + formEvent.preventDefault(); + }); + // eslint-disable-next-line no-secrets/no-secrets + /* + const workOrderOpenDateStringElement = document.querySelector("#searchFilter--workOrderOpenDateString") as HTMLInputElement; + + document.querySelector("#button--workOrderOpenDateString-previous").addEventListener("click", () => { + + if (workOrderOpenDateStringElement.value === "") { + workOrderOpenDateStringElement.valueAsDate = new Date(); + } else { + const openDate = workOrderOpenDateStringElement.valueAsDate; + openDate.setDate(openDate.getDate() - 1); + workOrderOpenDateStringElement.valueAsDate = openDate; + } + + resetOffsetAndGetWorkOrders(); + }); + + document.querySelector("#button--workOrderOpenDateString-next").addEventListener("click", () => { + + if (workOrderOpenDateStringElement.value === "") { + workOrderOpenDateStringElement.valueAsDate = new Date(); + } else { + const openDate = workOrderOpenDateStringElement.valueAsDate; + openDate.setDate(openDate.getDate() + 1); + workOrderOpenDateStringElement.valueAsDate = openDate; + } + + resetOffsetAndGetWorkOrders(); + }); + */ + getWorkOrders(); +})(); diff --git a/public/javascripts/workOrder.view.d.ts b/public/javascripts/workOrder.view.d.ts new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/public/javascripts/workOrder.view.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/public/javascripts/workOrder.view.js b/public/javascripts/workOrder.view.js new file mode 100644 index 00000000..e9929751 --- /dev/null +++ b/public/javascripts/workOrder.view.js @@ -0,0 +1,37 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +(() => { + const los = exports.los; + const reopenWorkOrderButtonElement = document.querySelector('#button--reopenWorkOrder'); + if (reopenWorkOrderButtonElement !== null) { + const workOrderId = reopenWorkOrderButtonElement.dataset.workOrderId ?? ''; + reopenWorkOrderButtonElement.addEventListener('click', () => { + function doReopen() { + cityssm.postJSON(`${los.urlPrefix}/workOrders/doReopenWorkOrder`, { + workOrderId + }, (rawResponseJSON) => { + const responseJSON = rawResponseJSON; + if (responseJSON.success) { + globalThis.location.href = los.getWorkOrderURL(workOrderId, true, true); + } + else { + bulmaJS.alert({ + title: 'Error Reopening Work Order', + message: responseJSON.errorMessage ?? '', + contextualColorName: 'danger' + }); + } + }); + } + bulmaJS.confirm({ + title: 'Reopen Work Order', + message: 'Are you sure you want to remove the close date from this work order and reopen it?', + contextualColorName: 'warning', + okButton: { + text: 'Yes, Reopen Work Order', + callbackFunction: doReopen + } + }); + }); + } +})(); diff --git a/temp/legacy.importFromCSV.js b/temp/legacy.importFromCSV.js index 76d599a3..a7f50fbf 100644 --- a/temp/legacy.importFromCSV.js +++ b/temp/legacy.importFromCSV.js @@ -1,24 +1,25 @@ +/* eslint-disable max-lines */ import fs from 'node:fs'; import { dateIntegerToString, dateToString } from '@cityssm/utils-datetime'; import sqlite from 'better-sqlite3'; import papa from 'papaparse'; -import { sunriseDB as databasePath } from '../data/databasePaths.js'; -import addLot from '../database/addLot.js'; +import { sunriseDB as databasePath } from '../helpers/database.helpers.js'; +import addBurialSite from '../database/addBurialSite.js'; import addBurialSiteContract from '../database/addBurialSiteContract.js'; import addBurialSiteContractComment from '../database/addBurialSiteContractComment.js'; import addBurialSiteContractFee from '../database/addBurialSiteContractFee.js'; import addBurialSiteContractOccupant from '../database/addBurialSiteContractOccupant.js'; import addBurialSiteContractTransaction from '../database/addBurialSiteContractTransaction.js'; -import addMap from '../database/addMap.js'; -import addOrUpdateLotOccupancyField from '../database/addOrUpdateLotOccupancyField.js'; +import addCemetery from '../database/addCemetery.js'; +import addOrUpdateBurialSiteContractField from '../database/addOrUpdateBurialSiteContractField.js'; import addWorkOrder from '../database/addWorkOrder.js'; -import addWorkOrderLot from '../database/addWorkOrderLot.js'; +import addWorkOrderBurialSite from '../database/addWorkOrderBurialSite.js'; import addWorkOrderBurialSiteContract from '../database/addWorkOrderBurialSiteContract.js'; import addWorkOrderMilestone from '../database/addWorkOrderMilestone.js'; import closeWorkOrder from '../database/closeWorkOrder.js'; -import getLot, { getLotByLotName } from '../database/getLot.js'; +import getBurialSite from '../database/getBurialSite.js'; import getBurialSiteContracts from '../database/getBurialSiteContracts.js'; -import getMapFromDatabase from '../database/getMap.js'; +import getCemeteryFromDatabase from '../database/getCemetery.js'; import getWorkOrder, { getWorkOrderByWorkOrderNumber } from '../database/getWorkOrder.js'; import reopenWorkOrder from '../database/reopenWorkOrder.js'; import { updateBurialSiteStatus } from '../database/updateBurialSite.js'; @@ -37,18 +38,18 @@ function purgeTables() { const tablesToPurge = [ 'WorkOrderMilestones', 'WorkOrderComments', - 'WorkOrderLots', - 'WorkOrderLotOccupancies', + 'WorkOrderBurialSites', + 'WorkOrderBurialSiteContracts', 'WorkOrders', - 'LotOccupancyTransactions', - 'LotOccupancyFees', - 'LotOccupancyFields', - 'LotOccupancyComments', - 'LotOccupancyOccupants', - 'LotOccupancies', - 'LotFields', - 'LotComments', - 'Lots' + 'BurialSiteContractTransactions', + 'BurialSiteContractFees', + 'BurialSiteContractFields', + 'BurialSiteContractComments', + 'BurialSiteContractInterments', + 'BurialSiteContracts', + 'BurialSiteFields', + 'BurialSiteComments', + 'BurialSites' ]; const database = sqlite(databasePath); for (const tableName of tablesToPurge) { @@ -63,20 +64,20 @@ function purgeTables() { function purgeConfigTables() { console.time('purgeConfigTables'); const database = sqlite(databasePath); - database.prepare('delete from Maps').run(); - database.prepare("delete from sqlite_sequence where name in ('Maps')").run(); + database.prepare('delete from Cemeteries').run(); + database.prepare("delete from sqlite_sequence where name in ('Cemeteries')").run(); database.close(); console.timeEnd('purgeConfigTables'); } -function getMapByMapDescription(mapDescription) { +function getCemeteryByDescription(cemeteryDescription) { const database = sqlite(databasePath, { readonly: true }); - const map = database - .prepare('select * from Maps where mapDescription = ?') - .get(mapDescription); + const cemetery = database + .prepare('select * from Cemeteries where cemeteryDescription = ?') + .get(cemeteryDescription); database.close(); - return map; + return cemetery; } function formatDateString(year, month, day) { const formattedYear = `0000${year}`.slice(-4); @@ -102,8 +103,8 @@ const cemeteryTocemeteryName = { UG: 'New Greenwood - Urn Garden', WK: 'West Korah' }; -const mapCache = new Map(); -async function getMap(dataRow) { +const cemeteryCache = new Map(); +async function getCemetery(dataRow) { const mapCacheKey = dataRow.cemetery; /* if (masterRow.CM_CEMETERY === "HS" && @@ -111,29 +112,29 @@ async function getMap(dataRow) { mapCacheKey += "-" + masterRow.CM_BLOCK; } */ - if (mapCache.has(mapCacheKey)) { - return mapCache.get(mapCacheKey); + if (cemeteryCache.has(mapCacheKey)) { + return cemeteryCache.get(mapCacheKey); } - let map = getMapByMapDescription(mapCacheKey); - if (!map) { - console.log(`Creating map: ${dataRow.cemetery}`); - const cemeteryId = await addMap({ + let cemetery = getCemeteryByDescription(mapCacheKey); + if (cemetery === undefined) { + console.log(`Creating cemetery: ${dataRow.cemetery}`); + const cemeteryId = await addCemetery({ cemeteryName: cemeteryTocemeteryName[dataRow.cemetery] ?? dataRow.cemetery, - mapDescription: dataRow.cemetery, - mapSVG: '', - mapLatitude: '', - mapLongitude: '', - mapAddress1: '', - mapAddress2: '', - mapCity: 'Sault Ste. Marie', - mapProvince: 'ON', - mapPostalCode: '', - mapPhoneNumber: '' + cemeteryDescription: dataRow.cemetery, + cemeterySvg: '', + cemeteryLatitude: '', + cemeteryLongitude: '', + cemeteryAddress1: '', + cemeteryAddress2: '', + cemeteryCity: 'Sault Ste. Marie', + cemeteryProvince: 'ON', + cemeteryPostalCode: '', + cemeteryPhoneNumber: '' }, user); - map = (await getMapFromDatabase(cemeteryId)); + cemetery = (await getCemeteryFromDatabase(cemeteryId)); } - mapCache.set(mapCacheKey, map); - return map; + cemeteryCache.set(mapCacheKey, cemetery); + return cemetery; } async function importFromMasterCSV() { console.time('importFromMasterCSV'); @@ -149,31 +150,20 @@ async function importFromMasterCSV() { } try { for (masterRow of cmmaster.data) { - const map = await getMap({ + const cemetery = await getCemetery({ cemetery: masterRow.CM_CEMETERY }); - const lotName = importData.buildLotName({ - cemetery: masterRow.CM_CEMETERY, - block: masterRow.CM_BLOCK, - range1: masterRow.CM_RANGE1, - range2: masterRow.CM_RANGE2, - lot1: masterRow.CM_LOT1, - lot2: masterRow.CM_LOT2, - grave1: masterRow.CM_GRAVE1, - grave2: masterRow.CM_GRAVE2, - interment: masterRow.CM_INTERMENT - }); const burialSiteTypeId = importIds.getburialSiteTypeId({ cemetery: masterRow.CM_CEMETERY }); - let lotId; + let burialSiteId; if (masterRow.CM_CEMETERY !== '00') { - lotId = await addLot({ + burialSiteId = await addBurialSite({ lotName, burialSiteTypeId, - burialSiteStatusId: importIds.availableburialSiteStatusId, - cemeteryId: map.cemeteryId, - mapKey: lotName.includes(',') ? lotName.split(',')[0] : lotName, + burialSiteStatusId: importIds.availableBurialSiteStatusId, + cemeteryId: cemetery.cemeteryId, + cemeterySvgId: '', burialSiteLatitude: '', burialSiteLongitude: '' }, user); @@ -209,7 +199,7 @@ async function importFromMasterCSV() { } preneedburialSiteContractId = await addBurialSiteContract({ contractTypeId: importIds.preneedOccupancyType.contractTypeId, - lotId: lotId ?? '', + lotId: burialSiteId ?? '', contractStartDateString: preneedcontractStartDateString, contractEndDateString, contractTypeFieldIds: '' @@ -253,7 +243,7 @@ async function importFromMasterCSV() { }, user); } if (contractEndDateString === '') { - await updateBurialSiteStatus(lotId ?? '', importIds.reservedburialSiteStatusId, user); + await updateBurialSiteStatus(burialSiteId ?? '', importIds.reservedburialSiteStatusId, user); } } let deceasedcontractStartDateString; @@ -270,15 +260,15 @@ async function importFromMasterCSV() { deceasedcontractStartDateString === '0000-00-00') { deceasedcontractStartDateString = '0001-01-01'; } - const deceasedcontractEndDateString = lotId + const deceasedcontractEndDateString = burialSiteId ? '' : deceasedcontractStartDateString; - const occupancyType = lotId + const occupancyType = burialSiteId ? importIds.deceasedOccupancyType : importIds.cremationOccupancyType; deceasedburialSiteContractId = await addBurialSiteContract({ contractTypeId: occupancyType.contractTypeId, - lotId: lotId ?? '', + lotId: burialSiteId ?? '', contractStartDateString: deceasedcontractStartDateString, contractEndDateString: deceasedcontractEndDateString, contractTypeFieldIds: '' @@ -299,14 +289,14 @@ async function importFromMasterCSV() { }, user); if (masterRow.CM_DEATH_YR !== '') { const burialSiteContractFieldValue = formatDateString(masterRow.CM_DEATH_YR, masterRow.CM_DEATH_MON, masterRow.CM_DEATH_DAY); - await addOrUpdateLotOccupancyField({ + await addOrUpdateBurialSiteContractField({ burialSiteContractId: deceasedburialSiteContractId, contractTypeFieldId: occupancyType.ContractTypeFields.find((occupancyTypeField) => occupancyTypeField.occupancyTypeField === 'Death Date').contractTypeFieldId, burialSiteContractFieldValue }, user); } if (masterRow.CM_AGE !== '') { - await addOrUpdateLotOccupancyField({ + await addOrUpdateBurialSiteContractField({ burialSiteContractId: deceasedburialSiteContractId, contractTypeFieldId: occupancyType.ContractTypeFields.find((occupancyTypeField) => occupancyTypeField.occupancyTypeField === 'Death Age').contractTypeFieldId, burialSiteContractFieldValue: masterRow.CM_AGE @@ -314,9 +304,9 @@ async function importFromMasterCSV() { } if (masterRow.CM_PERIOD !== '') { const period = importData.getDeathAgePeriod(masterRow.CM_PERIOD); - await addOrUpdateLotOccupancyField({ + await addOrUpdateBurialSiteContractField({ burialSiteContractId: deceasedburialSiteContractId, - contractTypeFieldId: occupancyType.ContractTypeFields.find((occupancyTypeField) => (occupancyTypeField.occupancyTypeField === 'Death Age Period')).contractTypeFieldId, + contractTypeFieldId: occupancyType.ContractTypeFields.find((occupancyTypeField) => occupancyTypeField.occupancyTypeField === 'Death Age Period').contractTypeFieldId, burialSiteContractFieldValue: period }, user); } @@ -336,7 +326,7 @@ async function importFromMasterCSV() { occupantEmailAddress: funeralHomeOccupant.occupantEmailAddress ?? '' }, user); /* - addOrUpdateLotOccupancyField( + addOrUpdateBurialSiteContractField( { burialSiteContractId: deceasedburialSiteContractId, contractTypeFieldId: allContractTypeFields.find( @@ -352,17 +342,17 @@ async function importFromMasterCSV() { } if (masterRow.CM_FUNERAL_YR !== '') { const burialSiteContractFieldValue = formatDateString(masterRow.CM_FUNERAL_YR, masterRow.CM_FUNERAL_MON, masterRow.CM_FUNERAL_DAY); - await addOrUpdateLotOccupancyField({ + await addOrUpdateBurialSiteContractField({ burialSiteContractId: deceasedburialSiteContractId, - contractTypeFieldId: occupancyType.ContractTypeFields.find((occupancyTypeField) => (occupancyTypeField.occupancyTypeField === 'Funeral Date')).contractTypeFieldId, + contractTypeFieldId: occupancyType.ContractTypeFields.find((occupancyTypeField) => occupancyTypeField.occupancyTypeField === 'Funeral Date').contractTypeFieldId, burialSiteContractFieldValue }, user); } if (occupancyType.occupancyType !== 'Cremation') { if (masterRow.CM_CONTAINER_TYPE !== '') { - await addOrUpdateLotOccupancyField({ + await addOrUpdateBurialSiteContractField({ burialSiteContractId: deceasedburialSiteContractId, - contractTypeFieldId: occupancyType.ContractTypeFields.find((occupancyTypeField) => (occupancyTypeField.occupancyTypeField === 'Container Type')).contractTypeFieldId, + contractTypeFieldId: occupancyType.ContractTypeFields.find((occupancyTypeField) => occupancyTypeField.occupancyTypeField === 'Container Type').contractTypeFieldId, burialSiteContractFieldValue: masterRow.CM_CONTAINER_TYPE }, user); } @@ -371,9 +361,9 @@ async function importFromMasterCSV() { if (commitalType === 'GS') { commitalType = 'Graveside'; } - await addOrUpdateLotOccupancyField({ + await addOrUpdateBurialSiteContractField({ burialSiteContractId: deceasedburialSiteContractId, - contractTypeFieldId: occupancyType.ContractTypeFields.find((occupancyTypeField) => (occupancyTypeField.occupancyTypeField === 'Committal Type')).contractTypeFieldId, + contractTypeFieldId: occupancyType.ContractTypeFields.find((occupancyTypeField) => occupancyTypeField.occupancyTypeField === 'Committal Type').contractTypeFieldId, burialSiteContractFieldValue: commitalType }, user); } @@ -402,7 +392,7 @@ async function importFromMasterCSV() { burialSiteContractComment: `Imported Contract #${masterRow.CM_WORK_ORDER}` }, user); } - await updateBurialSiteStatus(lotId ?? '', importIds.takenburialSiteStatusId, user); + await updateBurialSiteStatus(burialSiteId ?? '', importIds.takenburialSiteStatusId, user); if (masterRow.CM_PRENEED_OWNER !== '') { await addBurialSiteContractOccupant({ burialSiteContractId: deceasedburialSiteContractId, @@ -450,7 +440,7 @@ async function importFromPrepaidCSV() { } let lot; if (cemetery !== '') { - const map = await getMap({ + const map = await getCemetery({ cemetery }); const lotName = importData.buildLotName({ @@ -464,12 +454,12 @@ async function importFromPrepaidCSV() { grave2: prepaidRow.CMPP_GRAVE2, interment: prepaidRow.CMPP_INTERMENT }); - lot = await getLotByLotName(lotName); + lot = await getBurialSiteByLotName(lotName); if (!lot) { const burialSiteTypeId = importIds.getburialSiteTypeId({ cemetery }); - const lotId = await addLot({ + const lotId = await addBurialSite({ lotName, burialSiteTypeId, burialSiteStatusId: importIds.reservedburialSiteStatusId, @@ -478,10 +468,11 @@ async function importFromPrepaidCSV() { burialSiteLatitude: '', burialSiteLongitude: '' }, user); - lot = await getLot(lotId); + lot = await getBurialSite(lotId); } } - if (lot && lot.burialSiteStatusId === importIds.availableburialSiteStatusId) { + if (lot && + lot.burialSiteStatusId === importIds.availableburialSiteStatusId) { await updateBurialSiteStatus(lot.lotId, importIds.reservedburialSiteStatusId, user); } const contractStartDateString = formatDateString(prepaidRow.CMPP_PURCH_YR, prepaidRow.CMPP_PURCH_MON, prepaidRow.CMPP_PURCH_DAY); @@ -711,16 +702,16 @@ async function importFromWorkOrderCSV() { grave2: workOrderRow.WO_GRAVE2, interment: workOrderRow.WO_INTERMENT }); - lot = await getLotByLotName(lotName); + lot = await getBurialSiteByLotName(lotName); if (lot) { await updateBurialSiteStatus(lot.lotId, importIds.takenburialSiteStatusId, user); } else { - const map = await getMap({ cemetery: workOrderRow.WO_CEMETERY }); + const map = await getCemetery({ cemetery: workOrderRow.WO_CEMETERY }); const burialSiteTypeId = importIds.getburialSiteTypeId({ cemetery: workOrderRow.WO_CEMETERY }); - const lotId = await addLot({ + const lotId = await addBurialSite({ cemeteryId: map.cemeteryId, lotName, mapKey: lotName.includes(',') ? lotName.split(',')[0] : lotName, @@ -729,11 +720,11 @@ async function importFromWorkOrderCSV() { burialSiteLatitude: '', burialSiteLongitude: '' }, user); - lot = await getLot(lotId); + lot = await getBurialSite(lotId); } const workOrderContainsLot = workOrder.workOrderLots.find((possibleLot) => (possibleLot.lotId = lot.lotId)); if (!workOrderContainsLot) { - await addWorkOrderLot({ + await addWorkOrderBurialSite({ workOrderId: workOrder.workOrderId, lotId: lot.lotId }, user); @@ -768,21 +759,21 @@ async function importFromWorkOrderCSV() { }, user); if (workOrderRow.WO_DEATH_YR !== '') { const burialSiteContractFieldValue = formatDateString(workOrderRow.WO_DEATH_YR, workOrderRow.WO_DEATH_MON, workOrderRow.WO_DEATH_DAY); - await addOrUpdateLotOccupancyField({ + await addOrUpdateBurialSiteContractField({ burialSiteContractId, contractTypeFieldId: occupancyType.ContractTypeFields.find((occupancyTypeField) => occupancyTypeField.occupancyTypeField === 'Death Date').contractTypeFieldId, burialSiteContractFieldValue }, user); } if (workOrderRow.WO_DEATH_PLACE !== '') { - await addOrUpdateLotOccupancyField({ + await addOrUpdateBurialSiteContractField({ burialSiteContractId, contractTypeFieldId: occupancyType.ContractTypeFields.find((occupancyTypeField) => occupancyTypeField.occupancyTypeField === 'Death Place').contractTypeFieldId, burialSiteContractFieldValue: workOrderRow.WO_DEATH_PLACE }, user); } if (workOrderRow.WO_AGE !== '') { - await addOrUpdateLotOccupancyField({ + await addOrUpdateBurialSiteContractField({ burialSiteContractId, contractTypeFieldId: occupancyType.ContractTypeFields.find((occupancyTypeField) => occupancyTypeField.occupancyTypeField === 'Death Age').contractTypeFieldId, burialSiteContractFieldValue: workOrderRow.WO_AGE @@ -790,9 +781,9 @@ async function importFromWorkOrderCSV() { } if (workOrderRow.WO_PERIOD !== '') { const period = importData.getDeathAgePeriod(workOrderRow.WO_PERIOD); - await addOrUpdateLotOccupancyField({ + await addOrUpdateBurialSiteContractField({ burialSiteContractId, - contractTypeFieldId: occupancyType.ContractTypeFields.find((occupancyTypeField) => (occupancyTypeField.occupancyTypeField === 'Death Age Period')).contractTypeFieldId, + contractTypeFieldId: occupancyType.ContractTypeFields.find((occupancyTypeField) => occupancyTypeField.occupancyTypeField === 'Death Age Period').contractTypeFieldId, burialSiteContractFieldValue: period }, user); } @@ -812,7 +803,7 @@ async function importFromWorkOrderCSV() { occupantEmailAddress: funeralHomeOccupant.occupantEmailAddress }, user); /* - addOrUpdateLotOccupancyField( + addOrUpdateBurialSiteContractField( { burialSiteContractId: burialSiteContractId, contractTypeFieldId: allContractTypeFields.find((occupancyTypeField) => { @@ -826,7 +817,7 @@ async function importFromWorkOrderCSV() { } if (workOrderRow.WO_FUNERAL_YR !== '') { const burialSiteContractFieldValue = formatDateString(workOrderRow.WO_FUNERAL_YR, workOrderRow.WO_FUNERAL_MON, workOrderRow.WO_FUNERAL_DAY); - await addOrUpdateLotOccupancyField({ + await addOrUpdateBurialSiteContractField({ burialSiteContractId, contractTypeFieldId: occupancyType.ContractTypeFields.find((occupancyTypeField) => occupancyTypeField.occupancyTypeField === 'Funeral Date').contractTypeFieldId, burialSiteContractFieldValue @@ -834,9 +825,9 @@ async function importFromWorkOrderCSV() { } if (occupancyType.occupancyType !== 'Cremation') { if (workOrderRow.WO_CONTAINER_TYPE !== '') { - await addOrUpdateLotOccupancyField({ + await addOrUpdateBurialSiteContractField({ burialSiteContractId, - contractTypeFieldId: occupancyType.ContractTypeFields.find((occupancyTypeField) => (occupancyTypeField.occupancyTypeField === 'Container Type')).contractTypeFieldId, + contractTypeFieldId: occupancyType.ContractTypeFields.find((occupancyTypeField) => occupancyTypeField.occupancyTypeField === 'Container Type').contractTypeFieldId, burialSiteContractFieldValue: workOrderRow.WO_CONTAINER_TYPE }, user); } @@ -845,9 +836,9 @@ async function importFromWorkOrderCSV() { if (commitalType === 'GS') { commitalType = 'Graveside'; } - await addOrUpdateLotOccupancyField({ + await addOrUpdateBurialSiteContractField({ burialSiteContractId, - contractTypeFieldId: occupancyType.ContractTypeFields.find((occupancyTypeField) => (occupancyTypeField.occupancyTypeField === 'Committal Type')).contractTypeFieldId, + contractTypeFieldId: occupancyType.ContractTypeFields.find((occupancyTypeField) => occupancyTypeField.occupancyTypeField === 'Committal Type').contractTypeFieldId, burialSiteContractFieldValue: commitalType }, user); } diff --git a/temp/legacy.importFromCSV.ts b/temp/legacy.importFromCSV.ts index a6b7b784..542bf241 100644 --- a/temp/legacy.importFromCSV.ts +++ b/temp/legacy.importFromCSV.ts @@ -1,3 +1,5 @@ +/* eslint-disable max-lines */ + import fs from 'node:fs' import { @@ -9,23 +11,25 @@ import { import sqlite from 'better-sqlite3' import papa from 'papaparse' -import { sunriseDB as databasePath } from '../data/databasePaths.js' -import addLot from '../database/addLot.js' +import { sunriseDB as databasePath } from '../helpers/database.helpers.js' +import addBurialSite from '../database/addBurialSite.js' import addBurialSiteContract from '../database/addBurialSiteContract.js' import addBurialSiteContractComment from '../database/addBurialSiteContractComment.js' import addBurialSiteContractFee from '../database/addBurialSiteContractFee.js' import addBurialSiteContractOccupant from '../database/addBurialSiteContractOccupant.js' import addBurialSiteContractTransaction from '../database/addBurialSiteContractTransaction.js' -import addMap from '../database/addMap.js' -import addOrUpdateLotOccupancyField from '../database/addOrUpdateLotOccupancyField.js' +import addCemetery from '../database/addCemetery.js' +import addOrUpdateBurialSiteContractField from '../database/addOrUpdateBurialSiteContractField.js' import addWorkOrder from '../database/addWorkOrder.js' -import addWorkOrderLot from '../database/addWorkOrderLot.js' +import addWorkOrderBurialSite from '../database/addWorkOrderBurialSite.js' import addWorkOrderBurialSiteContract from '../database/addWorkOrderBurialSiteContract.js' import addWorkOrderMilestone from '../database/addWorkOrderMilestone.js' import closeWorkOrder from '../database/closeWorkOrder.js' -import getLot, { getLotByLotName } from '../database/getLot.js' +import getBurialSite, { + getBurialSiteByBurialSiteName +} from '../database/getBurialSite.js' import getBurialSiteContracts from '../database/getBurialSiteContracts.js' -import getMapFromDatabase from '../database/getMap.js' +import getCemeteryFromDatabase from '../database/getCemetery.js' import getWorkOrder, { getWorkOrderByWorkOrderNumber } from '../database/getWorkOrder.js' @@ -194,18 +198,18 @@ function purgeTables(): void { const tablesToPurge = [ 'WorkOrderMilestones', 'WorkOrderComments', - 'WorkOrderLots', - 'WorkOrderLotOccupancies', + 'WorkOrderBurialSites', + 'WorkOrderBurialSiteContracts', 'WorkOrders', - 'LotOccupancyTransactions', - 'LotOccupancyFees', - 'LotOccupancyFields', - 'LotOccupancyComments', - 'LotOccupancyOccupants', - 'LotOccupancies', - 'LotFields', - 'LotComments', - 'Lots' + 'BurialSiteContractTransactions', + 'BurialSiteContractFees', + 'BurialSiteContractFields', + 'BurialSiteContractComments', + 'BurialSiteContractInterments', + 'BurialSiteContracts', + 'BurialSiteFields', + 'BurialSiteComments', + 'BurialSites' ] const database = sqlite(databasePath) @@ -226,25 +230,27 @@ function purgeConfigTables(): void { console.time('purgeConfigTables') const database = sqlite(databasePath) - database.prepare('delete from Maps').run() - database.prepare("delete from sqlite_sequence where name in ('Maps')").run() + database.prepare('delete from Cemeteries').run() + database.prepare("delete from sqlite_sequence where name in ('Cemeteries')").run() database.close() console.timeEnd('purgeConfigTables') } -function getMapByMapDescription(mapDescription: string): recordTypes.MapRecord { +function getCemeteryByDescription( + cemeteryDescription: string +): recordTypes.Cemetery | undefined { const database = sqlite(databasePath, { readonly: true }) - const map = database - .prepare('select * from Maps where mapDescription = ?') - .get(mapDescription) as recordTypes.MapRecord + const cemetery = database + .prepare('select * from Cemeteries where cemeteryDescription = ?') + .get(cemeteryDescription) as recordTypes.Cemetery database.close() - return map + return cemetery } function formatDateString( @@ -280,11 +286,11 @@ const cemeteryTocemeteryName = { WK: 'West Korah' } -const mapCache = new Map() +const cemeteryCache = new Map() -async function getMap(dataRow: { +async function getCemetery(dataRow: { cemetery: string -}): Promise { +}): Promise { const mapCacheKey = dataRow.cemetery /* @@ -294,38 +300,39 @@ async function getMap(dataRow: { } */ - if (mapCache.has(mapCacheKey)) { - return mapCache.get(mapCacheKey)! + if (cemeteryCache.has(mapCacheKey)) { + return cemeteryCache.get(mapCacheKey)! } - let map = getMapByMapDescription(mapCacheKey) + let cemetery = getCemeteryByDescription(mapCacheKey) - if (!map) { - console.log(`Creating map: ${dataRow.cemetery}`) + if (cemetery === undefined) { + console.log(`Creating cemetery: ${dataRow.cemetery}`) - const cemeteryId = await addMap( + const cemeteryId = await addCemetery( { - cemeteryName: cemeteryTocemeteryName[dataRow.cemetery] ?? dataRow.cemetery, - mapDescription: dataRow.cemetery, - mapSVG: '', - mapLatitude: '', - mapLongitude: '', - mapAddress1: '', - mapAddress2: '', - mapCity: 'Sault Ste. Marie', - mapProvince: 'ON', - mapPostalCode: '', - mapPhoneNumber: '' + cemeteryName: + cemeteryTocemeteryName[dataRow.cemetery] ?? dataRow.cemetery, + cemeteryDescription: dataRow.cemetery, + cemeterySvg: '', + cemeteryLatitude: '', + cemeteryLongitude: '', + cemeteryAddress1: '', + cemeteryAddress2: '', + cemeteryCity: 'Sault Ste. Marie', + cemeteryProvince: 'ON', + cemeteryPostalCode: '', + cemeteryPhoneNumber: '' }, user ) - map = (await getMapFromDatabase(cemeteryId)) as recordTypes.MapRecord + cemetery = (await getCemeteryFromDatabase(cemeteryId)) as recordTypes.Cemetery } - mapCache.set(mapCacheKey, map) + cemeteryCache.set(mapCacheKey, cemetery) - return map + return cemetery } async function importFromMasterCSV(): Promise { @@ -347,36 +354,24 @@ async function importFromMasterCSV(): Promise { try { for (masterRow of cmmaster.data) { - const map = await getMap({ + const cemetery = await getCemetery({ cemetery: masterRow.CM_CEMETERY })! - const lotName = importData.buildLotName({ - cemetery: masterRow.CM_CEMETERY, - block: masterRow.CM_BLOCK, - range1: masterRow.CM_RANGE1, - range2: masterRow.CM_RANGE2, - lot1: masterRow.CM_LOT1, - lot2: masterRow.CM_LOT2, - grave1: masterRow.CM_GRAVE1, - grave2: masterRow.CM_GRAVE2, - interment: masterRow.CM_INTERMENT - }) - const burialSiteTypeId = importIds.getburialSiteTypeId({ cemetery: masterRow.CM_CEMETERY })! - let lotId: number | undefined + let burialSiteId: number | undefined if (masterRow.CM_CEMETERY !== '00') { - lotId = await addLot( + burialSiteId = await addBurialSite( { lotName, burialSiteTypeId, - burialSiteStatusId: importIds.availableburialSiteStatusId, - cemeteryId: map.cemeteryId!, - mapKey: lotName.includes(',') ? lotName.split(',')[0] : lotName, + burialSiteStatusId: importIds.availableBurialSiteStatusId, + cemeteryId: cemetery.cemeteryId!, + cemeterySvgId: '', burialSiteLatitude: '', burialSiteLongitude: '' }, @@ -446,7 +441,7 @@ async function importFromMasterCSV(): Promise { preneedburialSiteContractId = await addBurialSiteContract( { contractTypeId: importIds.preneedOccupancyType.contractTypeId, - lotId: lotId ?? '', + lotId: burialSiteId ?? '', contractStartDateString: preneedcontractStartDateString, contractEndDateString, contractTypeFieldIds: '' @@ -478,7 +473,8 @@ async function importFromMasterCSV(): Promise { await addBurialSiteContractComment( { burialSiteContractId: preneedburialSiteContractId, - burialSiteContractCommentDateString: preneedcontractStartDateString, + burialSiteContractCommentDateString: + preneedcontractStartDateString, burialSiteContractCommentTimeString: '00:00', burialSiteContractComment: masterRow.CM_REMARK1 }, @@ -490,7 +486,8 @@ async function importFromMasterCSV(): Promise { await addBurialSiteContractComment( { burialSiteContractId: preneedburialSiteContractId, - burialSiteContractCommentDateString: preneedcontractStartDateString, + burialSiteContractCommentDateString: + preneedcontractStartDateString, burialSiteContractCommentTimeString: '00:00', burialSiteContractComment: masterRow.CM_REMARK2 }, @@ -502,7 +499,8 @@ async function importFromMasterCSV(): Promise { await addBurialSiteContractComment( { burialSiteContractId: preneedburialSiteContractId, - burialSiteContractCommentDateString: preneedcontractStartDateString, + burialSiteContractCommentDateString: + preneedcontractStartDateString, burialSiteContractCommentTimeString: '00:00', burialSiteContractComment: `Imported Contract #${masterRow.CM_WORK_ORDER}` }, @@ -512,7 +510,7 @@ async function importFromMasterCSV(): Promise { if (contractEndDateString === '') { await updateBurialSiteStatus( - lotId ?? '', + burialSiteId ?? '', importIds.reservedburialSiteStatusId, user ) @@ -549,18 +547,18 @@ async function importFromMasterCSV(): Promise { deceasedcontractStartDateString = '0001-01-01' } - const deceasedcontractEndDateString = lotId + const deceasedcontractEndDateString = burialSiteId ? '' : deceasedcontractStartDateString - const occupancyType = lotId + const occupancyType = burialSiteId ? importIds.deceasedOccupancyType : importIds.cremationOccupancyType deceasedburialSiteContractId = await addBurialSiteContract( { contractTypeId: occupancyType.contractTypeId, - lotId: lotId ?? '', + lotId: burialSiteId ?? '', contractStartDateString: deceasedcontractStartDateString, contractEndDateString: deceasedcontractEndDateString, contractTypeFieldIds: '' @@ -595,11 +593,12 @@ async function importFromMasterCSV(): Promise { masterRow.CM_DEATH_DAY ) - await addOrUpdateLotOccupancyField( + await addOrUpdateBurialSiteContractField( { burialSiteContractId: deceasedburialSiteContractId, contractTypeFieldId: occupancyType.ContractTypeFields!.find( - (occupancyTypeField) => occupancyTypeField.occupancyTypeField === 'Death Date' + (occupancyTypeField) => + occupancyTypeField.occupancyTypeField === 'Death Date' )!.contractTypeFieldId!, burialSiteContractFieldValue }, @@ -608,11 +607,12 @@ async function importFromMasterCSV(): Promise { } if (masterRow.CM_AGE !== '') { - await addOrUpdateLotOccupancyField( + await addOrUpdateBurialSiteContractField( { burialSiteContractId: deceasedburialSiteContractId, contractTypeFieldId: occupancyType.ContractTypeFields!.find( - (occupancyTypeField) => occupancyTypeField.occupancyTypeField === 'Death Age' + (occupancyTypeField) => + occupancyTypeField.occupancyTypeField === 'Death Age' )!.contractTypeFieldId!, burialSiteContractFieldValue: masterRow.CM_AGE }, @@ -623,13 +623,12 @@ async function importFromMasterCSV(): Promise { if (masterRow.CM_PERIOD !== '') { const period = importData.getDeathAgePeriod(masterRow.CM_PERIOD) - await addOrUpdateLotOccupancyField( + await addOrUpdateBurialSiteContractField( { burialSiteContractId: deceasedburialSiteContractId, contractTypeFieldId: occupancyType.ContractTypeFields!.find( - (occupancyTypeField) => ( - occupancyTypeField.occupancyTypeField === 'Death Age Period' - ) + (occupancyTypeField) => + occupancyTypeField.occupancyTypeField === 'Death Age Period' )!.contractTypeFieldId!, burialSiteContractFieldValue: period }, @@ -654,14 +653,16 @@ async function importFromMasterCSV(): Promise { occupantCity: funeralHomeOccupant.occupantCity ?? '', occupantProvince: funeralHomeOccupant.occupantProvince ?? '', occupantPostalCode: funeralHomeOccupant.occupantPostalCode ?? '', - occupantPhoneNumber: funeralHomeOccupant.occupantPhoneNumber ?? '', - occupantEmailAddress: funeralHomeOccupant.occupantEmailAddress ?? '' + occupantPhoneNumber: + funeralHomeOccupant.occupantPhoneNumber ?? '', + occupantEmailAddress: + funeralHomeOccupant.occupantEmailAddress ?? '' }, user ) /* - addOrUpdateLotOccupancyField( + addOrUpdateBurialSiteContractField( { burialSiteContractId: deceasedburialSiteContractId, contractTypeFieldId: allContractTypeFields.find( @@ -683,13 +684,12 @@ async function importFromMasterCSV(): Promise { masterRow.CM_FUNERAL_DAY ) - await addOrUpdateLotOccupancyField( + await addOrUpdateBurialSiteContractField( { burialSiteContractId: deceasedburialSiteContractId, contractTypeFieldId: occupancyType.ContractTypeFields!.find( - (occupancyTypeField) => ( - occupancyTypeField.occupancyTypeField === 'Funeral Date' - ) + (occupancyTypeField) => + occupancyTypeField.occupancyTypeField === 'Funeral Date' )!.contractTypeFieldId!, burialSiteContractFieldValue }, @@ -699,13 +699,12 @@ async function importFromMasterCSV(): Promise { if (occupancyType.occupancyType !== 'Cremation') { if (masterRow.CM_CONTAINER_TYPE !== '') { - await addOrUpdateLotOccupancyField( + await addOrUpdateBurialSiteContractField( { burialSiteContractId: deceasedburialSiteContractId, contractTypeFieldId: occupancyType.ContractTypeFields!.find( - (occupancyTypeField) => ( - occupancyTypeField.occupancyTypeField === 'Container Type' - ) + (occupancyTypeField) => + occupancyTypeField.occupancyTypeField === 'Container Type' )!.contractTypeFieldId!, burialSiteContractFieldValue: masterRow.CM_CONTAINER_TYPE }, @@ -720,13 +719,12 @@ async function importFromMasterCSV(): Promise { commitalType = 'Graveside' } - await addOrUpdateLotOccupancyField( + await addOrUpdateBurialSiteContractField( { burialSiteContractId: deceasedburialSiteContractId, contractTypeFieldId: occupancyType.ContractTypeFields!.find( - (occupancyTypeField) => ( - occupancyTypeField.occupancyTypeField === 'Committal Type' - ) + (occupancyTypeField) => + occupancyTypeField.occupancyTypeField === 'Committal Type' )!.contractTypeFieldId!, burialSiteContractFieldValue: commitalType }, @@ -739,7 +737,8 @@ async function importFromMasterCSV(): Promise { await addBurialSiteContractComment( { burialSiteContractId: deceasedburialSiteContractId, - burialSiteContractCommentDateString: deceasedcontractStartDateString, + burialSiteContractCommentDateString: + deceasedcontractStartDateString, burialSiteContractCommentTimeString: '00:00', burialSiteContractComment: masterRow.CM_REMARK1 }, @@ -751,7 +750,8 @@ async function importFromMasterCSV(): Promise { await addBurialSiteContractComment( { burialSiteContractId: deceasedburialSiteContractId, - burialSiteContractCommentDateString: deceasedcontractStartDateString, + burialSiteContractCommentDateString: + deceasedcontractStartDateString, burialSiteContractCommentTimeString: '00:00', burialSiteContractComment: masterRow.CM_REMARK2 }, @@ -763,7 +763,8 @@ async function importFromMasterCSV(): Promise { await addBurialSiteContractComment( { burialSiteContractId: deceasedburialSiteContractId, - burialSiteContractCommentDateString: deceasedcontractStartDateString, + burialSiteContractCommentDateString: + deceasedcontractStartDateString, burialSiteContractCommentTimeString: '00:00', burialSiteContractComment: `Imported Contract #${masterRow.CM_WORK_ORDER}` }, @@ -771,7 +772,11 @@ async function importFromMasterCSV(): Promise { ) } - await updateBurialSiteStatus(lotId ?? '', importIds.takenburialSiteStatusId, user) + await updateBurialSiteStatus( + burialSiteId ?? '', + importIds.takenburialSiteStatusId, + user + ) if (masterRow.CM_PRENEED_OWNER !== '') { await addBurialSiteContractOccupant( @@ -833,7 +838,7 @@ async function importFromPrepaidCSV(): Promise { let lot: recordTypes.Lot | undefined if (cemetery !== '') { - const map = await getMap({ + const map = await getCemetery({ cemetery }) @@ -849,14 +854,14 @@ async function importFromPrepaidCSV(): Promise { interment: prepaidRow.CMPP_INTERMENT }) - lot = await getLotByLotName(lotName) + lot = await getBurialSiteByLotName(lotName) if (!lot) { const burialSiteTypeId = importIds.getburialSiteTypeId({ cemetery }) - const lotId = await addLot( + const lotId = await addBurialSite( { lotName, burialSiteTypeId, @@ -869,12 +874,19 @@ async function importFromPrepaidCSV(): Promise { user ) - lot = await getLot(lotId) + lot = await getBurialSite(lotId) } } - if (lot && lot.burialSiteStatusId === importIds.availableburialSiteStatusId) { - await updateBurialSiteStatus(lot.lotId, importIds.reservedburialSiteStatusId, user) + if ( + lot && + lot.burialSiteStatusId === importIds.availableburialSiteStatusId + ) { + await updateBurialSiteStatus( + lot.lotId, + importIds.reservedburialSiteStatusId, + user + ) } const contractStartDateString = formatDateString( @@ -909,14 +921,14 @@ async function importFromPrepaidCSV(): Promise { } burialSiteContractId ||= await addBurialSiteContract( - { - lotId: lot ? lot.lotId : '', - contractTypeId: importIds.preneedOccupancyType.contractTypeId, - contractStartDateString, - contractEndDateString: '' - }, - user - ); + { + lotId: lot ? lot.lotId : '', + contractTypeId: importIds.preneedOccupancyType.contractTypeId, + contractStartDateString, + contractEndDateString: '' + }, + user + ) await addBurialSiteContractOccupant( { @@ -1197,18 +1209,22 @@ async function importFromWorkOrderCSV(): Promise { interment: workOrderRow.WO_INTERMENT }) - lot = await getLotByLotName(lotName) + lot = await getBurialSiteByLotName(lotName) if (lot) { - await updateBurialSiteStatus(lot.lotId, importIds.takenburialSiteStatusId, user) + await updateBurialSiteStatus( + lot.lotId, + importIds.takenburialSiteStatusId, + user + ) } else { - const map = await getMap({ cemetery: workOrderRow.WO_CEMETERY }) + const map = await getCemetery({ cemetery: workOrderRow.WO_CEMETERY }) const burialSiteTypeId = importIds.getburialSiteTypeId({ cemetery: workOrderRow.WO_CEMETERY }) - const lotId = await addLot( + const lotId = await addBurialSite( { cemeteryId: map.cemeteryId!, lotName, @@ -1221,7 +1237,7 @@ async function importFromWorkOrderCSV(): Promise { user ) - lot = await getLot(lotId) + lot = await getBurialSite(lotId) } const workOrderContainsLot = workOrder.workOrderLots!.find( @@ -1229,7 +1245,7 @@ async function importFromWorkOrderCSV(): Promise { ) if (!workOrderContainsLot) { - await addWorkOrderLot( + await addWorkOrderBurialSite( { workOrderId: workOrder.workOrderId!, lotId: lot.lotId @@ -1289,11 +1305,12 @@ async function importFromWorkOrderCSV(): Promise { workOrderRow.WO_DEATH_DAY ) - await addOrUpdateLotOccupancyField( + await addOrUpdateBurialSiteContractField( { burialSiteContractId, contractTypeFieldId: occupancyType.ContractTypeFields!.find( - (occupancyTypeField) => occupancyTypeField.occupancyTypeField === 'Death Date' + (occupancyTypeField) => + occupancyTypeField.occupancyTypeField === 'Death Date' )!.contractTypeFieldId!, burialSiteContractFieldValue }, @@ -1302,11 +1319,12 @@ async function importFromWorkOrderCSV(): Promise { } if (workOrderRow.WO_DEATH_PLACE !== '') { - await addOrUpdateLotOccupancyField( + await addOrUpdateBurialSiteContractField( { burialSiteContractId, contractTypeFieldId: occupancyType.ContractTypeFields!.find( - (occupancyTypeField) => occupancyTypeField.occupancyTypeField === 'Death Place' + (occupancyTypeField) => + occupancyTypeField.occupancyTypeField === 'Death Place' )!.contractTypeFieldId!, burialSiteContractFieldValue: workOrderRow.WO_DEATH_PLACE }, @@ -1315,11 +1333,12 @@ async function importFromWorkOrderCSV(): Promise { } if (workOrderRow.WO_AGE !== '') { - await addOrUpdateLotOccupancyField( + await addOrUpdateBurialSiteContractField( { burialSiteContractId, contractTypeFieldId: occupancyType.ContractTypeFields!.find( - (occupancyTypeField) => occupancyTypeField.occupancyTypeField === 'Death Age' + (occupancyTypeField) => + occupancyTypeField.occupancyTypeField === 'Death Age' )!.contractTypeFieldId!, burialSiteContractFieldValue: workOrderRow.WO_AGE }, @@ -1330,13 +1349,12 @@ async function importFromWorkOrderCSV(): Promise { if (workOrderRow.WO_PERIOD !== '') { const period = importData.getDeathAgePeriod(workOrderRow.WO_PERIOD) - await addOrUpdateLotOccupancyField( + await addOrUpdateBurialSiteContractField( { burialSiteContractId, contractTypeFieldId: occupancyType.ContractTypeFields!.find( - (occupancyTypeField) => ( - occupancyTypeField.occupancyTypeField === 'Death Age Period' - ) + (occupancyTypeField) => + occupancyTypeField.occupancyTypeField === 'Death Age Period' )!.contractTypeFieldId!, burialSiteContractFieldValue: period }, @@ -1368,7 +1386,7 @@ async function importFromWorkOrderCSV(): Promise { ) /* - addOrUpdateLotOccupancyField( + addOrUpdateBurialSiteContractField( { burialSiteContractId: burialSiteContractId, contractTypeFieldId: allContractTypeFields.find((occupancyTypeField) => { @@ -1388,11 +1406,12 @@ async function importFromWorkOrderCSV(): Promise { workOrderRow.WO_FUNERAL_DAY ) - await addOrUpdateLotOccupancyField( + await addOrUpdateBurialSiteContractField( { burialSiteContractId, contractTypeFieldId: occupancyType.ContractTypeFields!.find( - (occupancyTypeField) => occupancyTypeField.occupancyTypeField === 'Funeral Date' + (occupancyTypeField) => + occupancyTypeField.occupancyTypeField === 'Funeral Date' )!.contractTypeFieldId!, burialSiteContractFieldValue }, @@ -1402,13 +1421,12 @@ async function importFromWorkOrderCSV(): Promise { if (occupancyType.occupancyType !== 'Cremation') { if (workOrderRow.WO_CONTAINER_TYPE !== '') { - await addOrUpdateLotOccupancyField( + await addOrUpdateBurialSiteContractField( { burialSiteContractId, contractTypeFieldId: occupancyType.ContractTypeFields!.find( - (occupancyTypeField) => ( - occupancyTypeField.occupancyTypeField === 'Container Type' - ) + (occupancyTypeField) => + occupancyTypeField.occupancyTypeField === 'Container Type' )!.contractTypeFieldId!, burialSiteContractFieldValue: workOrderRow.WO_CONTAINER_TYPE }, @@ -1423,13 +1441,12 @@ async function importFromWorkOrderCSV(): Promise { commitalType = 'Graveside' } - await addOrUpdateLotOccupancyField( + await addOrUpdateBurialSiteContractField( { burialSiteContractId, contractTypeFieldId: occupancyType.ContractTypeFields!.find( - (occupancyTypeField) => ( - occupancyTypeField.occupancyTypeField === 'Committal Type' - ) + (occupancyTypeField) => + occupancyTypeField.occupancyTypeField === 'Committal Type' )!.contractTypeFieldId!, burialSiteContractFieldValue: commitalType }, diff --git a/temp/legacy.importFromCsv.data.d.ts b/temp/legacy.importFromCsv.data.d.ts index 22a93891..2b5afdea 100644 --- a/temp/legacy.importFromCsv.data.d.ts +++ b/temp/legacy.importFromCsv.data.d.ts @@ -1,14 +1,3 @@ import type { LotOccupancyOccupant } from '../types/recordTypes.js'; -export declare function buildLotName(lotNamePieces: { - cemetery: string; - block: string; - range1: string; - range2: string; - lot1: string; - lot2: string; - grave1: string; - grave2: string; - interment: string; -}): string; export declare function getFuneralHomeLotOccupancyOccupantData(funeralHomeKey: string): LotOccupancyOccupant; export declare function getDeathAgePeriod(legacyDeathAgePeriod: string): string; diff --git a/temp/legacy.importFromCsv.data.js b/temp/legacy.importFromCsv.data.js index aa5370b3..b396f64d 100644 --- a/temp/legacy.importFromCsv.data.js +++ b/temp/legacy.importFromCsv.data.js @@ -1,18 +1,6 @@ +// eslint-disable-next-line @eslint-community/eslint-comments/disable-enable-pair +/* eslint-disable @cspell/spellchecker */ import * as importIds from './legacy.importFromCsv.ids.js'; -export function buildLotName(lotNamePieces) { - let lotName = `${lotNamePieces.cemetery}-`; - if (lotNamePieces.block !== '') { - lotName += `B${lotNamePieces.block}-`; - } - if (lotNamePieces.range1 !== '0' || lotNamePieces.range2 !== '') { - lotName += `R${lotNamePieces.range1 === '0' ? '' : lotNamePieces.range1}${lotNamePieces.range2}-`; - } - if (lotNamePieces.lot1 !== '0' || lotNamePieces.lot2 === '') { - lotName += `L${lotNamePieces.lot1}${lotNamePieces.lot2}-`; - } - lotName += `G${lotNamePieces.grave1}${lotNamePieces.grave2}, Interment ${lotNamePieces.interment}`; - return lotName; -} export function getFuneralHomeLotOccupancyOccupantData(funeralHomeKey) { switch (funeralHomeKey) { case 'AR': { diff --git a/temp/legacy.importFromCsv.data.ts b/temp/legacy.importFromCsv.data.ts index 63354951..90f6b72e 100644 --- a/temp/legacy.importFromCsv.data.ts +++ b/temp/legacy.importFromCsv.data.ts @@ -1,39 +1,10 @@ +// eslint-disable-next-line @eslint-community/eslint-comments/disable-enable-pair +/* eslint-disable @cspell/spellchecker */ + import type { LotOccupancyOccupant } from '../types/recordTypes.js' import * as importIds from './legacy.importFromCsv.ids.js' -export function buildLotName(lotNamePieces: { - cemetery: string - block: string - range1: string - range2: string - lot1: string - lot2: string - grave1: string - grave2: string - interment: string -}): string { - let lotName = `${lotNamePieces.cemetery}-` - - if (lotNamePieces.block !== '') { - lotName += `B${lotNamePieces.block}-` - } - - if (lotNamePieces.range1 !== '0' || lotNamePieces.range2 !== '') { - lotName += `R${lotNamePieces.range1 === '0' ? '' : lotNamePieces.range1}${ - lotNamePieces.range2 - }-` - } - - if (lotNamePieces.lot1 !== '0' || lotNamePieces.lot2 === '') { - lotName += `L${lotNamePieces.lot1}${lotNamePieces.lot2}-` - } - - lotName += `G${lotNamePieces.grave1}${lotNamePieces.grave2}, Interment ${lotNamePieces.interment}` - - return lotName -} - export function getFuneralHomeLotOccupancyOccupantData( funeralHomeKey: string ): LotOccupancyOccupant { diff --git a/temp/legacy.importFromCsv.ids.js b/temp/legacy.importFromCsv.ids.js index 32f808e8..2cb30094 100644 --- a/temp/legacy.importFromCsv.ids.js +++ b/temp/legacy.importFromCsv.ids.js @@ -25,19 +25,19 @@ export function getFeeIdByFeeDescription(feeDescription) { /* * Lot Occupant Type IDs */ -export const preneedOwnerLotOccupantTypeId = (await cacheFunctions.getLotOccupantTypeByLotOccupantType('Preneed Owner')) +export const preneedOwnerLotOccupantTypeId = (await cacheFunctions.getBurialSiteOccupantTypeByLotOccupantType('Preneed Owner')) .lotOccupantTypeId; -export const funeralDirectorLotOccupantTypeId = (await cacheFunctions.getLotOccupantTypeByLotOccupantType('Funeral Director')).lotOccupantTypeId; -export const deceasedLotOccupantTypeId = (await cacheFunctions.getLotOccupantTypeByLotOccupantType('Deceased')) +export const funeralDirectorLotOccupantTypeId = (await cacheFunctions.getBurialSiteOccupantTypeByLotOccupantType('Funeral Director')).lotOccupantTypeId; +export const deceasedLotOccupantTypeId = (await cacheFunctions.getBurialSiteOccupantTypeByLotOccupantType('Deceased')) .lotOccupantTypeId; -export const purchaserLotOccupantTypeId = (await cacheFunctions.getLotOccupantTypeByLotOccupantType('Purchaser')) +export const purchaserLotOccupantTypeId = (await cacheFunctions.getBurialSiteOccupantTypeByLotOccupantType('Purchaser')) .lotOccupantTypeId; /* * Lot Status IDs */ -export const availableburialSiteStatusId = (await cacheFunctions.getLotStatusByLotStatus('Available')).burialSiteStatusId; -export const reservedburialSiteStatusId = (await cacheFunctions.getLotStatusByLotStatus('Reserved')).burialSiteStatusId; -export const takenburialSiteStatusId = (await cacheFunctions.getLotStatusByLotStatus('Taken')).burialSiteStatusId; +export const availableburialSiteStatusId = (await cacheFunctions.getBurialSiteStatusByLotStatus('Available')).burialSiteStatusId; +export const reservedburialSiteStatusId = (await cacheFunctions.getBurialSiteStatusByLotStatus('Reserved')).burialSiteStatusId; +export const takenburialSiteStatusId = (await cacheFunctions.getBurialSiteStatusByLotStatus('Taken')).burialSiteStatusId; /* * Lot Type IDs */ diff --git a/temp/legacy.importFromCsv.ids.ts b/temp/legacy.importFromCsv.ids.ts index 3d5d85ff..d1fa206b 100644 --- a/temp/legacy.importFromCsv.ids.ts +++ b/temp/legacy.importFromCsv.ids.ts @@ -42,20 +42,20 @@ export function getFeeIdByFeeDescription(feeDescription: string): number { */ export const preneedOwnerLotOccupantTypeId = - (await cacheFunctions.getLotOccupantTypeByLotOccupantType('Preneed Owner'))! + (await cacheFunctions.getBurialSiteOccupantTypeByLotOccupantType('Preneed Owner'))! .lotOccupantTypeId export const funeralDirectorLotOccupantTypeId = - (await cacheFunctions.getLotOccupantTypeByLotOccupantType( + (await cacheFunctions.getBurialSiteOccupantTypeByLotOccupantType( 'Funeral Director' ))!.lotOccupantTypeId export const deceasedLotOccupantTypeId = - (await cacheFunctions.getLotOccupantTypeByLotOccupantType('Deceased'))! + (await cacheFunctions.getBurialSiteOccupantTypeByLotOccupantType('Deceased'))! .lotOccupantTypeId export const purchaserLotOccupantTypeId = - (await cacheFunctions.getLotOccupantTypeByLotOccupantType('Purchaser'))! + (await cacheFunctions.getBurialSiteOccupantTypeByLotOccupantType('Purchaser'))! .lotOccupantTypeId /* @@ -63,10 +63,10 @@ export const purchaserLotOccupantTypeId = */ export const availableburialSiteStatusId = - (await cacheFunctions.getLotStatusByLotStatus('Available'))!.burialSiteStatusId + (await cacheFunctions.getBurialSiteStatusByLotStatus('Available'))!.burialSiteStatusId export const reservedburialSiteStatusId = - (await cacheFunctions.getLotStatusByLotStatus('Reserved'))!.burialSiteStatusId -export const takenburialSiteStatusId = (await cacheFunctions.getLotStatusByLotStatus( + (await cacheFunctions.getBurialSiteStatusByLotStatus('Reserved'))!.burialSiteStatusId +export const takenburialSiteStatusId = (await cacheFunctions.getBurialSiteStatusByLotStatus( 'Taken' ))!.burialSiteStatusId diff --git a/test/functions.js b/test/functions.js index 5b3f8445..cbbdeade 100644 --- a/test/functions.js +++ b/test/functions.js @@ -19,18 +19,18 @@ describe('functions.cache', () => { const lotStatuses = await cacheFunctions.getBurialSiteStatuses(); assert.ok(lotStatuses.length > 0); for (const lotStatus of lotStatuses) { - const byId = await cacheFunctions.getLotStatusById(lotStatus.burialSiteStatusId); + const byId = await cacheFunctions.getBurialSiteStatusById(lotStatus.burialSiteStatusId); assert.strictEqual(lotStatus.burialSiteStatusId, byId?.burialSiteStatusId); - const byName = await cacheFunctions.getLotStatusByLotStatus(lotStatus.lotStatus); + const byName = await cacheFunctions.getBurialSiteStatusByLotStatus(lotStatus.lotStatus); assert.strictEqual(lotStatus.lotStatus, byName?.lotStatus); } }); it('returns undefined with a bad burialSiteStatusId', async () => { - const byBadId = await cacheFunctions.getLotStatusById(badId); + const byBadId = await cacheFunctions.getBurialSiteStatusById(badId); assert.ok(byBadId === undefined); }); it('returns undefined with a bad lotStatus', async () => { - const byBadName = await cacheFunctions.getLotStatusByLotStatus(badName); + const byBadName = await cacheFunctions.getBurialSiteStatusByLotStatus(badName); assert.ok(byBadName === undefined); }); }); @@ -40,14 +40,14 @@ describe('functions.cache', () => { const lotTypes = await cacheFunctions.getBurialSiteTypes(); assert.ok(lotTypes.length > 0); for (const lotType of lotTypes) { - const byId = await cacheFunctions.getLotTypeById(lotType.burialSiteTypeId); + const byId = await cacheFunctions.getBurialSiteTypeById(lotType.burialSiteTypeId); assert.strictEqual(lotType.burialSiteTypeId, byId?.burialSiteTypeId); const byName = await cacheFunctions.getBurialSiteTypesByBurialSiteType(lotType.lotType); assert.strictEqual(lotType.lotType, byName?.lotType); } }); it('returns undefined with a bad burialSiteTypeId', async () => { - const byBadId = await cacheFunctions.getLotTypeById(badId); + const byBadId = await cacheFunctions.getBurialSiteTypeById(badId); assert.ok(byBadId === undefined); }); it('returns undefined with a bad lotType', async () => { diff --git a/test/functions.ts b/test/functions.ts index 90f9ba5e..b012be1a 100644 --- a/test/functions.ts +++ b/test/functions.ts @@ -26,12 +26,12 @@ describe('functions.cache', () => { assert.ok(lotStatuses.length > 0) for (const lotStatus of lotStatuses) { - const byId = await cacheFunctions.getLotStatusById( + const byId = await cacheFunctions.getBurialSiteStatusById( lotStatus.burialSiteStatusId ) assert.strictEqual(lotStatus.burialSiteStatusId, byId?.burialSiteStatusId) - const byName = await cacheFunctions.getLotStatusByLotStatus( + const byName = await cacheFunctions.getBurialSiteStatusByLotStatus( lotStatus.lotStatus ) assert.strictEqual(lotStatus.lotStatus, byName?.lotStatus) @@ -39,12 +39,12 @@ describe('functions.cache', () => { }) it('returns undefined with a bad burialSiteStatusId', async () => { - const byBadId = await cacheFunctions.getLotStatusById(badId) + const byBadId = await cacheFunctions.getBurialSiteStatusById(badId) assert.ok(byBadId === undefined) }) it('returns undefined with a bad lotStatus', async () => { - const byBadName = await cacheFunctions.getLotStatusByLotStatus(badName) + const byBadName = await cacheFunctions.getBurialSiteStatusByLotStatus(badName) assert.ok(byBadName === undefined) }) }) @@ -58,7 +58,7 @@ describe('functions.cache', () => { assert.ok(lotTypes.length > 0) for (const lotType of lotTypes) { - const byId = await cacheFunctions.getLotTypeById(lotType.burialSiteTypeId) + const byId = await cacheFunctions.getBurialSiteTypeById(lotType.burialSiteTypeId) assert.strictEqual(lotType.burialSiteTypeId, byId?.burialSiteTypeId) const byName = await cacheFunctions.getBurialSiteTypesByBurialSiteType( @@ -69,7 +69,7 @@ describe('functions.cache', () => { }) it('returns undefined with a bad burialSiteTypeId', async () => { - const byBadId = await cacheFunctions.getLotTypeById(badId) + const byBadId = await cacheFunctions.getBurialSiteTypeById(badId) assert.ok(byBadId === undefined) }) diff --git a/views/_footerA.ejs b/views/_footerA.ejs index 518f37e0..44c821ac 100644 --- a/views/_footerA.ejs +++ b/views/_footerA.ejs @@ -14,15 +14,6 @@ + <%- include('_footerB'); -%> \ No newline at end of file diff --git a/views/cemetery-search.ejs b/views/cemetery-search.ejs index a1166023..c9e656ea 100644 --- a/views/cemetery-search.ejs +++ b/views/cemetery-search.ejs @@ -6,7 +6,7 @@
  • - <%= configFunctions.getConfigProperty("aliases.maps") %> + Cemeteries
  • @@ -15,11 +15,11 @@

    - Find a <%= configFunctions.getConfigProperty("aliases.map") %> + Find a Cemetery

    - + Export @@ -29,11 +29,11 @@ <% if (user.userProperties.canUpdate) { %> <% } %> @@ -42,8 +42,8 @@
    - name, description, and address" + @@ -58,8 +58,8 @@ <%- include('_footerA'); -%> - + <%- include('_footerB'); -%> \ No newline at end of file diff --git a/views/cemetery-view.ejs b/views/cemetery-view.ejs index 875dc2c0..9b4afbd5 100644 --- a/views/cemetery-view.ejs +++ b/views/cemetery-view.ejs @@ -4,44 +4,44 @@

    - <%= map.mapName || "(No Name)" %> + <%= cemetery.cemeteryName || "(No Name)" %>

    - <%= map.mapName || "(No Name)" %> + <%= cemetery.cemeteryName || "(No Name)" %>
    -
    -
    - <% if (map.mapDescription && map.mapDescription !== "") { %> -
    - Description
    - <%= map.mapDescription %> -
    - <% } %> -
    - Address
    - <% if (map.mapAddress1 !== "") { %> - <%= map.mapAddress1 %>
    - <% } %> - <% if (map.mapAddress2 !== "") { %> - <%= map.mapAddress2 %>
    - <% } %> - <%= map.mapCity %>, <%= map.mapProvince %>
    - <%= map.mapPostalCode %> -
    - <% if (map.mapPhoneNumber !== "") { %> -
    - Phone Number
    - <%= map.mapPhoneNumber %> -
    - <% } %> +
    +
    + <% if (cemetery.cemeteryDescription && cemetery.cemeteryDescription !== "") { %> +
    + Description
    + <%= cemetery.cemeteryDescription %>
    + <% } %> +
    + Address
    + <% if (cemetery.cemeteryAddress1 !== "") { %> + <%= cemetery.cemeteryAddress1 %>
    + <% } %> + <% if (cemetery.cemeteryAddress2 !== "") { %> + <%= cemetery.cemeteryAddress2 %>
    + <% } %> + <%= cemetery.cemeteryCity %>, <%= cemetery.cemeteryProvince %>
    + <%= cemetery.cemeteryPostalCode %> +
    + <% if (cemetery.cemeteryPhoneNumber !== "") { %> +
    + Phone Number
    + <%= cemetery.cemeteryPhoneNumber %> +
    + <% } %>
    +
    -
    -

    Geographic Location

    -
    - <% if (map.mapLatitude && map.mapLongitude) { %> -
    - <% } else { %> -
    -

    There are no geographic coordinates associated with this <%= configFunctions.getConfigProperty("aliases.map").toLowerCase() %>.

    -
    - <% } %> -
    +
    +

    Geographic Location

    +
    + <% if (cemetery.cemeteryLatitude && cemetery.cemeteryLongitude) { %> +
    + <% } else { %> +
    +

    There are no geographic coordinates associated with this cemetery.

    +
    + <% } %>
    +

    Image

    - <% if (map.mapSVG) { %> - <% const imageURL = urlPrefix + "/images/maps/" + map.mapSVG %> - - <%- include('../public/images/maps/' + map.mapSVG); -%> + <% if (cemetery.cemeterySvg) { %> + <% const imageURL = urlPrefix + "/images/cemeteries/" + cemetery.cemeterySvg %> + + <%- include('../public/images/cemeteries/' + cemetery.cemeterySvg); -%> <% } else { %>
    -

    There are no image associated with this <%= configFunctions.getConfigProperty("aliases.map").toLowerCase() %>.

    +

    There are no image associated with this cemetery.

    <% } %>
    @@ -124,38 +124,37 @@
    -<% const lotSearchUrl = urlPrefix + "/lots?mapId=" + map.mapId; %> +<% const burialSiteSearchUrl = urlPrefix + "/burialSites?cemeteryId=" + cemetery.cemeteryId; %>
    -
    -

    - <%= configFunctions.getConfigProperty("aliases.lot") %> Summaries - - <%= map.lotCount %> - -

    -
    +
    +

    + Burial Site Summaries + + <%= cemetery.burialSiteCount %> + +

    +
    - <% if (map.lotCount === 0) { %> -
    -

    - There are no <%= configFunctions.getConfigProperty("aliases.lots").toLowerCase() %> - associated with this <%= configFunctions.getConfigProperty("aliases.map").toLowerCase() %>. -

    -
    + <% if (cemetery.burialSiteCount === 0) { %> +
    +

    + There are no burial sites associated with this cemetery. +

    +
    <% } else { %>
    @@ -164,56 +163,56 @@
    - <% for (const lotType of lotTypeSummary) { %> - - - - - - <% } %> + <% for (const burialSiteType of burialSiteTypeSummary) { %> + + + + + + <% } %>
    Type - <%= configFunctions.getConfigProperty("aliases.lot") %> Count + Burial Site Count Percentage
    - - <%= lotType.lotType %> - - - <%= lotType.lotCount %> - - <%= ((lotType.lotCount / map.lotCount) * 100).toFixed(1) %>% -
    + + <%= burialSiteType.burialSiteType %> + + + <%= burialSiteType.burialSiteCount %> + + <%= ((burialSiteType.burialSiteCount / cemetery.burialSiteCount) * 100).toFixed(1) %>% +
    - - - - - + + + + + - <% for (const lotStatus of lotStatusSummary) { %> - - - - - + <% for (const burialSiteStatus of burialSiteStatusSummary) { %> + + + + + <% } %>
    Status - <%= configFunctions.getConfigProperty("aliases.lot") %> Count - Percentage
    Status + Burial Site Count + Percentage
    - - <%= lotStatus.lotStatus %> - - - <%= lotStatus.lotCount %> - - <%= ((lotStatus.lotCount / map.lotCount) * 100).toFixed(1) %>% -
    + + <%= burialSiteStatus.burialSiteStatus %> + + + <%= burialSiteStatus.burialSiteCount %> + + <%= ((burialSiteStatus.burialSiteCount / map.burialSiteCount) * 100).toFixed(1) %>% +
    @@ -225,6 +224,6 @@ <%- include('_footerA'); -%> - + <%- include('_footerB'); -%> \ No newline at end of file diff --git a/views/dashboard.ejs b/views/dashboard.ejs index 408e7280..b349198d 100644 --- a/views/dashboard.ejs +++ b/views/dashboard.ejs @@ -59,25 +59,24 @@ <%= milestone.workOrderNumber %>
    <% - if (milestone.workOrderLots.length > 0) { - for (const lot of milestone.workOrderLots) { + if (milestone.workOrderBurialSites.length > 0) { + for (const burialSite of milestone.workOrderBurialSites) { %> - - "> - <%= lot.lotName %> + + + <%= burialSite.burialSiteName %>
    <% } } - if (milestone.workOrderLotOccupancies.length > 0) { - for (const occupancy of milestone.workOrderLotOccupancies) { - for (const occupant of occupancy.lotOccupancyOccupants) { + if (milestone.workOrderBurialSiteContracts.length > 0) { + for (const burialSiteContract of milestone.workOrderBurialSiteContracts) { + for (const interment of burialSiteContract.lotOccupancyInterments) { %> - - "> - <%= occupant.occupantName %> - <%= occupant.occupantFamilyName %> + + + <%= interment.deceasedName %>
    <% } @@ -94,87 +93,86 @@ <% } %>
    -
    -
    -
    - - <% if (user.userProperties.canUpdate) { %> - - - - - New Work Order - - <% } %> - - - + -
    - <% if (user.userProperties.canUpdate) { %> - + - New <%= configFunctions.getConfigProperty("aliases.map") %> + New Cemetery <% } %>
    @@ -262,12 +258,13 @@
    @@ -291,11 +288,8 @@ Fee Management

    - Manage fees for - <%= configFunctions.getConfigProperty("aliases.lot").toLowerCase() %> - <%= configFunctions.getConfigProperty("aliases.occupancy").toLowerCase() %> - and specific - <%= configFunctions.getConfigProperty("aliases.lot").toLowerCase() %> types. + Manage fees for contracts + and specific burial site types.

    @@ -308,13 +302,12 @@
    - +

    - Manage - <%= configFunctions.getConfigProperty("aliases.occupancy").toLowerCase() %> types, + Manage contract types, the fields associated with them, and their available print options.

    @@ -329,14 +322,12 @@
    - +

    - Manage - <%= configFunctions.getConfigProperty("aliases.lot").toLowerCase() %> types - and fields associated with them. + Manage burial site types and fields associated with them.

    @@ -355,9 +346,8 @@

    Manage simple configuration tables fees for - work order types, - <%= configFunctions.getConfigProperty("aliases.lot").toLowerCase() %> statuses, - and <%= configFunctions.getConfigProperty("aliases.lot").toLowerCase() %> <%= configFunctions.getConfigProperty("aliases.occupant").toLowerCase() %> types. + work order types + and burial site statuses.