// eslint-disable-next-line @eslint-community/eslint-comments/disable-enable-pair /* eslint-disable unicorn/prefer-module */ 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 { LotType, LotTypeField } from '../types/recordTypes.js' declare const cityssm: cityssmGlobal declare const bulmaJS: BulmaJS declare const exports: Record type ResponseJSON = | { success: true lotTypes: LotType[] lotTypeFieldId?: number } | { success: false errorMessage: string } ;(() => { const los = exports.los as LOS const containerElement = document.querySelector( '#container--lotTypes' ) as HTMLElement let lotTypes = exports.lotTypes as LotType[] delete exports.lotTypes const expandedLotTypes = new Set() 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) } // eslint-disable-next-line no-unsanitized/property toggleButtonElement.innerHTML = expandedLotTypes.has(lotTypeId) ? '' : '' const panelBlockElements = lotTypeElement.querySelectorAll('.panel-block') as NodeListOf for (const panelBlockElement of panelBlockElements) { panelBlockElement.classList.toggle('is-hidden') } } function lotTypeResponseHandler(rawResponseJSON: unknown): void { const responseJSON = rawResponseJSON as ResponseJSON 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 }) as LotType 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 as number ) } } ) } 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 }) as LotType const lotTypeField = (lotType.lotTypeFields ?? []).find( (currentLotTypeField) => { return currentLotTypeField.lotTypeFieldId === lotTypeFieldId } ) as LotTypeField 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: LotTypeField[] ): void { if (lotTypeFields.length === 0) { // eslint-disable-next-line no-unsanitized/method panelElement.insertAdjacentHTML( 'beforeend', `

There are no additional fields.

` ) } 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() // eslint-disable-next-line no-unsanitized/property panelBlockElement.innerHTML = `
${los.getMoveUpDownButtonFieldHTML( 'button--moveLotTypeFieldUp', 'button--moveLotTypeFieldDown' )}
` panelBlockElement .querySelector('.button--editLotTypeField') ?.addEventListener('click', openEditLotTypeFieldByClick) ;( panelBlockElement.querySelector( '.button--moveLotTypeFieldUp' ) 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) { // eslint-disable-next-line no-unsanitized/method containerElement.insertAdjacentHTML( 'afterbegin', `
There are no active ${los.escapedAliases.lot} types.

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

${cityssm.escapeHTML(lotType.lotType)}

${los.getMoveUpDownButtonFieldHTML( 'button--moveLotTypeUp', 'button--moveLotTypeDown' )}
` 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() })()