Merged in feature/VBV-521-circle-seite-inhaltstype-einheit (pull request #290)

Circle Seite Inhaltstyp Einheit

Approved-by: Christian Cueni
This commit is contained in:
Reto Aebersold 2024-02-20 07:26:49 +00:00 committed by Christian Cueni
commit 39e3a6ab75
4 changed files with 107 additions and 116 deletions

View File

@ -0,0 +1,32 @@
<script setup lang="ts">
type Category = "default" | "certificate";
export interface Props {
completed?: boolean;
category?: Category;
}
withDefaults(defineProps<Props>(), {
completed: false,
category: "default",
});
</script>
<template>
<component
:is="
completed
? 'it-icon-lc-competence-certificate-checked'
: 'it-icon-lc-competence-certificate'
"
v-if="category === 'certificate'"
class="h-[32px] w-[32px]"
></component>
<div
v-else
class="flex h-[32px] w-[32px] items-center justify-center rounded-full border"
:class="[completed ? 'border-black' : 'border-gray-500']"
>
<it-icon-check v-if="completed" class="block h-6 w-6 text-black"></it-icon-check>
</div>
</template>

View File

@ -4,28 +4,24 @@ import { showIcon } from "@/pages/learningPath/circlePage/learningSequenceUtils"
import { useCircleStore } from "@/stores/circle";
import type {
CircleType,
CourseCompletionStatus,
LearningContent,
LearningContentAssignment,
LearningContentEdoniqTest,
LearningContentWithCompletion,
LearningSequence,
} from "@/types";
import type { Ref } from "vue";
import { computed } from "vue";
import {
itCheckboxDefaultIconCheckedTailwindClass,
itCheckboxDefaultIconUncheckedTailwindClass,
} from "@/constants";
import ItCheckbox from "@/components/ui/ItCheckbox.vue";
import {
allFinishedInLearningSequence,
calcSelfEvaluationStatus,
circleFlatLearningContents,
performanceCriteriaHasStatus,
performanceCriteriaStatusCount,
someFinishedInLearningSequence,
} from "@/services/circle";
import { useCourseDataWithCompletion } from "@/composables";
import { findLastIndex } from "lodash";
import CompletionStatus from "@/components/circle/CompletionStatus.vue";
type Props = {
courseSlug: string;
@ -41,16 +37,6 @@ const props = withDefaults(defineProps<Props>(), {
const circleStore = useCircleStore();
const lpQueryResult = useCourseDataWithCompletion(props.courseSlug);
function toggleCompleted(learningContent: LearningContentWithCompletion) {
let completionStatus: CourseCompletionStatus = "SUCCESS";
if (learningContent.completion_status === "SUCCESS") {
completionStatus = "FAIL";
}
lpQueryResult.markCompletion(learningContent, completionStatus);
}
const someFinished = computed(() => {
if (props.learningSequence) {
return someFinishedInLearningSequence(props.learningSequence);
@ -116,20 +102,6 @@ function belongsToCompetenceCertificate(lc: LearningContent) {
type LearninContentWithCompetenceCertificate =
| LearningContentAssignment
| LearningContentEdoniqTest;
function checkboxIconCheckedTailwindClass(lc: LearningContent) {
if (belongsToCompetenceCertificate(lc)) {
return "bg-[url(/static/icons/icon-lc-competence-certificate-checked.svg)]";
}
return itCheckboxDefaultIconCheckedTailwindClass;
}
function checkboxIconUncheckedTailwindClass(lc: LearningContent) {
if (belongsToCompetenceCertificate(lc)) {
return "bg-[url(/static/icons/icon-lc-competence-certificate.svg)]";
}
return itCheckboxDefaultIconUncheckedTailwindClass;
}
</script>
<template>
@ -143,9 +115,6 @@ function checkboxIconUncheckedTailwindClass(lc: LearningContent) {
<h3 class="text-large font-semibold">
{{ learningSequence.title }}
</h3>
<!-- <div v-if="learningSequence.minutes > 0">-->
<!-- {{ humanizeDuration(learningSequence.minutes) }}-->
<!-- </div>-->
</div>
<ol class="border bg-white px-4 lg:px-6" :class="learningSequenceBorderClass">
@ -163,9 +132,6 @@ function checkboxIconUncheckedTailwindClass(lc: LearningContent) {
<div class="font-semibold">
{{ learningUnit.title }}
</div>
<!-- <div v-if="learningUnit.minutes > 0" class="whitespace-nowrap">-->
<!-- {{ humanizeDuration(learningUnit.minutes) }}-->
<!-- </div>-->
</div>
<ol>
<li
@ -175,43 +141,22 @@ function checkboxIconUncheckedTailwindClass(lc: LearningContent) {
>
<div class="pb-6">
<div class="flex items-center gap-4">
<div v-if="props.readonly">
<it-icon-check
v-if="learningContent.completion_status === 'SUCCESS'"
class="block h-8 w-8"
></it-icon-check>
<div v-else class="h-8 w-8"></div>
</div>
<ItCheckbox
v-else
:checkbox-item="{
value: learningContent.completion_status,
checked: learningContent.completion_status === 'SUCCESS',
}"
:data-cy="`${learningContent.slug}-checkbox`"
:icon-checked-tailwind-class="
checkboxIconCheckedTailwindClass(learningContent)
<CompletionStatus
:completed="learningContent.completion_status === 'SUCCESS'"
:category="
belongsToCompetenceCertificate(learningContent)
? 'certificate'
: 'default'
"
:icon-unchecked-tailwind-class="
checkboxIconUncheckedTailwindClass(learningContent)
"
@toggle="toggleCompleted(learningContent)"
@click="
(event: MouseEvent) => {
// when disabled open the learning content directly
if (!learningContent.can_user_self_toggle_course_completion) {
circleStore.openLearningContent(learningContent);
event.preventDefault();
event.stopPropagation();
}
}
"
/>
<div
class="flex flex-auto flex-col gap-4 xl:flex-row xl:justify-between"
class="flex flex-auto flex-col gap-4 xl:flex-row xl:items-center xl:justify-between"
>
<div class="xl:order-last">
<LearningContentBadge :learning-content="learningContent" />
<LearningContentBadge
class="py-1"
:learning-content="learningContent"
/>
</div>
<div>
@ -231,7 +176,7 @@ function checkboxIconUncheckedTailwindClass(lc: LearningContent) {
</div>
<div
v-if="belongsToCompetenceCertificate(learningContent) && !hideLinks"
class="ml-16 text-sm text-gray-800"
class="ml-12 text-sm text-gray-800"
>
{{
$t("circlePage.Dieser Inhalt gehört zu x", {
@ -276,27 +221,47 @@ function checkboxIconUncheckedTailwindClass(lc: LearningContent) {
<div
v-if="learningUnit.performance_criteria.length"
class="pb-6"
:class="{ 'cursor-pointer': !props.readonly }"
:data-cy="`${learningUnit.slug}`"
@click="!props.readonly && circleStore.openSelfEvaluation(learningUnit)"
>
<div
v-if="calcSelfEvaluationStatus(learningUnit) === 'SUCCESS'"
class="self-evaluation-success flex items-center gap-4 pb-6"
>
<it-icon-smiley-happy class="mr-4 h-8 w-8 flex-none" data-cy="success" />
<div>{{ $t("selfEvaluation.selfEvaluationYes") }}</div>
<div class="flex items-center gap-4">
<CompletionStatus />
{{ $t("a.Selbsteinschätzung") }}
</div>
<div
v-else-if="calcSelfEvaluationStatus(learningUnit) === 'FAIL'"
class="self-evaluation-fail flex items-center gap-4 pb-6"
v-if="performanceCriteriaHasStatus(learningUnit.performance_criteria)"
class="flex items-center space-x-2 pl-12"
>
<it-icon-smiley-thinking class="mr-4 h-8 w-8 flex-none" data-cy="fail" />
<div>{{ $t("selfEvaluation.selfEvaluationNo") }}</div>
</div>
<div v-else class="self-evaluation-unknown flex items-center gap-4 pb-6">
<it-icon-smiley-neutral class="mr-4 h-8 w-8 flex-none" data-cy="unknown" />
<div>{{ $t("a.Selbsteinschätzung") }}</div>
<it-icon-smiley-happy></it-icon-smiley-happy>
<span class="pr-2">
{{
performanceCriteriaStatusCount(
learningUnit.performance_criteria,
"SUCCESS"
)
}}
</span>
<it-icon-smiley-thinking></it-icon-smiley-thinking>
<span class="pr-2">
{{
performanceCriteriaStatusCount(
learningUnit.performance_criteria,
"FAIL"
)
}}
</span>
<it-icon-smiley-neutral></it-icon-smiley-neutral>
<span>
{{
performanceCriteriaStatusCount(
learningUnit.performance_criteria,
"UNKNOWN"
)
}}
</span>
</div>
</div>
</li>

View File

@ -2,7 +2,7 @@ import type {
CircleType,
CourseCompletionStatus,
LearningSequence,
LearningUnit,
LearningUnitPerformanceCriteria,
} from "@/types";
export function circleFlatChildren(circle: CircleType) {
@ -49,22 +49,15 @@ export function allFinishedInLearningSequence(ls: LearningSequence) {
});
}
export function calcSelfEvaluationStatus(
learningUnit: LearningUnit
): CourseCompletionStatus {
if (learningUnit.performance_criteria.length > 0) {
if (
learningUnit.performance_criteria.every((q) => q.completion_status === "SUCCESS")
) {
return "SUCCESS";
}
if (
learningUnit.performance_criteria.every(
(q) => q.completion_status === "FAIL" || q.completion_status === "SUCCESS"
)
) {
return "FAIL";
}
}
return "UNKNOWN";
export function performanceCriteriaStatusCount(
performanceCriteria: LearningUnitPerformanceCriteria[],
status: CourseCompletionStatus
) {
return performanceCriteria.filter((pc) => pc.completion_status === status).length;
}
export function performanceCriteriaHasStatus(
performanceCriteria: LearningUnitPerformanceCriteria[]
) {
return performanceCriteria.some((pc) => pc.completion_status !== "UNKNOWN");
}

View File

@ -1,12 +1,13 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32" fill="none">
<g clip-path="url(#clip0_2_2021)">
<circle cx="25.5" cy="18.5" r="5.5" fill="#54CE8B"/>
<path d="M7.5 11.7762L11.5938 15.87L20.4638 7" stroke="#54CE8B" stroke-width="2"/>
<path d="M29 32C28.7614 32.0004 28.5305 31.9153 28.3493 31.76L25.5 29.3173L22.6507 31.7587C22.5055 31.8831 22.3277 31.9632 22.1384 31.9897C21.949 32.0161 21.7561 31.9878 21.5824 31.9079C21.4087 31.8281 21.2615 31.7001 21.1583 31.5392C21.0551 31.3783 21.0001 31.1912 21 31V27.8C20.4707 27.9147 19.804 28 19 28H7C6.73478 28 6.48043 27.8946 6.29289 27.7071C6.10536 27.5196 6 27.2652 6 27C6 26.7348 6.10536 26.4804 6.29289 26.2929C6.48043 26.1054 6.73478 26 7 26C8.10267 26 9 25.1027 9 24C9 23.6493 9.06 23.312 9.172 23H3C1.34667 23 0 21.6533 0 20V3C0 1.34667 1.34667 0 3 0H25C26.6533 0 28 1.34667 28 3V10H26V3C25.9996 2.73489 25.8942 2.48074 25.7067 2.29328C25.5193 2.10582 25.2651 2.00035 25 2H3C2.73489 2.00035 2.48074 2.10582 2.29328 2.29328C2.10582 2.48074 2.00035 2.73489 2 3V20C2 20.5507 2.44933 21 3 21H17C17.2652 21 17.5196 21.1054 17.7071 21.2929C17.8946 21.4804 18 21.7348 18 22C18 22.2652 17.8946 22.5196 17.7071 22.7071C17.5196 22.8946 17.2652 23 17 23H12C11.7349 23.0004 11.4807 23.1058 11.2933 23.2933C11.1058 23.4807 11.0004 23.7349 11 24C11 24.728 10.8053 25.412 10.464 26H19C20.6547 26 21.4973 25.548 21.5067 25.5427C21.6595 25.458 21.8318 25.4148 22.0064 25.4171C22.1811 25.4194 22.3522 25.4673 22.5027 25.556C22.6529 25.6434 22.7778 25.7684 22.865 25.9187C22.9522 26.0691 22.9988 26.2395 23 26.4133V28.8267L24.8493 27.24C25.0308 27.0852 25.2615 27.0002 25.5 27.0002C25.7385 27.0002 25.9692 27.0852 26.1507 27.24L28 28.8267L27.9987 25.1893C27.9413 25.096 27.8747 25.052 27.7667 25.0933C26.8053 25.4533 25.788 25.5733 24.7427 25.4573C21.8933 25.132 19.512 22.8467 19.0787 20.0213C18.9155 19.0074 18.9959 17.9691 19.3133 16.9923C19.6307 16.0156 20.176 15.1284 20.904 14.404C21.6281 13.6754 22.5152 13.1298 23.492 12.8121C24.4688 12.4945 25.5072 12.414 26.5213 12.5773C27.6114 12.7501 28.6395 13.1977 29.5087 13.8779C30.3779 14.5581 31.0595 15.4484 31.4894 16.4649C31.9192 17.4815 32.083 18.5907 31.9655 19.6881C31.8479 20.7855 31.4528 21.8349 30.8173 22.7373L29.1827 21.588C29.8454 20.6417 30.1212 19.4777 29.9533 18.3347C29.6827 16.4333 28.112 14.8453 26.2187 14.5547C25.5148 14.4421 24.7942 14.4979 24.116 14.7177C23.4379 14.9374 22.8215 15.3147 22.3173 15.8187C21.8128 16.3221 21.4352 16.9383 21.2157 17.6164C20.9961 18.2945 20.9409 19.0151 21.0547 19.7187C21.3547 21.668 22.9987 23.2453 24.968 23.4707C25.6785 23.5563 26.3992 23.4698 27.0693 23.2187C27.4025 23.0929 27.7612 23.0495 28.1148 23.0922C28.4683 23.1349 28.8064 23.2625 29.1 23.464C29.672 23.8613 29.9987 24.4907 29.9987 25.1893V31C29.998 31.265 29.8924 31.5189 29.705 31.7063C29.5176 31.8937 29.265 31.9993 29 32Z" fill="black"/>
</g>
<defs>
<clipPath id="clip0_2_2021">
<rect width="32" height="32" fill="white"/>
</clipPath>
</defs>
</svg>
<g clip-path="url(#clip0_2_2021)">
<circle cx="25.5" cy="18.5" r="5.5" fill="#54CE8B"/>
<path d="M7.5 11.7762L11.5938 15.87L20.4638 7" stroke="#54CE8B" stroke-width="2" fill="none"/>
<path d="M29 32C28.7614 32.0004 28.5305 31.9153 28.3493 31.76L25.5 29.3173L22.6507 31.7587C22.5055 31.8831 22.3277 31.9632 22.1384 31.9897C21.949 32.0161 21.7561 31.9878 21.5824 31.9079C21.4087 31.8281 21.2615 31.7001 21.1583 31.5392C21.0551 31.3783 21.0001 31.1912 21 31V27.8C20.4707 27.9147 19.804 28 19 28H7C6.73478 28 6.48043 27.8946 6.29289 27.7071C6.10536 27.5196 6 27.2652 6 27C6 26.7348 6.10536 26.4804 6.29289 26.2929C6.48043 26.1054 6.73478 26 7 26C8.10267 26 9 25.1027 9 24C9 23.6493 9.06 23.312 9.172 23H3C1.34667 23 0 21.6533 0 20V3C0 1.34667 1.34667 0 3 0H25C26.6533 0 28 1.34667 28 3V10H26V3C25.9996 2.73489 25.8942 2.48074 25.7067 2.29328C25.5193 2.10582 25.2651 2.00035 25 2H3C2.73489 2.00035 2.48074 2.10582 2.29328 2.29328C2.10582 2.48074 2.00035 2.73489 2 3V20C2 20.5507 2.44933 21 3 21H17C17.2652 21 17.5196 21.1054 17.7071 21.2929C17.8946 21.4804 18 21.7348 18 22C18 22.2652 17.8946 22.5196 17.7071 22.7071C17.5196 22.8946 17.2652 23 17 23H12C11.7349 23.0004 11.4807 23.1058 11.2933 23.2933C11.1058 23.4807 11.0004 23.7349 11 24C11 24.728 10.8053 25.412 10.464 26H19C20.6547 26 21.4973 25.548 21.5067 25.5427C21.6595 25.458 21.8318 25.4148 22.0064 25.4171C22.1811 25.4194 22.3522 25.4673 22.5027 25.556C22.6529 25.6434 22.7778 25.7684 22.865 25.9187C22.9522 26.0691 22.9988 26.2395 23 26.4133V28.8267L24.8493 27.24C25.0308 27.0852 25.2615 27.0002 25.5 27.0002C25.7385 27.0002 25.9692 27.0852 26.1507 27.24L28 28.8267L27.9987 25.1893C27.9413 25.096 27.8747 25.052 27.7667 25.0933C26.8053 25.4533 25.788 25.5733 24.7427 25.4573C21.8933 25.132 19.512 22.8467 19.0787 20.0213C18.9155 19.0074 18.9959 17.9691 19.3133 16.9923C19.6307 16.0156 20.176 15.1284 20.904 14.404C21.6281 13.6754 22.5152 13.1298 23.492 12.8121C24.4688 12.4945 25.5072 12.414 26.5213 12.5773C27.6114 12.7501 28.6395 13.1977 29.5087 13.8779C30.3779 14.5581 31.0595 15.4484 31.4894 16.4649C31.9192 17.4815 32.083 18.5907 31.9655 19.6881C31.8479 20.7855 31.4528 21.8349 30.8173 22.7373L29.1827 21.588C29.8454 20.6417 30.1212 19.4777 29.9533 18.3347C29.6827 16.4333 28.112 14.8453 26.2187 14.5547C25.5148 14.4421 24.7942 14.4979 24.116 14.7177C23.4379 14.9374 22.8215 15.3147 22.3173 15.8187C21.8128 16.3221 21.4352 16.9383 21.2157 17.6164C20.9961 18.2945 20.9409 19.0151 21.0547 19.7187C21.3547 21.668 22.9987 23.2453 24.968 23.4707C25.6785 23.5563 26.3992 23.4698 27.0693 23.2187C27.4025 23.0929 27.7612 23.0495 28.1148 23.0922C28.4683 23.1349 28.8064 23.2625 29.1 23.464C29.672 23.8613 29.9987 24.4907 29.9987 25.1893V31C29.998 31.265 29.8924 31.5189 29.705 31.7063C29.5176 31.8937 29.265 31.9993 29 32Z"
fill="black"/>
</g>
<defs>
<clipPath id="clip0_2_2021">
<rect width="32" height="32" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB