musora-content-services 1.3.21 → 2.0.5

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 (96) hide show
  1. package/.editorconfig +16 -0
  2. package/.github/workflows/node.js.yml +0 -0
  3. package/.prettierignore +0 -0
  4. package/.prettierrc +0 -0
  5. package/CHANGELOG.md +4 -4
  6. package/README.md +0 -0
  7. package/babel.config.cjs +0 -0
  8. package/docs/Content-Organization.html +245 -0
  9. package/docs/Playlists.html +192 -0
  10. package/docs/config.js.html +14 -5
  11. package/docs/content-org_playlists-types.js.html +109 -0
  12. package/docs/content-org_playlists.js.html +194 -0
  13. package/docs/content-org_types.js.html +112 -0
  14. package/docs/content.js.html +443 -0
  15. package/docs/fonts/Montserrat/Montserrat-Bold.eot +0 -0
  16. package/docs/fonts/Montserrat/Montserrat-Bold.ttf +0 -0
  17. package/docs/fonts/Montserrat/Montserrat-Bold.woff +0 -0
  18. package/docs/fonts/Montserrat/Montserrat-Bold.woff2 +0 -0
  19. package/docs/fonts/Montserrat/Montserrat-Regular.eot +0 -0
  20. package/docs/fonts/Montserrat/Montserrat-Regular.ttf +0 -0
  21. package/docs/fonts/Montserrat/Montserrat-Regular.woff +0 -0
  22. package/docs/fonts/Montserrat/Montserrat-Regular.woff2 +0 -0
  23. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.eot +0 -0
  24. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.svg +0 -0
  25. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.ttf +0 -0
  26. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff +0 -0
  27. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff2 +0 -0
  28. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.eot +0 -0
  29. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.svg +0 -0
  30. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.ttf +0 -0
  31. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff +0 -0
  32. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff2 +0 -0
  33. package/docs/global.html +3878 -0
  34. package/docs/index.html +2 -2
  35. package/docs/module-Config.html +60 -7
  36. package/docs/module-Content-Organization-Playlists.html +194 -0
  37. package/docs/module-Content-Organization.html +976 -0
  38. package/docs/module-Content-Services-V2.html +2433 -0
  39. package/docs/module-Playlists.html +969 -0
  40. package/docs/module-Railcontent-Services.html +3052 -1991
  41. package/docs/module-Sanity-Services.html +57 -43
  42. package/docs/module-Session-Management.html +575 -0
  43. package/docs/module-User-Permissions.html +406 -0
  44. package/docs/module-playlists.html +1878 -0
  45. package/docs/module-playlists_.html +108 -0
  46. package/docs/railcontent.js.html +149 -112
  47. package/docs/sanity.js.html +297 -109
  48. package/docs/scripts/collapse.js +0 -0
  49. package/docs/scripts/commonNav.js +0 -0
  50. package/docs/scripts/linenumber.js +0 -0
  51. package/docs/scripts/nav.js +0 -0
  52. package/docs/scripts/polyfill.js +0 -0
  53. package/docs/scripts/prettify/Apache-License-2.0.txt +0 -0
  54. package/docs/scripts/prettify/lang-css.js +0 -0
  55. package/docs/scripts/prettify/prettify.js +0 -0
  56. package/docs/scripts/search.js +0 -0
  57. package/docs/styles/jsdoc.css +0 -0
  58. package/docs/styles/prettify.css +0 -0
  59. package/docs/user_permissions.js.html +110 -0
  60. package/docs/user_sessions.js.html +139 -0
  61. package/docs/user_types.js.html +188 -0
  62. package/jest.config.js +0 -0
  63. package/jsdoc.json +3 -0
  64. package/package.json +1 -1
  65. package/publish.sh +2 -2
  66. package/src/contentMetaData.js +307 -1088
  67. package/src/contentTypeConfig.js +108 -4
  68. package/src/filterBuilder.js +6 -6
  69. package/src/index.d.ts +67 -9
  70. package/src/index.js +67 -9
  71. package/src/{services → lib}/lastUpdated.js +17 -1
  72. package/src/services/content-org/playlists-types.js +37 -0
  73. package/src/services/content-org/playlists.js +122 -0
  74. package/src/services/content.js +371 -0
  75. package/src/services/contentLikes.js +0 -0
  76. package/src/services/contentProgress.js +0 -0
  77. package/src/services/forum.js +57 -0
  78. package/src/services/railcontent.js +122 -122
  79. package/src/services/recommendations.js +19 -0
  80. package/src/services/sanity.js +278 -104
  81. package/src/services/{userPermissions.js → user/permissions.js} +16 -2
  82. package/src/services/user/sessions.js +67 -0
  83. package/src/services/user/types.js +116 -0
  84. package/src/services/userActivity.js +32 -0
  85. package/test/content.test.js +116 -0
  86. package/test/contentProgress.test.js +83 -5
  87. package/test/forum.test.js +18 -0
  88. package/test/initializeTests.js +6 -1
  89. package/test/{lastUpdated.test.js → lib/lastUpdated.test.js} +2 -5
  90. package/test/live/contentProgressLive.test.js +0 -0
  91. package/test/live/railcontentLive.test.js +0 -0
  92. package/test/localStorageMock.js +0 -0
  93. package/test/log.js +0 -0
  94. package/test/sanityQueryService.test.js +66 -18
  95. package/test/{userPermissions.test.js → user/permissions.test.js} +3 -3
  96. package/tools/generate-index.cjs +16 -3
@@ -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-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-Railcontent-Services.html">Railcontent-Services</a><ul class='methods'><li data-type='method'><a href="module-Railcontent-Services.html#.addItemToPlaylist">addItemToPlaylist</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.countAssignmentsAndLessons">countAssignmentsAndLessons</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.createPlaylist">createPlaylist</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.deletePlaylist">deletePlaylist</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.deletePlaylistItem">deletePlaylistItem</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.deletePlaylistLike">deletePlaylistLike</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.duplicatePlaylist">duplicatePlaylist</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#.fetchChallengeIndexMetadata">fetchChallengeIndexMetadata</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.fetchChallengeLessonData">fetchChallengeLessonData</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.fetchChallengeMetadata">fetchChallengeMetadata</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.fetchChallengeUserActiveChallenges">fetchChallengeUserActiveChallenges</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.fetchCompletedChallenges">fetchCompletedChallenges</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#.fetchOwnedChallenges">fetchOwnedChallenges</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.fetchPinnedPlaylists">fetchPinnedPlaylists</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.fetchPlaylist">fetchPlaylist</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.fetchPlaylistItem">fetchPlaylistItem</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.fetchPlaylistItems">fetchPlaylistItems</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#.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#.fetchUserChallengeProgress">fetchUserChallengeProgress</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.fetchUserPlaylists">fetchUserPlaylists</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.likePlaylist">likePlaylist</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.pinPlaylist">pinPlaylist</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.postChallengesCommunityNotification">postChallengesCommunityNotification</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.postChallengesCompleteLesson">postChallengesCompleteLesson</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.postChallengesEnroll">postChallengesEnroll</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.postChallengesEnrollmentNotification">postChallengesEnrollmentNotification</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.postChallengesHideCompletedBanner">postChallengesHideCompletedBanner</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.postChallengesLeave">postChallengesLeave</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.postChallengesSetStartDate">postChallengesSetStartDate</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.postChallengesSoloNotification">postChallengesSoloNotification</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.postChallengesUnlock">postChallengesUnlock</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.reportPlaylist">reportPlaylist</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#.unpinPlaylist">unpinPlaylist</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.updatePlaylist">updatePlaylist</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.updatePlaylistItem">updatePlaylistItem</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#.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#.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#.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#.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#~getNextAndPreviousQuarterDates">getNextAndPreviousQuarterDates</a></li><li data-type='method'><a href="module-Sanity-Services.html#~getQueryFromPage">getQueryFromPage</a></li><li data-type='method'><a href="module-Sanity-Services.html#~handleCustomFetchAll">handleCustomFetchAll</a></li></ul></li></ul>
32
+ <h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><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-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#.fetchUserPlaylists">fetchUserPlaylists</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#.countAssignmentsAndLessons">countAssignmentsAndLessons</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#.deletePlaylist">deletePlaylist</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.deletePlaylistItem">deletePlaylistItem</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.deletePlaylistLike">deletePlaylistLike</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.duplicatePlaylist">duplicatePlaylist</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#.fetchChallengeIndexMetadata">fetchChallengeIndexMetadata</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.fetchChallengeLessonData">fetchChallengeLessonData</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.fetchChallengeMetadata">fetchChallengeMetadata</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.fetchChallengeUserActiveChallenges">fetchChallengeUserActiveChallenges</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#.fetchCompletedChallenges">fetchCompletedChallenges</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#.fetchOwnedChallenges">fetchOwnedChallenges</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.fetchPinnedPlaylists">fetchPinnedPlaylists</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.fetchPlaylist">fetchPlaylist</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.fetchPlaylistItem">fetchPlaylistItem</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.fetchPlaylistItems">fetchPlaylistItems</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#.fetchUserChallengeProgress">fetchUserChallengeProgress</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#.likePlaylist">likePlaylist</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#.pinPlaylist">pinPlaylist</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.postChallengesCommunityNotification">postChallengesCommunityNotification</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.postChallengesCompleteLesson">postChallengesCompleteLesson</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.postChallengesEnroll">postChallengesEnroll</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.postChallengesEnrollmentNotification">postChallengesEnrollmentNotification</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.postChallengesHideCompletedBanner">postChallengesHideCompletedBanner</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.postChallengesLeave">postChallengesLeave</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.postChallengesSetStartDate">postChallengesSetStartDate</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.postChallengesSoloNotification">postChallengesSoloNotification</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.postChallengesUnlock">postChallengesUnlock</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#.reportPlaylist">reportPlaylist</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#.unpinPlaylist">unpinPlaylist</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.updatePlaylist">updatePlaylist</a></li><li data-type='method'><a href="module-Railcontent-Services.html#.updatePlaylistItem">updatePlaylistItem</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#.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#.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#.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#.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#~getNextAndPreviousQuarterDates">getNextAndPreviousQuarterDates</a></li><li data-type='method'><a href="module-Sanity-Services.html#~getQueryFromPage">getQueryFromPage</a></li><li data-type='method'><a href="module-Sanity-Services.html#~handleCustomFetchAll">handleCustomFetchAll</a></li></ul></li><li><a href="module-Session-Management.html">Session-Management</a><ul class='methods'><li data-type='method'><a href="module-Session-Management.html#.login">login</a></li><li data-type='method'><a href="module-Session-Management.html#.logout">logout</a></li></ul></li><li><a href="module-User-Permissions.html">User-Permissions</a><ul class='methods'><li data-type='method'><a href="module-User-Permissions.html#.fetchUserPermissions">fetchUserPermissions</a></li><li data-type='method'><a href="module-User-Permissions.html#.reset">reset</a></li></ul></li></ul><h3>Namespaces</h3><ul><li><a href="Content-Organization.html">Content-Organization</a></li></ul><h3><a href="global.html">Global</a></h3>
33
33
 
34
34
  </nav>
35
35
 
@@ -50,7 +50,6 @@
50
50
  */
51
51
  import {
52
52
  artistOrInstructorName,
53
- artistOrInstructorNameAsArray,
54
53
  assignmentsField,
55
54
  descriptionField,
56
55
  resourcesField,
@@ -70,14 +69,13 @@ import { processMetadata, typeWithSortOrder } from '../contentMetaData.js'
70
69
  import { globalConfig } from './config.js'
71
70
 
72
71
  import {
73
- fetchAllCompletedStates,
74
72
  fetchCompletedChallenges,
75
73
  fetchOwnedChallenges,
76
74
  fetchNextContentDataForParent,
77
75
  fetchHandler,
78
76
  } from './railcontent.js'
79
77
  import { arrayToStringRepresentation, FilterBuilder } from '../filterBuilder.js'
80
- import { fetchUserPermissions } from './userPermissions.js'
78
+ import { fetchUserPermissions } from './user/permissions.js'
81
79
  import { getAllCompleted, getAllStarted, getAllStartedOrCompleted } from './contentProgress.js'
82
80
 
83
81
  /**
@@ -120,15 +118,22 @@ export async function fetchSongById(documentId) {
120
118
  * @number contentPerPage
121
119
  * @returns {Promise&lt;Object|null>}
122
120
  */
123
- export async function fetchLeaving(
124
- brand,
125
- { pageNumber = 1, contentPerPage = 20 } = {}) {
126
- const nextQuarter = getNextAndPreviousQuarterDates()['next'];
121
+ export async function fetchLeaving(brand, { pageNumber = 1, contentPerPage = 20 } = {}) {
122
+ const nextQuarter = getNextAndPreviousQuarterDates()['next']
127
123
  const filterString = `brand == '${brand}' &amp;&amp; quarter_removed == '${nextQuarter}'`
128
- const startEndOrder = getQueryFromPage(pageNumber, contentPerPage);
129
- const sortOrder = {sortOrder: "published_on desc, id desc", start: startEndOrder['start'], end: startEndOrder['end']};
130
- const query = await buildQuery(filterString, {pullFutureContent: false, availableContentStatuses: ["published"]}, getFieldsForContentType(), sortOrder);
131
- return fetchSanity(query, true);
124
+ const startEndOrder = getQueryFromPage(pageNumber, contentPerPage)
125
+ const sortOrder = {
126
+ sortOrder: 'published_on desc, id desc',
127
+ start: startEndOrder['start'],
128
+ end: startEndOrder['end'],
129
+ }
130
+ const query = await buildQuery(
131
+ filterString,
132
+ { pullFutureContent: false, availableContentStatuses: ['published'] },
133
+ getFieldsForContentType(),
134
+ sortOrder
135
+ )
136
+ return fetchSanity(query, true)
132
137
  }
133
138
 
134
139
  /**
@@ -139,16 +144,23 @@ export async function fetchLeaving(
139
144
  * @number contentPerPage
140
145
  * @returns {Promise&lt;Object|null>}
141
146
  */
142
- export async function fetchReturning(
143
- brand,
144
- { pageNumber = 1, contentPerPage = 20 } = {}) {
145
- const nextQuarter = getNextAndPreviousQuarterDates()['next'];
146
- const filterString = `brand == '${brand}' &amp;&amp; quarter_published == '${nextQuarter}'`;
147
- const startEndOrder = getQueryFromPage(pageNumber, contentPerPage);
148
- const sortOrder = {sortOrder: "published_on desc, id desc", start: startEndOrder['start'], end: startEndOrder['end']};
149
- const query = await buildQuery(filterString, {pullFutureContent: true, availableContentStatuses: ["draft"]}, getFieldsForContentType(), sortOrder);
150
-
151
- return fetchSanity(query, true);
147
+ export async function fetchReturning(brand, { pageNumber = 1, contentPerPage = 20 } = {}) {
148
+ const nextQuarter = getNextAndPreviousQuarterDates()['next']
149
+ const filterString = `brand == '${brand}' &amp;&amp; quarter_published == '${nextQuarter}'`
150
+ const startEndOrder = getQueryFromPage(pageNumber, contentPerPage)
151
+ const sortOrder = {
152
+ sortOrder: 'published_on desc, id desc',
153
+ start: startEndOrder['start'],
154
+ end: startEndOrder['end'],
155
+ }
156
+ const query = await buildQuery(
157
+ filterString,
158
+ { pullFutureContent: true, availableContentStatuses: ['draft'] },
159
+ getFieldsForContentType('returning'),
160
+ sortOrder
161
+ )
162
+
163
+ return fetchSanity(query, true)
152
164
  }
153
165
 
154
166
  /**
@@ -159,14 +171,21 @@ export async function fetchReturning(
159
171
  * @number contentPerPage
160
172
  * @returns {Promise&lt;Object|null>}
161
173
  */
162
- export async function fetchComingSoon(
163
- brand,
164
- { pageNumber = 1, contentPerPage = 20 } = {}) {
165
- const filterString = `brand == '${brand}' &amp;&amp; _type == 'song'`;
166
- const startEndOrder = getQueryFromPage(pageNumber, contentPerPage);
167
- const sortOrder = {sortOrder: "published_on desc, id desc", start: startEndOrder['start'], end: startEndOrder['end']};
168
- const query = await buildQuery(filterString, {getFutureContentOnly: true}, getFieldsForContentType(), sortOrder);
169
- return fetchSanity(query, true);
174
+ export async function fetchComingSoon(brand, { pageNumber = 1, contentPerPage = 20 } = {}) {
175
+ const filterString = `brand == '${brand}' &amp;&amp; _type == 'song'`
176
+ const startEndOrder = getQueryFromPage(pageNumber, contentPerPage)
177
+ const sortOrder = {
178
+ sortOrder: 'published_on desc, id desc',
179
+ start: startEndOrder['start'],
180
+ end: startEndOrder['end'],
181
+ }
182
+ const query = await buildQuery(
183
+ filterString,
184
+ { getFutureContentOnly: true },
185
+ getFieldsForContentType(),
186
+ sortOrder
187
+ )
188
+ return fetchSanity(query, true)
170
189
  }
171
190
 
172
191
  /**
@@ -175,47 +194,47 @@ export async function fetchComingSoon(
175
194
  * @returns {number[]}
176
195
  */
177
196
  function getQueryFromPage(pageNumber, contentPerPage) {
178
- const start = contentPerPage*(pageNumber-1);
179
- const end = contentPerPage*pageNumber;
180
- let result = [];
181
- result['start'] = start;
182
- result['end'] = end;
183
- return result;
197
+ const start = contentPerPage * (pageNumber - 1)
198
+ const end = contentPerPage * pageNumber
199
+ let result = []
200
+ result['start'] = start
201
+ result['end'] = end
202
+ return result
184
203
  }
185
204
 
186
205
  /**
187
206
  * returns array of next and previous quarter dates as strings
188
207
  *
189
- * @returns {*[]}
208
+ * @returns {string[]}
190
209
  */
191
210
  function getNextAndPreviousQuarterDates() {
192
- const january = 1;
193
- const april = 4;
194
- const july = 7;
195
- const october = 10;
196
- const month = new Date().getMonth();
197
- let year = new Date().getFullYear();
198
- let nextQuarter = '';
199
- let prevQuarter = '';
211
+ const january = 1
212
+ const april = 4
213
+ const july = 7
214
+ const october = 10
215
+ const month = new Date().getMonth()
216
+ let year = new Date().getFullYear()
217
+ let nextQuarter = ''
218
+ let prevQuarter = ''
200
219
  if (month &lt; april) {
201
- nextQuarter = `${year}-0${april}-01`;
202
- prevQuarter = `${year}-0${january}-01`;
220
+ nextQuarter = `${year}-0${april}-01`
221
+ prevQuarter = `${year}-0${january}-01`
203
222
  } else if (month &lt; july) {
204
- nextQuarter = `${year}-0${july}-01`;
205
- prevQuarter = `${year}-0${april}-01`;
223
+ nextQuarter = `${year}-0${july}-01`
224
+ prevQuarter = `${year}-0${april}-01`
206
225
  } else if (month &lt; october) {
207
- nextQuarter = `${year}-${october}-01`;
208
- prevQuarter = `${year}-0${july}-01`;
226
+ nextQuarter = `${year}-${october}-01`
227
+ prevQuarter = `${year}-0${july}-01`
209
228
  } else {
210
- prevQuarter = `${year}-${october}-01`;
211
- year++;
212
- nextQuarter = `${year}-0${january}-01`;
229
+ prevQuarter = `${year}-${october}-01`
230
+ year++
231
+ nextQuarter = `${year}-0${january}-01`
213
232
  }
214
233
 
215
- let result = [];
216
- result['next'] = nextQuarter;
217
- result['previous'] = prevQuarter;
218
- return result;
234
+ let result = []
235
+ result['next'] = nextQuarter
236
+ result['previous'] = prevQuarter
237
+ return result
219
238
  }
220
239
 
221
240
  /**
@@ -249,8 +268,8 @@ export async function fetchArtists(brand) {
249
268
  */
250
269
  export async function fetchSongArtistCount(brand) {
251
270
  const filter = await new FilterBuilder(
252
- `_type == "song" &amp;&amp; brand == "${brand}" &amp;&amp; references(^._id)`,
253
- { bypassPermissions: true }
271
+ `_type == "song" &amp;&amp; brand == "${brand}" &amp;&amp; references(^._id)`,
272
+ { bypassPermissions: true }
254
273
  ).buildFilter()
255
274
  const query = `
256
275
  count(*[_type == "artist"]{
@@ -260,13 +279,13 @@ export async function fetchSongArtistCount(brand) {
260
279
  return fetchSanity(query, true, { processNeedAccess: false })
261
280
  }
262
281
 
263
- export async function fetchPlayAlongsCount(brand, {
264
- searchTerm,
265
- includedFields,
266
- progressIds,
267
- progress,
268
- }) {
269
- const searchFilter = searchTerm ? `&amp;&amp; (artist->name match "${searchTerm}*" || instructor[]->name match "${searchTerm}*" || title match "${searchTerm}*" || name match "${searchTerm}*")` :'';
282
+ export async function fetchPlayAlongsCount(
283
+ brand,
284
+ { searchTerm, includedFields, progressIds, progress }
285
+ ) {
286
+ const searchFilter = searchTerm
287
+ ? `&amp;&amp; (artist->name match "${searchTerm}*" || instructor[]->name match "${searchTerm}*" || title match "${searchTerm}*" || name match "${searchTerm}*")`
288
+ : ''
270
289
 
271
290
  // Construct the included fields filter, replacing 'difficulty' with 'difficulty_string'
272
291
  const includedFieldsFilter = includedFields.length > 0 ? filtersToGroq(includedFields) : ''
@@ -302,6 +321,7 @@ export async function fetchRelatedSongs(brand, songId) {
302
321
  "published_on": published_on,
303
322
  status,
304
323
  "image": thumbnail.asset->url,
324
+ "permission_id": permission[]->railcontent_id,
305
325
  "fields": [
306
326
  {
307
327
  "key": "title",
@@ -327,6 +347,7 @@ export async function fetchRelatedSongs(brand, songId) {
327
347
  "id": railcontent_id,
328
348
  "url": web_url_path,
329
349
  "published_on": published_on,
350
+ "permission_id": permission[]->railcontent_id,
330
351
  status,
331
352
  "fields": [
332
353
  {
@@ -372,7 +393,8 @@ export async function fetchNewReleases(
372
393
  const start = (page - 1) * limit
373
394
  const end = start + limit
374
395
  const sortOrder = getSortOrder(sort, brand)
375
- const filter = `_type in ${typesString} &amp;&amp; brand == '${brand}' &amp;&amp; show_in_new_feed == true`
396
+ const nextQuarter = getNextAndPreviousQuarterDates()['next']
397
+ const filter = `_type in ${typesString} &amp;&amp; brand == '${brand}' &amp;&amp; show_in_new_feed == true &amp;&amp; (!defined(quarter_published) || quarter_published != '${nextQuarter}')`
376
398
  const fields = `
377
399
  "id": railcontent_id,
378
400
  title,
@@ -534,7 +556,7 @@ export async function fetchByRailContentId(id, contentType) {
534
556
  */
535
557
  export async function fetchByRailContentIds(ids, contentType = undefined) {
536
558
  if (!ids) {
537
- return [];
559
+ return []
538
560
  }
539
561
  const idsString = ids.join(',')
540
562
 
@@ -635,6 +657,8 @@ export async function fetchAll(
635
657
  if (type === 'archives') {
636
658
  typeFilter = `&amp;&amp; status == "archived"`
637
659
  bypassStatusAndPublishedValidation = true
660
+ } else if (type === 'lessons' || type === 'songs') {
661
+ typeFilter = ``
638
662
  } else if (type === 'pack') {
639
663
  typeFilter = `&amp;&amp; (_type == 'pack' || _type == 'semester-pack')`
640
664
  } else {
@@ -902,6 +926,14 @@ async function getProgressFilter(progress, progressIds) {
902
926
  const ids = await getAllStartedOrCompleted()
903
927
  return `&amp;&amp; !(railcontent_id in [${ids.join(',')}])`
904
928
  }
929
+ case 'recent': {
930
+ const ids = await getAllStartedOrCompleted()
931
+ return `&amp;&amp; (railcontent_id in [${ids.join(',')}])`
932
+ }
933
+ case 'incomplete': {
934
+ const ids = await getAllStarted()
935
+ return `&amp;&amp; railcontent_id in [${ids.join(',')}]`
936
+ }
905
937
  default:
906
938
  throw new Error(`'${progress}' progress option not implemented`)
907
939
  }
@@ -977,6 +1009,13 @@ export async function fetchAllFilterOptions(
977
1009
  coachId,
978
1010
  includeTabs = false
979
1011
  ) {
1012
+ if (contentType == 'lessons' || contentType == 'songs') {
1013
+ const metaData = processMetadata(brand, contentType, true)
1014
+ return {
1015
+ meta: metaData,
1016
+ }
1017
+ }
1018
+
980
1019
  if (coachId &amp;&amp; contentType !== 'coach-lessons') {
981
1020
  throw new Error(
982
1021
  `Invalid contentType: '${contentType}' for coachId. It must be 'coach-lessons'.`
@@ -1255,26 +1294,26 @@ export async function fetchLessonContent(railContentId) {
1255
1294
  // Format changes made to the `fields` object may also need to be reflected in Musora-web-platform SanityGateway.php $fields object
1256
1295
  // Currently only for challenges and challenge lessons
1257
1296
  // If you're unsure, message Adrian, or just add them.
1258
- const fields = `title,
1297
+ const fields = `title,
1259
1298
  published_on,
1260
- "type":_type,
1299
+ "type":_type,
1261
1300
  "resources": ${resourcesField},
1262
- difficulty,
1263
- difficulty_string,
1264
- brand,
1301
+ difficulty,
1302
+ difficulty_string,
1303
+ brand,
1265
1304
  status,
1266
- soundslice,
1267
- instrumentless,
1268
- railcontent_id,
1269
- "id":railcontent_id,
1305
+ soundslice,
1306
+ instrumentless,
1307
+ railcontent_id,
1308
+ "id":railcontent_id,
1270
1309
  slug, artist->,
1271
- "thumbnail_url":thumbnail.asset->url,
1272
- "url": web_url_path,
1310
+ "thumbnail_url":thumbnail.asset->url,
1311
+ "url": web_url_path,
1273
1312
  soundslice_slug,
1274
1313
  "description": description[0].children[0].text,
1275
1314
  "chapters": chapter[]{
1276
1315
  chapter_description,
1277
- chapter_timecode,
1316
+ chapter_timecode,
1278
1317
  "chapter_thumbnail_url": chapter_thumbnail_url.asset->url
1279
1318
  },
1280
1319
  "instructors":instructor[]->name,
@@ -1282,7 +1321,7 @@ export async function fetchLessonContent(railContentId) {
1282
1321
  "id":railcontent_id,
1283
1322
  name,
1284
1323
  short_bio,
1285
- "biography": short_bio[0].children[0].text,
1324
+ "biography": short_bio[0].children[0].text,
1286
1325
  web_url_path,
1287
1326
  "coach_card_image": coach_card_image.asset->url,
1288
1327
  "coach_profile_image":thumbnail_url.asset->url
@@ -1303,11 +1342,22 @@ export async function fetchLessonContent(railContentId) {
1303
1342
  "type": *[railcontent_id == ^.id][0]._type,
1304
1343
  },
1305
1344
  sort,
1306
- xp`
1345
+ xp,
1346
+ stbs,ds2stbs, bdsStbs`
1307
1347
  const query = await buildQuery(`railcontent_id == ${railContentId}`, filterParams, fields, {
1308
1348
  isSingle: true,
1309
1349
  })
1310
- return fetchSanity(query, false)
1350
+ const chapterProcess = (result) => {
1351
+ const chapters = result.chapters ?? []
1352
+ if (chapters.length == 0) return result
1353
+ result.chapters = chapters.map((chapter, index) => ({
1354
+ ...chapter,
1355
+ chapter_thumbnail_url: `https://musora-web-platform.s3.amazonaws.com/chapters/${result.brand}/Chapter${index + 1}.jpg`,
1356
+ }))
1357
+ return result
1358
+ }
1359
+
1360
+ return fetchSanity(query, false, { customPostProcess: chapterProcess })
1311
1361
  }
1312
1362
 
1313
1363
  /**
@@ -1331,15 +1381,16 @@ export async function fetchRelatedLessons(railContentId, brand) {
1331
1381
  ).buildFilter()
1332
1382
  const filterNeighbouringSiblings = await new FilterBuilder(`references(^._id)`).buildFilter()
1333
1383
  const childrenFilter = await new FilterBuilder(``, { isChildrenFilter: true }).buildFilter()
1334
-
1384
+ const queryFields = `_id, "id":railcontent_id, published_on, "instructor": instructor[0]->name, title, "thumbnail_url":thumbnail.asset->url, length_in_seconds, web_url_path, "type": _type, difficulty, difficulty_string, railcontent_id, artist->,"permission_id": permission[]->railcontent_id,_type, "genre": genre[]->name`
1385
+ const queryFieldsWithSort = queryFields + ', sort'
1335
1386
  const query = `*[railcontent_id == ${railContentId} &amp;&amp; brand == "${brand}" &amp;&amp; (!defined(permission) || references(*[_type=='permission']._id))]{
1336
1387
  _type, parent_type, railcontent_id,
1337
1388
  "related_lessons" : array::unique([
1338
- ...(*[${filterNeighbouringSiblings}][0].child[${childrenFilter}]->{_id, "id":railcontent_id, published_on, "instructor": instructor[0]->name, title, "thumbnail_url":thumbnail.asset->url, length_in_seconds, web_url_path, "type": _type, difficulty, difficulty_string, railcontent_id, artist->,"permission_id": permission[]->railcontent_id,_type}),
1339
- ...(*[${filterSongSameArtist}]{_id, "id":railcontent_id, published_on, "instructor": instructor[0]->name, title, "thumbnail_url":thumbnail.asset->url, length_in_seconds, web_url_path, "type": _type, difficulty, difficulty_string, railcontent_id, artist->,"permission_id": permission[]->railcontent_id,_type}|order(published_on desc, title asc)[0...10]),
1340
- ...(*[${filterSongSameGenre}]{_id, "id":railcontent_id, published_on, "instructor": instructor[0]->name, title, "thumbnail_url":thumbnail.asset->url, length_in_seconds, web_url_path, "type": _type, difficulty, difficulty_string, railcontent_id, artist->,"permission_id": permission[]->railcontent_id,_type}|order(published_on desc, title asc)[0...10]),
1341
- ...(*[${filterSameTypeAndSortOrder}]{_id, "id":railcontent_id, published_on, "instructor": instructor[0]->name, title, "thumbnail_url":thumbnail.asset->url, length_in_seconds, web_url_path, "type": _type, difficulty, difficulty_string, railcontent_id, artist->,"permission_id": permission[]->railcontent_id,_type, sort}|order(sort asc, title asc)[0...10]),
1342
- ...(*[${filterSameType}]{_id, "id":railcontent_id, published_on, "instructor": instructor[0]->name, title, "thumbnail_url":thumbnail.asset->url, length_in_seconds, web_url_path, "type": _type, difficulty, difficulty_string, railcontent_id, artist->,"permission_id": permission[]->railcontent_id,_type}|order(published_on desc, title asc)[0...10])
1389
+ ...(*[${filterNeighbouringSiblings}][0].child[${childrenFilter}]->{${queryFields}}),
1390
+ ...(*[${filterSongSameArtist}]{${queryFields}}|order(published_on desc, title asc)[0...10]),
1391
+ ...(*[${filterSongSameGenre}]{${queryFields}}|order(published_on desc, title asc)[0...10]),
1392
+ ...(*[${filterSameTypeAndSortOrder}]{${queryFieldsWithSort}}|order(sort asc, title asc)[0...10]),
1393
+ ...(*[${filterSameType}]{${queryFields}}|order(published_on desc, title asc)[0...10])
1343
1394
  ,
1344
1395
  ])[0...10]}`
1345
1396
  return fetchSanity(query, false)
@@ -1386,7 +1437,7 @@ export async function fetchPackAll(railcontentId, type = 'pack') {
1386
1437
  return fetchByRailContentId(railcontentId, type)
1387
1438
  }
1388
1439
 
1389
- export async function fetchLiveEvent(brand) {
1440
+ export async function fetchLiveEvent(brand, forcedContentId = null) {
1390
1441
  //calendarIDs taken from addevent.php
1391
1442
  // TODO import instructor calendars to Sanity
1392
1443
  let defaultCalendarID = ''
@@ -1414,7 +1465,9 @@ export async function fetchLiveEvent(brand) {
1414
1465
  // See LiveStreamEventService.getCurrentOrNextLiveEvent for some nice complicated logic which I don't think is actually importart
1415
1466
  // this has some +- on times
1416
1467
  // But this query just finds the first scheduled event (sorted by start_time) that ends after now()
1417
- const query = `*[status == 'scheduled' &amp;&amp; brand == '${brand}' &amp;&amp; defined(live_event_start_time) &amp;&amp; live_event_start_time &lt;= '${getSanityDate(startDateTemp, false)}' &amp;&amp; live_event_end_time >= '${getSanityDate(endDateTemp, false)}']{
1468
+ const query =
1469
+ forcedContentId !== null
1470
+ ? `*[railcontent_id == ${forcedContentId} ]{
1418
1471
  'slug': slug.current,
1419
1472
  'id': railcontent_id,
1420
1473
  live_event_start_time,
@@ -1425,13 +1478,36 @@ export async function fetchLiveEvent(brand) {
1425
1478
  'event_coach_url' : instructor[0]->web_url_path,
1426
1479
  'event_coach_calendar_id': coalesce(calendar_id, '${defaultCalendarID}'),
1427
1480
  title,
1428
- "image": thumbnail.asset->url,
1481
+ "thumbnail": thumbnail.asset->url,
1482
+ ${artistOrInstructorName()},
1483
+ difficulty_string,
1429
1484
  "instructors": instructor[]->{
1430
1485
  name,
1431
1486
  web_url_path,
1432
1487
  },
1433
1488
  'videoId': coalesce(live_event_youtube_id, video.external_id),
1434
1489
  } | order(live_event_start_time)[0...1]`
1490
+ : `*[status == 'scheduled' &amp;&amp; brand == '${brand}' &amp;&amp; defined(live_event_start_time) &amp;&amp; live_event_start_time &lt;= '${getSanityDate(startDateTemp, false)}' &amp;&amp; live_event_end_time >= '${getSanityDate(endDateTemp, false)}']{
1491
+ 'slug': slug.current,
1492
+ 'id': railcontent_id,
1493
+ live_event_start_time,
1494
+ live_event_end_time,
1495
+ live_event_youtube_id,
1496
+ railcontent_id,
1497
+ published_on,
1498
+ 'event_coach_url' : instructor[0]->web_url_path,
1499
+ 'event_coach_calendar_id': coalesce(calendar_id, '${defaultCalendarID}'),
1500
+ title,
1501
+ "thumbnail": thumbnail.asset->url,
1502
+ ${artistOrInstructorName()},
1503
+ difficulty_string,
1504
+ "instructors": instructor[]->{
1505
+ name,
1506
+ web_url_path,
1507
+ },
1508
+ 'videoId': coalesce(live_event_youtube_id, video.external_id),
1509
+ } | order(live_event_start_time)[0...1]`
1510
+
1435
1511
  return await fetchSanity(query, false, { processNeedAccess: false })
1436
1512
  }
1437
1513
 
@@ -1594,10 +1670,10 @@ export async function fetchArtistLessons(
1594
1670
  progressIds !== undefined ? `&amp;&amp; railcontent_id in [${progressIds.join(',')}]` : ''
1595
1671
  const now = getSanityDate(new Date())
1596
1672
  const query = `{
1597
- "entity":
1673
+ "entity":
1598
1674
  *[_type == 'artist' &amp;&amp; name == '${name}']
1599
- {'type': _type, name, 'thumbnail_url':thumbnail_url.asset->url,
1600
- 'lessons_count': count(*[${addType} brand == '${brand}' &amp;&amp; references(^._id)]),
1675
+ {'type': _type, name, 'thumbnail_url':thumbnail_url.asset->url,
1676
+ 'lessons_count': count(*[${addType} brand == '${brand}' &amp;&amp; references(^._id)]),
1601
1677
  'lessons': *[${addType} brand == '${brand}' &amp;&amp; references(^._id) &amp;&amp; (status in ['published'] || (status == 'scheduled' &amp;&amp; defined(published_on) &amp;&amp; published_on >= '${now}')) ${searchFilter} ${includedFieldsFilter} ${progressFilter}]{${fieldsString}}
1602
1678
  [${start}...${end}]}
1603
1679
  |order(${sortOrder})
@@ -1648,10 +1724,10 @@ export async function fetchGenreLessons(
1648
1724
  progressIds !== undefined ? `&amp;&amp; railcontent_id in [${progressIds.join(',')}]` : ''
1649
1725
  const now = getSanityDate(new Date())
1650
1726
  const query = `{
1651
- "entity":
1727
+ "entity":
1652
1728
  *[_type == 'genre' &amp;&amp; name == '${name}']
1653
- {'type': _type, name, 'thumbnail_url':thumbnail_url.asset->url,
1654
- 'lessons_count': count(*[${addType} brand == '${brand}' &amp;&amp; references(^._id)]),
1729
+ {'type': _type, name, 'thumbnail_url':thumbnail_url.asset->url,
1730
+ 'lessons_count': count(*[${addType} brand == '${brand}' &amp;&amp; references(^._id)]),
1655
1731
  'lessons': *[${addType} brand == '${brand}' &amp;&amp; references(^._id) &amp;&amp; (status in ['published'] || (status == 'scheduled' &amp;&amp; defined(published_on) &amp;&amp; published_on >= '${now}')) ${searchFilter} ${includedFieldsFilter} ${progressFilter}]{${fieldsString}}
1656
1732
  [${start}...${end}]}
1657
1733
  |order(${sortOrder})
@@ -1671,8 +1747,8 @@ export async function fetchTopLevelParentId(railcontentId) {
1671
1747
  'parents': *[^._id in child[]._ref ${statusFilter}]{
1672
1748
  railcontent_id,
1673
1749
  'parents': *[^._id in child[]._ref ${statusFilter}]{
1674
- railcontent_id,
1675
- }
1750
+ railcontent_id,
1751
+ }
1676
1752
  }
1677
1753
  }
1678
1754
  }
@@ -1706,8 +1782,8 @@ export async function fetchHierarchy(railcontentId) {
1706
1782
  railcontent_id,
1707
1783
  'assignments': assignment[]{railcontent_id},
1708
1784
  'children': child[${childrenFilter}]->{
1709
- railcontent_id,
1710
- }
1785
+ railcontent_id,
1786
+ }
1711
1787
  }
1712
1788
  }
1713
1789
  },
@@ -1923,6 +1999,7 @@ export async function fetchShowsData(brand) {
1923
1999
 
1924
2000
  /**
1925
2001
  * Fetch metadata from the contentMetaData.js based on brand and type.
2002
+ * For v2 you need to provide page type('lessons' or 'songs') in type parameter
1926
2003
  *
1927
2004
  * @param {string} brand - The brand for which to fetch metadata.
1928
2005
  * @param {string} type - The type for which to fetch metadata.
@@ -2007,7 +2084,7 @@ function checkSanityConfig(config) {
2007
2084
  function buildRawQuery(
2008
2085
  filter = '',
2009
2086
  fields = '...',
2010
- { sortOrder = 'published_on desc', start = 0, end = 10, isSingle = false}
2087
+ { sortOrder = 'published_on desc', start = 0, end = 10, isSingle = false }
2011
2088
  ) {
2012
2089
  const sortString = sortOrder ? `order(${sortOrder})` : ''
2013
2090
  const countString = isSingle ? '[0...1]' : `[${start}...${end}]`
@@ -2021,10 +2098,10 @@ async function buildQuery(
2021
2098
  baseFilter = '',
2022
2099
  filterParams = { pullFutureContent: false },
2023
2100
  fields = '...',
2024
- { sortOrder = 'published_on desc', start = 0, end = 10, isSingle = false}
2101
+ { sortOrder = 'published_on desc', start = 0, end = 10, isSingle = false }
2025
2102
  ) {
2026
2103
  const filter = await new FilterBuilder(baseFilter, filterParams).buildFilter()
2027
- return buildRawQuery(filter, fields, { sortOrder, start, end, isSingle})
2104
+ return buildRawQuery(filter, fields, { sortOrder, start, end, isSingle })
2028
2105
  }
2029
2106
 
2030
2107
  function buildEntityAndTotalQuery(
@@ -2035,7 +2112,7 @@ function buildEntityAndTotalQuery(
2035
2112
  const sortString = sortOrder ? `order(${sortOrder})` : ''
2036
2113
  const countString = isSingle ? '[0...1]' : `[${start}...${end}]`
2037
2114
  const query = `{
2038
- "entity": *[${filter}] | ${sortString}${countString}
2115
+ "entity": *[${filter}] | ${sortString}${countString}
2039
2116
  {
2040
2117
  ${fields}
2041
2118
  },
@@ -2050,7 +2127,7 @@ function getFilterOptions(option, commonFilter, contentType, brand) {
2050
2127
 
2051
2128
  switch (option) {
2052
2129
  case 'difficulty':
2053
- filterGroq = `
2130
+ filterGroq = `
2054
2131
  "difficulty": [
2055
2132
  {"type": "All", "count": count(*[${commonFilter} &amp;&amp; difficulty_string == "All"])},
2056
2133
  {"type": "Introductory", "count": count(*[${commonFilter} &amp;&amp; (difficulty_string == "Novice" || difficulty_string == "Introductory")])},
@@ -2137,6 +2214,117 @@ function cleanUpGroq(query) {
2137
2214
 
2138
2215
  return cleanedQuery
2139
2216
  }
2217
+
2218
+ // V2 methods
2219
+
2220
+ export async function fetchTabData(
2221
+ brand,
2222
+ pageName,
2223
+ {
2224
+ page = 1,
2225
+ limit = 10,
2226
+ sort = '-published_on',
2227
+ includedFields = [],
2228
+ progressIds = undefined,
2229
+ progress = 'all',
2230
+ } = {}
2231
+ ) {
2232
+ const start = (page - 1) * limit
2233
+ const end = start + limit
2234
+
2235
+ // Construct the included fields filter, replacing 'difficulty' with 'difficulty_string'
2236
+ const includedFieldsFilter =
2237
+ includedFields.length > 0 ? filtersToGroq(includedFields, [], pageName) : ''
2238
+
2239
+ // limits the results to supplied progressIds for started &amp; completed filters
2240
+ const progressFilter = await getProgressFilter(progress, progressIds)
2241
+
2242
+ // Determine the sort order
2243
+ const sortOrder = getSortOrder(sort, brand, '')
2244
+
2245
+ let fields = DEFAULT_FIELDS
2246
+ let fieldsString = fields.join(',')
2247
+
2248
+ // Determine the group by clause
2249
+ let query = ''
2250
+ let entityFieldsString = ''
2251
+ let filter = ''
2252
+
2253
+ filter = `brand == "${brand}" ${includedFieldsFilter} ${progressFilter}`
2254
+ const childrenFilter = await new FilterBuilder(``, { isChildrenFilter: true }).buildFilter()
2255
+ entityFieldsString = ` ${fieldsString},
2256
+ 'lesson_count': coalesce(count(child[${childrenFilter}]->), 0) ,
2257
+ 'length_in_seconds': coalesce(
2258
+ math::sum(
2259
+ select(
2260
+ child[${childrenFilter}]->length_in_seconds
2261
+ )
2262
+ ),
2263
+ length_in_seconds
2264
+ ),`
2265
+
2266
+ const filterWithRestrictions = await new FilterBuilder(filter, {}).buildFilter()
2267
+ query = buildEntityAndTotalQuery(filterWithRestrictions, entityFieldsString, {
2268
+ sortOrder: sortOrder,
2269
+ start: start,
2270
+ end: end,
2271
+ })
2272
+
2273
+ return fetchSanity(query, true)
2274
+ }
2275
+
2276
+ export async function fetchRecent(
2277
+ brand,
2278
+ pageName,
2279
+ { page = 1, limit = 10, sort = '-published_on', includedFields = [], progress = 'recent' } = {}
2280
+ ) {
2281
+ const mergedIncludedFields = [...includedFields, `tab,all`]
2282
+ const results = await fetchTabData(brand, pageName, {
2283
+ page,
2284
+ limit,
2285
+ sort,
2286
+ includedFields: mergedIncludedFields,
2287
+ progress: progress.toLowerCase(),
2288
+ })
2289
+ return results.entity
2290
+ }
2291
+
2292
+ export async function fetchScheduledAndNewReleases(
2293
+ brand,
2294
+ { page = 1, limit = 20, sort = '-published_on' } = {}
2295
+ ) {
2296
+ const upcomingTypes = getUpcomingEventsTypes(brand)
2297
+ const newTypes = getNewReleasesTypes(brand)
2298
+
2299
+ const scheduledTypes = merge(upcomingTypes, newTypes)
2300
+ const typesString = arrayJoinWithQuotes(scheduledTypes)
2301
+ const now = getSanityDate(new Date())
2302
+
2303
+ const start = (page - 1) * limit
2304
+ const end = start + limit
2305
+ const sortOrder = getSortOrder(sort, brand)
2306
+
2307
+ const query = `
2308
+ *[_type in [${typesString}] &amp;&amp; brand == '${brand}' &amp;&amp; ((status in ['published','scheduled'] &amp;&amp; published_on > '${now}')||(show_in_new_feed == true)) ]
2309
+ [${start}...${end}]
2310
+ | order(published_on asc) {
2311
+ "id": railcontent_id,
2312
+ title,
2313
+ "image": thumbnail.asset->url,
2314
+ ${artistOrInstructorName()},
2315
+ "artists": instructor[]->name,
2316
+ difficulty,
2317
+ difficulty_string,
2318
+ length_in_seconds,
2319
+ published_on,
2320
+ "type": _type,
2321
+ show_in_new_feed,
2322
+ web_url_path,
2323
+ "permission_id": permission[]->railcontent_id
2324
+ }`
2325
+
2326
+ return fetchSanity(query, true)
2327
+ }
2140
2328
  </code></pre>
2141
2329
  </article>
2142
2330
  </section>
@@ -2151,7 +2339,7 @@ function cleanUpGroq(query) {
2151
2339
  <br class="clear">
2152
2340
 
2153
2341
  <footer>
2154
- Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.3</a> on Fri Feb 21 2025 20:42:51 GMT+0000 (Coordinated Universal Time) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
2342
+ Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.3</a> on Thu Mar 20 2025 22:08:57 GMT+0000 (Coordinated Universal Time) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
2155
2343
  </footer>
2156
2344
 
2157
2345
  <script>prettyPrint();</script>