Refactor circle code to Circle class
This commit is contained in:
parent
cc293400b4
commit
7022827cf3
|
|
@ -1,10 +1,10 @@
|
|||
<script setup lang="ts">
|
||||
import * as d3 from "d3";
|
||||
import {computed, onMounted} from "vue";
|
||||
import {computed} from "vue";
|
||||
import * as _ from 'underscore'
|
||||
import {useCircleStore} from '@/stores/circle';
|
||||
|
||||
const props = defineProps<{
|
||||
circleStore: {},
|
||||
width: {
|
||||
default: 500,
|
||||
type: number,
|
||||
|
|
@ -18,28 +18,26 @@ const props = defineProps<{
|
|||
},
|
||||
}>()
|
||||
|
||||
const circleStore = useCircleStore();
|
||||
|
||||
function someFinished(learningSequence) {
|
||||
return props.circleStore.flatChildren.filter((lc) => {
|
||||
return lc.completed && lc.parentLearningSequence?.translation_key === learningSequence.translation_key;
|
||||
}).length > 0;
|
||||
if (circleStore.circle) {
|
||||
return circleStore.circle.someFinishedInLearningSequence(learningSequence.translation_key);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
const pieData = computed(() => {
|
||||
const circle = props.circleStore.circleData, completionData = props.circleStore.completionData
|
||||
console.log('initial of compute pie data ', circle, completionData)
|
||||
const circle = circleStore.circle
|
||||
console.log('initial of compute pie data ', circle)
|
||||
|
||||
if (circle && completionData) {
|
||||
console.log('initial of compute pie data ', circle, completionData)
|
||||
if (circle) {
|
||||
console.log('initial of compute pie data ', circle)
|
||||
let learningSequences = _.filter(circle.children, (child) => {
|
||||
return child.type === 'learnpath.LearningSequence';
|
||||
})
|
||||
|
||||
const completionDataByPageId = _.object(_.map(completionData, function (item) {
|
||||
return [item.page_key, item]
|
||||
}))
|
||||
|
||||
let pieWeights = new Array(Math.max(learningSequences.length, 1)).fill(1)
|
||||
let pieGenerator = d3.pie()
|
||||
let angles = pieGenerator(pieWeights)
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
<script setup lang="ts">
|
||||
import type {Circle} from '@/types';
|
||||
import {Circle} from '@/services/circle';
|
||||
|
||||
const props = defineProps<{
|
||||
circleData: Circle
|
||||
circle: Circle
|
||||
}>()
|
||||
|
||||
</script>
|
||||
|
|
@ -17,7 +17,7 @@ const props = defineProps<{
|
|||
</div>
|
||||
|
||||
|
||||
<h1 class="">Überblick: Circle "{{ circleData.title }}"</h1>
|
||||
<h1 class="">Überblick: Circle "{{ circle.title }}"</h1>
|
||||
|
||||
<p class="mt-8 text-xl">Hier zeigen wir dir, was du in diesem Circle lernen wirst.</p>
|
||||
|
||||
|
|
@ -25,7 +25,7 @@ const props = defineProps<{
|
|||
<h3>Du wirst in der Lage sein, ... </h3>
|
||||
|
||||
<ul class="mt-4">
|
||||
<li class="text-xl flex items-center" v-for="goal in circleData.goals" :key="goal.id">
|
||||
<li class="text-xl flex items-center" v-for="goal in circle.goals" :key="goal.id">
|
||||
<it-icon-check class="mt-4 hidden lg:block w-12 h-12 text-sky-500 flex-none"></it-icon-check>
|
||||
<div class="mt-4">{{ goal.value }}</div>
|
||||
</li>
|
||||
|
|
@ -38,7 +38,7 @@ const props = defineProps<{
|
|||
|
||||
<ul class="grid grid-cols-1 lg:grid-cols-3 auto-rows-fr gap-6 mt-8">
|
||||
<li
|
||||
v-for="jobSituation in circleData.job_situations"
|
||||
v-for="jobSituation in circle.job_situations"
|
||||
:key="jobSituation.id"
|
||||
class="job-situation border border-gray-500 p-4 text-xl flex items-center"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -15,10 +15,8 @@ function toggleCompleted(learningContent: LearningContent) {
|
|||
}
|
||||
|
||||
const someFinished = computed(() => {
|
||||
if (props.learningSequence) {
|
||||
return circleStore.flatChildren.filter((lc) => {
|
||||
return lc.completed && lc.parentLearningSequence?.translation_key === props.learningSequence.translation_key;
|
||||
}).length > 0;
|
||||
if (props.learningSequence && circleStore.circle) {
|
||||
return circleStore.circle.someFinishedInLearningSequence(props.learningSequence.translation_key);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,13 @@
|
|||
import type {CircleChild, LearningContent, LearningSequence, LearningUnit} from '@/types';
|
||||
import type {
|
||||
CircleChild,
|
||||
CircleCompletion,
|
||||
CircleGoal,
|
||||
CircleInterface,
|
||||
CircleJobSituation,
|
||||
LearningContent,
|
||||
LearningSequence,
|
||||
LearningUnit
|
||||
} from '@/types';
|
||||
|
||||
|
||||
function _createEmptyLearningUnit(parentLearningSequence: LearningSequence): LearningUnit {
|
||||
|
|
@ -98,3 +107,74 @@ export function parseLearningSequences (children: CircleChild[]): LearningSequen
|
|||
return result;
|
||||
}
|
||||
|
||||
export class Circle implements CircleInterface {
|
||||
readonly type = 'learnpath.Circle';
|
||||
readonly learningSequences: LearningSequence[];
|
||||
readonly completed: boolean;
|
||||
|
||||
constructor(
|
||||
public readonly id: number,
|
||||
public readonly slug: string,
|
||||
public readonly title: string,
|
||||
public readonly translation_key: string,
|
||||
public description: string,
|
||||
public children: CircleChild[],
|
||||
public goals: CircleGoal[],
|
||||
public job_situations: CircleJobSituation[],
|
||||
) {
|
||||
this.learningSequences = parseLearningSequences(this.children);
|
||||
this.completed = false;
|
||||
}
|
||||
|
||||
public static fromJson(json: any): Circle {
|
||||
// TODO add error checking when the data does not conform to the schema
|
||||
return new Circle(
|
||||
json.id,
|
||||
json.slug,
|
||||
json.title,
|
||||
json.translation_key,
|
||||
json.description,
|
||||
json.children,
|
||||
json.goals,
|
||||
json.job_situations,
|
||||
)
|
||||
}
|
||||
|
||||
public get flatChildren(): CircleChild[] {
|
||||
const result: CircleChild[] = [];
|
||||
this.learningSequences.forEach((learningSequence) => {
|
||||
learningSequence.learningUnits.forEach((learningUnit) => {
|
||||
learningUnit.children.forEach((learningUnitQuestion) => {
|
||||
result.push(learningUnitQuestion);
|
||||
})
|
||||
learningUnit.learningContents.forEach((learningContent) => {
|
||||
result.push(learningContent);
|
||||
});
|
||||
});
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
public someFinishedInLearningSequence(translationKey: string): boolean {
|
||||
if (translationKey) {
|
||||
return this.flatChildren.filter((lc) => {
|
||||
return lc.completed && lc.parentLearningSequence?.translation_key === translationKey;
|
||||
}).length > 0;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public parseCompletionData(completionData: CircleCompletion[]) {
|
||||
this.flatChildren.forEach((page) => {
|
||||
const pageIndex = completionData.findIndex((e) => {
|
||||
return e.page_key === page.translation_key;
|
||||
});
|
||||
if (pageIndex >= 0) {
|
||||
page.completed = completionData[pageIndex].completed;
|
||||
} else {
|
||||
page.completed = undefined;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,14 +2,13 @@ import * as log from 'loglevel';
|
|||
|
||||
import {defineStore} from 'pinia'
|
||||
|
||||
import type {Circle, CircleChild, CircleCompletion, LearningContent, LearningUnit, LearningUnitQuestion} from '@/types'
|
||||
import type {LearningContent, LearningUnit, LearningUnitQuestion} from '@/types'
|
||||
import {Circle} from '@/services/circle'
|
||||
import {itGet, itPost} from '@/fetchHelpers';
|
||||
import {parseLearningSequences} from '@/services/circle';
|
||||
import {useAppStore} from '@/stores/app';
|
||||
|
||||
export type CircleStoreState = {
|
||||
circleData: Circle;
|
||||
completionData: CircleCompletion[];
|
||||
circle: Circle | undefined;
|
||||
currentLearningContent: LearningContent | undefined;
|
||||
currentSelfEvaluation: LearningUnit | undefined;
|
||||
page: 'INDEX' | 'OVERVIEW' | 'LEARNING_CONTENT' | 'SELF_EVALUATION';
|
||||
|
|
@ -19,7 +18,7 @@ export const useCircleStore = defineStore({
|
|||
id: 'circle',
|
||||
state: () => {
|
||||
return {
|
||||
circleData: {},
|
||||
circle: undefined,
|
||||
completionData: {},
|
||||
currentLearningContent: undefined,
|
||||
currentSelfEvaluation: undefined,
|
||||
|
|
@ -28,27 +27,15 @@ export const useCircleStore = defineStore({
|
|||
},
|
||||
getters: {
|
||||
flatChildren: (state) => {
|
||||
const result:CircleChild[] = [];
|
||||
state.circleData.learningSequences.forEach((learningSequence) => {
|
||||
learningSequence.learningUnits.forEach((learningUnit) => {
|
||||
learningUnit.children.forEach((learningUnitQuestion) => {
|
||||
result.push(learningUnitQuestion);
|
||||
})
|
||||
learningUnit.learningContents.forEach((learningContent) => {
|
||||
result.push(learningContent);
|
||||
});
|
||||
});
|
||||
});
|
||||
return result;
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
async loadCircle(slug: string) {
|
||||
try {
|
||||
this.circleData = await itGet(`/learnpath/api/circle/${slug}/`);
|
||||
this.circleData.learningSequences = parseLearningSequences(this.circleData.children);
|
||||
this.completionData = await itGet(`/api/completion/circle/${this.circleData.translation_key}/`);
|
||||
this.parseCompletionData();
|
||||
const circleData = await itGet(`/learnpath/api/circle/${slug}/`);
|
||||
this.circle = Circle.fromJson(circleData);
|
||||
const completionData = await itGet(`/api/completion/circle/${this.circle.translation_key}/`);
|
||||
this.circle.parseCompletionData(completionData);
|
||||
} catch (error) {
|
||||
log.error(error);
|
||||
return error
|
||||
|
|
@ -57,28 +44,18 @@ export const useCircleStore = defineStore({
|
|||
async markCompletion(page: LearningContent | LearningUnitQuestion, flag = true) {
|
||||
try {
|
||||
page.completed = flag;
|
||||
this.completionData = await itPost('/api/completion/circle/mark/', {
|
||||
const completionData = await itPost('/api/completion/circle/mark/', {
|
||||
page_key: page.translation_key,
|
||||
completed: page.completed,
|
||||
});
|
||||
this.parseCompletionData();
|
||||
if (this.circle) {
|
||||
this.circle.parseCompletionData(completionData);
|
||||
}
|
||||
} catch (error) {
|
||||
log.error(error);
|
||||
return error
|
||||
}
|
||||
},
|
||||
parseCompletionData() {
|
||||
this.flatChildren.forEach((page) => {
|
||||
const pageIndex = this.completionData.findIndex((e) => {
|
||||
return e.page_key === page.translation_key;
|
||||
});
|
||||
if (pageIndex >= 0) {
|
||||
page.completed = this.completionData[pageIndex].completed;
|
||||
} else {
|
||||
page.completed = undefined;
|
||||
}
|
||||
});
|
||||
},
|
||||
openLearningContent(learningContent: LearningContent) {
|
||||
this.currentLearningContent = learningContent;
|
||||
const appStore = useAppStore();
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import {parseLearningSequences} from '@/services/circle';
|
||||
|
||||
export interface LearningContentBlock {
|
||||
type: 'web-based-training' | 'competence' | 'exercise' | 'knowledge';
|
||||
value: {
|
||||
|
|
@ -46,10 +48,10 @@ export interface CircleJobSituation {
|
|||
}
|
||||
|
||||
export interface LearningWagtailPage {
|
||||
id: number;
|
||||
title: string;
|
||||
slug: string;
|
||||
translation_key: string;
|
||||
readonly id: number;
|
||||
readonly title: string;
|
||||
readonly slug: string;
|
||||
readonly translation_key: string;
|
||||
completed?: boolean;
|
||||
}
|
||||
|
||||
|
|
@ -105,15 +107,17 @@ export interface CircleCompletion {
|
|||
json_data: any;
|
||||
}
|
||||
|
||||
export interface Circle extends LearningWagtailPage {
|
||||
type: 'learnpath.Circle';
|
||||
children: CircleChild[];
|
||||
description: string;
|
||||
export interface CircleInterface extends LearningWagtailPage {
|
||||
readonly type: 'learnpath.Circle';
|
||||
readonly children: CircleChild[];
|
||||
readonly description: string;
|
||||
readonly goals: CircleGoal[];
|
||||
readonly job_situations: CircleJobSituation[];
|
||||
learningSequences: LearningSequence[];
|
||||
goals: CircleGoal[];
|
||||
job_situations: CircleJobSituation[];
|
||||
}
|
||||
|
||||
|
||||
|
||||
export interface CircleDiagramData {
|
||||
index: number
|
||||
title: string
|
||||
|
|
|
|||
|
|
@ -35,15 +35,15 @@ onMounted(async () => {
|
|||
<div v-else-if="circleStore.page === 'SELF_EVALUATION'">
|
||||
<SelfEvaluation :key="circleStore.currentSelfEvaluation.translation_key"/>
|
||||
</div>
|
||||
<div v-else>
|
||||
<div v-else-if="circleStore.circle">
|
||||
<div class="circle">
|
||||
<div class="flex flex-col lg:flex-row">
|
||||
<div class="flex-initial lg:w-128 px-4 py-4 lg:px-8 lg:py-8">
|
||||
<h1 class="text-blue-dark text-7xl">
|
||||
{{ circleStore.circleData.title }}
|
||||
{{ circleStore.circle.title }}
|
||||
</h1>
|
||||
|
||||
<div v-if="circleStore.circleData.learningSequences && circleStore.flatChildren" class="w-full mt-8">
|
||||
<div v-if="circleStore.circle.learningSequences && circleStore.circle.flatChildren" class="w-full mt-8">
|
||||
<CircleDiagram :circle-store="circleStore"></CircleDiagram>
|
||||
</div>
|
||||
|
||||
|
|
@ -65,7 +65,7 @@ onMounted(async () => {
|
|||
<div class="block border border-gray-500 mt-8 p-6">
|
||||
<h3 class="text-blue-dark">Das lernst du in diesem Circle.</h3>
|
||||
<div class="prose mt-4">
|
||||
{{ circleStore.circleData.description }}
|
||||
{{ circleStore.circle.description }}
|
||||
</div>
|
||||
|
||||
<button class="btn-primary mt-4" @click="circleStore.page = 'OVERVIEW'">Erfahre mehr dazu</button>
|
||||
|
|
@ -83,12 +83,11 @@ onMounted(async () => {
|
|||
|
||||
<div class="flex-auto bg-gray-100 px-4 py-8 lg:px-24">
|
||||
<div
|
||||
v-for="learningSequence in circleStore.circleData.learningSequences"
|
||||
v-for="learningSequence in circleStore.circle.learningSequences"
|
||||
:key="learningSequence.translation_key"
|
||||
>
|
||||
<LearningSequence
|
||||
:learning-sequence="learningSequence"
|
||||
:completion-data="circleStore.completionData"
|
||||
></LearningSequence>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue