Skip to content
Snippets Groups Projects
ModalEdit.vue 13.4 KiB
Newer Older
  • Learn to ignore specific revisions
  • Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
      <div>
        <b-modal
          ref="modalEmissionManagerEdit"
          :title="$t('scheduleEditor.titleEdit', { show: selectedShow.name })"
          size="lg"
        >
          <server-errors :errors="serverErrors" />
    
          <div v-if="timeslot && loaded.schedule">
            <p
              class="tw-mb-0"
              v-html="
                $t('scheduleEditor.timeslotRuns', {
                  firstDate: prettyDate(timeslot.start),
                  startTime: prettyTime(timeslot.start),
                  endTime: prettyTime(timeslot.end),
                })
              "
            />
    
            <div v-if="schedule.rrule === 1">
              <p>
                {{ $t('scheduleEditor.singleEmission') }}
                <span v-if="!loaded.scheduleTimeslots">
                  <br />
                  <img src="/assets/radio.gif" :alt="$t('loading')" />
                </span>
                <span v-else>
                  <span
                    v-if="scheduleTimeslots.length > 1"
                    v-html="
                      '<br>' +
                      $t('scheduleEditor.coexistingTimeslot', {
                        firstDate:
                          timeslot.start === scheduleTimeslots[0].start
                            ? prettyDate(scheduleTimeslots[1].start)
                            : prettyDate(scheduleTimeslots[0].start),
                        startTime:
                          timeslot.start === scheduleTimeslots[0].start
                            ? prettyTime(scheduleTimeslots[1].start)
                            : prettyTime(scheduleTimeslots[0].start),
                        endTime:
                          timeslot.start === scheduleTimeslots[0].start
                            ? prettyTime(scheduleTimeslots[1].end)
                            : prettyTime(scheduleTimeslots[0].end),
                      })
                    "
                  />
                </span>
              </p>
            </div>
            <div v-else>
              <p
                v-html="
                  $t('scheduleEditor.recurringSchedule', {
                    rrule: rruleRender(schedule.rrule),
                    lastDate: prettyDate(schedule.last_date),
                  })
                "
              />
    
              <b-table
                id="emission-table"
                striped
                :per-page="perPage"
                :current-page="currentPage"
                :fields="[
                  { key: 'start', label: $t('scheduleEditor.start') },
                  { key: 'end', label: $t('scheduleEditor.end') },
                ]"
                :items="scheduleTimeslots"
                :busy="!loaded.scheduleTimeslots"
                :tbody-tr-class="trClass"
              >
                <template #cell(start)="data">
                  {{ prettyDateTime(data.item.start) }}
    
                </template>
    
    Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
    
                <template #cell(end)="data">
                  {{ prettyDateTime(data.item.end) }}
                </template>
              </b-table>
    
              <div class="tw-w-full tw-flex tw-justify-end">
                <b-pagination
                  v-model="currentPage"
                  :total-rows="scheduleTimeslots.length"
                  :per-page="perPage"
                  aria-controls="emission-table"
                />
              </div>
            </div>
          </div>
          <div v-else>
            <img src="/assets/radio.gif" :alt="$t('loading')" />
          </div>
    
          <hr />
    
          <h4>{{ $t('scheduleEditor.addRepetition') }}</h4>
          <b-row>
            <b-col cols="6">
              <label class="tw-leading-loose">
                {{ $t('scheduleEditor.whenToRepeat') }}
    
                <b-form-select v-model="repetitionRule" :options="repetitionOptions" />
              </label>
    
              <b-checkbox v-if="repetitionRule !== 4" v-model="useSameTime">
                {{ $t('scheduleEditor.useSameTime') }}
              </b-checkbox>
            </b-col>
            <b-col v-if="!useSameTime" cols="6">
              <label class="tw-leading-loose">
                {{ $t('scheduleEditor.repeatAt') }}
                <b-form-input v-model="repetitionTime" type="time" />
              </label>
            </b-col>
          </b-row>
    
          <b-row v-if="repetitionRule === 3" class="tw-mt-4">
            <b-col cols="6">
              <label class="tw-leading-loose">
                {{ $t('scheduleEditor.addNoOfDays') }}
    
                <b-form-input v-model="addNoOfDays" type="number" />
              </label>
    
              <b-checkbox v-model="onlyBusinessDays">
                {{ $t('scheduleEditor.onlyBusinessDays') }}
              </b-checkbox>
            </b-col>
          </b-row>
    
          <b-row class="my-4">
            <b-col>
              <b-button variant="primary" size="sm" @click="createRepetitionSchedule">
                {{ $t('scheduleEditor.addRepetition') }}
              </b-button>
            </b-col>
          </b-row>
    
          <hr />
          <h4>Fallback für Ausstrahlungs-Schema hinzufügen</h4>
          <b-row class="tw-px-4">
            <p><strong>Momentan hinterlegte Playlist:</strong> (keine)</p>
    
            <div class="tw-w-full tw-block">
              <b-button variant="primary">
                {{ $t('scheduleEditor.assignPlaylist') }}
              </b-button>
            </div>
          </b-row>
    
          <template #modal-footer>
            <div
              v-if="loaded.scheduleTimeslots"
              class="tw-w-full tw-flex tw-justify-between tw-items-center"
    
    Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
              <div class="tw-space-x-2">
                <template v-if="isInTheFuture(timeslot)">
                  <b-button variant="danger" size="sm" @click="deleteFullSchedule(schedule.id)">
                    <span v-if="scheduleTimeslots.length === 1">{{
                      $t('scheduleEditor.delete.delete')
                    }}</span>
                    <span v-else-if="schedule.rrule === 1">{{ $t('scheduleEditor.delete.both') }}</span>
                    <span v-else>{{ $t('scheduleEditor.delete.scheduleTimeslots') }}</span>
                  </b-button>
    
                  <b-button
                    v-if="schedule.rrule > 1 && scheduleTimeslots.length > 1"
                    variant="danger"
                    size="sm"
                    @click="deleteSingleTimeslot(schedule.id, timeslot.id)"
                  >
                    {{ $t('scheduleEditor.delete.timeslot') }}
                  </b-button>
                </template>
    
                <b-button
                  v-if="schedule.rrule > 1 && scheduleTimeslots.length > 1"
                  variant="danger"
                  size="sm"
                  @click="deleteAllFutureTimeslots(schedule.id, timeslot.id)"
                >
                  {{ $t('scheduleEditor.delete.allTimeslots') }}
                </b-button>
              </div>
            </div>
            <div v-else>
              <img src="/assets/radio.gif" :alt="$t('loading')" />
            </div>
          </template>
        </b-modal>
    
        <b-modal
          ref="modalEmissionManagerDeleteTimeslots"
          :title="$t('scheduleEditor.delete.timeslotsTitle')"
          size="lg"
          centered
          hide-footer
          no-close-on-esc
          no-close-on-backdrop
        >
          <div>
            <img src="/assets/radio.gif" :alt="$t('loading')" />
            <b-progress :value="deletion.count" :max="deletion.amount" variant="primary" animated />
          </div>
        </b-modal>
      </div>
    
    Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
    import { mapGetters } from 'vuex'
    import prettyDate from '../../mixins/prettyDate'
    import rrules from '../../mixins/rrules'
    import ServerErrors from '@/components/ServerErrors.vue'
    
    export default {
      components: { ServerErrors },
      mixins: [prettyDate, rrules],
    
      emits: ['conflict'],
    
    Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
    
      data() {
        return {
          currentPage: 1,
          perPage: 5,
          timeslot: null,
          deletion: {
            amount: 0,
            count: 0,
          },
          useSameTime: true,
          onlyBusinessDays: false,
          addNoOfDays: 1,
          repetitionRule: 1,
          repetitionTime: '',
          serverErrors: [],
        }
      },
    
      computed: {
        loaded() {
          return {
            shows: this.$store.state.shows.loaded.shows,
            schedule: this.$store.state.shows.loaded.schedule,
            scheduleTimeslots: this.$store.state.shows.loaded.scheduleTimeslots,
          }
        },
    
        repetitionOptions() {
          return [
            { value: 1, text: this.$t('scheduleEditor.repetition.followingDay') },
            { value: 2, text: this.$t('scheduleEditor.repetition.followingBusinessDay') },
            { value: 3, text: this.$t('scheduleEditor.repetition.numberOfDaysLater') },
          ]
        },
    
        ...mapGetters({
          selectedShow: 'shows/selectedShow',
          schedule: 'shows/schedule',
          scheduleTimeslots: 'shows/scheduleTimeslots',
        }),
      },
    
      methods: {
        trClass(item, type) {
          if (!item || type !== 'row') {
            return ''
          }
    
          return item.id === this.timeslot.id ? 'table-info' : ''
        },
    
        isInTheFuture(timeslot) {
          const start = new Date(timeslot.start)
          const now = new Date()
    
          return start > now
        },
    
        async createRepetitionSchedule() {
          const { onlyBusinessDays, addNoOfDays } = this.getRepetitionParameters()
          let {
            first_date,
            time_start,
            time_end,
            rrule,
            last_date,
            default_playlist_id,
            automation_id,
            by_weekday,
          } = this.schedule
    
          if (this.repetitionTime.length > 0) {
            const newStartTime = `${this.repetitionTime}:00`
            const newStartTimeNs = this.hmsToNanoseconds(newStartTime)
            const oldStartTimeNs = this.hmsToNanoseconds(time_start)
            const oldEndTimeNs = this.hmsToNanoseconds(time_end)
    
            time_start = newStartTime
            time_end = this.prettyNanoseconds(newStartTimeNs + (oldEndTimeNs - oldStartTimeNs))
          }
    
          const newSchedule = {
            schedule: {
              first_date,
              time_start,
              time_end,
              rrule,
              last_date,
              default_playlist_id,
              automation_id,
              by_weekday,
              is_repetition: true,
              add_business_days_only: onlyBusinessDays,
              add_days_no: parseInt(addNoOfDays, 10),
    
    Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
          }
    
          this.serverErrors = []
          try {
            await this.$store.dispatch('shows/submitSchedule', {
              showId: this.selectedShow.id,
              schedule: newSchedule,
            })
          } catch (e) {
            if (e.response?.status === 409) {
              this.$log.debug('Timeslot conflict. Switching to resolve mode.')
    
              this.$emit('conflict', e.response.data)
    
    Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
            } else {
              this.serverErrors = e.errors ?? []
            }
          } finally {
            this.$refs.modalEmissionManagerEdit.hide()
          }
        },
    
        deleteFullSchedule(id) {
          this.$store.dispatch('shows/deleteSchedule', {
            show: this.selectedShow.id,
            schedule: id,
            callback: () => {
              this.$refs.modalEmissionManagerEdit.hide()
    
    Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
          })
        },
    
        deleteSingleTimeslot(scheduleId, timeslotId) {
          this.$store.dispatch('shows/deleteTimeslot', {
            show: this.selectedShow.id,
            schedule: scheduleId,
            timeslot: timeslotId,
            callback: () => {
              this.$refs.modalEmissionManagerEdit.hide()
            },
          })
        },
    
        deleteAllFutureTimeslots(scheduleId) {
          let startDate = new Date(this.timeslot.start)
          let toDelete = []
          for (let slot of this.scheduleTimeslots) {
            if (new Date(slot.start) >= startDate) {
              toDelete.push(slot.id)
            }
          }
    
          if (toDelete.length === this.scheduleTimeslots.length) {
            this.$log.debug('deleting full schedule')
            this.deleteFullSchedule(scheduleId)
          } else {
            this.deletion.amount = toDelete.length
            this.deletion.count = 0
            this.$refs.modalEmissionManagerDeleteTimeslots.show()
    
            for (let i in toDelete) {
              this.$log.debug('Deleting timeslot', toDelete[i])
              this.$store.dispatch('shows/deleteTimeslot', {
                show: this.selectedShow.id,
                schedule: scheduleId,
                timeslot: toDelete[i],
                callback: () => {
                  this.deletion.count++
                  this.$log.debug('deleted ' + this.deletion.count + ' timeslots')
                  if (this.deletion.count === this.deletion.amount) {
                    this.$refs.modalEmissionManagerDeleteTimeslots.hide()
                    this.$refs.modalEmissionManagerEdit.hide()
                  }
    
    Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
              })
            }
          }
        },
    
        loadSchedule(scheduleId) {
          this.$store.dispatch('shows/fetchSchedule', {
            show: this.selectedShow.id,
            schedule: scheduleId,
            callback: () => {
              this.loadScheduleTimeslots(scheduleId)
            },
          })
        },
    
        loadScheduleTimeslots(scheduleId) {
          this.$store.dispatch('shows/fetchTimeslots', {
            id: this.selectedShow.id,
            schedule: scheduleId,
            start: this.schedule.first_date,
            end: this.schedule.last_date,
          })
        },
    
        getRepetitionParameters() {
          if (this.repetitionRule == 1) {
            return {
              onlyBusinessDays: false,
              addNoOfDays: 1,
            }
          }
    
    Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
          if (this.repetitionRule == 2) {
            return {
              onlyBusinessDays: true,
              addNoOfDays: 1,
    
    Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
          }
    
          return {
            onlyBusinessDays: this.onlyBusinessDays,
            addNoOfDays: this.addNoOfDays,
          }
        },
    
        // initialise a new schedule and open the modal
        open(timeslot) {
          const timeslotIndex = this.scheduleTimeslots.findIndex((item) => item.id === timeslot.id)
          let timeslotPage = Math.ceil(timeslotIndex / this.perPage)
          const timeslotIsFirstEntryOnPage = timeslotIndex === timeslotPage * this.perPage
    
          // The math above is slightly off for every first entry on the page
          // So we add 1 to adjust the page to the correct one
          if (timeslotIsFirstEntryOnPage) {
            timeslotPage += 1
          }
    
          this.timeslot = timeslot
          this.currentPage = timeslotPage
          this.$refs.modalEmissionManagerEdit.show()
          this.loadSchedule(timeslot.schedule)
        },
      },
    }