Skip to content
Snippets Groups Projects
ShowSelector.vue 4.69 KiB
Newer Older
  • Learn to ignore specific revisions
  • <template>
      <ComboBox
    
        :model-value="selectedShow"
    
        :label="t('showSelector.selectShow')"
        :no-data-label="hasShows ? t('showSelector.noDataMatch') : t('showSelector.noData')"
    
        :keyboard-shortcut="!isMac ? keys.alt_k : undefined"
    
        :keyboard-shortcut-label="t('showSelector.keyboardShortcut')"
        :choices="filteredShows"
        data-testid="show-selector"
    
        @update:model-value="showStore.selectedShowId = $event.id"
    
        @search="showSearchQuery = $event"
        @close="filterActive = null"
      >
    
        <template #default="{ choice, index, activeIndex, ...attrs }">
    
          <li v-bind="attrs">
            <p class="tw-m-0 tw-font-bold tw-flex tw-items-baseline tw-justify-between">
    
              <SafeHTML :html="(choice as Show).name" sanitize-preset="strip" />
    
              <span class="tw-text-xs tw-opacity-75 tw-flex-none tw-font-normal">
    
                ID: {{ (choice as Show).id }}
    
              </span>
            </p>
            <span
    
              v-if="!(choice as Show).isActive"
    
              class="tw-text-sm tw-rounded-full tw-bg-black/10 tw-text-black/75 tw-px-2 tw-inline-block tw-float-right tw-m-0 tw-ml-1 tw-mb-1"
            >
              {{ t('showSelector.showState.inactive') }}
            </span>
    
            <SafeHTML
              v-show="activeIndex === index"
              as="p"
              class="tw-my-1 tw-text-sm tw-opacity-90"
    
              :html="(choice as Show).shortDescription"
    
            <span class="tw-clear-both" />
          </li>
        </template>
    
    
        <template #selected="{ isOpen }">
          <span
            v-if="!isOpen && selectedShow"
    
            class="tw-absolute tw-pointer-events-none tw-top-8 tw-left-3 tw-truncate"
            style="max-width: calc(100% - 5.5rem)"
    
          >
            <SafeHTML :html="selectedShow.name" sanitize-preset="strip" />
          </span>
    
        <template #filter>
          <div v-if="hasShows">
            <p class="mb-2 tw-text-sm tw-font-bold">{{ t('showSelector.showState.label') }}</p>
    
            <div
              class="tw-flex tw-text-sm tw-border tw-border-solid tw-border-gray-200 tw-w-min tw-rounded"
            >
    
              <SwitchButton
                :model-value="filterActive === true"
                class="tw-whitespace-nowrap"
                :label="t('showSelector.showState.active')"
                @update:model-value="toggleFilterActive(true)"
              />
              <SwitchButton
                :model-value="filterActive === false"
                class="tw-whitespace-nowrap"
                :label="t('showSelector.showState.inactive')"
                @update:model-value="toggleFilterActive(false)"
              />
            </div>
          </div>
    
    
          <div class="tw-block" :class="{ 'tw-mt-auto': hasShows }">
            <AddShowButton test-id="show-selector:add-show" />
          </div>
    
        </template>
      </ComboBox>
    </template>
    
    <script lang="ts" setup>
    import { sort } from 'fast-sort'
    
    import { computed, ref } from 'vue'
    
    import { useMagicKeys } from '@vueuse/core'
    
    import { useI18n } from '@/i18n'
    
    import { sanitizeHTML } from '@/util'
    
    import { useAuthStore, useShowStore } from '@/stores'
    
    import SwitchButton from '@/components/SwitchButton.vue'
    import ComboBox from '@/components/ComboBox.vue'
    import AddShowButton from '@/components/shows/AddShowButton.vue'
    
    import SafeHTML from '@/components/generic/SafeHTML'
    
    import { Show } from '@/types'
    
    defineOptions({ compatConfig: { MODE: 3 } })
    
    
    const keys = useMagicKeys()
    const { t } = useI18n()
    
    const showStore = useShowStore()
    
    const authStore = useAuthStore()
    
    const selectedShow = computed<Show | null>(() => showStore.selectedShow)
    
    const showSearchQuery = ref('')
    const filterActive = ref<null | boolean>(null)
    
    const isMac = navigator.platform.toLowerCase().includes('mac')
    
    const hasShows = computed(() => showStore.items.length > 0)
    
    const sortedShows = computed(() => {
    
      return sort(showStore.items).by([
    
        { desc: (show) => show.isActive },
    
        { asc: (show) => sanitizeHTML(show.name).toLowerCase() },
    
      ])
    })
    const filteredShows = computed(() => {
    
      return (
        sortedShows.value
          .filter((show) => (filterActive.value !== null ? show.isActive === filterActive.value : true))
          // FIXME: Re-implementation of the ?isWritable=1 filter on the show API endpoint.
          //        If we’re keeping the show selector it should be refactored to use the API.
          .filter(
            (show) =>
              authStore.steeringUser?.isPrivileged ||
              (authStore.steeringUser && show.ownerIds.includes(authStore.steeringUser.id)),
          )
          .filter(
            (show) =>
              sanitizeHTML(show.name).toLocaleLowerCase().includes(showSearchQuery.value) ||
              show.id.toString() === showSearchQuery.value,
          )
      )
    
    })
    
    function toggleFilterActive(toggleState: boolean) {
      if (filterActive.value === toggleState) {
        filterActive.value = null
        return
      }
      filterActive.value = toggleState
    }
    </script>