Skip to content
Snippets Groups Projects
Coursebook.vue 5.96 KiB
Newer Older
permcu's avatar
permcu committed
<template>
  <c-r-u-d-iterator
      i18n-key="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
          :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'"
        @change="changeSelection({ filterType: $event ? 'my' : 'all', type: objType, id: objId })"
    <template #default="{ items }">
      <template v-if="!$refs.iterator.loading">
        <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 v-else>
        <v-list-item v-for="_ in 10">
          <v-list-item-content>
            <v-list-item-title>
              <v-skeleton-loader type="heading"/>
            </v-list-item-title>
            <v-list max-width="100%">
              <v-list-item v-for="_ in 5">
                <v-card class="my-2 full-width">
                  <div class="full-width d-flex flex-column align-stretch flex-md-row">
                    <v-card-text>
                      <v-skeleton-loader
                        type="avatar, heading, chip"
                        class="d-flex full-width align-center gap"
                        height="100%"
                      />
                    </v-card-text>
                    <v-card-text>
                      <v-skeleton-loader
                        type="heading@2"
                        class="d-flex full-width align-center gap"
                        height="100%"
                      />
                    </v-card-text>
                    <v-card-text>
                      <v-skeleton-loader
                        type="chip@3"
                        class="d-flex full-width align-center justify-end gap"
                        height="100%"
                      />
                    </v-card-text>
                  </div>
                </v-card>
              </v-list-item>
            </v-list>
          </v-list-item-content>
        </v-list-item>
      </template>
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 {
  groupsByOwner,
  coursesOfTeacher,
  documentationsForCoursebook,
} from "./coursebook.graphql";
permcu's avatar
permcu committed

export default {
  name: "Coursebook",
  components: {
    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 })),
      ];
    },
    currentObj() {
      return this.selectable.find((o) => o.type === this.objType && o.id === this.objId);
    },
    selectLoading() {
      return this.$apollo.queries.groups.loading || this.$apollo.queries.courses.loading;
    }
    changeSelection(selection) {
      this.$router.push({
        name: "alsijil.coursebook_by_type_and_date",
          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>