From c7a32b3e09232098314e9b7ab139cd9272402eee Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Wed, 15 Dec 2021 09:10:39 +0100 Subject: [PATCH] MOBILE-3946 h5p: Refresh completion when H5P is finished --- .../mod/h5pactivity/components/index/index.ts | 16 ++++++-- .../mod/h5pactivity/services/h5pactivity.ts | 40 +++++++++++++++++++ 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/src/addons/mod/h5pactivity/components/index/index.ts b/src/addons/mod/h5pactivity/components/index/index.ts index 0f8e18d6f..d54c0db3e 100644 --- a/src/addons/mod/h5pactivity/components/index/index.ts +++ b/src/addons/mod/h5pactivity/components/index/index.ts @@ -37,6 +37,7 @@ import { AddonModH5PActivityAccessInfo, AddonModH5PActivityData, AddonModH5PActivityProvider, + AddonModH5PActivityXAPIData, } from '../../services/h5pactivity'; import { AddonModH5PActivitySync, @@ -409,7 +410,8 @@ export class AddonModH5PActivityIndexComponent extends CoreCourseModuleMainActiv * @return Promise resolved when done. */ protected async onIframeMessage(event: MessageEvent): Promise { - if (!event.data || !CoreXAPI.canPostStatementsInSite(this.site) || !this.isCurrentXAPIPost(event.data)) { + const data = event.data; + if (!data || !CoreXAPI.canPostStatementsInSite(this.site) || !this.isCurrentXAPIPost(data)) { return; } @@ -423,8 +425,8 @@ export class AddonModH5PActivityIndexComponent extends CoreCourseModuleMainActiv const sent = await CoreXAPI.postStatements( this.h5pActivity!.context, - event.data.component, - JSON.stringify(event.data.statements), + data.component, + JSON.stringify(data.statements), options, ); @@ -437,6 +439,12 @@ export class AddonModH5PActivityIndexComponent extends CoreCourseModuleMainActiv } catch (error) { // Ignore errors. } + + // Check if the H5P has ended. Final statements don't include a subContentId. + const hasEnded = data.statements.some(statement => !statement.object.id.includes('subContentId=')); + if (hasEnded) { + CoreCourse.checkModuleCompletion(this.courseId, this.module.completiondata); + } } } catch (error) { CoreDomUtils.showErrorModalDefault(error, 'Error sending tracking data.'); @@ -450,7 +458,7 @@ export class AddonModH5PActivityIndexComponent extends CoreCourseModuleMainActiv * @return Whether it's an XAPI post statement of the current activity. */ // eslint-disable-next-line @typescript-eslint/no-explicit-any - protected isCurrentXAPIPost(data: any): boolean { + protected isCurrentXAPIPost(data: any): data is AddonModH5PActivityXAPIData { if (data.environment != 'moodleapp' || data.context != 'h5p' || data.action != 'xapi_post_statement' || !data.statements) { return false; } diff --git a/src/addons/mod/h5pactivity/services/h5pactivity.ts b/src/addons/mod/h5pactivity/services/h5pactivity.ts index f3e3b0c1a..e43b39bdd 100644 --- a/src/addons/mod/h5pactivity/services/h5pactivity.ts +++ b/src/addons/mod/h5pactivity/services/h5pactivity.ts @@ -1128,3 +1128,43 @@ declare module '@singletons/events' { } } + +/** + * Data to be sent using xAPI. + */ +export type AddonModH5PActivityXAPIData = { + action: string; + component: string; + context: string; + environment: string; + statements: AddonModH5PActivityStatement[]; +}; + +/** + * xAPI statement. + */ +export type AddonModH5PActivityStatement = { + actor: Record; + context: Record; + object: { + id: string; + definition: Record; + objectType: string; + }; + result: { + completion: boolean; + duration: string; + score: { + min: number; + max: number; + raw: number; + scaled: number; + }; + success?: boolean; + response?: string; + }; + verb: { + id: string; + display: Record; + }; +};