From 8f474731b77aee0b5ec1f54556b3cfd3ad50acda Mon Sep 17 00:00:00 2001 From: Gabriele Antonini Date: Tue, 4 Jul 2023 10:21:16 +0200 Subject: [PATCH 01/13] feat: track text activities --- .../gatsby-theme-docs/src/layouts/content.js | 19 ++++++++++ .../components/self-learning-page.tsx | 15 ++++++++ .../self-learning/hooks/use-course-details.ts | 13 +++++-- .../src/content/course-3/overview.mdx | 35 +++++++++++++++++++ .../src/content/course-3/quiz.mdx | 9 +++++ .../src/data/navigation.yaml | 7 ++++ 6 files changed, 95 insertions(+), 3 deletions(-) create mode 100644 packages/gatsby-theme-docs/src/modules/self-learning/components/self-learning-page.tsx create mode 100644 websites/self-learning-smoke-test/src/content/course-3/overview.mdx create mode 100644 websites/self-learning-smoke-test/src/content/course-3/quiz.mdx diff --git a/packages/gatsby-theme-docs/src/layouts/content.js b/packages/gatsby-theme-docs/src/layouts/content.js index 8b3beaf28f..c15bbb5260 100644 --- a/packages/gatsby-theme-docs/src/layouts/content.js +++ b/packages/gatsby-theme-docs/src/layouts/content.js @@ -26,10 +26,25 @@ import { CourseCompleteModal, useCourseInfoByPageSlugs, } from '../modules/self-learning'; +import { + useFetchCourseDetails, + getMatchingTopic, +} from '../modules/self-learning/hooks/use-course-details'; +import SelfLearningPage from '../modules/self-learning/components/self-learning-page'; const LayoutContent = (props) => { const courseInfo = useCourseInfoByPageSlugs([props.pageContext.slug]); const courseId = courseInfo[props.pageContext.slug]?.courseId; + const { data } = useFetchCourseDetails(courseId); + const isSelfLearningPage = !!courseId; + let selfLearningTopic; + if (isSelfLearningPage) { + selfLearningTopic = getMatchingTopic( + data?.result?.topics, + courseInfo[props.pageContext.slug]?.topicName + ); + } + const { ref, inView, entry } = useInView(); const isSearchBoxInView = !Boolean(entry) || inView; const layoutState = useLayoutState(); @@ -97,6 +112,10 @@ const LayoutContent = (props) => { + {isSelfLearningPage && ( + + )} + {courseId} {props.children} diff --git a/packages/gatsby-theme-docs/src/modules/self-learning/components/self-learning-page.tsx b/packages/gatsby-theme-docs/src/modules/self-learning/components/self-learning-page.tsx new file mode 100644 index 0000000000..add0bcc5c5 --- /dev/null +++ b/packages/gatsby-theme-docs/src/modules/self-learning/components/self-learning-page.tsx @@ -0,0 +1,15 @@ +import { CourseTopic } from '../external-types'; + +type SelfLearningPageProps = { + topic: CourseTopic; +}; + +const SelfLearningPage = (props: SelfLearningPageProps) => { + // just dummy code for now + return props.topic?.activities[0]?.type === 'label' && + props.topic?.activities[0]?.name === 'pageview' + ? 'pageview' + : null; +}; + +export default SelfLearningPage; diff --git a/packages/gatsby-theme-docs/src/modules/self-learning/hooks/use-course-details.ts b/packages/gatsby-theme-docs/src/modules/self-learning/hooks/use-course-details.ts index fa07ba1c56..c2de4c9213 100644 --- a/packages/gatsby-theme-docs/src/modules/self-learning/hooks/use-course-details.ts +++ b/packages/gatsby-theme-docs/src/modules/self-learning/hooks/use-course-details.ts @@ -55,17 +55,24 @@ export const useFetchCourseDetails = ( }; }; -export const getTopicStatusByPageTitle = ( +export const getMatchingTopic = ( topics: CourseTopic[] | undefined, pageTitle: string ) => { if (!topics || !pageTitle) { - return 'notAvailable'; + return; } - const matchingTopic = topics.find( + return topics.find( (topic) => topic.name.trim().toLowerCase() === pageTitle.trim().toLowerCase() ); +}; + +export const getTopicStatusByPageTitle = ( + topics: CourseTopic[] | undefined, + pageTitle: string +) => { + const matchingTopic = getMatchingTopic(topics, pageTitle); if (matchingTopic) { return matchingTopic.completed ? 'completed' : 'inProgress'; } diff --git a/websites/self-learning-smoke-test/src/content/course-3/overview.mdx b/websites/self-learning-smoke-test/src/content/course-3/overview.mdx new file mode 100644 index 0000000000..75ca951ea3 --- /dev/null +++ b/websites/self-learning-smoke-test/src/content/course-3/overview.mdx @@ -0,0 +1,35 @@ +--- +title: Course overview +courseId: 70 +topicName: 'Overview' +--- + +The purpose of this activity is to track page view. It contains dummy content + +## Introduction + +In recent years, the landscape of education has witnessed a remarkable transformation with the advent of e-learning. As technological advancements continue to shape the way we live and learn, online education has emerged as a powerful tool that transcends boundaries and provides unparalleled opportunities for knowledge acquisition. In this article, we will delve into the world of e-learning and explore its evolution, benefits, and the potential it holds for the future. + +## The Evolution of E-Learning + +E-learning, or electronic learning, traces its roots back to the 1960s when the concept of computer-based training emerged. Initially, it involved the use of mainframe computers and punch cards to deliver educational content. However, it was not until the widespread availability of the internet in the 1990s that e-learning truly took off, paving the way for a revolution in education. + +## Benefits of E-Learning + +E-learning offers numerous advantages over traditional classroom-based learning. First and foremost, it provides flexibility and convenience. Learners can access educational materials and participate in courses from anywhere and at any time, eliminating the need for physical attendance. This flexibility allows individuals to balance their personal and professional commitments while pursuing their educational goals. + +Furthermore, e-learning promotes self-paced learning, allowing students to progress at their own speed. This personalized approach caters to diverse learning styles and preferences, enabling individuals to grasp concepts more effectively. Moreover, e-learning platforms often provide interactive elements, such as quizzes, videos, and simulations, which enhance engagement and knowledge retention. + +Another significant benefit of e-learning is its cost-effectiveness. Traditional education often involves expenses related to transportation, accommodation, and printed materials. E-learning eliminates many of these costs, making education more accessible and affordable for a wider audience. Additionally, e-learning enables institutions and organizations to reach a global audience without the need for physical infrastructure, expanding educational opportunities for individuals in remote areas or underserved communities. + +## The Future of E-Learning + +Looking ahead, the future of e-learning appears promising. As technology continues to advance, emerging trends such as artificial intelligence (AI), virtual reality (VR), and augmented reality (AR) are being integrated into e-learning platforms, revolutionizing the learning experience. AI-powered algorithms can personalize learning pathways based on individual strengths and weaknesses, providing targeted recommendations and adaptive feedback to enhance learning outcomes. + +Virtual reality and augmented reality have the potential to transform e-learning by creating immersive and interactive learning environments. Students can explore historical sites, conduct virtual science experiments, or engage in simulated real-life scenarios, significantly enhancing their understanding and retention of complex concepts. + +Moreover, the rise of microlearning, which involves delivering educational content in bite-sized modules, is gaining momentum. Microlearning caters to the shorter attention spans of learners in the digital age and allows for quick and efficient knowledge acquisition. It is particularly valuable for on-the-go professionals who can access short lessons or modules during their spare time. + +## Conclusion + +E-learning has come a long way since its inception and has proven to be a game-changer in the field of education. With its flexibility, cost-effectiveness, and personalized learning experiences, it has opened doors to education for millions worldwide. As technology continues to evolve, e-learning stands poised to unlock even greater potential, leveraging AI, VR, and AR to provide immersive and engaging educational experiences. The future of education is undoubtedly digital, and e-learning is at the forefront, revolutionizing the way we learn, grow, and adapt in an ever-changing world. diff --git a/websites/self-learning-smoke-test/src/content/course-3/quiz.mdx b/websites/self-learning-smoke-test/src/content/course-3/quiz.mdx new file mode 100644 index 0000000000..2efc7570b5 --- /dev/null +++ b/websites/self-learning-smoke-test/src/content/course-3/quiz.mdx @@ -0,0 +1,9 @@ +--- +title: Quiz component +courseId: 70 +topicName: 'Quiz 1' +--- + +# Test your knowledge + + diff --git a/websites/self-learning-smoke-test/src/data/navigation.yaml b/websites/self-learning-smoke-test/src/data/navigation.yaml index 19eb46fc1a..549cd9e395 100644 --- a/websites/self-learning-smoke-test/src/data/navigation.yaml +++ b/websites/self-learning-smoke-test/src/data/navigation.yaml @@ -15,3 +15,10 @@ path: /course-2/quiz - title: Test your knowledge 2 path: /course-2/2-quiz + +- chapter-title: Self-learning course 3 + pages: + - title: Overview + path: /course-3/overview + - title: Quiz + path: /course-3/quiz From 4714411657ecffbbfb9daea8a85f288000e31f0b Mon Sep 17 00:00:00 2001 From: Gabriele Antonini Date: Tue, 4 Jul 2023 10:41:33 +0200 Subject: [PATCH 02/13] chore: fix style --- .../self-learning-smoke-test/src/content/course-3/overview.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/websites/self-learning-smoke-test/src/content/course-3/overview.mdx b/websites/self-learning-smoke-test/src/content/course-3/overview.mdx index 75ca951ea3..e99d57a72c 100644 --- a/websites/self-learning-smoke-test/src/content/course-3/overview.mdx +++ b/websites/self-learning-smoke-test/src/content/course-3/overview.mdx @@ -12,7 +12,7 @@ In recent years, the landscape of education has witnessed a remarkable transform ## The Evolution of E-Learning -E-learning, or electronic learning, traces its roots back to the 1960s when the concept of computer-based training emerged. Initially, it involved the use of mainframe computers and punch cards to deliver educational content. However, it was not until the widespread availability of the internet in the 1990s that e-learning truly took off, paving the way for a revolution in education. +E-learning, or electronic learning, traces its roots back to when the concept of computer-based training emerged. Initially, it involved the use of mainframe computers and punch cards to deliver educational content. However, it was not until the widespread availability of the internet in that e-learning truly took off, paving the way for a revolution in education. ## Benefits of E-Learning From e5f15e559d4bdff8e4ead778c0a4a3318bf6fb71 Mon Sep 17 00:00:00 2001 From: Gabriele Antonini Date: Tue, 4 Jul 2023 15:15:14 +0200 Subject: [PATCH 03/13] feat: add tracking triggering for video component --- packages/gatsby-theme-docs/global.d.ts | 7 +++ .../components/video-player-client-side.js | 23 +++++++- .../components/self-learning-page.tsx | 57 +++++++++++++++++-- .../src/content/writing/images.mdx | 3 + .../src/content/course-3/video.mdx | 12 ++++ .../src/data/navigation.yaml | 2 + 6 files changed, 98 insertions(+), 6 deletions(-) create mode 100644 packages/gatsby-theme-docs/global.d.ts create mode 100644 websites/self-learning-smoke-test/src/content/course-3/video.mdx diff --git a/packages/gatsby-theme-docs/global.d.ts b/packages/gatsby-theme-docs/global.d.ts new file mode 100644 index 0000000000..66d59aa994 --- /dev/null +++ b/packages/gatsby-theme-docs/global.d.ts @@ -0,0 +1,7 @@ +import { VideoProgressReachedEvent } from './src/modules/self-learning/components/self-learning-page'; + +declare global { + interface GlobalEventHandlersEventMap { + videoProgressReached: VideoProgressReachedEvent; + } +} diff --git a/packages/gatsby-theme-docs/src/components/video-player-client-side.js b/packages/gatsby-theme-docs/src/components/video-player-client-side.js index f0a360047a..5d7b2aef4b 100644 --- a/packages/gatsby-theme-docs/src/components/video-player-client-side.js +++ b/packages/gatsby-theme-docs/src/components/video-player-client-side.js @@ -4,7 +4,7 @@ import { useLazyLoad } from '@commercetools-docs/ui-kit'; import LoadingSpinner from '@commercetools-uikit/loading-spinner'; import VideoPlaceholder from './video-placeholder'; -const videoJsVersion = '8.2.1'; +const videoJsVersion = '8.3.0'; /** * Preset value. Evaluate overtime if any of these needs to be a prop @@ -52,6 +52,26 @@ const VideoPlayer = (props) => { ); } const player = playerRef.current; + let eventTriggered = false; // Flag to track event triggering + + player.on('timeupdate', () => { + const completeThreshold = props.completeAtPercent + ? parseInt(props.completeAtPercent) / 100 + : 0.8; // defaults to 80% (0.8) + console.log('completeAtPercent', completeThreshold); + const currentTime = player.currentTime(); + const duration = player.duration(); + const progress = currentTime / duration; + if (!eventTriggered && progress >= completeThreshold) { + // Trigger custom event + const customEvent = new CustomEvent('videoProgressReached', { + detail: { progress }, + }); + const el = document.getElementById('application'); + el.dispatchEvent(customEvent); + eventTriggered = true; // Set the flag to prevent further triggering + } + }); return () => { if (player) { player.dispose(); @@ -78,6 +98,7 @@ const VideoPlayer = (props) => { VideoPlayer.propTypes = { url: PropTypes.string.isRequired, poster: PropTypes.string, + completeAtPercent: PropTypes.string, }; export default VideoPlayer; diff --git a/packages/gatsby-theme-docs/src/modules/self-learning/components/self-learning-page.tsx b/packages/gatsby-theme-docs/src/modules/self-learning/components/self-learning-page.tsx index add0bcc5c5..74fb65879c 100644 --- a/packages/gatsby-theme-docs/src/modules/self-learning/components/self-learning-page.tsx +++ b/packages/gatsby-theme-docs/src/modules/self-learning/components/self-learning-page.tsx @@ -1,15 +1,62 @@ +import { useEffect, useState } from 'react'; import { CourseTopic } from '../external-types'; type SelfLearningPageProps = { topic: CourseTopic; }; +export interface VideoProgressReachedEvent extends Event { + detail: { + progress: number; + }; +} + const SelfLearningPage = (props: SelfLearningPageProps) => { - // just dummy code for now - return props.topic?.activities[0]?.type === 'label' && - props.topic?.activities[0]?.name === 'pageview' - ? 'pageview' - : null; + const [actType, setActType] = useState(); + const pageviewRegexp = /^pageview/; + const videoRegexp = /^video/; + + useEffect(() => { + const handleVideoProgressReached = (event: VideoProgressReachedEvent) => { + const videoProgressEvent = event as VideoProgressReachedEvent; + const progress = videoProgressEvent.detail.progress; + // TODO: track video activity as completed + console.log(`User reached ${progress} of the video`); + }; + + const ancestorElement = document.getElementById( + 'application' + ) as HTMLElement; + if (actType === 'video' && ancestorElement) { + ancestorElement.addEventListener( + 'videoProgressReached', + handleVideoProgressReached + ); + + return () => { + ancestorElement.removeEventListener( + 'videoProgressReached', + handleVideoProgressReached + ); + }; + } + }, [actType]); + + useEffect(() => { + if (props.topic?.activities[0]?.type === 'label') { + const activityName = props.topic?.activities[0]?.name; + if (pageviewRegexp.test(activityName)) { + // text page activity + setActType('pageview'); + } else if (videoRegexp.test(activityName)) { + // video activity + setActType('video'); + } + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [props.topic]); + + return

{actType}

; }; export default SelfLearningPage; diff --git a/websites/documentation/src/content/writing/images.mdx b/websites/documentation/src/content/writing/images.mdx index c631301768..b38aa5fc78 100644 --- a/websites/documentation/src/content/writing/images.mdx +++ b/websites/documentation/src/content/writing/images.mdx @@ -70,17 +70,20 @@ The component accepts the following properties: - `url` (mandatory): The source URL to a video source to embed. - `poster`: an optional parameter specifying a URL to an image that displays before the video begins playing. This is often a frame of the video or a custom title screen. As soon as the user hits "play" the image will go away. If not specified, the initial frame of the video will be displayed instead. +- `completeAtPercent`: an optional parameter specifying the percentage of video the user need to watch to consider the learning activity complete. It must be a number between 0 and 100, it defaults to 80; ```md title="you write:" secondaryTheme diff --git a/websites/self-learning-smoke-test/src/content/course-3/video.mdx b/websites/self-learning-smoke-test/src/content/course-3/video.mdx new file mode 100644 index 0000000000..cdc2142925 --- /dev/null +++ b/websites/self-learning-smoke-test/src/content/course-3/video.mdx @@ -0,0 +1,12 @@ +--- +title: Video component +courseId: 70 +topicName: 'Video 1' +--- + +## Video + +