musora-content-services 2.93.1 → 2.93.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,9 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(rg:*)",
5
+ "Bash(npm run lint:*)"
6
+ ],
7
+ "deny": []
8
+ }
9
+ }
package/CHANGELOG.md CHANGED
@@ -2,6 +2,13 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
4
 
5
+ ### [2.93.2](https://github.com/railroadmedia/musora-content-services/compare/v2.93.1...v2.93.2) (2025-12-02)
6
+
7
+
8
+ ### Bug Fixes
9
+
10
+ * progress fixes and features with watermelon ([#607](https://github.com/railroadmedia/musora-content-services/issues/607)) ([005403c](https://github.com/railroadmedia/musora-content-services/commit/005403c9bbaeebe8c5ecb5315754de4448bcbf43))
11
+
5
12
  ### [2.93.1](https://github.com/railroadmedia/musora-content-services/compare/v2.93.0...v2.93.1) (2025-12-02)
6
13
 
7
14
  ## [2.93.0](https://github.com/railroadmedia/musora-content-services/compare/v2.92.7...v2.93.0) (2025-12-02)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "musora-content-services",
3
- "version": "2.93.1",
3
+ "version": "2.93.2",
4
4
  "description": "A package for Musoras content services ",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
package/src/index.d.ts CHANGED
@@ -91,6 +91,7 @@ import {
91
91
  contentStatusCompleted,
92
92
  contentStatusReset,
93
93
  contentStatusStarted,
94
+ contentsStatusCompleted,
94
95
  getAllCompleted,
95
96
  getAllCompletedByIds,
96
97
  getAllStarted,
@@ -250,6 +251,7 @@ import {
250
251
  fetchContentRows,
251
252
  fetchFoundation,
252
253
  fetchHierarchy,
254
+ fetchLearningPathHierarchy,
253
255
  fetchLeaving,
254
256
  fetchLessonContent,
255
257
  fetchLessonsFeaturingThisContent,
@@ -428,6 +430,7 @@ declare module 'musora-content-services' {
428
430
  contentStatusCompleted,
429
431
  contentStatusReset,
430
432
  contentStatusStarted,
433
+ contentsStatusCompleted,
431
434
  convertToTimeZone,
432
435
  createComment,
433
436
  createForumCategory,
@@ -494,6 +497,7 @@ declare module 'musora-content-services' {
494
497
  fetchInterests,
495
498
  fetchLastInteractedChild,
496
499
  fetchLatestThreads,
500
+ fetchLearningPathHierarchy,
497
501
  fetchLearningPathLessons,
498
502
  fetchLearningPathProgressCheckLessons,
499
503
  fetchLeaving,
package/src/index.js CHANGED
@@ -95,6 +95,7 @@ import {
95
95
  contentStatusCompleted,
96
96
  contentStatusReset,
97
97
  contentStatusStarted,
98
+ contentsStatusCompleted,
98
99
  getAllCompleted,
99
100
  getAllCompletedByIds,
100
101
  getAllStarted,
@@ -254,6 +255,7 @@ import {
254
255
  fetchContentRows,
255
256
  fetchFoundation,
256
257
  fetchHierarchy,
258
+ fetchLearningPathHierarchy,
257
259
  fetchLeaving,
258
260
  fetchLessonContent,
259
261
  fetchLessonsFeaturingThisContent,
@@ -427,6 +429,7 @@ export {
427
429
  contentStatusCompleted,
428
430
  contentStatusReset,
429
431
  contentStatusStarted,
432
+ contentsStatusCompleted,
430
433
  convertToTimeZone,
431
434
  createComment,
432
435
  createForumCategory,
@@ -493,6 +496,7 @@ export {
493
496
  fetchInterests,
494
497
  fetchLastInteractedChild,
495
498
  fetchLatestThreads,
499
+ fetchLearningPathHierarchy,
496
500
  fetchLearningPathLessons,
497
501
  fetchLearningPathProgressCheckLessons,
498
502
  fetchLeaving,
@@ -7,11 +7,14 @@ import { fetchByRailContentId, fetchMethodV2Structure } from '../sanity.js'
7
7
  import { addContextToContent } from '../contentAggregator.js'
8
8
  import {
9
9
  contentStatusCompleted,
10
+ contentsStatusCompleted,
10
11
  contentStatusReset,
11
12
  getAllCompletedByIds,
12
13
  getProgressState,
13
14
  } from '../contentProgress.js'
14
- import { STATE } from '../sync/models/ContentProgress'
15
+ import { COLLECTION_TYPE, STATE } from "../sync/models/ContentProgress";
16
+ import { SyncWriteDTO } from "../sync";
17
+ import { ContentProgress } from "../sync/models";
15
18
 
16
19
  const BASE_PATH: string = `/api/content-org`
17
20
  const LEARNING_PATHS_PATH = `${BASE_PATH}/v1/user/learning-paths`
@@ -22,6 +25,20 @@ interface ActiveLearningPathResponse {
22
25
  active_learning_path_id: number,
23
26
  }
24
27
 
28
+ interface DailySessionResponse {
29
+ user_id: number,
30
+ brand: string,
31
+ user_date: string
32
+ daily_session: DailySession[],
33
+ active_learning_path_id: number,
34
+ active_learning_path_created_at: string,
35
+ }
36
+
37
+ interface DailySession {
38
+ content_ids: number[],
39
+ learning_path_id: number,
40
+ }
41
+
25
42
  /**
26
43
  * Gets today's daily session for the user.
27
44
  * @param brand
@@ -30,7 +47,7 @@ interface ActiveLearningPathResponse {
30
47
  export async function getDailySession(brand: string, userDate: Date) {
31
48
  const stringDate = userDate.toISOString().split('T')[0]
32
49
  const url: string = `${LEARNING_PATHS_PATH}/daily-session/get?brand=${brand}&userDate=${stringDate}`
33
- return await fetchHandler(url, 'GET', null, null)
50
+ return await fetchHandler(url, 'GET', null, null) as DailySessionResponse
34
51
  }
35
52
 
36
53
  /**
@@ -47,7 +64,7 @@ export async function updateDailySession(
47
64
  const stringDate = userDate.toISOString().split('T')[0]
48
65
  const url: string = `${LEARNING_PATHS_PATH}/daily-session/create`
49
66
  const body = { brand: brand, userDate: stringDate, keepFirstLearningPath: keepFirstLearningPath }
50
- return await fetchHandler(url, 'POST', null, body)
67
+ return await fetchHandler(url, 'POST', null, body) as DailySessionResponse
51
68
  }
52
69
 
53
70
  /**
@@ -56,7 +73,7 @@ export async function updateDailySession(
56
73
  */
57
74
  export async function getActivePath(brand: string) {
58
75
  const url: string = `${LEARNING_PATHS_PATH}/active-path/get?brand=${brand}`
59
- return await fetchHandler(url, 'GET', null, null)
76
+ return await fetchHandler(url, 'GET', null, null) as ActiveLearningPathResponse
60
77
  }
61
78
 
62
79
  /**
@@ -67,7 +84,7 @@ export async function getActivePath(brand: string) {
67
84
  export async function startLearningPath(brand: string, learningPathId: number) {
68
85
  const url: string = `${LEARNING_PATHS_PATH}/active-path/set`
69
86
  const body = { brand: brand, learning_path_id: learningPathId }
70
- return await fetchHandler(url, 'POST', null, body)
87
+ return await fetchHandler(url, 'POST', null, body) as ActiveLearningPathResponse
71
88
  }
72
89
 
73
90
  /**
@@ -87,9 +104,9 @@ export async function getEnrichedLearningPath(learningPathId) {
87
104
  const response = (await addContextToContent(
88
105
  fetchByRailContentId,
89
106
  learningPathId,
90
- 'learning-path-v2',
107
+ COLLECTION_TYPE.LEARNING_PATH,
91
108
  {
92
- collection: { id: learningPathId, type: 'learning-path-v2' },
109
+ collection: { id: learningPathId, type: COLLECTION_TYPE.LEARNING_PATH },
93
110
  dataField: 'children',
94
111
  dataField_includeParent: true,
95
112
  addProgressStatus: true,
@@ -241,7 +258,7 @@ export async function fetchLearningPathProgressCheckLessons(contentIds: number[]
241
258
  }
242
259
 
243
260
  interface completeMethodIntroVideo {
244
- intro_video_response: Object | null,
261
+ intro_video_response: SyncWriteDTO<ContentProgress, any> | null,
245
262
  active_path_response: ActiveLearningPathResponse
246
263
  }
247
264
  /**
@@ -267,9 +284,9 @@ export async function completeMethodIntroVideo(introVideoId: number, brand: stri
267
284
  }
268
285
 
269
286
  interface completeLearningPathIntroVideo {
270
- intro_video_response: Object | null,
271
- learning_path_reset_response: void | null,
272
- lesson_import_response: Object | null
287
+ intro_video_response: SyncWriteDTO<ContentProgress, any> | null,
288
+ learning_path_reset_response: SyncWriteDTO<ContentProgress, any> | null,
289
+ lesson_import_response: SyncWriteDTO<ContentProgress, any> | null
273
290
  }
274
291
  /**
275
292
  * Handles completion of learning path intro video and other related actions.
@@ -286,24 +303,20 @@ export async function completeLearningPathIntroVideo(introVideoId: number, learn
286
303
 
287
304
  response.intro_video_response = await completeIfNotCompleted(introVideoId)
288
305
 
289
- const collection = { id: learningPathId, type: 'learning-path-v2' }
306
+ const collection = { id: learningPathId, type: COLLECTION_TYPE.LEARNING_PATH }
290
307
 
291
308
  if (!lessonsToImport) {
292
309
  response.learning_path_reset_response = await contentStatusReset(learningPathId, collection)
293
310
 
294
311
  } else {
295
- response.lesson_import_response = {}
296
- for (const contentId of lessonsToImport) {
297
- // todo: create bulk complete endpoint with bubbling. and set up watermelon method bubbling
298
- response.lesson_import_response[contentId] = await contentStatusCompleted(contentId, collection)
299
- }
312
+ response.lesson_import_response = await contentsStatusCompleted(lessonsToImport, collection)
300
313
  }
301
314
 
302
315
  return response
303
316
  }
304
317
 
305
318
 
306
- async function completeIfNotCompleted(contentId: number): Promise<Object | null> {
319
+ async function completeIfNotCompleted(contentId: number): Promise<SyncWriteDTO<ContentProgress, any> | null> {
307
320
  const introVideoStatus = await getProgressState(contentId)
308
321
 
309
322
  return introVideoStatus !== 'completed' ? await contentStatusCompleted(contentId) : null
@@ -1,6 +1,6 @@
1
- import { fetchHierarchy } from './sanity.js'
1
+ import { fetchHierarchy, fetchLearningPathHierarchy } from './sanity.js'
2
2
  import { db } from './sync'
3
- import { STATE } from './sync/models/ContentProgress'
3
+ import {COLLECTION_TYPE, STATE} from './sync/models/ContentProgress'
4
4
  import { trackUserPractice, findIncompleteLesson } from './userActivity'
5
5
  import { getNextLessonLessonParentTypes } from '../contentTypeConfig.js'
6
6
 
@@ -66,7 +66,7 @@ export async function getNavigateTo(data, collection = null) {
66
66
  let incompleteChild = findIncompleteLesson(childrenStates, lastInteracted, content.type)
67
67
  navigateToData[content.id] = buildNavigateTo(children.get(incompleteChild), null, collection)
68
68
  }
69
- } else if (['song-tutorial', 'guided-course', 'learning-path-v2'].includes(content.type)) { // send to first incomplete
69
+ } else if (['song-tutorial', 'guided-course', COLLECTION_TYPE.LEARNING_PATH].includes(content.type)) { // send to first incomplete
70
70
  let incompleteChild = findIncompleteLesson(childrenStates, lastInteracted, content.type)
71
71
  navigateToData[content.id] = buildNavigateTo(children.get(incompleteChild), null, collection)
72
72
  } else if (twoDepthContentTypes.includes(content.type)) { // send to navigateTo child of last interacted child
@@ -268,6 +268,11 @@ async function trackProgress(contentId, collection, currentSeconds, mediaLengthS
268
268
  export async function contentStatusCompleted(contentId, collection = null) {
269
269
  return setStartedOrCompletedStatus(contentId, collection, true)
270
270
  }
271
+
272
+ export async function contentsStatusCompleted(contentIds, collection = null) {
273
+ return setStartedOrCompletedStatuses(contentIds, collection, true)
274
+ }
275
+
271
276
  export async function contentStatusStarted(contentId, collection = null) {
272
277
  return setStartedOrCompletedStatus(contentId, collection, false)
273
278
  }
@@ -276,12 +281,12 @@ export async function contentStatusReset(contentId, collection = null) {
276
281
  }
277
282
 
278
283
  async function saveContentProgress(contentId, collection, progress, currentSeconds) {
279
- const response = await db.contentProgress.recordProgressRemotely(contentId, collection, progress, currentSeconds)
284
+ const response = await db.contentProgress.recordProgress(contentId, collection, progress, currentSeconds)
280
285
 
281
286
  // note - previous implementation explicitly did not trickle progress to children here
282
287
  // (only to siblings/parents via le bubbles)
283
288
 
284
- const bubbledProgresses = bubbleProgress(await fetchHierarchy(contentId), contentId, collection)
289
+ const bubbledProgresses = bubbleProgress(await getHierarchy(contentId, collection), contentId, collection)
285
290
  await db.contentProgress.recordProgressesTentative(bubbledProgresses, collection)
286
291
 
287
292
  return response
@@ -292,23 +297,55 @@ async function setStartedOrCompletedStatus(contentId, collection, isCompleted) {
292
297
  // we explicitly pessimistically await a remote push here
293
298
  // because awards may be generated (on server) on completion
294
299
  // which we would want to toast the user about *in band*
295
- const response = await db.contentProgress.recordProgressRemotely(contentId, collection, progress)
300
+ const response = await db.contentProgress.recordProgress(contentId, collection, progress)
301
+
302
+ const hierarchy = await getHierarchy(contentId, collection)
303
+
304
+ await Promise.all([
305
+ db.contentProgress.recordProgressesTentative(trickleProgress(hierarchy, contentId, collection, progress), collection),
306
+ bubbleProgress(hierarchy, contentId, collection).then(bubbledProgresses => db.contentProgress.recordProgressesTentative(bubbledProgresses, collection))
307
+ ])
296
308
 
297
- if (response.pushStatus === 'success') {
298
- const hierarchy = await fetchHierarchy(contentId)
309
+ return response
310
+ }
299
311
 
300
- await Promise.all([
301
- db.contentProgress.recordProgressesTentative(trickleProgress(hierarchy, contentId, collection, progress), collection),
302
- bubbleProgress(hierarchy, contentId, collection).then(bubbledProgresses => db.contentProgress.recordProgressesTentative(bubbledProgresses, collection))
303
- ])
312
+ async function getHierarchy(contentId, collection) {
313
+ if (collection && collection.type === COLLECTION_TYPE.LEARNING_PATH) {
314
+ return await fetchLearningPathHierarchy(contentId, collection)
315
+ } else {
316
+ return await fetchHierarchy(contentId)
304
317
  }
318
+ }
319
+
320
+ async function setStartedOrCompletedStatuses(contentIds, collection, isCompleted) {
321
+ const progress = isCompleted ? 100 : 0
322
+ // we explicitly pessimistically await a remote push here
323
+ // because awards may be generated (on server) on completion
324
+ // which we would want to toast the user about *in band*
325
+ const response = await db.contentProgress.recordProgresses(contentIds, collection, progress)
326
+
327
+ // we assume this is used only for contents within the same hierarchy
328
+ const hierarchy = await getHierarchy(contentIds[0], collection)
329
+
330
+ let ids = {}
331
+ for (const contentId of contentIds) {
332
+ ids = {
333
+ ...ids,
334
+ ...trickleProgress(hierarchy, contentId, collection, progress),
335
+ ...await bubbleProgress(hierarchy, contentId, collection)
336
+ }
337
+ }
338
+
339
+ await Promise.all([
340
+ db.contentProgress.recordProgressesTentative(ids, collection),
341
+ ]);
305
342
 
306
343
  return response
307
344
  }
308
345
 
309
346
  async function resetStatus(contentId, collection = null) {
310
347
  const response = await db.contentProgress.eraseProgress(contentId, collection)
311
- const hierarchy = await fetchHierarchy(contentId)
348
+ const hierarchy = await getHierarchy(contentId, collection)
312
349
 
313
350
  await Promise.all([
314
351
  db.contentProgress.recordProgressesTentative(trickleProgress(hierarchy, contentId, collection, 0), collection),
@@ -6,6 +6,7 @@ import { getActivePath, fetchLearningPathLessons } from '../content-org/learning
6
6
  import { getToday } from '../dateUtils.js'
7
7
  import { fetchMethodV2IntroVideo } from '../sanity'
8
8
  import { getProgressState } from '../contentProgress'
9
+ import {COLLECTION_TYPE} from "../sync/models/ContentProgress.js";
9
10
 
10
11
  export async function getMethodCard(brand) {
11
12
  const introVideo = await fetchMethodV2IntroVideo(brand)
@@ -82,7 +83,7 @@ export async function getMethodCard(brand) {
82
83
 
83
84
  return {
84
85
  id: 1,
85
- type: 'learning-path-v2',
86
+ type: COLLECTION_TYPE.LEARNING_PATH,
86
87
  progressType: 'method',
87
88
  header: 'Method',
88
89
  body: learningPath,
@@ -1523,6 +1523,25 @@ export async function fetchTopLevelParentId(railcontentId) {
1523
1523
  return response['railcontent_id']
1524
1524
  }
1525
1525
 
1526
+ export async function fetchLearningPathHierarchy(railcontentId, collection) {
1527
+ if (!collection) {
1528
+ return null
1529
+ }
1530
+
1531
+ const topLevelId = collection.id
1532
+
1533
+ let response = await fetchByRailContentId(topLevelId, collection.type)
1534
+ if (!response) return null
1535
+
1536
+ let data = {
1537
+ topLevelId: topLevelId,
1538
+ parents: {},
1539
+ children: {},
1540
+ }
1541
+ populateHierarchyLookups(response, data, null)
1542
+ return data
1543
+ }
1544
+
1526
1545
  export async function fetchHierarchy(railcontentId) {
1527
1546
  let topLevelId = await fetchTopLevelParentId(railcontentId)
1528
1547
  const childrenFilter = await new FilterBuilder(``, { isChildrenFilter: true }).buildFilter()
@@ -1557,12 +1576,14 @@ export async function fetchHierarchy(railcontentId) {
1557
1576
  }
1558
1577
 
1559
1578
  function populateHierarchyLookups(currentLevel, data, parentId) {
1560
- let contentId = currentLevel['railcontent_id']
1579
+ const railcontentIdField = currentLevel.railcontent_id ? "railcontent_id" : "id";
1580
+
1581
+ let contentId = currentLevel[railcontentIdField]
1561
1582
  let children = currentLevel['children']
1562
1583
 
1563
1584
  data.parents[contentId] = parentId
1564
1585
  if (children) {
1565
- data.children[contentId] = children.map((child) => child['railcontent_id'])
1586
+ data.children[contentId] = children.map((child) => child[railcontentIdField])
1566
1587
  for (let i = 0; i < children.length; i++) {
1567
1588
  populateHierarchyLookups(children[i], data, contentId)
1568
1589
  }
@@ -1572,7 +1593,7 @@ function populateHierarchyLookups(currentLevel, data, parentId) {
1572
1593
 
1573
1594
  let assignments = currentLevel['assignments']
1574
1595
  if (assignments) {
1575
- let assignmentIds = assignments.map((assignment) => assignment['railcontent_id'])
1596
+ let assignmentIds = assignments.map((assignment) => assignment[railcontentIdField])
1576
1597
  data.children[contentId] = (data.children[contentId] ?? []).concat(assignmentIds)
1577
1598
  assignmentIds.forEach((assignmentId) => {
1578
1599
  data.parents[assignmentId] = contentId
@@ -3,7 +3,7 @@ import { SYNC_TABLES } from '../schema'
3
3
 
4
4
  export enum COLLECTION_TYPE {
5
5
  SKILL_PACK = 'skill-pack',
6
- LEARNING_PATH = 'learning-path',
6
+ LEARNING_PATH = 'learning-path-v2',
7
7
  PLAYLIST = 'playlist',
8
8
  }
9
9
 
@@ -115,10 +115,10 @@ export default class ProgressRepository extends SyncRepository<ContentProgress>
115
115
  return await this.queryAll(...clauses)
116
116
  }
117
117
 
118
- recordProgressRemotely(contentId: number, collection: { type: COLLECTION_TYPE; id: number } | null, progressPct: number, resumeTime?: number) {
118
+ recordProgress(contentId: number, collection: { type: COLLECTION_TYPE; id: number } | null, progressPct: number, resumeTime?: number) {
119
119
  const id = ProgressRepository.generateId(contentId, collection)
120
120
 
121
- return this.upsertOneRemote(id, (r) => {
121
+ return this.upsertOne(id, (r) => {
122
122
  r.content_id = contentId
123
123
  r.collection_type = collection?.type ?? null
124
124
  r.collection_id = collection?.id ?? null
@@ -132,12 +132,16 @@ export default class ProgressRepository extends SyncRepository<ContentProgress>
132
132
  })
133
133
  }
134
134
 
135
- recordProgressesTentative(contentProgresses: Map<number, number>, collection: { type: COLLECTION_TYPE; id: number } | null) {
136
- return this.upsertSomeTentative(
135
+ recordProgresses(
136
+ contentIds: number[],
137
+ collection: { type: COLLECTION_TYPE; id: number } | null,
138
+ progressPct: number
139
+ ) {
140
+ return this.upsertSome(
137
141
  Object.fromEntries(
138
- Array.from(contentProgresses, ([contentId, progressPct]) => [
139
- ProgressRepository.generateId(contentId, null),
140
- (r) => {
142
+ contentIds.map((contentId) => [
143
+ ProgressRepository.generateId(contentId, collection),
144
+ (r: ContentProgress) => {
141
145
  r.content_id = contentId
142
146
  r.collection_type = collection?.type ?? null
143
147
  r.collection_id = collection?.id ?? null
@@ -150,6 +154,29 @@ export default class ProgressRepository extends SyncRepository<ContentProgress>
150
154
  )
151
155
  }
152
156
 
157
+ recordProgressesTentative(
158
+ contentProgresses: Record<string, number>, // Accept plain object
159
+ collection: { type: COLLECTION_TYPE; id: number } | null
160
+ ) {
161
+ const data = Object.fromEntries(
162
+ Object.entries(contentProgresses).map(([contentId, progressPct]) => {
163
+ const generatedId = ProgressRepository.generateId(Number(contentId), collection)
164
+ console.log('Processing:', { contentId, progressPct, generatedId, collection })
165
+ return [
166
+ generatedId,
167
+ (record: ContentProgress) => {
168
+ record.content_id = Number(contentId)
169
+ record.collection_type = collection?.type ?? null
170
+ record.collection_id = collection?.id ?? null
171
+ record.state = progressPct === 100 ? STATE.COMPLETED : STATE.STARTED
172
+ record.progress_percent = progressPct
173
+ },
174
+ ]
175
+ })
176
+ )
177
+ return this.upsertSomeTentative(data)
178
+ }
179
+
153
180
  eraseProgress(contentId: number, collection: { type: COLLECTION_TYPE; id: number } | null) {
154
181
  return this.deleteOne(ProgressRepository.generateId(contentId, collection))
155
182
  }
@@ -40,6 +40,7 @@ import dayjs from 'dayjs'
40
40
  import { addContextToContent } from './contentAggregator.js'
41
41
  import { getMethodCard } from './progress-row/method-card.js'
42
42
  import { db, Q } from './sync'
43
+ import {COLLECTION_TYPE} from "./sync/models/ContentProgress.js";
43
44
 
44
45
  const DATA_KEY_PRACTICES = 'practices'
45
46
 
@@ -1039,7 +1040,7 @@ export async function getProgressRows({ brand = 'drumeo', limit = 8 } = {}) {
1039
1040
  switch (item.type) {
1040
1041
  case 'playlist':
1041
1042
  return processPlaylistItem(item)
1042
- case 'learning-path-v2':
1043
+ case COLLECTION_TYPE.LEARNING_PATH:
1043
1044
  case 'method':
1044
1045
  return item
1045
1046
  default:
@@ -1282,7 +1283,7 @@ function mergeAndSortItems(items, limit) {
1282
1283
 
1283
1284
  export function findIncompleteLesson(progressOnItems, currentContentId, contentType) {
1284
1285
  const ids = Object.keys(progressOnItems).map(Number)
1285
- if (contentType === 'guided-course' || contentType === 'learning-path-v2') {
1286
+ if (contentType === 'guided-course' || contentType === COLLECTION_TYPE.LEARNING_PATH) {
1286
1287
  // Return first incomplete lesson
1287
1288
  return ids.find((id) => progressOnItems[id] !== 'completed') || ids.at(0)
1288
1289
  }