Skip to content
Snippets Groups Projects
TimeSlotRow.vue 3.92 KiB
Newer Older
  • Learn to ignore specific revisions
  • <template>
      <tr :class="rowClass" v-bind="attrs">
        <td>
          <div class="tw-w-12 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>
        </td>
        <td>
          <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>
          {{ time.duration }}
        </td>
        <td>
          <template v-if="playlist">
            <template v-if="playlist.description?.trim()">{{ playlist.description }}</template>
            <template v-else>{{ playlist.id }}</template>
          </template>
          <span v-else class="tw-text-sm tw-text-gray-500">
            {{ t('noneSetFeminine') }}
          </span>
        </td>
        <td>
          <div class="tw-flex tw-gap-2">
            <button
              type="button"
              class="btn btn-sm btn-default"
              :title="t('showTimeslots.editDescription')"
              @click="editNote"
            >
              <icon-system-uicons-pen />
            </button>
            <button
              type="button"
              class="btn btn-sm btn-default"
              :title="t('showTimeslots.editPlaylist')"
              @click="editPlaylist"
            >
              <icon-ph-playlist-light />
            </button>
          </div>
        </td>
      </tr>
    
      <Teleport to="body">
        <PlaylistModal ref="playlistModal" />
        <NoteEditorModal
          v-model="localNoteId"
          :is-open="showNoteEditor"
          :timeslot-id="timeslot.id"
          @show="showNoteEditor = $event"
        />
      </Teleport>
    </template>
    
    <script lang="ts" setup>
    import { computed, ref, useAttrs } from 'vue'
    import { useStore } from 'vuex'
    import { parseISO } from 'date-fns'
    import { useI18n } from '@/i18n'
    import { TimeSlot } from '@/types'
    import { useAPIObject } from '@/api'
    import { Note, useNoteStore } from '@/stores/notes'
    import { useImage } from '@/stores/images'
    import { prettyDuration, usePretty } from '@/mixins/prettyDate'
    import NoteEditorModal from './NoteEditorModal.vue'
    import PlaylistModal from './PlaylistSelector.vue'
    
    const props = defineProps<{
      timeslot: TimeSlot
    }>()
    
    const attrs = useAttrs()
    const { t } = useI18n()
    const { prettyDateTime } = usePretty()
    const store = useStore()
    const noteStore = useNoteStore()
    // TODO: once the timeslot store is migrated to pinia we actually want to trigger
    //       an API update for this timeslot.
    const localNoteId = ref(props.timeslot.note_id)
    const { obj: note, isLoading: isLoadingNote } = useAPIObject<Note>(noteStore, localNoteId)
    const noteImage = useImage(computed(() => note.value?.image ?? null))
    const time = computed(() => prettyDuration(props.timeslot.start, props.timeslot.end))
    const playlist = computed<{ id: number; description: string } | null>(() =>
      props.timeslot.playlist_id
        ? store.getters['playlists/getPlaylistById'](props.timeslot.playlist_id) ?? null
        : null,
    )
    const rowClass = computed(() => {
      const minutesInMs = time.value.minutes * 60 * 1000
      const now = new Date()
      const startDate = parseISO(props.timeslot.start)
      const endDate = new Date(startDate.getTime() + minutesInMs)
    
      return {
        'tw-opacity-50': now > endDate,
      }
    })
    const playlistModal = ref()
    const showNoteEditor = ref(false)
    
    function editNote() {
      showNoteEditor.value = true
    }
    
    function editPlaylist() {
      playlistModal.value.open(props.timeslot.schedule, props.timeslot.id)
    }
    </script>
    
    <script lang="ts">
    export default {
      inheritAttrs: false,
      compatConfig: {
        MODE: 3,
      },
    }
    </script>