Skip to content
Snippets Groups Projects
TimeSlotRow.vue 3.9 KiB
Newer Older
  • Learn to ignore specific revisions
  • <template>
      <tr :class="rowClass" v-bind="attrs">
        <td>
    
          <router-link
            :to="{
              name: 'show-episode',
              params: { showId: timeslot.showId, episodeId: timeslot.id },
            }"
            class="tw-text-inherit tw-flex tw-gap-3 tw-items-center hocus:tw-underline hocus:tw-outline-none"
            :title="t('showTimeslots.editDescription')"
          >
            <div
              class="tw-w-12 tw-flex-none tw-aspect-square rounded-lg tw-bg-gray-400 tw-overflow-hidden"
            >
              <img
                v-if="noteImage"
                class="tw-object-cover tw-h-full tw-w-full tw-max-w-full tw-max-h-full"
                :src="noteImage.image"
                sizes="100px"
                :srcset="
                  noteImage.thumbnails
                    .filter(({ width, height }) => width === height)
                    .map(({ width, url }) => `${url} ${width}w`)
                    .join(',')
                "
                alt=""
              />
            </div>
            <span class="tw-truncate tw-max-w-[200px]">
              <template v-if="!isLoadingNote">
                <template v-if="note">
                  {{ note.title }}
                </template>
                <span v-else class="tw-text-sm tw-text-gray-500">
                  {{ t('noneSetMasculine') }}
                </span>
              </template>
    
        </td>
        <td>
          {{ prettyDateTime(timeslot.start) }}
        </td>
        <td>
    
          {{ secondsToDurationString(duration) }}
    
          <AStatus
            class="tw-text-xs"
            rounded
            :is-warning="playlistState.state !== 'ok'"
            :is-success="playlistState.state === 'ok'"
          >
            {{ t(`playlist.state.${playlistState.state}.title`) }}
          </AStatus>
    
        <td class="tw-relative tw-p-0" :class="{ 'tw-w-6': isOnAir || isNextUp }">
          <div
            v-if="isNextUp || isOnAir"
            class="tw-absolute tw-right-0 tw-inset-y-0 tw-w-6 tw-leading-0 tw-px-[2px] tw-select-none tw-text-white tw-flex tw-items-center tw-text-sm tw-font-bold tw-whitespace-nowrap tw-pointer-events-none"
            :class="{ 'tw-bg-green-400': isNextUp, 'tw-bg-indigo-400': isOnAir }"
          >
            <span style="writing-mode: vertical-lr">
              <template v-if="isOnAir">On Air</template>
              <template v-else-if="isNextUp">Next Up</template>
            </span>
          </div>
        </td>
    
      </tr>
    </template>
    
    <script lang="ts" setup>
    
    import { useObjectFromStore } from '@rokoli/bnb/drf'
    import { parseISO } from 'date-fns'
    
    import { computed, useAttrs } from 'vue'
    
    import { useI18n } from '@/i18n'
    import { TimeSlot } from '@/types'
    
    import { useNoteStore } from '@/stores/notes'
    
    import { useImage } from '@/stores/images'
    
    import { usePretty } from '@/mixins/prettyDate'
    import { calculateDurationSeconds, secondsToDurationString } from '@/util'
    
    import { usePlaylistStore } from '@/stores'
    import { usePlaylistState } from '@/stores/playlists'
    import AStatus from '@/components/generic/AStatus.vue'
    
    defineOptions({
      compatConfig: { MODE: 3 },
      inheritAttrs: false,
      ATTR_FALSE_VALUE: false,
    })
    
    
    const props = defineProps<{
      timeslot: TimeSlot
    
      isNextUp?: boolean
      isOnAir?: boolean
    
    }>()
    
    const attrs = useAttrs()
    const { t } = useI18n()
    const { prettyDateTime } = usePretty()
    
    const playlistStore = usePlaylistStore()
    
    const noteStore = useNoteStore()
    
    const { obj: note, isLoading: isLoadingNote } = useObjectFromStore(
      () => props.timeslot.noteId,
      noteStore,
    )
    
    const noteImage = useImage(computed(() => note.value?.imageId ?? null))
    
    const duration = computed(() => calculateDurationSeconds(props.timeslot.start, props.timeslot.end))
    
    const { obj: playlist } = useObjectFromStore(() => props.timeslot.playlistId, playlistStore)
    const playlistState = usePlaylistState(playlist, duration)
    
    const rowClass = computed(() => {
      const now = new Date()
      const startDate = parseISO(props.timeslot.start)
    
      const endDate = new Date(startDate.getTime() + duration.value * 1000)
    
      return { 'tw-opacity-50': now > endDate }