瀏覽代碼

feat: Display custom messages on launch

Sean Blackburn 10 月之前
父節點
當前提交
029d74a868
共有 4 個文件被更改,包括 118 次插入0 次删除
  1. 4 0
      src/App.vue
  2. 54 0
      src/components/modals/AdministrativeModal.vue
  3. 5 0
      src/components/pages/PlannerPage.vue
  4. 55 0
      src/stores/adminMessages.ts

+ 4 - 0
src/App.vue

@@ -10,13 +10,17 @@ import { useLecturersStore } from "./stores/lecturers";
 import { useStudenthubStore } from "./stores/studenthub";
 import { useClassVersionStore } from "./stores/ClassVersion";
 import { useClassesStore } from "./stores/classes";
+import { useAdminMessagesStore } from "./stores/adminMessages";
 
+const adminMessageStore = useAdminMessagesStore();
 const moduleStore = useModulesStore();
 const lecturersStore = useLecturersStore();
 const studenthubStore = useStudenthubStore();
 const classVersionStore = useClassVersionStore();
 const classesStore = useClassesStore();
 
+adminMessageStore.fetchData();
+
 classVersionStore.fetchData();
 classesStore.fetchData();
 

+ 54 - 0
src/components/modals/AdministrativeModal.vue

@@ -0,0 +1,54 @@
+<template>
+  <BaseModal :show="message !== null" @close="close">
+    <div v-if="message" class="flex flex-col gap-10">
+      <h1 class="text-3xl font-bold leading-6 text-gray-900 dark:text-white">
+        {{ message.title }}
+      </h1>
+
+      <!-- eslint-disable-next-line vue/no-v-html -->
+      <div class="flex flex-col gap-5" v-html="message.message"></div>
+
+      <div class="w-full flex justify-end">
+        <input
+          type="submit"
+          class="bg-green-500 text-white py-2 px-5 rounded-sm hover:bg-green-600 w-1/2 cursor-pointer"
+          value="Verstanden"
+          @click="close"
+        />
+      </div>
+    </div>
+  </BaseModal>
+</template>
+
+<script lang="ts">
+import { PropType } from "vue";
+import {
+  useAdminMessagesStore,
+  type Message,
+} from "../../stores/adminMessages";
+import BaseModal from "./BaseModal.vue";
+
+export default {
+  name: "AdministrativeModal",
+  components: { BaseModal },
+  props: {
+    message: {
+      required: true,
+      type: Object as PropType<Message | null>,
+    },
+  },
+  setup() {
+    const adminMessagesStore = useAdminMessagesStore();
+
+    return {
+      adminMessagesStore,
+    };
+  },
+  methods: {
+    close() {
+      if (this.message === null) return;
+      this.adminMessagesStore.markAsRead(this.message.pk);
+    },
+  },
+};
+</script>

+ 5 - 0
src/components/pages/PlannerPage.vue

@@ -17,6 +17,7 @@
     </div>
   </div>
 
+  <AdministrativeModal :message="adminMessageStore.currentMessage" />
   <ModuleDetails />
   <SettingsModal />
   <ClassUpdateModal />
@@ -42,8 +43,12 @@ import SettingsModal from "../modals/SettingsModal.vue";
 import { useStateStore } from "../../stores/state";
 import ClassUpdateModal from "../modals/ClassUpdateModal.vue";
 import OldSemesterReminderModal from "../modals/OldSemesterReminderModal.vue";
+import AdministrativeModal from "../modals/AdministrativeModal.vue";
+import { useAdminMessagesStore } from "../../stores/adminMessages";
+
 // import HelpWantedModal from "../modals/HelpWantedModal.vue";
 
+const adminMessageStore = useAdminMessagesStore();
 const planningStore = usePlanningStore();
 const configStore = useConfigStore();
 const stateStore = useStateStore();

+ 55 - 0
src/stores/adminMessages.ts

@@ -0,0 +1,55 @@
+import { defineStore } from "pinia";
+
+export type Message = {
+  pk: number;
+  display: boolean;
+  title: string;
+  message: string;
+};
+
+const READ_ADMIN_MESSAGES_KEY = "read-admin-messages";
+
+export const useAdminMessagesStore = defineStore("adminMessages", {
+  state: () => {
+    return {
+      currentMessage: null as Message | null,
+      messages: [] as Message[],
+      readMessageIds: [] as number[],
+      ready: null as Promise<Response> | null,
+    };
+  },
+
+  actions: {
+    fetchData() {
+      this.readMessageIds = JSON.parse(
+        localStorage[READ_ADMIN_MESSAGES_KEY] ?? "[]",
+      );
+
+      this.ready = fetch(`/data/messages.json`);
+
+      this.ready
+        .then((response) => response.json())
+        .then((data: Message[]) => {
+          this.messages = data.filter((m) => m.display);
+
+          this.determineNextMessage();
+        })
+        .catch((error) => {
+          console.error(error);
+        });
+    },
+    markAsRead(messageId: number) {
+      const read_ids = this.readMessageIds;
+      read_ids.push(messageId);
+      localStorage[READ_ADMIN_MESSAGES_KEY] = JSON.stringify(read_ids);
+
+      this.determineNextMessage();
+    },
+    determineNextMessage() {
+      this.currentMessage =
+        this.messages.find((m) => {
+          return m.display && !this.readMessageIds.includes(m.pk);
+        }) ?? null;
+    },
+  },
+});