major refactoring, but the application starts!

deepsource-autofix-76c6eb20
Dan Gowans 2025-02-25 15:25:38 -05:00
parent 06f6874298
commit 0bdc76247f
98 changed files with 7548 additions and 1115 deletions

View File

@ -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,

View File

@ -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,

View File

@ -13,4 +13,4 @@ export interface AddBurialSiteForm {
burialSiteTypeFieldIds?: string;
[fieldValue_burialSiteTypeFieldId: string]: unknown;
}
export default function addLot(burialSiteForm: AddBurialSiteForm, user: User): Promise<number>;
export default function addBurialSite(burialSiteForm: AddBurialSiteForm, user: User): Promise<number>;

View File

@ -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);

View File

@ -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<number> {

View File

@ -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();
}

View File

@ -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()
}

View File

@ -1,5 +1,6 @@
export interface AddCemeteryForm {
cemeteryName: string;
cemeteryKey: string;
cemeteryDescription: string;
cemeterySvg: string;
cemeteryLatitude: string;

View File

@ -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;
}

View File

@ -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,

View File

@ -2,4 +2,4 @@ export interface AddWorkOrderLotForm {
workOrderId: number | string;
burialSiteId: number | string;
}
export default function addWorkOrderLot(workOrderLotForm: AddWorkOrderLotForm, user: User): Promise<boolean>;
export default function addWorkOrderBurialSite(workOrderLotForm: AddWorkOrderLotForm, user: User): Promise<boolean>;

View File

@ -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

View File

@ -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<boolean> {

View File

@ -1,2 +1,2 @@
import type { Cemetery } from '../types/recordTypes.js';
export default function getMap(cemeteryId: number | string): Promise<Cemetery | undefined>;
export default function getCemetery(cemeteryId: number | string): Promise<Cemetery | undefined>;

View File

@ -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,

View File

@ -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<Cemetery | undefined> {
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,

View File

@ -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`,
/*

View File

@ -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`,

View File

@ -1,6 +1,7 @@
export interface UpdateCemeteryForm {
cemeteryId: string;
cemeteryName: string;
cemeteryKey: string;
cemeteryDescription: string;
cemeterySvg: string;
cemeteryLatitude: string;

View File

@ -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;
}

View File

@ -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,

View File

@ -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);
}

View File

@ -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)

View File

@ -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');

View File

@ -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-]+$/

View File

@ -17,6 +17,6 @@ export declare function getWorkOrderMilestoneTypeById(workOrderMilestoneTypeId:
export declare function getWorkOrderMilestoneTypeByWorkOrderMilestoneType(workOrderMilestoneTypeString: string): Promise<WorkOrderMilestoneType | undefined>;
export declare function preloadCaches(): Promise<void>;
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 {};

View File

@ -177,7 +177,6 @@ export function clearCacheByTableName(tableName, relayMessage = true) {
clearWorkOrderTypesCache();
break;
}
// eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check
default: {
return;
}

View File

@ -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
}

View File

@ -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';

View File

@ -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'

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

View File

@ -0,0 +1 @@
export {};

View File

@ -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 = `<div class="message is-info">
<p class="message-body">Select the ${los.escapedAliases.lot} type to load the available fields.</p>
</div>`;
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 = `<div class="message is-info">
<p class="message-body">
There are no additional fields for this ${los.escapedAliases.lot} type.
</p>
</div>`;
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 = `<label class="label" for="${fieldId}"></label>
<div class="control"></div>`;
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 = `<div class="select is-fullwidth">
<select id="${fieldId}" name="${fieldName}"><option value="">(Not Set)</option></select>
</div>`;
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', `<input name="lotTypeFieldIds" type="hidden"
value="${cityssm.escapeHTML(lotTypeFieldIds.slice(1))}" />`);
});
});
}
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 = `<div class="message is-info">
<p class="message-body">There are no comments to display.</p>
</div>`;
return;
}
const tableElement = document.createElement('table');
tableElement.className = 'table is-fullwidth is-striped is-hoverable';
tableElement.innerHTML = `<thead><tr>
<th>Commentor</th>
<th>Comment Date</th>
<th>Comment</th>
<th class="is-hidden-print"><span class="is-sr-only">Options</span></th>
</tr></thead>
<tbody></tbody>`;
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 = `<td>
${cityssm.escapeHTML(lotComment.recordCreate_userName ?? '')}
</td><td>
${lotComment.lotCommentDateString}
${lotComment.lotCommentTime === 0
? ''
: ` ${lotComment.lotCommentTimePeriodString}`}
</td><td>
${cityssm.escapeHTML(lotComment.lotComment ?? '')}
</td><td class="is-hidden-print">
<div class="buttons are-small is-justify-content-end">
<button class="button is-primary button--edit" type="button">
<span class="icon is-small"><i class="fas fa-pencil-alt" aria-hidden="true"></i></span>
<span>Edit</span>
</button>
<button class="button is-light is-danger button--delete" data-tooltip="Delete Comment" type="button" aria-label="Delete">
<i class="fas fa-trash" aria-hidden="true"></i>
</button>
</div>
</td>`;
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();
}
})();

View File

@ -55,7 +55,7 @@ declare const exports: Record<string, unknown>
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<string, unknown>
if (responseJSON.success) {
clearUnsavedChanges()
window.location.href = los.getLotURL()
window.location.href = los.getBurialSiteURL()
} else {
bulmaJS.alert({
title: `Error Deleting ${los.escapedAliases.Lot}`,

View File

@ -0,0 +1 @@
export {};

View File

@ -20,13 +20,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
// eslint-disable-next-line no-unsanitized/method
resultsTbodyElement.insertAdjacentHTML('beforeend', `<tr>
<td>
<a class="has-text-weight-bold" href="${los.getLotURL(lot.lotId)}">
<a class="has-text-weight-bold" href="${los.getBurialSiteURL(lot.lotId)}">
${cityssm.escapeHTML(lot.lotName ?? '')}
</a>
</td><td>
<a href="${los.getMapURL(lot.mapId)}">
${lot.mapName
? cityssm.escapeHTML(lot.mapName)
<a href="${los.getCemeteryURL(lot.cemeteryId)}">
${lot.cemeteryName
? cityssm.escapeHTML(lot.cemeteryName)
: '<span class="has-text-grey">(No Name)</span>'}
</a>
</td><td>
@ -35,7 +35,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
${lot.burialSiteStatusId
? cityssm.escapeHTML(lot.lotStatus ?? '')
: '<span class="has-text-grey">(No Status)</span>'}<br />
${(lot.lotOccupancyCount ?? 0) > 0
${(lot.burialSiteContractCount ?? 0) > 0
? '<span class="is-size-7">Currently Occupied</span>'
: ''}
</td>
@ -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();
})();

View File

@ -49,11 +49,11 @@ declare const exports: Record<string, unknown>
'beforeend',
`<tr>
<td>
<a class="has-text-weight-bold" href="${los.getLotURL(lot.lotId)}">
<a class="has-text-weight-bold" href="${los.getBurialSiteURL(lot.lotId)}">
${cityssm.escapeHTML(lot.lotName ?? '')}
</a>
</td><td>
<a href="${los.getMapURL(lot.cemeteryId)}">
<a href="${los.getCemeteryURL(lot.cemeteryId)}">
${
lot.cemeteryName
? cityssm.escapeHTML(lot.cemeteryName)

View File

@ -0,0 +1 @@
export {};

View File

@ -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');
}
})();

View File

@ -0,0 +1 @@
export {};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1 @@
export {};

View File

@ -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 = `<div class="message is-info">
<p class="message-body">
There are no ${los.escapedAliases.occupancy} records that meet the search criteria.
</p>
</div>`;
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 = `<span class="has-tooltip-right" data-tooltip="Current ${los.escapedAliases.Occupancy}">
<i class="fas fa-play" aria-label="Current ${los.escapedAliases.Occupancy}"></i>
</span>`;
}
else if (burialSiteContract.contractStartDateString > nowDateString) {
occupancyTimeHTML = `<span class="has-tooltip-right" data-tooltip="Future ${los.escapedAliases.Occupancy}">
<i class="fas fa-fast-forward" aria-label="Future ${los.escapedAliases.Occupancy}"></i>
</span>`;
}
else {
occupancyTimeHTML = `<span class="has-tooltip-right" data-tooltip="Past ${los.escapedAliases.Occupancy}">
<i class="fas fa-stop" aria-label="Past ${los.escapedAliases.Occupancy}"></i>
</span>`;
}
let occupantsHTML = '';
for (const occupant of burialSiteContract.burialSiteContractOccupants ?? []) {
occupantsHTML += `<li class="has-tooltip-left" data-tooltip="${cityssm.escapeHTML(occupant.lotOccupantType ?? '')}">
<span class="fa-li">
<i class="fas fa-fw fa-${cityssm.escapeHTML((occupant.fontAwesomeIconClass ?? '') === ''
? 'user'
: occupant.fontAwesomeIconClass ?? '')}" aria-hidden="true"></i>
</span>
${cityssm.escapeHTML(occupant.occupantName ?? '')}
${cityssm.escapeHTML(occupant.occupantFamilyName ?? '')}
</li>`;
}
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 = `<span class="icon"
data-tooltip="Total Fees: $${feeTotal}"
aria-label="Total Fees: $${feeTotal}">
<i class="fas fa-dollar-sign ${feeTotal === transactionTotal
? 'has-text-success'
: 'has-text-danger'}" aria-hidden="true"></i>
</span>`;
}
// eslint-disable-next-line no-unsanitized/method
resultsTbodyElement.insertAdjacentHTML('beforeend', `<tr>
<td class="has-width-1">
${occupancyTimeHTML}
</td><td>
<a class="has-text-weight-bold"
href="${los.getBurialSiteContractURL(burialSiteContract.burialSiteContractId)}">
${cityssm.escapeHTML(burialSiteContract.occupancyType ?? '')}
</a><br />
<span class="is-size-7">#${burialSiteContract.burialSiteContractId}</span>
</td><td>
${(burialSiteContract.lotId ?? -1) === -1
? `<span class="has-text-grey">(No ${los.escapedAliases.Lot})</span>`
: `<a class="has-tooltip-right" data-tooltip="${cityssm.escapeHTML(burialSiteContract.lotType ?? '')}" href="${los.getBurialSiteURL(burialSiteContract.lotId)}">${cityssm.escapeHTML(burialSiteContract.lotName ?? '')}</a>`}<br />
<span class="is-size-7">${cityssm.escapeHTML(burialSiteContract.cemeteryName ?? '')}</span>
</td><td>
${burialSiteContract.contractStartDateString}
</td><td>
${burialSiteContract.contractEndDate
? burialSiteContract.contractEndDateString
: '<span class="has-text-grey">(No End Date)</span>'}
</td><td>
${occupantsHTML === ''
? ''
: `<ul class="fa-ul ml-5">${occupantsHTML}</ul>`}
</td><td>
${feeIconHTML}
</td><td>
${burialSiteContract.printEJS
? `<a class="button is-small" data-tooltip="Print"
href="${los.urlPrefix}/print/${burialSiteContract.printEJS}/?burialSiteContractId=${burialSiteContract.burialSiteContractId.toString()}" target="_blank">
<i class="fas fa-print" aria-label="Print"></i>
</a>`
: ''}</td></tr>`);
}
// eslint-disable-next-line no-unsanitized/property
searchResultsContainerElement.innerHTML = `<table class="table is-fullwidth is-striped is-hoverable has-sticky-header">
<thead><tr>
<th class="has-width-1"></th>
<th>${los.escapedAliases.Occupancy} Type</th>
<th>${los.escapedAliases.Lot}</th>
<th>${los.escapedAliases.contractStartDate}</th>
<th>End Date</th>
<th>${los.escapedAliases.Occupants}</th>
<th class="has-width-1"><span class="is-sr-only">Fees and Transactions</span></th>
<th class="has-width-1"><span class="is-sr-only">Print</span></th>
</tr></thead>
<table>`;
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();
})();

View File

@ -133,7 +133,7 @@ declare const exports: Record<string, unknown>
${
(burialSiteContract.lotId ?? -1) === -1
? `<span class="has-text-grey">(No ${los.escapedAliases.Lot})</span>`
: `<a class="has-tooltip-right" data-tooltip="${cityssm.escapeHTML(burialSiteContract.lotType ?? '')}" href="${los.getLotURL(burialSiteContract.lotId)}">${cityssm.escapeHTML(burialSiteContract.lotName ?? '')}</a>`
: `<a class="has-tooltip-right" data-tooltip="${cityssm.escapeHTML(burialSiteContract.lotType ?? '')}" href="${los.getBurialSiteURL(burialSiteContract.lotId)}">${cityssm.escapeHTML(burialSiteContract.lotName ?? '')}</a>`
}<br />
<span class="is-size-7">${cityssm.escapeHTML(burialSiteContract.cemeteryName ?? '')}</span>
</td><td>

View File

@ -0,0 +1 @@
export {};

View File

@ -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)
? '<i class="fas fa-fw fa-minus" aria-hidden="true"></i>'
: '<i class="fas fa-fw fa-plus" aria-hidden="true"></i>';
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', `<div class="panel-block is-block
${expandedLotTypes.has(burialSiteTypeId) ? '' : ' is-hidden'}">
<div class="message is-info"><p class="message-body">There are no additional fields.</p></div>
</div>`);
}
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 = `<div class="level is-mobile">
<div class="level-left">
<div class="level-item">
<a class="has-text-weight-bold button--editLotTypeField" href="#">
${cityssm.escapeHTML(lotTypeField.lotTypeField ?? '')}
</a>
</div>
</div>
<div class="level-right">
<div class="level-item">
${los.getMoveUpDownButtonFieldHTML('button--moveLotTypeFieldUp', 'button--moveLotTypeFieldDown')}
</div>
</div>
</div>`;
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', `<div class="message is-warning>
<p class="message-body">There are no active ${los.escapedAliases.lot} types.</p>
</div>`);
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 = `<div class="panel-heading">
<div class="level is-mobile">
<div class="level-left">
<div class="level-item">
<button class="button is-small button--toggleBurialSiteTypeFields" data-tooltip="Toggle Fields" type="button" aria-label="Toggle Fields">
${expandedLotTypes.has(lotType.burialSiteTypeId)
? '<i class="fas fa-fw fa-minus" aria-hidden="true"></i>'
: '<i class="fas fa-fw fa-plus" aria-hidden="true"></i>'}
</button>
</div>
<div class="level-item">
<h2 class="title is-4">${cityssm.escapeHTML(lotType.lotType)}</h2>
</div>
</div>
<div class="level-right">
<div class="level-item">
<button class="button is-danger is-small button--deleteLotType" type="button">
<span class="icon is-small"><i class="fas fa-trash" aria-hidden="true"></i></span>
<span>Delete</span>
</button>
</div>
<div class="level-item">
<button class="button is-primary is-small button--editLotType" type="button">
<span class="icon is-small"><i class="fas fa-pencil-alt" aria-hidden="true"></i></span>
<span>Edit ${los.escapedAliases.Lot} Type</span>
</button>
</div>
<div class="level-item">
<button class="button is-success is-small button--addBurialSiteTypeField" type="button">
<span class="icon is-small"><i class="fas fa-plus" aria-hidden="true"></i></span>
<span>Add Field</span>
</button>
</div>
<div class="level-item">
${los.getMoveUpDownButtonFieldHTML('button--moveLotTypeUp', 'button--moveLotTypeDown')}
</div>
</div>
</div>
</div>`;
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();
})();

View File

@ -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 =
</button>
</div>
<div class="level-item">
<button class="button is-success is-small button--addLotTypeField" type="button">
<button class="button is-success is-small button--addBurialSiteTypeField" type="button">
<span class="icon is-small"><i class="fas fa-plus" aria-hidden="true"></i></span>
<span>Add Field</span>
</button>
@ -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)
},

View File

@ -0,0 +1 @@
export {};

View File

@ -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
}
});
});
})();

View File

@ -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<string, unknown>
;(() => {
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<string, unknown>
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<string, unknown>
)
}
mapForm.addEventListener('submit', updateMap)
cemeteryForm.addEventListener('submit', updateCemetery)
const inputElements: NodeListOf<HTMLInputElement | HTMLSelectElement> =
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<string, unknown>
}
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<string, unknown>
}
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
}
})

View File

@ -0,0 +1 @@
export {};

View File

@ -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', `<tr>
<td>
<a class="has-text-weight-bold" href="${los.getCemeteryURL(cemetery.cemeteryId)}">
${cityssm.escapeHTML((cemetery.cemeteryName ?? '') === '' ? '(No Name)' : cemetery.cemeteryName ?? '')}
</a><br />
<span class="is-size-7">
${cityssm.escapeHTML(cemetery.cemeteryDescription ?? '')}
</span>
</td><td>
${(cemetery.cemeteryAddress1 ?? '') === ''
? ''
: `${cityssm.escapeHTML(cemetery.cemeteryAddress1 ?? '')}<br />`}
${(cemetery.cemeteryAddress2 ?? '') === ''
? ''
: `${cityssm.escapeHTML(cemetery.cemeteryAddress2 ?? '')}<br />`}
${cemetery.cemeteryCity || cemetery.cemeteryProvince
? `${cityssm.escapeHTML(cemetery.cemeteryCity ?? '')}, ${cityssm.escapeHTML(cemetery.cemeteryProvince ?? '')}<br />`
: ''}
${(cemetery.cemeteryPostalCode ?? '') === ''
? ''
: cityssm.escapeHTML(cemetery.cemeteryPostalCode ?? '')}
</td><td>
${cityssm.escapeHTML(cemetery.cemeteryPhoneNumber ?? '')}
</td><td class="has-text-centered">
${cemetery.cemeteryLatitude && cemetery.cemeteryLongitude
? `<span data-tooltip="Has Geographic Coordinates">
<i class="fas fa-map-marker-alt" role="img" aria-label="Has Geographic Coordinates"></i>
</span>`
: ''}
</td><td class="has-text-centered">
${(cemetery.cemeterySvg ?? '') === ''
? ''
: '<span data-tooltip="Has Image"><i class="fas fa-image" role="img" aria-label="Has Image"></i></span>'}
</td><td class="has-text-right">
<a href="${los.urlPrefix}/burialSites?cemeteryId=${cemetery.cemeteryId}">${cemetery.burialSiteCount}</a>
</td>
</tr>`);
}
searchResultsContainerElement.innerHTML = '';
if (searchResultCount === 0) {
// eslint-disable-next-line no-unsanitized/property
searchResultsContainerElement.innerHTML = `<div class="message is-info">
<p class="message-body">There are no cemeteries that meet the search criteria.</p>
</div>`;
}
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 = `<thead><tr>
<th>Cemetery</th>
<th>Address</th>
<th>Phone Number</th>
<th class="has-text-centered">Coordinates</th>
<th class="has-text-centered">Image</th>
<th class="has-text-right">Burial Site Count</th>
</tr></thead>`;
searchResultsTableElement.append(searchResultsTbodyElement);
searchResultsContainerElement.append(searchResultsTableElement);
}
}
searchFilterElement.addEventListener('keyup', renderResults);
document
.querySelector('#form--searchFilters')
?.addEventListener('submit', (formEvent) => {
formEvent.preventDefault();
renderResults();
});
renderResults();
})();

View File

@ -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<string, unknown>
;(() => {
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<string, unknown>
.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<string, unknown>
'beforeend',
`<tr>
<td>
<a class="has-text-weight-bold" href="${los.getMapURL(map.cemeteryId)}">
<a class="has-text-weight-bold" href="${los.getCemeteryURL(cemetery.cemeteryId)}">
${cityssm.escapeHTML(
(map.cemeteryName ?? '') === '' ? '(No Name)' : map.cemeteryName ?? ''
(cemetery.cemeteryName ?? '') === '' ? '(No Name)' : cemetery.cemeteryName ?? ''
)}
</a><br />
<span class="is-size-7">
${cityssm.escapeHTML(map.mapDescription ?? '')}
${cityssm.escapeHTML(cemetery.cemeteryDescription ?? '')}
</span>
</td><td>
${
(map.mapAddress1 ?? '') === ''
(cemetery.cemeteryAddress1 ?? '') === ''
? ''
: `${cityssm.escapeHTML(map.mapAddress1 ?? '')}<br />`
: `${cityssm.escapeHTML(cemetery.cemeteryAddress1 ?? '')}<br />`
}
${
(map.mapAddress2 ?? '') === ''
(cemetery.cemeteryAddress2 ?? '') === ''
? ''
: `${cityssm.escapeHTML(map.mapAddress2 ?? '')}<br />`
: `${cityssm.escapeHTML(cemetery.cemeteryAddress2 ?? '')}<br />`
}
${
map.mapCity || map.mapProvince
? `${cityssm.escapeHTML(map.mapCity ?? '')}, ${cityssm.escapeHTML(map.mapProvince ?? '')}<br />`
cemetery.cemeteryCity || cemetery.cemeteryProvince
? `${cityssm.escapeHTML(cemetery.cemeteryCity ?? '')}, ${cityssm.escapeHTML(cemetery.cemeteryProvince ?? '')}<br />`
: ''
}
${
(map.mapPostalCode ?? '') === ''
(cemetery.cemeteryPostalCode ?? '') === ''
? ''
: cityssm.escapeHTML(map.mapPostalCode ?? '')
: cityssm.escapeHTML(cemetery.cemeteryPostalCode ?? '')
}
</td><td>
${cityssm.escapeHTML(map.mapPhoneNumber ?? '')}
${cityssm.escapeHTML(cemetery.cemeteryPhoneNumber ?? '')}
</td><td class="has-text-centered">
${
map.mapLatitude && map.mapLongitude
cemetery.cemeteryLatitude && cemetery.cemeteryLongitude
? `<span data-tooltip="Has Geographic Coordinates">
<i class="fas fa-map-marker-alt" role="img" aria-label="Has Geographic Coordinates"></i>
</span>`
@ -99,12 +101,12 @@ declare const exports: Record<string, unknown>
}
</td><td class="has-text-centered">
${
(map.mapSVG ?? '') === ''
(cemetery.cemeterySvg ?? '') === ''
? ''
: '<span data-tooltip="Has Image"><i class="fas fa-image" role="img" aria-label="Has Image"></i></span>'
}
</td><td class="has-text-right">
<a href="${los.urlPrefix}/lots?cemeteryId=${map.cemeteryId}">${map.lotCount}</a>
<a href="${los.urlPrefix}/burialSites?cemeteryId=${cemetery.cemeteryId}">${cemetery.burialSiteCount}</a>
</td>
</tr>`
)
@ -115,7 +117,7 @@ declare const exports: Record<string, unknown>
if (searchResultCount === 0) {
// eslint-disable-next-line no-unsanitized/property
searchResultsContainerElement.innerHTML = `<div class="message is-info">
<p class="message-body">There are no ${los.escapedAliases.maps} that meet the search criteria.</p>
<p class="message-body">There are no cemeteries that meet the search criteria.</p>
</div>`
} else {
const searchResultsTableElement = document.createElement('table')
@ -125,12 +127,12 @@ declare const exports: Record<string, unknown>
// eslint-disable-next-line no-unsanitized/property
searchResultsTableElement.innerHTML = `<thead><tr>
<th>${los.escapedAliases.Map}</th>
<th>Cemetery</th>
<th>Address</th>
<th>Phone Number</th>
<th class="has-text-centered">Coordinates</th>
<th class="has-text-centered">Image</th>
<th class="has-text-right">${los.escapedAliases.Lot} Count</th>
<th class="has-text-right">Burial Site Count</th>
</tr></thead>`
searchResultsTableElement.append(searchResultsTbodyElement)

View File

@ -0,0 +1 @@
export {};

View File

@ -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);
}
})();

View File

@ -0,0 +1 @@
export {};

View File

@ -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)
? '<i class="fas fa-fw fa-minus" aria-hidden="true"></i>'
: '<i class="fas fa-fw fa-plus" aria-hidden="true"></i>';
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', `<div class="panel-block is-block ${!contractTypeId || expandedOccupancyTypes.has(contractTypeId)
? ''
: ' is-hidden'}">
<div class="message is-info"><p class="message-body">There are no additional fields.</p></div>
</div>`);
}
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 = `<div class="level is-mobile">
<div class="level-left">
<div class="level-item">
<a class="has-text-weight-bold button--editOccupancyTypeField" href="#">
${cityssm.escapeHTML(occupancyTypeField.occupancyTypeField ?? '')}
</a>
</div>
</div>
<div class="level-right">
<div class="level-item">
${los.getMoveUpDownButtonFieldHTML('button--moveOccupancyTypeFieldUp', 'button--moveOccupancyTypeFieldDown')}
</div>
</div>
</div>`;
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', `<div class="panel-block is-block">
<div class="message is-info">
<p class="message-body">There are no prints associated with this record.</p>
</div>
</div>`);
}
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 = `<div class="level is-mobile">
<div class="level-left">
<div class="level-item">
<i class="fas fa-fw ${printIconClass}" aria-hidden="true"></i>
</div>
<div class="level-item">
${cityssm.escapeHTML(printTitle || printEJS)}
</div>
</div>
<div class="level-right">
<div class="level-item">
${los.getMoveUpDownButtonFieldHTML('button--moveOccupancyTypePrintUp', 'button--moveOccupancyTypePrintDown')}
</div>
<div class="level-item">
<button class="button is-small is-danger button--deleteOccupancyTypePrint" data-tooltip="Delete" type="button" aria-label="Delete Print">
<i class="fas fa-trash" aria-hidden="true"></i>
</button>
</div>
</div>
</div>`;
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 = `<div class="panel container--occupancyType" id="container--allContractTypeFields" data-occupancy-type-id="">
<div class="panel-heading">
<div class="level is-mobile">
<div class="level-left">
<div class="level-item">
<h2 class="title is-4">(All ${los.escapedAliases.Occupancy} Types)</h2>
</div>
</div>
<div class="level-right">
<div class="level-item">
<button class="button is-success is-small button--addOccupancyTypeField" type="button">
<span class="icon is-small"><i class="fas fa-plus" aria-hidden="true"></i></span>
<span>Add Field</span>
</button>
</div>
</div>
</div>
</div>
</div>`;
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', `<div class="message is-warning>
<p class="message-body">There are no active ${los.escapedAliases.occupancy} types.</p>
</div>`);
// eslint-disable-next-line no-unsanitized/method
ContractTypePrintsContainerElement.insertAdjacentHTML('afterbegin', `<div class="message is-warning>
<p class="message-body">There are no active ${los.escapedAliases.occupancy} types.</p>
</div>`);
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 = `<div class="panel-heading">
<div class="level is-mobile">
<div class="level-left">
<div class="level-item">
<button class="button is-small button--toggleContractTypeFields" data-tooltip="Toggle Fields" type="button" aria-label="Toggle Fields">
${expandedOccupancyTypes.has(occupancyType.contractTypeId)
? '<i class="fas fa-fw fa-minus" aria-hidden="true"></i>'
: '<i class="fas fa-fw fa-plus" aria-hidden="true"></i>'}
</button>
</div>
<div class="level-item">
<h2 class="title is-4">${cityssm.escapeHTML(occupancyType.occupancyType)}</h2>
</div>
</div>
<div class="level-right">
<div class="level-item">
<button class="button is-danger is-small button--deleteOccupancyType" type="button">
<span class="icon is-small"><i class="fas fa-trash" aria-hidden="true"></i></span>
<span>Delete</span>
</button>
</div>
<div class="level-item">
<button class="button is-primary is-small button--editOccupancyType" type="button">
<span class="icon is-small"><i class="fas fa-pencil-alt" aria-hidden="true"></i></span>
<span>Edit ${los.escapedAliases.Occupancy} Type</span>
</button>
</div>
<div class="level-item">
<button class="button is-success is-small button--addOccupancyTypeField" type="button">
<span class="icon is-small"><i class="fas fa-plus" aria-hidden="true"></i></span>
<span>Add Field</span>
</button>
</div>
<div class="level-item">
${los.getMoveUpDownButtonFieldHTML('button--moveOccupancyTypeUp', 'button--moveOccupancyTypeDown')}
</div>
</div>
</div>
</div>`;
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 = `<div class="panel-heading">
<div class="level is-mobile">
<div class="level-left">
<div class="level-item">
<h2 class="title is-4">${cityssm.escapeHTML(occupancyType.occupancyType)}</h2>
</div>
</div>
<div class="level-right">
<div class="level-item">
<button class="button is-success is-small button--addOccupancyTypePrint" type="button">
<span class="icon is-small"><i class="fas fa-plus" aria-hidden="true"></i></span>
<span>Add Print</span>
</button>
</div>
</div>
</div>
</div>`;
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();
})();

View File

@ -0,0 +1 @@
export {};

View File

@ -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 <strong>${responseJSON.fileName}</strong><br />
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
}
});
});
})();

View File

@ -0,0 +1 @@
export {};

View File

@ -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 = `<div class="message is-warning">
<p class="message-body">There are no available fees.</p>
</div>`;
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 = `<div class="panel-heading">
<div class="columns">
<div class="column">
<h2 class="title is-4 mb-2">${cityssm.escapeHTML(feeCategory.feeCategory ?? '')}</h2>
${feeCategory.isGroupedFee
? '<span class="tag">Grouped Fee</span>'
: ''}
</div>
<div class="column is-narrow">
<div class="field is-grouped is-justify-content-end">
${feeCategory.fees.length === 0
? `<div class="control">
<button class="button is-small is-danger button--deleteFeeCategory" type="button">
<span class="icon is-small"><i class="fas fa-trash" aria-hidden="true"></i></span>
<span>Delete Category</span>
</button>
</div>`
: ''}
<div class="control">
<button class="button is-small is-primary button--editFeeCategory" type="button">
<span class="icon is-small"><i class="fas fa-pencil-alt" aria-hidden="true"></i></span>
<span>
${feeCategory.isGroupedFee
? 'Edit Grouped Fee'
: 'Edit Category'}
</span>
</button>
</div>
<div class="control">
<button class="button is-small is-success button--addFee" data-cy="addFee" type="button">
<span class="icon is-small"><i class="fas fa-plus" aria-hidden="true"></i></span>
<span>Add Fee</span>
</button>
</div>
<div class="control">
${los.getMoveUpDownButtonFieldHTML('button--moveFeeCategoryUp', 'button--moveFeeCategoryDown')}
</div>
</div>
</div>
</div>`;
if (feeCategory.fees.length === 0) {
feeCategoryContainerElement.insertAdjacentHTML('beforeend', `<div class="panel-block is-block">
<div class="message is-info">
<p class="message-body">
There are no fees in the
"${cityssm.escapeHTML(feeCategory.feeCategory ?? '')}"
category.
</p>
</div>
</div>`);
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 = `<div class="columns">
<div class="column is-half">
<p>
<a class="has-text-weight-bold a--editFee" href="#">${cityssm.escapeHTML(fee.feeName ?? '')}</a><br />
<small>
${
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
cityssm
.escapeHTML(fee.feeDescription ?? '')
.replaceAll('\n', '<br />')}
</small>
</p>
${hasTagsBlock
? `<p class="tags">
${fee.isRequired ?? false
? '<span class="tag is-warning">Required</span>'
: ''}
${(fee.contractTypeId ?? -1) === -1
? ''
: ` <span class="tag has-tooltip-bottom" data-tooltip="${los.escapedAliases.Occupancy} Type Filter">
<span class="icon is-small"><i class="fas fa-filter" aria-hidden="true"></i></span>
<span>${cityssm.escapeHTML(fee.occupancyType ?? '')}</span>
</span>`}
${(fee.burialSiteTypeId ?? -1) === -1
? ''
: ` <span class="tag has-tooltip-bottom" data-tooltip="${los.escapedAliases.Lot} Type Filter">
<span class="icon is-small"><i class="fas fa-filter" aria-hidden="true"></i></span>
<span>${cityssm.escapeHTML(fee.lotType ?? '')}</span>
</span>`}
</p>`
: ''}
</div>
<div class="column">
<div class="columns is-mobile">
<div class="column has-text-centered">
${fee.feeFunction
? `${cityssm.escapeHTML(fee.feeFunction)}<br />
<small>Fee Function</small>`
: `<a class="a--editFeeAmount" href="#">
$${(fee.feeAmount ?? 0).toFixed(2)}<br />
<small>Fee</small>
</a>`}
</div>
<div class="column has-text-centered">
${fee.taxPercentage
? `${fee.taxPercentage.toString()}%`
: `$${(fee.taxAmount ?? 0).toFixed(2)}`}<br />
<small>Tax</small>
</div>
<div class="column has-text-centered">
${fee.includeQuantity
? `${cityssm.escapeHTML(fee.quantityUnit ?? '')}<br />
<small>Quantity</small>`
: ''}
</div>
</div>
</div>
<div class="column is-narrow">
${los.getMoveUpDownButtonFieldHTML('button--moveFeeUp', 'button--moveFeeDown')}
</div>
</div>`;
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();
})();

View File

@ -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;

View File

@ -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<string, unknown> & {
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<string, unknown> & {
'.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<string, unknown> & {
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<string, unknown> & {
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<string, unknown> & {
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<string, unknown> & {
)
}
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<string, unknown> & {
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<string, unknown> & {
getLoadingParagraphHTML,
getSearchResultsPagerHTML,
getMapURL,
getLotURL,
getCemeteryURL,
getBurialSiteURL,
getBurialSiteContractURL,
getWorkOrderURL
}

View File

View File

@ -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);
}
})();

View File

@ -0,0 +1 @@
export {};

View File

@ -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 =
`<i class="fas fa-fw fa-${fontAwesomeIconClass}" aria-hidden="true"></i>`;
}
/**
* 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?<br />
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 = `<tr><td colspan="2">
<div class="message is-warning"><p class="message-body">There are no active work order types.</p></div>
</td></tr>`;
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 = `<td>
<form>
<input name="workOrderTypeId" type="hidden" value="${workOrderType.workOrderTypeId.toString()}" />
<div class="field has-addons">
<div class="control">
<input class="input" name="workOrderType" type="text"
value="${cityssm.escapeHTML(workOrderType.workOrderType ?? '')}" maxlength="100" aria-label="Work Order Type" required />
</div>
<div class="control">
<button class="button is-success" type="submit" aria-label="Save">
<i class="fas fa-save" aria-hidden="true"></i>
</button>
</div>
</div>
</form>
</td><td class="is-nowrap">
<div class="field is-grouped">
<div class="control">
${los.getMoveUpDownButtonFieldHTML('button--moveWorkOrderTypeUp', 'button--moveWorkOrderTypeDown', false)}
</div>
<div class="control">
<button class="button is-danger is-light button--deleteWorkOrderType" data-tooltip="Delete Work Order Type" type="button" aria-label="Delete Work Order Type">
<i class="fas fa-trash" aria-hidden="true"></i>
</button>
</div>
</div>
</td>`;
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?<br />
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 = `<tr><td colspan="2">
<div class="message is-warning">
<p class="message-body">There are no active work order milestone types.</p>
</div>
</td></tr>`;
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 = `<td>
<form>
<input name="workOrderMilestoneTypeId" type="hidden" value="${workOrderMilestoneType.workOrderMilestoneTypeId.toString()}" />
<div class="field has-addons">
<div class="control">
<input class="input" name="workOrderMilestoneType" type="text"
value="${cityssm.escapeHTML(workOrderMilestoneType.workOrderMilestoneType)}" maxlength="100" aria-label="Work Order Milestone Type" required />
</div>
<div class="control">
<button class="button is-success" type="submit" aria-label="Save">
<i class="fas fa-save" aria-hidden="true"></i>
</button>
</div>
</div>
</form>
</td><td class="is-nowrap">
<div class="field is-grouped">
<div class="control">
${los.getMoveUpDownButtonFieldHTML('button--moveWorkOrderMilestoneTypeUp', 'button--moveWorkOrderMilestoneTypeDown', false)}
</div>
<div class="control">
<button class="button is-danger is-light button--deleteWorkOrderMilestoneType" data-tooltip="Delete Mielstone Type" type="button" aria-label="Delete Milestone Type">
<i class="fas fa-trash" aria-hidden="true"></i>
</button>
</div>
</div>
</td>`;
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?<br />
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 = `<tr><td colspan="2">
<div class="message is-warning">
<p class="message-body">There are no active ${los.escapedAliases.lot} statuses.</p>
</div>
</td></tr>`;
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 = `<td>
<form>
<input name="burialSiteStatusId" type="hidden" value="${lotStatus.burialSiteStatusId.toString()}" />
<div class="field has-addons">
<div class="control">
<input class="input" name="lotStatus" type="text"
value="${cityssm.escapeHTML(lotStatus.lotStatus)}"
aria-label="${los.escapedAliases.Lot} Status" maxlength="100" required />
</div>
<div class="control">
<button class="button is-success" type="submit" aria-label="Save">
<i class="fas fa-save" aria-hidden="true"></i>\
</button>
</div>
</div>
</form>
</td><td class="is-nowrap">
<div class="field is-grouped">
<div class="control">
${los.getMoveUpDownButtonFieldHTML('button--moveLotStatusUp', 'button--moveLotStatusDown', false)}
</div>
<div class="control">
<button class="button is-danger is-light button--deleteLotStatus" data-tooltip="Delete Status" type="button" aria-label="Delete Status">
<i class="fas fa-trash" aria-hidden="true"></i>
</button>
</div>
</div>
</td>`;
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?<br />
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 = `<tr><td colspan="3">
<div class="message is-warning">
<p class="message-body">There are no active ${los.escapedAliases.lot} ${los.escapedAliases.occupant} types.</p>
</div>
</td></tr>`;
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 = `<td>
<div class="field">
<div class="control">
<input class="input" name="lotOccupantType" type="text"
value="${cityssm.escapeHTML(lotOccupantType.lotOccupantType)}"
form="${formId}"
aria-label="${los.escapedAliases.Lot} ${los.escapedAliases.Occupant} Type" maxlength="100" required />
</div>
</div>
</td><td>
<div class="field has-addons">
<div class="control">
<span class="button is-static">fa-</span>
</div>
<div class="control">
<input class="input" name="fontAwesomeIconClass" type="text"
value="${cityssm.escapeHTML(lotOccupantType.fontAwesomeIconClass)}"
form="${formId}"
list="datalist--fontAwesomeIconClass" aria-label="Icon Name" maxlength="50" />
</div>
<div class="control">
<span class="button is-static">
<i class="fas fa-fw fa-${cityssm.escapeHTML(lotOccupantType.fontAwesomeIconClass)}"></i>
</span>
</div>
</div>
</td><td>
<div class="field">
<div class="control">
<input class="input" name="occupantCommentTitle" type="text"
value="${cityssm.escapeHTML(lotOccupantType.occupantCommentTitle)}"
form="${formId}"
aria-label="${los.escapedAliases.Occupant} Comment Title" maxlength="50" />
</div>
</div>
</td><td>
<form id="${formId}">
<input name="lotOccupantTypeId" type="hidden"
value="${lotOccupantType.lotOccupantTypeId.toString()}" />
<button class="button is-success" type="submit" aria-label="Save">
<i class="fas fa-save" aria-hidden="true"></i>
</button>
</form>
</td><td class="is-nowrap">
<div class="field is-grouped">
<div class="control">
${los.getMoveUpDownButtonFieldHTML('button--moveLotOccupantTypeUp', 'button--moveLotOccupantTypeDown', false)}
</div>
<div class="control">
<button class="button is-danger is-light button--deleteLotOccupantType"
data-tooltip="Delete ${los.escapedAliases.Lot} ${los.escapedAliases.Occupant} Type"
type="button"
aria-label="Delete ${los.escapedAliases.Lot} ${los.escapedAliases.Occupant} Type">
<i class="fas fa-trash" aria-hidden="true"></i>
</button>
</div>
</div>
</td>`;
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();
})();
})();

View File

@ -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()

28
public/javascripts/types.d.ts vendored 100644
View File

@ -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;
}

View File

@ -0,0 +1,2 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });

View File

@ -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,

View File

@ -0,0 +1 @@
export {};

File diff suppressed because it is too large Load Diff

View File

@ -270,7 +270,7 @@ declare const exports: Record<string, unknown>
})
}
function addLot(
function addBurialSite(
lotId: number | string,
callbackFunction?: (success: boolean) => void
): void {
@ -340,10 +340,10 @@ declare const exports: Record<string, unknown>
)
}
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<string, unknown>
${
hasLotRecord
? ''
: ` <button class="button is-small is-light is-success button--addLot"
: ` <button class="button is-small is-light is-success button--addBurialSite"
data-lot-id="${burialSiteContract.lotId.toString()}"
data-tooltip="Add ${los.escapedAliases.Lot}"
aria-label="Add ${los.escapedAliases.Lot}" type="button">
@ -479,8 +479,8 @@ declare const exports: Record<string, unknown>
)
rowElement
.querySelector('.button--addLot')
?.addEventListener('click', addLotFromLotOccupancy)
.querySelector('.button--addBurialSite')
?.addEventListener('click', addBurialSiteFromLotOccupancy)
rowElement
.querySelector('.button--deleteLotOccupancy')
@ -686,7 +686,7 @@ declare const exports: Record<string, unknown>
// eslint-disable-next-line no-unsanitized/property
rowElement.innerHTML = `<td>
<a class="has-text-weight-bold" href="${los.getLotURL(lot.lotId)}">
<a class="has-text-weight-bold" href="${los.getBurialSiteURL(lot.lotId)}">
${cityssm.escapeHTML(lot.lotName ?? '')}
</a>
</td><td>
@ -923,7 +923,7 @@ declare const exports: Record<string, unknown>
const lotId = rowElement.dataset.lotId ?? ''
addLot(lotId, (success) => {
addBurialSite(lotId, (success) => {
if (success) {
rowElement.remove()
}
@ -931,7 +931,7 @@ declare const exports: Record<string, unknown>
}
document
.querySelector('#button--addLot')
.querySelector('#button--addBurialSite')
?.addEventListener('click', () => {
let searchFormElement: HTMLFormElement
let searchResultsContainerElement: HTMLElement
@ -977,7 +977,7 @@ declare const exports: Record<string, unknown>
rowElement.dataset.lotId = lot.lotId.toString()
rowElement.innerHTML = `<td class="has-text-centered">
<button class="button is-small is-success button--addLot" data-tooltip="Add" type="button" aria-label="Add">
<button class="button is-small is-success button--addBurialSite" data-tooltip="Add" type="button" aria-label="Add">
<i class="fas fa-plus" aria-hidden="true"></i>
</button>
</td><td class="has-text-weight-bold">
@ -991,7 +991,7 @@ declare const exports: Record<string, unknown>
</td>`
rowElement
.querySelector('.button--addLot')
.querySelector('.button--addBurialSite')
?.addEventListener('click', doAddLot)
searchResultsContainerElement
@ -1002,7 +1002,7 @@ declare const exports: Record<string, unknown>
)
}
cityssm.openHtmlModal('workOrder-addLot', {
cityssm.openHtmlModal('workOrder-addBurialSite', {
onshow(modalElement) {
los.populateAliases(modalElement)
@ -1051,7 +1051,7 @@ declare const exports: Record<string, unknown>
onremoved() {
bulmaJS.toggleHtmlClipped()
;(
document.querySelector('#button--addLot') as HTMLButtonElement
document.querySelector('#button--addBurialSite') as HTMLButtonElement
).focus()
}
})

View File

@ -0,0 +1 @@
export {};

View File

@ -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 = `<div class="message is-info">
<p class="message-body">There are no milestones that meet the search criteria.</p>
</div>`;
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 = `<h2 class="panel-heading">
${cityssm.escapeHTML(milestone.workOrderMilestoneDate === 0
? 'No Set Date'
: milestone.workOrderMilestoneDateString ?? '')}
</h2>`;
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 += `<li class="has-tooltip-left"
data-tooltip="${cityssm.escapeHTML(lot.cemeteryName ?? '')}">
<span class="fa-li">
<i class="fas fa-vector-square"
aria-label="${los.escapedAliases.Lot}"></i>
</span>
${cityssm.escapeHTML(lot.lotName ?? '')}
</li>`;
}
for (const burialSiteContract of milestone.workOrderBurialSiteContracts ?? []) {
for (const occupant of burialSiteContract.burialSiteContractOccupants ?? []) {
burialSiteContractHTML += `<li class="has-tooltip-left"
data-tooltip="${cityssm.escapeHTML(occupant.lotOccupantType ?? '')}">
<span class="fa-li">
<i class="fas fa-user"
aria-label="${los.escapedAliases.Occupancy}"></i>
</span>
${cityssm.escapeHTML(occupant.occupantName ?? '')}
${cityssm.escapeHTML(occupant.occupantFamilyName ?? '')}
</li>`;
}
}
// eslint-disable-next-line no-unsanitized/property
panelBlockElement.innerHTML = `<div class="columns">
<div class="column is-narrow">
<span class="icon is-small">
${milestone.workOrderMilestoneCompletionDate
? '<i class="fas fa-check" aria-label="Completed"></i>'
: '<i class="far fa-square has-text-grey" aria-label="Incomplete"></i>'}
</span>
</div><div class="column">
${milestone.workOrderMilestoneTime === 0
? ''
: `${milestone.workOrderMilestoneTimePeriodString}<br />`}
${milestone.workOrderMilestoneTypeId
? `<strong>${cityssm.escapeHTML(milestone.workOrderMilestoneType ?? '')}</strong><br />`
: ''}
<span class="is-size-7">
${cityssm.escapeHTML(milestone.workOrderMilestoneDescription ?? '')}
</span>
</div><div class="column">
<i class="fas fa-circle" style="color:${los.getRandomColor(milestone.workOrderNumber ?? '')}" aria-hidden="true"></i>
<a class="has-text-weight-bold" href="${los.getWorkOrderURL(milestone.workOrderId)}">
${cityssm.escapeHTML(milestone.workOrderNumber ?? '')}
</a><br />
<span class="is-size-7">${cityssm.escapeHTML(milestone.workOrderDescription ?? '')}</span>
</div><div class="column is-size-7">
${burialSiteContractHTML === ''
? ''
: `<ul class="fa-ul ml-4">${burialSiteContractHTML}</ul>`}</div></div>`;
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();
})();

View File

@ -0,0 +1 @@
export {};

View File

@ -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();
});
})();

View File

@ -0,0 +1 @@
export {};

View File

@ -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 = `<div class="message is-info">
<p class="message-body">There are no work orders that meet the search criteria.</p>
</div>`;
return;
}
const resultsTbodyElement = document.createElement('tbody');
for (const workOrder of responseJSON.workOrders) {
let relatedHTML = '';
for (const lot of workOrder.workOrderLots ?? []) {
relatedHTML += `<li class="has-tooltip-left"
data-tooltip="${cityssm.escapeHTML(lot.cemeteryName ?? '')}">
<span class="fa-li">
<i class="fas fa-fw fa-vector-square"
aria-label="${los.escapedAliases.Lot}"></i>
</span>
${cityssm.escapeHTML((lot.lotName ?? '') === ''
? `(No ${los.escapedAliases.Lot} Name)`
: lot.lotName ?? '')}
</li>`;
}
for (const occupancy of workOrder.workOrderBurialSiteContracts ?? []) {
for (const occupant of occupancy.burialSiteContractOccupants ?? []) {
relatedHTML += `<li class="has-tooltip-left"
data-tooltip="${cityssm.escapeHTML(occupant.lotOccupantType ?? '')}">
<span class="fa-li">
<i class="fas fa-fw fa-${cityssm.escapeHTML((occupant.fontAwesomeIconClass ?? '') === ''
? 'user'
: occupant.fontAwesomeIconClass ?? '')}" aria-label="${los.escapedAliases.occupant}"></i>
</span>
${cityssm.escapeHTML((occupant.occupantName ?? '') === '' &&
(occupant.occupantFamilyName ?? '') === ''
? '(No Name)'
: `${occupant.occupantName} ${occupant.occupantFamilyName}`)}
</li>`;
}
}
// eslint-disable-next-line no-unsanitized/method
resultsTbodyElement.insertAdjacentHTML('beforeend', `<tr>
<td>
<a class="has-text-weight-bold" href="${los.getWorkOrderURL(workOrder.workOrderId)}">
${workOrder.workOrderNumber?.trim() === ''
? '(No Number)'
: cityssm.escapeHTML(workOrder.workOrderNumber ?? '')}
</a>
</td><td>
${cityssm.escapeHTML(workOrder.workOrderType ?? '')}<br />
<span class="is-size-7">
${cityssm.escapeHTML(workOrder.workOrderDescription ?? '')}
</span>
</td><td>
${relatedHTML === ''
? ''
: `<ul class="fa-ul ml-5 is-size-7">${relatedHTML}</ul>`}
</td><td>
<ul class="fa-ul ml-5 is-size-7">
<li class="has-tooltip-left"
data-tooltip="${los.escapedAliases.WorkOrderOpenDate}">
<span class="fa-li">
<i class="fas fa-fw fa-play" aria-label="${los.escapedAliases.WorkOrderOpenDate}"></i>
</span>
${workOrder.workOrderOpenDateString}
</li>
<li class="has-tooltip-left" data-tooltip="${los.escapedAliases.WorkOrderCloseDate}">
<span class="fa-li">
<i class="fas fa-fw fa-stop" aria-label="${los.escapedAliases.WorkOrderCloseDate}"></i>
</span>
${workOrder.workOrderCloseDate
? workOrder.workOrderCloseDateString
: `<span class="has-text-grey">(No ${los.escapedAliases.WorkOrderCloseDate})</span>`}
</li>
</ul>
</td><td>
${workOrder.workOrderMilestoneCount === 0
? '-'
: `${(workOrder.workOrderMilestoneCompletionCount ?? '').toString()}
/
${(workOrder.workOrderMilestoneCount ?? '').toString()}`}
</td>
${workOrderPrints.length > 0
? `<td>
<a class="button is-small" data-tooltip="Print"
href="${los.urlPrefix}/print/${workOrderPrints[0]}/?workOrderId=${workOrder.workOrderId.toString()}"
target="_blank">
<i class="fas fa-print" aria-label="Print"></i>
</a>
</td>`
: ''}</tr>`);
}
// eslint-disable-next-line no-unsanitized/property
searchResultsContainerElement.innerHTML = `<table class="table is-fullwidth is-striped is-hoverable has-sticky-header">
<thead><tr>
<th>Work Order Number</th>
<th>Description</th>
<th>Related</th>
<th>Date</th>
<th class="has-tooltip-bottom" data-tooltip="Completed / Total Milestones">Progress</th>
${workOrderPrints.length > 0 ? '<th class="has-width-1"></th>' : ''}
</tr></thead>
<table>`;
// 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();
})();

View File

@ -0,0 +1 @@
export {};

View File

@ -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
}
});
});
}
})();

View File

@ -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);
}

View File

@ -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<string, recordTypes.MapRecord>()
const cemeteryCache = new Map<string, recordTypes.Cemetery>()
async function getMap(dataRow: {
async function getCemetery(dataRow: {
cemetery: string
}): Promise<recordTypes.MapRecord> {
}): Promise<recordTypes.Cemetery> {
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<void> {
@ -347,36 +354,24 @@ async function importFromMasterCSV(): Promise<void> {
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<void> {
preneedburialSiteContractId = await addBurialSiteContract(
{
contractTypeId: importIds.preneedOccupancyType.contractTypeId,
lotId: lotId ?? '',
lotId: burialSiteId ?? '',
contractStartDateString: preneedcontractStartDateString,
contractEndDateString,
contractTypeFieldIds: ''
@ -478,7 +473,8 @@ async function importFromMasterCSV(): Promise<void> {
await addBurialSiteContractComment(
{
burialSiteContractId: preneedburialSiteContractId,
burialSiteContractCommentDateString: preneedcontractStartDateString,
burialSiteContractCommentDateString:
preneedcontractStartDateString,
burialSiteContractCommentTimeString: '00:00',
burialSiteContractComment: masterRow.CM_REMARK1
},
@ -490,7 +486,8 @@ async function importFromMasterCSV(): Promise<void> {
await addBurialSiteContractComment(
{
burialSiteContractId: preneedburialSiteContractId,
burialSiteContractCommentDateString: preneedcontractStartDateString,
burialSiteContractCommentDateString:
preneedcontractStartDateString,
burialSiteContractCommentTimeString: '00:00',
burialSiteContractComment: masterRow.CM_REMARK2
},
@ -502,7 +499,8 @@ async function importFromMasterCSV(): Promise<void> {
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<void> {
if (contractEndDateString === '') {
await updateBurialSiteStatus(
lotId ?? '',
burialSiteId ?? '',
importIds.reservedburialSiteStatusId,
user
)
@ -549,18 +547,18 @@ async function importFromMasterCSV(): Promise<void> {
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<void> {
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<void> {
}
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<void> {
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<void> {
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<void> {
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<void> {
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<void> {
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<void> {
await addBurialSiteContractComment(
{
burialSiteContractId: deceasedburialSiteContractId,
burialSiteContractCommentDateString: deceasedcontractStartDateString,
burialSiteContractCommentDateString:
deceasedcontractStartDateString,
burialSiteContractCommentTimeString: '00:00',
burialSiteContractComment: masterRow.CM_REMARK1
},
@ -751,7 +750,8 @@ async function importFromMasterCSV(): Promise<void> {
await addBurialSiteContractComment(
{
burialSiteContractId: deceasedburialSiteContractId,
burialSiteContractCommentDateString: deceasedcontractStartDateString,
burialSiteContractCommentDateString:
deceasedcontractStartDateString,
burialSiteContractCommentTimeString: '00:00',
burialSiteContractComment: masterRow.CM_REMARK2
},
@ -763,7 +763,8 @@ async function importFromMasterCSV(): Promise<void> {
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<void> {
)
}
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<void> {
let lot: recordTypes.Lot | undefined
if (cemetery !== '') {
const map = await getMap({
const map = await getCemetery({
cemetery
})
@ -849,14 +854,14 @@ async function importFromPrepaidCSV(): Promise<void> {
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<void> {
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<void> {
}
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<void> {
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<void> {
user
)
lot = await getLot(lotId)
lot = await getBurialSite(lotId)
}
const workOrderContainsLot = workOrder.workOrderLots!.find(
@ -1229,7 +1245,7 @@ async function importFromWorkOrderCSV(): Promise<void> {
)
if (!workOrderContainsLot) {
await addWorkOrderLot(
await addWorkOrderBurialSite(
{
workOrderId: workOrder.workOrderId!,
lotId: lot.lotId
@ -1289,11 +1305,12 @@ async function importFromWorkOrderCSV(): Promise<void> {
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<void> {
}
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<void> {
}
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<void> {
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<void> {
)
/*
addOrUpdateLotOccupancyField(
addOrUpdateBurialSiteContractField(
{
burialSiteContractId: burialSiteContractId,
contractTypeFieldId: allContractTypeFields.find((occupancyTypeField) => {
@ -1388,11 +1406,12 @@ async function importFromWorkOrderCSV(): Promise<void> {
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<void> {
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<void> {
commitalType = 'Graveside'
}
await addOrUpdateLotOccupancyField(
await addOrUpdateBurialSiteContractField(
{
burialSiteContractId,
contractTypeFieldId: occupancyType.ContractTypeFields!.find(
(occupancyTypeField) => (
occupancyTypeField.occupancyTypeField === 'Committal Type'
)
(occupancyTypeField) =>
occupancyTypeField.occupancyTypeField === 'Committal Type'
)!.contractTypeFieldId!,
burialSiteContractFieldValue: commitalType
},

View File

@ -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;

View File

@ -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': {

View File

@ -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 {

View File

@ -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
*/

View File

@ -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

View File

@ -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 () => {

View File

@ -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)
})

View File

@ -14,15 +14,6 @@
<script>
window.exports = window.exports || {};
exports.aliases = {
map: "<%= configFunctions.getConfigProperty('aliases.map') %>",
maps: "<%= configFunctions.getConfigProperty('aliases.maps') %>",
lot: "<%= configFunctions.getConfigProperty('aliases.lot') %>",
lots: "<%= configFunctions.getConfigProperty('aliases.lots') %>",
occupancy: "<%= configFunctions.getConfigProperty('aliases.occupancy') %>",
occupancies: "<%= configFunctions.getConfigProperty('aliases.occupancies') %>",
occupancyStartDate: "<%= configFunctions.getConfigProperty('aliases.occupancyStartDate') %>",
occupant: "<%= configFunctions.getConfigProperty('aliases.occupant') %>",
occupants: "<%= configFunctions.getConfigProperty('aliases.occupants') %>",
externalReceiptNumber: "<%= configFunctions.getConfigProperty('aliases.externalReceiptNumber') %>",
workOrderOpenDate: "<%= configFunctions.getConfigProperty('aliases.workOrderOpenDate') %>",
workOrderCloseDate: "<%= configFunctions.getConfigProperty('aliases.workOrderCloseDate') %>"

View File

@ -45,14 +45,14 @@
<span>Work Orders</span>
</a>
<a class="navbar-item" href="<%= urlPrefix %>/lotOccupancies" accesskey="2">
<a class="navbar-item" href="<%= urlPrefix %>/contracts" accesskey="2">
<span class="icon mr-1">
<span class="fa-layers fa-fw" aria-hidden="true">
<i class="fas fa-vector-square"></i>
<i class="fas fa-user" data-fa-transform="shrink-10"></i>
</span>
</span>
<span><%= configFunctions.getConfigProperty("aliases.occupancies") %></span>
<span>Contracts</span>
</a>
<div class="navbar-item has-dropdown">
@ -63,17 +63,17 @@
</span>
</a>
<div class="navbar-dropdown">
<a class="navbar-item" href="<%= urlPrefix %>/lots" accesskey="3">
<a class="navbar-item" href="<%= urlPrefix %>/burialSites" accesskey="3">
<span class="icon mr-1">
<i class="fas fa-fw fa-vector-square" aria-hidden="true"></i>
</span>
<span><%= configFunctions.getConfigProperty("aliases.lots") %></span>
<span>Burial Sites</span>
</a>
<a class="navbar-item" href="<%= urlPrefix %>/maps" accesskey="4">
<a class="navbar-item" href="<%= urlPrefix %>/cemeteries" accesskey="4">
<span class="icon mr-1">
<i class="far fa-fw fa-map" aria-hidden="true"></i>
</span>
<span><%= configFunctions.getConfigProperty("aliases.maps") %></span>
<span>Cemeteries</span>
</a>
<hr class="navbar-divider" />
<a class="navbar-item" href="<%= urlPrefix %>/reports">

View File

@ -4,22 +4,22 @@
<ul>
<li><a href="<%= urlPrefix %>/dashboard">Home</a></li>
<li>
<a href="<%= urlPrefix %>/maps">
<a href="<%= urlPrefix %>/cemeteries">
<span class="icon is-small"><i class="far fa-map" aria-hidden="true"></i></span>
<span><%= configFunctions.getConfigProperty("aliases.maps") %></span>
<span>Cemeteries</span>
</a>
</li>
<% if (!isCreate) { %>
<li>
<a href="<%= urlPrefix %>/maps/<%= map.mapId %>" accesskey="v">
<%= map.mapName || "(No Name)" %>
<a href="<%= urlPrefix %>/cemeteries/<%= cemetery.cemeteryId %>" accesskey="v">
<%= cemetery.cemeteryName || "(No Name)" %>
</a>
</li>
<% } %>
<li class="is-active">
<a href="#" aria-current="page">
<% if (isCreate) { %>
Create a New <%= configFunctions.getConfigProperty("aliases.map") %>
Create a New Cemetery
<% } else { %>
Update
<% } %>
@ -30,9 +30,9 @@
<h1 class="title is-1">
<% if (isCreate) { %>
Create a New <%= configFunctions.getConfigProperty("aliases.map") %>
Create a New Cemetery
<% } else { %>
Update <%= configFunctions.getConfigProperty("aliases.map") %>
Update Cemetery
<% } %>
</h1>
@ -40,14 +40,14 @@
<div class="level-left">
<% if (!isCreate) { %>
<span class="level-item has-text-weight-bold">
<%= map.mapName || "(No Name)" %>
<%= cemetery.cemeteryName || "(No Name)" %>
</span>
<% } %>
</div>
<div class="level-right">
<% if (isCreate) { %>
<div class="level-item">
<a class="button is-danger is-inverted" href="<%= urlPrefix %>/maps">
<a class="button is-danger is-inverted" href="<%= urlPrefix %>/cemeteries">
Cancel
</a>
</div>
@ -64,9 +64,9 @@
</div>
<div class="dropdown-menu">
<div class="dropdown-content">
<a class="dropdown-item" id="button--deleteMap" href="#">
<a class="dropdown-item" id="button--deleteCemetery" href="#">
<span class="icon is-small"><i class="fas fa-trash has-text-danger" aria-hidden="true"></i></span>
<span>Delete <%= configFunctions.getConfigProperty("aliases.map") %></span>
<span>Delete Cemetery</span>
</a>
</div>
</div>
@ -74,11 +74,11 @@
</div>
<% } %>
<div class="level-item">
<button class="button is-primary is-light" type="submit" form="form--map">
<button class="button is-primary is-light" type="submit" form="form--cemetery">
<span class="icon is-small"><i class="fas fa-save" aria-hidden="true"></i></span>
<span>
<%= (isCreate ? "Create": "Update") %>
<%= configFunctions.getConfigProperty("aliases.map") %>
Cemetery
</span>
</button>
</div>
@ -86,27 +86,34 @@
</div>
<form id="form--map">
<input id="map--mapId" name="mapId" type="hidden" value="<%= map.mapId %>" />
<form id="form--cemetery">
<input id="cemetery--cemeteryId" name="cemeteryId" type="hidden" value="<%= cemetery.cemeteryId %>" />
<div class="columns">
<div class="column">
<div class="panel">
<div class="panel-block is-block">
<div class="field">
<label class="label" for="map--mapName"><%= configFunctions.getConfigProperty("aliases.map") %> Name</label>
<div class="control">
<input class="input" id="map--mapName" name="mapName" type="text"
value="<%= map.mapName %>" maxlength="200" required
accesskey="f"
<%= (isCreate ? " autofocus" : "") %> />
</div>
<label class="label" for="cemetery--cemeteryName">Cemetery Name</label>
<div class="control">
<input class="input" id="cemetery--cemeteryName" name="cemeteryName" type="text"
value="<%= cemetery.cemeteryName %>" maxlength="200" required
accesskey="f"
<%= (isCreate ? " autofocus" : "") %> />
</div>
</div>
<div class="field">
<label class="label" for="map--mapDescription"><%= configFunctions.getConfigProperty("aliases.map") %> Description</label>
<div class="control">
<textarea class="textarea" id="map--mapDescription" name="mapDescription"><%= map.mapDescription %></textarea>
</div>
<label class="label" for="cemetery--cemeteryKey">Cemetery Key</label>
<div class="control">
<input class="input" id="cemetery--cemeteryKey" name="cemeteryKey" type="text"
value="<%= cemetery.cemeteryKey %>" maxlength="20" required />
</div>
</div>
<div class="field">
<label class="label" for="cemetery--cemeteryDescription">Cemetery Description</label>
<div class="control">
<textarea class="textarea" id="cemetery--cemeteryDescription" name="cemeteryDescription"><%= cemetery.cemeteryDescription %></textarea>
</div>
</div>
</div>
</div>
@ -116,51 +123,51 @@
<h2 class="panel-heading">Address</h2>
<div class="panel-block is-block">
<div class="field">
<label class="label" for="map--mapAddress1">Address</label>
<div class="control">
<input class="input" id="map--mapAddress1" name="mapAddress1" type="text" value="<%= map.mapAddress1 %>" maxlength="50" placeholder="Line 1" />
</div>
<label class="label" for="cemetery--cemeteryAddress1">Address</label>
<div class="control">
<input class="input" id="cemetery--cemeteryAddress1" name="cemeteryAddress1" type="text" value="<%= cemetery.cemeteryAddress1 %>" maxlength="50" placeholder="Line 1" />
</div>
</div>
<div class="field">
<div class="control">
<input class="input" id="map--mapAddress2" name="mapAddress2" type="text" value="<%= map.mapAddress2 %>" maxlength="50" placeholder="Line 2" aria-label="Address Line 2" />
</div>
<div class="control">
<input class="input" id="cemetery--cemeteryAddress2" name="cemeteryAddress2" type="text" value="<%= cemetery.cemeteryAddress2 %>" maxlength="50" placeholder="Line 2" aria-label="Address Line 2" />
</div>
</div>
<div class="columns">
<div class="column is-8">
<div class="field">
<label class="label" for="map--mapCity">City</label>
<div class="control">
<input class="input" id="map--mapCity" name="mapCity" value="<%= map.mapCity %>" maxlength="20" />
</div>
</div>
<div class="column is-8">
<div class="field">
<label class="label" for="cemetery--cemeteryCity">City</label>
<div class="control">
<input class="input" id="cemetery--cemeteryCity" name="cemeteryCity" value="<%= cemetery.cemeteryCity %>" maxlength="20" />
</div>
</div>
<div class="column">
<div class="field">
<label class="label" for="map--mapProvince">Province</label>
<div class="control">
<input class="input" id="map--mapProvince" name="mapProvince" value="<%= map.mapProvince %>" maxlength="2" />
</div>
</div>
</div>
<div class="column">
<div class="field">
<label class="label" for="cemetery--cemeteryProvince">Province</label>
<div class="control">
<input class="input" id="cemetery--cemeteryProvince" name="cemeteryProvince" value="<%= cemetery.cemeteryProvince %>" maxlength="2" />
</div>
</div>
</div>
</div>
<div class="columns">
<div class="column">
<div class="field">
<label class="label" for="map--mapPostalCode">Postal Code</label>
<div class="control">
<input class="input" id="map--mapPostalCode" name="mapPostalCode" value="<%= map.mapPostalCode %>" maxlength="7" />
</div>
</div>
<div class="column">
<div class="field">
<label class="label" for="cemetery--cemeteryPostalCode">Postal Code</label>
<div class="control">
<input class="input" id="cemetery--cemeteryPostalCode" name="cemeteryPostalCode" value="<%= cemetery.cemeteryPostalCode %>" maxlength="7" />
</div>
</div>
<div class="column">
<div class="field">
<label class="label" for="map--mapPhoneNumber">Phone Number</label>
<div class="control">
<input class="input" id="map--mapPhoneNumber" name="mapPhoneNumber" value="<%= map.mapPhoneNumber %>" maxlength="30" />
</div>
</div>
</div>
<div class="column">
<div class="field">
<label class="label" for="cemetery--cemeteryPhoneNumber">Phone Number</label>
<div class="control">
<input class="input" id="cemetery--cemeteryPhoneNumber" name="cemeteryPhoneNumber" value="<%= cemetery.cemeteryPhoneNumber %>" maxlength="30" />
</div>
</div>
</div>
</div>
</div>
</div>
@ -172,15 +179,15 @@
<h2 class="panel-heading">Geographic Location</h2>
<div class="panel-block is-block">
<div class="field">
<label class="label" for="map--mapLatitude">Latitude</label>
<label class="label" for="cemetery--cemeteryLatitude">Latitude</label>
<div class="control">
<input class="input" id="map--mapLatitude" name="mapLatitude" type="number" min="-90" max="90" step="0.00000001" value="<%= map.mapLatitude %>" />
<input class="input" id="cemetery--cemeteryLatitude" name="cemeteryLatitude" type="number" min="-90" max="90" step="0.00000001" value="<%= cemetery.cemeteryLatitude %>" />
</div>
</div>
<div class="field">
<label class="label" for="map--mapLongitude">Longitude</label>
<label class="label" for="cemetery--cemeteryLongitude">Longitude</label>
<div class="control">
<input class="input" id="map--mapLongitude" name="mapLongitude" type="number" min="-180" max="180" step="0.00000001" value="<%= map.mapLongitude %>" />
<input class="input" id="cemetery--cemeteryLongitude" name="cemeteryLongitude" type="number" min="-180" max="180" step="0.00000001" value="<%= cemetery.cemeteryLongitude %>" />
</div>
</div>
</div>
@ -188,24 +195,24 @@
</div>
<div class="column">
<div class="panel">
<h2 class="panel-heading">Image</h2>
<div class="panel-block is-block">
<div class="field">
<label class="label" for="map--mapSVG">SVG File</label>
<div class="control">
<div class="select is-fullwidth">
<select id="map--mapSVG" name="mapSVG">
<option value="">(Select a File)</option>
<% for (const mapSVG of mapSVGs) { %>
<option value="<%= mapSVG %>" <%= (map.mapSVG === mapSVG) ? " selected" : "" %>>
<%= mapSVG %>
</option>
<% } %>
</select>
</div>
</div>
<h2 class="panel-heading">Image</h2>
<div class="panel-block is-block">
<div class="field">
<label class="label" for="cemetery--cemeterySvg">SVG File</label>
<div class="control">
<div class="select is-fullwidth">
<select id="cemetery--cemeterySvg" name="cemeterySvg">
<option value="">(Select a File)</option>
<% for (const cemeterySVG of cemeterySVGs) { %>
<option value="<%= cemeterySVG %>" <%= (cemetery.cemeterySvg === cemeterySVG) ? " selected" : "" %>>
<%= cemeterySVG %>
</option>
<% } %>
</select>
</div>
</div>
</div>
</div>
</div>
</div>
@ -214,107 +221,107 @@
</form>
<% if (!isCreate) { %>
<% const lotSearchUrl = urlPrefix + "/lots?mapId=" + map.mapId; %>
<% const burialSiteSearchUrl = urlPrefix + "/burialSites?cemeteryId=" + cemetery.cemeteryId; %>
<div class="panel mt-4">
<div class="panel-heading">
<div class="level is-mobile">
<div class="level-left">
<div class="level-item">
<h2 class="title is-5 has-text-weight-bold">
<%= configFunctions.getConfigProperty("aliases.lot") %> Summaries
<a class="tag is-link ml-2" href="<%= lotSearchUrl %>">
<%= map.lotCount %>
</a>
</h2>
</div>
<div class="level-item">
<h2 class="title is-5 has-text-weight-bold">
Burial Site Summaries
<a class="tag is-link ml-2" href="<%= burialSiteSearchUrl %>">
<%= cemetery.burialSiteCount %>
</a>
</h2>
</div>
</div>
<div class="level-right">
<div class="level-item">
<a class="button is-small is-success has-text-weight-normal" href="<%=urlPrefix %>/lots/new?mapId=<%= map.mapId %>">
<a class="button is-small is-success has-text-weight-normal" href="<%=urlPrefix %>/burialSites/new?cemeteryId=<%= cemetery.cemeteryId %>">
<span class="icon"><i class="fas fa-plus" aria-hidden="true"></i></span>
<span>Create a <%= configFunctions.getConfigProperty("aliases.lot") %></span>
<span>Create a Burial Site</span>
</a>
</div>
<div class="level-item">
<a class="button is-small is-link has-text-weight-normal" href="<%=urlPrefix %>/reports/lots-byMapId?mapId=<%= map.mapId %>" download>
<span class="icon"><i class="fas fa-download" aria-hidden="true"></i></span>
<span>Export All</span>
</a>
<a class="button is-small is-link has-text-weight-normal" href="<%=urlPrefix %>/reports/burialSites-byCemeteryId?cemeteryId=<%= cemetery.cemeteryId %>" download>
<span class="icon"><i class="fas fa-download" aria-hidden="true"></i></span>
<span>Export All</span>
</a>
</div>
</div>
</div>
</div>
<div class="panel-block is-block">
<% if (map.lotCount === 0) { %>
<div class="message is-info">
<p class="message-body">
There are no <%= configFunctions.getConfigProperty("aliases.lots").toLowerCase() %>
associated with this <%= configFunctions.getConfigProperty("aliases.map").toLowerCase() %>.
</p>
</div>
<% if (cemetery.burialSiteCount === 0) { %>
<div class="message is-info">
<p class="message-body">
There are no burial sites
associated with this cemetery.
</p>
</div>
<% } else { %>
<div class="columns">
<div class="column">
<table class="table is-fullwidth is-striped is-hoverable">
<thead>
<tr>
<th>Type</th>
<th class="has-text-right">
<%= configFunctions.getConfigProperty("aliases.lot") %> Count
</th>
<th class="has-text-right">Percentage</th>
</tr>
</thead>
<tbody>
<% for (const lotType of lotTypeSummary) { %>
<tr>
<td>
<a class="has-text-weight-bold" href="<%= lotSearchUrl %>&burialSiteTypeId=<%= lotType.burialSiteTypeId %>">
<%= lotType.lotType %>
</a>
</td>
<td class="has-text-right">
<%= lotType.lotCount %>
</td>
<td class="has-text-right">
<%= ((lotType.lotCount / map.lotCount) * 100).toFixed(1) %>%
</td>
</tr>
<% } %>
</tbody>
</table>
</div>
<div class="column">
<table class="table is-fullwidth is-striped is-hoverable">
<thead>
<tr>
<th>Status</th>
<th class="has-text-right">
<%= configFunctions.getConfigProperty("aliases.lot") %> Count
</th>
<th class="has-text-right">Percentage</th>
</tr>
</thead>
<tbody>
<% for (const lotStatus of lotStatusSummary) { %>
<tr>
<td>
<a class="has-text-weight-bold" href="<%= lotSearchUrl %>&burialSiteStatusId=<%= lotStatus.burialSiteStatusId %>">
<%= lotStatus.lotStatus %>
</a>
</td>
<td class="has-text-right">
<%= lotStatus.lotCount %>
</td>
<td class="has-text-right">
<%= ((lotStatus.lotCount / map.lotCount) * 100).toFixed(1) %>%
</td>
</tr>
<% } %>
</tbody>
</table>
</div>
<div class="columns">
<div class="column">
<table class="table is-fullwidth is-striped is-hoverable">
<thead>
<tr>
<th>Type</th>
<th class="has-text-right">
Burial Site Count
</th>
<th class="has-text-right">Percentage</th>
</tr>
</thead>
<tbody>
<% for (const burialSiteType of burialSiteTypeSummary) { %>
<tr>
<td>
<a class="has-text-weight-bold" href="<%= burialSiteSearchUrl %>&burialSiteTypeId=<%= burialSiteType.burialSiteTypeId %>">
<%= burialSiteType.burialSiteType %>
</a>
</td>
<td class="has-text-right">
<%= burialSiteType.burialSiteCount %>
</td>
<td class="has-text-right">
<%= ((burialSiteType.burialSiteCount / cemetery.burialSiteCount) * 100).toFixed(1) %>%
</td>
</tr>
<% } %>
</tbody>
</table>
</div>
<div class="column">
<table class="table is-fullwidth is-striped is-hoverable">
<thead>
<tr>
<th>Status</th>
<th class="has-text-right">
Burial Site Count
</th>
<th class="has-text-right">Percentage</th>
</tr>
</thead>
<tbody>
<% for (const burialSiteStatus of burialSiteStatusSummary) { %>
<tr>
<td>
<a class="has-text-weight-bold" href="<%= burialSiteSearchUrl %>&burialSiteStatusId=<%= burialSiteStatus.burialSiteStatusId %>">
<%= burialSiteStatus.burialSiteStatus %>
</a>
</td>
<td class="has-text-right">
<%= burialSiteStatus.burialSiteCount %>
</td>
<td class="has-text-right">
<%= ((burialSiteStatus.burialSiteCount / cemetery.burialSiteCount) * 100).toFixed(1) %>%
</td>
</tr>
<% } %>
</tbody>
</table>
</div>
</div>
<% } %>
</div>
</div>
@ -322,6 +329,6 @@
<%- include('_footerA'); -%>
<script src="<%= urlPrefix %>/javascripts/mapEdit.js"></script>
<script src="<%= urlPrefix %>/javascripts/cemetery.edit.js"></script>
<%- include('_footerB'); -%>

View File

@ -6,7 +6,7 @@
<li class="is-active">
<a href="#" aria-current="page">
<span class="icon is-small"><i class="far fa-map" aria-hidden="true"></i></span>
<span><%= configFunctions.getConfigProperty("aliases.maps") %></span>
<span>Cemeteries</span>
</a>
</li>
</ul>
@ -15,11 +15,11 @@
<div class="columns is-vcentered">
<div class="column">
<h1 class="title is-1">
Find a <%= configFunctions.getConfigProperty("aliases.map") %>
Find a Cemetery
</h1>
</div>
<div class="column has-text-right is-narrow">
<a class="button" href="<%= urlPrefix %>/reports/maps-formatted" target="_blank" download>
<a class="button" href="<%= urlPrefix %>/reports/cemeteries-formatted" target="_blank" download>
<span class="icon is-small"><i class="fas fa-download" aria-hidden="true"></i></span>
<span>Export</span>
</a>
@ -29,11 +29,11 @@
<% if (user.userProperties.canUpdate) { %>
<div class="fixed-container is-fixed-bottom-right mx-4 my-4 has-text-right is-hidden-print">
<a class="button is-circle is-primary has-tooltip-left"
data-tooltip="Create a New <%= configFunctions.getConfigProperty("aliases.map") %>"
href="<%= urlPrefix %>/maps/new"
data-tooltip="Create a New Cemetery"
href="<%= urlPrefix %>/cemeteries/new"
accesskey="n">
<i class="fas fa-plus" aria-hidden="true"></i>
<span class="sr-only">Create a New <%= configFunctions.getConfigProperty("aliases.map") %></span>
<span class="sr-only">Create a New Cemetery</span>
</a>
</div>
<% } %>
@ -42,8 +42,8 @@
<form id="form--searchFilters">
<div class="field">
<div class="control has-icons-left">
<input class="input" id="searchFilter--map" type="text"
placeholder="Search <%= configFunctions.getConfigProperty("aliases.map").toLowerCase() %> name, description, and address"
<input class="input" id="searchFilter--cemetery" type="text"
placeholder="Search cemetery name, description, and address"
accesskey="f" />
<span class="icon is-small is-left">
<i class="fas fa-search" aria-hidden="true"></i>
@ -58,8 +58,8 @@
<%- include('_footerA'); -%>
<script>
exports.maps = <%- JSON.stringify(maps) %>;
exports.cemeteries = <%- JSON.stringify(cemeteries) %>;
</script>
<script src="<%= urlPrefix %>/javascripts/mapSearch.js"></script>
<script src="<%= urlPrefix %>/javascripts/cemetery.search.js"></script>
<%- include('_footerB'); -%>

View File

@ -4,44 +4,44 @@
<ul>
<li><a href="<%= urlPrefix %>/dashboard">Home</a></li>
<li>
<a href="<%= urlPrefix %>/maps">
<span class="icon is-small"><i class="far fa-map" aria-hidden="true"></i></span>
<span><%= configFunctions.getConfigProperty("aliases.maps") %></span>
</a>
<a href="<%= urlPrefix %>/maps">
<span class="icon is-small"><i class="far fa-map" aria-hidden="true"></i></span>
<span>Cemeteries</span>
</a>
</li>
<li class="is-active">
<a href="#" aria-current="page">
<%= map.mapName || "(No Name)" %>
</a>
<a href="#" aria-current="page">
<%= cemetery.cemeteryName || "(No Name)" %>
</a>
</li>
</ul>
</nav>
<h1 class="title is-1">
<%= map.mapName || "(No Name)" %>
<%= cemetery.cemeteryName || "(No Name)" %>
</h1>
<div class="level is-fixed-bottom is-mobile has-background-white has-shadow is-hidden-print">
<div class="level-left">
<span class="level-item has-text-weight-bold">
<%= map.mapName || "(No Name)" %>
<%= cemetery.cemeteryName || "(No Name)" %>
</span>
</div>
<div class="level-right">
<div class="level-item">
<a class="button is-link is-outlined has-tooltip-left"
data-tooltip="Previous <%= configFunctions.getConfigProperty("aliases.map") %>"
href="<%= urlPrefix %>/maps/<%= map.mapId %>/previous"
data-tooltip="Previous Cemetery"
href="<%= urlPrefix %>/cemeteries/<%= cemetery.cemeteryId %>/previous"
accesskey=",">
<i class="fas fa-arrow-left" aria-hidden="true"></i>
<span class="sr-only">Previous <%= configFunctions.getConfigProperty("aliases.map") %></span>
<span class="sr-only">Previous Cemetery</span>
</a>
</div>
<div class="level-item">
<a class="button is-link has-tooltip-left"
data-tooltip="Next <%= configFunctions.getConfigProperty("aliases.map") %>"
href="<%= urlPrefix %>/maps/<%= map.mapId %>/next"
data-tooltip="Next Cemetery"
href="<%= urlPrefix %>/cemeteries/<%= cemetery.cemeteryId %>/next"
accesskey=".">
<span>Next</span>
<span class="icon"><i class="fas fa-arrow-right" aria-hidden="true"></i></span>
@ -50,10 +50,10 @@
<% if (user.userProperties.canUpdate) { %>
<div class="level-item">
<a class="button is-primary"
href="<%= urlPrefix %>/maps/<%= map.mapId %>/edit"
accesskey="e">
<span class="icon"><i class="fas fa-pencil-alt" aria-hidden="true"></i></span>
<span>Switch to Edit Mode</span>
href="<%= urlPrefix %>/cemeteries/<%= cemetery.cemeteryId %>/edit"
accesskey="e">
<span class="icon"><i class="fas fa-pencil-alt" aria-hidden="true"></i></span>
<span>Switch to Edit Mode</span>
</a>
</div>
<% } %>
@ -61,62 +61,62 @@
</div>
<div class="panel">
<div class="panel-block is-block">
<div class="columns">
<% if (map.mapDescription && map.mapDescription !== "") { %>
<div class="column">
<strong>Description</strong><br />
<%= map.mapDescription %>
</div>
<% } %>
<div class="column">
<strong>Address</strong><br />
<% if (map.mapAddress1 !== "") { %>
<%= map.mapAddress1 %><br />
<% } %>
<% if (map.mapAddress2 !== "") { %>
<%= map.mapAddress2 %><br />
<% } %>
<%= map.mapCity %>, <%= map.mapProvince %><br />
<%= map.mapPostalCode %>
</div>
<% if (map.mapPhoneNumber !== "") { %>
<div class="column">
<strong>Phone Number</strong><br />
<%= map.mapPhoneNumber %>
</div>
<% } %>
<div class="panel-block is-block">
<div class="columns">
<% if (cemetery.cemeteryDescription && cemetery.cemeteryDescription !== "") { %>
<div class="column">
<strong>Description</strong><br />
<%= cemetery.cemeteryDescription %>
</div>
<% } %>
<div class="column">
<strong>Address</strong><br />
<% if (cemetery.cemeteryAddress1 !== "") { %>
<%= cemetery.cemeteryAddress1 %><br />
<% } %>
<% if (cemetery.cemeteryAddress2 !== "") { %>
<%= cemetery.cemeteryAddress2 %><br />
<% } %>
<%= cemetery.cemeteryCity %>, <%= cemetery.cemeteryProvince %><br />
<%= cemetery.cemeteryPostalCode %>
</div>
<% if (cemetery.cemeteryPhoneNumber !== "") { %>
<div class="column">
<strong>Phone Number</strong><br />
<%= cemetery.cemeteryPhoneNumber %>
</div>
<% } %>
</div>
</div>
</div>
<div class="columns">
<div class="column">
<div class="panel">
<h2 class="panel-heading">Geographic Location</h2>
<div class="panel-block is-block">
<% if (map.mapLatitude && map.mapLongitude) { %>
<div id="map--leaflet" data-map-latitude="<%= map.mapLatitude %>" data-map-longitude="<%= map.mapLongitude %>" style="height:300px"></div>
<% } else { %>
<div class="message is-info">
<p class="message-body">There are no geographic coordinates associated with this <%= configFunctions.getConfigProperty("aliases.map").toLowerCase() %>.</p>
</div>
<% } %>
</div>
<div class="panel">
<h2 class="panel-heading">Geographic Location</h2>
<div class="panel-block is-block">
<% if (cemetery.cemeteryLatitude && cemetery.cemeteryLongitude) { %>
<div id="cemetery--leaflet" data-cemetery-latitude="<%= cemetery.cemeteryLatitude %>" data-cemetery-longitude="<%= cemetery.cemeteryLongitude %>" style="height:300px"></div>
<% } else { %>
<div class="message is-info">
<p class="message-body">There are no geographic coordinates associated with this cemetery.</p>
</div>
<% } %>
</div>
</div>
</div>
<div class="column">
<div class="panel">
<h2 class="panel-heading">Image</h2>
<div class="panel-block is-block">
<% if (map.mapSVG) { %>
<% const imageURL = urlPrefix + "/images/maps/" + map.mapSVG %>
<a class="image" href="<%= urlPrefix %>/images/maps/<%= map.mapSVG %>" target="_blank">
<%- include('../public/images/maps/' + map.mapSVG); -%>
<% if (cemetery.cemeterySvg) { %>
<% const imageURL = urlPrefix + "/images/cemeteries/" + cemetery.cemeterySvg %>
<a class="image" href="<%= urlPrefix %>/images/cemeteries/<%= cemetery.cemeterySvg %>" target="_blank">
<%- include('../public/images/cemeteries/' + cemetery.cemeterySvg); -%>
</a>
<% } else { %>
<div class="message is-info">
<p class="message-body">There are no image associated with this <%= configFunctions.getConfigProperty("aliases.map").toLowerCase() %>.</p>
<p class="message-body">There are no image associated with this cemetery.</p>
</div>
<% } %>
</div>
@ -124,38 +124,37 @@
</div>
</div>
<% const lotSearchUrl = urlPrefix + "/lots?mapId=" + map.mapId; %>
<% const burialSiteSearchUrl = urlPrefix + "/burialSites?cemeteryId=" + cemetery.cemeteryId; %>
<div class="panel">
<div class="panel-heading">
<div class="level is-mobile">
<div class="level-left">
<div class="level-item">
<h2 class="title is-5 has-text-weight-bold">
<%= configFunctions.getConfigProperty("aliases.lot") %> Summaries
<a class="tag is-link ml-2" href="<%= lotSearchUrl %>">
<%= map.lotCount %>
</a>
</h2>
</div>
<div class="level-item">
<h2 class="title is-5 has-text-weight-bold">
Burial Site Summaries
<a class="tag is-link ml-2" href="<%= burialSiteSearchUrl %>">
<%= cemetery.burialSiteCount %>
</a>
</h2>
</div>
</div>
<div class="level-right">
<div class="level-item">
<a class="button is-small is-link has-text-weight-normal" href="<%=urlPrefix %>/reports/lots-byMapId?mapId=<%= map.mapId %>" download>
<span class="icon"><i class="fas fa-download" aria-hidden="true"></i></span>
<span>Export All</span>
</a>
</div>
<div class="level-item">
<a class="button is-small is-link has-text-weight-normal" href="<%=urlPrefix %>/reports/burialSites-byCemeteryId?cemeteryId=<%= cemetery.cemeteryId %>" download>
<span class="icon"><i class="fas fa-download" aria-hidden="true"></i></span>
<span>Export All</span>
</a>
</div>
</div>
</div>
</div>
<div class="panel-block is-block">
<% if (map.lotCount === 0) { %>
<div class="message is-info">
<p class="message-body">
There are no <%= configFunctions.getConfigProperty("aliases.lots").toLowerCase() %>
associated with this <%= configFunctions.getConfigProperty("aliases.map").toLowerCase() %>.
</p>
</div>
<% if (cemetery.burialSiteCount === 0) { %>
<div class="message is-info">
<p class="message-body">
There are no burial sites associated with this cemetery.
</p>
</div>
<% } else { %>
<div class="columns">
<div class="column">
@ -164,56 +163,56 @@
<tr>
<th>Type</th>
<th class="has-text-right">
<%= configFunctions.getConfigProperty("aliases.lot") %> Count
Burial Site Count
</th>
<th class="has-text-right">Percentage</th>
</tr>
</thead>
<tbody>
<% for (const lotType of lotTypeSummary) { %>
<tr>
<td>
<a class="has-text-weight-bold" href="<%= lotSearchUrl %>&burialSiteTypeId=<%= lotType.burialSiteTypeId %>">
<%= lotType.lotType %>
</a>
</td>
<td class="has-text-right">
<%= lotType.lotCount %>
</td>
<td class="has-text-right">
<%= ((lotType.lotCount / map.lotCount) * 100).toFixed(1) %>%
</td>
</tr>
<% } %>
<% for (const burialSiteType of burialSiteTypeSummary) { %>
<tr>
<td>
<a class="has-text-weight-bold" href="<%= lotSearchUrl %>&burialSiteTypeId=<%= burialSiteType.burialSiteTypeId %>">
<%= burialSiteType.burialSiteType %>
</a>
</td>
<td class="has-text-right">
<%= burialSiteType.burialSiteCount %>
</td>
<td class="has-text-right">
<%= ((burialSiteType.burialSiteCount / cemetery.burialSiteCount) * 100).toFixed(1) %>%
</td>
</tr>
<% } %>
</tbody>
</table>
</div>
<div class="column">
<table class="table is-fullwidth is-striped is-hoverable">
<thead>
<tr>
<th>Status</th>
<th class="has-text-right">
<%= configFunctions.getConfigProperty("aliases.lot") %> Count
</th>
<th class="has-text-right">Percentage</th>
</tr>
<tr>
<th>Status</th>
<th class="has-text-right">
Burial Site Count
</th>
<th class="has-text-right">Percentage</th>
</tr>
</thead>
<tbody>
<% for (const lotStatus of lotStatusSummary) { %>
<tr>
<td>
<a class="has-text-weight-bold" href="<%= lotSearchUrl %>&burialSiteStatusId=<%= lotStatus.burialSiteStatusId %>">
<%= lotStatus.lotStatus %>
</a>
</td>
<td class="has-text-right">
<%= lotStatus.lotCount %>
</td>
<td class="has-text-right">
<%= ((lotStatus.lotCount / map.lotCount) * 100).toFixed(1) %>%
</td>
</tr>
<% for (const burialSiteStatus of burialSiteStatusSummary) { %>
<tr>
<td>
<a class="has-text-weight-bold" href="<%= lotSearchUrl %>&burialSiteStatusId=<%= burialSiteStatus.burialSiteStatusId %>">
<%= burialSiteStatus.burialSiteStatus %>
</a>
</td>
<td class="has-text-right">
<%= burialSiteStatus.burialSiteCount %>
</td>
<td class="has-text-right">
<%= ((burialSiteStatus.burialSiteCount / map.burialSiteCount) * 100).toFixed(1) %>%
</td>
</tr>
<% } %>
</tbody>
</table>
@ -225,6 +224,6 @@
<%- include('_footerA'); -%>
<script src="<%= urlPrefix %>/javascripts/mapView.js"></script>
<script src="<%= urlPrefix %>/javascripts/cemetery.view.js"></script>
<%- include('_footerB'); -%>

View File

@ -59,25 +59,24 @@
<%= milestone.workOrderNumber %>
</a><br />
<%
if (milestone.workOrderLots.length > 0) {
for (const lot of milestone.workOrderLots) {
if (milestone.workOrderBurialSites.length > 0) {
for (const burialSite of milestone.workOrderBurialSites) {
%>
<span class="has-tooltip-right" data-tooltip="<%= lot.mapName %>">
<i class="fas fa-fw fa-vector-square" aria-label="<%= configFunctions.getConfigProperty("aliases.lot") %>"></i>
<%= lot.lotName %>
<span class="has-tooltip-right" data-tooltip="<%= burialSite.cemeteryName %>">
<i class="fas fa-fw fa-vector-square" aria-label="Burial Site"></i>
<%= burialSite.burialSiteName %>
</span><br />
<%
}
}
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) {
%>
<span class="has-tooltip-right" data-tooltip="<%= occupant.lotOccupantType %>">
<i class="fas fa-fw fa-<%= occupant.fontAwesomeIconClass || 'user' %>" aria-label="<%= configFunctions.getConfigProperty("aliases.occupancy") %>"></i>
<%= occupant.occupantName %>
<%= occupant.occupantFamilyName %>
<span class="has-tooltip-right" data-tooltip="Interment">
<i class="fas fa-fw fa-user" aria-label="Contract"></i>
<%= interment.deceasedName %>
</span><br />
<%
}
@ -94,87 +93,86 @@
<% } %>
<div class="column">
<div class="columns is-desktop">
<div class="column">
<div class="card is-hover-container">
<div class="card-content">
<div class="media">
<div class="media-left">
<span class="fa-layers fa-4x fa-fw">
<i class="fas fa-fw fa-hard-hat" aria-hidden="true"></i>
<% if (workOrderCount > 0) { %>
<a class="fa-layers-counter has-background-success has-text-white" href="<%= urlPrefix %>/workOrders/?workOrderOpenDateString=<%= dateTimeFunctions.dateToString(new Date()) %>"><%= workOrderCount %></a>
<% } %>
</span>
</div>
<a class="media-content" href="<%= urlPrefix %>/workOrders">
<h2 class="title is-4 is-marginless has-text-link">
Work Orders
</h2>
<p>
View and maintain work orders.<br />
<span class="tags has-addons is-invisible is-visible-hover">
<span class="tag is-link is-light">Shortcut</span>
<kbd class="tag">1</kbd>
</span>
</p>
</a>
</div>
<% if (user.userProperties.canUpdate) { %>
<a class="button is-fullwidth is-success is-light mb-2" href="<%= urlPrefix %>/workOrders/new">
<span class="icon">
<i class="fas fa-plus" aria-hidden="true"></i>
</span>
<span>New Work Order</span>
</a>
<% } %>
<a class="button is-fullwidth is-link is-light" href="<%= urlPrefix %>/workOrders/milestoneCalendar">
<span class="icon">
<i class="fas fa-calendar" aria-hidden="true"></i>
<div class="column">
<div class="card is-hover-container">
<div class="card-content">
<div class="media">
<div class="media-left">
<span class="fa-layers fa-4x fa-fw">
<i class="fas fa-fw fa-hard-hat" aria-hidden="true"></i>
<% if (workOrderCount > 0) { %>
<a class="fa-layers-counter has-background-success has-text-white" href="<%= urlPrefix %>/workOrders/?workOrderOpenDateString=<%= dateTimeFunctions.dateToString(new Date()) %>"><%= workOrderCount %></a>
<% } %>
</span>
<span>Milestone Calendar</span>
</div>
<a class="media-content" href="<%= urlPrefix %>/workOrders">
<h2 class="title is-4 is-marginless has-text-link">
Work Orders
</h2>
<p>
View and maintain work orders.<br />
<span class="tags has-addons is-invisible is-visible-hover">
<span class="tag is-link is-light">Shortcut</span>
<kbd class="tag">1</kbd>
</span>
</p>
</a>
</div>
<% if (user.userProperties.canUpdate) { %>
<a class="button is-fullwidth is-success is-light mb-2" href="<%= urlPrefix %>/workOrders/new">
<span class="icon">
<i class="fas fa-plus" aria-hidden="true"></i>
</span>
<span>New Work Order</span>
</a>
<% } %>
<a class="button is-fullwidth is-link is-light" href="<%= urlPrefix %>/workOrders/milestoneCalendar">
<span class="icon">
<i class="fas fa-calendar" aria-hidden="true"></i>
</span>
<span>Milestone Calendar</span>
</a>
</div>
</div>
</div>
<div class="column">
<div class="card is-hover-container">
<div class="card-content">
<div class="media">
<div class="media-left">
<span class="fa-layers fa-4x fa-fw" aria-hidden="true">
<i class="fas fa-vector-square"></i>
<i class="fas fa-user" data-fa-transform="shrink-10"></i>
<% if (lotOccupancyCount > 0) { %>
<span class="fa-layers-counter has-background-success"><%= lotOccupancyCount %></span>
<% } %>
</span>
</div>
<a class="media-content" href="<%= urlPrefix %>/lotOccupancies">
<h2 class="title is-4 is-marginless has-text-link">
<%= configFunctions.getConfigProperty("aliases.occupancies") %>
</h2>
<p>
View and maintain current and past
<%= configFunctions.getConfigProperty("aliases.occupancies").toLowerCase() %>.<br />
<span class="tags has-addons is-invisible is-visible-hover">
<span class="tag is-link is-light">Shortcut</span>
<kbd class="tag">2</kbd>
</span>
</p>
</a>
</div>
<% if (user.userProperties.canUpdate) { %>
<a class="button is-fullwidth is-success is-light" href="<%= urlPrefix %>/lotOccupancies/new">
<span class="icon">
<i class="fas fa-plus" aria-hidden="true"></i>
</span>
<span>New <%= configFunctions.getConfigProperty("aliases.occupancy") %></span>
</a>
<% } %>
<div class="column">
<div class="card is-hover-container">
<div class="card-content">
<div class="media">
<div class="media-left">
<span class="fa-layers fa-4x fa-fw" aria-hidden="true">
<i class="fas fa-vector-square"></i>
<i class="fas fa-user" data-fa-transform="shrink-10"></i>
<% if (burialSiteContractCount > 0) { %>
<span class="fa-layers-counter has-background-success"><%= burialSiteContractCount %></span>
<% } %>
</span>
</div>
<a class="media-content" href="<%= urlPrefix %>/contracts">
<h2 class="title is-4 is-marginless has-text-link">
Contracts
</h2>
<p>
View and maintain current and past contracts.<br />
<span class="tags has-addons is-invisible is-visible-hover">
<span class="tag is-link is-light">Shortcut</span>
<kbd class="tag">2</kbd>
</span>
</p>
</a>
</div>
<% if (user.userProperties.canUpdate) { %>
<a class="button is-fullwidth is-success is-light" href="<%= urlPrefix %>/contracts/new">
<span class="icon">
<i class="fas fa-plus" aria-hidden="true"></i>
</span>
<span>New Contract</span>
</a>
<% } %>
</div>
</div>
</div>
</div>
<div class="columns is-desktop">
<div class="column">
@ -184,14 +182,12 @@
<div class="media-left">
<i class="fas fa-4x fa-fw fa-vector-square" aria-hidden="true"></i>
</div>
<a class="media-content" href="<%= urlPrefix %>/lots">
<a class="media-content" href="<%= urlPrefix %>/burialSites">
<h2 class="title is-4 is-marginless has-text-link">
<%= configFunctions.getConfigProperty("aliases.lots") %>
Burial Sites
</h2>
<p>
View and maintain
<%= configFunctions.getConfigProperty("aliases.lots").toLowerCase() %> within a
<%= configFunctions.getConfigProperty("aliases.map").toLowerCase() %>.<br />
View and maintain burial sites within a cemetery.<br />
<span class="tags has-addons is-invisible is-visible-hover">
<span class="tag is-link is-light">Shortcut</span>
<kbd class="tag">3</kbd>
@ -200,11 +196,11 @@
</a>
</div>
<% if (user.userProperties.canUpdate) { %>
<a class="button is-fullwidth is-success is-light" href="<%= urlPrefix %>/lots/new">
<a class="button is-fullwidth is-success is-light" href="<%= urlPrefix %>/burialSites/new">
<span class="icon">
<i class="fas fa-plus" aria-hidden="true"></i>
</span>
<span>New <%= configFunctions.getConfigProperty("aliases.lot") %></span>
<span>New Burial Site</span>
</a>
<% } %>
</div>
@ -217,12 +213,12 @@
<div class="media-left">
<i class="far fa-4x fa-fw fa-map" aria-hidden="true"></i>
</div>
<a class="media-content" href="<%= urlPrefix %>/maps">
<a class="media-content" href="<%= urlPrefix %>/cemeteries">
<h2 class="title is-4 is-marginless has-text-link">
<%= configFunctions.getConfigProperty("aliases.maps") %>
Cemeteries
</h2>
<p>
View and maintain <%= configFunctions.getConfigProperty("aliases.maps").toLowerCase() %>.
View and maintain cemeteries.
<span class="tags has-addons is-invisible is-visible-hover">
<span class="tag is-link is-light">Shortcut</span>
<kbd class="tag">4</kbd>
@ -231,11 +227,11 @@
</a>
</div>
<% if (user.userProperties.canUpdate) { %>
<a class="button is-fullwidth is-success is-light" href="<%= urlPrefix %>/maps/new">
<a class="button is-fullwidth is-success is-light" href="<%= urlPrefix %>/cemeteries/new">
<span class="icon">
<i class="fas fa-plus" aria-hidden="true"></i>
</span>
<span>New <%= configFunctions.getConfigProperty("aliases.map") %></span>
<span>New Cemetery</span>
</a>
<% } %>
</div>
@ -262,12 +258,13 @@
</div>
<div class="column">
<div class="card is-hover-container">
<a class="button is-fullwidth is-link is-light has-tooltip-bottom" data-tooltip="Latest Updates, Issue Tracker, Say Hello"
href="https://github.com/cityssm/sunrise-cms" target="_blank" rel="noreferrer">
<span class="icon">
<i class="fab fa-github" aria-hidden="true"></i>
</span>
<span>GitHub</span>
<div class="card-content">
<a class="button is-fullwidth is-link is-light has-tooltip-bottom" data-tooltip="Latest Updates, Issue Tracker, Say Hello"
href="https://github.com/cityssm/sunrise-cms" target="_blank" rel="noreferrer">
<span class="icon">
<i class="fab fa-github" aria-hidden="true"></i>
</span>
<span>GitHub</span>
</a>
</div>
</div>
@ -291,11 +288,8 @@
Fee Management
</h2>
<p>
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.
</p>
</a>
</div>
@ -308,13 +302,12 @@
<i class="fas fa-cog" data-fa-transform="shrink-8 right-8 down-5" data-fa-glow="10"></i>
</span>
</div>
<a class="media-content" href="<%= urlPrefix %>/admin/occupancyTypes">
<a class="media-content" href="<%= urlPrefix %>/admin/contractTypes">
<h2 class="title is-4 is-marginless has-text-link">
<%= configFunctions.getConfigProperty("aliases.occupancy") %> Type Management
Contract Type Management
</h2>
<p>
Manage
<%= configFunctions.getConfigProperty("aliases.occupancy").toLowerCase() %> types,
Manage contract types,
the fields associated with them,
and their available print options.
</p>
@ -329,14 +322,12 @@
<i class="fas fa-cog" data-fa-transform="shrink-8 right-8 down-5" data-fa-glow="10"></i>
</span>
</div>
<a class="media-content" href="<%= urlPrefix %>/admin/lotTypes">
<a class="media-content" href="<%= urlPrefix %>/admin/burialSiteTypes">
<h2 class="title is-4 is-marginless has-text-link">
<%= configFunctions.getConfigProperty("aliases.lot") %> Type Management
Burial Site Type Management
</h2>
<p>
Manage
<%= configFunctions.getConfigProperty("aliases.lot").toLowerCase() %> types
and fields associated with them.
Manage burial site types and fields associated with them.
</p>
</a>
</div>
@ -355,9 +346,8 @@
</h2>
<p>
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.
</p>
</a>
</div>