145 lines
4.2 KiB
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>
|