/* eslint-disable @typescript-eslint/no-non-null-assertion, unicorn/prefer-module */ import type * as globalTypes from '../types/globalTypes' import type * as recordTypes from '../types/recordTypes' import type { cityssmGlobal } from '@cityssm/bulma-webapp-js/src/types' import type { BulmaJS } from '@cityssm/bulma-js/types' declare const cityssm: cityssmGlobal declare const bulmaJS: BulmaJS type ResponseJSON = | { success: true occupancyTypes: recordTypes.OccupancyType[] allOccupancyTypeFields: recordTypes.OccupancyTypeField[] occupancyTypeFieldId?: number } | { success: false errorMessage: string } ;(() => { const los = exports.los as globalTypes.LOS const occupancyTypesContainerElement = document.querySelector( '#container--occupancyTypes' ) as HTMLElement const occupancyTypePrintsContainerElement = document.querySelector( '#container--occupancyTypePrints' ) as HTMLElement let occupancyTypes: recordTypes.OccupancyType[] = exports.occupancyTypes delete exports.occupancyTypes let allOccupancyTypeFields: recordTypes.OccupancyTypeField[] = exports.allOccupancyTypeFields delete exports.allOccupancyTypeFields const expandedOccupancyTypes = new Set() function toggleOccupancyTypeFields(clickEvent: Event): void { const toggleButtonElement = clickEvent.currentTarget as HTMLButtonElement const occupancyTypeElement = toggleButtonElement.closest( '.container--occupancyType' ) as HTMLElement const occupancyTypeId = Number.parseInt( occupancyTypeElement.dataset.occupancyTypeId!, 10 ) if (expandedOccupancyTypes.has(occupancyTypeId)) { expandedOccupancyTypes.delete(occupancyTypeId) } else { expandedOccupancyTypes.add(occupancyTypeId) } toggleButtonElement.innerHTML = expandedOccupancyTypes.has(occupancyTypeId) ? '' : '' const panelBlockElements = occupancyTypeElement.querySelectorAll('.panel-block') for (const panelBlockElement of panelBlockElements) { panelBlockElement.classList.toggle('is-hidden') } } function occupancyTypeResponseHandler(responseJSON: { success: boolean errorMessage?: string occupancyTypes?: recordTypes.OccupancyType[] allOccupancyTypeFields?: recordTypes.OccupancyTypeField[] }): void { if (responseJSON.success) { occupancyTypes = responseJSON.occupancyTypes! allOccupancyTypeFields = responseJSON.allOccupancyTypeFields! renderOccupancyTypes() } else { bulmaJS.alert({ title: 'Error Updating ' + los.escapedAliases.Occupancy + ' Type', message: responseJSON.errorMessage ?? '', contextualColorName: 'danger' }) } } function deleteOccupancyType(clickEvent: Event): void { const occupancyTypeId = Number.parseInt( ( (clickEvent.currentTarget as HTMLElement).closest( '.container--occupancyType' ) as HTMLElement ).dataset.occupancyTypeId!, 10 ) function doDelete(): void { cityssm.postJSON( los.urlPrefix + '/admin/doDeleteOccupancyType', { occupancyTypeId }, 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: Event): void { const occupancyTypeId = Number.parseInt( ( (clickEvent.currentTarget as HTMLElement).closest( '.container--occupancyType' ) as HTMLElement ).dataset.occupancyTypeId!, 10 ) const occupancyType = occupancyTypes.find((currentOccupancyType) => { return occupancyTypeId === currentOccupancyType.occupancyTypeId })! let editCloseModalFunction: () => void function doEdit(submitEvent: SubmitEvent): void { submitEvent.preventDefault() cityssm.postJSON( los.urlPrefix + '/admin/doUpdateOccupancyType', submitEvent.currentTarget, (rawResponseJSON) => { const responseJSON = rawResponseJSON as ResponseJSON occupancyTypeResponseHandler(responseJSON) if (responseJSON.success) { editCloseModalFunction() } } ) } cityssm.openHtmlModal('adminOccupancyTypes-editOccupancyType', { onshow(modalElement): void { los.populateAliases(modalElement) ;( modalElement.querySelector( '#occupancyTypeEdit--occupancyTypeId' ) as HTMLInputElement ).value = occupancyTypeId.toString() ;( modalElement.querySelector( '#occupancyTypeEdit--occupancyType' ) as HTMLInputElement ).value = occupancyType.occupancyType }, onshown(modalElement, closeModalFunction) { editCloseModalFunction = closeModalFunction ;( modalElement.querySelector( '#occupancyTypeEdit--occupancyType' ) as HTMLInputElement ).focus() modalElement.querySelector('form')!.addEventListener('submit', doEdit) bulmaJS.toggleHtmlClipped() }, onremoved() { bulmaJS.toggleHtmlClipped() } }) } function openAddOccupancyTypeField(clickEvent: Event): void { const occupancyTypeId = Number.parseInt( ( (clickEvent.currentTarget as HTMLElement).closest( '.container--occupancyType' ) as HTMLElement ).dataset.occupancyTypeId!, 10 ) let addCloseModalFunction: () => void function doAdd(submitEvent: SubmitEvent): void { submitEvent.preventDefault() cityssm.postJSON( los.urlPrefix + '/admin/doAddOccupancyTypeField', submitEvent.currentTarget, (rawResponseJSON) => { const responseJSON = rawResponseJSON as ResponseJSON expandedOccupancyTypes.add(occupancyTypeId) occupancyTypeResponseHandler(responseJSON) if (responseJSON.success) { addCloseModalFunction() openEditOccupancyTypeField( occupancyTypeId, responseJSON.occupancyTypeFieldId! ) } } ) } cityssm.openHtmlModal('adminOccupancyTypes-addOccupancyTypeField', { onshow(modalElement) { los.populateAliases(modalElement) if (occupancyTypeId) { ;( modalElement.querySelector( '#occupancyTypeFieldAdd--occupancyTypeId' ) as HTMLInputElement ).value = occupancyTypeId.toString() } }, onshown(modalElement, closeModalFunction) { addCloseModalFunction = closeModalFunction ;( modalElement.querySelector( '#occupancyTypeFieldAdd--occupancyTypeField' ) as HTMLInputElement ).focus() modalElement.querySelector('form')!.addEventListener('submit', doAdd) bulmaJS.toggleHtmlClipped() }, onremoved() { bulmaJS.toggleHtmlClipped() } }) } function moveOccupancyType(clickEvent: MouseEvent): void { const buttonElement = clickEvent.currentTarget as HTMLButtonElement const occupancyTypeId = ( (clickEvent.currentTarget as HTMLElement).closest( '.container--occupancyType' ) as HTMLElement ).dataset.occupancyTypeId cityssm.postJSON( los.urlPrefix + '/admin/' + (buttonElement.dataset.direction === 'up' ? 'doMoveOccupancyTypeUp' : 'doMoveOccupancyTypeDown'), { occupancyTypeId, moveToEnd: clickEvent.shiftKey ? '1' : '0' }, occupancyTypeResponseHandler ) } function openEditOccupancyTypeField( occupancyTypeId: number, occupancyTypeFieldId: number ): void { let occupancyType: recordTypes.OccupancyType | undefined if (occupancyTypeId) { occupancyType = occupancyTypes.find((currentOccupancyType) => { return currentOccupancyType.occupancyTypeId === occupancyTypeId }) } const occupancyTypeField = ( occupancyType ? occupancyType.occupancyTypeFields! : allOccupancyTypeFields ).find((currentOccupancyTypeField) => { return ( currentOccupancyTypeField.occupancyTypeFieldId === occupancyTypeFieldId ) })! let minimumLengthElement: HTMLInputElement let maximumLengthElement: HTMLInputElement let patternElement: HTMLInputElement let occupancyTypeFieldValuesElement: HTMLTextAreaElement let editCloseModalFunction: () => void function updateMaximumLengthMin(): void { maximumLengthElement.min = minimumLengthElement.value } function toggleInputFields(): void { if (occupancyTypeFieldValuesElement.value === '') { minimumLengthElement.disabled = false maximumLengthElement.disabled = false patternElement.disabled = false } else { minimumLengthElement.disabled = true maximumLengthElement.disabled = true patternElement.disabled = true } } function doUpdate(submitEvent: SubmitEvent): void { submitEvent.preventDefault() cityssm.postJSON( los.urlPrefix + '/admin/doUpdateOccupancyTypeField', submitEvent.currentTarget, (rawResponseJSON) => { const responseJSON = rawResponseJSON as ResponseJSON occupancyTypeResponseHandler(responseJSON) if (responseJSON.success) { editCloseModalFunction() } } ) } function doDelete(): void { cityssm.postJSON( los.urlPrefix + '/admin/doDeleteOccupancyTypeField', { occupancyTypeFieldId }, (rawResponseJSON) => { const responseJSON = rawResponseJSON as ResponseJSON occupancyTypeResponseHandler(responseJSON) if (responseJSON.success) { editCloseModalFunction() } } ) } function confirmDoDelete(): void { 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--occupancyTypeFieldId' ) as HTMLInputElement ).value = occupancyTypeField.occupancyTypeFieldId!.toString() ;( modalElement.querySelector( '#occupancyTypeFieldEdit--occupancyTypeField' ) as HTMLInputElement ).value = occupancyTypeField.occupancyTypeField! ;( modalElement.querySelector( '#occupancyTypeFieldEdit--isRequired' ) as HTMLSelectElement ).value = occupancyTypeField.isRequired ? '1' : '0' minimumLengthElement = modalElement.querySelector( '#occupancyTypeFieldEdit--minimumLength' ) as HTMLInputElement minimumLengthElement.value = occupancyTypeField.minimumLength!.toString() maximumLengthElement = modalElement.querySelector( '#occupancyTypeFieldEdit--maximumLength' ) as HTMLInputElement maximumLengthElement.value = occupancyTypeField.maximumLength!.toString() patternElement = modalElement.querySelector( '#occupancyTypeFieldEdit--pattern' ) as HTMLInputElement patternElement.value = occupancyTypeField.pattern! occupancyTypeFieldValuesElement = modalElement.querySelector( '#occupancyTypeFieldEdit--occupancyTypeFieldValues' ) as HTMLTextAreaElement 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() occupancyTypeFieldValuesElement.addEventListener( 'keyup', toggleInputFields ) modalElement .querySelector('#button--deleteOccupancyTypeField')! .addEventListener('click', confirmDoDelete) }, onremoved: () => { bulmaJS.toggleHtmlClipped() cityssm.disableNavBlocker() } }) } function openEditOccupancyTypeFieldByClick(clickEvent: Event): void { clickEvent.preventDefault() const occupancyTypeFieldId = Number.parseInt( ( (clickEvent.currentTarget as HTMLElement).closest( '.container--occupancyTypeField' ) as HTMLElement ).dataset.occupancyTypeFieldId!, 10 ) const occupancyTypeId = Number.parseInt( ( (clickEvent.currentTarget as HTMLElement).closest( '.container--occupancyType' ) as HTMLElement ).dataset.occupancyTypeId!, 10 ) openEditOccupancyTypeField(occupancyTypeId, occupancyTypeFieldId) } function moveOccupancyTypeField(clickEvent: MouseEvent): void { const buttonElement = clickEvent.currentTarget as HTMLButtonElement const occupancyTypeFieldId = ( (clickEvent.currentTarget as HTMLElement).closest( '.container--occupancyTypeField' ) as HTMLElement ).dataset.occupancyTypeFieldId cityssm.postJSON( los.urlPrefix + '/admin/' + (buttonElement.dataset.direction === 'up' ? 'doMoveOccupancyTypeFieldUp' : 'doMoveOccupancyTypeFieldDown'), { occupancyTypeFieldId, moveToEnd: clickEvent.shiftKey ? '1' : '0' }, occupancyTypeResponseHandler ) } function renderOccupancyTypeFields( panelElement: HTMLElement, occupancyTypeId: number | undefined, occupancyTypeFields: recordTypes.OccupancyTypeField[] ): void { if (occupancyTypeFields.length === 0) { panelElement.insertAdjacentHTML( 'beforeend', '
' + '
' + '

There are no additional fields.

' + '
' + '
' ) } else { for (const occupancyTypeField of occupancyTypeFields) { const panelBlockElement = document.createElement('div') panelBlockElement.className = 'panel-block is-block container--occupancyTypeField' if (occupancyTypeId && !expandedOccupancyTypes.has(occupancyTypeId)) { panelBlockElement.classList.add('is-hidden') } panelBlockElement.dataset.occupancyTypeFieldId = occupancyTypeField.occupancyTypeFieldId!.toString() panelBlockElement.innerHTML = '
' + '' + '
' + ('
' + los.getMoveUpDownButtonFieldHTML( 'button--moveOccupancyTypeFieldUp', 'button--moveOccupancyTypeFieldDown' ) + '
') + '
' + '
' panelBlockElement .querySelector('.button--editOccupancyTypeField')! .addEventListener('click', openEditOccupancyTypeFieldByClick) ;( panelBlockElement.querySelector( '.button--moveOccupancyTypeFieldUp' ) as HTMLButtonElement ).addEventListener('click', moveOccupancyTypeField) ;( panelBlockElement.querySelector( '.button--moveOccupancyTypeFieldDown' ) as HTMLButtonElement ).addEventListener('click', moveOccupancyTypeField) panelElement.append(panelBlockElement) } } } function openAddOccupancyTypePrint(clickEvent: Event): void { const occupancyTypeId = ( (clickEvent.currentTarget as HTMLElement).closest( '.container--occupancyTypePrintList' ) as HTMLElement ).dataset.occupancyTypeId! let closeAddModalFunction: () => void function doAdd(formEvent: SubmitEvent): void { formEvent.preventDefault() cityssm.postJSON( los.urlPrefix + '/admin/doAddOccupancyTypePrint', formEvent.currentTarget, (rawResponseJSON) => { const responseJSON = rawResponseJSON as ResponseJSON if (responseJSON.success) { closeAddModalFunction() } occupancyTypeResponseHandler(responseJSON) } ) } cityssm.openHtmlModal('adminOccupancyTypes-addOccupancyTypePrint', { onshow(modalElement) { los.populateAliases(modalElement) ;( modalElement.querySelector( '#occupancyTypePrintAdd--occupancyTypeId' ) as HTMLInputElement ).value = occupancyTypeId const printSelectElement = modalElement.querySelector( '#occupancyTypePrintAdd--printEJS' ) as HTMLSelectElement for (const [printEJS, printTitle] of Object.entries( exports.occupancyTypePrintTitles )) { const optionElement = document.createElement('option') optionElement.value = printEJS optionElement.textContent = printTitle as string printSelectElement.append(optionElement) } }, onshown(modalElement, closeModalFunction) { closeAddModalFunction = closeModalFunction modalElement.querySelector('form')?.addEventListener('submit', doAdd) } }) } function moveOccupancyTypePrint(clickEvent: MouseEvent): void { const buttonElement = clickEvent.currentTarget as HTMLButtonElement const printEJS = ( buttonElement.closest('.container--occupancyTypePrint') as HTMLElement ).dataset.printEJS const occupancyTypeId = ( buttonElement.closest('.container--occupancyTypePrintList') as HTMLElement ).dataset.occupancyTypeId cityssm.postJSON( los.urlPrefix + '/admin/' + (buttonElement.dataset.direction === 'up' ? 'doMoveOccupancyTypePrintUp' : 'doMoveOccupancyTypePrintDown'), { occupancyTypeId, printEJS, moveToEnd: clickEvent.shiftKey ? '1' : '0' }, occupancyTypeResponseHandler ) } function deleteOccupancyTypePrint(clickEvent: Event): void { clickEvent.preventDefault() const printEJS = ( (clickEvent.currentTarget as HTMLElement).closest( '.container--occupancyTypePrint' ) as HTMLElement ).dataset.printEJS const occupancyTypeId = ( (clickEvent.currentTarget as HTMLElement).closest( '.container--occupancyTypePrintList' ) as HTMLElement ).dataset.occupancyTypeId function doDelete(): void { cityssm.postJSON( los.urlPrefix + '/admin/doDeleteOccupancyTypePrint', { occupancyTypeId, 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 renderOccupancyTypePrints( panelElement: HTMLElement, occupancyTypeId: number, occupancyTypePrints: string[] ): void { if (occupancyTypePrints.length === 0) { panelElement.insertAdjacentHTML( 'beforeend', `

There are no prints associated with this record.

` ) } else { for (const printEJS of occupancyTypePrints) { 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] as string) let printIconClass = 'fa-star' if (printEJS.startsWith('pdf/')) { printIconClass = 'fa-file-pdf' } else if (printEJS.startsWith('screen/')) { printIconClass = 'fa-file' } panelBlockElement.innerHTML = '
' + '
' + ('
' + '' + '
') + ('
' + cityssm.escapeHTML(printTitle || printEJS) + '
') + '
' + '
' + ('
' + los.getMoveUpDownButtonFieldHTML( 'button--moveOccupancyTypePrintUp', 'button--moveOccupancyTypePrintDown' ) + '
') + ('
' + '' + '
' + '
') + '
' + '' ;( panelBlockElement.querySelector( '.button--moveOccupancyTypePrintUp' ) as HTMLButtonElement ).addEventListener('click', moveOccupancyTypePrint) ;( panelBlockElement.querySelector( '.button--moveOccupancyTypePrintDown' ) as HTMLButtonElement ).addEventListener('click', moveOccupancyTypePrint) panelBlockElement .querySelector('.button--deleteOccupancyTypePrint')! .addEventListener('click', deleteOccupancyTypePrint) panelElement.append(panelBlockElement) } } } function renderOccupancyTypes(): void { occupancyTypesContainerElement.innerHTML = '
' + '
' + ('
' + ('
' + '
' + ('

(All ' + los.escapedAliases.Occupancy + ' Types)

') + '
' + '
') + ('
' + ('
' + '' + '
') + '
') + '
') + '
' + '
' occupancyTypePrintsContainerElement.innerHTML = '' renderOccupancyTypeFields( occupancyTypesContainerElement.querySelector( '#container--allOccupancyTypeFields' ) as HTMLElement, undefined, allOccupancyTypeFields ) occupancyTypesContainerElement .querySelector('.button--addOccupancyTypeField')! .addEventListener('click', openAddOccupancyTypeField) if (occupancyTypes.length === 0) { occupancyTypesContainerElement.insertAdjacentHTML( 'afterbegin', `
There are no active ${los.escapedAliases.occupancy} types.

` ) occupancyTypePrintsContainerElement.insertAdjacentHTML( 'afterbegin', `
There are no active ${los.escapedAliases.occupancy} types.

` ) return } for (const occupancyType of occupancyTypes) { // Types and Fields { const occupancyTypeContainer = document.createElement('div') occupancyTypeContainer.className = 'panel container--occupancyType' occupancyTypeContainer.dataset.occupancyTypeId = occupancyType.occupancyTypeId.toString() occupancyTypeContainer.innerHTML = '
' + '
' + ('
' + '
' + '' + '
' + '
' + '

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

' + '
' + '
') + ('
' + ('
' + '' + '
') + ('
' + '' + '
') + ('
' + '' + '
') + ('
' + los.getMoveUpDownButtonFieldHTML( 'button--moveOccupancyTypeUp', 'button--moveOccupancyTypeDown' ) + '
') + '
') + '
' + '
' renderOccupancyTypeFields( occupancyTypeContainer, occupancyType.occupancyTypeId, occupancyType.occupancyTypeFields! ) occupancyTypeContainer .querySelector('.button--toggleOccupancyTypeFields')! .addEventListener('click', toggleOccupancyTypeFields) 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' ) as HTMLButtonElement ).addEventListener('click', moveOccupancyType) ;( occupancyTypeContainer.querySelector( '.button--moveOccupancyTypeDown' ) as HTMLButtonElement ).addEventListener('click', moveOccupancyType) occupancyTypesContainerElement.append(occupancyTypeContainer) } // Prints { const occupancyTypePrintContainer = document.createElement('div') occupancyTypePrintContainer.className = 'panel container--occupancyTypePrintList' occupancyTypePrintContainer.dataset.occupancyTypeId = occupancyType.occupancyTypeId.toString() occupancyTypePrintContainer.innerHTML = '
' + '
' + ('
' + '
' + '

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

' + '
' + '
') + ('
' + ('
' + '' + '
') + '
') + '
' + '
' renderOccupancyTypePrints( occupancyTypePrintContainer, occupancyType.occupancyTypeId, occupancyType.occupancyTypePrints! ) occupancyTypePrintContainer .querySelector('.button--addOccupancyTypePrint')! .addEventListener('click', openAddOccupancyTypePrint) occupancyTypePrintsContainerElement.append(occupancyTypePrintContainer) } } } document .querySelector('#button--addOccupancyType')! .addEventListener('click', () => { let addCloseModalFunction: () => void function doAdd(submitEvent: SubmitEvent): void { submitEvent.preventDefault() cityssm.postJSON( los.urlPrefix + '/admin/doAddOccupancyType', submitEvent.currentTarget, (rawResponseJSON) => { const responseJSON = rawResponseJSON as ResponseJSON 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' ) as HTMLInputElement ).focus() modalElement.querySelector('form')!.addEventListener('submit', doAdd) bulmaJS.toggleHtmlClipped() }, onremoved: () => { bulmaJS.toggleHtmlClipped() } }) }) renderOccupancyTypes() })()