Skip to content
Snippets Groups Projects
Coursebook.vue 5.16 KiB
Newer Older
permcu's avatar
permcu committed
<template>
  <c-r-u-d-iterator
Julian's avatar
Julian committed
    i18n-key="alsijil.coursebook"
    :gql-query="gqlQuery"
    :gql-additional-query-args="gqlQueryArgs"
    :enable-create="false"
    :enable-edit="false"
    @lastQuery="lastQuery = $event"
    ref="iterator"
Hangzhi Yu's avatar
Hangzhi Yu committed
  >
    <template #additionalActions="{ attrs, on }">
      <v-autocomplete
Julian's avatar
Julian committed
        :items="selectable"
        item-text="name"
        clearable
        return-object
        filled
        dense
        hide-details
        :placeholder="$t('alsijil.coursebook.filter.filter_for_obj')"
        :loading="selectLoading"
        :value="currentObj"
        @input="changeSelection"
        @click:clear="changeSelection"
      />
      <v-switch
        :loading="selectLoading"
        :label="$t('alsijil.coursebook.filter.own')"
        :input-value="filterType === 'my'"
Julian's avatar
Julian committed
        @change="
          changeSelection({
            filterType: $event ? 'my' : 'all',
            type: objType,
            id: objId,
          })
        "
    <template #default="{ items }">
      <v-list-item v-for="day in groupDocsByDay(items)" two-line>
        <v-list-item-content>
          <v-list-item-title>{{ $d(day[0], "short") }}</v-list-item-title>
          <v-list max-width="100%">
            <v-list-item v-for="doc in day.slice(1)">
              <documentation-modal
                :documentation="doc"
                :affected-query="lastQuery"
              />
            </v-list-item>
          </v-list>
        </v-list-item-content>
      </v-list-item>
    </template>
    <template #loading>
      <CoursebookEmptyMessage icon="mdi-book-off-outline">
        {{ $t("alsijil.coursebook.no_data") }}
      </CoursebookEmptyMessage>
      <CoursebookEmptyMessage icon="mdi-book-alert-outline">
        {{ $t("alsijil.coursebook.no_results", { search: $refs.iterator.search }) }}
      </CoursebookEmptyMessage>
permcu's avatar
permcu committed
    </template>
  </c-r-u-d-iterator>
</template>

<script>
import CRUDIterator from "aleksis.core/components/generic/CRUDIterator.vue";
import DocumentationModal from "./documentation/DocumentationModal.vue";
import {DateTime} from "luxon";
import {coursesOfTeacher, documentationsForCoursebook, groupsByOwner,} from "./coursebook.graphql";
import CoursebookLoader from "./CoursebookLoader.vue";
import CoursebookEmptyMessage from "./CoursebookEmptyMessage.vue";
permcu's avatar
permcu committed

export default {
  name: "Coursebook",
  components: {
    CoursebookEmptyMessage,
permcu's avatar
permcu committed
    CRUDIterator,
    DocumentationModal,
permcu's avatar
permcu committed
  },
  props: {
    // Either as props OR route params
    // TODO: Remove default?
    filterType: {
      type: String,
      required: true,
    },
permcu's avatar
permcu committed
      type: [Number, String],
      required: false,
permcu's avatar
permcu committed
    // Next two in ISODate
    dateStart: {
      type: String,
      required: false,
      default: "",
    },
    dateEnd: {
      type: String,
      required: false,
      default: "",
    },
  },
  data() {
    return {
      gqlQuery: documentationsForCoursebook,
permcu's avatar
permcu committed
      lastQuery: null,
      // Placeholder values while query isn't completed yet
      groups: [],
      courses: [],
  apollo: {
    groups: {
      query: groupsByOwner,
    },
    courses: {
      query: coursesOfTeacher,
    },
  },
permcu's avatar
permcu committed
  computed: {
    gqlQueryArgs() {
      return {
        // Assure courseId is a number
        own: this.filterType === "all" ? false : true,
        objId: this.objId ? Number(this.objId) : null,
        objType: this.objType?.toUpperCase(),
permcu's avatar
permcu committed
        dateStart: this.dateStart,
        dateEnd: this.dateEnd,
      };
    },
    selectable() {
      return [
        { header: this.$t("alsijil.coursebook.filter.groups") },
        ...this.groups.map((group) => ({ type: "group", ...group })),
        { header: this.$t("alsijil.coursebook.filter.courses") },
        ...this.courses.map((course) => ({ type: "course", ...course })),
      ];
    },
Julian's avatar
Julian committed
      return this.selectable.find(
        (o) => o.type === this.objType && o.id === this.objId,
      );
    selectLoading() {
Julian's avatar
Julian committed
      return (
        this.$apollo.queries.groups.loading ||
        this.$apollo.queries.courses.loading
      );
    },
    changeSelection(selection) {
      this.$router.push({
        name: "alsijil.coursebook_by_type_and_date",
Julian's avatar
Julian committed
          filterType: selection.filterType
            ? selection.filterType
            : this.filterType,
          objType: selection.type,
          objId: selection.id,
          dateStart: this.dateStart,
          dateEnd: this.dateEnd,
        },
      });
    },
    // => [[dt doc ...] ...]
Hangzhi Yu's avatar
Hangzhi Yu committed
      const byDay = docs.reduce((byDay, doc) => {
        // This works with dummy. Does actual doc have dateStart instead?
        const day = DateTime.fromISO(doc.datetimeStart).startOf("day");
        byDay[day] ??= [day];
        byDay[day].push(doc);
        return byDay;
      }, {});
Hangzhi Yu's avatar
Hangzhi Yu committed
      return Object.keys(byDay)
        .sort()
        .map((key) => byDay[key]);
permcu's avatar
permcu committed
};
</script>