musora-content-services 2.85.1 → 2.86.1

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 (222) hide show
  1. package/.coderabbit.yaml +0 -0
  2. package/.editorconfig +0 -0
  3. package/.github/pull_request_template.md +0 -0
  4. package/.github/workflows/conventional-commits.yaml +0 -0
  5. package/.github/workflows/docs.js.yml +0 -0
  6. package/.github/workflows/node.js.yml +0 -0
  7. package/.prettierignore +0 -0
  8. package/.prettierrc +0 -0
  9. package/CHANGELOG.md +19 -0
  10. package/README.md +0 -0
  11. package/babel.config.cjs +0 -0
  12. package/docs/Content.html +0 -0
  13. package/docs/ContentOrganization.html +2 -2
  14. package/docs/Forums.html +2 -2
  15. package/docs/Gamification.html +2 -2
  16. package/docs/TestUser.html +2 -2
  17. package/docs/UserManagementSystem.html +2 -2
  18. package/docs/api_types.js.html +2 -2
  19. package/docs/config.js.html +5 -2
  20. package/docs/content-org_content-org.js.html +2 -2
  21. package/docs/content-org_guided-courses.ts.html +2 -2
  22. package/docs/content-org_learning-paths.ts.html +126 -24
  23. package/docs/content-org_playlists-types.js.html +2 -2
  24. package/docs/content-org_playlists.js.html +2 -2
  25. package/docs/content.js.html +88 -10
  26. package/docs/content_artist.ts.html +36 -41
  27. package/docs/content_content.ts.html +0 -0
  28. package/docs/content_genre.ts.html +29 -34
  29. package/docs/content_instructor.ts.html +25 -27
  30. package/docs/fonts/Montserrat/Montserrat-Bold.eot +0 -0
  31. package/docs/fonts/Montserrat/Montserrat-Bold.ttf +0 -0
  32. package/docs/fonts/Montserrat/Montserrat-Bold.woff +0 -0
  33. package/docs/fonts/Montserrat/Montserrat-Bold.woff2 +0 -0
  34. package/docs/fonts/Montserrat/Montserrat-Regular.eot +0 -0
  35. package/docs/fonts/Montserrat/Montserrat-Regular.ttf +0 -0
  36. package/docs/fonts/Montserrat/Montserrat-Regular.woff +0 -0
  37. package/docs/fonts/Montserrat/Montserrat-Regular.woff2 +0 -0
  38. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.eot +0 -0
  39. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.svg +0 -0
  40. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.ttf +0 -0
  41. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff +0 -0
  42. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff2 +0 -0
  43. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.eot +0 -0
  44. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.svg +0 -0
  45. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.ttf +0 -0
  46. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff +0 -0
  47. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff2 +0 -0
  48. package/docs/forums_categories.ts.html +22 -3
  49. package/docs/forums_discussions.js.html +0 -0
  50. package/docs/forums_forum.js.html +0 -0
  51. package/docs/forums_forums.ts.html +2 -2
  52. package/docs/forums_posts.ts.html +2 -2
  53. package/docs/forums_threads.ts.html +9 -9
  54. package/docs/gamification_awards.js.html +0 -0
  55. package/docs/gamification_awards.ts.html +26 -12
  56. package/docs/gamification_gamification.js.html +2 -2
  57. package/docs/gamification_types.js.html +0 -0
  58. package/docs/global.html +2 -2
  59. package/docs/index.html +2 -2
  60. package/docs/liveTesting.ts.html +2 -2
  61. package/docs/module-Accounts.html +14 -14
  62. package/docs/module-Artist.html +12 -10
  63. package/docs/module-Awards.html +106 -6
  64. package/docs/module-Categories.html +0 -0
  65. package/docs/module-Config.html +5 -4
  66. package/docs/module-Content-Services-V2.html +440 -9
  67. package/docs/module-ForumCategories.html +0 -0
  68. package/docs/module-ForumDiscussions.html +0 -0
  69. package/docs/module-Forums.html +627 -63
  70. package/docs/module-Genre.html +6 -6
  71. package/docs/module-GuidedCourses.html +2 -2
  72. package/docs/module-Instructor.html +10 -10
  73. package/docs/module-Interests.html +2 -2
  74. package/docs/module-LearningPaths.html +640 -12
  75. package/docs/module-Onboarding.html +32 -8
  76. package/docs/module-Payments.html +2 -2
  77. package/docs/module-Permissions.html +2 -2
  78. package/docs/module-Playlists.html +2 -2
  79. package/docs/module-ProgressRow.html +2 -2
  80. package/docs/module-Railcontent-Services.html +2 -2
  81. package/docs/module-Sanity-Services.html +786 -1853
  82. package/docs/module-Sessions.html +2 -2
  83. package/docs/module-Threads.html +0 -0
  84. package/docs/module-UserActivity.html +4 -4
  85. package/docs/module-UserChat.html +2 -2
  86. package/docs/module-UserManagement.html +2 -2
  87. package/docs/module-UserMemberships.html +2 -2
  88. package/docs/module-UserNotifications.html +2 -2
  89. package/docs/module-UserProfile.html +2 -2
  90. package/docs/progress-row_method-card.js.html +3 -3
  91. package/docs/railcontent.js.html +2 -2
  92. package/docs/sanity.js.html +230 -321
  93. package/docs/scripts/collapse.js +0 -0
  94. package/docs/scripts/commonNav.js +0 -0
  95. package/docs/scripts/linenumber.js +0 -0
  96. package/docs/scripts/nav.js +0 -0
  97. package/docs/scripts/polyfill.js +0 -0
  98. package/docs/scripts/prettify/Apache-License-2.0.txt +0 -0
  99. package/docs/scripts/prettify/lang-css.js +0 -0
  100. package/docs/scripts/prettify/prettify.js +0 -0
  101. package/docs/scripts/search.js +0 -0
  102. package/docs/styles/jsdoc.css +0 -0
  103. package/docs/styles/prettify.css +0 -0
  104. package/docs/userActivity.js.html +4 -3
  105. package/docs/user_account.ts.html +14 -13
  106. package/docs/user_chat.js.html +2 -2
  107. package/docs/user_interests.js.html +2 -2
  108. package/docs/user_management.js.html +2 -2
  109. package/docs/user_memberships.js.html +0 -0
  110. package/docs/user_memberships.ts.html +2 -2
  111. package/docs/user_notifications.js.html +2 -2
  112. package/docs/user_onboarding.ts.html +95 -4
  113. package/docs/user_payments.ts.html +2 -2
  114. package/docs/user_permissions.js.html +3 -3
  115. package/docs/user_profile.js.html +2 -2
  116. package/docs/user_sessions.js.html +2 -2
  117. package/docs/user_types.js.html +2 -2
  118. package/docs/user_user-management-system.js.html +2 -2
  119. package/jest.config.js +0 -0
  120. package/jsdoc.json +0 -0
  121. package/package.json +1 -1
  122. package/src/contentMetaData.js +0 -0
  123. package/src/contentTypeConfig.js +24 -16
  124. package/src/filterBuilder.js +0 -0
  125. package/src/index.d.ts +0 -0
  126. package/src/index.js +0 -0
  127. package/src/infrastructure/http/HttpClient.ts +0 -0
  128. package/src/infrastructure/http/executors/FetchRequestExecutor.ts +0 -0
  129. package/src/infrastructure/http/index.ts +0 -0
  130. package/src/infrastructure/http/interfaces/HeaderProvider.ts +0 -0
  131. package/src/infrastructure/http/interfaces/HttpError.ts +0 -0
  132. package/src/infrastructure/http/interfaces/NetworkError.ts +0 -0
  133. package/src/infrastructure/http/interfaces/RequestExecutor.ts +0 -0
  134. package/src/infrastructure/http/interfaces/RequestOptions.ts +0 -0
  135. package/src/infrastructure/http/providers/DefaultHeaderProvider.ts +0 -0
  136. package/src/lib/brands.ts +8 -0
  137. package/src/lib/httpHelper.js +0 -0
  138. package/src/lib/lastUpdated.js +0 -0
  139. package/src/lib/sanity/query.ts +30 -0
  140. package/src/services/api/types.js +0 -0
  141. package/src/services/api/types.ts +0 -0
  142. package/src/services/config.js +0 -0
  143. package/src/services/content/artist.ts +34 -39
  144. package/src/services/content/content.ts +7 -1
  145. package/src/services/content/genre.ts +27 -32
  146. package/src/services/content/instructor.ts +23 -25
  147. package/src/services/content-org/content-org.js +0 -0
  148. package/src/services/content-org/guided-courses.ts +0 -0
  149. package/src/services/content-org/learning-paths.ts +4 -4
  150. package/src/services/content-org/playlists-types.js +0 -0
  151. package/src/services/content-org/playlists.js +0 -0
  152. package/src/services/content.js +0 -0
  153. package/src/services/contentAggregator.js +5 -1
  154. package/src/services/contentLikes.js +0 -0
  155. package/src/services/contentProgress.js +6 -6
  156. package/src/services/dataContext.js +0 -0
  157. package/src/services/dateUtils.js +0 -0
  158. package/src/services/eventsAPI.js +0 -0
  159. package/src/services/forums/categories.ts +0 -0
  160. package/src/services/forums/forums.ts +0 -0
  161. package/src/services/forums/posts.ts +0 -0
  162. package/src/services/forums/threads.ts +0 -0
  163. package/src/services/forums/types.ts +0 -0
  164. package/src/services/gamification/awards.ts +0 -0
  165. package/src/services/gamification/gamification.js +0 -0
  166. package/src/services/imageSRCBuilder.js +0 -0
  167. package/src/services/imageSRCVerify.js +0 -0
  168. package/src/services/liveTesting.ts +0 -0
  169. package/src/services/permissions/PermissionsAdapter.ts +0 -0
  170. package/src/services/permissions/PermissionsAdapterFactory.ts +0 -0
  171. package/src/services/permissions/PermissionsV1Adapter.ts +0 -0
  172. package/src/services/permissions/PermissionsV2Adapter.ts +0 -0
  173. package/src/services/permissions/README.md +0 -0
  174. package/src/services/permissions/index.ts +0 -0
  175. package/src/services/progress-row/method-card.js +0 -0
  176. package/src/services/railcontent.js +0 -0
  177. package/src/services/recommendations.js +0 -0
  178. package/src/services/sanity.js +52 -45
  179. package/src/services/types.js +0 -0
  180. package/src/services/user/account.ts +0 -0
  181. package/src/services/user/chat.js +0 -0
  182. package/src/services/user/interests.js +0 -0
  183. package/src/services/user/management.js +0 -0
  184. package/src/services/user/memberships.ts +0 -0
  185. package/src/services/user/notifications.js +0 -0
  186. package/src/services/user/onboarding.ts +93 -2
  187. package/src/services/user/payments.ts +0 -0
  188. package/src/services/user/permissions.js +0 -0
  189. package/src/services/user/profile.js +0 -0
  190. package/src/services/user/sessions.js +0 -0
  191. package/src/services/user/types.d.ts +0 -0
  192. package/src/services/user/types.js +0 -0
  193. package/src/services/user/user-management-system.js +0 -0
  194. package/src/services/userActivity.js +1 -1
  195. package/test/HttpClient.test.js +0 -0
  196. package/test/content.test.js +0 -0
  197. package/test/contentLikes.test.js +0 -0
  198. package/test/contentProgress.test.js +0 -0
  199. package/test/dataContext.test.js +0 -0
  200. package/test/forum.test.js +0 -0
  201. package/test/imageSRCBuilder.test.js +0 -0
  202. package/test/imageSRCVerify.test.js +0 -0
  203. package/test/initializeTests.js +0 -0
  204. package/test/learningPaths.test.js +0 -0
  205. package/test/lib/lastUpdated.test.js +0 -0
  206. package/test/live/contentProgressLive.test.js +0 -0
  207. package/test/live/railcontentLive.test.js +0 -0
  208. package/test/localStorageMock.js +0 -0
  209. package/test/log.js +0 -0
  210. package/test/mockData/mockData_fetchByRailContentIds_one_content.json +0 -0
  211. package/test/mockData/mockData_progress_content.json +0 -0
  212. package/test/mockData/mockData_sanity_progress_content.json +0 -0
  213. package/test/mockData/mockData_user_practices.json +0 -0
  214. package/test/notifications.test.js +0 -0
  215. package/test/progressRows.test.js +0 -0
  216. package/test/sanityQueryService.test.js +0 -0
  217. package/test/streakMessage.test.js +0 -0
  218. package/test/user/permissions.test.js +0 -0
  219. package/test/userActivity.test.js +0 -0
  220. package/tools/generate-index.cjs +0 -0
  221. package/.claude/settings.local.json +0 -14
  222. package/.yarnrc.yml +0 -1
@@ -101,22 +101,22 @@ export async function resetAllLearningPaths() {
101
101
  * @returns {Promise<Object>} Learning path with enriched lesson data
102
102
  */
103
103
  export async function getEnrichedLearningPath(learningPathId) {
104
- // TODO: replace addNextLesson with addNaviageTo
105
104
  const response = (await addContextToContent(
106
105
  fetchByRailContentId,
107
106
  learningPathId,
108
107
  'learning-path-v2',
109
108
  {
109
+ collection: { id: learningPathId, type: 'learning-path-v2' },
110
110
  dataField: 'children',
111
111
  dataField_includeParent: true,
112
112
  addProgressStatus: true,
113
113
  addProgressPercentage: true,
114
114
  addProgressTimestamp: true,
115
- addNextLesson: true,
115
+ addNavigateTo: true,
116
116
  }
117
117
  )) as any
118
118
  if (!response) return response
119
-
119
+
120
120
  response.children = mapContentToParent(
121
121
  response.children,
122
122
  'learning-path-lesson-v2',
@@ -222,7 +222,7 @@ export async function fetchLearningPathLessons(
222
222
  nextLPLessons = await getLearningPathLessonsByIds(nextContentIds, nextLearningPathId)
223
223
  }
224
224
 
225
-
225
+
226
226
 
227
227
  return {
228
228
  ...learningPath,
File without changes
File without changes
File without changes
@@ -173,7 +173,11 @@ function extractItemsFromData(data, dataField, isParentArray, includeParent) {
173
173
  if (includeParent) {
174
174
  if (isParentArray) {
175
175
  for (const parent of data) {
176
- items = [...items, ...parent]
176
+ if(Array.isArray(parent)){
177
+ items = [...items, ...parent]
178
+ } else {
179
+ items = [...items, parent]
180
+ }
177
181
  }
178
182
  } else {
179
183
  items = [...items, data]
File without changes
@@ -410,7 +410,7 @@ function setStartedOrCompletedStatusInLocalContext(
410
410
 
411
411
  if (!hierarchy) return
412
412
 
413
- if (collection && collection.type === 'learning-path') {
413
+ if (collection && collection.type === 'learning-path-v2') {
414
414
  bubbleOrTrickleLearningPathProgress(hierarchy, contentId, localContext, isCompleted, collection)
415
415
  return
416
416
  }
@@ -453,7 +453,7 @@ function resetStatusInLocalContext(localContext, contentId, hierarchy, collectio
453
453
  let allChildIds
454
454
  let learningPathId = null
455
455
  let childrenIds = []
456
- if (collection && collection.type === 'learning-path') {
456
+ if (collection && collection.type === 'learning-path-v2') {
457
457
  [learningPathId, childrenIds] = findLearningPathAndChildren(hierarchy, contentId)
458
458
  allChildIds = (learningPathId === contentId) ? childrenIds : []
459
459
  } else {
@@ -471,7 +471,7 @@ function resetStatusInLocalContext(localContext, contentId, hierarchy, collectio
471
471
  delete localContext.data[key]
472
472
  }
473
473
  })
474
- if (collection && collection.type === 'learning-path') { // manual bubbling for LP
474
+ if (collection && collection.type === 'learning-path-v2') { // manual bubbling for LP
475
475
  if (learningPathId !== contentId) {
476
476
  bubbleLearningPathProgress(hierarchy, contentId, localContext, collection)
477
477
  }
@@ -492,7 +492,7 @@ function resetStatusInLocalContext(localContext, contentId, hierarchy, collectio
492
492
  * @param {string} sessionId - This function records a sessionId to pass into future updates to progress on the same video
493
493
  * @param {int} instrumentId - enum value of instrument id
494
494
  * @param {int} categoryId - enum value of category id
495
- * @param {object|null} collection - optional collection info { type: 'learning-path', id: 123 }
495
+ * @param {object|null} collection - optional collection info { type: 'learning-path-v2', id: 123 }
496
496
  */
497
497
  // NOTE: have not set up collection because its not super important for testing and this will change soon with watermelon
498
498
  export async function recordWatchSession(
@@ -507,7 +507,7 @@ export async function recordWatchSession(
507
507
  categoryId = null,
508
508
  collection = null
509
509
  ) {
510
- if (collection && collection.type === 'learning-path') {
510
+ if (collection && collection.type === 'learning-path-v2') {
511
511
  console.log('Learning Path lesson watch sessions are not set up yet without watermelon')
512
512
  return sessionId
513
513
  }
@@ -640,7 +640,7 @@ function extractContentIdFromRecordKey(key) {
640
640
  }
641
641
 
642
642
  async function getContentHierarchy(contentId, collection = null) {
643
- if (collection && collection.type === 'learning-path') {
643
+ if (collection && collection.type === 'learning-path-v2') {
644
644
  return fetchMethodV2StructureFromId(contentId)
645
645
  }
646
646
  return await fetchHierarchy(contentId)
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -490,7 +490,10 @@ export async function fetchByRailContentIds(
490
490
  }
491
491
  return results.map(liveProcess)
492
492
  }
493
- const results = await fetchSanity(query, true, { customPostProcess: customPostProcess, processNeedAccess: true })
493
+ const results = await fetchSanity(query, true, {
494
+ customPostProcess: customPostProcess,
495
+ processNeedAccess: true,
496
+ })
494
497
 
495
498
  const sortFuction = function compare(a, b) {
496
499
  const indexA = ids.indexOf(a['id'])
@@ -510,8 +513,14 @@ export async function fetchContentRows(brand, pageName, contentRowSlug) {
510
513
  if (pageName === 'lessons') pageName = 'lesson'
511
514
  if (pageName === 'songs') pageName = 'song'
512
515
  const rowString = contentRowSlug ? ` && slug.current == "${contentRowSlug.toLowerCase()}"` : ''
513
- const lessonCountFilter = await new FilterBuilder(`_id in ^.child[]._ref`, {pullFutureContent: true, showMembershipRestrictedContent: true}).buildFilter()
514
- const childFilter = await new FilterBuilder('', {isChildrenFilter: true, showMembershipRestrictedContent: true}).buildFilter()
516
+ const lessonCountFilter = await new FilterBuilder(`_id in ^.child[]._ref`, {
517
+ pullFutureContent: true,
518
+ showMembershipRestrictedContent: true,
519
+ }).buildFilter()
520
+ const childFilter = await new FilterBuilder('', {
521
+ isChildrenFilter: true,
522
+ showMembershipRestrictedContent: true,
523
+ }).buildFilter()
515
524
  const query = `*[_type == 'recommended-content-row' && brand == '${brand}' && type == '${pageName}'${rowString}]{
516
525
  brand,
517
526
  name,
@@ -524,7 +533,7 @@ export async function fetchContentRows(brand, pageName, contentRowSlug) {
524
533
  'lesson_count': coalesce(count(*[${lessonCountFilter}]), 0),
525
534
  },
526
535
  }`
527
- return fetchSanity(query, true, {processNeedAccess: true})
536
+ return fetchSanity(query, true, { processNeedAccess: true })
528
537
  }
529
538
 
530
539
  /**
@@ -1084,7 +1093,11 @@ export async function jumpToContinueContent(railcontentId) {
1084
1093
  * .catch(error => console.error(error));
1085
1094
  */
1086
1095
  export async function fetchLessonContent(railContentId, { addParent = false } = {}) {
1087
- const filterParams = { isSingle: true, pullFutureContent: true, showMembershipRestrictedContent: true }
1096
+ const filterParams = {
1097
+ isSingle: true,
1098
+ pullFutureContent: true,
1099
+ showMembershipRestrictedContent: true,
1100
+ }
1088
1101
 
1089
1102
  const parentQuery = addParent
1090
1103
  ? `"parent_content_data": *[railcontent_id in [...(^.parent_content_data[].id)]]{
@@ -1236,20 +1249,20 @@ async function fetchRelatedByLicense(railcontentId, brand, onlyUseSongTypes, cou
1236
1249
  export async function fetchSiblingContent(railContentId, brand = null) {
1237
1250
  const filterGetParent = await new FilterBuilder(`references(^._id) && _type == ^.parent_type`, {
1238
1251
  pullFutureContent: true,
1239
- showMembershipRestrictedContent: true // Show parent even without permissions
1252
+ showMembershipRestrictedContent: true, // Show parent even without permissions
1240
1253
  }).buildFilter()
1241
1254
  const filterForParentList = await new FilterBuilder(
1242
1255
  `references(^._id) && _type == ^.parent_type`,
1243
1256
  {
1244
1257
  pullFutureContent: true,
1245
1258
  isParentFilter: true,
1246
- showMembershipRestrictedContent: true // Show parent even without permissions
1259
+ showMembershipRestrictedContent: true, // Show parent even without permissions
1247
1260
  }
1248
1261
  ).buildFilter()
1249
1262
 
1250
1263
  const childrenFilter = await new FilterBuilder(``, {
1251
1264
  isChildrenFilter: true,
1252
- showMembershipRestrictedContent: true // Show all lessons in sidebar, need_access applied on individual page
1265
+ showMembershipRestrictedContent: true, // Show all lessons in sidebar, need_access applied on individual page
1253
1266
  }).buildFilter()
1254
1267
 
1255
1268
  const brandString = brand ? ` && brand == "${brand}"` : ''
@@ -1480,35 +1493,34 @@ export async function fetchByReference(
1480
1493
  return fetchSanity(query, true)
1481
1494
  }
1482
1495
 
1496
+ /**
1497
+ *
1498
+ * Return the top level parent content railcontent_id.
1499
+ * Ignores learning-path-v2 parents.
1500
+ * ex: if railcontentId is of type 'skill-pack-lesson', return the corresponding 'skill-pack' railcontent_id
1501
+ *
1502
+ * @param {int} railcontentId
1503
+ * @returns {Promise<int|null>}
1504
+ */
1483
1505
  export async function fetchTopLevelParentId(railcontentId) {
1506
+ const parentFilter = "railcontent_id in [...(^.parent_content_data[].id)]"
1484
1507
  const statusFilter = "&& status in ['scheduled', 'published', 'archived', 'unlisted']"
1485
1508
 
1486
1509
  const query = `*[railcontent_id == ${railcontentId}]{
1487
1510
  railcontent_id,
1488
- 'parents': *[^._id in child[]._ref ${statusFilter}]{
1489
- railcontent_id,
1490
- 'parents': *[^._id in child[]._ref ${statusFilter}]{
1491
- railcontent_id,
1492
- 'parents': *[^._id in child[]._ref ${statusFilter}]{
1493
- railcontent_id,
1494
- 'parents': *[^._id in child[]._ref ${statusFilter}]{
1495
- railcontent_id,
1496
- }
1497
- }
1498
- }
1511
+ 'parents': *[${parentFilter} ${statusFilter}]{
1512
+ railcontent_id
1499
1513
  }
1500
1514
  }`
1501
1515
  let response = await fetchSanity(query, false, { processNeedAccess: false })
1502
1516
  if (!response) return null
1503
- let currentLevel = response
1504
- for (let i = 0; i < 4; i++) {
1505
- if (currentLevel['parents'].length > 0) {
1506
- currentLevel = currentLevel['parents'][0]
1507
- } else {
1508
- return currentLevel['railcontent_id']
1509
- }
1517
+ let parents = response['parents']
1518
+ let parentsLength = parents ? response['parents'].length : 0
1519
+ if (parentsLength > 0) {
1520
+ // return the last parent
1521
+ return parents[parentsLength - 1]['railcontent_id']
1510
1522
  }
1511
- return null
1523
+ return response['railcontent_id']
1512
1524
  }
1513
1525
 
1514
1526
  export async function fetchHierarchy(railcontentId) {
@@ -1656,12 +1668,8 @@ export async function fetchSanity(
1656
1668
  if (!results) {
1657
1669
  throw new Error('No results found')
1658
1670
  }
1659
- results = processNeedAccess
1660
- ? await needsAccessDecorator(results, userPermissions)
1661
- : results
1662
- results = processPageType
1663
- ? pageTypeDecorator(results)
1664
- : results
1671
+ results = processNeedAccess ? await needsAccessDecorator(results, userPermissions) : results
1672
+ results = processPageType ? pageTypeDecorator(results) : results
1665
1673
  return customPostProcess ? customPostProcess(results) : results
1666
1674
  } else {
1667
1675
  throw new Error('No results found')
@@ -1715,7 +1723,6 @@ function pageTypeDecorator(results) {
1715
1723
  })
1716
1724
  }
1717
1725
 
1718
-
1719
1726
  function needsAccessDecorator(results, userPermissions) {
1720
1727
  if (globalConfig.sanityConfig.useDummyRailContentMethods) return results
1721
1728
  const adapter = getPermissionsAdapter()
@@ -2037,7 +2044,10 @@ export async function fetchTabData(
2037
2044
  let filter = ''
2038
2045
 
2039
2046
  filter = `brand == "${brand}" && (defined(railcontent_id)) ${includedFieldsFilter} ${progressFilter}`
2040
- const childrenFilter = await new FilterBuilder(``, { isChildrenFilter: true, showMembershipRestrictedContent: true }).buildFilter()
2047
+ const childrenFilter = await new FilterBuilder(``, {
2048
+ isChildrenFilter: true,
2049
+ showMembershipRestrictedContent: true,
2050
+ }).buildFilter()
2041
2051
  const childrenFields = await getChildFieldsForContentType('tab-data')
2042
2052
  const lessonCountFilter = await new FilterBuilder(`_id in ^.child[]._ref`).buildFilter()
2043
2053
  entityFieldsString = ` ${fieldsString}
@@ -2052,14 +2062,16 @@ export async function fetchTabData(
2052
2062
  ),
2053
2063
  length_in_seconds
2054
2064
  ),`
2055
- const filterWithRestrictions = await new FilterBuilder(filter, {showMembershipRestrictedContent: true}).buildFilter()
2065
+ const filterWithRestrictions = await new FilterBuilder(filter, {
2066
+ showMembershipRestrictedContent: true,
2067
+ }).buildFilter()
2056
2068
  query = buildEntityAndTotalQuery(filterWithRestrictions, entityFieldsString, {
2057
2069
  sortOrder: sortOrder,
2058
2070
  start: start,
2059
2071
  end: end,
2060
2072
  })
2061
2073
 
2062
- let results = await fetchSanity(query, true, {processNeedAccess: true});
2074
+ let results = await fetchSanity(query, true, { processNeedAccess: true })
2063
2075
 
2064
2076
  if (['recent', 'incomplete', 'completed'].includes(progress) && results.entity.length > 1) {
2065
2077
  const orderMap = new Map(progressIds.map((id, index) => [id, index]))
@@ -2203,12 +2215,7 @@ export async function fetchMethodV2StructureFromId(contentId) {
2203
2215
  */
2204
2216
  export async function fetchOwnedContent(
2205
2217
  brand,
2206
- {
2207
- type = [],
2208
- page = 1,
2209
- limit = 10,
2210
- sort = '-published_on',
2211
- } = {}
2218
+ { type = [], page = 1, limit = 10, sort = '-published_on' } = {}
2212
2219
  ) {
2213
2220
  const start = (page - 1) * limit
2214
2221
  const end = start + limit
@@ -2219,7 +2226,7 @@ export async function fetchOwnedContent(
2219
2226
  // Build the type filter
2220
2227
  let typeFilter = ''
2221
2228
  if (type.length > 0) {
2222
- const typesString = type.map(t => `'${t}'`).join(', ')
2229
+ const typesString = type.map((t) => `'${t}'`).join(', ')
2223
2230
  typeFilter = `&& _type in [${typesString}]`
2224
2231
  }
2225
2232
 
@@ -2228,7 +2235,7 @@ export async function fetchOwnedContent(
2228
2235
 
2229
2236
  // Apply owned content filter
2230
2237
  const filterWithRestrictions = await new FilterBuilder(filter, {
2231
- showOnlyOwnedContent: true, // Key parameter: exclude membership content
2238
+ showOnlyOwnedContent: true, // Key parameter: exclude membership content
2232
2239
  }).buildFilter()
2233
2240
 
2234
2241
  const fieldsString = DEFAULT_FIELDS.join(',')
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -2,6 +2,7 @@
2
2
  * @module Onboarding
3
3
  */
4
4
  import { HttpClient } from '../../infrastructure/http/HttpClient'
5
+ import { Brand } from '../../lib/brands'
5
6
  import { globalConfig } from '../config.js'
6
7
 
7
8
  export interface OnboardingSteps {
@@ -131,17 +132,107 @@ export interface OnboardingRecommendedContent {
131
132
  }
132
133
  }
133
134
 
135
+ const recommendedContentCache: { [brand: string]: OnboardingRecommendedContent } = {
136
+ drumeo: {
137
+ id: 391995,
138
+ title: 'Getting Started On The Drums',
139
+ difficulty: 'Beginner',
140
+ lesson_count: 12,
141
+ skill_count: 1,
142
+ badge: 'https://cdn.sanity.io/files/4032r8py/staging/drumeo_badge.png',
143
+ description:
144
+ 'Start your drumming journey with essential techniques and rhythms to get you playing quickly.',
145
+ video: {
146
+ external_id: '1002267396',
147
+ hlsManifestUrl:
148
+ 'https://player.vimeo.com/external/1002267396.m3u8?s=abcdef1234567890abcdef1234567890abcdef12&oauth2_token_id=1284792284',
149
+ type: 'vimeo-video',
150
+ },
151
+ },
152
+ pianote: {
153
+ id: 412405,
154
+ title: 'Getting Started On The Piano',
155
+ difficulty: 'Beginner',
156
+ lesson_count: 4,
157
+ skill_count: 3,
158
+ badge:
159
+ 'https://cdn.sanity.io/files/4032r8py/staging/9470587f03479b7c1f8019c3cbcbdfe12aa267f3.png',
160
+ description:
161
+ 'The goal of this course is to introduce you to the keys, and get you playing a song as fast as possible. ',
162
+ video: {
163
+ external_id: '1001267395',
164
+ hlsManifestUrl:
165
+ 'https://player.vimeo.com/external/1001267395.m3u8?s=8f8d8a8a762f688058e6e6fd6704c402baf1b797&oauth2_token_id=1284792283',
166
+ type: 'vimeo-video',
167
+ },
168
+ },
169
+ guitareo: {
170
+ id: 294635,
171
+ title: 'Getting Started On The Acoustic Guitar',
172
+ difficulty: 'Beginner',
173
+ lesson_count: 6,
174
+ skill_count: 5,
175
+ badge: 'https://cdn.sanity.io/files/4032r8py/staging/guitareo_badge.png',
176
+ description:
177
+ 'New to the acoustic guitar? Then this Course is for you! Learn everything you need to get started on the acoustic guitar, and start playing music as fast as possible!',
178
+ video: {
179
+ external_id: '1003267397',
180
+ hlsManifestUrl:
181
+ 'https://player.vimeo.com/external/1003267397.m3u8?s=1234567890abcdef1234567890abcdef12345678&oauth2_token_id=1284792285',
182
+ type: 'vimeo-video',
183
+ },
184
+ },
185
+ singeo: {
186
+ id: 712408,
187
+ title: 'Singing Starter Kit',
188
+ difficulty: 'Beginner',
189
+ lesson_count: 5,
190
+ skill_count: 4,
191
+ badge: 'https://cdn.sanity.io/files/4032r8py/staging/singeo_badge.png',
192
+ description:
193
+ 'Welcome to the Singing Starter Kit! This course will teach you everything you need to know to sound better when you sing! You will learn how your unique voice works so that you can develop vocal strength, accurate pitch, and find confidence singing your favorite songs. You can sing, and the Singing Starter Kit is the perfect way to start your singing journey.',
194
+ video: {
195
+ external_id: '1004267398',
196
+ hlsManifestUrl:
197
+ 'https://player.vimeo.com/external/1004267398.m3u8?s=fedcba0987654321fedcba0987654321fedcba09&oauth2_token_id=1284792286',
198
+ type: 'vimeo-video',
199
+ },
200
+ },
201
+ playbass: {
202
+ id: 294635,
203
+ title: 'Getting Started On The Acoustic Guitar',
204
+ difficulty: 'Beginner',
205
+ lesson_count: 6,
206
+ skill_count: 5,
207
+ badge: 'https://cdn.sanity.io/files/4032r8py/staging/guitareo_badge.png',
208
+ description:
209
+ 'New to the acoustic guitar? Then this Course is for you! Learn everything you need to get started on the acoustic guitar, and start playing music as fast as possible!',
210
+ video: {
211
+ external_id: '1003267397',
212
+ hlsManifestUrl:
213
+ 'https://player.vimeo.com/external/1003267397.m3u8?s=1234567890abcdef1234567890abcdef12345678&oauth2_token_id=1284792285',
214
+ type: 'vimeo-video',
215
+ },
216
+ },
217
+ }
218
+
134
219
  /**
135
220
  * Fetches recommended content for onboarding based on the specified brand.
136
221
  *
137
- * @param {string} brand - The brand identifier.
222
+ * @param {string} email - The user's email address.
223
+ * @param {Brand} brand - The brand identifier.
138
224
  * @returns {Promise<OnboardingRecommendedContent>} - A promise that resolves with the recommended content.
139
225
  * @throws {HttpError} - If the HTTP request fails.
140
226
  */
141
227
  export async function getOnboardingRecommendedContent(
142
- brand: string
228
+ email: string,
229
+ brand: Brand
143
230
  ): Promise<OnboardingRecommendedContent> {
144
231
  // TODO: Replace with real API call when available
232
+ if (recommendedContentCache[brand]) {
233
+ return recommendedContentCache[brand]
234
+ }
235
+
145
236
  return {
146
237
  id: 412405,
147
238
  title: 'Getting Started On The Piano',
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -1347,7 +1347,7 @@ function mergeAndSortItems(items, limit) {
1347
1347
 
1348
1348
  export function findIncompleteLesson(progressOnItems, currentContentId, contentType) {
1349
1349
  const ids = Object.keys(progressOnItems).map(Number)
1350
- if (contentType === 'guided-course' || contentType === 'learning-path') {
1350
+ if (contentType === 'guided-course' || contentType === 'learning-path-v2') {
1351
1351
  // Return first incomplete lesson
1352
1352
  return ids.find((id) => progressOnItems[id] !== 'completed') || ids.at(0)
1353
1353
  }
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
package/test/log.js CHANGED
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -1,14 +0,0 @@
1
- {
2
- "permissions": {
3
- "allow": [
4
- "Read(//app/musora-platform-backend/**)",
5
- "Read(//app/musora-platform-frontend/**)",
6
- "Bash(find:*)",
7
- "Bash(sed:*)",
8
- "Read(//app/**)",
9
- "Bash(cat:*)"
10
- ],
11
- "deny": [],
12
- "ask": []
13
- }
14
- }
package/.yarnrc.yml DELETED
@@ -1 +0,0 @@
1
- nodeLinker: node-modules