Refactor learningPath views

This commit is contained in:
Daniel Egger 2022-07-04 11:52:05 +02:00
parent 7022827cf3
commit cbbf4e42a2
5 changed files with 118 additions and 88 deletions

View File

@ -1,6 +1,6 @@
<script> <script>
import * as d3 from 'd3' import * as d3 from 'd3';
import * as _ from 'underscore' import { useLearningPathStore } from '../../stores/learningPath';
export default { export default {
props: { props: {
@ -157,23 +157,31 @@ export default {
type: Number, type: Number,
}, },
}, },
setup() {
const learningPathStore = useLearningPathStore()
return { learningPathStore }
},
computed: { computed: {
viewBox() { viewBox() {
return `0 0 ${this.width} ${this.height* 1.5}` return `0 0 ${this.width} ${this.height* 1.5}`
}, },
circles() { circles() {
if (this.learningPathStore.learningPath) {
let internalCircles = _.flatten(_.pluck(this.learningPathContents.topics, 'circles')) let internalCircles = this.learningPathStore.learningPath.topics.flatMap(topic => topic.circles);
_.forEach(internalCircles, function (circle) { // console.log(internalCircles);
let pieWeights = new Array(Math.max(circle.learning_sequences.length, 1)).fill(1) internalCircles.forEach((circle) => {
let pieGenerator = d3.pie() let pieWeights = new Array(Math.max(circle.learningSequences.length, 1)).fill(1)
let pieData = pieGenerator(pieWeights) let pieGenerator = d3.pie()
_.forEach(pieData, function (pie) { let pieData = pieGenerator(pieWeights)
pie.done = circle.learning_sequences.length === 0 ? false : circle.learning_sequences[parseInt(pie.index)].done // _.forEach(pieData, function(pie) {
}) // pie.done = circle.learning_sequences.length === 0 ? false : circle.learning_sequences[parseInt(pie.index)].done
circle.pieData = pieData // })
}) circle.pieData = pieData
return internalCircles });
return internalCircles
}
return [];
}, },
svg() { svg() {
return d3.select('.learning-path-visualization') return d3.select('.learning-path-visualization')

View File

@ -2,11 +2,11 @@ import type {
CircleChild, CircleChild,
CircleCompletion, CircleCompletion,
CircleGoal, CircleGoal,
CircleInterface,
CircleJobSituation, CircleJobSituation,
LearningContent, LearningContent,
LearningSequence, LearningSequence,
LearningUnit LearningUnit,
LearningWagtailPage
} from '@/types'; } from '@/types';
@ -107,7 +107,7 @@ export function parseLearningSequences (children: CircleChild[]): LearningSequen
return result; return result;
} }
export class Circle implements CircleInterface { export class Circle implements LearningWagtailPage {
readonly type = 'learnpath.Circle'; readonly type = 'learnpath.Circle';
readonly learningSequences: LearningSequence[]; readonly learningSequences: LearningSequence[];
readonly completed: boolean; readonly completed: boolean;

View File

@ -0,0 +1,59 @@
import * as log from 'loglevel';
import {defineStore} from 'pinia'
import type {LearningPath, Topic} from '@/types'
import {itGet} from '@/fetchHelpers';
import {Circle} from '@/services/circle';
export type LearningPathStoreState = {
learningPath: LearningPath;
}
export const useLearningPathStore = defineStore({
id: 'learningPath',
state: () => {
return {
learningPath: undefined,
} as LearningPathStoreState;
},
getters: {
},
actions: {
async loadLearningPath(slug: string) {
try {
this.learningPath = await itGet(`/learnpath/api/learningpath/${slug}/`);
this.learningPath.topics = [];
const emptyTopic: Topic = {
id: 0,
title: '',
slug: '',
type: 'learnpath.Topic',
translation_key: '',
is_visible: false,
circles: []
}
let topic = Object.assign({}, emptyTopic);
this.learningPath.children.forEach((page) => {
if (page.type === 'learnpath.Topic') {
if (topic.id !== 0) {
this.learningPath.topics.push(topic);
}
topic = Object.assign({}, emptyTopic, page);
}
if (page.type === 'learnpath.Circle') {
const circle = Circle.fromJson(page);
topic.circles.push(circle);
}
this.learningPath.topics.push(topic);
})
console.log(this.learningPath);
return this.learningPath;
} catch (error) {
log.error(error);
return error
}
},
}
})

View File

@ -1,4 +1,4 @@
import {parseLearningSequences} from '@/services/circle'; import type {Circle} from '@/services/circle';
export interface LearningContentBlock { export interface LearningContentBlock {
type: 'web-based-training' | 'competence' | 'exercise' | 'knowledge'; type: 'web-based-training' | 'competence' | 'exercise' | 'knowledge';
@ -95,6 +95,20 @@ export interface WagtailCircle extends LearningWagtailPage {
description: string; description: string;
} }
export interface Topic extends LearningWagtailPage {
type: 'learnpath.Topic';
is_visible: boolean;
circles: Circle[];
}
export type LearningPathChild = Topic | WagtailCircle;
export interface LearningPath extends LearningWagtailPage {
type: 'learnpath.LearningPath';
children: LearningPathChild[];
topics: Topic[];
}
export interface CircleCompletion { export interface CircleCompletion {
id: number; id: number;
created_at: string; created_at: string;
@ -107,17 +121,6 @@ export interface CircleCompletion {
json_data: any; json_data: any;
} }
export interface CircleInterface extends LearningWagtailPage {
readonly type: 'learnpath.Circle';
readonly children: CircleChild[];
readonly description: string;
readonly goals: CircleGoal[];
readonly job_situations: CircleJobSituation[];
learningSequences: LearningSequence[];
}
export interface CircleDiagramData { export interface CircleDiagramData {
index: number index: number
title: string title: string

View File

@ -1,80 +1,40 @@
<script> <script setup lang="ts">
import axios from 'axios';
import * as log from 'loglevel'; import * as log from 'loglevel';
import { mapStores } from 'pinia';
import LearningPathDiagram from '../components/circle/LearningPathDiagram.vue'; import {onMounted} from 'vue'
import { useUserStore } from '../stores/user'; import {useLearningPathStore} from '@/stores/learningPath';
import {useUserStore} from '@/stores/user';
export default { import LearningPathDiagram from '@/components/circle/LearningPathDiagram.vue';
components: {LearningPathDiagram}, log.debug('LearningPathView created');
props: ['learningPathSlug',],
data() {
return {
count: 0,
learningPathData: {},
learningPathContents: null,
circles: [],
learningSequences: [],
}
},
computed: {
...mapStores(useUserStore)
},
mounted() {
log.debug('LearningPath mounted', this.learningPathSlug);
axios({
method: 'get',
url: `/learnpath/api/learningpath/${this.learningPathSlug}/`,
}).then((response) => {
this.learningPathData = response.data const props = defineProps<{
learningPathSlug: string
}>()
let learningPathContents = {topics: []} const learningPathStore = useLearningPathStore();
let topic = { const userStore = useUserStore();
id: 0,
title: '',
slug: '',
type: 'learnpath.Topic',
translation_key: '',
is_visible: false,
cirlces: []
}
response.data.children.forEach((child) => {
if (child.type === 'learnpath.Topic') {
if (topic.id != 0) {
learningPathContents.topics.push(child)
}
topic = child
topic.circles = []
}
if (child.type === 'learnpath.Circle') {
topic.circles.push(child)
}
});
learningPathContents.topics.push(topic)
this.learningPathContents = learningPathContents;
});
}
}
onMounted(async () => {
log.info('LearningPathView mounted');
await learningPathStore.loadLearningPath(props.learningPathSlug);
});
</script> </script>
<template> <template>
<div class="bg-gray-100" v-if="learningPathContents"> <div class="bg-gray-100" v-if="learningPathStore.learningPath">
<div class="learningpath flex flex-col"> <div class="learningpath flex flex-col">
<div class="flex flex-col h-max"> <div class="flex flex-col h-max">
<div class="bg-white h-80 pt-8"> <div class="bg-white h-80 pt-8">
<LearningPathDiagram :learning-path-contents="learningPathContents"></LearningPathDiagram> <LearningPathDiagram></LearningPathDiagram>
</div> </div>
<h1 class="m-12">{{ learningPathData.title }}</h1> <h1 class="m-12">{{ learningPathStore.learningPath.title }}</h1>
<div class="bg-white m-12 p-8 flex flex-row justify-start"> <div class="bg-white m-12 p-8 flex flex-row justify-start">
<div class="p-8 flex-auto"> <div class="p-8 flex-auto">