musora-content-services 2.31.2 → 2.32.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/docs/ContentOrganization.html +2 -2
- package/docs/Gamification.html +2 -2
- package/docs/UserManagementSystem.html +2 -2
- package/docs/api_types.js.html +2 -2
- package/docs/config.js.html +2 -8
- package/docs/content-org_content-org.js.html +2 -2
- package/docs/content-org_playlists-types.js.html +12 -2
- package/docs/content-org_playlists.js.html +16 -16
- package/docs/content.js.html +71 -39
- package/docs/gamification_awards.js.html +54 -35
- package/docs/gamification_gamification.js.html +2 -2
- package/docs/gamification_types.js.html +7 -25
- package/docs/global.html +298 -322
- package/docs/index.html +2 -2
- package/docs/module-Awards.html +2 -2
- package/docs/module-Config.html +4 -8
- package/docs/module-Content-Services-V2.html +455 -8
- package/docs/module-Interests.html +2 -2
- package/docs/module-Permissions.html +2 -2
- package/docs/module-Playlists.html +18 -17
- package/docs/module-Railcontent-Services.html +479 -35
- package/docs/module-Sanity-Services.html +45 -173
- package/docs/module-Sessions.html +2 -2
- package/docs/module-UserActivity.html +189 -21
- package/docs/module-UserChat.html +2 -2
- package/docs/module-UserManagement.html +410 -8
- package/docs/module-UserNotifications.html +203 -8
- package/docs/module-UserProfile.html +2 -2
- package/docs/railcontent.js.html +65 -37
- package/docs/sanity.js.html +120 -185
- package/docs/userActivity.js.html +448 -466
- package/docs/user_chat.js.html +2 -2
- package/docs/user_interests.js.html +2 -2
- package/docs/user_management.js.html +32 -2
- package/docs/user_notifications.js.html +27 -5
- package/docs/user_permissions.js.html +2 -2
- package/docs/user_profile.js.html +3 -9
- package/docs/user_sessions.js.html +2 -2
- package/docs/user_types.js.html +10 -2
- package/docs/user_user-management-system.js.html +2 -2
- package/package.json +1 -1
- package/src/contentTypeConfig.js +6 -1
- package/src/index.d.ts +6 -0
- package/src/index.js +6 -0
- package/src/services/sanity.js +14 -19
- package/src/services/user/management.js +30 -0
- package/src/services/user/types.js +8 -0
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
<nav >
|
|
30
30
|
|
|
31
31
|
|
|
32
|
-
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-Awards.html">Awards</a><ul class='methods'><li data-type='method'><a href="module-Awards.html#.fetchAwardsForUser">fetchAwardsForUser</a></li></ul></li><li><a href="module-Config.html">Config</a><ul class='methods'><li data-type='method'><a href="module-Config.html#.initializeService">initializeService</a></li></ul></li><li><a href="module-Content-Services-V2.html">Content-Services-V2</a><ul class='methods'><li data-type='method'><a href="module-Content-Services-V2.html#.getContentRows">getContentRows</a></li><li data-type='method'><a href="module-Content-Services-V2.html#.getNewAndUpcoming">getNewAndUpcoming</a></li><li data-type='method'><a href="module-Content-Services-V2.html#.getRecent">getRecent</a></li><li data-type='method'><a href="module-Content-Services-V2.html#.getRecommendedForYou">getRecommendedForYou</a></li><li data-type='method'><a href="module-Content-Services-V2.html#.getScheduleContentRows">getScheduleContentRows</a></li><li data-type='method'><a href="module-Content-Services-V2.html#.getTabResults">getTabResults</a></li></ul></li><li><a href="module-Interests.html">Interests</a><ul class='methods'><li data-type='method'><a href="module-Interests.html#.fetchInterests">fetchInterests</a></li><li data-type='method'><a href="module-Interests.html#.fetchUninterests">fetchUninterests</a></li><li data-type='method'><a href="module-Interests.html#.markContentAsInterested">markContentAsInterested</a></li><li data-type='method'><a href="module-Interests.html#.markContentAsNotInterested">markContentAsNotInterested</a></li><li data-type='method'><a href="module-Interests.html#.removeContentAsInterested">removeContentAsInterested</a></li><li data-type='method'><a href="module-Interests.html#.removeContentAsNotInterested">removeContentAsNotInterested</a></li></ul></li><li><a href="module-Permissions.html">Permissions</a><ul class='methods'><li data-type='method'><a href="module-Permissions.html#.fetchUserPermissions">fetchUserPermissions</a></li><li data-type='method'><a href="module-Permissions.html#.reset">reset</a></li></ul></li><li><a href="module-Playlists.html">Playlists</a><ul class='methods'><li data-type='method'><a href="module-Playlists.html#.addItemToPlaylist">addItemToPlaylist</a></li><li data-type='method'><a href="module-Playlists.html#.createPlaylist">createPlaylist</a></li><li data-type='method'><a href="module-Playlists.html#.deletePlaylist">deletePlaylist</a></li><li data-type='method'><a href="module-Playlists.html#.duplicatePlaylist">duplicatePlaylist</a></li><li data-type='method'><a href="module-Playlists.html#.fetchPlaylist">fetchPlaylist</a></li><li data-type='method'><a href="module-Playlists.html#.fetchPlaylistItems">fetchPlaylistItems</a></li><li data-type='method'><a href="module-Playlists.html#.fetchUserPlaylists">fetchUserPlaylists</a></li><li data-type='method'><a href="module-Playlists.html#.togglePlaylistPrivate">togglePlaylistPrivate</a></li><li data-type='method'><a href="module-Playlists.html#.undeletePlaylist">undeletePlaylist</a></li><li data-type='method'><a href="module-Playlists.html#.updatePlaylist">updatePlaylist</a></li><li data-type='method'><a href="module-Playlists.html#~deleteItemsFromPlaylist">deleteItemsFromPlaylist</a></li><li data-type='method'><a href="module-Playlists.html#~likePlaylist">likePlaylist</a></li><li data-type='method'><a href="module-Playlists.html#~reportPlaylist">reportPlaylist</a></li><li data-type='method'><a href="module-Playlists.html#~restoreItemFromPlaylist">restoreItemFromPlaylist</a></li><li data-type='method'><a href="module-Playlists.html#~unlikePlaylist">unlikePlaylist</a></li></ul></li><li><a href="module-Railcontent-Services.html">Railcontent-Services</a><ul class='methods'><li data-type='method'><a href="module-Railcontent-Services.html#.assignModeratorToComment">assignModeratorToComment</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.closeComment">closeComment</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.createComment">createComment</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.deleteComment">deleteComment</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.editComment">editComment</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.fetchAllCompletedStates">fetchAllCompletedStates</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.fetchCarouselCardData">fetchCarouselCardData</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.fetchComment">fetchComment</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.fetchCommentRelies">fetchCommentRelies</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.fetchComments">fetchComments</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.fetchCompletedContent">fetchCompletedContent</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.fetchCompletedState">fetchCompletedState</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.fetchContentInProgress">fetchContentInProgress</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.fetchContentPageUserData">fetchContentPageUserData</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.fetchNextContentDataForParent">fetchNextContentDataForParent</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.fetchRecentUserActivities">fetchRecentUserActivities</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.fetchSongsInProgress">fetchSongsInProgress</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.fetchTopComment">fetchTopComment</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.fetchUserAward">fetchUserAward</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.fetchUserBadges">fetchUserBadges</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.fetchUserPracticeNotes">fetchUserPracticeNotes</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.likeComment">likeComment</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.openComment">openComment</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.replyToComment">replyToComment</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.reportComment">reportComment</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.restoreComment">restoreComment</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.setStudentViewForUser">setStudentViewForUser</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.unassignModeratorToComment">unassignModeratorToComment</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.unlikeComment">unlikeComment</a></li><li data-type='method'><a href="module-Railcontent-Services.html#~fetchLastInteractedChild">fetchLastInteractedChild</a></li></ul></li><li><a href="module-Sanity-Services.html">Sanity-Services</a><ul class='methods'><li data-type='method'><a href="module-Sanity-Services.html#.fetchAll">fetchAll</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchAllFilterOptions">fetchAllFilterOptions</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchAllPacks">fetchAllPacks</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchArtistLessons">fetchArtistLessons</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchArtists">fetchArtists</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchByRailContentId">fetchByRailContentId</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchByRailContentIds">fetchByRailContentIds</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchByReference">fetchByReference</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchCoachLessons">fetchCoachLessons</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchComingSoon">fetchComingSoon</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchCommentModContentData">fetchCommentModContentData</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchFoundation">fetchFoundation</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchGenreLessons">fetchGenreLessons</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchLeaving">fetchLeaving</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchLessonContent">fetchLessonContent</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchLessonsFeaturingThisContent">fetchLessonsFeaturingThisContent</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchMetadata">fetchMetadata</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchMethod">fetchMethod</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchMethodChildren">fetchMethodChildren</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchMethodChildrenIds">fetchMethodChildrenIds</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchMethodPreviousNextLesson">fetchMethodPreviousNextLesson</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchNewReleases">fetchNewReleases</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchNextPreviousLesson">fetchNextPreviousLesson</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchOtherSongVersions">fetchOtherSongVersions</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchPackAll">fetchPackAll</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchPackData">fetchPackData</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchParentForDownload">fetchParentForDownload</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchRelatedLessons">fetchRelatedLessons</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchRelatedRecommendedContent">fetchRelatedRecommendedContent</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchRelatedSongs">fetchRelatedSongs</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchReturning">fetchReturning</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchSanity">fetchSanity</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchScheduledReleases">fetchScheduledReleases</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchShowsData">fetchShowsData</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchSiblingContent">fetchSiblingContent</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchSongArtistCount">fetchSongArtistCount</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchSongById">fetchSongById</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchUpcomingEvents">fetchUpcomingEvents</a></li><li data-type='method'><a href="module-Sanity-Services.html#.jumpToContinueContent">jumpToContinueContent</a></li><li data-type='method'><a href="module-Sanity-Services.html#~fetchRelatedByLicense">fetchRelatedByLicense</a></li><li data-type='method'><a href="module-Sanity-Services.html#~getNextAndPreviousQuarterDates">getNextAndPreviousQuarterDates</a></li><li data-type='method'><a href="module-Sanity-Services.html#~getQueryFromPage">getQueryFromPage</a></li></ul></li><li><a href="module-Sessions.html">Sessions</a><ul class='methods'><li data-type='method'><a href="module-Sessions.html#.login">login</a></li><li data-type='method'><a href="module-Sessions.html#.logout">logout</a></li></ul></li><li><a href="module-UserActivity.html">UserActivity</a><ul class='methods'><li data-type='method'><a href="module-UserActivity.html#.calculateLongestStreaks">calculateLongestStreaks</a></li><li data-type='method'><a href="module-UserActivity.html#.createPracticeNotes">createPracticeNotes</a></li><li data-type='method'><a href="module-UserActivity.html#.deletePracticeSession">deletePracticeSession</a></li><li data-type='method'><a href="module-UserActivity.html#.deleteUserActivity">deleteUserActivity</a></li><li data-type='method'><a href="module-UserActivity.html#.getPracticeNotes">getPracticeNotes</a></li><li data-type='method'><a href="module-UserActivity.html#.getPracticeSessions">getPracticeSessions</a></li><li data-type='method'><a href="module-UserActivity.html#.getProgressRows">getProgressRows</a></li><li data-type='method'><a href="module-UserActivity.html#.getRecentActivity">getRecentActivity</a></li><li data-type='method'><a href="module-UserActivity.html#.getUserMonthlyStats">getUserMonthlyStats</a></li><li data-type='method'><a href="module-UserActivity.html#.getUserWeeklyStats">getUserWeeklyStats</a></li><li data-type='method'><a href="module-UserActivity.html#.pinProgressRow">pinProgressRow</a></li><li data-type='method'><a href="module-UserActivity.html#.recordUserActivity">recordUserActivity</a></li><li data-type='method'><a href="module-UserActivity.html#.recordUserPractice">recordUserPractice</a></li><li data-type='method'><a href="module-UserActivity.html#.removeUserPractice">removeUserPractice</a></li><li data-type='method'><a href="module-UserActivity.html#.restorePracticeSession">restorePracticeSession</a></li><li data-type='method'><a href="module-UserActivity.html#.restoreUserPractice">restoreUserPractice</a></li><li data-type='method'><a href="module-UserActivity.html#.unpinProgressRow">unpinProgressRow</a></li><li data-type='method'><a href="module-UserActivity.html#.updatePracticeNotes">updatePracticeNotes</a></li><li data-type='method'><a href="module-UserActivity.html#.updateUserPractice">updateUserPractice</a></li></ul></li><li><a href="module-UserChat.html">UserChat</a><ul class='methods'><li data-type='method'><a href="module-UserChat.html#.fetchChatSettings">fetchChatSettings</a></li></ul></li><li><a href="module-UserManagement.html">UserManagement</a><ul class='methods'><li data-type='method'><a href="module-UserManagement.html#.blockUser">blockUser</a></li><li data-type='method'><a href="module-UserManagement.html#.deletePicture">deletePicture</a></li><li data-type='method'><a href="module-UserManagement.html#.getUserData">getUserData</a></li><li data-type='method'><a href="module-UserManagement.html#.unblockUser">unblockUser</a></li><li data-type='method'><a href="module-UserManagement.html#.uploadPicture">uploadPicture</a></li><li data-type='method'><a href="module-UserManagement.html#.uploadPictureFromS3">uploadPictureFromS3</a></li></ul></li><li><a href="module-UserNotifications.html">UserNotifications</a><ul class='methods'><li data-type='method'><a href="module-UserNotifications.html#.deleteNotification">deleteNotification</a></li><li data-type='method'><a href="module-UserNotifications.html#.fetchLiveEventPollingState">fetchLiveEventPollingState</a></li><li data-type='method'><a href="module-UserNotifications.html#.fetchNotificationSettings">fetchNotificationSettings</a></li><li data-type='method'><a href="module-UserNotifications.html#.fetchNotifications">fetchNotifications</a></li><li data-type='method'><a href="module-UserNotifications.html#.fetchUnreadCount">fetchUnreadCount</a></li><li data-type='method'><a href="module-UserNotifications.html#.markAllNotificationsAsRead">markAllNotificationsAsRead</a></li><li data-type='method'><a href="module-UserNotifications.html#.markNotificationAsRead">markNotificationAsRead</a></li><li data-type='method'><a href="module-UserNotifications.html#.markNotificationAsUnread">markNotificationAsUnread</a></li><li data-type='method'><a href="module-UserNotifications.html#.pauseLiveEventPolling">pauseLiveEventPolling</a></li><li data-type='method'><a href="module-UserNotifications.html#.startLiveEventPolling">startLiveEventPolling</a></li><li data-type='method'><a href="module-UserNotifications.html#.updateNotificationSetting">updateNotificationSetting</a></li></ul></li><li><a href="module-UserProfile.html">UserProfile</a><ul class='methods'><li data-type='method'><a href="module-UserProfile.html#.deleteProfilePicture">deleteProfilePicture</a></li><li data-type='method'><a href="module-UserProfile.html#.otherStats">otherStats</a></li></ul></li></ul><h3>Namespaces</h3><ul><li><a href="ContentOrganization.html">ContentOrganization</a></li><li><a href="Gamification.html">Gamification</a></li><li><a href="UserManagementSystem.html">UserManagementSystem</a></li></ul><h3><a href="global.html">Global</a></h3>
|
|
32
|
+
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-Awards.html">Awards</a><ul class='methods'><li data-type='method'><a href="module-Awards.html#.fetchAwardsForUser">fetchAwardsForUser</a></li></ul></li><li><a href="module-Config.html">Config</a><ul class='methods'><li data-type='method'><a href="module-Config.html#.initializeService">initializeService</a></li></ul></li><li><a href="module-Content-Services-V2.html">Content-Services-V2</a><ul class='methods'><li data-type='method'><a href="module-Content-Services-V2.html#.getContentRows">getContentRows</a></li><li data-type='method'><a href="module-Content-Services-V2.html#.getNewAndUpcoming">getNewAndUpcoming</a></li><li data-type='method'><a href="module-Content-Services-V2.html#.getRecent">getRecent</a></li><li data-type='method'><a href="module-Content-Services-V2.html#.getRecentForTab">getRecentForTab</a></li><li data-type='method'><a href="module-Content-Services-V2.html#.getRecommendedForYou">getRecommendedForYou</a></li><li data-type='method'><a href="module-Content-Services-V2.html#.getScheduleContentRows">getScheduleContentRows</a></li><li data-type='method'><a href="module-Content-Services-V2.html#.getTabResults">getTabResults</a></li></ul></li><li><a href="module-Interests.html">Interests</a><ul class='methods'><li data-type='method'><a href="module-Interests.html#.fetchInterests">fetchInterests</a></li><li data-type='method'><a href="module-Interests.html#.fetchUninterests">fetchUninterests</a></li><li data-type='method'><a href="module-Interests.html#.markContentAsInterested">markContentAsInterested</a></li><li data-type='method'><a href="module-Interests.html#.markContentAsNotInterested">markContentAsNotInterested</a></li><li data-type='method'><a href="module-Interests.html#.removeContentAsInterested">removeContentAsInterested</a></li><li data-type='method'><a href="module-Interests.html#.removeContentAsNotInterested">removeContentAsNotInterested</a></li></ul></li><li><a href="module-Permissions.html">Permissions</a><ul class='methods'><li data-type='method'><a href="module-Permissions.html#.fetchUserPermissions">fetchUserPermissions</a></li><li data-type='method'><a href="module-Permissions.html#.reset">reset</a></li></ul></li><li><a href="module-Playlists.html">Playlists</a><ul class='methods'><li data-type='method'><a href="module-Playlists.html#.addItemToPlaylist">addItemToPlaylist</a></li><li data-type='method'><a href="module-Playlists.html#.createPlaylist">createPlaylist</a></li><li data-type='method'><a href="module-Playlists.html#.deletePlaylist">deletePlaylist</a></li><li data-type='method'><a href="module-Playlists.html#.duplicatePlaylist">duplicatePlaylist</a></li><li data-type='method'><a href="module-Playlists.html#.fetchPlaylist">fetchPlaylist</a></li><li data-type='method'><a href="module-Playlists.html#.fetchPlaylistItems">fetchPlaylistItems</a></li><li data-type='method'><a href="module-Playlists.html#.fetchUserPlaylists">fetchUserPlaylists</a></li><li data-type='method'><a href="module-Playlists.html#.togglePlaylistPrivate">togglePlaylistPrivate</a></li><li data-type='method'><a href="module-Playlists.html#.undeletePlaylist">undeletePlaylist</a></li><li data-type='method'><a href="module-Playlists.html#.updatePlaylist">updatePlaylist</a></li><li data-type='method'><a href="module-Playlists.html#~deleteItemsFromPlaylist">deleteItemsFromPlaylist</a></li><li data-type='method'><a href="module-Playlists.html#~likePlaylist">likePlaylist</a></li><li data-type='method'><a href="module-Playlists.html#~reportPlaylist">reportPlaylist</a></li><li data-type='method'><a href="module-Playlists.html#~restoreItemFromPlaylist">restoreItemFromPlaylist</a></li><li data-type='method'><a href="module-Playlists.html#~unlikePlaylist">unlikePlaylist</a></li></ul></li><li><a href="module-Railcontent-Services.html">Railcontent-Services</a><ul class='methods'><li data-type='method'><a href="module-Railcontent-Services.html#.assignModeratorToComment">assignModeratorToComment</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.closeComment">closeComment</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.createComment">createComment</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.deleteComment">deleteComment</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.editComment">editComment</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.fetchAllCompletedStates">fetchAllCompletedStates</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.fetchCarouselCardData">fetchCarouselCardData</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.fetchComment">fetchComment</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.fetchCommentRelies">fetchCommentRelies</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.fetchComments">fetchComments</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.fetchCompletedContent">fetchCompletedContent</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.fetchCompletedState">fetchCompletedState</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.fetchContentInProgress">fetchContentInProgress</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.fetchContentPageUserData">fetchContentPageUserData</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.fetchNextContentDataForParent">fetchNextContentDataForParent</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.fetchRecentUserActivities">fetchRecentUserActivities</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.fetchSongsInProgress">fetchSongsInProgress</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.fetchTopComment">fetchTopComment</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.fetchUserAward">fetchUserAward</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.fetchUserBadges">fetchUserBadges</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.fetchUserPracticeNotes">fetchUserPracticeNotes</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.likeComment">likeComment</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.openComment">openComment</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.postContentComplete">postContentComplete</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.postContentReset">postContentReset</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.postContentRestore">postContentRestore</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.replyToComment">replyToComment</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.reportComment">reportComment</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.restoreComment">restoreComment</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.setStudentViewForUser">setStudentViewForUser</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.unassignModeratorToComment">unassignModeratorToComment</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.unlikeComment">unlikeComment</a></li><li data-type='method'><a href="module-Railcontent-Services.html#~fetchLastInteractedChild">fetchLastInteractedChild</a></li></ul></li><li><a href="module-Sanity-Services.html">Sanity-Services</a><ul class='methods'><li data-type='method'><a href="module-Sanity-Services.html#.fetchAll">fetchAll</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchAllFilterOptions">fetchAllFilterOptions</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchAllPacks">fetchAllPacks</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchArtistLessons">fetchArtistLessons</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchArtists">fetchArtists</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchByRailContentId">fetchByRailContentId</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchByRailContentIds">fetchByRailContentIds</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchByReference">fetchByReference</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchCoachLessons">fetchCoachLessons</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchComingSoon">fetchComingSoon</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchCommentModContentData">fetchCommentModContentData</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchFoundation">fetchFoundation</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchGenreLessons">fetchGenreLessons</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchLeaving">fetchLeaving</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchLessonContent">fetchLessonContent</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchLessonsFeaturingThisContent">fetchLessonsFeaturingThisContent</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchMetadata">fetchMetadata</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchMethod">fetchMethod</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchMethodChildren">fetchMethodChildren</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchMethodChildrenIds">fetchMethodChildrenIds</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchMethodPreviousNextLesson">fetchMethodPreviousNextLesson</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchNewReleases">fetchNewReleases</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchNextPreviousLesson">fetchNextPreviousLesson</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchOtherSongVersions">fetchOtherSongVersions</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchPackAll">fetchPackAll</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchPackData">fetchPackData</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchParentForDownload">fetchParentForDownload</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchRelatedLessons">fetchRelatedLessons</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchRelatedRecommendedContent">fetchRelatedRecommendedContent</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchRelatedSongs">fetchRelatedSongs</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchReturning">fetchReturning</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchSanity">fetchSanity</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchScheduledReleases">fetchScheduledReleases</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchShowsData">fetchShowsData</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchSiblingContent">fetchSiblingContent</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchSongArtistCount">fetchSongArtistCount</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchSongById">fetchSongById</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchUpcomingEvents">fetchUpcomingEvents</a></li><li data-type='method'><a href="module-Sanity-Services.html#.jumpToContinueContent">jumpToContinueContent</a></li><li data-type='method'><a href="module-Sanity-Services.html#~fetchRelatedByLicense">fetchRelatedByLicense</a></li><li data-type='method'><a href="module-Sanity-Services.html#~getQueryFromPage">getQueryFromPage</a></li></ul></li><li><a href="module-Sessions.html">Sessions</a><ul class='methods'><li data-type='method'><a href="module-Sessions.html#.login">login</a></li><li data-type='method'><a href="module-Sessions.html#.logout">logout</a></li></ul></li><li><a href="module-UserActivity.html">UserActivity</a><ul class='methods'><li data-type='method'><a href="module-UserActivity.html#.calculateLongestStreaks">calculateLongestStreaks</a></li><li data-type='method'><a href="module-UserActivity.html#.createPracticeNotes">createPracticeNotes</a></li><li data-type='method'><a href="module-UserActivity.html#.deletePracticeSession">deletePracticeSession</a></li><li data-type='method'><a href="module-UserActivity.html#.deleteUserActivity">deleteUserActivity</a></li><li data-type='method'><a href="module-UserActivity.html#.getPracticeNotes">getPracticeNotes</a></li><li data-type='method'><a href="module-UserActivity.html#.getPracticeSessions">getPracticeSessions</a></li><li data-type='method'><a href="module-UserActivity.html#.getProgressRows">getProgressRows</a></li><li data-type='method'><a href="module-UserActivity.html#.getRecentActivity">getRecentActivity</a></li><li data-type='method'><a href="module-UserActivity.html#.getUserMonthlyStats">getUserMonthlyStats</a></li><li data-type='method'><a href="module-UserActivity.html#.getUserWeeklyStats">getUserWeeklyStats</a></li><li data-type='method'><a href="module-UserActivity.html#.pinProgressRow">pinProgressRow</a></li><li data-type='method'><a href="module-UserActivity.html#.recordUserActivity">recordUserActivity</a></li><li data-type='method'><a href="module-UserActivity.html#.recordUserPractice">recordUserPractice</a></li><li data-type='method'><a href="module-UserActivity.html#.removeUserPractice">removeUserPractice</a></li><li data-type='method'><a href="module-UserActivity.html#.restorePracticeSession">restorePracticeSession</a></li><li data-type='method'><a href="module-UserActivity.html#.restoreUserActivity">restoreUserActivity</a></li><li data-type='method'><a href="module-UserActivity.html#.restoreUserPractice">restoreUserPractice</a></li><li data-type='method'><a href="module-UserActivity.html#.unpinProgressRow">unpinProgressRow</a></li><li data-type='method'><a href="module-UserActivity.html#.updatePracticeNotes">updatePracticeNotes</a></li><li data-type='method'><a href="module-UserActivity.html#.updateUserPractice">updateUserPractice</a></li></ul></li><li><a href="module-UserChat.html">UserChat</a><ul class='methods'><li data-type='method'><a href="module-UserChat.html#.fetchChatSettings">fetchChatSettings</a></li></ul></li><li><a href="module-UserManagement.html">UserManagement</a><ul class='methods'><li data-type='method'><a href="module-UserManagement.html#.blockUser">blockUser</a></li><li data-type='method'><a href="module-UserManagement.html#.blockedUsers">blockedUsers</a></li><li data-type='method'><a href="module-UserManagement.html#.deletePicture">deletePicture</a></li><li data-type='method'><a href="module-UserManagement.html#.getUserData">getUserData</a></li><li data-type='method'><a href="module-UserManagement.html#.isDisplayNameAvailable">isDisplayNameAvailable</a></li><li data-type='method'><a href="module-UserManagement.html#.unblockUser">unblockUser</a></li><li data-type='method'><a href="module-UserManagement.html#.updateDisplayName">updateDisplayName</a></li><li data-type='method'><a href="module-UserManagement.html#.uploadPicture">uploadPicture</a></li><li data-type='method'><a href="module-UserManagement.html#.uploadPictureFromS3">uploadPictureFromS3</a></li></ul></li><li><a href="module-UserNotifications.html">UserNotifications</a><ul class='methods'><li data-type='method'><a href="module-UserNotifications.html#.deleteNotification">deleteNotification</a></li><li data-type='method'><a href="module-UserNotifications.html#.fetchLiveEventPollingState">fetchLiveEventPollingState</a></li><li data-type='method'><a href="module-UserNotifications.html#.fetchNotificationSettings">fetchNotificationSettings</a></li><li data-type='method'><a href="module-UserNotifications.html#.fetchNotifications">fetchNotifications</a></li><li data-type='method'><a href="module-UserNotifications.html#.fetchUnreadCount">fetchUnreadCount</a></li><li data-type='method'><a href="module-UserNotifications.html#.markAllNotificationsAsRead">markAllNotificationsAsRead</a></li><li data-type='method'><a href="module-UserNotifications.html#.markNotificationAsRead">markNotificationAsRead</a></li><li data-type='method'><a href="module-UserNotifications.html#.markNotificationAsUnread">markNotificationAsUnread</a></li><li data-type='method'><a href="module-UserNotifications.html#.pauseLiveEventPolling">pauseLiveEventPolling</a></li><li data-type='method'><a href="module-UserNotifications.html#.restoreNotification">restoreNotification</a></li><li data-type='method'><a href="module-UserNotifications.html#.startLiveEventPolling">startLiveEventPolling</a></li><li data-type='method'><a href="module-UserNotifications.html#.updateNotificationSetting">updateNotificationSetting</a></li></ul></li><li><a href="module-UserProfile.html">UserProfile</a><ul class='methods'><li data-type='method'><a href="module-UserProfile.html#.deleteProfilePicture">deleteProfilePicture</a></li><li data-type='method'><a href="module-UserProfile.html#.otherStats">otherStats</a></li></ul></li></ul><h3>Namespaces</h3><ul><li><a href="ContentOrganization.html">ContentOrganization</a></li><li><a href="Gamification.html">Gamification</a></li><li><a href="UserManagementSystem.html">UserManagementSystem</a></li></ul><h3><a href="global.html">Global</a></h3>
|
|
33
33
|
|
|
34
34
|
</nav>
|
|
35
35
|
|
|
@@ -56,26 +56,33 @@ import {
|
|
|
56
56
|
fetchUserPracticeNotes,
|
|
57
57
|
fetchHandler,
|
|
58
58
|
fetchRecentUserActivities,
|
|
59
|
-
fetchLastInteractedChild,
|
|
60
59
|
} from './railcontent'
|
|
61
60
|
import { DataContext, UserActivityVersionKey } from './dataContext.js'
|
|
62
|
-
import { fetchByRailContentIds, fetchShows } from './sanity'
|
|
63
|
-
import {fetchPlaylist, fetchUserPlaylists} from
|
|
64
|
-
import {pinnedGuidedCourses} from
|
|
65
|
-
import {
|
|
61
|
+
import { fetchByRailContentId, fetchByRailContentIds, fetchShows } from './sanity'
|
|
62
|
+
import { fetchPlaylist, fetchUserPlaylists } from './content-org/playlists'
|
|
63
|
+
import { pinnedGuidedCourses } from './content-org/guided-courses'
|
|
64
|
+
import {
|
|
65
|
+
getMonday,
|
|
66
|
+
getWeekNumber,
|
|
67
|
+
isSameDate,
|
|
68
|
+
isNextDay,
|
|
69
|
+
getTimeRemainingUntilLocal,
|
|
70
|
+
toDayjs,
|
|
71
|
+
} from './dateUtils.js'
|
|
66
72
|
import { globalConfig } from './config'
|
|
67
|
-
import {collectionLessonTypes, lessonTypesMapping, progressTypesMapping, recentTypes, showsLessonTypes, songs} from "../contentTypeConfig";
|
|
68
73
|
import {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
import {
|
|
74
|
+
collectionLessonTypes,
|
|
75
|
+
progressTypesMapping,
|
|
76
|
+
recentTypes,
|
|
77
|
+
showsLessonTypes,
|
|
78
|
+
songs,
|
|
79
|
+
} from '../contentTypeConfig'
|
|
80
|
+
import { getAllStartedOrCompleted, getProgressStateByIds } from './contentProgress'
|
|
81
|
+
import { TabResponseType } from '../contentMetaData'
|
|
76
82
|
import dayjs from 'dayjs'
|
|
77
83
|
import isSameOrBefore from 'dayjs/plugin/isSameOrBefore'
|
|
78
84
|
import weekOfYear from 'dayjs/plugin/weekOfYear'
|
|
85
|
+
import { addContextToContent } from './contentAggregator.js'
|
|
79
86
|
|
|
80
87
|
const DATA_KEY_PRACTICES = 'practices'
|
|
81
88
|
const DATA_KEY_LAST_UPDATED_TIME = 'u'
|
|
@@ -135,7 +142,7 @@ export let userActivityContext = new DataContext(UserActivityVersionKey, fetchUs
|
|
|
135
142
|
* .catch(error => console.error(error));
|
|
136
143
|
*/
|
|
137
144
|
export async function getUserWeeklyStats() {
|
|
138
|
-
const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone
|
|
145
|
+
const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone
|
|
139
146
|
let data = await userActivityContext.getData()
|
|
140
147
|
let practices = data?.[DATA_KEY_PRACTICES] ?? {}
|
|
141
148
|
let sortedPracticeDays = Object.keys(practices)
|
|
@@ -146,10 +153,19 @@ export async function getUserWeeklyStats() {
|
|
|
146
153
|
let dailyStats = []
|
|
147
154
|
for (let i = 0; i < 7; i++) {
|
|
148
155
|
const day = startOfWeek.add(i, 'day')
|
|
149
|
-
let hasPractice = sortedPracticeDays.some((practiceDate) =>
|
|
150
|
-
|
|
156
|
+
let hasPractice = sortedPracticeDays.some((practiceDate) =>
|
|
157
|
+
isSameDate(practiceDate, day.format('YYYY-MM-DD'))
|
|
158
|
+
)
|
|
159
|
+
let isActive = isSameDate(today.format(), day.format())
|
|
151
160
|
let type = hasPractice ? 'tracked' : isActive ? 'active' : 'none'
|
|
152
|
-
dailyStats.push({
|
|
161
|
+
dailyStats.push({
|
|
162
|
+
key: i,
|
|
163
|
+
label: DAYS[i],
|
|
164
|
+
isActive,
|
|
165
|
+
inStreak: hasPractice,
|
|
166
|
+
type,
|
|
167
|
+
day: day.format('YYYY-MM-DD'),
|
|
168
|
+
})
|
|
153
169
|
}
|
|
154
170
|
|
|
155
171
|
let { streakMessage } = getStreaksAndMessage(practices)
|
|
@@ -216,7 +232,7 @@ export async function getUserMonthlyStats(params = {}) {
|
|
|
216
232
|
}
|
|
217
233
|
}
|
|
218
234
|
|
|
219
|
-
|
|
235
|
+
// let endOfMonth = new Date(year, month + 1, 0)
|
|
220
236
|
let endOfGrid = endOfMonth.clone()
|
|
221
237
|
while (endOfGrid.day() !== 0) {
|
|
222
238
|
endOfGrid = endOfGrid.add(1, 'day')
|
|
@@ -268,7 +284,7 @@ export async function getUserMonthlyStats(params = {}) {
|
|
|
268
284
|
|
|
269
285
|
// Filter past practices only
|
|
270
286
|
let filteredPractices = Object.entries(practices)
|
|
271
|
-
.filter(([date]) => dayjs
|
|
287
|
+
.filter(([date]) => dayjs(date).isSameOrBefore(endOfMonth))
|
|
272
288
|
.reduce((acc, [date, val]) => {
|
|
273
289
|
acc[date] = val
|
|
274
290
|
return acc
|
|
@@ -322,6 +338,7 @@ export async function getUserMonthlyStats(params = {}) {
|
|
|
322
338
|
*/
|
|
323
339
|
export async function recordUserPractice(practiceDetails) {
|
|
324
340
|
practiceDetails.auto = 0
|
|
341
|
+
practiceDetails.timezone = Intl.DateTimeFormat().resolvedOptions().timeZone
|
|
325
342
|
if (practiceDetails.content_id) {
|
|
326
343
|
practiceDetails.auto = 1
|
|
327
344
|
}
|
|
@@ -437,13 +454,11 @@ export async function restoreUserPractice(id) {
|
|
|
437
454
|
const restoredPractice = response.data.find((p) => p.id === id)
|
|
438
455
|
if (restoredPractice) {
|
|
439
456
|
await userActivityContext.updateLocal(async function (localContext) {
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
if (localContext.data[DATA_KEY_PRACTICES][date]) {
|
|
443
|
-
localContext.data[DATA_KEY_PRACTICES][date] = []
|
|
457
|
+
if (!localContext.data[DATA_KEY_PRACTICES][restoredPractice.day]) {
|
|
458
|
+
localContext.data[DATA_KEY_PRACTICES][restoredPractice.day] = []
|
|
444
459
|
}
|
|
445
460
|
response.data.forEach((restoredPractice) => {
|
|
446
|
-
localContext.data[DATA_KEY_PRACTICES][
|
|
461
|
+
localContext.data[DATA_KEY_PRACTICES][restoredPractice.day].push({
|
|
447
462
|
id: restoredPractice.id,
|
|
448
463
|
duration_seconds: restoredPractice.duration_seconds,
|
|
449
464
|
})
|
|
@@ -613,7 +628,21 @@ export async function getPracticeNotes(day) {
|
|
|
613
628
|
* .catch(error => console.error("Failed to get recent activity:", error));
|
|
614
629
|
*/
|
|
615
630
|
export async function getRecentActivity({ page = 1, limit = 5, tabName = null } = {}) {
|
|
616
|
-
|
|
631
|
+
const recentActivityData = await fetchRecentUserActivities({ page, limit, tabName })
|
|
632
|
+
const contentIds = recentActivityData.data.map((p) => p.contentId).filter((id) => id !== null)
|
|
633
|
+
const contents = await addContextToContent(fetchByRailContentIds, contentIds, {
|
|
634
|
+
addNavigateTo: true,
|
|
635
|
+
addNextLesson: true,
|
|
636
|
+
})
|
|
637
|
+
recentActivityData.data = recentActivityData.data.map((practice) => {
|
|
638
|
+
const content = contents?.find((c) => c.id === practice.contentId) || {}
|
|
639
|
+
return {
|
|
640
|
+
...practice,
|
|
641
|
+
parent_id: content.parent_id || null,
|
|
642
|
+
navigateTo: content.navigateTo,
|
|
643
|
+
}
|
|
644
|
+
})
|
|
645
|
+
return recentActivityData
|
|
617
646
|
}
|
|
618
647
|
|
|
619
648
|
/**
|
|
@@ -692,7 +721,7 @@ function calculateStreaks(practices, includeStreakMessage = false) {
|
|
|
692
721
|
let lastActiveDay = null
|
|
693
722
|
let streakMessage = ''
|
|
694
723
|
|
|
695
|
-
const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone
|
|
724
|
+
const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone
|
|
696
725
|
let sortedPracticeDays = Object.keys(practices)
|
|
697
726
|
.map((dateStr) => {
|
|
698
727
|
const [year, month, day] = dateStr.split('-').map(Number)
|
|
@@ -871,14 +900,15 @@ export async function calculateLongestStreaks(userId = globalConfig.sessionConfi
|
|
|
871
900
|
}
|
|
872
901
|
}
|
|
873
902
|
|
|
874
|
-
async function formatPracticeMeta(practices) {
|
|
903
|
+
async function formatPracticeMeta(practices = []) {
|
|
875
904
|
const contentIds = practices.map((p) => p.content_id).filter((id) => id !== null)
|
|
876
|
-
const contents = await fetchByRailContentIds
|
|
877
|
-
|
|
878
|
-
|
|
905
|
+
const contents = await addContextToContent(fetchByRailContentIds, contentIds, {
|
|
906
|
+
addNavigateTo: true,
|
|
907
|
+
addNextLesson: true,
|
|
908
|
+
})
|
|
879
909
|
|
|
880
910
|
return practices.map((practice) => {
|
|
881
|
-
const content = contents.find((c) => c.id === practice.content_id)
|
|
911
|
+
const content = contents && contents.length > 0 ? contents.find((c) => c.id === practice.content_id) : {}
|
|
882
912
|
|
|
883
913
|
return {
|
|
884
914
|
id: practice.id,
|
|
@@ -887,21 +917,22 @@ async function formatPracticeMeta(practices) {
|
|
|
887
917
|
thumbnail_url: practice.content_id ? content.thumbnail : practice.thumbnail_url || '',
|
|
888
918
|
duration: practice.duration_seconds || 0,
|
|
889
919
|
duration_seconds: practice.duration_seconds || 0,
|
|
890
|
-
content_url: content
|
|
920
|
+
content_url: content?.url || null,
|
|
891
921
|
title: practice.content_id ? content.title : practice.title,
|
|
892
922
|
category_id: practice.category_id,
|
|
893
923
|
instrument_id: practice.instrument_id,
|
|
894
|
-
content_type: getFormattedType(content
|
|
924
|
+
content_type: getFormattedType(content?.type || '', content?.brand || null),
|
|
895
925
|
content_id: practice.content_id || null,
|
|
896
|
-
content_brand: content
|
|
897
|
-
created_at:
|
|
898
|
-
sanity_type: content
|
|
899
|
-
content_slug: content
|
|
926
|
+
content_brand: content?.brand || null,
|
|
927
|
+
created_at: dayjs(practice.created_at),
|
|
928
|
+
sanity_type: content?.type || null,
|
|
929
|
+
content_slug: content?.slug || null,
|
|
930
|
+
parent_id: content?.parent_id || null,
|
|
931
|
+
navigateTo: content?.navigateTo || null,
|
|
900
932
|
}
|
|
901
933
|
})
|
|
902
934
|
}
|
|
903
935
|
|
|
904
|
-
|
|
905
936
|
/**
|
|
906
937
|
* Records a new user activity in the system.
|
|
907
938
|
*
|
|
@@ -945,6 +976,112 @@ export async function deleteUserActivity(id) {
|
|
|
945
976
|
const url = `/api/user-management-system/v1/activities/${id}`
|
|
946
977
|
return await fetchHandler(url, 'DELETE')
|
|
947
978
|
}
|
|
979
|
+
|
|
980
|
+
/**
|
|
981
|
+
* Restores a specific user activity by its ID.
|
|
982
|
+
*
|
|
983
|
+
* @param {number|string} id - The ID of the user activity to restore.
|
|
984
|
+
* @returns {Promise<Object>} - A promise that resolves to the API response after restoration.
|
|
985
|
+
*
|
|
986
|
+
* @example
|
|
987
|
+
* restoreUserActivity(789)
|
|
988
|
+
* .then(response => console.log('Restored:', response))
|
|
989
|
+
* .catch(error => console.error(error));
|
|
990
|
+
*/
|
|
991
|
+
export async function restoreUserActivity(id) {
|
|
992
|
+
const url = `/api/user-management-system/v1/activities/${id}`
|
|
993
|
+
return await fetchHandler(url, 'POST')
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
async function extractPinnedItemsAndSortAllItems(
|
|
997
|
+
userPinnedItem,
|
|
998
|
+
contentsMap,
|
|
999
|
+
eligiblePlaylistItems,
|
|
1000
|
+
pinnedGuidedCourse,
|
|
1001
|
+
limit
|
|
1002
|
+
) {
|
|
1003
|
+
let pinnedItem = await popPinnedItemFromContentsOrPlaylistMap(
|
|
1004
|
+
userPinnedItem,
|
|
1005
|
+
contentsMap,
|
|
1006
|
+
eligiblePlaylistItems
|
|
1007
|
+
)
|
|
1008
|
+
|
|
1009
|
+
const guidedCourseID = pinnedGuidedCourse?.content_id
|
|
1010
|
+
let combined = []
|
|
1011
|
+
if (pinnedGuidedCourse) {
|
|
1012
|
+
const guidedCourseContent =
|
|
1013
|
+
contentsMap.get(guidedCourseID) ??
|
|
1014
|
+
(await addContextToContent(fetchByRailContentId, guidedCourseID, 'guided-course', {
|
|
1015
|
+
addNextLesson: true,
|
|
1016
|
+
addNavigateTo: true,
|
|
1017
|
+
addProgressStatus: true,
|
|
1018
|
+
addProgressPercentage: true,
|
|
1019
|
+
addProgressTimestamp: true,
|
|
1020
|
+
}))
|
|
1021
|
+
contentsMap = popContentAndRemoveChildrenFromContentsMap(guidedCourseContent, contentsMap)
|
|
1022
|
+
guidedCourseContent.pinned = true
|
|
1023
|
+
combined.push(guidedCourseContent)
|
|
1024
|
+
}
|
|
1025
|
+
if (pinnedItem) {
|
|
1026
|
+
pinnedItem.pinned = true
|
|
1027
|
+
combined.push(pinnedItem)
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
const progressList = Array.from(contentsMap.values())
|
|
1031
|
+
combined = [...combined, ...progressList, ...eligiblePlaylistItems]
|
|
1032
|
+
return mergeAndSortItems(combined, limit)
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
function generateContentsMap(contents, playlistsContents) {
|
|
1036
|
+
const excludedTypes = new Set([
|
|
1037
|
+
'pack-bundle',
|
|
1038
|
+
'learning-path-course',
|
|
1039
|
+
'learning-path-level',
|
|
1040
|
+
'guided-course-part',
|
|
1041
|
+
])
|
|
1042
|
+
const existingShows = new Set()
|
|
1043
|
+
const contentsMap = new Map()
|
|
1044
|
+
const childToParentMap = {}
|
|
1045
|
+
contents.forEach((content) => {
|
|
1046
|
+
if (Array.isArray(content.parent_content_data) && content.parent_content_data.length > 0) {
|
|
1047
|
+
childToParentMap[content.id] =
|
|
1048
|
+
content.parent_content_data[content.parent_content_data.length - 1]
|
|
1049
|
+
}
|
|
1050
|
+
})
|
|
1051
|
+
|
|
1052
|
+
const allRecentTypeSet = new Set(Object.values(recentTypes).flat())
|
|
1053
|
+
contents.forEach((content) => {
|
|
1054
|
+
const id = content.id
|
|
1055
|
+
const type = content.type
|
|
1056
|
+
if (
|
|
1057
|
+
excludedTypes.has(type) ||
|
|
1058
|
+
(!allRecentTypeSet.has(type) && !showsLessonTypes.includes(type))
|
|
1059
|
+
)
|
|
1060
|
+
return
|
|
1061
|
+
if (!childToParentMap[id]) {
|
|
1062
|
+
// Shows don't have a parent to link them, but need to be handled as if they're a set of children
|
|
1063
|
+
if (!existingShows.has(type)) {
|
|
1064
|
+
contentsMap.set(id, content)
|
|
1065
|
+
}
|
|
1066
|
+
if (showsLessonTypes.includes(type)) {
|
|
1067
|
+
existingShows.add(type)
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
})
|
|
1071
|
+
|
|
1072
|
+
// TODO this doesn't work for guided courses as the GC card takes precedence over the playlist card
|
|
1073
|
+
// https://musora.atlassian.net/browse/BEH-812
|
|
1074
|
+
if (playlistsContents) {
|
|
1075
|
+
for (const item of playlistsContents) {
|
|
1076
|
+
const contentId = item.id
|
|
1077
|
+
contentsMap.delete(contentId)
|
|
1078
|
+
const parentIds = item.parent_content_data || []
|
|
1079
|
+
parentIds.forEach((id) => contentsMap.delete(id))
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
return contentsMap
|
|
1083
|
+
}
|
|
1084
|
+
|
|
948
1085
|
/**
|
|
949
1086
|
* Fetches and combines recent user progress rows and playlists, excluding certain types and parents.
|
|
950
1087
|
*
|
|
@@ -959,425 +1096,357 @@ export async function deleteUserActivity(id) {
|
|
|
959
1096
|
* .catch(error => console.error(error));
|
|
960
1097
|
*/
|
|
961
1098
|
export async function getProgressRows({ brand = null, limit = 8 } = {}) {
|
|
962
|
-
const excludedTypes = new Set([
|
|
963
|
-
'pack-bundle',
|
|
964
|
-
'learning-path-course',
|
|
965
|
-
'learning-path-level'
|
|
966
|
-
]);
|
|
967
1099
|
// TODO slice progress to a reasonable number, say 100
|
|
968
|
-
const [recentPlaylists, progressContents, allPinnedGuidedCourse, userPinnedItem
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
1100
|
+
const [recentPlaylists, progressContents, allPinnedGuidedCourse, userPinnedItem] =
|
|
1101
|
+
await Promise.all([
|
|
1102
|
+
fetchUserPlaylists(brand, { sort: '-last_progress', limit: limit }),
|
|
1103
|
+
getAllStartedOrCompleted({ onlyIds: false, brand: brand }),
|
|
1104
|
+
pinnedGuidedCourses(brand),
|
|
1105
|
+
getUserPinnedItem(brand),
|
|
1106
|
+
])
|
|
975
1107
|
let pinnedGuidedCourse = allPinnedGuidedCourse?.[0] ?? null
|
|
976
1108
|
|
|
977
|
-
const playlists = recentPlaylists?.data || []
|
|
978
|
-
const eligiblePlaylistItems = await getEligiblePlaylistItems(playlists)
|
|
979
|
-
const playlistEngagedOnContents = eligiblePlaylistItems.map(
|
|
1109
|
+
const playlists = recentPlaylists?.data || []
|
|
1110
|
+
const eligiblePlaylistItems = await getEligiblePlaylistItems(playlists)
|
|
1111
|
+
const playlistEngagedOnContents = eligiblePlaylistItems.map(
|
|
1112
|
+
(item) => item.playlist.last_engaged_on
|
|
1113
|
+
)
|
|
980
1114
|
|
|
981
1115
|
const nonPlaylistContentIds = Object.keys(progressContents)
|
|
982
1116
|
if (pinnedGuidedCourse) {
|
|
983
|
-
nonPlaylistContentIds.push(pinnedGuidedCourse.content_id)
|
|
1117
|
+
nonPlaylistContentIds.push(pinnedGuidedCourse.content_id)
|
|
984
1118
|
}
|
|
985
1119
|
if (userPinnedItem?.progressType === 'content') {
|
|
986
1120
|
nonPlaylistContentIds.push(userPinnedItem.id)
|
|
987
1121
|
}
|
|
988
|
-
const [
|
|
989
|
-
fetchByRailContentIds
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
const contentsMap = {};
|
|
1007
|
-
contents.forEach(content => {
|
|
1008
|
-
contentsMap[content.railcontent_id] = content;
|
|
1009
|
-
});
|
|
1010
|
-
const childToParentMap = {};
|
|
1011
|
-
Object.values(contentsMap).forEach(content => {
|
|
1012
|
-
if (Array.isArray(content.parent_content_data) && content.parent_content_data.length > 0) {
|
|
1013
|
-
childToParentMap[content.id] = content.parent_content_data[content.parent_content_data.length - 1];
|
|
1014
|
-
}
|
|
1015
|
-
});
|
|
1016
|
-
|
|
1017
|
-
const allRecentTypeSet = new Set(
|
|
1018
|
-
Object.values(recentTypes).flat()
|
|
1019
|
-
)
|
|
1020
|
-
const progressMap = new Map();
|
|
1021
|
-
for (const [idStr, progress] of Object.entries(progressContents)) {
|
|
1022
|
-
const id = parseInt(idStr);
|
|
1023
|
-
const content = contentsMap[id];
|
|
1024
|
-
if (!content || excludedTypes.has(content.type) || !allRecentTypeSet.has(content.type) ) continue;
|
|
1025
|
-
const parentId = childToParentMap[id];
|
|
1026
|
-
// Handle children with parents
|
|
1027
|
-
if (parentId) {
|
|
1028
|
-
const parentContent = contentsMap[parentId];
|
|
1029
|
-
if (!parentContent || excludedTypes.has(parentContent.type)) continue;
|
|
1030
|
-
const existing = progressMap.get(parentId);
|
|
1031
|
-
if (existing) {
|
|
1032
|
-
// If childIndex isn't already set, set it
|
|
1033
|
-
if (existing.childIndex === undefined) {
|
|
1034
|
-
existing.childIndex = id;
|
|
1035
|
-
}
|
|
1036
|
-
} else {
|
|
1037
|
-
progressMap.set(parentId, {
|
|
1038
|
-
id: parentId,
|
|
1039
|
-
raw: parentContent,
|
|
1040
|
-
state: progress.status,
|
|
1041
|
-
percent: progress.progress,
|
|
1042
|
-
progressTimestamp: progress.last_update * 1000,
|
|
1043
|
-
childIndex: id
|
|
1044
|
-
});
|
|
1045
|
-
}
|
|
1046
|
-
continue;
|
|
1047
|
-
}
|
|
1048
|
-
// Handle standalone parents
|
|
1049
|
-
if (!progressMap.has(id)) {
|
|
1050
|
-
if(!existingShows.has(content.type)){
|
|
1051
|
-
progressMap.set(id, {
|
|
1052
|
-
id,
|
|
1053
|
-
raw: content,
|
|
1054
|
-
state: progress.status,
|
|
1055
|
-
percent: progress.progress,
|
|
1056
|
-
progressTimestamp: progress.last_update * 1000
|
|
1057
|
-
});
|
|
1058
|
-
}
|
|
1059
|
-
if(showsLessonTypes.includes(content.type)) {
|
|
1060
|
-
existingShows.add(content.type)
|
|
1061
|
-
}
|
|
1062
|
-
}
|
|
1063
|
-
}
|
|
1064
|
-
const pinnedItem = userPinnedItem ? await extractPinnedItem(
|
|
1122
|
+
const [playlistsContents, contents] = await Promise.all([
|
|
1123
|
+
addContextToContent(fetchByRailContentIds, playlistEngagedOnContents, 'progress-tracker', {
|
|
1124
|
+
addNextLesson: true,
|
|
1125
|
+
addNavigateTo: true,
|
|
1126
|
+
addProgressStatus: true,
|
|
1127
|
+
addProgressPercentage: true,
|
|
1128
|
+
addProgressTimestamp: true,
|
|
1129
|
+
}),
|
|
1130
|
+
addContextToContent(fetchByRailContentIds, nonPlaylistContentIds, 'progress-tracker', brand, {
|
|
1131
|
+
addNextLesson: true,
|
|
1132
|
+
addNavigateTo: true,
|
|
1133
|
+
addProgressStatus: true,
|
|
1134
|
+
addProgressPercentage: true,
|
|
1135
|
+
addProgressTimestamp: true,
|
|
1136
|
+
}),
|
|
1137
|
+
])
|
|
1138
|
+
const contentsMap = generateContentsMap(contents, playlistsContents)
|
|
1139
|
+
let combined = await extractPinnedItemsAndSortAllItems(
|
|
1065
1140
|
userPinnedItem,
|
|
1066
|
-
|
|
1141
|
+
contentsMap,
|
|
1067
1142
|
eligiblePlaylistItems,
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
const guidedCourseID = pinnedGuidedCourse?.content_id
|
|
1072
|
-
let combined = [];
|
|
1073
|
-
if (pinnedGuidedCourse) {
|
|
1074
|
-
const guidedCourseContent = contentsMap[guidedCourseID]
|
|
1075
|
-
if (guidedCourseContent) {
|
|
1076
|
-
const temp = await extractPinnedGuidedCourseItem(guidedCourseContent, progressMap)
|
|
1077
|
-
temp.pinned = true
|
|
1078
|
-
combined.push(temp)
|
|
1079
|
-
}
|
|
1080
|
-
}
|
|
1081
|
-
if (pinnedItem) {
|
|
1082
|
-
pinnedItem.pinned = true
|
|
1083
|
-
combined.push(pinnedItem)
|
|
1084
|
-
}
|
|
1085
|
-
const progressList = Array.from(progressMap.values())
|
|
1086
|
-
|
|
1087
|
-
const filteredProgressList = pinnedId
|
|
1088
|
-
? progressList.filter(item => !(item.id === pinnedId || item.id === guidedCourseID))
|
|
1089
|
-
: progressList;
|
|
1090
|
-
const filteredPlaylists = pinnedId
|
|
1091
|
-
? (eligiblePlaylistItems.filter(item => !(item.id === pinnedId || item.id === guidedCourseID)))
|
|
1092
|
-
: eligiblePlaylistItems;
|
|
1093
|
-
|
|
1094
|
-
combined = [...combined, ...filteredProgressList, ...filteredPlaylists]
|
|
1095
|
-
const finalCombined = mergeAndSortItems(combined, limit)
|
|
1143
|
+
pinnedGuidedCourse,
|
|
1144
|
+
limit
|
|
1145
|
+
)
|
|
1096
1146
|
const results = await Promise.all(
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
: processContentItem(item)
|
|
1101
|
-
|
|
1102
|
-
)
|
|
1103
|
-
|
|
1147
|
+
combined
|
|
1148
|
+
.slice(0, limit)
|
|
1149
|
+
.map((item) =>
|
|
1150
|
+
item.type === 'playlist' ? processPlaylistItem(item) : processContentItem(item)
|
|
1151
|
+
)
|
|
1152
|
+
)
|
|
1153
|
+
console.log('HomePageProgressRows results: remove before merge', results)
|
|
1104
1154
|
return {
|
|
1105
1155
|
type: TabResponseType.PROGRESS_ROWS,
|
|
1106
1156
|
displayBrowseAll: combined.length > limit,
|
|
1107
|
-
data: results
|
|
1108
|
-
}
|
|
1157
|
+
data: results,
|
|
1158
|
+
}
|
|
1109
1159
|
}
|
|
1110
1160
|
|
|
1111
1161
|
async function getUserPinnedItem(brand) {
|
|
1112
|
-
const userRaw = await globalConfig.localStorage.getItem('user')
|
|
1113
|
-
const user = userRaw ? JSON.parse(userRaw) : {}
|
|
1162
|
+
const userRaw = await globalConfig.localStorage.getItem('user')
|
|
1163
|
+
const user = userRaw ? JSON.parse(userRaw) : {}
|
|
1114
1164
|
user.brand_pinned_progress = user.brand_pinned_progress || {}
|
|
1115
1165
|
return user.brand_pinned_progress[brand] ?? null
|
|
1116
1166
|
}
|
|
1117
1167
|
|
|
1118
|
-
async function processContentItem(
|
|
1119
|
-
|
|
1120
|
-
const
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
if (
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
if (
|
|
1138
|
-
|
|
1139
|
-
const nextByProgress = findIncompleteLesson(progressOnItems, item.childIndex, item.raw.type)
|
|
1140
|
-
nextId = nextByProgress ? nextByProgress : nextId
|
|
1141
|
-
|
|
1142
|
-
const nestedLessons = data.lessons
|
|
1143
|
-
.filter(item => Array.isArray(item.lessons))
|
|
1144
|
-
.flatMap(parent =>
|
|
1145
|
-
parent.lessons.map(lesson => ({
|
|
1146
|
-
...lesson,
|
|
1147
|
-
parent: {
|
|
1148
|
-
id: parent.id,
|
|
1149
|
-
slug: parent.slug,
|
|
1150
|
-
title: parent.title,
|
|
1151
|
-
type: parent.type
|
|
1152
|
-
}
|
|
1153
|
-
}))
|
|
1154
|
-
);
|
|
1155
|
-
|
|
1156
|
-
const lessons = (nestedLessons.length === 0) ? data.lessons : nestedLessons
|
|
1157
|
-
const nextLesson = lessons.find(lesson => lesson.id === nextId)
|
|
1158
|
-
data.first_incomplete_child = nextLesson?.parent ?? nextLesson
|
|
1159
|
-
data.second_incomplete_child = (nextLesson?.parent) ? nextLesson : null
|
|
1160
|
-
if(data.type === 'guided-course'){
|
|
1161
|
-
let isLocked = new Date(nextLesson.published_on) > new Date()
|
|
1162
|
-
data.thumbnail = nextLesson.thumbnail
|
|
1163
|
-
// USHP-4 completed
|
|
1164
|
-
if (status === 'completed') {
|
|
1165
|
-
// duplicated code to above, but here for clarity
|
|
1166
|
-
ctaText = 'Revisit Lessons'
|
|
1167
|
-
// USHP-1 if lesson locked show unlock in X time
|
|
1168
|
-
} else if (isLocked) {
|
|
1169
|
-
data.is_locked = true
|
|
1170
|
-
const timeRemaining = getTimeRemainingUntilLocal(nextLesson.published_on, {withTotalSeconds: true})
|
|
1171
|
-
data.time_remaining_seconds = timeRemaining.totalSeconds
|
|
1172
|
-
ctaText = 'Next lesson in ' + timeRemaining.formatted
|
|
1173
|
-
}
|
|
1174
|
-
// USHP-2 start course if not started
|
|
1175
|
-
else if (status === 'not-started') {
|
|
1176
|
-
ctaText = "Start Course"
|
|
1177
|
-
}
|
|
1178
|
-
// USHP-3 in progress for lesson
|
|
1179
|
-
else {
|
|
1180
|
-
ctaText = "Continue"
|
|
1181
|
-
}
|
|
1182
|
-
}
|
|
1168
|
+
async function processContentItem(content) {
|
|
1169
|
+
const contentType = getFormattedType(content.type, content.brand)
|
|
1170
|
+
const isLive = content.isLive ?? false
|
|
1171
|
+
let ctaText = getDefaultCTATextForContent(content, contentType)
|
|
1172
|
+
|
|
1173
|
+
content.completed_children = await getCompletedChildren(content, contentType)
|
|
1174
|
+
|
|
1175
|
+
if (content.type === 'guided-course') {
|
|
1176
|
+
const nextLessonPublishedOn = content.children.find(
|
|
1177
|
+
(child) => child.id === content.navigateTo.id
|
|
1178
|
+
)?.published_on
|
|
1179
|
+
let isLocked = new Date(nextLessonPublishedOn) > new Date()
|
|
1180
|
+
if (isLocked) {
|
|
1181
|
+
content.is_locked = true
|
|
1182
|
+
const timeRemaining = getTimeRemainingUntilLocal(nextLessonPublishedOn, {
|
|
1183
|
+
withTotalSeconds: true,
|
|
1184
|
+
})
|
|
1185
|
+
content.time_remaining_seconds = timeRemaining.totalSeconds
|
|
1186
|
+
ctaText = 'Next lesson in ' + timeRemaining.formatted
|
|
1187
|
+
} else if (!content.progressStatus || content.progressStatus === 'not-started') {
|
|
1188
|
+
ctaText = 'Start Course'
|
|
1183
1189
|
}
|
|
1184
1190
|
}
|
|
1185
1191
|
|
|
1186
|
-
if(contentType
|
|
1187
|
-
const shows = await fetchShows(
|
|
1188
|
-
const showIds = shows.map(item => item.id)
|
|
1189
|
-
const progressOnItems = await getProgressStateByIds(showIds)
|
|
1190
|
-
const
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1192
|
+
if (contentType === 'show') {
|
|
1193
|
+
const shows = await fetchShows(content.brand, content.type)
|
|
1194
|
+
const showIds = shows.map((item) => item.id)
|
|
1195
|
+
const progressOnItems = await getProgressStateByIds(showIds)
|
|
1196
|
+
const completedShows = content.completed_children
|
|
1197
|
+
const progressTimestamp = content.progressTimestamp
|
|
1198
|
+
const wasPinned = content.pinned ?? false
|
|
1199
|
+
if (content.progressStatus === 'completed') {
|
|
1200
|
+
// this could be handled more gracefully if their was a parent content type for shows
|
|
1201
|
+
const nextByProgress = findIncompleteLesson(progressOnItems, content.id, content.type)
|
|
1202
|
+
content = shows.find((lesson) => lesson.id === nextByProgress)
|
|
1203
|
+
content.completed_children = completedShows
|
|
1204
|
+
content.progressTimestamp = progressTimestamp
|
|
1205
|
+
content.pinned = wasPinned
|
|
1194
1206
|
}
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
ctaText = 'Revisit Lessons';
|
|
1207
|
+
content.child_count = shows.length
|
|
1208
|
+
content.progressPercentage = Math.round((completedShows / shows.length) * 100)
|
|
1209
|
+
if (completedShows === shows.length) {
|
|
1210
|
+
ctaText = 'Revisit Show'
|
|
1200
1211
|
}
|
|
1201
1212
|
}
|
|
1202
1213
|
|
|
1203
1214
|
return {
|
|
1204
|
-
id:
|
|
1215
|
+
id: content.id,
|
|
1205
1216
|
progressType: 'content',
|
|
1206
1217
|
header: contentType,
|
|
1207
|
-
pinned:
|
|
1218
|
+
pinned: content.pinned ?? false,
|
|
1219
|
+
content: content,
|
|
1208
1220
|
body: {
|
|
1209
|
-
progressPercent: isLive ? undefined:
|
|
1210
|
-
thumbnail:
|
|
1211
|
-
title:
|
|
1221
|
+
progressPercent: isLive ? undefined : content.progressPercentage,
|
|
1222
|
+
thumbnail: content.thumbnail,
|
|
1223
|
+
title: content.title,
|
|
1212
1224
|
isLive: isLive,
|
|
1213
|
-
badge:
|
|
1214
|
-
isLocked:
|
|
1215
|
-
subtitle:
|
|
1216
|
-
?
|
|
1217
|
-
: `${
|
|
1225
|
+
badge: content.badge ?? null,
|
|
1226
|
+
isLocked: content.is_locked ?? false,
|
|
1227
|
+
subtitle: collectionLessonTypes.includes(content.type) || content.lesson_count > 1
|
|
1228
|
+
? `${content.completed_children} of ${content.lesson_count ?? content.child_count} Lessons Complete`
|
|
1229
|
+
: (contentType === 'lesson' && isLive === false) ? `${content.progressPercentage}% Complete`: `${content.difficulty_string} • ${content.artist_name}`
|
|
1218
1230
|
},
|
|
1219
|
-
cta:
|
|
1220
|
-
text:
|
|
1221
|
-
timeRemainingToUnlockSeconds:
|
|
1231
|
+
cta: {
|
|
1232
|
+
text: ctaText,
|
|
1233
|
+
timeRemainingToUnlockSeconds: content.time_remaining_seconds ?? null,
|
|
1222
1234
|
action: {
|
|
1223
|
-
type:
|
|
1224
|
-
brand:
|
|
1225
|
-
id:
|
|
1226
|
-
slug:
|
|
1227
|
-
child:
|
|
1228
|
-
|
|
1229
|
-
id: data.first_incomplete_child.id,
|
|
1230
|
-
type: data.first_incomplete_child.type,
|
|
1231
|
-
brand: data.first_incomplete_child.brand,
|
|
1232
|
-
slug: data.first_incomplete_child.slug,
|
|
1233
|
-
child: data.second_incomplete_child
|
|
1234
|
-
? {
|
|
1235
|
-
id: data.second_incomplete_child.id,
|
|
1236
|
-
type: data.second_incomplete_child.type,
|
|
1237
|
-
brand: data.second_incomplete_child.brand,
|
|
1238
|
-
slug: data.second_incomplete_child.slug
|
|
1239
|
-
}
|
|
1240
|
-
: null
|
|
1241
|
-
}
|
|
1242
|
-
: null
|
|
1243
|
-
}
|
|
1235
|
+
type: content.type,
|
|
1236
|
+
brand: content.brand,
|
|
1237
|
+
id: content.id,
|
|
1238
|
+
slug: content.slug,
|
|
1239
|
+
child: content.navigateTo,
|
|
1240
|
+
},
|
|
1244
1241
|
},
|
|
1245
|
-
|
|
1246
|
-
|
|
1242
|
+
// *1000 is to match playlists which are saved in millisecond accuracy
|
|
1243
|
+
progressTimestamp: content.progressTimestamp * 1000,
|
|
1244
|
+
}
|
|
1247
1245
|
}
|
|
1248
1246
|
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
if (
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1247
|
+
function getDefaultCTATextForContent(content, contentType) {
|
|
1248
|
+
let ctaText = 'Continue'
|
|
1249
|
+
if (content.progressStatus === 'completed') {
|
|
1250
|
+
if (
|
|
1251
|
+
contentType === songs[content.brand] ||
|
|
1252
|
+
contentType === 'play along' ||
|
|
1253
|
+
contentType === 'jam track'
|
|
1254
|
+
)
|
|
1255
|
+
ctaText = 'Replay Song'
|
|
1256
|
+
if (contentType === 'lesson') ctaText = 'Revisit Lesson'
|
|
1257
|
+
if (contentType === 'song tutorial' || collectionLessonTypes.includes(contentType))
|
|
1258
|
+
ctaText = 'Revisit Lessons'
|
|
1259
|
+
if (contentType === 'pack') ctaText = 'View Lessons'
|
|
1260
|
+
}
|
|
1261
|
+
return ctaText
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
async function getCompletedChildren(content, contentType) {
|
|
1265
|
+
let completedChildren = null
|
|
1266
|
+
if (contentType === 'show') {
|
|
1267
|
+
const shows = await addContextToContent(fetchShows, content.brand, content.type, {
|
|
1268
|
+
addProgressStatus: true,
|
|
1269
|
+
})
|
|
1270
|
+
completedChildren = Object.values(shows).filter(
|
|
1271
|
+
(show) => show.progressStatus === 'completed'
|
|
1272
|
+
).length
|
|
1273
|
+
} else if (content.lesson_count > 0) {
|
|
1274
|
+
const lessonIds = getLeafNodes(content)
|
|
1275
|
+
const progressOnItems = await getProgressStateByIds(lessonIds)
|
|
1276
|
+
completedChildren = Object.values(progressOnItems).filter(
|
|
1277
|
+
(value) => value === 'completed'
|
|
1278
|
+
).length
|
|
1266
1279
|
}
|
|
1280
|
+
return completedChildren
|
|
1281
|
+
}
|
|
1267
1282
|
|
|
1283
|
+
async function processPlaylistItem(item) {
|
|
1284
|
+
const playlist = item.playlist
|
|
1268
1285
|
return {
|
|
1269
|
-
id:
|
|
1270
|
-
progressType:
|
|
1271
|
-
header:
|
|
1272
|
-
pinned:
|
|
1273
|
-
|
|
1286
|
+
id: playlist.id,
|
|
1287
|
+
progressType: 'playlist',
|
|
1288
|
+
header: 'playlist',
|
|
1289
|
+
pinned: item.pinned ?? false,
|
|
1290
|
+
playlist: playlist,
|
|
1291
|
+
body: {
|
|
1274
1292
|
first_items_thumbnail_url: playlist.first_items_thumbnail_url,
|
|
1275
|
-
title:
|
|
1276
|
-
subtitle:
|
|
1277
|
-
total_items:
|
|
1293
|
+
title: playlist.name,
|
|
1294
|
+
subtitle: `${playlist.duration_formated} • ${playlist.total_items} items • ${playlist.likes} likes • ${playlist.user.display_name}`,
|
|
1295
|
+
total_items: playlist.total_items,
|
|
1278
1296
|
},
|
|
1279
1297
|
progressTimestamp: item.progressTimestamp,
|
|
1280
|
-
cta:
|
|
1281
|
-
text:
|
|
1298
|
+
cta: {
|
|
1299
|
+
text: 'Continue',
|
|
1282
1300
|
action: {
|
|
1283
|
-
brand:
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
}
|
|
1290
|
-
}
|
|
1301
|
+
brand: playlist.brand,
|
|
1302
|
+
item_id: playlist.navigateTo.id ?? null,
|
|
1303
|
+
content_id: playlist.navigateTo.content_id ?? null,
|
|
1304
|
+
type: 'playlists',
|
|
1305
|
+
// TODO depreciated, maintained to avoid breaking changes
|
|
1306
|
+
id: playlist.id,
|
|
1307
|
+
},
|
|
1308
|
+
},
|
|
1291
1309
|
}
|
|
1292
1310
|
}
|
|
1293
1311
|
|
|
1294
1312
|
const getFormattedType = (type, brand) => {
|
|
1295
1313
|
for (const [key, values] of Object.entries(progressTypesMapping)) {
|
|
1296
1314
|
if (values.includes(type)) {
|
|
1297
|
-
return key === 'songs' ? songs[brand] : key
|
|
1315
|
+
return key === 'songs' ? songs[brand] : key
|
|
1298
1316
|
}
|
|
1299
1317
|
}
|
|
1300
1318
|
|
|
1301
|
-
return null
|
|
1302
|
-
}
|
|
1303
|
-
|
|
1304
|
-
function
|
|
1305
|
-
const ids = []
|
|
1306
|
-
function traverse(
|
|
1307
|
-
for (const item of
|
|
1308
|
-
if (item.
|
|
1309
|
-
traverse(item.
|
|
1310
|
-
}else if (item.id) {
|
|
1311
|
-
ids.push(item.id)
|
|
1319
|
+
return null
|
|
1320
|
+
}
|
|
1321
|
+
|
|
1322
|
+
function getLeafNodes(content) {
|
|
1323
|
+
const ids = []
|
|
1324
|
+
function traverse(children) {
|
|
1325
|
+
for (const item of children) {
|
|
1326
|
+
if (item.children) {
|
|
1327
|
+
traverse(item.children) // Recursively handle nested lessons
|
|
1328
|
+
} else if (item.id) {
|
|
1329
|
+
ids.push(item.id)
|
|
1312
1330
|
}
|
|
1313
1331
|
}
|
|
1314
1332
|
}
|
|
1315
|
-
if (
|
|
1316
|
-
traverse(
|
|
1333
|
+
if (content && Array.isArray(content.children)) {
|
|
1334
|
+
traverse(content.children)
|
|
1317
1335
|
}
|
|
1318
|
-
|
|
1319
|
-
return ids;
|
|
1336
|
+
return ids
|
|
1320
1337
|
}
|
|
1321
1338
|
|
|
1322
|
-
|
|
1323
1339
|
async function getEligiblePlaylistItems(playlists) {
|
|
1324
|
-
const eligible = playlists.filter(p => p.last_progress && p.last_engaged_on)
|
|
1340
|
+
const eligible = playlists.filter((p) => p.last_progress && p.last_engaged_on)
|
|
1325
1341
|
return Promise.all(
|
|
1326
|
-
eligible.map(async p => {
|
|
1327
|
-
const utcDate = new Date(p.last_progress.replace(' ', 'T') + 'Z')
|
|
1328
|
-
const timestamp = utcDate.getTime()
|
|
1342
|
+
eligible.map(async (p) => {
|
|
1343
|
+
const utcDate = new Date(p.last_progress.replace(' ', 'T') + 'Z')
|
|
1344
|
+
const timestamp = utcDate.getTime()
|
|
1329
1345
|
return {
|
|
1330
1346
|
type: 'playlist',
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1347
|
+
// Content timestamps are millisecond accurate so for comparison we bring this to the same resolution
|
|
1348
|
+
progressTimestamp: timestamp / 1000,
|
|
1349
|
+
playlist: p,
|
|
1350
|
+
id: p.id,
|
|
1351
|
+
}
|
|
1335
1352
|
})
|
|
1336
|
-
)
|
|
1353
|
+
)
|
|
1337
1354
|
}
|
|
1338
1355
|
|
|
1339
1356
|
function mergeAndSortItems(items, limit) {
|
|
1340
|
-
const seen = new Set()
|
|
1341
|
-
const deduped = []
|
|
1357
|
+
const seen = new Set()
|
|
1358
|
+
const deduped = []
|
|
1342
1359
|
|
|
1343
1360
|
for (const item of items) {
|
|
1344
|
-
const key = `${item.id}-${item.type
|
|
1361
|
+
const key = `${item.id}-${item.type}`
|
|
1345
1362
|
if (!seen.has(key)) {
|
|
1346
|
-
seen.add(key)
|
|
1347
|
-
deduped.push(item)
|
|
1363
|
+
seen.add(key)
|
|
1364
|
+
deduped.push(item)
|
|
1348
1365
|
}
|
|
1349
1366
|
}
|
|
1350
1367
|
|
|
1351
1368
|
return deduped
|
|
1352
|
-
.filter(item => typeof item.progressTimestamp === 'number' && item.progressTimestamp
|
|
1369
|
+
.filter((item) => typeof item.progressTimestamp === 'number' && item.progressTimestamp >= 0)
|
|
1353
1370
|
.sort((a, b) => {
|
|
1354
|
-
if (a.pinned && !b.pinned) return -1
|
|
1355
|
-
if (!a.pinned && b.pinned) return 1
|
|
1356
|
-
// TODO guided course should always be before user pinned item
|
|
1357
|
-
return b.progressTimestamp - a.progressTimestamp
|
|
1371
|
+
if (a.pinned && !b.pinned) return -1
|
|
1372
|
+
if (!a.pinned && b.pinned) return 1
|
|
1373
|
+
// TODO pinned guided course should always be before user pinned item
|
|
1374
|
+
return b.progressTimestamp - a.progressTimestamp
|
|
1358
1375
|
})
|
|
1359
|
-
.slice(0, limit + 5)
|
|
1376
|
+
.slice(0, limit + 5)
|
|
1360
1377
|
}
|
|
1361
1378
|
|
|
1362
1379
|
export function findIncompleteLesson(progressOnItems, currentContentId, contentType) {
|
|
1363
|
-
const ids = Object.keys(progressOnItems).map(Number)
|
|
1380
|
+
const ids = Object.keys(progressOnItems).map(Number)
|
|
1364
1381
|
if (contentType === 'guided-course') {
|
|
1365
1382
|
// Return first incomplete lesson
|
|
1366
|
-
return ids.find(id => progressOnItems[id] !== 'completed') || ids.at(0)
|
|
1383
|
+
return ids.find((id) => progressOnItems[id] !== 'completed') || ids.at(0)
|
|
1367
1384
|
}
|
|
1368
1385
|
|
|
1369
1386
|
// For other types, find next incomplete after current
|
|
1370
|
-
const currentIndex = ids.indexOf(Number(currentContentId))
|
|
1371
|
-
if (currentIndex === -1) return null
|
|
1387
|
+
const currentIndex = ids.indexOf(Number(currentContentId))
|
|
1388
|
+
if (currentIndex === -1) return null
|
|
1372
1389
|
|
|
1373
1390
|
for (let i = currentIndex + 1; i < ids.length; i++) {
|
|
1374
|
-
const id = ids[i]
|
|
1391
|
+
const id = ids[i]
|
|
1375
1392
|
if (progressOnItems[id] !== 'completed') {
|
|
1376
|
-
return id
|
|
1393
|
+
return id
|
|
1377
1394
|
}
|
|
1378
1395
|
}
|
|
1379
1396
|
|
|
1380
|
-
return ids[0]
|
|
1397
|
+
return ids[0]
|
|
1398
|
+
}
|
|
1399
|
+
|
|
1400
|
+
async function popPinnedItemFromContentsOrPlaylistMap(pinned, contentsMap, playlistItems) {
|
|
1401
|
+
if (!pinned) return null
|
|
1402
|
+
const { id, progressType, pinnedAt } = pinned
|
|
1403
|
+
let item = null
|
|
1404
|
+
if (progressType === 'content') {
|
|
1405
|
+
const pinnedId = parseInt(id)
|
|
1406
|
+
if (contentsMap.has(pinnedId)) {
|
|
1407
|
+
item = contentsMap.get(pinnedId)
|
|
1408
|
+
contentsMap.delete(pinnedId)
|
|
1409
|
+
} else {
|
|
1410
|
+
// we use fetchByRailContentIds so that we don't have the _type restriction in the query
|
|
1411
|
+
let data = await fetchByRailContentIds([id], 'progress-tracker')
|
|
1412
|
+
item = await addContextToContent(() => data[0] ?? null, {
|
|
1413
|
+
addNextLesson: true,
|
|
1414
|
+
addNavigateTo: true,
|
|
1415
|
+
addProgressStatus: true,
|
|
1416
|
+
addProgressPercentage: true,
|
|
1417
|
+
addProgressTimestamp: true,
|
|
1418
|
+
})
|
|
1419
|
+
}
|
|
1420
|
+
}
|
|
1421
|
+
if (progressType === 'playlist') {
|
|
1422
|
+
const pinnedPlaylist = playlistItems.find((p) => p.playlist.id === id)
|
|
1423
|
+
if (pinnedPlaylist) {
|
|
1424
|
+
playlistItems = playlistItems.filter((p) => p.playlist.id !== id)
|
|
1425
|
+
item = pinnedPlaylist
|
|
1426
|
+
} else {
|
|
1427
|
+
const playlist = await fetchPlaylist(id)
|
|
1428
|
+
item = {
|
|
1429
|
+
id: id,
|
|
1430
|
+
playlist: playlist,
|
|
1431
|
+
type: 'playlist',
|
|
1432
|
+
progressTimestamp: new Date(pinnedAt).getTime(),
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1435
|
+
}
|
|
1436
|
+
return item
|
|
1437
|
+
}
|
|
1438
|
+
|
|
1439
|
+
function popContentAndRemoveChildrenFromContentsMap(content, contentsMap) {
|
|
1440
|
+
const children = content.children.map((child) => child.id)
|
|
1441
|
+
if (contentsMap.has(content.id)) {
|
|
1442
|
+
contentsMap.delete(content.id)
|
|
1443
|
+
}
|
|
1444
|
+
children.forEach((child) => {
|
|
1445
|
+
if (contentsMap.has(child)) {
|
|
1446
|
+
contentsMap.delete(child)
|
|
1447
|
+
}
|
|
1448
|
+
})
|
|
1449
|
+
return contentsMap
|
|
1381
1450
|
}
|
|
1382
1451
|
|
|
1383
1452
|
/**
|
|
@@ -1394,16 +1463,16 @@ export function findIncompleteLesson(progressOnItems, currentContentId, contentT
|
|
|
1394
1463
|
* .catch(error => console.error(error));
|
|
1395
1464
|
*/
|
|
1396
1465
|
export async function pinProgressRow(brand, id, progressType) {
|
|
1397
|
-
const url = `/api/user-management-system/v1/progress/pin?brand=${brand}&id=${id}&progressType=${progressType}
|
|
1466
|
+
const url = `/api/user-management-system/v1/progress/pin?brand=${brand}&id=${id}&progressType=${progressType}`
|
|
1398
1467
|
const response = await fetchHandler(url, 'PUT', null)
|
|
1399
1468
|
if (response && !response.error && response['action'] === 'update_user_pin') {
|
|
1400
1469
|
await updateUserPinnedProgressRow(brand, {
|
|
1401
1470
|
id,
|
|
1402
1471
|
progressType,
|
|
1403
1472
|
pinnedAt: new Date().toISOString(),
|
|
1404
|
-
})
|
|
1473
|
+
})
|
|
1405
1474
|
}
|
|
1406
|
-
return response
|
|
1475
|
+
return response
|
|
1407
1476
|
}
|
|
1408
1477
|
/**
|
|
1409
1478
|
* Unpins the current pinned progress row for a user, scoped by brand.
|
|
@@ -1428,116 +1497,29 @@ export async function unpinProgressRow(brand, id) {
|
|
|
1428
1497
|
}
|
|
1429
1498
|
|
|
1430
1499
|
async function updateUserPinnedProgressRow(brand, pinnedData) {
|
|
1431
|
-
const userRaw = await globalConfig.localStorage.getItem('user')
|
|
1432
|
-
const user = userRaw ? JSON.parse(userRaw) : {}
|
|
1500
|
+
const userRaw = await globalConfig.localStorage.getItem('user')
|
|
1501
|
+
const user = userRaw ? JSON.parse(userRaw) : {}
|
|
1433
1502
|
user.brand_pinned_progress = user.brand_pinned_progress || {}
|
|
1434
1503
|
user.brand_pinned_progress[brand] = pinnedData
|
|
1435
1504
|
await globalConfig.localStorage.setItem('user', JSON.stringify(user))
|
|
1436
1505
|
}
|
|
1437
1506
|
|
|
1438
|
-
async function extractPinnedItem(pinned, progressMap, playlistItems) {
|
|
1439
|
-
const {id, progressType, pinnedAt} = pinned
|
|
1440
|
-
|
|
1441
|
-
if (progressType === 'content') {
|
|
1442
|
-
const pinnedId = parseInt(id)
|
|
1443
|
-
if (progressMap.has(pinnedId)) {
|
|
1444
|
-
const item = progressMap.get(pinnedId)
|
|
1445
|
-
progressMap.delete(pinnedId)
|
|
1446
|
-
return item
|
|
1447
|
-
} else {
|
|
1448
|
-
const content = await fetchByRailContentIds([`${pinnedId}`], 'progress-tracker')
|
|
1449
|
-
const firstLessonId = getFirstLeafLessonId(content[0])
|
|
1450
|
-
return {
|
|
1451
|
-
id: pinnedId,
|
|
1452
|
-
state: 'started',
|
|
1453
|
-
percent: 0,
|
|
1454
|
-
raw: content[0],
|
|
1455
|
-
progressTimestamp: new Date(pinnedAt).getTime(),
|
|
1456
|
-
childIndex: firstLessonId
|
|
1457
|
-
}
|
|
1458
|
-
}
|
|
1459
|
-
}
|
|
1460
|
-
if (progressType === 'playlist') {
|
|
1461
|
-
const pinnedPlaylist = playlistItems.find(p => p.raw.id === id)
|
|
1462
|
-
if (pinnedPlaylist) {
|
|
1463
|
-
return pinnedPlaylist
|
|
1464
|
-
}else{
|
|
1465
|
-
const playlist = await fetchPlaylist(id)
|
|
1466
|
-
return {
|
|
1467
|
-
id: id,
|
|
1468
|
-
raw: playlist,
|
|
1469
|
-
progressTimestamp: new Date(pinnedAt).getTime(),
|
|
1470
|
-
type: 'playlist',
|
|
1471
|
-
last_engaged_on: playlist.last_engaged_on,
|
|
1472
|
-
}
|
|
1473
|
-
}
|
|
1474
|
-
}
|
|
1475
|
-
|
|
1476
|
-
return null
|
|
1477
|
-
}
|
|
1478
|
-
|
|
1479
|
-
async function extractPinnedGuidedCourseItem(guidedCourse, progressMap) {
|
|
1480
|
-
const children = guidedCourse.lessons.map(child => child.id)
|
|
1481
|
-
let existingGuidedCourseProgress = null
|
|
1482
|
-
if (progressMap.has(guidedCourse.id)) {
|
|
1483
|
-
existingGuidedCourseProgress = progressMap.get(guidedCourse.id)
|
|
1484
|
-
progressMap.delete(guidedCourse.id)
|
|
1485
|
-
}
|
|
1486
|
-
let lastChild = null
|
|
1487
|
-
children.forEach(child => {
|
|
1488
|
-
if (progressMap.has(child)) {
|
|
1489
|
-
let childProgress = progressMap.get(child)
|
|
1490
|
-
if (!lastChild && childProgress.state !== 'completed') {
|
|
1491
|
-
lastChild = childProgress
|
|
1492
|
-
lastChild.id = child
|
|
1493
|
-
}
|
|
1494
|
-
progressMap.delete(child)
|
|
1495
|
-
}
|
|
1496
|
-
})
|
|
1497
|
-
return existingGuidedCourseProgress ?? {
|
|
1498
|
-
id: guidedCourse.id,
|
|
1499
|
-
state: 'not-started',
|
|
1500
|
-
percent: 0,
|
|
1501
|
-
raw: guidedCourse,
|
|
1502
|
-
pinned: true,
|
|
1503
|
-
progressTimestamp: new Date().getTime(),
|
|
1504
|
-
childIndex: guidedCourse.id,
|
|
1505
|
-
}
|
|
1506
|
-
}
|
|
1507
|
-
|
|
1508
|
-
function getFirstLeafLessonId(data) {
|
|
1509
|
-
function findFirstLeaf(lessons) {
|
|
1510
|
-
for (const item of lessons) {
|
|
1511
|
-
if (!item.lessons || item.lessons.length === 0) {
|
|
1512
|
-
return item.id || null
|
|
1513
|
-
}
|
|
1514
|
-
const found = findFirstLeaf(item.lessons)
|
|
1515
|
-
if (found) return found
|
|
1516
|
-
}
|
|
1517
|
-
return null
|
|
1518
|
-
}
|
|
1519
|
-
|
|
1520
|
-
return data.lessons ? findFirstLeaf(data.lessons) : null
|
|
1521
|
-
}
|
|
1522
|
-
|
|
1523
1507
|
export async function fetchRecentActivitiesActiveTabs() {
|
|
1524
1508
|
const url = `/api/user-management-system/v1/activities/tabs`
|
|
1525
1509
|
try {
|
|
1526
|
-
const tabs = await fetchHandler(url, 'GET')
|
|
1527
|
-
const activitiesTabs = []
|
|
1510
|
+
const tabs = await fetchHandler(url, 'GET')
|
|
1511
|
+
const activitiesTabs = []
|
|
1528
1512
|
|
|
1529
|
-
tabs.forEach(tab => {
|
|
1530
|
-
activitiesTabs.push({ name: tab.label, short_name:tab.label })
|
|
1531
|
-
})
|
|
1513
|
+
tabs.forEach((tab) => {
|
|
1514
|
+
activitiesTabs.push({ name: tab.label, short_name: tab.label })
|
|
1515
|
+
})
|
|
1532
1516
|
|
|
1533
|
-
return activitiesTabs
|
|
1517
|
+
return activitiesTabs
|
|
1534
1518
|
} catch (error) {
|
|
1535
|
-
console.error('Error fetching activity tabs:', error)
|
|
1536
|
-
return []
|
|
1519
|
+
console.error('Error fetching activity tabs:', error)
|
|
1520
|
+
return []
|
|
1537
1521
|
}
|
|
1538
1522
|
}
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
1523
|
</code></pre>
|
|
1542
1524
|
</article>
|
|
1543
1525
|
</section>
|
|
@@ -1552,7 +1534,7 @@ export async function fetchRecentActivitiesActiveTabs() {
|
|
|
1552
1534
|
<br class="clear">
|
|
1553
1535
|
|
|
1554
1536
|
<footer>
|
|
1555
|
-
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.3</a> on
|
|
1537
|
+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.3</a> on Tue Aug 19 2025 17:54:03 GMT+0000 (Coordinated Universal Time) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
|
|
1556
1538
|
</footer>
|
|
1557
1539
|
|
|
1558
1540
|
<script>prettyPrint();</script>
|