cityssm/attendance-tracking

View on GitHub
public-typescript/attendance.callOuts.ts

Summary

Maintainability
A
1 hr
Test Coverage
// eslint-disable-next-line eslint-comments/disable-enable-pair
/* eslint-disable unicorn/prefer-module */

// eslint-disable-next-line n/no-missing-import
import type { BulmaJS } from '@cityssm/bulma-js/types.js'
import type { cityssmGlobal } from '@cityssm/bulma-webapp-js/src/types.js'

import type { DoCreateCallOutListResponse } from '../handlers/attendance-post/doCreateCallOutList.js'
import type { DoToggleFavouriteCallOutListResponse } from '../handlers/attendance-post/doToggleFavouriteCallOutList.js'
import type {
  AttendCallOuts as AttendCallOutsGlobal,
  Attend as AttendGlobal
} from '../types/globalTypes.js'

declare const bulmaJS: BulmaJS

declare const cityssm: cityssmGlobal
;(() => {
  const Attend = exports.Attend as AttendGlobal
  const AttendCallOuts = Attend.callOuts as AttendCallOutsGlobal

  const searchFilterElement = document.querySelector(
    '#callOuts--searchFilter'
  ) as HTMLInputElement

  const searchResultsElement = document.querySelector(
    '#callOuts--searchResults'
  ) as HTMLElement

  function toggleCallOutListFavourite(clickEvent: Event): void {
    const buttonElement = clickEvent.currentTarget as HTMLButtonElement

    const oldIsFavourite = buttonElement.dataset.isFavourite === '1'

    const panelBlockElement = buttonElement.closest(
      '.panel-block'
    ) as HTMLElement

    const listId = panelBlockElement.dataset.listId

    cityssm.postJSON(
      `${Attend.urlPrefix}/attendance/${
        oldIsFavourite
          ? 'doRemoveFavouriteCallOutList'
          : 'doAddFavouriteCallOutList'
      }`,
      { listId },
      (rawResponseJSON) => {
        const responseJSON =
          rawResponseJSON as unknown as DoToggleFavouriteCallOutListResponse

        if (responseJSON.success) {
          AttendCallOuts.callOutLists = responseJSON.callOutLists

          renderCallOutLists()
        } else {
          bulmaJS.alert({
            title: 'Error Updating Favourites',
            message: 'Please try again.'
          })
        }
      }
    )
  }

  function renderCallOutLists(): void {
    const panelElement = document.createElement('div')
    panelElement.className = 'panel'

    const searchFilterPieces = searchFilterElement.value
      .trim()
      .toLowerCase()
      .split(' ')

    // eslint-disable-next-line no-labels
    callOutListLoop: for (const callOutList of AttendCallOuts.callOutLists) {
      const listStringToSearch = `${callOutList.listName} ${
        callOutList.listDescription ?? ''
      }`.toLowerCase()

      for (const searchFilterPiece of searchFilterPieces) {
        if (!listStringToSearch.includes(searchFilterPiece)) {
          // eslint-disable-next-line no-labels
          continue callOutListLoop
        }
      }

      const panelBlockElement = document.createElement('div')

      panelBlockElement.className = 'panel-block is-block'
      panelBlockElement.dataset.listId = callOutList.listId.toString()

      // eslint-disable-next-line unicorn/prefer-string-replace-all
      const listDescriptionHTML = (callOutList.listDescription ?? '').replace(
        /\n/g,
        '<br />'
      )

      panelBlockElement.innerHTML = `<div class="columns is-mobile is-variable is-1">
        <div class="column is-narrow">
          <button class="button is-white" data-is-favourite="${
            (callOutList.isFavourite as boolean) ? '1' : '0'
          }" data-tooltip="Toggle Favourite" type="button" aria-label="Toggle Favourite">
            ${
              (callOutList.isFavourite as boolean)
                ? '<i class="fas fa-star" aria-hidden="true"></i><span class="is-sr-only">Favourite</span>'
                : '<i class="far fa-star" aria-hidden="true"></i><span class="is-sr-only">Not Favourite</span>'
            }
          </button>
        </div>
        <div class="column">
          <a class="is-block" href="#">
          <strong>${callOutList.listName}</strong><br />
            <span class="is-size-7">${listDescriptionHTML}</span>
          </a>
        </div>
        <div class="column is-narrow">
        ${
          callOutList.allowSelfSignUp ?? false
            ? `<span class="tag is-light is-info">
              <span class="icon is-small"><i class="fas fa-hand-paper" aria-hidden="true"></i></span>
              <span>Self Sign Up</span>
              </span>`
            : ''
        } 
          <span class="tag" data-tooltip="Members">
            <span class="icon is-small"><i class="fas fa-hard-hat" aria-hidden="true"></i></span>
            <span>${callOutList.callOutListMembersCount ?? ''}</span>
          </span>
        </div>
        <div class="column is-narrow">
          <a class="button is-small" data-tooltip="Print List" href="${Attend.urlPrefix}/print/screen/callOutList/?listIds=${callOutList.listId}" target="_blank">
            <i class="fas fa-print" aria-hidden="true"></i>
            <span class="is-sr-only">Self Sign Up</span>
          </a>
        </div>
        </div>`

      panelBlockElement
        .querySelector('button')
        ?.addEventListener('click', toggleCallOutListFavourite)

      const listAnchorElement = panelBlockElement.querySelector(
        'a'
      ) as HTMLAnchorElement

      listAnchorElement.dataset.cy = callOutList.listName
      listAnchorElement.addEventListener('click', openCallOutListByClick)

      panelElement.append(panelBlockElement)
    }

    if (panelElement.hasChildNodes()) {
      searchResultsElement.innerHTML = ''
      searchResultsElement.append(panelElement)
    } else {
      searchResultsElement.innerHTML = `<div class="message is-info">
        <p class="message-body">There are no call out lists that meet your search criteria.</p>
        </div>`
    }
  }

  function openCallOutListByClick(clickEvent: MouseEvent): void {
    clickEvent.preventDefault()

    const listId = (
      (clickEvent.currentTarget as HTMLAnchorElement).closest(
        '.panel-block'
      ) as HTMLElement
    ).dataset.listId as string

    AttendCallOuts.openCallOutList(listId, renderCallOutLists)
  }

  document.querySelector('#callOuts--create')?.addEventListener('click', () => {
    let createCloseModalFunction: () => void

    function doCreate(formEvent: Event): void {
      formEvent.preventDefault()

      cityssm.postJSON(
        `${Attend.urlPrefix}/attendance/doCreateCallOutList`,
        formEvent.currentTarget,
        (rawResponseJSON) => {
          const responseJSON =
            rawResponseJSON as unknown as DoCreateCallOutListResponse

          AttendCallOuts.callOutLists = responseJSON.callOutLists
          renderCallOutLists()

          AttendCallOuts.openCallOutList(responseJSON.listId)

          createCloseModalFunction()
        }
      )
    }

    cityssm.openHtmlModal('callOuts-createList', {
      onshown(modalElement, closeModalFunction) {
        createCloseModalFunction = closeModalFunction
        bulmaJS.toggleHtmlClipped()
        ;(
          modalElement.querySelector(
            '#callOutListAdd--listName'
          ) as HTMLInputElement
        ).focus()

        modalElement
          .querySelector('#form--callOutListAdd')
          ?.addEventListener('submit', doCreate)
      },
      onremoved() {
        bulmaJS.toggleHtmlClipped()
      }
    })
  })

  // Load Page

  renderCallOutLists()

  searchFilterElement.addEventListener('keyup', renderCallOutLists)
})()