Skip to content
Snippets Groups Projects
ModalEdit.vue 13.6 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: sanitizeHTML(selectedShow.name) })"
    
    Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
          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.rruleId === 1">
    
    Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
              <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.rruleId),
                    lastDate: prettyDate(schedule.lastDate),
    
    Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
                  })
                "
              />
    
              <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>{{ $t('scheduleEditor.addFallbackTitle') }}</h4>
    
    Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
          <b-row class="tw-px-4">
    
            <p>
              <strong>{{ $t('scheduleEditor.currentlySelectedPlaylist') }}:</strong>
              {{ $t('noneSetFeminine') }}
            </p>
    
    Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
    
            <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.rruleId === 1">{{
                      $t('scheduleEditor.delete.both')
                    }}</span>
    
    Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
                    <span v-else>{{ $t('scheduleEditor.delete.scheduleTimeslots') }}</span>
                  </b-button>
    
                  <b-button
    
                    v-if="schedule.rruleId > 1 && scheduleTimeslots.length > 1"
    
    Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
                    variant="danger"
                    size="sm"
                    @click="deleteSingleTimeslot(schedule.id, timeslot.id)"
                  >
                    {{ $t('scheduleEditor.delete.timeslot') }}
                  </b-button>
                </template>
    
                <b-button
    
                  v-if="schedule.rruleId > 1 && scheduleTimeslots.length > 1"
    
    Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
                  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, { formatSeconds, hmsToSeconds } from '../../mixins/prettyDate'
    
    Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
    import rrules from '../../mixins/rrules'
    import ServerErrors from '@/components/ServerErrors.vue'
    
    import { sanitizeHTML, secondsToDurationString } from '@/util'
    
    Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
    
    export default {
      components: { ServerErrors },
      mixins: [prettyDate, rrules],
    
      emits: ['conflict', 'update'],
    
    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: {
    
    Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
        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()
    
          const { firstDate, rruleId, lastDate, defaultPlaylistId, automationId, byWeekday } =
    
          let { startTime, endTime } = this.schedule
    
    Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
    
          if (this.repetitionTime.length > 0) {
    
            const newStartTime = hmsToSeconds(this.repetitionTime)
            const oldStartTime = hmsToSeconds(startTime)
            const oldEndTime = hmsToSeconds(endTime)
    
            startTime = formatSeconds(newStartTime, true)
            endTime = formatSeconds(newStartTime + (oldEndTime - oldStartTime), true)
    
    Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
          }
    
          const newSchedule = {
            schedule: {
    
              firstDate,
              startTime,
              endTime,
              rruleId,
              lastDate,
              defaultPlaylistId,
              automationId,
              byWeekday,
              isRepetition: true,
              addBusinessDaysOnly: onlyBusinessDays,
              addDaysNo: 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,
            })
    
    Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
          } 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', {
    
            showId: this.selectedShow.id,
            scheduleId: id,
    
    Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
            callback: () => {
    
    Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
              this.$refs.modalEmissionManagerEdit.hide()
    
    Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
          })
        },
    
        deleteSingleTimeslot(scheduleId, timeslotId) {
          this.$store.dispatch('shows/deleteTimeslot', {
    
            showId: this.selectedShow.id,
            scheduleId: scheduleId,
            timeslotId: timeslotId,
    
    Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
            callback: () => {
    
    Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
              this.$refs.modalEmissionManagerEdit.hide()
            },
          })
        },
    
        deleteAllFutureTimeslots(scheduleId) {
    
          const startDate = new Date(this.timeslot.start)
          const toDelete = []
          for (const slot of this.scheduleTimeslots) {
    
    Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
            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 (const i in toDelete) {
    
    Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
              this.$log.debug('Deleting timeslot', toDelete[i])
              this.$store.dispatch('shows/deleteTimeslot', {
    
                showId: this.selectedShow.id,
                scheduleId: scheduleId,
                timeslotId: toDelete[i],
    
    Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
                callback: () => {
                  this.deletion.count++
                  this.$log.debug('deleted ' + this.deletion.count + ' timeslots')
                  if (this.deletion.count === this.deletion.amount) {
    
    Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
                    this.$refs.modalEmissionManagerDeleteTimeslots.hide()
                    this.$refs.modalEmissionManagerEdit.hide()
                  }
    
    Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
              })
            }
          }
        },
    
        loadSchedule(scheduleId) {
          this.$store.dispatch('shows/fetchSchedule', {
    
            showId: this.selectedShow.id,
            scheduleId,
    
    Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
            callback: () => {
              this.loadScheduleTimeslots(scheduleId)
            },
          })
        },
    
        loadScheduleTimeslots(scheduleId) {
          this.$store.dispatch('shows/fetchTimeslots', {
            id: this.selectedShow.id,
    
            scheduleId,
            start: this.schedule.firstDate,
            end: this.schedule.lastDate,
    
    Konrad Mohrfeldt's avatar
    Konrad Mohrfeldt committed
          })
        },
    
        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.scheduleId)