feat(frontend): Functionaliteit om leerobjecten te tonen toegevoegd.
Hiervoor ook de state management geherstructureerd.
This commit is contained in:
		
							parent
							
								
									07340de2e3
								
							
						
					
					
						commit
						728b04c9d8
					
				
					 12 changed files with 141 additions and 150 deletions
				
			
		|  | @ -1,32 +1,22 @@ | ||||||
| <script setup lang="ts" generic="T"> | <script setup lang="ts" generic="T"> | ||||||
| import {type ErrorState, RemoteResource, type RemoteResourceState} from "@/services/api-client/remote-resource.ts"; |     import {RemoteResource} from "@/services/api-client/remote-resource.ts"; | ||||||
| import {computed, onMounted, reactive, ref, type UnwrapNestedRefs, watch} from "vue"; |     import {computed} from "vue"; | ||||||
|     import {useI18n} from "vue-i18n"; |     import {useI18n} from "vue-i18n"; | ||||||
| 
 | 
 | ||||||
|     const props = defineProps<{ |     const props = defineProps<{ | ||||||
|         resource: RemoteResource<T> | (UnwrapNestedRefs<RemoteResource<T>> & {}) |         resource: RemoteResource<T> | ||||||
|     }>() |     }>() | ||||||
| 
 | 
 | ||||||
|     const resource = reactive(props.resource as RemoteResource<T>); |  | ||||||
| 
 |  | ||||||
|     const { t } = useI18n(); |     const { t } = useI18n(); | ||||||
| 
 | 
 | ||||||
|     const isLoading = computed(() => resource.state.type === 'loading'); |     const isLoading = computed(() => props.resource.state.type === 'loading'); | ||||||
|     const isError = computed(() => resource.state.type === 'error'); |     const isError = computed(() => props.resource.state.type === 'error'); | ||||||
|  |     const data = computed(() => props.resource.state.type === 'success' ? props.resource.state.data : null); | ||||||
| 
 | 
 | ||||||
|     // `data` will be correctly inferred as `T` |     const error = computed(() => props.resource.state.type === "error" ? props.resource.state : null); | ||||||
|     const data = computed(() => resource.data); |  | ||||||
| 
 |  | ||||||
|     const error = computed(() => resource.state.type === "error" ? resource.state as ErrorState : null); |  | ||||||
|     const errorMessage = computed(() => |     const errorMessage = computed(() => | ||||||
|         error.value?.message ? error.value.message : JSON.stringify(error.value?.error) |         error.value?.error.message ? error.value.error.message : JSON.stringify(error.value?.error) | ||||||
|     ); |     ); | ||||||
| 
 |  | ||||||
|     watch(data, (newValue, _) => { |  | ||||||
|         if (!newValue && resource.state.type !== "loading") { |  | ||||||
|             (resource as RemoteResource<T>).startRequestInBackground(); |  | ||||||
|         } |  | ||||||
|     }, {immediate: true}); |  | ||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
| <template> | <template> | ||||||
|  | @ -46,6 +36,5 @@ import {computed, onMounted, reactive, ref, type UnwrapNestedRefs, watch} from " | ||||||
| <style scoped> | <style scoped> | ||||||
|   .loading-div { |   .loading-div { | ||||||
|       text-align: center; |       text-align: center; | ||||||
|       margin: 10px; |  | ||||||
|   } |   } | ||||||
| </style> | </style> | ||||||
|  |  | ||||||
|  | @ -1,10 +1,9 @@ | ||||||
| import {type Params, RestEndpoint} from "@/services/api-client/endpoints/rest-endpoint.ts"; | import {type Params, RestEndpoint} from "@/services/api-client/endpoints/rest-endpoint.ts"; | ||||||
| import {RemoteResource} from "@/services/api-client/remote-resource.ts"; |  | ||||||
| 
 | 
 | ||||||
| export class DeleteEndpoint<PP extends Params, QP extends Params, R> extends RestEndpoint<PP, QP, undefined, R> { | export class DeleteEndpoint<PP extends Params, QP extends Params, R> extends RestEndpoint<PP, QP, undefined, R> { | ||||||
|     readonly method = "GET"; |     readonly method = "GET"; | ||||||
| 
 | 
 | ||||||
|     public delete(pathParams: PP, queryParams: QP): RemoteResource<R> { |     public delete(pathParams: PP, queryParams: QP): Promise<R> { | ||||||
|         return super.request(pathParams, queryParams, undefined); |         return super.request(pathParams, queryParams, undefined); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,10 +1,9 @@ | ||||||
| import {type Params, RestEndpoint} from "@/services/api-client/endpoints/rest-endpoint.ts"; | import {type Params, RestEndpoint} from "@/services/api-client/endpoints/rest-endpoint.ts"; | ||||||
| import {RemoteResource} from "@/services/api-client/remote-resource.ts"; |  | ||||||
| 
 | 
 | ||||||
| export class GetEndpoint<PP extends Params, QP extends Params, R> extends RestEndpoint<PP, QP, undefined, R> { | export class GetEndpoint<PP extends Params, QP extends Params, R> extends RestEndpoint<PP, QP, undefined, R> { | ||||||
|     readonly method = "GET"; |     readonly method = "GET"; | ||||||
| 
 | 
 | ||||||
|     public get(pathParams: PP, queryParams: QP): RemoteResource<R> { |     public get(pathParams: PP, queryParams: QP): Promise<R> { | ||||||
|         return super.request(pathParams, queryParams, undefined); |         return super.request(pathParams, queryParams, undefined); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,10 +1,9 @@ | ||||||
| import {type Params, RestEndpoint} from "@/services/api-client/endpoints/rest-endpoint.ts"; | import {type Params, RestEndpoint} from "@/services/api-client/endpoints/rest-endpoint.ts"; | ||||||
| import {RemoteResource} from "@/services/api-client/remote-resource.ts"; |  | ||||||
| 
 | 
 | ||||||
| export class GetHtmlEndpoint<PP extends Params, QP extends Params> extends RestEndpoint<PP, QP, undefined, Document> { | export class GetHtmlEndpoint<PP extends Params, QP extends Params> extends RestEndpoint<PP, QP, undefined, Document> { | ||||||
|     readonly method: "GET" | "POST" | "PUT" | "DELETE" = "GET"; |     readonly method: "GET" | "POST" | "PUT" | "DELETE" = "GET"; | ||||||
| 
 | 
 | ||||||
|     public get(pathParams: PP, queryParams: QP): RemoteResource<Document> { |     public get(pathParams: PP, queryParams: QP): Promise<Document> { | ||||||
|         return super.request(pathParams, queryParams, undefined, "document"); |         return super.request(pathParams, queryParams, undefined, "document"); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,10 +1,9 @@ | ||||||
| import {type Params, RestEndpoint} from "@/services/api-client/endpoints/rest-endpoint.ts"; | import {type Params, RestEndpoint} from "@/services/api-client/endpoints/rest-endpoint.ts"; | ||||||
| import {RemoteResource} from "@/services/api-client/remote-resource.ts"; |  | ||||||
| 
 | 
 | ||||||
| export class PostEndpoint<PP extends Params, QP extends Params, B, R> extends RestEndpoint<PP, QP, B, R> { | export class PostEndpoint<PP extends Params, QP extends Params, B, R> extends RestEndpoint<PP, QP, B, R> { | ||||||
|     readonly method = "POST"; |     readonly method = "POST"; | ||||||
| 
 | 
 | ||||||
|     public post(pathParams: PP, queryParams: QP, body: B): RemoteResource<R> { |     public post(pathParams: PP, queryParams: QP, body: B): Promise<R> { | ||||||
|         return super.request(pathParams, queryParams, body); |         return super.request(pathParams, queryParams, body); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,4 +1,3 @@ | ||||||
| import {RemoteResource} from "@/services/api-client/remote-resource.ts"; |  | ||||||
| import apiClient from "@/services/api-client/api-client.ts"; | import apiClient from "@/services/api-client/api-client.ts"; | ||||||
| import {HttpErrorStatusException} from "@/services/api-client/api-exceptions.ts"; | import {HttpErrorStatusException} from "@/services/api-client/api-exceptions.ts"; | ||||||
| import type {ResponseType} from "axios"; | import type {ResponseType} from "axios"; | ||||||
|  | @ -8,27 +7,21 @@ export abstract class RestEndpoint<PP extends Params, QP extends Params, B, R> { | ||||||
|     constructor(public readonly url: string) { |     constructor(public readonly url: string) { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     protected request(pathParams: PP, queryParams: QP, body: B, responseType?: ResponseType): RemoteResource<R> { |     protected async request(pathParams: PP, queryParams: QP, body: B, responseType?: ResponseType): Promise<R> { | ||||||
|         let urlFilledIn = this.url.replace(/:(\w+)(\/|$)/g, (_, key, after) => |         let urlFilledIn = this.url.replace(/:(\w+)(\/|$)/g, (_, key, after) => | ||||||
|             (pathParams[key] ? encodeURIComponent(pathParams[key]) : `:${key}`) + after |             (pathParams[key] ? encodeURIComponent(pathParams[key]) : `:${key}`) + after | ||||||
|         ); |         ); | ||||||
|         console.log(this.url); |         const response = await apiClient.request<R>({ | ||||||
|         console.log(/:(\w+)(\W|$)/g.test(this.url)) |             url: urlFilledIn, | ||||||
|         console.log(pathParams); |             method: this.method, | ||||||
|         console.log("--> filled in: " + urlFilledIn); |             params: queryParams, | ||||||
|         return new RemoteResource(async () => { |             data: body, | ||||||
|             const response = await apiClient.request<R>({ |             responseType: responseType || 'json' | ||||||
|                 url: urlFilledIn, |  | ||||||
|                 method: this.method, |  | ||||||
|                 params: queryParams, |  | ||||||
|                 data: body, |  | ||||||
|                 responseType: responseType || 'json' |  | ||||||
|             }); |  | ||||||
|             if (response.status / 100 !== 2) { |  | ||||||
|                 throw new HttpErrorStatusException(response); |  | ||||||
|             } |  | ||||||
|             return response.data; |  | ||||||
|         }); |         }); | ||||||
|  |         if (response.status / 100 !== 2) { | ||||||
|  |             throw new HttpErrorStatusException(response); | ||||||
|  |         } | ||||||
|  |         return response.data; | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,78 +1,4 @@ | ||||||
| export class RemoteResource<T> { | import {type ShallowReactive, shallowReactive} from "vue"; | ||||||
|     static NOT_LOADED: NotLoadedState = {type: "notLoaded"}; |  | ||||||
|     static LOADING: LoadingState = {type: "loading"}; |  | ||||||
| 
 |  | ||||||
|     private _state: RemoteResourceState<T> = RemoteResource.NOT_LOADED; |  | ||||||
| 
 |  | ||||||
|     constructor(private readonly requestFn: () => Promise<T>) { |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public static join<T>(resources: RemoteResource<T>[]): RemoteResource<T[]> { |  | ||||||
|         return new RemoteResource(async () => { |  | ||||||
|             console.log("joined fetch"); |  | ||||||
|             const promises = resources.map(it => it.request()); |  | ||||||
|             const data = await Promise.all(promises); |  | ||||||
|             const failed = resources |  | ||||||
|                 .filter(it => it.state.type === "error") |  | ||||||
|                 .map(it => it.state as ErrorState); |  | ||||||
|             if (failed.length > 0) { |  | ||||||
|                 console.log("joined error!"); |  | ||||||
|                 throw failed[0].error; |  | ||||||
|             } |  | ||||||
|             console.log("succ"); |  | ||||||
|             console.log(data); |  | ||||||
|             return data.map(it => it!); |  | ||||||
|         }); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public async request(): Promise<T | undefined> { |  | ||||||
|         this._state = RemoteResource.LOADING; |  | ||||||
|         try { |  | ||||||
|             let resource = await this.requestFn(); |  | ||||||
|             this._state = { |  | ||||||
|                 type: "success", |  | ||||||
|                 data: resource |  | ||||||
|             }; |  | ||||||
|             return resource; |  | ||||||
|         } catch (e: any) { |  | ||||||
|             this._state = { |  | ||||||
|                 type: "error", |  | ||||||
|                 errorCode: e.statusCode, |  | ||||||
|                 message: e.message, |  | ||||||
|                 error: e |  | ||||||
|             }; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public startRequestInBackground(): RemoteResource<T> { |  | ||||||
|         this.request().then(); |  | ||||||
|         return this; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public get state(): RemoteResourceState<T> { |  | ||||||
|         return this._state; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public get data(): T | undefined { |  | ||||||
|         if (this._state.type === "success") { |  | ||||||
|             return this._state.data; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public map<U>(mappingFn: (content: T) => U): RemoteResource<U> { |  | ||||||
|         return new RemoteResource<U>(async () => { |  | ||||||
|             await this.request(); |  | ||||||
|             if (this._state.type === "success") { |  | ||||||
|                 return mappingFn(this._state.data); |  | ||||||
|             } else if (this._state.type === "error") { |  | ||||||
|                 throw this._state.error; |  | ||||||
|             } else { |  | ||||||
|                 throw new Error("Fetched resource, but afterwards, it was neither in a success nor in an error state. " + |  | ||||||
|                     "This should never happen."); |  | ||||||
|             } |  | ||||||
|         }); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| export type NotLoadedState = { | export type NotLoadedState = { | ||||||
|     type: "notLoaded" |     type: "notLoaded" | ||||||
|  | @ -82,8 +8,6 @@ export type LoadingState = { | ||||||
| }; | }; | ||||||
| export type ErrorState = { | export type ErrorState = { | ||||||
|     type: "error", |     type: "error", | ||||||
|     errorCode?: number, |  | ||||||
|     message?: string, |  | ||||||
|     error: any |     error: any | ||||||
| }; | }; | ||||||
| export type SuccessState<T> = { | export type SuccessState<T> = { | ||||||
|  | @ -91,3 +15,23 @@ export type SuccessState<T> = { | ||||||
|     data: T |     data: T | ||||||
| }; | }; | ||||||
| export type RemoteResourceState<T> = NotLoadedState | LoadingState | ErrorState | SuccessState<T>; | export type RemoteResourceState<T> = NotLoadedState | LoadingState | ErrorState | SuccessState<T>; | ||||||
|  | 
 | ||||||
|  | export type RemoteResource<T> = ShallowReactive<{ | ||||||
|  |     state: RemoteResourceState<T> | ||||||
|  | }>; | ||||||
|  | 
 | ||||||
|  | export function remoteResource<T>(): RemoteResource<T> { | ||||||
|  |     return shallowReactive({ | ||||||
|  |         state: { | ||||||
|  |             type: "notLoaded" | ||||||
|  |         } | ||||||
|  |     }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export function loadResource<T>(resource: RemoteResource<T>, promise: Promise<T>): void { | ||||||
|  |     resource.state = { type: "loading" } | ||||||
|  |     promise.then( | ||||||
|  |         data => resource.state = { type: "success", data }, | ||||||
|  |         error => resource.state = { type: "error", error } | ||||||
|  |     ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -1,13 +1,28 @@ | ||||||
| import {GetEndpoint} from "@/services/api-client/endpoints/get-endpoint.ts"; | import {GetEndpoint} from "@/services/api-client/endpoints/get-endpoint.ts"; | ||||||
| import type {LearningObject} from "@/services/learning-content/learning-object.ts"; | import type {LearningObject} from "@/services/learning-content/learning-object.ts"; | ||||||
| import type {Language} from "@/services/learning-content/language.ts"; | import type {Language} from "@/services/learning-content/language.ts"; | ||||||
| import type {RemoteResource} from "@/services/api-client/remote-resource.ts"; | import {GetHtmlEndpoint} from "@/services/api-client/endpoints/get-html-endpoint.ts"; | ||||||
| 
 | 
 | ||||||
| const getLearningObjectMetadataEndpoint = new GetEndpoint<{hruid: string}, {language: Language, version: number}, LearningObject>( | const getLearningObjectMetadataEndpoint = new GetEndpoint<{hruid: string}, {language: Language, version: number}, LearningObject>( | ||||||
|     "/learningObject/:hruid" |     "/learningObject/:hruid" | ||||||
| ); | ); | ||||||
| 
 | 
 | ||||||
| export function getLearningObjectMetadata(hruid: string, language: Language, version: number): RemoteResource<LearningObject> { | const getLearningObjectHtmlEndpoint = new GetHtmlEndpoint<{hruid: string}, {language: Language, version: number}>( | ||||||
|     return getLearningObjectMetadataEndpoint |     "/learningObject/:hruid/html" | ||||||
|         .get({hruid}, {language, version}); | ); | ||||||
|  | 
 | ||||||
|  | export function getLearningObjectMetadata( | ||||||
|  |     hruid: string, | ||||||
|  |     language: Language, | ||||||
|  |     version: number | ||||||
|  | ): Promise<LearningObject> { | ||||||
|  |     return getLearningObjectMetadataEndpoint.get({hruid}, {language, version}); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export function getLearningObjectHTML( | ||||||
|  |     hruid: string, | ||||||
|  |     language: Language, | ||||||
|  |     version: number | ||||||
|  | ): Promise<Document> { | ||||||
|  |     return getLearningObjectHtmlEndpoint.get({hruid}, {language, version}); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,6 +1,5 @@ | ||||||
| import {GetEndpoint} from "@/services/api-client/endpoints/get-endpoint.ts"; | import {GetEndpoint} from "@/services/api-client/endpoints/get-endpoint.ts"; | ||||||
| import {LearningPath, type LearningPathDTO} from "@/services/learning-content/learning-path.ts"; | import {LearningPath, type LearningPathDTO} from "@/services/learning-content/learning-path.ts"; | ||||||
| import type {RemoteResource} from "@/services/api-client/remote-resource.ts"; |  | ||||||
| import type {Language} from "@/services/learning-content/language.ts"; | import type {Language} from "@/services/learning-content/language.ts"; | ||||||
| import {single} from "@/utils/response-assertions.ts"; | import {single} from "@/utils/response-assertions.ts"; | ||||||
| 
 | 
 | ||||||
|  | @ -8,16 +7,12 @@ const learningPathEndpoint = new GetEndpoint<{}, {search?: string, hruid?: strin | ||||||
|     "/learningPath" |     "/learningPath" | ||||||
| ); | ); | ||||||
| 
 | 
 | ||||||
| export function searchLearningPaths(query: string): RemoteResource<LearningPath[]> { | export async function searchLearningPaths(query: string): Promise<LearningPath[]> { | ||||||
|     return learningPathEndpoint |     let dtos = await learningPathEndpoint.get({}, {search: query}) | ||||||
|         .get({}, {search: query}) |     return dtos.map(dto => LearningPath.fromDTO(dto)); | ||||||
|         .map(dtos => dtos.map(dto => LearningPath.fromDTO(dto))); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export function getLearningPath(hruid: string, language: Language): RemoteResource<LearningPath> { | export async function getLearningPath(hruid: string, language: Language): Promise<LearningPath> { | ||||||
|     console.log({hruid, language}) |     let dtos = await learningPathEndpoint.get({}, {hruid, language}); | ||||||
|     return learningPathEndpoint |     return LearningPath.fromDTO(single(dtos)); | ||||||
|         .get({}, {hruid, language}) |  | ||||||
|         .map(it => {console.log(it); return it;}) |  | ||||||
|         .map(dtos => LearningPath.fromDTO(single(dtos))); |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,5 +1,4 @@ | ||||||
| import type {Language} from "@/services/learning-content/language.ts"; | import type {Language} from "@/services/learning-content/language.ts"; | ||||||
| import {RemoteResource} from "@/services/api-client/remote-resource.ts"; |  | ||||||
| import type {LearningObject} from "@/services/learning-content/learning-object.ts"; | import type {LearningObject} from "@/services/learning-content/learning-object.ts"; | ||||||
| import {getLearningObjectMetadata} from "@/services/learning-content/learning-object-service.ts"; | import {getLearningObjectMetadata} from "@/services/learning-content/learning-object-service.ts"; | ||||||
| 
 | 
 | ||||||
|  | @ -43,7 +42,6 @@ interface LearningPathTransitionDTO { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export class LearningPathNode { | export class LearningPathNode { | ||||||
|     public learningObject: RemoteResource<LearningObject> |  | ||||||
| 
 | 
 | ||||||
|     constructor( |     constructor( | ||||||
|         public readonly learningobjectHruid: string, |         public readonly learningobjectHruid: string, | ||||||
|  | @ -53,7 +51,10 @@ export class LearningPathNode { | ||||||
|         public readonly createdAt: Date, |         public readonly createdAt: Date, | ||||||
|         public readonly updatedAt: Date |         public readonly updatedAt: Date | ||||||
|     ) { |     ) { | ||||||
|         this.learningObject = getLearningObjectMetadata(learningobjectHruid, language, version); |     } | ||||||
|  | 
 | ||||||
|  |     get learningObject(): Promise<LearningObject> { | ||||||
|  |         return getLearningObjectMetadata(this.learningobjectHruid, this.language, this.version); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     static fromDTOAndOtherNodes(dto: LearningPathNodeDTO, otherNodes: LearningPathNodeDTO[]): LearningPathNode { |     static fromDTOAndOtherNodes(dto: LearningPathNodeDTO, otherNodes: LearningPathNodeDTO[]): LearningPathNode { | ||||||
|  | @ -109,8 +110,8 @@ export class LearningPath { | ||||||
|         return list; |         return list; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public get learningObjectsAsList(): RemoteResource<LearningObject[]> { |     public get learningObjectsAsList(): Promise<LearningObject[]> { | ||||||
|         return RemoteResource.join(this.nodesAsList.map(node => node.learningObject)); |         return Promise.all(this.nodesAsList.map(node => node.learningObject)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     static fromDTO(dto: LearningPathDTO): LearningPath { |     static fromDTO(dto: LearningPathDTO): LearningPath { | ||||||
|  |  | ||||||
							
								
								
									
										31
									
								
								frontend/src/views/learning-paths/LearningObjectView.vue
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								frontend/src/views/learning-paths/LearningObjectView.vue
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,31 @@ | ||||||
|  | <script setup lang="ts"> | ||||||
|  | import {Language} from "@/services/learning-content/language.ts"; | ||||||
|  | import {watch} from "vue"; | ||||||
|  | import {getLearningObjectHTML} from "@/services/learning-content/learning-object-service.ts"; | ||||||
|  | import UsingRemoteResource from "@/components/UsingRemoteResource.vue"; | ||||||
|  | import {loadResource, remoteResource} from "@/services/api-client/remote-resource.ts"; | ||||||
|  | 
 | ||||||
|  | const props = defineProps<{hruid: string, language: Language, version: number}>() | ||||||
|  | 
 | ||||||
|  | const learningPathHtmlResource = remoteResource<Document>(); | ||||||
|  | watch(props, () => { | ||||||
|  |     loadResource(learningPathHtmlResource, getLearningObjectHTML(props.hruid, props.language, props.version)) | ||||||
|  | }, {immediate: true}); | ||||||
|  | 
 | ||||||
|  | </script> | ||||||
|  | 
 | ||||||
|  | <template> | ||||||
|  |     <using-remote-resource :resource="learningPathHtmlResource" v-slot="learningPathHtml : {data: Document}"> | ||||||
|  |         <div class="learning-object-container" v-html="learningPathHtml.data.body.innerHTML"></div> | ||||||
|  |     </using-remote-resource> | ||||||
|  | </template> | ||||||
|  | 
 | ||||||
|  | <style scoped> | ||||||
|  |     .learning-object-container { | ||||||
|  |         margin: 20px; | ||||||
|  |     } | ||||||
|  |     :deep(hr) { | ||||||
|  |         margin-top: 10px; | ||||||
|  |         margin-bottom: 10px; | ||||||
|  |     } | ||||||
|  | </style> | ||||||
|  | @ -2,31 +2,52 @@ | ||||||
|     import {Language} from "@/services/learning-content/language.ts"; |     import {Language} from "@/services/learning-content/language.ts"; | ||||||
|     import {getLearningPath} from "@/services/learning-content/learning-path-service.ts"; |     import {getLearningPath} from "@/services/learning-content/learning-path-service.ts"; | ||||||
|     import UsingRemoteResource from "@/components/UsingRemoteResource.vue"; |     import UsingRemoteResource from "@/components/UsingRemoteResource.vue"; | ||||||
|     import type {LearningPath} from "@/services/learning-content/learning-path.ts"; |     import {type LearningPath} from "@/services/learning-content/learning-path.ts"; | ||||||
|     import {onMounted, reactive, watch} from "vue"; |     import {computed, watch, watchEffect} from "vue"; | ||||||
|     import type {LearningObject} from "@/services/learning-content/learning-object.ts"; |     import type {LearningObject} from "@/services/learning-content/learning-object.ts"; | ||||||
|     import {useRouter} from "vue-router"; |     import {useRouter} from "vue-router"; | ||||||
|     import type {SuccessState} from "@/services/api-client/remote-resource.ts"; |     import {loadResource, remoteResource, type SuccessState} from "@/services/api-client/remote-resource.ts"; | ||||||
|  |     import LearningObjectView from "@/views/learning-paths/LearningObjectView.vue"; | ||||||
| 
 | 
 | ||||||
|     const router = useRouter(); |     const router = useRouter(); | ||||||
|     const props = defineProps<{hruid: string, language: Language, learningObjectHruid?: string}>() |     const props = defineProps<{hruid: string, language: Language, learningObjectHruid?: string}>() | ||||||
| 
 | 
 | ||||||
|     const learningPathResource = reactive(getLearningPath(props.hruid, props.language)); |     const learningPathResource = remoteResource<LearningPath>(); | ||||||
|  |     watchEffect(() => { | ||||||
|  |         loadResource(learningPathResource, getLearningPath(props.hruid, props.language)); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     const learningObjectListResource = remoteResource<LearningObject[]>(); | ||||||
|  |     watch(learningPathResource, () => { | ||||||
|  |         if (learningPathResource.state.type === "success") { | ||||||
|  |             loadResource(learningObjectListResource, learningPathResource.state.data.learningObjectsAsList) | ||||||
|  |         } | ||||||
|  |     }, {immediate: true}); | ||||||
|  | 
 | ||||||
|  |     const currentNode = computed(() => { | ||||||
|  |         let currentHruid = props.learningObjectHruid; | ||||||
|  |         if (learningPathResource.state.type === "success") { | ||||||
|  |             return learningPathResource.state.data.nodesAsList.filter(it => it.learningobjectHruid === currentHruid)[0] | ||||||
|  |         } else { | ||||||
|  |             return undefined; | ||||||
|  |         } | ||||||
|  |     }); | ||||||
| 
 | 
 | ||||||
|     if (!props.learningObjectHruid) { |     if (!props.learningObjectHruid) { | ||||||
|         watch(() => learningPathResource.state, (newValue) => { |         watch(() => learningPathResource.state, (newValue) => { | ||||||
|             console.log("state changed!!"); |  | ||||||
|             if (newValue.type === "success") { |             if (newValue.type === "success") { | ||||||
|                 router.push(router.currentRoute.value.path |                 router.push(router.currentRoute.value.path | ||||||
|                     + "/" + (newValue as SuccessState<LearningPath>).data.startNode.learningobjectHruid); |                     + "/" + (newValue as SuccessState<LearningPath>).data.startNode.learningobjectHruid); | ||||||
|             } |             } | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
| <template> | <template> | ||||||
|     <using-remote-resource :resource="learningPathResource" v-slot="learningPath: {data: LearningPath}"> |     <using-remote-resource | ||||||
|  |         :resource="learningPathResource" | ||||||
|  |         v-slot="learningPath: {data: LearningPath}" | ||||||
|  |     > | ||||||
|         <v-navigation-drawer> |         <v-navigation-drawer> | ||||||
|             <v-list-item |             <v-list-item | ||||||
|                 :title="learningPath.data.title" |                 :title="learningPath.data.title" | ||||||
|  | @ -36,7 +57,7 @@ | ||||||
| 
 | 
 | ||||||
|             <div v-if="props.learningObjectHruid"> |             <div v-if="props.learningObjectHruid"> | ||||||
|                 <using-remote-resource |                 <using-remote-resource | ||||||
|                     :resource="learningPath.data.learningObjectsAsList" |                     :resource="learningObjectListResource" | ||||||
|                     v-slot="learningObjects: {data: LearningObject[]}" |                     v-slot="learningObjects: {data: LearningObject[]}" | ||||||
|                 > |                 > | ||||||
|                     <v-list-item |                     <v-list-item | ||||||
|  | @ -53,6 +74,12 @@ | ||||||
|                 </using-remote-resource> |                 </using-remote-resource> | ||||||
|             </div> |             </div> | ||||||
|         </v-navigation-drawer> |         </v-navigation-drawer> | ||||||
|  |         <learning-object-view | ||||||
|  |             :hruid="currentNode.learningobjectHruid" | ||||||
|  |             :language="currentNode.language" | ||||||
|  |             :version="currentNode.version" | ||||||
|  |             v-if="currentNode" | ||||||
|  |         ></learning-object-view> | ||||||
|     </using-remote-resource> |     </using-remote-resource> | ||||||
| </template> | </template> | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Reference in a new issue
	
	 Gerald Schmittinger
						Gerald Schmittinger