Load MediaCenter data from api

This commit is contained in:
Daniel Egger 2022-09-23 16:49:00 +02:00
parent 8941f4ad24
commit 18c3e28ba1
14 changed files with 193 additions and 121 deletions

View File

@ -0,0 +1,33 @@
<script setup lang="ts">
import MediaLink from '@/components/mediacenter/MediaLink.vue'
export interface Props {
title: string
description: string
linkText: string
url: string
icon: string
openWindow?: boolean
}
const props = withDefaults(defineProps<Props>(), {
icon: '',
description: '',
openWindow: false,
})
</script>
<template>
<div class="border-gray-500 border flex p-4 items-center">
<img class="mr-6" :src="icon" />
<div>
<h4 class="mb-2 text-bold">{{ title }}</h4>
<p class="mb-2">{{ description }}</p>
<media-link :to="url" :blank="openWindow" class="link">
<span class="inline">{{ linkText }}</span>
</media-link>
</div>
</div>
</template>
<style lang="scss" scoped></style>

View File

@ -0,0 +1,28 @@
<script setup lang="ts">
// https://router.vuejs.org/guide/advanced/extending-router-link.html
// https://vueschool.io/articles/vuejs-tutorials/extending-vue-router-links-in-vue-3/
import { RouterLink } from 'vue-router'
import { computed } from 'vue'
const props = defineProps({
...RouterLink.props, // @ts-ignore
blank: {
type: Boolean,
default: false,
},
})
const isExternalLink = computed(() => typeof props.to === 'string' && props.to.startsWith('http'))
</script>
<template>
<div>
<a v-if="isExternalLink" :target="props.blank ? '_blank' : '_self'" rel="noopener" :href="props.to">
<slot />
</a>
<router-link v-else :target="props.blank ? '_blank' : '_self'" rel="noopener" v-bind="props">
<slot />
</router-link>
</div>
</template>

View File

@ -1,42 +0,0 @@
<script setup lang="ts">
import MediaLink from "@/components/mediacenter/MediaLink.vue";
export interface Props {
title: string,
description: string,
linkText: string,
url: string,
icon: string,
openWindow?: boolean
}
const props = withDefaults(defineProps<Props>(), {
icon: '',
description: '',
openWindow: false
})
</script>
<template>
<div class="border-gray-500 border flex p-4 items-center">
<img
class="mr-6"
:src="icon" />
<div>
<h4 class="mb-2 text-bold">{{title}}</h4>
<p class="mb-2">{{description}}</p>
<media-link
:to="url"
:blank="openWindow"
class="link"
>
<span class="inline">{{linkText}}</span>
</media-link>
</div>
</div>
</template>
<style lang="scss" scoped>
</style>

View File

@ -1,38 +0,0 @@
<script setup lang="ts">
// https://router.vuejs.org/guide/advanced/extending-router-link.html
// https://vueschool.io/articles/vuejs-tutorials/extending-vue-router-links-in-vue-3/
import { RouterLink, useLink } from 'vue-router'
import {computed} from "vue";
const props = defineProps(
{
...RouterLink.props, // @ts-ignore
blank: {
type: Boolean,
default: false
}
})
const isExternalLink = computed(() => typeof props.to === 'string' && props.to.startsWith('http'));
</script>
<template>
<div>
<a v-if="isExternalLink"
:target="props.blank ? '_blank' : '_self'"
rel="noopener"
:href="props.to">
<slot />
</a>
<router-link
v-else
:target="props.blank ? '_blank' : '_self'"
rel="noopener"
v-bind="props"
>
<slot />
</router-link>
</div>
</template>

View File

@ -1,7 +1,6 @@
import { createRouter, createWebHistory } from 'vue-router'
import CockpitView from '@/views/CockpitView.vue'
import LoginView from '@/views/LoginView.vue'
import MediaMainView from '@/views/MediaMainView.vue'
import { redirectToLoginIfRequired, updateLoggedIn } from '@/router/guards'
import { useAppStore } from '@/stores/app'
@ -26,26 +25,27 @@ const router = createRouter({
component: () => import('@/views/ShopView.vue'),
},
{
path: '/mediacenter',
component: () => import('@/views/MediaView.vue'),
path: '/mediacenter/:mediaCenterPageSlug',
props: true,
component: () => import('@/views/MediaCenterView.vue'),
children: [
{
path: 'overview',
component: () => import('@/views/MediaMainView.vue')
component: () => import('@/views/MediaMainView.vue'),
},
{
path: 'handlungsfelder',
component: () => import('@/views/HandlungsfelderOverview.vue')
component: () => import('@/views/HandlungsfelderOverview.vue'),
},
{
path: 'handlungsfeld',
component: () => import('@/views/Handlungsfeld.vue')
component: () => import('@/views/Handlungsfeld.vue'),
},
{
path: 'handlungsfeldlist',
component: () => import('@/views/MediaList.vue')
component: () => import('@/views/MediaList.vue'),
},
]
],
},
{
path: '/messages',

View File

@ -7,7 +7,7 @@ import type {
LearningSequence,
LearningUnit,
LearningUnitQuestion,
LearningWagtailPage,
CourseWagtailPage,
} from '@/types'
import type { LearningPath } from '@/services/learningPath'
@ -109,7 +109,7 @@ export function parseLearningSequences (circle: Circle, children: CircleChild[])
return result;
}
export class Circle implements LearningWagtailPage {
export class Circle implements CourseWagtailPage {
readonly type = 'learnpath.Circle';
readonly learningSequences: LearningSequence[];
readonly completed: boolean;

View File

@ -1,6 +1,6 @@
import * as _ from 'lodash'
import type { CircleCompletion, LearningContent, LearningPathChild, LearningWagtailPage, Topic } from '@/types'
import type { CircleCompletion, LearningContent, LearningPathChild, CourseWagtailPage, Topic } from '@/types'
import { Circle } from '@/services/circle'
function getLastCompleted(learningPathKey: string, completionData: CircleCompletion[]) {
@ -9,7 +9,7 @@ function getLastCompleted(learningPathKey: string, completionData: CircleComplet
})
}
export class LearningPath implements LearningWagtailPage {
export class LearningPath implements CourseWagtailPage {
readonly type = 'learnpath.LearningPath'
public topics: Topic[]
public circles: Circle[]

View File

@ -0,0 +1,39 @@
import { defineStore } from 'pinia'
import { itGet } from '@/fetchHelpers'
import type { MediaLibraryPage } from '@/types'
export type MediaCenterStoreState = {
mediaCenterPage: MediaLibraryPage | undefined
selectedLearningPath: { id: number; name: string }
availableLearningPaths: { id: number; name: string }[]
}
export const useMediaCenterStore = defineStore({
id: 'mediaCenter',
state: () => {
return {
mediaCenterPage: undefined,
selectedLearningPath: { id: 1, name: 'Alle Lehrgänge' },
availableLearningPaths: [
{ id: 1, name: 'Alle Lehrgänge' },
{ id: 2, name: 'Versicherungsvermittler/in' },
],
} as MediaCenterStoreState
},
getters: {},
actions: {
async loadMediaCenterPage(slug: string, reload = false) {
if (this.mediaCenterPage && !reload) {
return this.mediaCenterPage
}
const mediaCenterPageData = await itGet(`/api/course/page/${slug}/`)
if (!mediaCenterPageData) {
throw `No mediaCenterPageData found with: ${slug}`
}
this.mediaCenterPage = mediaCenterPageData
return this.mediaCenterPage
},
},
})

View File

@ -1,16 +0,0 @@
import { defineStore } from 'pinia'
export const useMediaCenterStore = defineStore({
id: 'mediacenter',
state: () => {
return {
selectedLearningPath: { id: 1, name: 'Alle Lehrgänge' },
availableLearningPaths: [
{ id: 1, name: 'Alle Lehrgänge' },
{ id: 2, name: 'Versicherungsvermittler/in' }
]
}
},
getters: {},
actions: {},
})

View File

@ -47,7 +47,7 @@ export interface CircleJobSituation {
id: string;
}
export interface LearningWagtailPage {
export interface CourseWagtailPage {
readonly id: number;
readonly title: string;
readonly slug: string;
@ -55,7 +55,7 @@ export interface LearningWagtailPage {
completed?: boolean;
}
export interface LearningContent extends LearningWagtailPage {
export interface LearningContent extends CourseWagtailPage {
type: 'learnpath.LearningContent';
minutes: number;
contents: (LearningContentBlock | VideoBlock | PodcastBlock | DocumentBlock)[];
@ -66,13 +66,13 @@ export interface LearningContent extends LearningWagtailPage {
previousLearningContent?: LearningContent;
}
export interface LearningUnitQuestion extends LearningWagtailPage {
export interface LearningUnitQuestion extends CourseWagtailPage {
type: 'learnpath.LearningUnitQuestion';
parentLearningSequence?: LearningSequence;
parentLearningUnit?: LearningUnit;
}
export interface LearningUnit extends LearningWagtailPage {
export interface LearningUnit extends CourseWagtailPage {
type: 'learnpath.LearningUnit';
learningContents: LearningContent[];
minutes: number;
@ -81,7 +81,7 @@ export interface LearningUnit extends LearningWagtailPage {
last?: boolean;
}
export interface LearningSequence extends LearningWagtailPage {
export interface LearningSequence extends CourseWagtailPage {
type: 'learnpath.LearningSequence';
icon: string;
learningUnits: LearningUnit[];
@ -90,13 +90,13 @@ export interface LearningSequence extends LearningWagtailPage {
export type CircleChild = LearningContent | LearningUnit | LearningSequence | LearningUnitQuestion;
export interface WagtailCircle extends LearningWagtailPage {
export interface WagtailCircle extends CourseWagtailPage {
type: 'learnpath.Circle';
children: CircleChild[];
description: string;
}
export interface Topic extends LearningWagtailPage {
export interface Topic extends CourseWagtailPage {
type: 'learnpath.Topic';
is_visible: boolean;
circles: Circle[];
@ -127,3 +127,55 @@ export interface CircleDiagramData {
arrowEndAngle: number
done: boolean
}
export interface Course {
id: number;
name: string;
category_name: string;
}
export interface CourseCategory {
id: number;
name: string;
general: boolean;
}
export interface MediaDocument {
type: "Documents";
value: number;
id: string;
}
export interface MediaLink {
type: "Links";
id: string;
value: {
title: string;
description: string;
link_display_text: string;
url: string;
}
}
export interface MediaContentCollection {
type: "content_collection";
value: {
title: string;
contents: (MediaDocument | MediaLink)[];
}
}
export interface MediaCategoryPage extends CourseWagtailPage {
type: 'media_library.MediaCategoryPage';
introduction_text: string;
description: string;
course_category: CourseCategory;
body: MediaContentCollection[];
}
export interface MediaLibraryPage extends CourseWagtailPage {
type: 'media_library.MediaLibraryPage';
course: Course;
children: MediaCategoryPage[];
}

View File

@ -2,7 +2,7 @@
import * as log from 'loglevel';
import ItDropdownSelect from "@/components/ui/ItDropdownSelect.vue";
import {reactive, ref, watch} from "vue";
import {useMediaCenterStore} from "@/stores/mediacenter";
import {useMediaCenterStore} from "@/stores/mediaCenter";
log.debug('HandlungsfelderOverview created');

View File

@ -1,8 +1,25 @@
<script setup lang="ts">
import * as log from 'loglevel';
import * as log from 'loglevel'
import { onMounted } from 'vue'
import { useMediaCenterStore } from '@/stores/mediaCenter'
log.debug('ShopView created');
log.debug('MediaCenterView created')
const props = defineProps<{
mediaCenterPageSlug: string
}>()
const mediaCenterStore = useMediaCenterStore()
onMounted(async () => {
log.debug('MediaCenterView mounted', props.mediaCenterPageSlug)
try {
await mediaCenterStore.loadMediaCenterPage(props.mediaCenterPageSlug)
} catch (error) {
log.error(error)
}
})
</script>
<template>
@ -22,5 +39,4 @@ log.debug('ShopView created');
</div>
</template>
<style scoped>
</style>
<style scoped></style>

View File

@ -3,7 +3,7 @@ import * as log from 'loglevel';
import OverviewCard from '@/components/mediacenter/OverviewCard.vue';
import ItDropdownSelect from "@/components/ui/ItDropdownSelect.vue";
import {watch, ref} from "vue";
import {useMediaCenterStore} from "@/stores/mediacenter";
import {useMediaCenterStore} from "@/stores/mediaCenter";
log.debug('MediaMainView created');