Skip to content
Snippets Groups Projects
TimeSlotList.vue 5.19 KiB
Newer Older
  • Learn to ignore specific revisions
  •   <ASection :title="t('showTimeslots.title')">
        <template #header>
    
          <TimeSlotFilter
            v-model:start-date="formattedLocalStartTime"
    
            v-model:direction="direction"
    
            class="tw-flex tw-gap-3 tw-items-center tw-ml-auto"
          />
    
        <div class="aura-table-wrapper">
          <table ref="tableEl" class="aura-table">
    
            <thead class="tw-sticky tw-top-0 tw-z-10 tw-bg-white">
    
              <tr>
                <th>{{ t('emissionTable.title') }}</th>
                <th>{{ t('emissionTable.start') }}</th>
                <th>{{ t('emissionTable.duration') }}</th>
                <th>{{ t('emissionTable.playlist') }}</th>
    
              <template v-for="timeslot in result.items" :key="timeslot.id">
    
                <TimeSlotRow
                  class="tw-transition hover:tw-bg-gray-50"
                  :timeslot="timeslot"
                  :is-next-up="nextBroadcastedTimeslot?.id === timeslot.id"
                  :is-on-air="onAirTimeslot?.id === timeslot.id"
                />
    
              </template>
              <template v-if="!hasTimeslots">
                <tr>
    
                  <td colspan="4">
    
                    <p class="tw-text-center tw-p-3 tw-m-0">
    
                      {{ t('showTimeslots.noTimeslotsScheduled') }}
                    </p>
                  </td>
                </tr>
              </template>
            </tbody>
          </table>
    
          <div
    
            class="tw-flex tw-flex-wrap tw-gap-3 tw-items-center tw-px-6 tw-mt-3 tw-py-3 tw-border-0 tw-border-t tw-border-solid tw-border-gray-200 empty:tw-hidden"
    
            <PaginationRange v-if="result.count > 0" :pagination-data="result" />
    
            <FormGroup v-slot="attrs" class="tw-ml-auto tw-m-0 last:tw-mr-0">
              <label class="tw-flex tw-items-center tw-gap-3 tw-m-0">
                <span>{{ t('showTimeslots.numberOfSlots') }}</span>
                <input
                  v-model.lazy="limit"
                  v-bind="attrs"
                  type="number"
                  min="1"
                  step="1"
                  class="tw-w-[80px] tw-self-center"
                />
              </label>
            </FormGroup>
            <Pagination v-model="page" :items-per-page="result.itemsPerPage" :count="result.count" />
    
    </template>
    
    <script lang="ts" setup>
    
    import { usePaginatedList } from '@rokoli/bnb/drf'
    import { useNow, useStorage } from '@vueuse/core'
    
    import { formatISO, roundToNearestMinutes } from 'date-fns'
    import { computed, ref, watch, watchEffect } from 'vue'
    
    import { useI18n } from '@/i18n'
    
    import { Show } from '@/types'
    import { useFormattedISODate, useQuery } from '@/util'
    import { useTimeSlotStore } from '@/stores/timeslots'
    
    
    import TimeSlotFilter from './TimeSlotFilter.vue'
    import TimeSlotRow from '@/components/shows/TimeSlotRow.vue'
    import Pagination from '@/components/generic/Pagination.vue'
    import PaginationRange from '@/components/generic/PaginationRange.vue'
    
    import ASection from '@/components/generic/ASection.vue'
    
    import FormGroup from '@/components/generic/FormGroup.vue'
    
    const DEFAULT_TIMESLOT_LIMIT = parseInt(
    
      import.meta.env.VUE_APP_TIMESLOT_FILTER_DEFAULT_NUMSLOTS ?? 5,
    
    defineOptions({
      compatConfig: { MODE: 3 },
      ATTR_FALSE_VALUE: false,
    })
    
    
    const { t } = useI18n()
    
    const now = useNow({ interval: 60_000 })
    
    const page = ref(1)
    
    const direction = ref<'future' | 'past'>('future')
    
    const limit = useStorage('aura:timeslotList:timeslotsPerPage', DEFAULT_TIMESLOT_LIMIT)
    const startTime = ref(roundToNearestMinutes(new Date()))
    const formattedStartTime = useFormattedISODate(startTime)
    const formattedLocalStartTime = useFormattedISODate(startTime, now, { stripOffset: true })
    
    const tableEl = ref<HTMLTableElement>()
    const hasPageBeenModified = ref(false)
    
    const { result } = usePaginatedList(timeslotStore.listIsolated, page, limit, {
      events: timeslotStore.events,
    
      query: useQuery(() => ({
        showIds: props.show.id,
    
        endsAfter: direction.value === 'future' ? formattedStartTime.value : undefined,
        endsBefore: direction.value === 'past' ? formattedStartTime.value : undefined,
        order: direction.value === 'future' ? 'start' : '-start',
    
    })
    const hasTimeslots = computed(() => result.value.count > 0)
    
    const onAirTimeslot = computed(() => {
      const _now = formatISO(now.value)
      return result.value.items.find((t) => t.start <= _now && _now < t.end) ?? null
    })
    
    const currentResultTime = ref(new Date())
    const { result: currentResult } = usePaginatedList(timeslotStore.listIsolated, 1, 1, {
      events: timeslotStore.events,
      query: useQuery(() => ({
        showIds: props.show.id,
        startsAfter: formatISO(currentResultTime.value),
        order: 'start',
      })),
    })
    const nextBroadcastedTimeslot = computed(() => currentResult.value.items[0] ?? null)
    watch([onAirTimeslot, useNow({ interval: 15 * 60_000 })], () => {
      // reload from usePaginatedList doesn’t cut it, because we actually need to change the query
      currentResultTime.value = new Date()
    })
    
    
    watchEffect(() => {
      if (page.value !== 1) {
        hasPageBeenModified.value = true
      }
      if (hasPageBeenModified.value && tableEl.value) {
        tableEl.value.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'start' })
      }
    })
    </script>