Refactor to pinia store
This commit is contained in:
parent
626e336db9
commit
1483ec8be0
|
|
@ -1,22 +1,19 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import ItCheckbox from '@/components/ui/ItCheckbox.vue';
|
import ItCheckbox from '@/components/ui/ItCheckbox.vue';
|
||||||
import type {LearningContent, LearningSequence} from '@/services/circle';
|
import type {LearningContent, LearningSequence} from '@/types';
|
||||||
|
import {useCircleStore} from '@/stores/circle';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
learningSequence: LearningSequence
|
learningSequence: LearningSequence
|
||||||
completionData: any
|
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const contentCompleted = (learningContent: LearningContent) => {
|
const circleStore = useCircleStore();
|
||||||
if (props.completionData?.completed_learning_contents) {
|
|
||||||
return props.completionData.completed_learning_contents.findIndex((e) => {
|
|
||||||
return e.learning_content_key === learningContent.translation_key && e.completed;
|
|
||||||
}) >= 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
function toggleCompleted(learningContent: LearningContent) {
|
||||||
|
circleStore.toggleCompleted(learningContent, !learningContent.completed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
@ -44,8 +41,8 @@ const contentCompleted = (learningContent: LearningContent) => {
|
||||||
class="flex items-center gap-4 pb-3"
|
class="flex items-center gap-4 pb-3"
|
||||||
>
|
>
|
||||||
<ItCheckbox
|
<ItCheckbox
|
||||||
:modelValue="contentCompleted(learningContent)"
|
:modelValue="learningContent.completed"
|
||||||
@click="$emit('toggleLearningContentCheckbox', learningContent, !contentCompleted(learningContent))"
|
@click="toggleCompleted(learningContent)"
|
||||||
>
|
>
|
||||||
{{ learningContent.contents[0].type }}: {{ learningContent.title }}
|
{{ learningContent.contents[0].type }}: {{ learningContent.title }}
|
||||||
</ItCheckbox>
|
</ItCheckbox>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import {describe, it} from 'vitest'
|
import {describe, it} from 'vitest'
|
||||||
import type {Circle} from '../circle';
|
|
||||||
import {parseLearningSequences} from '../circle';
|
import {parseLearningSequences} from '../circle';
|
||||||
|
import type {WagtailCircle} from '@/types';
|
||||||
|
|
||||||
describe('circleService.parseLearningSequences', () => {
|
describe('circleService.parseLearningSequences', () => {
|
||||||
it('can parse learning sequences from api response', () => {
|
it('can parse learning sequences from api response', () => {
|
||||||
|
|
@ -117,7 +117,7 @@ describe('circleService.parseLearningSequences', () => {
|
||||||
"job_situations": [],
|
"job_situations": [],
|
||||||
"goals": [],
|
"goals": [],
|
||||||
"experts": []
|
"experts": []
|
||||||
} as Circle;
|
} as WagtailCircle;
|
||||||
|
|
||||||
const learningSequences = parseLearningSequences(input.children);
|
const learningSequences = parseLearningSequences(input.children);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,66 +1,6 @@
|
||||||
export interface LearningContentBlock {
|
import type {CircleChild, LearningSequence, LearningUnit} from '@/types';
|
||||||
type: 'video' | 'web-based-training' | 'podcast' | 'competence' | 'exercise' | 'document' | 'knowledge';
|
|
||||||
value: {
|
|
||||||
description: string;
|
|
||||||
url?: string;
|
|
||||||
},
|
|
||||||
id: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export interface CircleGoal {
|
|
||||||
type: 'goal';
|
|
||||||
value: string;
|
|
||||||
id: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export interface CircleJobSituation {
|
|
||||||
type: 'job_situation';
|
|
||||||
value: string;
|
|
||||||
id: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export interface LearningWagtailPage {
|
|
||||||
id: number;
|
|
||||||
title: string;
|
|
||||||
slug: string;
|
|
||||||
translation_key: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export interface LearningContent extends LearningWagtailPage {
|
|
||||||
type: 'learnpath.LearningContent';
|
|
||||||
minutes: number;
|
|
||||||
contents: LearningContentBlock[];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export interface LearningUnit extends LearningWagtailPage {
|
|
||||||
type: 'learnpath.LearningUnit';
|
|
||||||
questions: [];
|
|
||||||
learningContents: LearningContent[];
|
|
||||||
minutes: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export interface LearningSequence extends LearningWagtailPage {
|
|
||||||
type: 'learnpath.LearningSequence';
|
|
||||||
icon: string;
|
|
||||||
learningUnits: LearningUnit[];
|
|
||||||
minutes: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
type CircleChild = LearningContent | LearningUnit | LearningSequence;
|
|
||||||
|
|
||||||
export interface Circle extends LearningWagtailPage {
|
|
||||||
type: 'learnpath.Circle';
|
|
||||||
children: CircleChild[];
|
|
||||||
description: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
function createEmptyLearningUnit(): LearningUnit {
|
function createEmptyLearningUnit(): LearningUnit {
|
||||||
return {
|
return {
|
||||||
id: -1,
|
id: -1,
|
||||||
|
|
@ -132,3 +72,4 @@ export function parseLearningSequences (children: CircleChild[]): LearningSequen
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,59 @@
|
||||||
|
import {defineStore} from 'pinia'
|
||||||
|
|
||||||
|
import type {Circle, LearningContent} from '@/types'
|
||||||
|
import {itGet, itPost} from '@/fetchHelpers';
|
||||||
|
import {parseLearningSequences} from '@/services/circle';
|
||||||
|
|
||||||
|
export type CircleStoreState = {
|
||||||
|
circleData: Circle;
|
||||||
|
completionData: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useCircleStore = defineStore({
|
||||||
|
id: 'circle',
|
||||||
|
state: () => {
|
||||||
|
return {
|
||||||
|
circleData: {},
|
||||||
|
completionData: {},
|
||||||
|
} as CircleStoreState;
|
||||||
|
},
|
||||||
|
getters: {},
|
||||||
|
actions: {
|
||||||
|
async loadCircle(slug: string) {
|
||||||
|
try {
|
||||||
|
this.circleData = await itGet(`/learnpath/api/circle/${slug}/`);
|
||||||
|
console.log(this.circleData);
|
||||||
|
this.circleData.learningSequences = parseLearningSequences(this.circleData.children);
|
||||||
|
this.completionData = await itGet(`/api/completion/circle/${this.circleData.translation_key}/`);
|
||||||
|
this.parseCompletionData();
|
||||||
|
} catch (error) {
|
||||||
|
console.warn(error);
|
||||||
|
return error
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async toggleCompleted(learningContent: LearningContent, flag = true) {
|
||||||
|
try {
|
||||||
|
learningContent.completed = flag;
|
||||||
|
this.completionData = await itPost('/api/completion/complete_learning_content/', {
|
||||||
|
learning_content_key: learningContent.translation_key,
|
||||||
|
completed: learningContent.completed,
|
||||||
|
});
|
||||||
|
this.parseCompletionData();
|
||||||
|
} catch (error) {
|
||||||
|
console.warn(error);
|
||||||
|
return error
|
||||||
|
}
|
||||||
|
},
|
||||||
|
parseCompletionData() {
|
||||||
|
this.circleData.learningSequences.forEach((learningSequence) => {
|
||||||
|
learningSequence.learningUnits.forEach((learningUnit) => {
|
||||||
|
learningUnit.learningContents.forEach((learningContent) => {
|
||||||
|
learningContent.completed = this.completionData.completed_learning_contents.findIndex((e) => {
|
||||||
|
return e.learning_content_key === learningContent.translation_key && e.completed;
|
||||||
|
}) >= 0;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
export interface LearningContentBlock {
|
||||||
|
type: 'video' | 'web-based-training' | 'podcast' | 'competence' | 'exercise' | 'document' | 'knowledge';
|
||||||
|
value: {
|
||||||
|
description: string;
|
||||||
|
url?: string;
|
||||||
|
},
|
||||||
|
id: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CircleGoal {
|
||||||
|
type: 'goal';
|
||||||
|
value: string;
|
||||||
|
id: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CircleJobSituation {
|
||||||
|
type: 'job_situation';
|
||||||
|
value: string;
|
||||||
|
id: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LearningWagtailPage {
|
||||||
|
id: number;
|
||||||
|
title: string;
|
||||||
|
slug: string;
|
||||||
|
translation_key: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LearningContent extends LearningWagtailPage {
|
||||||
|
type: 'learnpath.LearningContent';
|
||||||
|
minutes: number;
|
||||||
|
contents: LearningContentBlock[];
|
||||||
|
completed?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LearningUnit extends LearningWagtailPage {
|
||||||
|
type: 'learnpath.LearningUnit';
|
||||||
|
questions: [];
|
||||||
|
learningContents: LearningContent[];
|
||||||
|
minutes: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LearningSequence extends LearningWagtailPage {
|
||||||
|
type: 'learnpath.LearningSequence';
|
||||||
|
icon: string;
|
||||||
|
learningUnits: LearningUnit[];
|
||||||
|
minutes: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CircleChild = LearningContent | LearningUnit | LearningSequence;
|
||||||
|
|
||||||
|
export interface WagtailCircle extends LearningWagtailPage {
|
||||||
|
type: 'learnpath.Circle';
|
||||||
|
children: CircleChild[];
|
||||||
|
description: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Circle extends LearningWagtailPage {
|
||||||
|
type: 'learnpath.Circle';
|
||||||
|
children: CircleChild[];
|
||||||
|
description: string;
|
||||||
|
learningSequences: LearningSequence[];
|
||||||
|
}
|
||||||
|
|
@ -1,57 +1,23 @@
|
||||||
<script lang="ts">
|
<script setup lang="ts">
|
||||||
import * as log from 'loglevel';
|
import * as log from 'loglevel';
|
||||||
|
|
||||||
import MainNavigationBar from '../components/MainNavigationBar.vue';
|
import MainNavigationBar from '../components/MainNavigationBar.vue';
|
||||||
import LearningSequence from '../components/circle/LearningSequence.vue';
|
import LearningSequence from '../components/circle/LearningSequence.vue';
|
||||||
import type {Circle, LearningContent} from '../services/circle';
|
|
||||||
import {parseLearningSequences} from '../services/circle';
|
|
||||||
|
|
||||||
import {defineComponent} from 'vue'
|
import {onMounted} from 'vue'
|
||||||
import {itGet, itPost} from '@/fetchHelpers';
|
import {useCircleStore} from '@/stores/circle';
|
||||||
|
|
||||||
export default defineComponent({
|
const props = defineProps<{
|
||||||
components: { LearningSequence, MainNavigationBar },
|
circleSlug: string
|
||||||
props: {
|
}>()
|
||||||
circleSlug: {
|
|
||||||
type: String,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
count: 0,
|
|
||||||
circleData: {} as Circle,
|
|
||||||
learningSequences: [] as LearningSequence[],
|
|
||||||
completionData: {},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
toggleLearningContentCheckbox(learningContent: LearningContent, completed=true) {
|
|
||||||
log.debug('toggleLearningContentCheckbox', learningContent, completed);
|
|
||||||
console.log(learningContent);
|
|
||||||
|
|
||||||
itPost('/api/completion/complete_learning_content/', {
|
const circleStore = useCircleStore();
|
||||||
learning_content_key: learningContent.translation_key,
|
|
||||||
completed: completed,
|
|
||||||
}).then((data) => {
|
|
||||||
log.warn(data);
|
|
||||||
this.completionData = data;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
log.debug('CircleView mounted', this.circleSlug);
|
|
||||||
itGet(`/learnpath/api/circle/${this.circleSlug}/`).then((data) => {
|
|
||||||
this.circleData = data;
|
|
||||||
this.learningSequences = parseLearningSequences(this.circleData.children);
|
|
||||||
log.debug(this.learningSequences);
|
|
||||||
|
|
||||||
itGet(`/api/completion/circle/${this.circleData.translation_key}/`).then((completionData) => {
|
onMounted(() => {
|
||||||
this.completionData = completionData;
|
log.info('CircleView.vue mounted');
|
||||||
});
|
circleStore.loadCircle(props.circleSlug);
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
@ -61,7 +27,7 @@ export default defineComponent({
|
||||||
<div class="flex flex-col lg:flex-row">
|
<div class="flex flex-col lg:flex-row">
|
||||||
<div class="flex-initial lg:w-128 px-4 py-8 lg:px-8">
|
<div class="flex-initial lg:w-128 px-4 py-8 lg:px-8">
|
||||||
<h1 class="text-blue-dark text-7xl">
|
<h1 class="text-blue-dark text-7xl">
|
||||||
{{ circleData.title }}
|
{{ circleStore.circleData.title }}
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<div class="mt-8">
|
<div class="mt-8">
|
||||||
|
|
@ -71,7 +37,7 @@ export default defineComponent({
|
||||||
<div class="outcome border border-gray-500 mt-8 p-6">
|
<div class="outcome border border-gray-500 mt-8 p-6">
|
||||||
<h3 class="text-blue-dark">Das lernst du in diesem Circle.</h3>
|
<h3 class="text-blue-dark">Das lernst du in diesem Circle.</h3>
|
||||||
<div class="prose mt-4">
|
<div class="prose mt-4">
|
||||||
{{ circleData.description }}
|
{{ circleStore.circleData.description }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button class="btn-primary mt-4">Erfahre mehr dazu</button>
|
<button class="btn-primary mt-4">Erfahre mehr dazu</button>
|
||||||
|
|
@ -88,12 +54,12 @@ export default defineComponent({
|
||||||
|
|
||||||
<div class="flex-auto bg-gray-100 px-4 py-8 lg:px-24">
|
<div class="flex-auto bg-gray-100 px-4 py-8 lg:px-24">
|
||||||
<div
|
<div
|
||||||
v-for="learningSequence in learningSequences"
|
v-for="learningSequence in circleStore.circleData.learningSequences"
|
||||||
:key="learningSequence.translation_key"
|
:key="learningSequence.translation_key"
|
||||||
>
|
>
|
||||||
<LearningSequence
|
<LearningSequence
|
||||||
:learning-sequence="learningSequence" @toggleLearningContentCheckbox="toggleLearningContentCheckbox"
|
:learning-sequence="learningSequence" @toggleLearningContentCheckbox="toggleLearningContentCheckbox"
|
||||||
:completion-data="completionData"
|
:completion-data="circleStore.completionData"
|
||||||
></LearningSequence>
|
></LearningSequence>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue