vbv/client/src/components/assignment/evaluation/EvaluationTask.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>