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

139 lines
4.1 KiB
Vue

<script setup lang="ts">
import ItCheckbox from "@/components/ui/ItCheckbox.vue";
import ItTextarea from "@/components/ui/ItTextarea.vue";
import { useAssignmentStore } from "@/stores/assignmentStore";
import { useCourseSessionsStore } from "@/stores/courseSessions";
import type {
AssignmentCompletionData,
AssignmentTask,
UserDataConfirmation,
UserDataText,
} from "@/types";
import { useDebounceFn } from "@vueuse/core";
import dayjs from "dayjs";
import { computed, reactive, ref } from "vue";
const props = defineProps<{
assignmentId: number;
task: AssignmentTask;
}>();
const lastSaved = ref(dayjs());
const lastSaveUnsuccessful = ref(false);
const checkboxState = reactive({} as Record<string, boolean>);
const courseSessionStore = useCourseSessionsStore();
const assignmentStore = useAssignmentStore();
async function upsertAssignmentCompletion(completion_data: AssignmentCompletionData) {
try {
const courseSessionId = courseSessionStore.currentCourseSession?.id;
if (!courseSessionId) {
console.error("Invalid courseSessionId");
return;
}
await assignmentStore.upsertAssignmentCompletion({
assignment_id: props.assignmentId,
course_session_id: courseSessionId,
completion_data: completion_data,
completion_status: "in_progress",
});
lastSaved.value = dayjs();
lastSaveUnsuccessful.value = false;
console.debug("Saved user input");
} catch (error) {
lastSaveUnsuccessful.value = true;
console.error("Could not save user input", error);
}
}
const upsertAssignmentCompletionDebounced = useDebounceFn(
upsertAssignmentCompletion,
500
);
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 = assignmentStore.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 assignmentStore.assignmentCompletion?.completion_status ?? "in_progress";
});
</script>
<template>
<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 class="text-large pb-4">{{ block.value.text }}</p>
<ItTextarea
: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 v-if="lastSaveUnsuccessful" class="text-red-600">
{{ $t("assignment.lastChangesNotSaved") }}
</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>