fix: 403 error bij het opvragen van een opdracht
This commit is contained in:
parent
96076844a5
commit
149e4e80fc
2 changed files with 277 additions and 269 deletions
|
@ -1,36 +1,50 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, computed, watchEffect } from "vue";
|
import {ref, computed, watchEffect} from "vue";
|
||||||
import auth from "@/services/auth/auth-service.ts";
|
import auth from "@/services/auth/auth-service.ts";
|
||||||
import { useI18n } from "vue-i18n";
|
import {useI18n} from "vue-i18n";
|
||||||
import { useAssignmentQuery } from "@/queries/assignments.ts";
|
import UsingQueryResult from "@/components/UsingQueryResult.vue";
|
||||||
import UsingQueryResult from "@/components/UsingQueryResult.vue";
|
import type {AssignmentsResponse} from "@/controllers/assignments.ts";
|
||||||
import type { AssignmentResponse } from "@/controllers/assignments.ts";
|
import {asyncComputed} from "@vueuse/core";
|
||||||
import { asyncComputed } from "@vueuse/core";
|
import {
|
||||||
import { useStudentGroupsQuery, useStudentsByUsernamesQuery } from "@/queries/students.ts";
|
useStudentAssignmentsQuery,
|
||||||
import { useGetLearningPathQuery } from "@/queries/learning-paths.ts";
|
useStudentGroupsQuery,
|
||||||
import type { Language } from "@/data-objects/language.ts";
|
useStudentsByUsernamesQuery
|
||||||
import { calculateProgress } from "@/utils/assignment-utils.ts";
|
} from "@/queries/students.ts";
|
||||||
import type { LearningPath } from "@/data-objects/learning-paths/learning-path.ts";
|
import {useGetLearningPathQuery} from "@/queries/learning-paths.ts";
|
||||||
|
import type {Language} from "@/data-objects/language.ts";
|
||||||
|
import {calculateProgress} from "@/utils/assignment-utils.ts";
|
||||||
|
import type {LearningPath} from "@/data-objects/learning-paths/learning-path.ts";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
classId: string;
|
classId: string;
|
||||||
assignmentId: number;
|
assignmentId: number;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const { t } = useI18n();
|
const {t} = useI18n();
|
||||||
const lang = ref();
|
const lang = ref();
|
||||||
const learningPath = ref();
|
const learningPath = ref();
|
||||||
// Get the user's username/id
|
// Get the user's username/id
|
||||||
const username = asyncComputed(async () => {
|
const username = asyncComputed(async () => {
|
||||||
const user = await auth.loadUser();
|
const user = await auth.loadUser();
|
||||||
return user?.profile?.preferred_username ?? undefined;
|
return user?.profile?.preferred_username ?? undefined;
|
||||||
});
|
});
|
||||||
|
|
||||||
const assignmentQueryResult = useAssignmentQuery(() => props.classId, props.assignmentId);
|
const assignmentsQueryResult = useStudentAssignmentsQuery(username, true);
|
||||||
learningPath.value = assignmentQueryResult.data.value?.assignment?.learningPath;
|
|
||||||
|
|
||||||
const groupsQueryResult = useStudentGroupsQuery(username, true);
|
const assignment = computed(() => {
|
||||||
const group = computed(() => {
|
const assignments = assignmentsQueryResult.data.value?.assignments;
|
||||||
|
if (!assignments) return undefined;
|
||||||
|
|
||||||
|
return assignments.find(
|
||||||
|
(a) => a.id === props.assignmentId && a.within === props.classId
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
learningPath.value = assignment.value?.learningPath;
|
||||||
|
|
||||||
|
const groupsQueryResult = useStudentGroupsQuery(username, true);
|
||||||
|
const group = computed(() => {
|
||||||
const groups = groupsQueryResult.data.value?.groups;
|
const groups = groupsQueryResult.data.value?.groups;
|
||||||
|
|
||||||
if (!groups) return undefined;
|
if (!groups) return undefined;
|
||||||
|
@ -44,14 +58,14 @@
|
||||||
groupNo: index + 1, // Renumbered index
|
groupNo: index + 1, // Renumbered index
|
||||||
}))
|
}))
|
||||||
.find((group) => group.members?.some((m) => m.username === username.value));
|
.find((group) => group.members?.some((m) => m.username === username.value));
|
||||||
});
|
});
|
||||||
|
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
learningPath.value = assignmentQueryResult.data.value?.assignment?.learningPath;
|
learningPath.value = assignment.value?.learningPath;
|
||||||
lang.value = assignmentQueryResult.data.value?.assignment?.language as Language;
|
lang.value = assignment.value?.language as Language;
|
||||||
});
|
});
|
||||||
|
|
||||||
const learningPathParams = computed(() => {
|
const learningPathParams = computed(() => {
|
||||||
if (!group.value || !learningPath.value || !lang.value) return undefined;
|
if (!group.value || !learningPath.value || !lang.value) return undefined;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -59,32 +73,31 @@
|
||||||
assignmentNo: props.assignmentId,
|
assignmentNo: props.assignmentId,
|
||||||
classId: props.classId,
|
classId: props.classId,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
const lpQueryResult = useGetLearningPathQuery(
|
const lpQueryResult = useGetLearningPathQuery(
|
||||||
() => learningPath.value,
|
() => learningPath.value,
|
||||||
() => lang.value,
|
() => lang.value,
|
||||||
() => learningPathParams.value,
|
() => learningPathParams.value,
|
||||||
);
|
);
|
||||||
|
|
||||||
const progressColor = computed(() => {
|
const progressColor = computed(() => {
|
||||||
const progress = calculateProgress(lpQueryResult.data.value as LearningPath);
|
const progress = calculateProgress(lpQueryResult.data.value as LearningPath);
|
||||||
if (progress >= 100) return "success";
|
if (progress >= 100) return "success";
|
||||||
if (progress >= 50) return "warning";
|
if (progress >= 50) return "warning";
|
||||||
return "error";
|
return "error";
|
||||||
});
|
});
|
||||||
|
|
||||||
const studentQueries = useStudentsByUsernamesQuery(() => (group.value?.members as string[]) ?? undefined);
|
const studentQueries = useStudentsByUsernamesQuery(() => (group.value?.members as string[]) ?? undefined);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<using-query-result
|
<using-query-result
|
||||||
:query-result="assignmentQueryResult"
|
:query-result="assignmentsQueryResult"
|
||||||
v-slot="assignmentResponse: { data: AssignmentResponse }"
|
|
||||||
>
|
>
|
||||||
<v-card
|
<v-card
|
||||||
v-if="assignmentResponse"
|
v-if="assignment"
|
||||||
class="assignment-card"
|
class="assignment-card"
|
||||||
>
|
>
|
||||||
<div class="top-buttons">
|
<div class="top-buttons">
|
||||||
|
@ -98,7 +111,7 @@
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</div>
|
</div>
|
||||||
<v-card-title class="text-h4 assignmentTopTitle"
|
<v-card-title class="text-h4 assignmentTopTitle"
|
||||||
>{{ assignmentResponse.data.assignment.title }}
|
>{{ assignment.title }}
|
||||||
</v-card-title>
|
</v-card-title>
|
||||||
|
|
||||||
<v-card-subtitle class="subtitle-section">
|
<v-card-subtitle class="subtitle-section">
|
||||||
|
@ -110,7 +123,7 @@
|
||||||
v-if="lpData"
|
v-if="lpData"
|
||||||
:to="
|
:to="
|
||||||
group
|
group
|
||||||
? `/learningPath/${lpData.hruid}/${assignmentResponse.data.assignment?.language}/${lpData.startNode.learningobjectHruid}?forGroup=${0}&assignmentNo=${assignmentId}&classId=${classId}`
|
? `/learningPath/${lpData.hruid}/${assignment.language}/${lpData.startNode.learningobjectHruid}?forGroup=${group.groupNo}&assignmentNo=${assignment.id}&classId=${assignment.within}`
|
||||||
: undefined
|
: undefined
|
||||||
"
|
"
|
||||||
:disabled="!group"
|
:disabled="!group"
|
||||||
|
@ -123,7 +136,7 @@
|
||||||
</v-card-subtitle>
|
</v-card-subtitle>
|
||||||
|
|
||||||
<v-card-text class="description">
|
<v-card-text class="description">
|
||||||
{{ assignmentResponse.data.assignment.description }}
|
{{ assignment.description }}
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
|
@ -177,9 +190,9 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
@import "@/assets/assignment.css";
|
@import "@/assets/assignment.css";
|
||||||
|
|
||||||
.progress-bar {
|
.progress-bar {
|
||||||
width: 40%;
|
width: 40%;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,26 +1,26 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, computed, onMounted, watch } from "vue";
|
import {ref, computed, onMounted, watch} from "vue";
|
||||||
import { useI18n } from "vue-i18n";
|
import {useI18n} from "vue-i18n";
|
||||||
import { useRouter } from "vue-router";
|
import {useRouter} from "vue-router";
|
||||||
import authState from "@/services/auth/auth-service.ts";
|
import authState from "@/services/auth/auth-service.ts";
|
||||||
import auth from "@/services/auth/auth-service.ts";
|
import auth from "@/services/auth/auth-service.ts";
|
||||||
import { useTeacherAssignmentsQuery, useTeacherClassesQuery } from "@/queries/teachers.ts";
|
import {useTeacherAssignmentsQuery, useTeacherClassesQuery} from "@/queries/teachers.ts";
|
||||||
import { useStudentAssignmentsQuery, useStudentClassesQuery } from "@/queries/students.ts";
|
import {useStudentAssignmentsQuery, useStudentClassesQuery} from "@/queries/students.ts";
|
||||||
import { useDeleteAssignmentMutation } from "@/queries/assignments.ts";
|
import {useDeleteAssignmentMutation} from "@/queries/assignments.ts";
|
||||||
import UsingQueryResult from "@/components/UsingQueryResult.vue";
|
import UsingQueryResult from "@/components/UsingQueryResult.vue";
|
||||||
import { asyncComputed } from "@vueuse/core";
|
|
||||||
|
|
||||||
const { t, locale } = useI18n();
|
const {t, locale} = useI18n();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const role = ref(auth.authState.activeRole);
|
const role = ref(auth.authState.activeRole);
|
||||||
const username = ref<string | undefined>(undefined);
|
const isTeacher = computed(() => role.value === "teacher");
|
||||||
const isLoading = ref(false);
|
const username = ref<string | undefined>(undefined);
|
||||||
const isError = ref(false);
|
const isLoading = ref(false);
|
||||||
const errorMessage = ref<string>("");
|
const isError = ref(false);
|
||||||
|
const errorMessage = ref<string>("");
|
||||||
|
|
||||||
// Load current user before rendering the page
|
// Load current user before rendering the page
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
isLoading.value = true;
|
isLoading.value = true;
|
||||||
try {
|
try {
|
||||||
const userObject = await authState.loadUser();
|
const userObject = await authState.loadUser();
|
||||||
|
@ -31,19 +31,17 @@
|
||||||
} finally {
|
} finally {
|
||||||
isLoading.value = false;
|
isLoading.value = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const isTeacher = computed(() => role.value === "teacher");
|
const classesQueryResult = isTeacher.value
|
||||||
const classesQueryResult = isTeacher.value
|
|
||||||
? useTeacherClassesQuery(username, true)
|
? useTeacherClassesQuery(username, true)
|
||||||
: useStudentClassesQuery(username, true);
|
: useStudentClassesQuery(username, true);
|
||||||
|
|
||||||
const assignmentsQueryResult = isTeacher.value
|
const assignmentsQueryResult = isTeacher.value
|
||||||
? useTeacherAssignmentsQuery(username, true)
|
? useTeacherAssignmentsQuery(username, true)
|
||||||
: useStudentAssignmentsQuery(username, true);
|
: useStudentAssignmentsQuery(username, true);
|
||||||
|
|
||||||
const allAssignments = asyncComputed(
|
const allAssignments = computed(() => {
|
||||||
async () => {
|
|
||||||
const assignments = assignmentsQueryResult.data.value?.assignments;
|
const assignments = assignmentsQueryResult.data.value?.assignments;
|
||||||
if (!assignments) return [];
|
if (!assignments) return [];
|
||||||
|
|
||||||
|
@ -75,32 +73,30 @@
|
||||||
|
|
||||||
return aTime - bTime;
|
return aTime - bTime;
|
||||||
});
|
});
|
||||||
},
|
});
|
||||||
[],
|
|
||||||
{ evaluating: true },
|
|
||||||
);
|
|
||||||
|
|
||||||
async function goToCreateAssignment(): Promise<void> {
|
|
||||||
|
async function goToCreateAssignment(): Promise<void> {
|
||||||
await router.push("/assignment/create");
|
await router.push("/assignment/create");
|
||||||
}
|
}
|
||||||
|
|
||||||
async function goToAssignmentDetails(id: number, clsId: string): Promise<void> {
|
async function goToAssignmentDetails(id: number, clsId: string): Promise<void> {
|
||||||
await router.push(`/assignment/${clsId}/${id}`);
|
await router.push(`/assignment/${clsId}/${id}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const { mutate, data, isSuccess } = useDeleteAssignmentMutation();
|
const {mutate, data, isSuccess} = useDeleteAssignmentMutation();
|
||||||
|
|
||||||
watch([isSuccess, data], async ([success, oldData]) => {
|
watch([isSuccess, data], async ([success, oldData]) => {
|
||||||
if (success && oldData?.assignment) {
|
if (success && oldData?.assignment) {
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
async function goToDeleteAssignment(num: number, clsId: string): Promise<void> {
|
async function goToDeleteAssignment(num: number, clsId: string): Promise<void> {
|
||||||
mutate({ cid: clsId, an: num });
|
mutate({cid: clsId, an: num});
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatDate(date?: string | Date): string {
|
function formatDate(date?: string | Date): string {
|
||||||
if (!date) return "–";
|
if (!date) return "–";
|
||||||
const d = new Date(date);
|
const d = new Date(date);
|
||||||
|
|
||||||
|
@ -115,9 +111,9 @@
|
||||||
hour: "numeric",
|
hour: "numeric",
|
||||||
minute: "2-digit",
|
minute: "2-digit",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDeadlineClass(deadline?: string | Date): string {
|
function getDeadlineClass(deadline?: string | Date): string {
|
||||||
if (!deadline) return "";
|
if (!deadline) return "";
|
||||||
|
|
||||||
const date = new Date(deadline);
|
const date = new Date(deadline);
|
||||||
|
@ -127,17 +123,17 @@
|
||||||
if (date.getTime() < now.getTime()) return "deadline-passed";
|
if (date.getTime() < now.getTime()) return "deadline-passed";
|
||||||
if (date.getTime() <= in24Hours.getTime()) return "deadline-in24hours";
|
if (date.getTime() <= in24Hours.getTime()) return "deadline-in24hours";
|
||||||
return "deadline-upcoming";
|
return "deadline-upcoming";
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
const user = await auth.loadUser();
|
const user = await auth.loadUser();
|
||||||
username.value = user?.profile?.preferred_username ?? "";
|
username.value = user?.profile?.preferred_username ?? "";
|
||||||
});
|
});
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
const user = await auth.loadUser();
|
const user = await auth.loadUser();
|
||||||
username.value = user?.profile?.preferred_username ?? "";
|
username.value = user?.profile?.preferred_username ?? "";
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -214,88 +210,87 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.assignments-container {
|
.assignments-container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.center-btn {
|
.center-btn {
|
||||||
display: block;
|
display: block;
|
||||||
margin: 0 auto 2rem auto;
|
margin: 0 auto 2rem auto;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
background-color: #10ad61;
|
background-color: #10ad61;
|
||||||
color: white;
|
color: white;
|
||||||
transition: background-color 0.2s;
|
transition: background-color 0.2s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.center-btn:hover {
|
.center-btn:hover {
|
||||||
background-color: #0e6942;
|
background-color: #0e6942;
|
||||||
}
|
}
|
||||||
|
|
||||||
.assignment-card {
|
.assignment-card {
|
||||||
padding: 1.25rem;
|
padding: 1.25rem;
|
||||||
border-radius: 16px;
|
border-radius: 16px;
|
||||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
||||||
background-color: white;
|
background-color: white;
|
||||||
transition:
|
transition: transform 0.2s,
|
||||||
transform 0.2s,
|
|
||||||
box-shadow 0.2s;
|
box-shadow 0.2s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.assignment-card:hover {
|
.assignment-card:hover {
|
||||||
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.12);
|
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.12);
|
||||||
}
|
}
|
||||||
|
|
||||||
.top-content {
|
.top-content {
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
}
|
}
|
||||||
|
|
||||||
.assignment-title {
|
.assignment-title {
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
font-size: 1.4rem;
|
font-size: 1.4rem;
|
||||||
color: #0e6942;
|
color: #0e6942;
|
||||||
margin-bottom: 0.3rem;
|
margin-bottom: 0.3rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.assignment-class,
|
.assignment-class,
|
||||||
.assignment-deadline {
|
.assignment-deadline {
|
||||||
font-size: 0.95rem;
|
font-size: 0.95rem;
|
||||||
color: #444;
|
color: #444;
|
||||||
margin-bottom: 0.2rem;
|
margin-bottom: 0.2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.class-name {
|
.class-name {
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: #097180;
|
color: #097180;
|
||||||
}
|
}
|
||||||
|
|
||||||
.assignment-deadline.deadline-passed {
|
.assignment-deadline.deadline-passed {
|
||||||
color: #d32f2f;
|
color: #d32f2f;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
.assignment-deadline.deadline-in24hours {
|
.assignment-deadline.deadline-in24hours {
|
||||||
color: #f57c00;
|
color: #f57c00;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
.spacer {
|
.spacer {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button-row {
|
.button-row {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
gap: 0.75rem;
|
gap: 0.75rem;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.no-assignments {
|
.no-assignments {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 1.2rem;
|
font-size: 1.2rem;
|
||||||
color: #777;
|
color: #777;
|
||||||
padding: 3rem 0;
|
padding: 3rem 0;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue