sunrise-cms/public-typescript/adminLotTypes.ts

676 lines
20 KiB
TypeScript

/* eslint-disable @typescript-eslint/indent */
/* 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
lotTypes: recordTypes.LotType[]
lotTypeFieldId?: number
}
| {
success: false
errorMessage: string
}
;(() => {
const los = exports.los as globalTypes.LOS
const containerElement = document.querySelector(
'#container--lotTypes'
) as HTMLElement
let lotTypes: recordTypes.LotType[] = exports.lotTypes
delete exports.lotTypes
const expandedLotTypes = new Set<number>()
function toggleLotTypeFields(clickEvent: Event): void {
const toggleButtonElement = clickEvent.currentTarget as HTMLButtonElement
const lotTypeElement = toggleButtonElement.closest(
'.container--lotType'
) as HTMLElement
const lotTypeId = Number.parseInt(lotTypeElement.dataset.lotTypeId!, 10)
if (expandedLotTypes.has(lotTypeId)) {
expandedLotTypes.delete(lotTypeId)
} else {
expandedLotTypes.add(lotTypeId)
}
toggleButtonElement.innerHTML = expandedLotTypes.has(lotTypeId)
? '<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(responseJSON: ResponseJSON): void {
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: Event): void {
const lotTypeId = Number.parseInt(
(
(clickEvent.currentTarget as HTMLElement).closest(
'.container--lotType'
) as HTMLElement
).dataset.lotTypeId!,
10
)
function doDelete(): void {
cityssm.postJSON(
los.urlPrefix + '/admin/doDeleteLotType',
{
lotTypeId
},
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: Event): void {
const lotTypeId = Number.parseInt(
(
(clickEvent.currentTarget as HTMLElement).closest(
'.container--lotType'
) as HTMLElement
).dataset.lotTypeId!,
10
)
const lotType = lotTypes.find((currentLotType) => {
return lotTypeId === currentLotType.lotTypeId
})!
let editCloseModalFunction: () => void
function doEdit(submitEvent: SubmitEvent): void {
submitEvent.preventDefault()
cityssm.postJSON(
los.urlPrefix + '/admin/doUpdateLotType',
submitEvent.currentTarget,
(rawResponseJSON) => {
const responseJSON = rawResponseJSON as ResponseJSON
lotTypeResponseHandler(responseJSON)
if (responseJSON.success) {
editCloseModalFunction()
}
}
)
}
cityssm.openHtmlModal('adminLotTypes-editLotType', {
onshow(modalElement) {
los.populateAliases(modalElement)
;(
modalElement.querySelector(
'#lotTypeEdit--lotTypeId'
) as HTMLInputElement
).value = lotTypeId.toString()
;(
modalElement.querySelector(
'#lotTypeEdit--lotType'
) as HTMLInputElement
).value = lotType.lotType
},
onshown(modalElement, closeModalFunction) {
editCloseModalFunction = closeModalFunction
;(
modalElement.querySelector(
'#lotTypeEdit--lotType'
) as HTMLInputElement
).focus()
modalElement.querySelector('form')!.addEventListener('submit', doEdit)
bulmaJS.toggleHtmlClipped()
},
onremoved() {
bulmaJS.toggleHtmlClipped()
}
})
}
function openAddLotTypeField(clickEvent: Event): void {
const lotTypeId = Number.parseInt(
(
(clickEvent.currentTarget as HTMLElement).closest(
'.container--lotType'
) as HTMLElement
).dataset.lotTypeId!,
10
)
let addCloseModalFunction: () => void
function doAdd(submitEvent: SubmitEvent): void {
submitEvent.preventDefault()
cityssm.postJSON(
los.urlPrefix + '/admin/doAddLotTypeField',
submitEvent.currentTarget,
(rawResponseJSON) => {
const responseJSON = rawResponseJSON as ResponseJSON
expandedLotTypes.add(lotTypeId)
lotTypeResponseHandler(responseJSON)
if (responseJSON.success) {
addCloseModalFunction()
openEditLotTypeField(lotTypeId, responseJSON.lotTypeFieldId!)
}
}
)
}
cityssm.openHtmlModal('adminLotTypes-addLotTypeField', {
onshow(modalElement) {
los.populateAliases(modalElement)
if (lotTypeId) {
;(
modalElement.querySelector(
'#lotTypeFieldAdd--lotTypeId'
) as HTMLInputElement
).value = lotTypeId.toString()
}
},
onshown(modalElement, closeModalFunction) {
addCloseModalFunction = closeModalFunction
;(
modalElement.querySelector(
'#lotTypeFieldAdd--lotTypeField'
) as HTMLInputElement
).focus()
modalElement.querySelector('form')!.addEventListener('submit', doAdd)
bulmaJS.toggleHtmlClipped()
},
onremoved() {
bulmaJS.toggleHtmlClipped()
}
})
}
function moveLotType(clickEvent: MouseEvent): void {
const buttonElement = clickEvent.currentTarget as HTMLButtonElement
const lotTypeId = (
buttonElement.closest('.container--lotType') as HTMLElement
).dataset.lotTypeId
cityssm.postJSON(
los.urlPrefix +
'/admin/' +
(buttonElement.dataset.direction === 'up'
? 'doMoveLotTypeUp'
: 'doMoveLotTypeDown'),
{
lotTypeId,
moveToEnd: clickEvent.shiftKey ? '1' : '0'
},
lotTypeResponseHandler
)
}
function openEditLotTypeField(
lotTypeId: number,
lotTypeFieldId: number
): void {
const lotType = lotTypes.find((currentLotType) => {
return currentLotType.lotTypeId === lotTypeId
})!
const lotTypeField = lotType.lotTypeFields!.find((currentLotTypeField) => {
return currentLotTypeField.lotTypeFieldId === lotTypeFieldId
})!
let minimumLengthElement: HTMLInputElement
let maximumLengthElement: HTMLInputElement
let patternElement: HTMLInputElement
let lotTypeFieldValuesElement: HTMLTextAreaElement
let editCloseModalFunction: () => void
function updateMaximumLengthMin(): void {
maximumLengthElement.min = minimumLengthElement.value
}
function toggleInputFields(): void {
if (lotTypeFieldValuesElement.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/doUpdateLotTypeField',
submitEvent.currentTarget,
(rawResponseJSON) => {
const responseJSON = rawResponseJSON as ResponseJSON
lotTypeResponseHandler(responseJSON)
if (responseJSON.success) {
editCloseModalFunction()
}
}
)
}
function doDelete(): void {
cityssm.postJSON(
los.urlPrefix + '/admin/doDeleteLotTypeField',
{
lotTypeFieldId
},
(rawResponseJSON) => {
const responseJSON = rawResponseJSON as ResponseJSON
lotTypeResponseHandler(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('adminLotTypes-editLotTypeField', {
onshow(modalElement) {
los.populateAliases(modalElement)
;(
modalElement.querySelector(
'#lotTypeFieldEdit--lotTypeFieldId'
) as HTMLInputElement
).value = lotTypeField.lotTypeFieldId.toString()
;(
modalElement.querySelector(
'#lotTypeFieldEdit--lotTypeField'
) as HTMLInputElement
).value = lotTypeField.lotTypeField!
;(
modalElement.querySelector(
'#lotTypeFieldEdit--isRequired'
) as HTMLSelectElement
).value = lotTypeField.isRequired ? '1' : '0'
minimumLengthElement = modalElement.querySelector(
'#lotTypeFieldEdit--minimumLength'
) as HTMLInputElement
minimumLengthElement.value = lotTypeField.minimumLength!.toString()
maximumLengthElement = modalElement.querySelector(
'#lotTypeFieldEdit--maximumLength'
) as HTMLInputElement
maximumLengthElement.value = lotTypeField.maximumLength!.toString()
patternElement = modalElement.querySelector(
'#lotTypeFieldEdit--pattern'
) as HTMLInputElement
patternElement.value = lotTypeField.pattern!
lotTypeFieldValuesElement = modalElement.querySelector(
'#lotTypeFieldEdit--lotTypeFieldValues'
) as HTMLTextAreaElement
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()
lotTypeFieldValuesElement.addEventListener('keyup', toggleInputFields)
modalElement
.querySelector('#button--deleteLotTypeField')!
.addEventListener('click', confirmDoDelete)
},
onremoved() {
bulmaJS.toggleHtmlClipped()
cityssm.disableNavBlocker()
}
})
}
function openEditLotTypeFieldByClick(clickEvent: Event): void {
clickEvent.preventDefault()
const lotTypeFieldId = Number.parseInt(
(
(clickEvent.currentTarget as HTMLElement).closest(
'.container--lotTypeField'
) as HTMLElement
).dataset.lotTypeFieldId!,
10
)
const lotTypeId = Number.parseInt(
(
(clickEvent.currentTarget as HTMLElement).closest(
'.container--lotType'
) as HTMLElement
).dataset.lotTypeId!,
10
)
openEditLotTypeField(lotTypeId, lotTypeFieldId)
}
function moveLotTypeField(clickEvent: MouseEvent): void {
const buttonElement = clickEvent.currentTarget as HTMLButtonElement
const lotTypeFieldId = (
buttonElement.closest('.container--lotTypeField') as HTMLElement
).dataset.lotTypeFieldId
cityssm.postJSON(
los.urlPrefix +
'/admin/' +
(buttonElement.dataset.direction === 'up'
? 'doMoveLotTypeFieldUp'
: 'doMoveLotTypeFieldDown'),
{
lotTypeFieldId,
moveToEnd: clickEvent.shiftKey ? '1' : '0'
},
lotTypeResponseHandler
)
}
function renderLotTypeFields(
panelElement: HTMLElement,
lotTypeId: number,
lotTypeFields: recordTypes.LotTypeField[]
): void {
if (lotTypeFields.length === 0) {
panelElement.insertAdjacentHTML(
'beforeend',
'<div class="panel-block is-block' +
(expandedLotTypes.has(lotTypeId) ? '' : ' is-hidden') +
'">' +
'<div class="message is-info">' +
'<p class="message-body">There are no additional fields.</p>' +
'</div>' +
'</div>'
)
} else {
for (const lotTypeField of lotTypeFields) {
const panelBlockElement = document.createElement('div')
panelBlockElement.className =
'panel-block is-block container--lotTypeField'
if (!expandedLotTypes.has(lotTypeId)) {
panelBlockElement.classList.add('is-hidden')
}
panelBlockElement.dataset.lotTypeFieldId =
lotTypeField.lotTypeFieldId.toString()
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'
) as HTMLButtonElement
).addEventListener('click', moveLotTypeField)
;(
panelBlockElement.querySelector(
'.button--moveLotTypeFieldDown'
) as HTMLButtonElement
).addEventListener('click', moveLotTypeField)
panelElement.append(panelBlockElement)
}
}
}
function renderLotTypes(): void {
containerElement.innerHTML = ''
if (lotTypes.length === 0) {
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.lotTypeId = lotType.lotTypeId.toString()
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--toggleLotTypeFields" data-tooltip="Toggle Fields" type="button" aria-label="Toggle Fields">' +
(expandedLotTypes.has(lotType.lotTypeId)
? '<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--addLotTypeField" 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>'
renderLotTypeFields(
lotTypeContainer,
lotType.lotTypeId,
lotType.lotTypeFields!
)
lotTypeContainer
.querySelector('.button--toggleLotTypeFields')!
.addEventListener('click', toggleLotTypeFields)
lotTypeContainer
.querySelector('.button--deleteLotType')!
.addEventListener('click', deleteLotType)
lotTypeContainer
.querySelector('.button--editLotType')!
.addEventListener('click', openEditLotType)
lotTypeContainer
.querySelector('.button--addLotTypeField')!
.addEventListener('click', openAddLotTypeField)
;(
lotTypeContainer.querySelector(
'.button--moveLotTypeUp'
) as HTMLButtonElement
).addEventListener('click', moveLotType)
;(
lotTypeContainer.querySelector(
'.button--moveLotTypeDown'
) as HTMLButtonElement
).addEventListener('click', moveLotType)
containerElement.append(lotTypeContainer)
}
}
document
.querySelector('#button--addLotType')!
.addEventListener('click', () => {
let addCloseModalFunction: () => void
function doAdd(submitEvent: SubmitEvent): void {
submitEvent.preventDefault()
cityssm.postJSON(
los.urlPrefix + '/admin/doAddLotType',
submitEvent.currentTarget,
(rawResponseJSON) => {
const responseJSON = rawResponseJSON as ResponseJSON
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-addLotType', {
onshow(modalElement) {
los.populateAliases(modalElement)
},
onshown(modalElement, closeModalFunction) {
addCloseModalFunction = closeModalFunction
;(
modalElement.querySelector(
'#lotTypeAdd--lotType'
) as HTMLInputElement
).focus()
modalElement.querySelector('form')!.addEventListener('submit', doAdd)
bulmaJS.toggleHtmlClipped()
},
onremoved() {
bulmaJS.toggleHtmlClipped()
}
})
})
renderLotTypes()
})()