From 17108a678107f88f1c76aa81c43bf912eb0c22b6 Mon Sep 17 00:00:00 2001 From: Lauritz Tieste Date: Mon, 28 Oct 2024 18:38:12 +0100 Subject: [PATCH 1/5] Modify reported quizzes --- components/DialogSlot.vue | 56 ++++ components/form/Quiz.vue | 326 ++++++++++++++++++++++++ composables/dialogSlot.ts | 2 + composables/quizzes.ts | 49 ++++ locales/de.json | 5 + locales/en-US.json | 4 + package-lock.json | 42 +++ package.json | 1 + pages/dashboard/reported-tasks/[id].vue | 62 +++-- types/courseTypes.ts | 16 ++ 10 files changed, 540 insertions(+), 23 deletions(-) create mode 100644 components/DialogSlot.vue create mode 100644 components/form/Quiz.vue create mode 100644 composables/dialogSlot.ts create mode 100644 composables/quizzes.ts create mode 100644 types/courseTypes.ts diff --git a/components/DialogSlot.vue b/components/DialogSlot.vue new file mode 100644 index 0000000..d3cf4c8 --- /dev/null +++ b/components/DialogSlot.vue @@ -0,0 +1,56 @@ + + + diff --git a/components/form/Quiz.vue b/components/form/Quiz.vue new file mode 100644 index 0000000..0ff6e28 --- /dev/null +++ b/components/form/Quiz.vue @@ -0,0 +1,326 @@ + + + diff --git a/composables/dialogSlot.ts b/composables/dialogSlot.ts new file mode 100644 index 0000000..218e6df --- /dev/null +++ b/composables/dialogSlot.ts @@ -0,0 +1,2 @@ +export const useDialogSlot = () => useState("dialogSlot", () => false); +export const useDialogCreateSubtask = () => useState("dialogCreateSubtask", () => false); diff --git a/composables/quizzes.ts b/composables/quizzes.ts new file mode 100644 index 0000000..61f0227 --- /dev/null +++ b/composables/quizzes.ts @@ -0,0 +1,49 @@ +import { useState } from "#app"; +import { Quiz } from "~/types/courseTypes"; +import { GET } from "./fetch"; + +export const useSubTasksInQuiz = () => useState("subTasksInQuiz", () => []); +export const useSubTaskAndSolutionInQuiz = () => useState("subTaskAndSolutionInQuiz", () => null); + +export async function getSubTasksInQuiz(taskId: any, creator: any = "") { + try { + let query = ""; + + if (!!creator) { + query = `/challenges/tasks/${taskId}/multiple_choice?creator=${creator}`; + } else { + query = `/challenges/tasks/${taskId}/multiple_choice`; + } + const res = await GET(query); + const subTasksInQuiz = useSubTasksInQuiz(); + subTasksInQuiz.value = res ?? []; + + return [res, null]; + } catch (error) { + return [null, error]; + } +} + +export async function updateSubTaskInQuizForAdmin(taskId: any, subTaskId: any, body: any) { + try { + const res = await PATCH(`/challenges/tasks/${taskId}/multiple_choice/${subTaskId}`, body); + const user: any = useUser(); + await getSubTasksInQuiz(taskId, user?.value.id ?? ""); + + return [res, null]; + } catch (error) { + return [null, error]; + } +} + +export async function getSubTaskAndSolutionInQuiz(taskId: any, subTaskId: any) { + try { + const res = await GET(`/challenges/tasks/${taskId}/multiple_choice/${subTaskId}/solution`); + const subTaskAndSolutionInQuiz = useSubTaskAndSolutionInQuiz(); + subTaskAndSolutionInQuiz.value = res ?? null; + + return [res, null]; + } catch (error) { + return [null, error]; + } +} diff --git a/locales/de.json b/locales/de.json index 6556da2..c69f7b2 100644 --- a/locales/de.json +++ b/locales/de.json @@ -151,6 +151,9 @@ } }, "Inputs": { + "Option": "Option", + "Correct": "Richtig", + "Question": "Frage", "EmailOrUsername": "E-Mail-Adresse oder Spitzname", "Password": "Passwort", "CompanyId": "Firmen-ID", @@ -182,6 +185,7 @@ "MFACode": "6-stelliger MFA-Code" }, "Buttons": { + "UpdateQuiz": "Quiz aktualisieren", "Incorrect": "Falsch", "Correct": "Richtig", "Safe": "Sicher", @@ -205,6 +209,7 @@ "EditCompany": "Firma bearbeiten", "CreateCompany": "Neue Firma erstellen", "adjustTask": "Aufgabe anpassen", + "markAsRevised": "Aufgabe als überarbeitet markieren", "deleteTask": "Aufgabe löschen", "blockReporter": "Reporter blockieren", "blockCreator": "Ersteller blockieren" diff --git a/locales/en-US.json b/locales/en-US.json index 5cb8be0..bedf2ad 100644 --- a/locales/en-US.json +++ b/locales/en-US.json @@ -5,6 +5,8 @@ "LoginForm": "Please enter your credentials" }, "Headings": { + "Option": "Option", + "Correct": "Correct", "ManageReport": "Manage Report", "userEnabled": "User aktiviert", "userDisabled": "User deaktiviert", @@ -185,6 +187,7 @@ "MFACode": "MFA 6 digit Code" }, "Buttons": { + "UpdateQuiz": "Update Quiz", "Incorrect": "Incorrect", "Correct": "Correct", "Safe": "Safe", @@ -208,6 +211,7 @@ "EditCompany": "Edit Company", "CreateCompany": "Create New Company", "adjustTask": "Adjust Task", + "markAsRevised": "Mark task as revised", "deleteTask": "Delete Task", "blockReporter": "Block reporter", "blockCreator": "Block creator" diff --git a/package-lock.json b/package-lock.json index b567df0..f8fc3b4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,6 +6,7 @@ "": { "hasInstallScript": true, "dependencies": { + "@headlessui/vue": "^1.7.22", "@heroicons/vue": "^2.1.3", "@typescript-eslint/parser": "^7.11.0", "async-mutex": "^0.5.0", @@ -1275,6 +1276,21 @@ "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.2.tgz", "integrity": "sha512-J4yDIIthosAsRZ5CPYP/jQvUAQtlZTTD/4suA08/FEnlxqW3sKS9iAhgsa9VYLZ6vDHn/ixJgIqRQPotoBjxIw==" }, + "node_modules/@headlessui/vue": { + "version": "1.7.23", + "resolved": "https://registry.npmjs.org/@headlessui/vue/-/vue-1.7.23.tgz", + "integrity": "sha512-JzdCNqurrtuu0YW6QaDtR2PIYCKPUWq28csDyMvN4zmGccmE7lz40Is6hc3LA4HFeCI7sekZ/PQMTNmn9I/4Wg==", + "license": "MIT", + "dependencies": { + "@tanstack/vue-virtual": "^3.0.0-beta.60" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "vue": "^3.2.0" + } + }, "node_modules/@heroicons/vue": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/@heroicons/vue/-/vue-2.1.3.tgz", @@ -3067,6 +3083,32 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@tanstack/virtual-core": { + "version": "3.10.8", + "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.10.8.tgz", + "integrity": "sha512-PBu00mtt95jbKFi6Llk9aik8bnR3tR/oQP1o3TSi+iG//+Q2RTIzCEgKkHG8BB86kxMNW6O8wku+Lmi+QFR6jA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/vue-virtual": { + "version": "3.10.8", + "resolved": "https://registry.npmjs.org/@tanstack/vue-virtual/-/vue-virtual-3.10.8.tgz", + "integrity": "sha512-DB5QA8c/LfqOqIUCpSs3RdOTVroRRdqeHMqBkYrcashSZtOzIv8xbiqHgg7RYxDfkH5F3Y+e0MkuuyGNDVB0BQ==", + "license": "MIT", + "dependencies": { + "@tanstack/virtual-core": "3.10.8" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "vue": "^2.7.0 || ^3.0.0" + } + }, "node_modules/@trysound/sax": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", diff --git a/package.json b/package.json index d72a3f1..a4ba478 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ }, "dependencies": { "@heroicons/vue": "^2.1.3", + "@headlessui/vue": "^1.7.22", "@typescript-eslint/parser": "^7.11.0", "async-mutex": "^0.5.0", "dompurify": "^3.1.4", diff --git a/pages/dashboard/reported-tasks/[id].vue b/pages/dashboard/reported-tasks/[id].vue index 3aa9958..308a07f 100644 --- a/pages/dashboard/reported-tasks/[id].vue +++ b/pages/dashboard/reported-tasks/[id].vue @@ -69,14 +69,6 @@
- - {{ t("Buttons.adjustTask") }} - - {{ t("Buttons.blockCreator") }} + + + {{ t("Buttons.adjustTask") }} + + + + {{ t("Buttons.markAsRevised") }} + + + + +
@@ -109,16 +125,16 @@ - - diff --git a/types/courseTypes.ts b/types/courseTypes.ts new file mode 100644 index 0000000..b158bad --- /dev/null +++ b/types/courseTypes.ts @@ -0,0 +1,16 @@ +export class Quiz { + coins: number = 0; + creation_timestamp: string = ""; + creator: string = ""; + enabled: boolean = false; + id: string = ""; + question: string = ""; + rated: boolean = false; + retired: boolean = false; + single_choice: boolean = false; + solved: boolean = false; + task_id: string = ""; + type: string = ""; // ? 'MULTIPLE_CHOICE_QUESTION + xp: number = 0; + answers: string[] = []; +} From d8f8027ccbc0ddde261a331ac172869653797f96 Mon Sep 17 00:00:00 2001 From: Lauritz Tieste Date: Mon, 28 Oct 2024 18:40:57 +0100 Subject: [PATCH 2/5] Fix linting --- package.json | 3 ++- pages/dashboard/reported-tasks/[id].vue | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index a4ba478..57e565f 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,8 @@ "generate": "nuxt generate", "preview": "nuxt preview", "postinstall": "nuxt prepare", - "lint": "eslint --ext .js,.vue,.ts ." + "lint": "eslint --ext .js,.vue,.ts .", + "lint:fix": "eslint --ext .js,.vue,.ts --fix ." }, "devDependencies": { "autoprefixer": "^10.4.19", diff --git a/pages/dashboard/reported-tasks/[id].vue b/pages/dashboard/reported-tasks/[id].vue index 308a07f..078614b 100644 --- a/pages/dashboard/reported-tasks/[id].vue +++ b/pages/dashboard/reported-tasks/[id].vue @@ -155,8 +155,8 @@ const subtask_id = computed(() => route.query?.subtaskId ?? ""); const reportedTask = useReportedSubtask(); const reportedAt = computed(() => convertTimestampToDate( - convertDateToTimestamp(reportedTask.value.timestamp) - )); + convertDateToTimestamp(reportedTask.value.timestamp) +)); const loadingCorrect = ref(false); const loadingInCorrect = ref(false); From ae9baae3c6b7475c986cf617c244a0909a8cd50f Mon Sep 17 00:00:00 2001 From: Lauritz Tieste Date: Sun, 25 May 2025 14:16:28 +0200 Subject: [PATCH 3/5] Fix errors --- package-lock.json | 26 ++- package.json | 9 +- pages/dashboard/reported-tasks/[id].vue | 205 ++++++++++-------------- 3 files changed, 115 insertions(+), 125 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7b2afbf..075e210 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,6 +6,7 @@ "": { "hasInstallScript": true, "dependencies": { + "@headlessui/vue": "^1.7.23", "@heroicons/vue": "^2.2.0", "@typescript-eslint/parser": "^8.32.1", "async-mutex": "^0.5.0", @@ -1124,7 +1125,6 @@ "version": "1.7.23", "resolved": "https://registry.npmjs.org/@headlessui/vue/-/vue-1.7.23.tgz", "integrity": "sha512-JzdCNqurrtuu0YW6QaDtR2PIYCKPUWq28csDyMvN4zmGccmE7lz40Is6hc3LA4HFeCI7sekZ/PQMTNmn9I/4Wg==", - "license": "MIT", "dependencies": { "@tanstack/vue-virtual": "^3.0.0-beta.60" }, @@ -4021,6 +4021,30 @@ "dev": true, "license": "CC0-1.0" }, + "node_modules/@tanstack/virtual-core": { + "version": "3.13.9", + "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.13.9.tgz", + "integrity": "sha512-3jztt0jpaoJO5TARe2WIHC1UQC3VMLAFUW5mmMo0yrkwtDB2AQP0+sh10BVUpWrnvHjSLvzFizydtEGLCJKFoQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/vue-virtual": { + "version": "3.13.9", + "resolved": "https://registry.npmjs.org/@tanstack/vue-virtual/-/vue-virtual-3.13.9.tgz", + "integrity": "sha512-HsvHaOo+o52cVcPhomKDZ3CMpTF/B2qg+BhPHIQJwzn4VIqDyt/rRVqtIomG6jE83IFsE2vlr6cmx7h3dHA0SA==", + "dependencies": { + "@tanstack/virtual-core": "3.13.9" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "vue": "^2.7.0 || ^3.0.0" + } + }, "node_modules/@trysound/sax": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", diff --git a/package.json b/package.json index 653911f..488b6e3 100644 --- a/package.json +++ b/package.json @@ -5,20 +5,21 @@ "dev": "nuxt dev", "generate": "nuxt generate", "preview": "nuxt preview", - "postinstall": "nuxt prepare", - "lint": "eslint --ext .js,.vue,.ts .", + "postinstall": "nuxt prepare", + "lint": "eslint --ext .js,.vue,.ts .", "lint:fix": "eslint --ext .js,.vue,.ts --fix ." }, "devDependencies": { "autoprefixer": "^10.4.21", - "eslint": "^8.57.1", - "eslint-plugin-vue": "^10.1.0", + "eslint": "^8.57.1", + "eslint-plugin-vue": "^10.1.0", "nuxt": "3.17.4", "postcss": "^8.5.3", "tailwindcss": "^3.4.17", "vue-i18n": "^11.1.4" }, "dependencies": { + "@headlessui/vue": "^1.7.23", "@heroicons/vue": "^2.2.0", "@typescript-eslint/parser": "^8.32.1", "async-mutex": "^0.5.0", diff --git a/pages/dashboard/reported-tasks/[id].vue b/pages/dashboard/reported-tasks/[id].vue index fb5341d..076e108 100644 --- a/pages/dashboard/reported-tasks/[id].vue +++ b/pages/dashboard/reported-tasks/[id].vue @@ -1,9 +1,7 @@ From 4ee3e9c7b85100097eaf1315a9e0dc3fd2e3244e Mon Sep 17 00:00:00 2001 From: Lauritz Tieste Date: Sun, 25 May 2025 14:17:30 +0200 Subject: [PATCH 4/5] Fix linting --- pages/dashboard/reported-tasks/[id].vue | 122 ++++++++++++------------ 1 file changed, 61 insertions(+), 61 deletions(-) diff --git a/pages/dashboard/reported-tasks/[id].vue b/pages/dashboard/reported-tasks/[id].vue index 076e108..5c486a5 100644 --- a/pages/dashboard/reported-tasks/[id].vue +++ b/pages/dashboard/reported-tasks/[id].vue @@ -89,26 +89,26 @@ From f0005e1e5fabadda8900a7d776181ae6aeca0333 Mon Sep 17 00:00:00 2001 From: Lauritz Tieste Date: Sun, 25 May 2025 14:21:31 +0200 Subject: [PATCH 5/5] Implement Copilot's suggestions --- components/DialogSlot.vue | 4 ++-- types/courseTypes.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/components/DialogSlot.vue b/components/DialogSlot.vue index d3cf4c8..31e4db8 100644 --- a/components/DialogSlot.vue +++ b/components/DialogSlot.vue @@ -10,7 +10,7 @@ import { XMarkIcon } from "@heroicons/vue/24/solid"; import { useI18n } from "vue-i18n"; defineProps({ - label: { type: String, defalt: "" }, + label: { type: String, default: "" }, showCross: { type: Boolean, default: true }, propClass: { type: String, default: "" }, }); @@ -40,7 +40,7 @@ function close() { enter-to="opacity-100 translate-y-0 sm:scale-100" leave="ease-in duration-200" leave-from="opacity-100 translate-y-0 sm:scale-100" leave-to="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"> -

{{ t(label) }}

diff --git a/types/courseTypes.ts b/types/courseTypes.ts index b158bad..76a7449 100644 --- a/types/courseTypes.ts +++ b/types/courseTypes.ts @@ -10,7 +10,7 @@ export class Quiz { single_choice: boolean = false; solved: boolean = false; task_id: string = ""; - type: string = ""; // ? 'MULTIPLE_CHOICE_QUESTION + type: string = ""; xp: number = 0; answers: string[] = []; }