From c816eb507f485e74d7e601ddc5b5f12286482444 Mon Sep 17 00:00:00 2001
From: Julian Leucker <leuckerj@gmail.com>
Date: Sat, 22 Jun 2024 01:04:09 +0200
Subject: [PATCH] Create initial draft of TardinessNote.vue

---
 .../personal_notes/TardinessNote.vue          | 156 ++++++++++++++++++
 1 file changed, 156 insertions(+)
 create mode 100644 aleksis/apps/alsijil/frontend/components/coursebook/personal_notes/TardinessNote.vue

diff --git a/aleksis/apps/alsijil/frontend/components/coursebook/personal_notes/TardinessNote.vue b/aleksis/apps/alsijil/frontend/components/coursebook/personal_notes/TardinessNote.vue
new file mode 100644
index 000000000..94d9d317e
--- /dev/null
+++ b/aleksis/apps/alsijil/frontend/components/coursebook/personal_notes/TardinessNote.vue
@@ -0,0 +1,156 @@
+<script>
+import {
+  createPersonalNotes,
+  deletePersonalNotes,
+  updatePersonalNotes,
+} from "./personal_notes.graphql";
+import personalNoteRelatedMixin from "./personalNoteRelatedMixin";
+import mutateMixin from "aleksis.core/mixins/mutateMixin.js";
+import DeleteDialog from "aleksis.core/components/generic/dialogs/DeleteDialog.vue";
+import PositiveSmallIntegerField from "aleksis.core/components/generic/forms/PositiveSmallIntegerField.vue";
+
+export default {
+  name: "TardinessNote",
+  components: { DeleteDialog, PositiveSmallIntegerField },
+  mixins: [mutateMixin, personalNoteRelatedMixin],
+  computed: {
+    value() {
+      return this.participation.noteWithTardiness;
+    },
+    lessonLength() {
+      // TODO: calculate lesson length in minutes
+      return 60;
+    },
+    model: {
+      get() {
+        return this.value?.tardiness;
+      },
+      set(newValue) {
+        if (!newValue) {
+          // this is a DELETE action, show the dialog, ...
+          this.showDeleteConfirm = true;
+          return;
+        }
+        const create = !this.value?.id;
+
+        this.mutate(
+          create ? createPersonalNotes : updatePersonalNotes,
+          this.getInput(
+            newValue,
+            create
+              ? {
+                  documentation: this.documentation.id,
+                  person: this.participation.person.id,
+                }
+              : {
+                  id: this.value.id,
+                },
+          ),
+          this.getUpdater(create ? "create" : "update"),
+        );
+      },
+    },
+  },
+  methods: {
+    getInput(newValue, extras) {
+      return {
+        input: [
+          {
+            tardiness: newValue,
+            ...extras,
+          },
+        ],
+      };
+    },
+    getUpdater(mode) {
+      return (storedDocumentations, incomingPersonalNotes) => {
+        const note = incomingPersonalNotes?.[0] || undefined;
+        const documentation = storedDocumentations.find(
+          (doc) => doc.id === this.documentation.id,
+        );
+        const participationStatus = documentation.participations.find(
+          (part) => part.id === this.participation.id,
+        );
+        switch (mode.toLowerCase()) {
+          case "update": {
+            const oldNote = participationStatus.noteWithTardiness;
+            participationStatus.noteWithTardiness = {
+              ...oldNote,
+              ...note,
+            };
+            break;
+          }
+          case "delete": {
+            participationStatus.noteWithTardiness = null;
+            break;
+          }
+
+          case "create":
+            participationStatus.noteWithTardiness = note;
+            break;
+
+          default:
+            console.error("Invalid mode in getUpdater():", mode);
+            break;
+        }
+
+        return storedDocumentations;
+      };
+    },
+    lessonLengthRule(time) {
+      // FIXME: translation
+      return time <= lessonLength || this.$t("alsijil.personal_notes.lesson_length_exceeded");
+    }
+  },
+  data() {
+    return {
+      showDeleteConfirm: false,
+      deletePersonalNotes,
+    };
+  },
+}
+</script>
+
+<template>
+  <positive-small-integer-field
+    outlined
+    class="mt-1"
+    prepend-inner-icon="mdi-clock-alert-outline"
+    :suffix="$t('time.minutes')"
+    :label="$t('alsijil.personal_notes.tardiness')"
+    :rules="[lessonLengthRule]"
+    :value="model"
+    @change="model = $event"
+    :loading="loading"
+  >
+    <template #append>
+      <v-slide-x-reverse-transition>
+        <v-btn v-if="!!model" icon @click="showDeleteConfirm = true">
+          <v-icon> $deleteContent </v-icon>
+        </v-btn>
+      </v-slide-x-reverse-transition>
+
+      <delete-dialog
+        v-model="showDeleteConfirm"
+        :gql-delete-mutation="deletePersonalNotes"
+        :affected-query="affectedQuery"
+        item-attribute="fullName"
+        :items="[value]"
+        :custom-update="getUpdater('delete')"
+      >
+        <template #title>
+          {{ $t("alsijil.personal_notes.confirm_delete") }}
+        </template>
+        <template #body>
+          {{
+            // TODO: Fix delete content
+            $t("alsijil.personal_notes.confirm_delete_explanation", {
+              note: value.note,
+              name: participation.person.fullName,
+            })
+          }}
+        </template>
+      </delete-dialog>
+    </template>
+  </positive-small-integer-field>
+</template>
-- 
GitLab