diff --git a/client/src/components/selfEvaluationFeedback/FeedbackReceived.vue b/client/src/components/selfEvaluationFeedback/FeedbackReceived.vue new file mode 100644 index 00000000..7038efea --- /dev/null +++ b/client/src/components/selfEvaluationFeedback/FeedbackReceived.vue @@ -0,0 +1,79 @@ + + + + + diff --git a/client/src/components/selfEvaluationFeedback/FeedbackRequested.vue b/client/src/components/selfEvaluationFeedback/FeedbackRequested.vue new file mode 100644 index 00000000..07615ef5 --- /dev/null +++ b/client/src/components/selfEvaluationFeedback/FeedbackRequested.vue @@ -0,0 +1,41 @@ + + + + + diff --git a/client/src/components/selfEvaluationFeedback/FeedbackRequestedInformationPanel.vue b/client/src/components/selfEvaluationFeedback/FeedbackRequestedInformationPanel.vue new file mode 100644 index 00000000..9baf746d --- /dev/null +++ b/client/src/components/selfEvaluationFeedback/FeedbackRequestedInformationPanel.vue @@ -0,0 +1,26 @@ + + + diff --git a/client/src/composables.ts b/client/src/composables.ts index 094f60c2..570ad2d1 100644 --- a/client/src/composables.ts +++ b/client/src/composables.ts @@ -28,8 +28,8 @@ import type { import { useQuery } from "@urql/vue"; import orderBy from "lodash/orderBy"; import log from "loglevel"; -import type { ComputedRef, Ref } from "vue"; -import { computed, onMounted, ref, toValue, watchEffect } from "vue"; +import type { ComputedRef } from "vue"; +import { computed, onMounted, ref, watchEffect } from "vue"; export function useCurrentCourseSession() { /** @@ -487,34 +487,3 @@ export function useLearningMentors() { loading, }; } - -export function useSelfEvaluationFeedback(learningUnitId: Ref | string) { - const feedback = ref({}); - const loading = ref(false); - const exists = ref(false); - - const url = `/api/self-evaluation-feedback/requester/${toValue( - learningUnitId - )}/feedback`; - - const fetchSelfEvaluationFeedback = async () => { - loading.value = true; - const { data, statusCode } = await useCSRFFetch(url).json(); - loading.value = false; - - if (statusCode.value === 404) { - exists.value = false; - return; - } else { - exists.value = true; - feedback.value = data.value; - } - }; - onMounted(fetchSelfEvaluationFeedback); - - return { - feedback, - exists, - loading, - }; -} diff --git a/client/src/pages/learningPath/selfEvaluationPage/SelfEvaluation.vue b/client/src/pages/learningPath/selfEvaluationPage/SelfEvaluation.vue index 1efbe2f7..d9d61d04 100644 --- a/client/src/pages/learningPath/selfEvaluationPage/SelfEvaluation.vue +++ b/client/src/pages/learningPath/selfEvaluationPage/SelfEvaluation.vue @@ -15,24 +15,16 @@ import SelfEvaluationSubmit from "@/pages/learningPath/selfEvaluationPage/SelfEv log.debug("LearningContent.vue setup"); -const circleStore = useCircleStore(); -const courseSession = useCurrentCourseSession(); -const courseCompletionData = useCourseDataWithCompletion(); - -const questionIndex = useRouteQuery("step", "0", { transform: Number, mode: "push" }); -const previousRoute = getPreviousRoute(); - const props = defineProps<{ learningUnit: LearningUnit; circle: CircleType; }>(); -const learningUnitHasFeedbackPage = computed( - () => props.learningUnit?.feedback_user !== "NO_FEEDBACK" -); +const circleStore = useCircleStore(); +const courseSession = useCurrentCourseSession(); +const courseCompletionData = useCourseDataWithCompletion(); const questions = computed(() => props.learningUnit?.performance_criteria ?? []); - const numPages = computed(() => { if (learningUnitHasFeedbackPage.value) { return questions.value.length + 1; @@ -41,6 +33,13 @@ const numPages = computed(() => { } }); +const questionIndex = useRouteQuery("step", "0", { transform: Number, mode: "push" }); +const previousRoute = getPreviousRoute(); + +const learningUnitHasFeedbackPage = computed( + () => props.learningUnit?.feedback_user !== "NO_FEEDBACK" +); + const currentQuestion = computed(() => questions.value[questionIndex.value]); const showPreviousButton = computed(() => questionIndex.value != 0); const showNextButton = computed( diff --git a/client/src/pages/learningPath/selfEvaluationPage/SelfEvaluationRequestFeedback.vue b/client/src/pages/learningPath/selfEvaluationPage/SelfEvaluationRequestFeedback.vue index e658e5ca..d2f174f9 100644 --- a/client/src/pages/learningPath/selfEvaluationPage/SelfEvaluationRequestFeedback.vue +++ b/client/src/pages/learningPath/selfEvaluationPage/SelfEvaluationRequestFeedback.vue @@ -1,25 +1,29 @@ diff --git a/client/src/services/selfEvaluationFeedback.ts b/client/src/services/selfEvaluationFeedback.ts new file mode 100644 index 00000000..c80f6f0a --- /dev/null +++ b/client/src/services/selfEvaluationFeedback.ts @@ -0,0 +1,60 @@ +import { useCSRFFetch } from "@/fetchHelpers"; +import type { User } from "@/types"; +import type { Ref } from "vue"; +import { computed, onMounted, ref, toValue } from "vue"; + +export interface FeedbackRequest { + learning_unit_id: number; + circle_name: string; + // submitted => provider submitted (released) his/her feedback + feedback_submitted: boolean; + feedback_requester_user: User; + feedback_provider_user: User; + criteria: Criterion[]; +} + +interface Criterion { + course_completion_id: string; + title: string; + self_assessment: "FAIL" | "SUCCESS" | "UNKNOWN"; + feedback_assessment: "FAIL" | "SUCCESS" | "UNKNOWN"; +} + +export function useSelfEvaluationFeedback(learningUnitId: Ref | string) { + const feedback = ref(); + const loading = ref(false); + const error = ref(); + + const url = computed( + () => `/api/self-evaluation-feedback/requester/${toValue(learningUnitId)}/feedback` + ); + + const fetchSelfEvaluationFeedback = async () => { + feedback.value = undefined; + error.value = undefined; + + loading.value = true; + const { data, statusCode, error: _error } = await useCSRFFetch(url.value).json(); + loading.value = false; + + if (_error.value) { + error.value = _error; + feedback.value = undefined; + return; + } + + if (statusCode.value === 404) { + feedback.value = undefined; + } else { + feedback.value = data.value; + } + }; + + onMounted(fetchSelfEvaluationFeedback); + + return { + feedback, + error, + loading, + }; +} diff --git a/client/src/types.ts b/client/src/types.ts index 19146357..88c08e93 100644 --- a/client/src/types.ts +++ b/client/src/types.ts @@ -589,3 +589,16 @@ export interface FeedbackData { }; feedbackType: FeedbackType; } + +export type User = { + id: string; + first_name: string; + last_name: string; + email: string; + username: string; + avatar_url: string; + organisation: string | null; + is_superuser: boolean; + course_session_experts: any[]; + language: string; +}; diff --git a/server/vbv_lernwelt/assignment/migrations/0012_auto_20240124_1004.py b/server/vbv_lernwelt/assignment/migrations/0012_auto_20240124_1004.py index 3a5a91be..0489bb0b 100644 --- a/server/vbv_lernwelt/assignment/migrations/0012_auto_20240124_1004.py +++ b/server/vbv_lernwelt/assignment/migrations/0012_auto_20240124_1004.py @@ -4,20 +4,33 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('assignment', '0011_assignment_solution_sample'), + ("assignment", "0011_assignment_solution_sample"), ] operations = [ migrations.AlterField( - model_name='assignment', - name='assignment_type', - field=models.CharField(choices=[('PRAXIS_ASSIGNMENT', 'PRAXIS_ASSIGNMENT'), ('CASEWORK', 'CASEWORK'), ('PREP_ASSIGNMENT', 'PREP_ASSIGNMENT'), ('REFLECTION', 'REFLECTION'), ('CONDITION_ACCEPTANCE', 'CONDITION_ACCEPTANCE'), ('EDONIQ_TEST', 'EDONIQ_TEST')], default='CASEWORK', max_length=50), + model_name="assignment", + name="assignment_type", + field=models.CharField( + choices=[ + ("PRAXIS_ASSIGNMENT", "PRAXIS_ASSIGNMENT"), + ("CASEWORK", "CASEWORK"), + ("PREP_ASSIGNMENT", "PREP_ASSIGNMENT"), + ("REFLECTION", "REFLECTION"), + ("CONDITION_ACCEPTANCE", "CONDITION_ACCEPTANCE"), + ("EDONIQ_TEST", "EDONIQ_TEST"), + ], + default="CASEWORK", + max_length=50, + ), ), migrations.AlterField( - model_name='assignment', - name='needs_expert_evaluation', - field=models.BooleanField(default=False, help_text='Muss der Auftrag durch eine/n Experten/in oder eine Lernbegleitung beurteilt werden?'), + model_name="assignment", + name="needs_expert_evaluation", + field=models.BooleanField( + default=False, + help_text="Muss der Auftrag durch eine/n Experten/in oder eine Lernbegleitung beurteilt werden?", + ), ), ] diff --git a/server/vbv_lernwelt/core/create_default_users.py b/server/vbv_lernwelt/core/create_default_users.py index aef8516d..b7d61b37 100644 --- a/server/vbv_lernwelt/core/create_default_users.py +++ b/server/vbv_lernwelt/core/create_default_users.py @@ -346,11 +346,11 @@ def create_default_users(default_password="test"): _create_user( _id=TEST_MENTOR1_USER_ID, email="test-mentor1@example.com", - first_name="[Mentor]", - last_name="Mentor", + first_name="Micheala", + last_name="Weber-Mentor", password=default_password, language="de", - avatar_url="", + avatar_url="/static/avatars/uk1.patrizia.huggel.jpg", ) diff --git a/server/vbv_lernwelt/course_session/migrations/0006_auto_20240124_1004.py b/server/vbv_lernwelt/course_session/migrations/0006_auto_20240124_1004.py index 2921f1da..9aab3304 100644 --- a/server/vbv_lernwelt/course_session/migrations/0006_auto_20240124_1004.py +++ b/server/vbv_lernwelt/course_session/migrations/0006_auto_20240124_1004.py @@ -1,25 +1,36 @@ # Generated by Django 3.2.20 on 2024-01-24 09:04 -from django.db import migrations, models import django.db.models.deletion +from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('duedate', '0008_auto_20231108_0747'), - ('course_session', '0005_auto_20230825_1723'), + ("duedate", "0008_auto_20231108_0747"), + ("course_session", "0005_auto_20230825_1723"), ] operations = [ migrations.AlterField( - model_name='coursesessionassignment', - name='evaluation_deadline', - field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='assignment_evaluation_deadline', to='duedate.duedate'), + model_name="coursesessionassignment", + name="evaluation_deadline", + field=models.OneToOneField( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="assignment_evaluation_deadline", + to="duedate.duedate", + ), ), migrations.AlterField( - model_name='coursesessionassignment', - name='submission_deadline', - field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='assignment_submission_deadline', to='duedate.duedate'), + model_name="coursesessionassignment", + name="submission_deadline", + field=models.OneToOneField( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="assignment_submission_deadline", + to="duedate.duedate", + ), ), ]