vbv/client/src/pages/learningPath/learningContentPage/assignment/AssignmentTaskView.vue

145 lines
4.2 KiB
Vue

<script setup lang="ts">
import ItCheckbox from "@/components/ui/ItCheckbox.vue";
import ItTextarea from "@/components/ui/ItTextarea.vue";
import { useCurrentCourseSession } from "@/composables";
import { UPSERT_ASSIGNMENT_COMPLETION_MUTATION } from "@/graphql/mutations";
import type {
AssignmentCompletion,
AssignmentCompletionData,
AssignmentTask,
UserDataConfirmation,
UserDataText,
} from "@/types";
import { useMutation } from "@urql/vue";
import { useDebounceFn } from "@vueuse/core";
import log from "loglevel";
import { computed, reactive } from "vue";
const props = defineProps<{
assignmentId: number;
learningContentId: number;
task: AssignmentTask;
assignmentCompletion?: AssignmentCompletion;
}>();
const checkboxState = reactive({} as Record<string, boolean>);
const courseSession = useCurrentCourseSession();
const upsertAssignmentCompletionMutation = useMutation(
UPSERT_ASSIGNMENT_COMPLETION_MUTATION
);
async function upsertAssignmentCompletion(completion_data: AssignmentCompletionData) {
try {
await upsertAssignmentCompletionMutation.executeMutation({
assignmentId: props.assignmentId.toString(),
courseSessionId: courseSession.value.id.toString(),
learningContentId: props.learningContentId.toString(),
completionDataString: JSON.stringify(completion_data),
completionStatus: "IN_PROGRESS",
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
id: props.assignmentCompletion?.id,
});
log.debug("Saved user input");
} catch (error) {
log.error("Could not save user input", error);
}
}
const upsertAssignmentCompletionDebounced = useDebounceFn(
upsertAssignmentCompletion,
500
);
function getCompletionDataForUserInput(id: string) {
return props.assignmentCompletion?.completion_data[id];
}
const onUpdateText = (id: string, value: string) => {
const data: AssignmentCompletionData = {};
data[id] = {
user_data: {
text: value,
} as UserDataText,
};
upsertAssignmentCompletionDebounced(data);
};
const onUpdateConfirmation = (id: string, value: boolean) => {
const data: AssignmentCompletionData = {};
data[id] = {
user_data: {
confirmation: value,
} as UserDataConfirmation,
};
upsertAssignmentCompletion(data);
};
const getBlockData = (id: string) => {
const userData = getCompletionDataForUserInput(id)?.user_data;
if (userData && "text" in userData) {
return userData.text;
} else if (userData && "confirmation" in userData) {
return userData.confirmation;
}
return null;
};
const onToggleCheckbox = (id: string) => {
checkboxState[id] = !checkboxState[id];
onUpdateConfirmation(id, checkboxState[id]);
};
const completionStatus = computed(() => {
return props.assignmentCompletion?.completion_status ?? "IN_PROGRESS";
});
</script>
<template>
<!-- eslint-disable vue/no-v-html -->
<div class="flex flex-col space-y-10">
<div v-for="(block, index) in props.task.value.content" :key="block.id">
<div v-if="block.type === 'explanation'">
<p class="default-wagtail-rich-text text-large" v-html="block.value.text"></p>
</div>
<div v-if="block.type === 'user_confirmation'">
<ItCheckbox
:checkbox-item="{
label: block.value.text,
value: `confirmation-${index}`,
checked: getBlockData(block.id) as boolean,
}"
:disabled="completionStatus !== 'IN_PROGRESS'"
@toggle="onToggleCheckbox(block.id)"
></ItCheckbox>
</div>
<div v-if="block.type === 'user_text_input'">
<p
v-if="block.value.text"
class="text-large pb-4"
v-html="block.value.text"
></p>
<ItTextarea
class="w-[300px] sm:w-[600px]"
:model-value="(getBlockData(block.id) as string) ?? ''"
:cy-key="`user-text-input-${index}`"
:disabled="completionStatus !== 'IN_PROGRESS'"
label=""
@update:model-value="onUpdateText(block.id, $event)"
></ItTextarea>
</div>
</div>
</div>
<div v-if="props.task.value.file_submission_required">
<p class="text-large">Datei hochladen</p>
<p class="text-sm text-gray-900">
Mögliche Formate: .JPG, .PNG, .PDF, .DOC, .MOV, .PPT
</p>
</div>
</template>