musora-content-services 1.6.9 → 1.7.2

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.
Files changed (190) hide show
  1. package/.github/workflows/conventional-commits.yaml +0 -0
  2. package/.github/workflows/docs.js.yml +0 -0
  3. package/.github/workflows/node.js.yml +0 -0
  4. package/.github/workflows/sync-docs.yml +0 -0
  5. package/.prettierignore +0 -0
  6. package/.prettierrc +0 -0
  7. package/CHANGELOG.md +16 -0
  8. package/README.md +0 -0
  9. package/babel.config.cjs +0 -0
  10. package/docs/algolia.js.html +0 -0
  11. package/docs/config.js.html +0 -0
  12. package/docs/fonts/Montserrat/Montserrat-Bold.eot +0 -0
  13. package/docs/fonts/Montserrat/Montserrat-Bold.ttf +0 -0
  14. package/docs/fonts/Montserrat/Montserrat-Bold.woff +0 -0
  15. package/docs/fonts/Montserrat/Montserrat-Bold.woff2 +0 -0
  16. package/docs/fonts/Montserrat/Montserrat-Regular.eot +0 -0
  17. package/docs/fonts/Montserrat/Montserrat-Regular.ttf +0 -0
  18. package/docs/fonts/Montserrat/Montserrat-Regular.woff +0 -0
  19. package/docs/fonts/Montserrat/Montserrat-Regular.woff2 +0 -0
  20. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.eot +0 -0
  21. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.svg +0 -0
  22. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.ttf +0 -0
  23. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff +0 -0
  24. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff2 +0 -0
  25. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.eot +0 -0
  26. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.svg +0 -0
  27. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.ttf +0 -0
  28. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff +0 -0
  29. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff2 +0 -0
  30. package/docs/index.html +0 -0
  31. package/docs/module-Config.html +0 -0
  32. package/docs/module-Railcontent-Services.html +0 -0
  33. package/docs/module-Sanity-Services.html +0 -0
  34. package/docs/module-Search-Engine-Services.html +0 -0
  35. package/docs/railcontent.js.html +0 -0
  36. package/docs/sanity.js.html +0 -0
  37. package/docs/scripts/collapse.js +0 -0
  38. package/docs/scripts/commonNav.js +0 -0
  39. package/docs/scripts/linenumber.js +0 -0
  40. package/docs/scripts/nav.js +0 -0
  41. package/docs/scripts/polyfill.js +0 -0
  42. package/docs/scripts/prettify/Apache-License-2.0.txt +0 -0
  43. package/docs/scripts/prettify/lang-css.js +0 -0
  44. package/docs/scripts/prettify/prettify.js +0 -0
  45. package/docs/scripts/search.js +0 -0
  46. package/docs/styles/jsdoc.css +0 -0
  47. package/docs/styles/prettify.css +0 -0
  48. package/docs/v2/Content.html +269 -0
  49. package/docs/v2/ContentOrganization.html +2 -2
  50. package/docs/v2/Forums.html +2 -2
  51. package/docs/v2/Gamification.html +2 -2
  52. package/docs/v2/TestUser.html +3 -3
  53. package/docs/v2/UserManagementSystem.html +2 -2
  54. package/docs/v2/api_types.js.html +2 -2
  55. package/docs/v2/config.js.html +5 -2
  56. package/docs/v2/content-org_content-org.js.html +2 -2
  57. package/docs/v2/content-org_guided-courses.ts.html +2 -2
  58. package/docs/v2/content-org_learning-paths.ts.html +286 -18
  59. package/docs/v2/content-org_playlists-types.js.html +2 -2
  60. package/docs/v2/content-org_playlists.js.html +2 -2
  61. package/docs/v2/content.js.html +94 -16
  62. package/docs/v2/content_artist.ts.html +206 -0
  63. package/docs/v2/content_content.ts.html +77 -0
  64. package/docs/v2/content_genre.ts.html +209 -0
  65. package/docs/v2/content_instructor.ts.html +206 -0
  66. package/docs/v2/fonts/Montserrat/Montserrat-Bold.eot +0 -0
  67. package/docs/v2/fonts/Montserrat/Montserrat-Bold.ttf +0 -0
  68. package/docs/v2/fonts/Montserrat/Montserrat-Bold.woff +0 -0
  69. package/docs/v2/fonts/Montserrat/Montserrat-Bold.woff2 +0 -0
  70. package/docs/v2/fonts/Montserrat/Montserrat-Regular.eot +0 -0
  71. package/docs/v2/fonts/Montserrat/Montserrat-Regular.ttf +0 -0
  72. package/docs/v2/fonts/Montserrat/Montserrat-Regular.woff +0 -0
  73. package/docs/v2/fonts/Montserrat/Montserrat-Regular.woff2 +0 -0
  74. package/docs/v2/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.eot +0 -0
  75. package/docs/v2/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.svg +0 -0
  76. package/docs/v2/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.ttf +0 -0
  77. package/docs/v2/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff +0 -0
  78. package/docs/v2/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff2 +0 -0
  79. package/docs/v2/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.eot +0 -0
  80. package/docs/v2/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.svg +0 -0
  81. package/docs/v2/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.ttf +0 -0
  82. package/docs/v2/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff +0 -0
  83. package/docs/v2/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff2 +0 -0
  84. package/docs/v2/forums_categories.ts.html +22 -3
  85. package/docs/v2/forums_discussions.js.html +0 -0
  86. package/docs/v2/forums_forum.js.html +0 -0
  87. package/docs/v2/forums_forums.ts.html +41 -41
  88. package/docs/v2/forums_posts.ts.html +54 -28
  89. package/docs/v2/forums_threads.ts.html +23 -10
  90. package/docs/v2/gamification_awards.js.html +0 -0
  91. package/docs/v2/gamification_awards.ts.html +26 -12
  92. package/docs/v2/gamification_gamification.js.html +2 -2
  93. package/docs/v2/gamification_types.js.html +0 -0
  94. package/docs/v2/global.html +57 -9
  95. package/docs/v2/index.html +2 -2
  96. package/docs/v2/liveTesting.ts.html +4 -3
  97. package/docs/v2/module-Accounts.html +202 -13
  98. package/docs/v2/module-Artist.html +993 -0
  99. package/docs/v2/module-Awards.html +106 -6
  100. package/docs/v2/module-Categories.html +0 -0
  101. package/docs/v2/module-Config.html +5 -4
  102. package/docs/v2/module-Content-Services-V2.html +440 -9
  103. package/docs/v2/module-ForumCategories.html +0 -0
  104. package/docs/v2/module-ForumDiscussions.html +0 -0
  105. package/docs/v2/module-Forums.html +1398 -192
  106. package/docs/v2/module-Genre.html +981 -0
  107. package/docs/v2/module-GuidedCourses.html +2 -1198
  108. package/docs/v2/module-Instructor.html +929 -0
  109. package/docs/v2/module-Interests.html +2 -2
  110. package/docs/v2/module-LearningPaths.html +2424 -0
  111. package/docs/v2/module-Onboarding.html +217 -5
  112. package/docs/v2/module-Payments.html +148 -6
  113. package/docs/v2/module-Permissions.html +2 -2
  114. package/docs/v2/module-Playlists.html +2 -2
  115. package/docs/v2/module-ProgressRow.html +108 -0
  116. package/docs/v2/module-Railcontent-Services.html +34 -626
  117. package/docs/v2/module-Sanity-Services.html +803 -1722
  118. package/docs/v2/module-Sessions.html +2 -2
  119. package/docs/v2/module-Threads.html +0 -0
  120. package/docs/v2/module-UserActivity.html +70 -116
  121. package/docs/v2/module-UserChat.html +2 -2
  122. package/docs/v2/module-UserManagement.html +2 -2
  123. package/docs/v2/module-UserMemberships.html +2 -2
  124. package/docs/v2/module-UserNotifications.html +2 -2
  125. package/docs/v2/module-UserProfile.html +2 -2
  126. package/docs/v2/progress-row_method-card.js.html +184 -0
  127. package/docs/v2/railcontent.js.html +14 -125
  128. package/docs/v2/sanity.js.html +261 -325
  129. package/docs/v2/scripts/collapse.js +0 -0
  130. package/docs/v2/scripts/commonNav.js +0 -0
  131. package/docs/v2/scripts/linenumber.js +0 -0
  132. package/docs/v2/scripts/nav.js +0 -0
  133. package/docs/v2/scripts/polyfill.js +0 -0
  134. package/docs/v2/scripts/prettify/Apache-License-2.0.txt +0 -0
  135. package/docs/v2/scripts/prettify/lang-css.js +0 -0
  136. package/docs/v2/scripts/prettify/prettify.js +0 -0
  137. package/docs/v2/scripts/search.js +0 -0
  138. package/docs/v2/styles/jsdoc.css +0 -0
  139. package/docs/v2/styles/prettify.css +0 -0
  140. package/docs/v2/userActivity.js.html +191 -211
  141. package/docs/v2/user_account.ts.html +42 -14
  142. package/docs/v2/user_chat.js.html +2 -2
  143. package/docs/v2/user_interests.js.html +2 -2
  144. package/docs/v2/user_management.js.html +2 -2
  145. package/docs/v2/user_memberships.js.html +0 -0
  146. package/docs/v2/user_memberships.ts.html +2 -2
  147. package/docs/v2/user_notifications.js.html +2 -2
  148. package/docs/v2/user_onboarding.ts.html +148 -2
  149. package/docs/v2/user_payments.ts.html +54 -5
  150. package/docs/v2/user_permissions.js.html +3 -3
  151. package/docs/v2/user_profile.js.html +2 -2
  152. package/docs/v2/user_sessions.js.html +2 -2
  153. package/docs/v2/user_types.js.html +4 -2
  154. package/docs/v2/user_user-management-system.js.html +2 -2
  155. package/jest.config.js +0 -0
  156. package/jsdoc.json +0 -0
  157. package/link_mcs.sh +0 -0
  158. package/package.json +1 -1
  159. package/src/contentMetaData.js +0 -0
  160. package/src/contentTypeConfig.js +2 -0
  161. package/src/filterBuilder.js +3 -1
  162. package/src/index.d.ts +0 -0
  163. package/src/index.js +0 -0
  164. package/src/services/algolia.js +0 -0
  165. package/src/services/config.js +0 -0
  166. package/src/services/contentLikes.js +0 -0
  167. package/src/services/contentProgress.js +0 -0
  168. package/src/services/dataContext.js +0 -0
  169. package/src/services/imageSRCBuilder.js +0 -0
  170. package/src/services/imageSRCVerify.js +0 -0
  171. package/src/services/lastUpdated.js +0 -0
  172. package/src/services/railcontent.js +0 -0
  173. package/src/services/recommendations.js +0 -0
  174. package/src/services/sanity.js +15 -6
  175. package/src/services/userPermissions.js +0 -0
  176. package/test/config.test.js +0 -0
  177. package/test/contentLikes.test.js +0 -0
  178. package/test/contentProgress.test.js +0 -0
  179. package/test/dataContext.test.js +0 -0
  180. package/test/imageSRCBuilder.test.js +0 -0
  181. package/test/imageSRCVerify.test.js +0 -0
  182. package/test/initializeTests.js +0 -0
  183. package/test/lastUpdated.test.js +0 -0
  184. package/test/live/contentProgressLive.test.js +0 -0
  185. package/test/live/railcontentLive.test.js +0 -0
  186. package/test/localStorageMock.js +0 -0
  187. package/test/log.js +0 -0
  188. package/test/sanityQueryService.test.js +0 -0
  189. package/test/userPermissions.test.js +0 -0
  190. package/tools/generate-index.cjs +0 -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-Accounts.html">Accounts</a><ul class='methods'><li data-type='method'><a href="module-Accounts.html#~confirmEmailChange">confirmEmailChange</a></li><li data-type='method'><a href="module-Accounts.html#~deleteAccount">deleteAccount</a></li><li data-type='method'><a href="module-Accounts.html#~numberOfActiveUsers">numberOfActiveUsers</a></li><li data-type='method'><a href="module-Accounts.html#~requestEmailChange">requestEmailChange</a></li><li data-type='method'><a href="module-Accounts.html#~resetPassword">resetPassword</a></li><li data-type='method'><a href="module-Accounts.html#~sendAccountSetupEmail">sendAccountSetupEmail</a></li><li data-type='method'><a href="module-Accounts.html#~sendPasswordResetEmail">sendPasswordResetEmail</a></li><li data-type='method'><a href="module-Accounts.html#~setupAccount">setupAccount</a></li><li data-type='method'><a href="module-Accounts.html#~status">status</a></li></ul></li><li><a href="module-Awards.html">Awards</a><ul class='methods'><li data-type='method'><a href="module-Awards.html#~fetchAwardsForUser">fetchAwardsForUser</a></li><li data-type='method'><a href="module-Awards.html#~fetchCertificate">fetchCertificate</a></li><li data-type='method'><a href="module-Awards.html#~getAwardDataForGuidedContent">getAwardDataForGuidedContent</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#.getLegacyMethods">getLegacyMethods</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-Forums.html">Forums</a><ul class='methods'><li data-type='method'><a href="module-Forums.html#~createForumCategory">createForumCategory</a></li><li data-type='method'><a href="module-Forums.html#~createPost">createPost</a></li><li data-type='method'><a href="module-Forums.html#~createThread">createThread</a></li><li data-type='method'><a href="module-Forums.html#~deletePost">deletePost</a></li><li data-type='method'><a href="module-Forums.html#~deleteThread">deleteThread</a></li><li data-type='method'><a href="module-Forums.html#~fetchCommunityGuidelines">fetchCommunityGuidelines</a></li><li data-type='method'><a href="module-Forums.html#~fetchFollowedThreads">fetchFollowedThreads</a></li><li data-type='method'><a href="module-Forums.html#~fetchForumCategories">fetchForumCategories</a></li><li data-type='method'><a href="module-Forums.html#~fetchLatestThreads">fetchLatestThreads</a></li><li data-type='method'><a href="module-Forums.html#~fetchPosts">fetchPosts</a></li><li data-type='method'><a href="module-Forums.html#~fetchThreads">fetchThreads</a></li><li data-type='method'><a href="module-Forums.html#~followThread">followThread</a></li><li data-type='method'><a href="module-Forums.html#~jumpToPost">jumpToPost</a></li><li data-type='method'><a href="module-Forums.html#~likePost">likePost</a></li><li data-type='method'><a href="module-Forums.html#~lockThread">lockThread</a></li><li data-type='method'><a href="module-Forums.html#~pinThread">pinThread</a></li><li data-type='method'><a href="module-Forums.html#~search">search</a></li><li data-type='method'><a href="module-Forums.html#~unfollowThread">unfollowThread</a></li><li data-type='method'><a href="module-Forums.html#~unlikePost">unlikePost</a></li><li data-type='method'><a href="module-Forums.html#~unlockThread">unlockThread</a></li><li data-type='method'><a href="module-Forums.html#~unpinThread">unpinThread</a></li><li data-type='method'><a href="module-Forums.html#~updateForumCategory">updateForumCategory</a></li><li data-type='method'><a href="module-Forums.html#~updatePost">updatePost</a></li><li data-type='method'><a href="module-Forums.html#~updateThread">updateThread</a></li></ul></li><li></li><li></li><li><a href="module-GuidedCourses.html">GuidedCourses</a><ul class='methods'><li data-type='method'><a href="module-GuidedCourses.html#~getActivePath">getActivePath</a></li><li data-type='method'><a href="module-GuidedCourses.html#~getDailySession">getDailySession</a></li><li data-type='method'><a href="module-GuidedCourses.html#~updateActivePath">updateActivePath</a></li><li data-type='method'><a href="module-GuidedCourses.html#~updateDailySession">updateDailySession</a></li></ul></li><li></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-Onboarding.html">Onboarding</a><ul class='methods'><li data-type='method'><a href="module-Onboarding.html#~startOnboarding">startOnboarding</a></li><li data-type='method'><a href="module-Onboarding.html#~updateOnboarding">updateOnboarding</a></li><li data-type='method'><a href="module-Onboarding.html#~userOnboardingForBrand">userOnboardingForBrand</a></li></ul></li><li><a href="module-Payments.html">Payments</a><ul class='methods'><li data-type='method'><a href="module-Payments.html#~fetchCustomerPayments">fetchCustomerPayments</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#.postContentStart">postContentStart</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#.fetchMethodV2IntroVideo">fetchMethodV2IntroVideo</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchMethodV2Structure">fetchMethodV2Structure</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#.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#.getUserSignature">getUserSignature</a></li><li data-type='method'><a href="module-UserManagement.html#.isUsernameAvailable">isUsernameAvailable</a></li><li data-type='method'><a href="module-UserManagement.html#.setUserSignature">setUserSignature</a></li><li data-type='method'><a href="module-UserManagement.html#.toggleSignaturePrivate">toggleSignaturePrivate</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-UserMemberships.html">UserMemberships</a><ul class='methods'><li data-type='method'><a href="module-UserMemberships.html#~fetchMemberships">fetchMemberships</a></li><li data-type='method'><a href="module-UserMemberships.html#~fetchRechargeTokens">fetchRechargeTokens</a></li><li data-type='method'><a href="module-UserMemberships.html#~restorePurchases">restorePurchases</a></li><li data-type='method'><a href="module-UserMemberships.html#~upgradeSubscription">upgradeSubscription</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="Forums.html">Forums</a></li><li><a href="Gamification.html">Gamification</a></li><li><a href="UserManagementSystem.html">UserManagementSystem</a></li></ul><h3>Interfaces</h3><ul><li><a href="TestUser.html">TestUser</a></li></ul><h3>Global</h3><ul><li><a href="global.html#createTestUser">createTestUser</a></li></ul>
32
+ <h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-Accounts.html">Accounts</a><ul class='methods'><li data-type='method'><a href="module-Accounts.html#~confirmEmailChange">confirmEmailChange</a></li><li data-type='method'><a href="module-Accounts.html#~deleteAccount">deleteAccount</a></li><li data-type='method'><a href="module-Accounts.html#~numberOfActiveUsers">numberOfActiveUsers</a></li><li data-type='method'><a href="module-Accounts.html#~requestEmailChange">requestEmailChange</a></li><li data-type='method'><a href="module-Accounts.html#~resetPassword">resetPassword</a></li><li data-type='method'><a href="module-Accounts.html#~sendAccountSetupEmail">sendAccountSetupEmail</a></li><li data-type='method'><a href="module-Accounts.html#~sendPasswordResetEmail">sendPasswordResetEmail</a></li><li data-type='method'><a href="module-Accounts.html#~setupAccount">setupAccount</a></li><li data-type='method'><a href="module-Accounts.html#~status">status</a></li><li data-type='method'><a href="module-Accounts.html#~toggleStudentView">toggleStudentView</a></li></ul></li><li><a href="module-Artist.html">Artist</a><ul class='methods'><li data-type='method'><a href="module-Artist.html#~fetchArtistBySlug">fetchArtistBySlug</a></li><li data-type='method'><a href="module-Artist.html#~fetchArtistLessons">fetchArtistLessons</a></li><li data-type='method'><a href="module-Artist.html#~fetchArtists">fetchArtists</a></li></ul></li><li><a href="module-Awards.html">Awards</a><ul class='methods'><li data-type='method'><a href="module-Awards.html#~fetchAwardsForUser">fetchAwardsForUser</a></li><li data-type='method'><a href="module-Awards.html#~fetchCertificate">fetchCertificate</a></li><li data-type='method'><a href="module-Awards.html#~getAwardDataForGuidedContent">getAwardDataForGuidedContent</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#.getLegacyMethods">getLegacyMethods</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#.getOwnedContent">getOwnedContent</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-Forums.html">Forums</a><ul class='methods'><li data-type='method'><a href="module-Forums.html#~createForumCategory">createForumCategory</a></li><li data-type='method'><a href="module-Forums.html#~createPost">createPost</a></li><li data-type='method'><a href="module-Forums.html#~createThread">createThread</a></li><li data-type='method'><a href="module-Forums.html#~deleteForumCategory">deleteForumCategory</a></li><li data-type='method'><a href="module-Forums.html#~deletePost">deletePost</a></li><li data-type='method'><a href="module-Forums.html#~deleteThread">deleteThread</a></li><li data-type='method'><a href="module-Forums.html#~fetchCommunityGuidelines">fetchCommunityGuidelines</a></li><li data-type='method'><a href="module-Forums.html#~fetchFollowedThreads">fetchFollowedThreads</a></li><li data-type='method'><a href="module-Forums.html#~fetchForumCategories">fetchForumCategories</a></li><li data-type='method'><a href="module-Forums.html#~fetchLatestThreads">fetchLatestThreads</a></li><li data-type='method'><a href="module-Forums.html#~fetchPosts">fetchPosts</a></li><li data-type='method'><a href="module-Forums.html#~fetchThreads">fetchThreads</a></li><li data-type='method'><a href="module-Forums.html#~followThread">followThread</a></li><li data-type='method'><a href="module-Forums.html#~jumpToPost">jumpToPost</a></li><li data-type='method'><a href="module-Forums.html#~likePost">likePost</a></li><li data-type='method'><a href="module-Forums.html#~lockThread">lockThread</a></li><li data-type='method'><a href="module-Forums.html#~markThreadAsRead">markThreadAsRead</a></li><li data-type='method'><a href="module-Forums.html#~pinThread">pinThread</a></li><li data-type='method'><a href="module-Forums.html#~search">search</a></li><li data-type='method'><a href="module-Forums.html#~unfollowThread">unfollowThread</a></li><li data-type='method'><a href="module-Forums.html#~unlikePost">unlikePost</a></li><li data-type='method'><a href="module-Forums.html#~unlockThread">unlockThread</a></li><li data-type='method'><a href="module-Forums.html#~unpinThread">unpinThread</a></li><li data-type='method'><a href="module-Forums.html#~updateForumCategory">updateForumCategory</a></li><li data-type='method'><a href="module-Forums.html#~updatePost">updatePost</a></li><li data-type='method'><a href="module-Forums.html#~updateThread">updateThread</a></li></ul></li><li></li><li></li><li><a href="module-Genre.html">Genre</a><ul class='methods'><li data-type='method'><a href="module-Genre.html#~fetchGenreBySlug">fetchGenreBySlug</a></li><li data-type='method'><a href="module-Genre.html#~fetchGenreLessons">fetchGenreLessons</a></li><li data-type='method'><a href="module-Genre.html#~fetchGenres">fetchGenres</a></li></ul></li><li><a href="module-GuidedCourses.html">GuidedCourses</a></li><li><a href="module-Instructor.html">Instructor</a><ul class='methods'><li data-type='method'><a href="module-Instructor.html#~fetchInstructorBySlug">fetchInstructorBySlug</a></li><li data-type='method'><a href="module-Instructor.html#~fetchInstructorLessons">fetchInstructorLessons</a></li><li data-type='method'><a href="module-Instructor.html#~fetchInstructors">fetchInstructors</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-LearningPaths.html">LearningPaths</a><ul class='methods'><li data-type='method'><a href="module-LearningPaths.html#~completeLearningPathIntroVideo">completeLearningPathIntroVideo</a></li><li data-type='method'><a href="module-LearningPaths.html#~completeMethodIntroVideo">completeMethodIntroVideo</a></li><li data-type='method'><a href="module-LearningPaths.html#~fetchLearningPathLessons">fetchLearningPathLessons</a></li><li data-type='method'><a href="module-LearningPaths.html#~fetchLearningPathProgressCheckLessons">fetchLearningPathProgressCheckLessons</a></li><li data-type='method'><a href="module-LearningPaths.html#~getActivePath">getActivePath</a></li><li data-type='method'><a href="module-LearningPaths.html#~getDailySession">getDailySession</a></li><li data-type='method'><a href="module-LearningPaths.html#~getEnrichedLearningPath">getEnrichedLearningPath</a></li><li data-type='method'><a href="module-LearningPaths.html#~getLearningPathLessonsByIds">getLearningPathLessonsByIds</a></li><li data-type='method'><a href="module-LearningPaths.html#~mapContentToParent">mapContentToParent</a></li><li data-type='method'><a href="module-LearningPaths.html#~resetAllLearningPaths">resetAllLearningPaths</a></li><li data-type='method'><a href="module-LearningPaths.html#~startLearningPath">startLearningPath</a></li><li data-type='method'><a href="module-LearningPaths.html#~updateDailySession">updateDailySession</a></li></ul></li><li><a href="module-Onboarding.html">Onboarding</a><ul class='methods'><li data-type='method'><a href="module-Onboarding.html#~getOnboardingRecommendedContent">getOnboardingRecommendedContent</a></li><li data-type='method'><a href="module-Onboarding.html#~startOnboarding">startOnboarding</a></li><li data-type='method'><a href="module-Onboarding.html#~updateOnboarding">updateOnboarding</a></li><li data-type='method'><a href="module-Onboarding.html#~userOnboardingForBrand">userOnboardingForBrand</a></li></ul></li><li><a href="module-Payments.html">Payments</a><ul class='methods'><li data-type='method'><a href="module-Payments.html#~fetchCustomerPayments">fetchCustomerPayments</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-ProgressRow.html">ProgressRow</a></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#.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#.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#.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#.fetchMethodV2IntroVideo">fetchMethodV2IntroVideo</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchMethodV2Structure">fetchMethodV2Structure</a></li><li data-type='method'><a href="module-Sanity-Services.html#.fetchMethodV2StructureFromId">fetchMethodV2StructureFromId</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#.fetchOwnedContent">fetchOwnedContent</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#.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#.fetchTopLevelParentId">fetchTopLevelParentId</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#.getUserSignature">getUserSignature</a></li><li data-type='method'><a href="module-UserManagement.html#.isUsernameAvailable">isUsernameAvailable</a></li><li data-type='method'><a href="module-UserManagement.html#.setUserSignature">setUserSignature</a></li><li data-type='method'><a href="module-UserManagement.html#.toggleSignaturePrivate">toggleSignaturePrivate</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-UserMemberships.html">UserMemberships</a><ul class='methods'><li data-type='method'><a href="module-UserMemberships.html#~fetchMemberships">fetchMemberships</a></li><li data-type='method'><a href="module-UserMemberships.html#~fetchRechargeTokens">fetchRechargeTokens</a></li><li data-type='method'><a href="module-UserMemberships.html#~restorePurchases">restorePurchases</a></li><li data-type='method'><a href="module-UserMemberships.html#~upgradeSubscription">upgradeSubscription</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="Forums.html">Forums</a></li><li><a href="Gamification.html">Gamification</a></li><li><a href="UserManagementSystem.html">UserManagementSystem</a></li></ul><h3>Interfaces</h3><ul><li><a href="TestUser.html">TestUser</a></li></ul><h3>Global</h3><ul><li><a href="global.html#createTestUser">createTestUser</a></li></ul>
33
33
 
34
34
  </nav>
35
35
 
@@ -51,16 +51,20 @@
51
51
 
52
52
  import {
53
53
  fetchUserPractices,
54
- logUserPractice,
55
54
  fetchUserPracticeMeta,
56
55
  fetchUserPracticeNotes,
57
56
  fetchHandler,
58
57
  fetchRecentUserActivities,
59
58
  } from './railcontent'
60
59
  import { DataContext, UserActivityVersionKey } from './dataContext.js'
61
- import { fetchByRailContentId, fetchByRailContentIds, fetchShows } from './sanity'
60
+ import {
61
+ fetchByRailContentId,
62
+ fetchByRailContentIds,
63
+ fetchMethodV2IntroVideo,
64
+ fetchShows,
65
+ } from './sanity'
62
66
  import { fetchPlaylist, fetchUserPlaylists } from './content-org/playlists'
63
- import {guidedCourses} from './content-org/guided-courses'
67
+ import { guidedCourses } from './content-org/guided-courses'
64
68
  import {
65
69
  getMonday,
66
70
  getWeekNumber,
@@ -80,12 +84,11 @@ import {
80
84
  import { getAllStartedOrCompleted, getProgressStateByIds } from './contentProgress'
81
85
  import { TabResponseType } from '../contentMetaData'
82
86
  import dayjs from 'dayjs'
83
- import isSameOrBefore from 'dayjs/plugin/isSameOrBefore'
84
- import weekOfYear from 'dayjs/plugin/weekOfYear'
85
87
  import { addContextToContent } from './contentAggregator.js'
88
+ import { getMethodCard } from './progress-row/method-card.js'
89
+ import { db, Q } from './sync'
86
90
 
87
91
  const DATA_KEY_PRACTICES = 'practices'
88
- const DATA_KEY_LAST_UPDATED_TIME = 'u'
89
92
 
90
93
  const DAYS = ['M', 'T', 'W', 'T', 'F', 'S', 'S']
91
94
 
@@ -118,17 +121,29 @@ function getIndefiniteArticle(streak) {
118
121
  : 'a'
119
122
  }
120
123
 
121
- export async function getUserPractices(userId = globalConfig.sessionConfig.userId) {
122
- if (userId !== globalConfig.sessionConfig.userId) {
123
- let data = await fetchUserPractices(0, { userId: userId })
124
- return data?.['data']?.[DATA_KEY_PRACTICES] ?? {}
124
+ async function getUserPractices(userId) {
125
+ if (userId === globalConfig.sessionConfig.userId) {
126
+ return getOwnPractices()
125
127
  } else {
126
- let data = await userActivityContext.getData()
127
- return data?.[DATA_KEY_PRACTICES] ?? {}
128
+ return await fetchUserPractices(userId)
128
129
  }
129
130
  }
130
131
 
131
- export let userActivityContext = new DataContext(UserActivityVersionKey, fetchUserPractices)
132
+ async function getOwnPractices(...clauses) {
133
+ const query = await db.practices.queryAll(...clauses)
134
+ const data = query.data.reduce((acc, practice) => {
135
+ acc[practice.date] = acc[practice.date] || []
136
+ acc[practice.date].push({
137
+ id: practice.id,
138
+ duration_seconds: practice.duration_seconds,
139
+ })
140
+ return acc
141
+ }, {})
142
+
143
+ return data
144
+ }
145
+
146
+ export let userActivityContext = new DataContext(UserActivityVersionKey, function() {})
132
147
 
133
148
  /**
134
149
  * Retrieves user activity statistics for the current week, including daily activity and streak messages.
@@ -143,20 +158,21 @@ export let userActivityContext = new DataContext(UserActivityVersionKey, fetchUs
143
158
  */
144
159
  export async function getUserWeeklyStats() {
145
160
  const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone
146
- let data = await userActivityContext.getData()
147
- let practices = data?.[DATA_KEY_PRACTICES] ?? {}
148
- let sortedPracticeDays = Object.keys(practices)
149
- .map((date) => toDayjs(date)) // Convert to dayjs instance
150
- .sort((a, b) => b.valueOf() - a.valueOf())
151
- let today = dayjs()
152
- let startOfWeek = getMonday(today, timeZone) // Get last Monday
161
+ const today = dayjs()
162
+ const startOfWeek = getMonday(today, timeZone)
163
+ const weekDays = Array.from({ length: 7 }, (_, i) => startOfWeek.add(i, 'day').format('YYYY-MM-DD'))
164
+
165
+ const practices = await getOwnPractices(
166
+ Q.where('date', Q.oneOf(weekDays)),
167
+ Q.sortBy('date', 'desc')
168
+ )
169
+ const practiceDaysSet = new Set(Object.keys(practices))
153
170
  let dailyStats = []
154
171
  for (let i = 0; i &lt; 7; i++) {
155
172
  const day = startOfWeek.add(i, 'day')
156
- let hasPractice = sortedPracticeDays.some((practiceDate) =>
157
- isSameDate(practiceDate, day.format('YYYY-MM-DD'))
158
- )
159
- let isActive = isSameDate(today.format(), day.format())
173
+ const dayStr = day.format('YYYY-MM-DD')
174
+ let hasPractice = practiceDaysSet.has(dayStr)
175
+ let isActive = isSameDate(today.format(), dayStr)
160
176
  let type = hasPractice ? 'tracked' : isActive ? 'active' : 'none'
161
177
  dailyStats.push({
162
178
  key: i,
@@ -164,7 +180,7 @@ export async function getUserWeeklyStats() {
164
180
  isActive,
165
181
  inStreak: hasPractice,
166
182
  type,
167
- day: day.format('YYYY-MM-DD'),
183
+ day: dayStr,
168
184
  })
169
185
  }
170
186
 
@@ -305,82 +321,50 @@ export async function getUserMonthlyStats(params = {}) {
305
321
  }
306
322
 
307
323
  /**
308
- * Records user practice data and updates both the remote and local activity context.
324
+ * Records a manual user practice data, updating the local database and syncing with remote.
309
325
  *
310
326
  * @param {Object} practiceDetails - The details of the practice session.
311
327
  * @param {number} practiceDetails.duration_seconds - The duration of the practice session in seconds.
312
- * @param {boolean} [practiceDetails.auto=true] - Whether the session was automatically logged.
313
- * @param {number} [practiceDetails.content_id] - The ID of the practiced content (if available).
314
- * @param {number} [practiceDetails.category_id] - The ID of the associated category (if available).
315
328
  * @param {string} [practiceDetails.title] - The title of the practice session (max 64 characters).
329
+ * @param {number} [practiceDetails.category_id] - The ID of the associated category (if available).
316
330
  * @param {string} [practiceDetails.thumbnail_url] - The URL of the session's thumbnail (max 255 characters).
331
+ * @param {number} [practiceDetails.instrument_id] - The ID of the associated instrument (if available).
317
332
  * @returns {Promise&lt;Object>} - A promise that resolves to the response from logging the user practice.
318
333
  *
319
334
  * @example
320
- * // Record an auto practice session with content ID
321
- * recordUserPractice({ content_id: 123, duration_seconds: 300 })
335
+ * // Record a manual practice session with a title
336
+ * recordUserPractice({ title: "Some title", duration_seconds: 300 })
322
337
  * .then(response => console.log(response))
323
338
  * .catch(error => console.error(error));
324
339
  *
325
- * @example
326
- * // Record a custom practice session with additional details
327
- * recordUserPractice({
328
- * duration_seconds: 600,
329
- * auto: false,
330
- * category_id: 5,
331
- * title: "Guitar Warm-up",
332
- * thumbnail_url: "https://example.com/thumbnail.jpg",
333
- * instrument_id: 1,
334
- * instrument_id: 2,
335
- * })
336
- * .then(response => console.log(response))
337
- * .catch(error => console.error(error));
338
340
  */
339
341
  export async function recordUserPractice(practiceDetails) {
340
- practiceDetails.auto = 0
341
- practiceDetails.timezone = Intl.DateTimeFormat().resolvedOptions().timeZone
342
- if (practiceDetails.content_id) {
343
- practiceDetails.auto = 1
344
- }
342
+ const day = new Date().toLocaleDateString('sv-SE'); // YYYY-MM-DD wall clock date in user's timezone
343
+ const durationSeconds = practiceDetails.duration_seconds
344
+
345
+ return await db.practices.recordManualPractice(day, durationSeconds, {
346
+ title: practiceDetails.title ?? null,
347
+ category_id: practiceDetails.category_id ?? null,
348
+ thumbnail_url: practiceDetails.thumbnail_url ?? null,
349
+ instrument_id: practiceDetails.instrument_id ?? null,
350
+ })
351
+ }
345
352
 
346
- await userActivityContext.update(
347
- async function (localContext) {
348
- let userData = localContext.data ?? { [DATA_KEY_PRACTICES]: {} }
349
- localContext.data = userData
350
- },
351
- async function () {
352
- const response = await logUserPractice(practiceDetails)
353
- if (response) {
354
- await userActivityContext.updateLocal(async function (localContext) {
355
- const newPractices = response.data ?? []
356
- newPractices.forEach((newPractice) => {
357
- const { date } = newPractice
358
- if (!localContext.data[DATA_KEY_PRACTICES][date]) {
359
- localContext.data[DATA_KEY_PRACTICES][date] = []
360
- }
361
- localContext.data[DATA_KEY_PRACTICES][date][DATA_KEY_LAST_UPDATED_TIME] = Math.round(
362
- new Date().getTime() / 1000
363
- )
364
- localContext.data[DATA_KEY_PRACTICES][date].push({
365
- id: newPractice.id,
366
- duration_seconds: newPractice.duration_seconds, // Add the new practice for this date
367
- })
368
- })
369
- })
370
- }
371
- return response
372
- }
373
- )
353
+ export async function trackUserPractice(contentId, incSeconds) {
354
+ const day = new Date().toLocaleDateString('sv-SE'); // YYYY-MM-DD wall clock date in user's timezone
355
+ return await db.practices.trackAutoPractice(contentId, day, incSeconds);
374
356
  }
357
+
375
358
  /**
376
359
  * Updates a user's practice session with new details and syncs the changes remotely.
377
360
  *
378
- * @param {number} id - The unique identifier of the practice session to update.
361
+ * @param {string} id - The unique identifier of the practice session to update.
379
362
  * @param {Object} practiceDetails - The updated details of the practice session.
380
363
  * @param {number} [practiceDetails.duration_seconds] - The duration of the practice session in seconds.
381
364
  * @param {number} [practiceDetails.category_id] - The ID of the associated category (if available).
382
365
  * @param {string} [practiceDetails.title] - The title of the practice session (max 64 characters).
383
366
  * @param {string} [practiceDetails.thumbnail_url] - The URL of the session's thumbnail (max 255 characters).
367
+ * @param {number} [practiceDetails.instrument_id] - The ID of the associated instrument (if available).
384
368
  * @returns {Promise&lt;Object>} - A promise that resolves to the response from updating the user practice.
385
369
  *
386
370
  * @example
@@ -389,15 +373,9 @@ export async function recordUserPractice(practiceDetails) {
389
373
  * .then(response => console.log(response))
390
374
  * .catch(error => console.error(error));
391
375
  *
392
- * @example
393
- * // Change a practice session to manual and update its category
394
- * updateUserPractice(456, { auto: false, category_id: 8 })
395
- * .then(response => console.log(response))
396
- * .catch(error => console.error(error));
397
376
  */
398
377
  export async function updateUserPractice(id, practiceDetails) {
399
- const url = `/api/user/practices/v1/practices/${id}`
400
- return await fetchHandler(url, 'PUT', null, practiceDetails)
378
+ return await db.practices.updateDetails(id, practiceDetails)
401
379
  }
402
380
 
403
381
  /**
@@ -413,26 +391,7 @@ export async function updateUserPractice(id, practiceDetails) {
413
391
  * .catch(error => console.error(error));
414
392
  */
415
393
  export async function removeUserPractice(id) {
416
- let url = `/api/user/practices/v1/practices${buildQueryString([id])}`
417
- await userActivityContext.update(
418
- async function (localContext) {
419
- if (localContext.data?.[DATA_KEY_PRACTICES]) {
420
- Object.keys(localContext.data[DATA_KEY_PRACTICES]).forEach((date) => {
421
- const filtered = localContext.data[DATA_KEY_PRACTICES][date].filter(
422
- (practice) => practice.id !== id
423
- )
424
- if (filtered.length > 0) {
425
- localContext.data[DATA_KEY_PRACTICES][date] = filtered
426
- } else {
427
- delete localContext.data[DATA_KEY_PRACTICES][date]
428
- }
429
- })
430
- }
431
- },
432
- async function () {
433
- return await fetchHandler(url, 'delete')
434
- }
435
- )
394
+ return await db.practices.deleteOne(id)
436
395
  }
437
396
 
438
397
  /**
@@ -496,20 +455,8 @@ export async function restoreUserPractice(id) {
496
455
  * .catch(error => console.error("Delete failed:", error));
497
456
  */
498
457
  export async function deletePracticeSession(day) {
499
- const userPracticesIds = await getUserPracticeIds(day)
500
- if (!userPracticesIds.length) return []
501
-
502
- const url = `/api/user/practices/v1/practices${buildQueryString(userPracticesIds)}`
503
- await userActivityContext.update(
504
- async function (localContext) {
505
- if (localContext.data?.[DATA_KEY_PRACTICES]?.[day]) {
506
- delete localContext.data[DATA_KEY_PRACTICES][day]
507
- }
508
- },
509
- async function () {
510
- return await fetchHandler(url, 'DELETE', null)
511
- }
512
- )
458
+ const ids = await db.practices.queryAllIds(Q.where('date', day))
459
+ return await db.practices.deleteSome(ids.data)
513
460
  }
514
461
 
515
462
  /**
@@ -580,13 +527,23 @@ export async function restorePracticeSession(date) {
580
527
  */
581
528
  export async function getPracticeSessions(params = {}) {
582
529
  const { day, userId = globalConfig.sessionConfig.userId } = params
583
- const userPracticesIds = await getUserPracticeIds(day, userId)
584
- if (!userPracticesIds.length) return { data: { practices: [], practiceDuration: 0 } }
585
530
 
586
- const meta = await fetchUserPracticeMeta(userPracticesIds, userId)
587
- if (!meta.data.length) return { data: { practices: [], practiceDuration: 0 } }
531
+ let data
588
532
 
589
- const formattedMeta = await formatPracticeMeta(meta.data)
533
+ if (userId === globalConfig.sessionConfig.userId) {
534
+ const query = await db.practices.queryAll(
535
+ Q.where('date', day),
536
+ Q.sortBy('created_at', 'asc')
537
+ )
538
+ data = query.data
539
+ } else {
540
+ const query = await fetchUserPracticeMeta(day, userId)
541
+ data = query.data
542
+ }
543
+
544
+ if (!data.length) return { data: { practices: [], practiceDuration: 0 } }
545
+
546
+ const formattedMeta = await formatPracticeMeta(data)
590
547
  const practiceDuration = formattedMeta.reduce(
591
548
  (total, practice) => total + (practice.duration || 0),
592
549
  0
@@ -608,9 +565,8 @@ export async function getPracticeSessions(params = {}) {
608
565
  * .then(({ data }) => console.log("Practice notes:", data))
609
566
  * .catch(error => console.error("Failed to get notes:", error));
610
567
  */
611
- export async function getPracticeNotes(day) {
612
- const notes = await fetchUserPracticeNotes(day)
613
- return { data: notes }
568
+ export async function getPracticeNotes(date) {
569
+ return await db.practiceDayNotes.queryOne(Q.where('date', date))
614
570
  }
615
571
 
616
572
  /**
@@ -659,8 +615,10 @@ export async function getRecentActivity({ page = 1, limit = 5, tabName = null }
659
615
  * .catch(error => console.error(error));
660
616
  */
661
617
  export async function createPracticeNotes(payload) {
662
- const url = `/api/user/practices/v1/notes`
663
- return await fetchHandler(url, 'POST', null, payload)
618
+ return await db.practiceDayNotes.upsertOne(payload.date, r => {
619
+ r.date = payload.date
620
+ r.notes = payload.notes
621
+ })
664
622
  }
665
623
 
666
624
  /**
@@ -677,8 +635,9 @@ export async function createPracticeNotes(payload) {
677
635
  * .catch(error => console.error(error));
678
636
  */
679
637
  export async function updatePracticeNotes(payload) {
680
- const url = `/api/user/practices/v1/notes`
681
- return await fetchHandler(url, 'PUT', null, payload)
638
+ return await db.practiceDayNotes.updateOneId(payload.date, r => {
639
+ r.notes = payload.notes
640
+ })
682
641
  }
683
642
 
684
643
  function getStreaksAndMessage(practices) {
@@ -691,24 +650,6 @@ function getStreaksAndMessage(practices) {
691
650
  }
692
651
  }
693
652
 
694
- async function getUserPracticeIds(day = dayjs().format('YYYY-MM-DD'), userId = null) {
695
- let practices = {}
696
- if (userId !== globalConfig.sessionConfig.userId) {
697
- let data = await fetchUserPractices(0, { userId: userId })
698
- practices = data?.['data']?.[DATA_KEY_PRACTICES] ?? {}
699
- } else {
700
- let data = await userActivityContext.getData()
701
- practices = data?.[DATA_KEY_PRACTICES] ?? {}
702
- }
703
- let userPracticesIds = []
704
- Object.keys(practices).forEach((date) => {
705
- if (date === day) {
706
- practices[date].forEach((practice) => userPracticesIds.push(practice.id))
707
- }
708
- })
709
- return userPracticesIds
710
- }
711
-
712
653
  function buildQueryString(ids, paramName = 'practice_ids') {
713
654
  if (!ids.length) return ''
714
655
  return '?' + ids.map((id) => `${paramName}[]=${id}`).join('&amp;')
@@ -908,7 +849,8 @@ async function formatPracticeMeta(practices = []) {
908
849
  })
909
850
 
910
851
  return practices.map((practice) => {
911
- const content = contents &amp;&amp; contents.length > 0 ? contents.find((c) => c.id === practice.content_id) : {}
852
+ const content =
853
+ contents &amp;&amp; contents.length > 0 ? contents.find((c) => c.id === practice.content_id) : {}
912
854
 
913
855
  return {
914
856
  id: practice.id,
@@ -997,12 +939,15 @@ async function extractPinnedItemsAndSortAllItems(
997
939
  userPinnedItem,
998
940
  contentsMap,
999
941
  eligiblePlaylistItems,
942
+ methodCard,
943
+ //method contents
1000
944
  limit
1001
945
  ) {
1002
946
  let pinnedItem = await popPinnedItemFromContentsOrPlaylistMap(
1003
947
  userPinnedItem,
1004
948
  contentsMap,
1005
- eligiblePlaylistItems
949
+ eligiblePlaylistItems,
950
+ methodCard
1006
951
  )
1007
952
 
1008
953
  let combined = []
@@ -1012,18 +957,19 @@ async function extractPinnedItemsAndSortAllItems(
1012
957
  combined.push(pinnedItem)
1013
958
  }
1014
959
 
960
+ if (!(pinnedItem &amp;&amp; pinnedItem.progressType === 'method')) {
961
+ combined.push(methodCard)
962
+ }
963
+
1015
964
  const progressList = Array.from(contentsMap.values())
965
+ //need another for methodContents?
966
+
1016
967
  combined = [...combined, ...progressList, ...eligiblePlaylistItems]
1017
968
  return mergeAndSortItems(combined, limit)
1018
969
  }
1019
970
 
1020
971
  function generateContentsMap(contents, playlistsContents) {
1021
- const excludedTypes = new Set([
1022
- 'pack-bundle',
1023
- 'learning-path-course',
1024
- 'learning-path-level',
1025
- 'guided-course-part',
1026
- ])
972
+ const excludedTypes = new Set(['pack-bundle', 'guided-course-part'])
1027
973
  const existingShows = new Set()
1028
974
  const contentsMap = new Map()
1029
975
  const childToParentMap = {}
@@ -1055,8 +1001,6 @@ function generateContentsMap(contents, playlistsContents) {
1055
1001
  }
1056
1002
  })
1057
1003
 
1058
- // TODO this doesn't work for guided courses as the GC card takes precedence over the playlist card
1059
- // https://musora.atlassian.net/browse/BEH-812
1060
1004
  if (playlistsContents) {
1061
1005
  for (const item of playlistsContents) {
1062
1006
  const contentId = item.id
@@ -1065,6 +1009,7 @@ function generateContentsMap(contents, playlistsContents) {
1065
1009
  parentIds.forEach((id) => contentsMap.delete(id))
1066
1010
  }
1067
1011
  }
1012
+
1068
1013
  return contentsMap
1069
1014
  }
1070
1015
 
@@ -1081,15 +1026,14 @@ function generateContentsMap(contents, playlistsContents) {
1081
1026
  * .then(data => console.log(data))
1082
1027
  * .catch(error => console.error(error));
1083
1028
  */
1084
- export async function getProgressRows({ brand = null, limit = 8 } = {}) {
1029
+ export async function getProgressRows({ brand = 'drumeo', limit = 8 } = {}) {
1085
1030
  // TODO slice progress to a reasonable number, say 100
1086
-
1087
- const [recentPlaylists, progressContents, userPinnedItem] =
1088
- await Promise.all([
1089
- fetchUserPlaylists(brand, { sort: '-last_progress', limit: limit }),
1090
- getAllStartedOrCompleted({ onlyIds: false, brand: brand }),
1091
- getUserPinnedItem(brand),
1092
- ])
1031
+ const methodCardPromise = getMethodCard(brand)
1032
+ const [recentPlaylists, progressContents, userPinnedItem] = await Promise.all([
1033
+ fetchUserPlaylists(brand, { sort: '-last_progress', limit: limit }),
1034
+ getAllStartedOrCompleted({ onlyIds: false, brand: brand, limit }),
1035
+ getUserPinnedItem(brand),
1036
+ ])
1093
1037
 
1094
1038
  const playlists = recentPlaylists?.data || []
1095
1039
  const eligiblePlaylistItems = await getEligiblePlaylistItems(playlists)
@@ -1097,40 +1041,58 @@ export async function getProgressRows({ brand = null, limit = 8 } = {}) {
1097
1041
  (item) => item.playlist.last_engaged_on
1098
1042
  )
1099
1043
 
1044
+ // todo post v2: refactor this once we migrate playlist progress tracking to new system
1100
1045
  const nonPlaylistContentIds = Object.keys(progressContents)
1101
1046
  if (userPinnedItem?.progressType === 'content') {
1102
1047
  nonPlaylistContentIds.push(userPinnedItem.id)
1103
1048
  }
1104
-
1049
+ //need to update addContextToContent to accept collection info
1105
1050
  const [playlistsContents, contents] = await Promise.all([
1106
- playlistEngagedOnContents ? addContextToContent(fetchByRailContentIds, playlistEngagedOnContents, 'progress-tracker', {
1107
- addNextLesson: true,
1108
- addNavigateTo: true,
1109
- addProgressStatus: true,
1110
- addProgressPercentage: true,
1111
- addProgressTimestamp: true,
1112
- }) : Promise.resolve([]),
1113
- nonPlaylistContentIds ? addContextToContent(fetchByRailContentIds, nonPlaylistContentIds, 'progress-tracker', brand, {
1114
- addNextLesson: true,
1115
- addNavigateTo: true,
1116
- addProgressStatus: true,
1117
- addProgressPercentage: true,
1118
- addProgressTimestamp: true,
1119
- }) : Promise.resolve([]),
1051
+ (playlistEngagedOnContents.length > 0)
1052
+ ? addContextToContent(fetchByRailContentIds, playlistEngagedOnContents, 'progress-tracker', {
1053
+ addNavigateTo: true,
1054
+ addProgressStatus: true,
1055
+ addProgressPercentage: true,
1056
+ addProgressTimestamp: true,
1057
+ })
1058
+ : Promise.resolve([]),
1059
+ (nonPlaylistContentIds.length > 0)
1060
+ ? addContextToContent(
1061
+ fetchByRailContentIds,
1062
+ nonPlaylistContentIds,
1063
+ 'progress-tracker',
1064
+ brand,
1065
+ {
1066
+ addNavigateTo: true,
1067
+ addProgressStatus: true,
1068
+ addProgressPercentage: true,
1069
+ addProgressTimestamp: true,
1070
+ }
1071
+ )
1072
+ : Promise.resolve([]),
1120
1073
  ])
1074
+
1121
1075
  const contentsMap = generateContentsMap(contents, playlistsContents)
1076
+ const methodCard = await methodCardPromise
1122
1077
  let combined = await extractPinnedItemsAndSortAllItems(
1123
1078
  userPinnedItem,
1124
1079
  contentsMap,
1125
1080
  eligiblePlaylistItems,
1081
+ methodCard,
1126
1082
  limit
1127
1083
  )
1128
1084
  const results = await Promise.all(
1129
- combined
1130
- .slice(0, limit)
1131
- .map((item) =>
1132
- item.type === 'playlist' ? processPlaylistItem(item) : processContentItem(item)
1133
- )
1085
+ combined.slice(0, limit).map((item) => {
1086
+ switch (item.type) {
1087
+ case 'playlist':
1088
+ return processPlaylistItem(item)
1089
+ case 'learning-path-v2':
1090
+ case 'method':
1091
+ return item
1092
+ default:
1093
+ return processContentItem(item)
1094
+ }
1095
+ })
1134
1096
  )
1135
1097
  return {
1136
1098
  type: TabResponseType.PROGRESS_ROWS,
@@ -1165,7 +1127,11 @@ async function processContentItem(content) {
1165
1127
  })
1166
1128
  content.time_remaining_seconds = timeRemaining.totalSeconds
1167
1129
  ctaText = 'Next lesson in ' + timeRemaining.formatted
1168
- } else if (!content.progressStatus || content.progressStatus === 'not-started' || content.progressPercentage === 0) {
1130
+ } else if (
1131
+ !content.progressStatus ||
1132
+ content.progressStatus === 'not-started' ||
1133
+ content.progressPercentage === 0
1134
+ ) {
1169
1135
  ctaText = 'Start Course'
1170
1136
  }
1171
1137
  }
@@ -1183,6 +1149,7 @@ async function processContentItem(content) {
1183
1149
  content = shows.find((lesson) => lesson.id === nextByProgress)
1184
1150
  content.completed_children = completedShows
1185
1151
  content.progressTimestamp = progressTimestamp
1152
+ content.progressTimestamp = progressTimestamp
1186
1153
  content.pinned = wasPinned
1187
1154
  }
1188
1155
  content.child_count = shows.length
@@ -1191,23 +1158,26 @@ async function processContentItem(content) {
1191
1158
  ctaText = 'Revisit Show'
1192
1159
  }
1193
1160
  }
1194
-
1161
+ console.log('Progress Timestamp', content.progressTimestamp)
1195
1162
  return {
1196
- id: content.id,
1197
- progressType: 'content',
1198
- header: contentType,
1199
- pinned: content.pinned ?? false,
1200
- content: content,
1201
- body: {
1163
+ id: content.id,
1164
+ progressType: 'content',
1165
+ header: contentType,
1166
+ pinned: content.pinned ?? false,
1167
+ content: content,
1168
+ body: {
1202
1169
  progressPercent: isLive ? undefined : content.progressPercentage,
1203
- thumbnail: content.thumbnail,
1204
- title: content.title,
1205
- isLive: isLive,
1206
- badge: content.badge ?? null,
1207
- isLocked: content.is_locked ?? false,
1208
- subtitle: collectionLessonTypes.includes(content.type) || content.lesson_count > 1
1209
- ? `${content.completed_children} of ${content.lesson_count ?? content.child_count} Lessons Complete`
1210
- : (contentType === 'lesson' &amp;&amp; isLive === false) ? `${content.progressPercentage}% Complete`: `${content.difficulty_string} ${content.artist_name}`
1170
+ thumbnail: content.thumbnail,
1171
+ title: content.title,
1172
+ isLive: isLive,
1173
+ badge: content.badge ?? null,
1174
+ isLocked: content.is_locked ?? false,
1175
+ subtitle:
1176
+ collectionLessonTypes.includes(content.type) || content.lesson_count > 1
1177
+ ? `${content.completed_children} of ${content.lesson_count ?? content.child_count} Lessons Complete`
1178
+ : contentType === 'lesson' &amp;&amp; isLive === false
1179
+ ? `${content.progressPercentage}% Complete`
1180
+ : `${content.difficulty_string} • ${content.artist_name}`,
1211
1181
  },
1212
1182
  cta: {
1213
1183
  text: ctaText,
@@ -1263,6 +1233,7 @@ async function getCompletedChildren(content, contentType) {
1263
1233
 
1264
1234
  async function processPlaylistItem(item) {
1265
1235
  const playlist = item.playlist
1236
+
1266
1237
  return {
1267
1238
  id: playlist.id,
1268
1239
  progressType: 'playlist',
@@ -1351,7 +1322,6 @@ function mergeAndSortItems(items, limit) {
1351
1322
  .sort((a, b) => {
1352
1323
  if (a.pinned &amp;&amp; !b.pinned) return -1
1353
1324
  if (!a.pinned &amp;&amp; b.pinned) return 1
1354
- // TODO pinned guided course should always be before user pinned item
1355
1325
  return b.progressTimestamp - a.progressTimestamp
1356
1326
  })
1357
1327
  .slice(0, limit + 5)
@@ -1359,7 +1329,7 @@ function mergeAndSortItems(items, limit) {
1359
1329
 
1360
1330
  export function findIncompleteLesson(progressOnItems, currentContentId, contentType) {
1361
1331
  const ids = Object.keys(progressOnItems).map(Number)
1362
- if (contentType === 'guided-course') {
1332
+ if (contentType === 'guided-course' || contentType === 'learning-path-v2') {
1363
1333
  // Return first incomplete lesson
1364
1334
  return ids.find((id) => progressOnItems[id] !== 'completed') || ids.at(0)
1365
1335
  }
@@ -1378,11 +1348,16 @@ export function findIncompleteLesson(progressOnItems, currentContentId, contentT
1378
1348
  return ids[0]
1379
1349
  }
1380
1350
 
1381
- async function popPinnedItemFromContentsOrPlaylistMap(pinned, contentsMap, playlistItems) {
1351
+ async function popPinnedItemFromContentsOrPlaylistMap(
1352
+ pinned,
1353
+ contentsMap,
1354
+ playlistItems,
1355
+ methodCard
1356
+ ) {
1382
1357
  if (!pinned) return null
1383
1358
  const { id, pinnedAt } = pinned
1384
1359
  let item = null
1385
- const progressType = pinned.progressType ?? pinned.type;
1360
+ const progressType = pinned.progressType ?? pinned.type
1386
1361
 
1387
1362
  if (progressType === 'content') {
1388
1363
  const pinnedId = parseInt(id)
@@ -1416,12 +1391,17 @@ async function popPinnedItemFromContentsOrPlaylistMap(pinned, contentsMap, playl
1416
1391
  }
1417
1392
  }
1418
1393
  }
1394
+ if (progressType === 'method') {
1395
+ // simply get method card and return
1396
+ item = methodCard
1397
+ //todo remove method card
1398
+ }
1419
1399
  return item
1420
1400
  }
1421
1401
 
1422
1402
  function popContentAndRemoveChildrenFromContentsMap(content, contentsMap) {
1423
- if (!content.children || content.children.length === 0){
1424
- console.warn(`content ${content.id} has no children`, content);
1403
+ if (!content.children || content.children.length === 0) {
1404
+ console.warn(`content ${content.id} has no children`, content)
1425
1405
  } else {
1426
1406
  const children = content.children.map((child) => child.id)
1427
1407
  if (contentsMap.has(content.id)) {
@@ -1519,7 +1499,7 @@ export async function fetchRecentActivitiesActiveTabs() {
1519
1499
  <br class="clear">
1520
1500
 
1521
1501
  <footer>
1522
- Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.3</a> on Tue Nov 04 2025 18:21:55 GMT+0000 (Coordinated Universal Time) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
1502
+ Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.3</a> on Fri Nov 28 2025 11:22:56 GMT-0800 (Pacific Standard Time) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
1523
1503
  </footer>
1524
1504
 
1525
1505
  <script>prettyPrint();</script>