Skip to content
Snippets Groups Projects
Schedules.vue 4.97 KiB
Newer Older
  <section>
    <header class="tw-flex tw-items-center tw-gap-6 tw-mt-12 tw-mb-4">
      <SectionTitle>{{ t('showSchedules.title') }}</SectionTitle>

      <button
        v-if="collapseSchedules"
        type="button"
        class="btn btn-default"
        aria-controls="schedule-collapsable"
        :aria-expanded="!isCollapsed"
        @click="isCollapsed = !isCollapsed"
      >
        {{ t(isCollapsed ? 'showSchedules.showAll' : 'showSchedules.hide') }}
      </button>
    </header>

    <Collapse
      id="schedule-collapsable"
      v-model:is-collapsed="isCollapsed"
      class="tw-mb-12"
      peek="10rem"
    >
      <div class="aura-table-wrapper tw-mb-0">
        <table class="aura-table">
          <thead>
            <tr>
              <th scope="col">
                {{ t('showSchedules.rhythm') }}
              </th>
              <th scope="col">
                {{ t('showSchedules.firstBroadcast') }}
              </th>
              <th scope="col">
                {{ t('showSchedules.lastBroadcast') }}
              </th>
              <th scope="col" class="tw-text-right">
                {{ t('showSchedules.times') }}
              </th>
            </tr>
          </thead>

          <tbody>
            <tr
              v-for="schedule in relevantSchedules"
              :key="schedule.id"
              :aria-label="
                t(
                  schedule.lastDate
                    ? 'showSchedules.scheduleDescriptionFinite'
                    : 'showSchedules.scheduleDescription',
                  {
                    rhythm: renderRruleForSchedule(schedule),
                    startDate: prettyDate(parseISO(schedule.firstDate)),
                    endDate: schedule.lastDate ? prettyDate(parseISO(schedule.lastDate)) : '',
                    startTime: prettyHours(schedule.startTime),
                    endTime: prettyHours(schedule.endTime),
                  },
                )
              "
            >
              <th scope="row">
                {{ renderRruleForSchedule(schedule) }}
              </th>
              <td :colspan="schedule.firstDate === schedule.lastDate ? 2 : 1">
                {{ prettyDate(parseISO(schedule.firstDate)) }}
              </td>
              <td v-if="schedule.firstDate !== schedule.lastDate">
                <template v-if="schedule.lastDate">
                  {{ prettyDate(parseISO(schedule.lastDate)) }}
                </template>
                <template v-else> offen </template>
              </td>
              <td class="tw-text-right">
                {{ prettyHours(schedule.startTime) }} - {{ prettyHours(schedule.endTime) }}
              </td>
            </tr>
            <tr v-if="relevantSchedules.length === 0">
              <td colspan="2">
                <p>{{ t('showSchedules.noSchedulesAvailable') }}</p>
              </td>
            </tr>
          </tbody>
        </table>
      </div>
    </Collapse>
  </section>
<script lang="ts" setup>
import { computed, ref, watch } from 'vue'
import { useStore } from 'vuex'
import { useRRule } from '@/mixins/rrules'
import { usePretty } from '@/mixins/prettyDate'
import { lowercaseFirst, uppercaseFirst, useSelectedShow } from '@/utilities'
import { useI18n } from '@/i18n'
import SectionTitle from '@/components/generic/SectionTitle.vue'
import Collapse from '@/components/generic/Collapse.vue'
import { Schedule } from '@/types'

defineOptions({
  compatConfig: { MODE: 3 },
})

const { t } = useI18n()
const { rruleRender } = useRRule()
const { prettyWeekday, prettyDate, prettyHours } = usePretty()
const store = useStore()
const selectedShow = useSelectedShow()
const schedules = computed<Schedule[]>(() => store.state.shows.schedules)
const relevantSchedules = computed(() => schedules.value.filter((s) => !isPossiblyPastSchedule(s)))
const collapseSchedules = computed(() => relevantSchedules.value.length > 2)
const isCollapsed = ref(!collapseSchedules.value)
function isPossiblyPastSchedule(schedule: Schedule) {
  // Recurrence rules get very complex very fast, so we only give
  // a definitive answer if a lastDate is set for this schedule.
  if (!schedule.lastDate) {
  const lastDate = parseISO(schedule.lastDate)
  const [hours, minutes, seconds] = (schedule.endTime ?? '00:00:00').split(':')
  lastDate.setHours(parseInt(hours ?? '0'), parseInt(minutes ?? '0'), parseInt(seconds ?? '0'))
  return new Date() > lastDate
}

function updateSchedules() {
  if (selectedShow.value) {
    store.dispatch('shows/fetchSchedules', { showId: selectedShow.value.id })
function renderRruleForSchedule(schedule: Schedule) {
  if (schedule.rruleId < 3) {
    return uppercaseFirst(rruleRender(schedule.rruleId))
  const rrule = uppercaseFirst(rruleRender(schedule.rruleId))
  const weekday = lowercaseFirst(prettyWeekday(schedule.byWeekday))
// TODO[#127]: this belongs in the store
watch(selectedShow, updateSchedules, { immediate: true })
</script>