vbv/client/src/components/learningPath/LearningSequence.vue

194 lines
6.2 KiB
Vue

<script setup lang="ts">
import ItCheckbox from "@/components/ui/ItCheckbox.vue";
import { useCircleStore } from "@/stores/circle";
import type {
CourseCompletionStatus,
LearningContent,
LearningSequence,
} from "@/types";
import { humanizeDuration } from "@/utils/humanizeDuration";
import _ from "lodash";
import { computed } from "vue";
import LearningContentBadge from "./LearningContentTypeBadge.vue";
const props = defineProps<{
learningSequence: LearningSequence;
}>();
const circleStore = useCircleStore();
function toggleCompleted(learningContent: LearningContent) {
let completionStatus: CourseCompletionStatus = "success";
if (learningContent.completion_status === "success") {
completionStatus = "fail";
}
circleStore.markCompletion(learningContent, completionStatus);
}
const someFinished = computed(() => {
if (props.learningSequence && circleStore.circle) {
return circleStore.circle.someFinishedInLearningSequence(
props.learningSequence.translation_key
);
}
return false;
});
const allFinished = computed(() => {
if (props.learningSequence && circleStore.circle) {
return circleStore.circle.allFinishedInLearningSequence(
props.learningSequence.translation_key
);
}
return false;
});
const continueTranslationKeyTuple = computed(() => {
if (props.learningSequence && circleStore.circle) {
const lastFinished = _.findLast(
circleStore.circle.flatLearningContents,
(learningContent) => {
return learningContent.completion_status === "success";
}
);
if (!lastFinished) {
// must be the first
return [circleStore.circle.flatLearningContents[0].translation_key, true];
}
if (lastFinished && lastFinished.nextLearningContent) {
return [lastFinished.nextLearningContent.translation_key, false];
}
}
return "";
});
const learningSequenceBorderClass = computed(() => {
let result: string[] = [];
if (props.learningSequence && circleStore.circle) {
if (allFinished.value) {
result = ["border-l-4", "border-l-green-500"];
} else if (someFinished.value) {
result = ["border-l-4", "border-l-sky-500"];
} else {
result = ["border-l-gray-500"];
}
}
return result;
});
</script>
<template>
<div :id="learningSequence.slug" class="mb-8 learning-sequence">
<div class="flex items-center gap-4 mb-2 text-blue-900">
<component :is="learningSequence.icon" />
<h3 class="text-large font-semibold">
{{ learningSequence.title }}
</h3>
<div>{{ humanizeDuration(learningSequence.minutes) }}</div>
</div>
<div
class="bg-white px-4 lg:px-6 border border-gray-500"
:class="learningSequenceBorderClass"
>
<div
v-for="learningUnit in learningSequence.learningUnits"
:id="learningUnit.slug"
:key="learningUnit.id"
class="pt-3 lg:pt-6"
>
<div v-if="learningUnit.title" class="pb-3 lg:pg-6 flex gap-4 text-blue-900">
<div class="font-semibold">{{ learningUnit.title }}</div>
<div class="whitespace-nowrap">
{{ humanizeDuration(learningUnit.minutes) }}
</div>
</div>
<div
v-for="learningContent in learningUnit.learningContents"
:key="learningContent.id"
class="flex gap-4 pb-3 lg:pb-6"
>
<ItCheckbox
:model-value="learningContent.completion_status === 'success'"
:on-toggle="() => toggleCompleted(learningContent)"
:data-cy="`${learningContent.slug}`"
>
<span class="flex flex-wrap gap-4 items-center">
<div
class="cursor-pointer w-full sm:w-auto"
@click.stop="circleStore.openLearningContent(learningContent)"
>
{{ learningContent.title }}
</div>
<div
class="flex items-center gap-4 flex-col justify-between sm:flex-row sm:grow"
>
<button
v-if="
learningContent.translation_key === continueTranslationKeyTuple[0]
"
class="btn-blue order-1 sm:order-none"
data-cy="ls-continue-button"
@click.stop="circleStore.openLearningContent(learningContent)"
>
<span v-if="continueTranslationKeyTuple[1]" class="whitespace-nowrap"
>Los geht's
</span>
<span v-else class="whitespace-nowrap"> Weiter geht's </span>
</button>
<div class="hidden sm:block"></div>
<div class="w-full sm:w-auto">
<LearningContentBadge
:learning-content-type="learningContent.contents[0].type"
/>
</div>
</div>
</span>
</ItCheckbox>
</div>
<div
v-if="learningUnit.children.length"
class="hover:cursor-pointer"
:data-cy="`${learningUnit.slug}`"
@click="circleStore.openSelfEvaluation(learningUnit)"
>
<div
v-if="circleStore.calcSelfEvaluationStatus(learningUnit)"
class="flex items-center gap-4 pb-3 lg:pb-6 self-evaluation-success"
>
<it-icon-smiley-happy class="w-8 h-8 flex-none" data-cy="success" />
<div>Selbsteinschätzung: Ich kann das.</div>
</div>
<div
v-else-if="circleStore.calcSelfEvaluationStatus(learningUnit) === false"
class="flex items-center gap-4 pb-3 lg:pb-6 self-evaluation-fail"
>
<it-icon-smiley-thinking class="w-8 h-8 flex-none" data-cy="fail" />
<div>Selbsteinschätzung: Muss ich nochmals anschauen</div>
</div>
<div
v-else
class="flex items-center gap-4 pb-3 lg:pb-6 self-evaluation-unknown"
>
<it-icon-smiley-neutral class="w-8 h-8 flex-none" data-cy="unknown" />
<div>Selbsteinschätzung</div>
</div>
</div>
<hr v-if="!learningUnit.last" class="-mx-4 text-gray-500" />
</div>
</div>
</div>
</template>
<style scoped></style>