160 lines
4.8 KiB
Vue
160 lines
4.8 KiB
Vue
<script setup lang="ts">
|
|
import ItTextarea from "@/components/ui/ItTextarea.vue";
|
|
import RichText from "@/components/ui/RichText.vue";
|
|
import { useCurrentCourseSession } from "@/composables";
|
|
import { UPSERT_ASSIGNMENT_COMPLETION_MUTATION } from "@/graphql/mutations";
|
|
import type {
|
|
Assignment,
|
|
AssignmentCompletion,
|
|
AssignmentCompletionData,
|
|
CourseSessionUser,
|
|
ExpertData,
|
|
} from "@/types";
|
|
import { useMutation } from "@urql/vue";
|
|
import { useDebounceFn } from "@vueuse/core";
|
|
import * as log from "loglevel";
|
|
import { computed } from "vue";
|
|
|
|
const props = defineProps<{
|
|
assignmentUser: CourseSessionUser;
|
|
assignment: Assignment;
|
|
assignmentCompletion: AssignmentCompletion;
|
|
taskIndex: number;
|
|
allowEdit: boolean;
|
|
}>();
|
|
|
|
log.debug("EvaluationTask setup", props.taskIndex);
|
|
|
|
const courseSession = useCurrentCourseSession();
|
|
|
|
const task = computed(() => props.assignment.evaluation_tasks[props.taskIndex]);
|
|
|
|
const expertData = computed(() => {
|
|
return (props.assignmentCompletion?.completion_data?.[task.value.id]?.expert_data ?? {
|
|
points: 0,
|
|
text: "",
|
|
}) as ExpertData;
|
|
});
|
|
|
|
const text = computed(() => {
|
|
if (props.assignment.assignment_type === "CASEWORK") {
|
|
return {
|
|
evaluationCriteria: "a.Beurteilungskriterium",
|
|
evaluationReason: "assignment.evaluationReason",
|
|
evaluationReasonPlaceholder: "assignment.justificationRequiredText",
|
|
};
|
|
} else if (props.assignment.assignment_type === "PRAXIS_ASSIGNMENT") {
|
|
return {
|
|
evaluationCriteria: "Feedback",
|
|
evaluationReason: "assignment.evaluationFeedback",
|
|
evaluationReasonPlaceholder: "assignment.feedbackRequiredText",
|
|
};
|
|
} else {
|
|
return {
|
|
evaluationCriteria: "UNKNOWN ASSIGNMENT TYPE",
|
|
evaluationReason: "UNKNOWN ASSIGNMENT TYPE",
|
|
evaluationReasonPlaceholder: "UNKNOWN ASSIGNMENT TYPE",
|
|
};
|
|
}
|
|
});
|
|
|
|
function changePoints(points: number) {
|
|
log.debug("changePoints", points);
|
|
evaluateAssignmentCompletion({
|
|
[task.value.id]: {
|
|
expert_data: { points, text: expertData.value.text },
|
|
},
|
|
});
|
|
}
|
|
|
|
function onUpdateText(value: string) {
|
|
// log.debug("onUpdateText", value);
|
|
evaluateAssignmentCompletionDebounced({
|
|
[task.value.id]: {
|
|
expert_data: {
|
|
text: value,
|
|
points: expertData.value.points,
|
|
},
|
|
},
|
|
});
|
|
}
|
|
|
|
const upsertAssignmentCompletionMutation = useMutation(
|
|
UPSERT_ASSIGNMENT_COMPLETION_MUTATION
|
|
);
|
|
|
|
async function evaluateAssignmentCompletion(completionData: AssignmentCompletionData) {
|
|
log.debug("evaluateAssignmentCompletion", completionData);
|
|
|
|
upsertAssignmentCompletionMutation.executeMutation({
|
|
assignmentId: props.assignment.id,
|
|
courseSessionId: courseSession.value.id,
|
|
assignmentUserId: props.assignmentUser.id,
|
|
completionStatus: "EVALUATION_IN_PROGRESS",
|
|
completionDataString: JSON.stringify(completionData),
|
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
// @ts-ignore
|
|
id: props.assignmentCompletion?.id,
|
|
});
|
|
}
|
|
|
|
const evaluateAssignmentCompletionDebounced = useDebounceFn(
|
|
evaluateAssignmentCompletion,
|
|
300
|
|
);
|
|
</script>
|
|
|
|
<template>
|
|
<!-- eslint-disable vue/no-v-html -->
|
|
<div data-cy="evaluation-task">
|
|
<div class="text-bold mb-4 text-sm">
|
|
{{ $t(text.evaluationCriteria) }} {{ taskIndex + 1 }} /
|
|
{{ props.assignment.evaluation_tasks.length }}
|
|
{{ task.value.title }}
|
|
</div>
|
|
|
|
<h3 class="default-wagtail-rich-text mb-8" v-html="task.value.description"></h3>
|
|
|
|
<fieldset>
|
|
<div>
|
|
<div
|
|
v-for="(subTask, index) in task.value.sub_tasks"
|
|
:key="index"
|
|
class="mb-4 flex items-center last:mb-0"
|
|
:data-cy="`subtask-${subTask.value.points}`"
|
|
>
|
|
<input
|
|
:id="String(index)"
|
|
name="coursesessions"
|
|
type="radio"
|
|
:value="subTask.value.points"
|
|
:checked="expertData.points === subTask.value.points"
|
|
:disabled="!props.allowEdit"
|
|
class="focus:ring-indigo-900 h-4 w-4 border-gray-300 text-blue-900"
|
|
@change="changePoints(subTask.value.points)"
|
|
/>
|
|
<label :for="String(index)" class="ml-4 block">
|
|
<div>{{ subTask.value.title }}</div>
|
|
<RichText
|
|
v-if="subTask.value.description"
|
|
:content="subTask.value.description"
|
|
/>
|
|
<div class="text-sm text-gray-800">{{ subTask.value.points }} Punkte</div>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</fieldset>
|
|
<ItTextarea
|
|
class="mt-8"
|
|
:model-value="expertData.text ?? ''"
|
|
:label="$t(text.evaluationReason)"
|
|
:disabled="!props.allowEdit"
|
|
:placeholder="$t(text.evaluationReasonPlaceholder)"
|
|
data-cy="reason-text"
|
|
@update:model-value="onUpdateText($event)"
|
|
></ItTextarea>
|
|
</div>
|
|
</template>
|
|
|
|
<style lang="scss" scoped></style>
|