Skip to content
Snippets Groups Projects
TimetableWrapper.vue 6.72 KiB
Newer Older
<script>
import { gqlAvailableTimetables } from "./timetables.graphql";
import NoTimetableCard from "./NoTimetableCard.vue";
import SelectTimetable from "./SelectTimetable.vue";
import timetableTypes from "./timetableTypes";

export default {
  name: "TimetableWrapper",
  components: { NoTimetableCard, SelectTimetable },
  apollo: {
    availableTimetables: {
      query: gqlAvailableTimetables,
      result() {
        if (
          !this.selected &&
          this.$route.params.id &&
          this.$route.params.type
        ) {
          this.selectTimetable(
            this.availableTimetables.find(
              (t) =>
                t.objId === this.$route.params.id &&
                t.type.toLowerCase() === this.$route.params.type,
            ),
          );
        }
      },
    },
  },
  data() {
    return {
      availableTimetables: [],
      selected: null,
      search: "",
      selectedTypes: ["GROUP", "TEACHER", "ROOM"],
      types: timetableTypes,
      selectDialog: false,
    };
  },
  props: {
    onSelected: {
      type: Function,
      required: false,
      default: null,
    },
  },
  watch: {
    selected(selected) {
      if (this.onSelected) {
        this.onSelected(selected);
        return;
      }
      // Align navigation with currently selected timetable
      if (!selected) {
        this.$router.push({ name: "chronos.timetable" });
      } else if (
        selected.objId !== this.$route.params.id ||
        selected.type.toLowerCase() !== this.$route.params.type
      ) {
        this.$router.push({
          name: "chronos.timetableWithId",
          params: {
            type: selected.type.toLowerCase(),
            id: selected.objId,
          },
        });
      }
    },
  },
  methods: {
    findNextTimetable(offset = 1) {
      const currentIndex = this.availableTimetablesIds.indexOf(
        this.selected.id,
      );
      const newIndex = currentIndex + offset;
      if (newIndex < 0 || newIndex >= this.availableTimetablesIds.length) {
        return null;
      }
      return this.availableTimetables[newIndex];
    },
    selectTimetable(timetable) {
      this.selected = timetable;
    },
  },
  computed: {
    selectedTypesFull() {
      return this.selectedTypes.map((type) => {
        return this.types[type];
      });
    },
    availableTimetablesFiltered() {
      // Filter timetables by selected types
      return this.availableTimetables.filter((timetable) => {
        return this.selectedTypes.indexOf(timetable.type) !== -1;
      });
    },
    availableTimetablesIds() {
      return this.availableTimetables.map((timetable) => timetable.id);
    },
    prevTimetable() {
      return this.findNextTimetable(-1);
    },
    nextTimetable() {
      return this.findNextTimetable(1);
    },
  },
};
</script>

<template>
  <div>
    <v-row>
      <v-dialog
        v-model="selectDialog"
        fullscreen
        hide-overlay
        transition="dialog-bottom-transition"
      >
        <v-card>
          <v-toolbar dark color="primary">
            <v-btn icon dark @click="selectDialog = false">
              <v-icon>mdi-close</v-icon>
            </v-btn>
            <v-toolbar-title>{{
              $t("chronos.timetable.select")
            }}</v-toolbar-title>
            <v-spacer></v-spacer>
          </v-toolbar>
          <slot
            name="additionalSelect"
            :selected="selected"
            :mobile="true"
          ></slot>
          <select-timetable
            v-model="selected"
            @input="selectDialog = false"
            :loading="$apollo.queries.availableTimetables.loading"
            :available-timetables="availableTimetables"
          />
        </v-card>
      </v-dialog>

      <v-col md="3" lg="3" xl="3" v-if="$vuetify.breakpoint.lgAndUp">
        <slot
          name="additionalSelect"
          :selected="selected"
          :mobile="false"
        ></slot>
        <v-card>
          <select-timetable
            v-model="selected"
            :loading="$apollo.queries.availableTimetables.loading"
            :available-timetables="availableTimetables"
            limit-height
          />
        </v-card>
      </v-col>
      <v-col sm="12" md="12" lg="9" xl="9" class="full-height">
        <!-- No timetable card-->
        <no-timetable-card
          v-if="selected == null"
          @selectTimetable="selectDialog = true"
        />

        <!-- Calendar card-->
        <v-card v-else>
          <div class="d-flex flex-column" v-if="$vuetify.breakpoint.mdAndDown">
            <v-card-title class="pt-2">
              <v-btn
                icon
                :disabled="!prevTimetable"
                @click="selectTimetable(prevTimetable)"
                :title="$t('chronos.timetable.prev')"
                class="mr-1"
              >
                <v-icon>mdi-chevron-left</v-icon>
              </v-btn>
              <v-spacer />
              <v-chip outlined color="secondary" @click="selectDialog = true">
                {{ selected.name }}
                <v-icon right>mdi-chevron-down</v-icon>
              </v-chip>
              <v-spacer />
              <v-btn
                icon
                :disabled="!nextTimetable"
                @click="selectTimetable(nextTimetable)"
                :title="$t('chronos.timetable.next')"
                class="ml-1 float-right"
              >
                <v-icon>mdi-chevron-right</v-icon>
              </v-btn>
            </v-card-title>
            <slot
              name="additionalButton"
              :selected="selected"
              :mobile="true"
            ></slot>
          </div>

          <div class="d-flex flex-wrap justify-space-between mb-2" v-else>
            <v-card-title>
              {{ selected.name }}
              <slot
                name="additionalButton"
                :selected="selected"
                :mobile="false"
              ></slot>
            </v-card-title>
            <div class="pa-2 mt-1">
              <v-btn
                icon
                :disabled="!prevTimetable"
                @click="selectTimetable(prevTimetable)"
                :title="$t('chronos.timetable.prev')"
              >
                <v-icon>mdi-chevron-left</v-icon>
              </v-btn>
              <v-chip label color="secondary" outlined class="mx-1">{{
                selected.shortName
              }}</v-chip>
              <v-btn
                icon
                :disabled="!nextTimetable"
                @click="selectTimetable(nextTimetable)"
                :title="$t('chronos.timetable.next')"
              >
                <v-icon>mdi-chevron-right</v-icon>
              </v-btn>
            </div>
          </div>
          <slot :selected="selected"></slot>
        </v-card>
      </v-col>
    </v-row>
  </div>
</template>