musora-content-services 2.154.0 → 2.155.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,10 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(rg:*)",
5
+ "Bash(npm run lint:*)",
6
+ "Bash(ls:*)"
7
+ ],
8
+ "deny": []
9
+ }
10
+ }
package/CHANGELOG.md CHANGED
@@ -2,6 +2,15 @@
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.155.0](https://github.com/railroadmedia/musora-content-services/compare/v2.154.0...v2.155.0) (2026-04-22)
6
+
7
+
8
+ ### Features
9
+
10
+ * **BEHSTP-167:** offline progress tracking support ([#889](https://github.com/railroadmedia/musora-content-services/issues/889)) ([0528597](https://github.com/railroadmedia/musora-content-services/commit/05285977237ccbfa577a5770a1762c31d855e59e))
11
+ * handle late-start active paths, and set up better resetAllLearningPaths ([#928](https://github.com/railroadmedia/musora-content-services/issues/928)) ([5d80430](https://github.com/railroadmedia/musora-content-services/commit/5d80430fbedfb21668882d402c5f6b07c82cfbf9))
12
+ * **MU2-1452:** free tier content sort to front ([#915](https://github.com/railroadmedia/musora-content-services/issues/915)) ([0655e68](https://github.com/railroadmedia/musora-content-services/commit/0655e685f32fe77728d7b8c2505283adbc1a7c97))
13
+
5
14
  ## [2.154.0](https://github.com/railroadmedia/musora-content-services/compare/v2.153.0...v2.154.0) (2026-04-21)
6
15
 
7
16
 
package/jsdoc.json CHANGED
@@ -15,6 +15,7 @@
15
15
  "src/services/userActivity.js",
16
16
  "src/services/railcontent.js",
17
17
  "src/services/liveTesting.ts",
18
+ "src/services/offline",
18
19
  "src/services/forums",
19
20
  "src/index.js"
20
21
  ],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "musora-content-services",
3
- "version": "2.154.0",
3
+ "version": "2.155.0",
4
4
  "description": "A package for Musoras content services ",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -99,13 +99,12 @@ export const DEFAULT_CHILD_FIELDS = [
99
99
  `"grandparent_id": ${grandParentReferenceField}->railcontent_id`,
100
100
  ]
101
101
 
102
- export const playAlongMp3sField = `{
103
- 'mp3_no_drums_no_click_url': mp3_no_drums_no_click_url,
104
- 'mp3_no_drums_yes_click_url': mp3_no_drums_yes_click_url,
105
- 'mp3_yes_drums_no_click_url': mp3_yes_drums_no_click_url,
106
- 'mp3_yes_drums_yes_click_url': mp3_yes_drums_yes_click_url,
107
- }
108
- `
102
+ export const playAlongMp3sFields = [
103
+ 'mp3_no_drums_no_click_url',
104
+ 'mp3_no_drums_yes_click_url',
105
+ 'mp3_yes_drums_no_click_url',
106
+ 'mp3_yes_drums_yes_click_url',
107
+ ]
109
108
 
110
109
  export const chapterField = `chapter[]{
111
110
  chapter_description,
@@ -142,25 +141,31 @@ export const assignmentsField = `"assignments":assignment[]{
142
141
  }.url, assignment_sheet_music_image),
143
142
  "timecode": assignment_timecode,
144
143
  "description": coalesce(assignment_description,'')
145
- },`
144
+ }`
146
145
 
147
146
  // todo: refactor live event queries to use this
148
- export const liveFields = `
149
- 'slug': slug.current,
150
- 'id': railcontent_id,
151
- title,
152
- live_event_start_time,
153
- live_event_end_time,
154
- live_event_stream_id,
155
- "live_event_is_global": live_global_event == true,
156
- published_on,
157
- "thumbnail": thumbnail.asset->url,
158
- ${artistOrInstructorName()},
159
- difficulty_string,
160
- railcontent_id,
161
- "instructors": ${instructorField},
162
- 'videoId': coalesce(live_event_stream_id, video.external_id)
163
- `
147
+ export function getLiveFields(minimum = false) {
148
+ const minimumFields = [
149
+ "live_event_start_time",
150
+ "live_event_end_time",
151
+ "live_event_stream_id",
152
+ "'live_event_is_global': live_global_event == true",
153
+ "'videoId': coalesce(live_event_stream_id, video.external_id)",
154
+ ]
155
+ const additionalFields = [
156
+ "'slug': slug.current",
157
+ "'id': railcontent_id",
158
+ "title",
159
+ "published_on",
160
+ "'thumbnail': thumbnail.asset->url",
161
+ `${artistOrInstructorName()}`,
162
+ "difficulty_string",
163
+ "railcontent_id",
164
+ `'instructors': ${instructorField}`,
165
+ ]
166
+
167
+ return minimum ? minimumFields : minimumFields.concat(additionalFields)
168
+ }
164
169
 
165
170
  const contentWithInstructorsField = {
166
171
  fields: ['"instructors": instructor[]->name'],
@@ -175,6 +180,21 @@ const isLiveField = () => {
175
180
  return `"isLive": live_event_start_time <= '${now}' && live_event_end_time >= '${now}'`
176
181
  }
177
182
 
183
+ const pcdForDownloadField = `
184
+ "parent_content_data": parent_content_reference[]->{
185
+ "id": railcontent_id,
186
+ title,
187
+ slug,
188
+ "type": _type,
189
+ "logo" : logo_image_url.asset->url,
190
+ "dark_mode_logo": dark_mode_logo_url.asset->url,
191
+ "light_mode_logo": light_mode_logo_url.asset->url,
192
+ "badge": *[references(^._id) && _type == 'content-award'][0].badge.asset->url,
193
+ "badge_rear": *[references(^._id) && _type == 'content-award'][0].badge_rear.asset->url,
194
+ "badge_logo": *[references(^._id) && _type == 'content-award'][0].logo.asset->url,
195
+ 'parentCount': coalesce(count(parent_content_data), 0)
196
+ }`
197
+
178
198
  export const showsTypes = {
179
199
  drumeo: [
180
200
  'odd-times',
@@ -346,7 +366,7 @@ export const filterTypes = {
346
366
  ],
347
367
  }
348
368
 
349
- const lessonRecentTypes = [
369
+ export const lessonRecentTypes = [
350
370
  ...individualLessonsTypes,
351
371
  'skill-pack-lesson',
352
372
  ...entertainmentLessonTypes,
@@ -415,12 +435,12 @@ export let contentTypeConfig = {
415
435
  fields: [
416
436
  'railcontent_id',
417
437
  '"assignments": assignment[]{railcontent_id}',
418
- '"metadata": { brand, "type": _type, "parent_id": coalesce(parent_content_data[0].id, 0) }',
419
- ],
438
+ `"metadata": { brand, "type": _type, "parent_id": coalesce(${parentReferenceField}->railcontent_id, 0) }`,
439
+ ],
420
440
  childFields: [
421
441
  'railcontent_id',
422
442
  '"assignments": assignment[]{railcontent_id}',
423
- '"metadata": { brand, "type": _type, "parent_id": coalesce(parent_content_data[0].id, 0) }',
443
+ `"metadata": { brand, "type": _type, "parent_id": coalesce(${parentReferenceField}->railcontent_id, 0) }`,
424
444
  ],
425
445
  },
426
446
  song: {
@@ -479,42 +499,40 @@ export let contentTypeConfig = {
479
499
  },
480
500
  download: {
481
501
  fields: [
482
- `"resource": ${resourcesField}`,
502
+ `"resources": ${resourcesField}`,
483
503
  'soundslice',
504
+ 'soundslice_slug',
484
505
  'instrumentless',
485
506
  `"description": ${descriptionField}`,
507
+ assignmentsField,
486
508
  `"chapters": ${chapterField}`,
487
509
  '"instructors":instructor[]->name',
488
510
  `"instructor": ${instructorField}`,
489
511
  'video',
490
- `"play_along_mp3s": ${playAlongMp3sField}`,
512
+ ...playAlongMp3sFields,
513
+ pcdForDownloadField,
491
514
  `...select(
492
515
  defined(live_event_start_time) => {
493
- "live_event_start_time": live_event_start_time,
494
- "live_event_end_time": live_event_end_time,
495
- "live_event_stream_id": live_event_stream_id,
496
- "videoId": coalesce(live_event_stream_id, video.external_id),
497
- "live_event_is_global": live_global_event == true
516
+ ${getLiveFields(true).join(',')}
498
517
  }
499
518
  )`,
500
519
  ],
501
520
  childFields: [
502
- `"resource": ${resourcesField}`,
521
+ `"resources": ${resourcesField}`,
503
522
  'soundslice',
523
+ 'soundslice_slug',
504
524
  'instrumentless',
505
525
  `"description": ${descriptionField}`,
526
+ assignmentsField,
506
527
  `"chapters": ${chapterField}`,
507
528
  '"instructors":instructor[]->name',
508
529
  `"instructor": ${instructorField}`,
509
530
  'video',
510
- `"play_along_mp3s": ${playAlongMp3sField}`,
531
+ ...playAlongMp3sFields,
532
+ pcdForDownloadField,
511
533
  `...select(
512
534
  defined(live_event_start_time) => {
513
- "live_event_start_time": live_event_start_time,
514
- "live_event_end_time": live_event_end_time,
515
- "live_event_stream_id": live_event_stream_id,
516
- "videoId": coalesce(live_event_stream_id, video.external_id),
517
- "live_event_is_global": live_global_event == true
535
+ ${getLiveFields(true).join(',')}
518
536
  }
519
537
  )`,
520
538
  ],
@@ -676,7 +694,6 @@ export let contentTypeConfig = {
676
694
  'show_in_new_feed',
677
695
  isLiveField()
678
696
  ],
679
- includeChildFields: true,
680
697
  },
681
698
  }
682
699
 
package/src/index.d.ts CHANGED
@@ -225,6 +225,35 @@ import {
225
225
  updateMultiUserAccount
226
226
  } from './services/multi-user-accounts/multi-user-accounts.ts';
227
227
 
228
+ import {
229
+ getRecentActivityOffline
230
+ } from './services/offline/activities.ts';
231
+
232
+ import {
233
+ getPracticeSessionsOffline,
234
+ otherStatsOffline
235
+ } from './services/offline/practices.ts';
236
+
237
+ import {
238
+ contentStatusCompletedManyOffline,
239
+ contentStatusCompletedOffline,
240
+ contentStatusResetOffline,
241
+ contentStatusStartedOffline,
242
+ recordWatchSessionOffline
243
+ } from './services/offline/progress.ts';
244
+
245
+ import {
246
+ PermissionsAdapter,
247
+ PermissionsV1Adapter,
248
+ PermissionsV2Adapter,
249
+ doesUserHaveMembership,
250
+ fetchUserPermissions,
251
+ getPermissionsAdapter,
252
+ getPermissionsVersion,
253
+ isUserFreeTier,
254
+ reset
255
+ } from './services/permissions/index.ts';
256
+
228
257
  import {
229
258
  emitProgressSaved,
230
259
  onProgressSaved
@@ -252,7 +281,6 @@ import {
252
281
  fetchLiveStreamData,
253
282
  fetchRecentUserActivities,
254
283
  fetchTopComment,
255
- fetchUserPermissionsData,
256
284
  fetchUserPracticeMeta,
257
285
  fetchUserPracticeNotes,
258
286
  fetchUserPractices,
@@ -323,6 +351,7 @@ import {
323
351
  fetchTabData,
324
352
  fetchTopLevelParentId,
325
353
  fetchUpcomingEvents,
354
+ getHierarchies,
326
355
  getHierarchy,
327
356
  getSanityDate,
328
357
  getSongTypesFor,
@@ -422,11 +451,6 @@ import {
422
451
  fetchCustomerPayments
423
452
  } from './services/user/payments.ts';
424
453
 
425
- import {
426
- fetchUserPermissions,
427
- reset
428
- } from './services/user/permissions.js';
429
-
430
454
  import {
431
455
  deleteProfilePicture,
432
456
  otherStats
@@ -444,7 +468,6 @@ import {
444
468
  deletePracticeSession,
445
469
  deleteUserActivity,
446
470
  fetchRecentActivitiesActiveTabs,
447
- findIncompleteLesson,
448
471
  getPracticeNotes,
449
472
  getPracticeSessions,
450
473
  getRecentActivity,
@@ -468,6 +491,9 @@ import {
468
491
 
469
492
  declare module 'musora-content-services' {
470
493
  export {
494
+ PermissionsAdapter,
495
+ PermissionsV1Adapter,
496
+ PermissionsV2Adapter,
471
497
  acceptInvite,
472
498
  addContextToContent,
473
499
  addContextToLearningPaths,
@@ -488,8 +514,12 @@ declare module 'musora-content-services' {
488
514
  confirmEmailChange,
489
515
  contentStatusCompleted,
490
516
  contentStatusCompletedMany,
517
+ contentStatusCompletedManyOffline,
518
+ contentStatusCompletedOffline,
491
519
  contentStatusReset,
520
+ contentStatusResetOffline,
492
521
  contentStatusStarted,
522
+ contentStatusStartedOffline,
493
523
  convertToTimeZone,
494
524
  createAccount,
495
525
  createComment,
@@ -513,6 +543,7 @@ declare module 'musora-content-services' {
513
543
  deleteProfilePicture,
514
544
  deleteThread,
515
545
  deleteUserActivity,
546
+ doesUserHaveMembership,
516
547
  duplicatePlaylist,
517
548
  editComment,
518
549
  emitProgressSaved,
@@ -608,14 +639,12 @@ declare module 'musora-content-services' {
608
639
  fetchUnreadCount,
609
640
  fetchUpcomingEvents,
610
641
  fetchUserPermissions,
611
- fetchUserPermissionsData,
612
642
  fetchUserPlaylists,
613
643
  fetchUserPracticeMeta,
614
644
  fetchUserPracticeNotes,
615
645
  fetchUserPractices,
616
646
  fetchUsersMultiAccountDetails,
617
647
  filterCoursesInCourseCollections,
618
- findIncompleteLesson,
619
648
  flushWatchSession,
620
649
  followThread,
621
650
  generateAuthSessionUrl,
@@ -640,6 +669,7 @@ declare module 'musora-content-services' {
640
669
  getDailySession,
641
670
  getEnrichedLearningPath,
642
671
  getEnrichedLearningPaths,
672
+ getHierarchies,
643
673
  getHierarchy,
644
674
  getIdsWhereLastAccessedFromMethod,
645
675
  getInProgressAwards,
@@ -654,8 +684,11 @@ declare module 'musora-content-services' {
654
684
  getNewAndUpcoming,
655
685
  getOnboardingRecommendedContent,
656
686
  getOwnedContent,
687
+ getPermissionsAdapter,
688
+ getPermissionsVersion,
657
689
  getPracticeNotes,
658
690
  getPracticeSessions,
691
+ getPracticeSessionsOffline,
659
692
  getProgressDataByIds,
660
693
  getProgressDataByRecordIds,
661
694
  getProgressRows,
@@ -664,6 +697,7 @@ declare module 'musora-content-services' {
664
697
  getProgressStateByRecordIds,
665
698
  getRecent,
666
699
  getRecentActivity,
700
+ getRecentActivityOffline,
667
701
  getRecommendedForYou,
668
702
  getReportIssueOptions,
669
703
  getResumeTimeSecondsByIds,
@@ -694,6 +728,7 @@ declare module 'musora-content-services' {
694
728
  isContentLikedByIds,
695
729
  isNextDay,
696
730
  isSameDate,
731
+ isUserFreeTier,
697
732
  isUsernameAvailable,
698
733
  jumpToContinueContent,
699
734
  jumpToPost,
@@ -718,6 +753,7 @@ declare module 'musora-content-services' {
718
753
  onProgressSaved,
719
754
  openComment,
720
755
  otherStats,
756
+ otherStatsOffline,
721
757
  pauseLiveEventPolling,
722
758
  pinProgressRow,
723
759
  pinThread,
@@ -728,6 +764,7 @@ declare module 'musora-content-services' {
728
764
  recordUserActivity,
729
765
  recordUserPractice,
730
766
  recordWatchSession,
767
+ recordWatchSessionOffline,
731
768
  registerAwardCallback,
732
769
  registerProgressCallback,
733
770
  removeContentAsInterested,
package/src/index.js CHANGED
@@ -229,6 +229,35 @@ import {
229
229
  updateMultiUserAccount
230
230
  } from './services/multi-user-accounts/multi-user-accounts.ts';
231
231
 
232
+ import {
233
+ getRecentActivityOffline
234
+ } from './services/offline/activities.ts';
235
+
236
+ import {
237
+ getPracticeSessionsOffline,
238
+ otherStatsOffline
239
+ } from './services/offline/practices.ts';
240
+
241
+ import {
242
+ contentStatusCompletedManyOffline,
243
+ contentStatusCompletedOffline,
244
+ contentStatusResetOffline,
245
+ contentStatusStartedOffline,
246
+ recordWatchSessionOffline
247
+ } from './services/offline/progress.ts';
248
+
249
+ import {
250
+ PermissionsAdapter,
251
+ PermissionsV1Adapter,
252
+ PermissionsV2Adapter,
253
+ doesUserHaveMembership,
254
+ fetchUserPermissions,
255
+ getPermissionsAdapter,
256
+ getPermissionsVersion,
257
+ isUserFreeTier,
258
+ reset
259
+ } from './services/permissions/index.ts';
260
+
232
261
  import {
233
262
  emitProgressSaved,
234
263
  onProgressSaved
@@ -256,7 +285,6 @@ import {
256
285
  fetchLiveStreamData,
257
286
  fetchRecentUserActivities,
258
287
  fetchTopComment,
259
- fetchUserPermissionsData,
260
288
  fetchUserPracticeMeta,
261
289
  fetchUserPracticeNotes,
262
290
  fetchUserPractices,
@@ -327,6 +355,7 @@ import {
327
355
  fetchTabData,
328
356
  fetchTopLevelParentId,
329
357
  fetchUpcomingEvents,
358
+ getHierarchies,
330
359
  getHierarchy,
331
360
  getSanityDate,
332
361
  getSongTypesFor,
@@ -426,11 +455,6 @@ import {
426
455
  fetchCustomerPayments
427
456
  } from './services/user/payments.ts';
428
457
 
429
- import {
430
- fetchUserPermissions,
431
- reset
432
- } from './services/user/permissions.js';
433
-
434
458
  import {
435
459
  deleteProfilePicture,
436
460
  otherStats
@@ -448,7 +472,6 @@ import {
448
472
  deletePracticeSession,
449
473
  deleteUserActivity,
450
474
  fetchRecentActivitiesActiveTabs,
451
- findIncompleteLesson,
452
475
  getPracticeNotes,
453
476
  getPracticeSessions,
454
477
  getRecentActivity,
@@ -467,6 +490,9 @@ import {
467
490
  } from './services/userActivity.js';
468
491
 
469
492
  export {
493
+ PermissionsAdapter,
494
+ PermissionsV1Adapter,
495
+ PermissionsV2Adapter,
470
496
  acceptInvite,
471
497
  addContextToContent,
472
498
  addContextToLearningPaths,
@@ -487,8 +513,12 @@ export {
487
513
  confirmEmailChange,
488
514
  contentStatusCompleted,
489
515
  contentStatusCompletedMany,
516
+ contentStatusCompletedManyOffline,
517
+ contentStatusCompletedOffline,
490
518
  contentStatusReset,
519
+ contentStatusResetOffline,
491
520
  contentStatusStarted,
521
+ contentStatusStartedOffline,
492
522
  convertToTimeZone,
493
523
  createAccount,
494
524
  createComment,
@@ -512,6 +542,7 @@ export {
512
542
  deleteProfilePicture,
513
543
  deleteThread,
514
544
  deleteUserActivity,
545
+ doesUserHaveMembership,
515
546
  duplicatePlaylist,
516
547
  editComment,
517
548
  emitProgressSaved,
@@ -607,14 +638,12 @@ export {
607
638
  fetchUnreadCount,
608
639
  fetchUpcomingEvents,
609
640
  fetchUserPermissions,
610
- fetchUserPermissionsData,
611
641
  fetchUserPlaylists,
612
642
  fetchUserPracticeMeta,
613
643
  fetchUserPracticeNotes,
614
644
  fetchUserPractices,
615
645
  fetchUsersMultiAccountDetails,
616
646
  filterCoursesInCourseCollections,
617
- findIncompleteLesson,
618
647
  flushWatchSession,
619
648
  followThread,
620
649
  generateAuthSessionUrl,
@@ -639,6 +668,7 @@ export {
639
668
  getDailySession,
640
669
  getEnrichedLearningPath,
641
670
  getEnrichedLearningPaths,
671
+ getHierarchies,
642
672
  getHierarchy,
643
673
  getIdsWhereLastAccessedFromMethod,
644
674
  getInProgressAwards,
@@ -653,8 +683,11 @@ export {
653
683
  getNewAndUpcoming,
654
684
  getOnboardingRecommendedContent,
655
685
  getOwnedContent,
686
+ getPermissionsAdapter,
687
+ getPermissionsVersion,
656
688
  getPracticeNotes,
657
689
  getPracticeSessions,
690
+ getPracticeSessionsOffline,
658
691
  getProgressDataByIds,
659
692
  getProgressDataByRecordIds,
660
693
  getProgressRows,
@@ -663,6 +696,7 @@ export {
663
696
  getProgressStateByRecordIds,
664
697
  getRecent,
665
698
  getRecentActivity,
699
+ getRecentActivityOffline,
666
700
  getRecommendedForYou,
667
701
  getReportIssueOptions,
668
702
  getResumeTimeSecondsByIds,
@@ -693,6 +727,7 @@ export {
693
727
  isContentLikedByIds,
694
728
  isNextDay,
695
729
  isSameDate,
730
+ isUserFreeTier,
696
731
  isUsernameAvailable,
697
732
  jumpToContinueContent,
698
733
  jumpToPost,
@@ -717,6 +752,7 @@ export {
717
752
  onProgressSaved,
718
753
  openComment,
719
754
  otherStats,
755
+ otherStatsOffline,
720
756
  pauseLiveEventPolling,
721
757
  pinProgressRow,
722
758
  pinThread,
@@ -727,6 +763,7 @@ export {
727
763
  recordUserActivity,
728
764
  recordUserPractice,
729
765
  recordWatchSession,
766
+ recordWatchSessionOffline,
730
767
  registerAwardCallback,
731
768
  registerProgressCallback,
732
769
  removeContentAsInterested,
@@ -1,6 +1,6 @@
1
1
  import { filtersToGroq } from '../../contentTypeConfig'
2
2
  import { getPermissionsAdapter } from '../../services/permissions/index'
3
- import type { UserPermissions } from '../../services/permissions/PermissionsAdapter'
3
+ import type { UserPermissions } from '../../services/permissions/types'
4
4
  import { Brands } from '../brands'
5
5
  import { filterOps } from './query'
6
6
 
@@ -4,10 +4,12 @@
4
4
 
5
5
  import { GET, POST } from '../../infrastructure/http/HttpClient'
6
6
  import {
7
+ devFetchAllLearningPathsAndIntroVideoIdsForDelete,
7
8
  fetchByRailContentId,
8
9
  fetchByRailContentIds,
9
10
  fetchMethodV2Structure,
10
- fetchParentChildRelationshipsFor
11
+ fetchParentChildRelationshipsFor,
12
+ hasAnyMethodV2IntroCompleted,
11
13
  } from '../sanity.js'
12
14
  import { addContextToLearningPaths } from '../contentAggregator.js'
13
15
  import {
@@ -18,12 +20,11 @@ import {
18
20
  getIdsWhereLastAccessedFromMethod,
19
21
  getProgressState,
20
22
  } from '../contentProgress.js'
21
- import { COLLECTION_ID_SELF, COLLECTION_TYPE, STATE } from '../sync/models/ContentProgress'
22
- import { SyncWriteDTO } from '../sync'
23
+ import { COLLECTION_ID_SELF, COLLECTION_TYPE, CollectionParameter, STATE } from '../sync/models/ContentProgress'
24
+ import { db, SyncWriteDTO } from '../sync'
23
25
  import { ContentProgress } from '../sync/models'
24
- import { CollectionParameter } from '../sync/models/ContentProgress'
25
26
  import dayjs from 'dayjs'
26
- import { LEARNING_PATH_LESSON } from "../../contentTypeConfig";
27
+ import { LEARNING_PATH_LESSON } from '../../contentTypeConfig'
27
28
 
28
29
  const BASE_PATH: string = `/api/content-org`
29
30
  const LEARNING_PATHS_PATH = `${BASE_PATH}/v1/user/learning-paths`
@@ -196,7 +197,18 @@ async function dataPromiseGET(
196
197
  */
197
198
  export async function resetAllLearningPaths() {
198
199
  const url: string = `${LEARNING_PATHS_PATH}/reset`
199
- return await POST(url, {})
200
+
201
+ return await Promise.all([
202
+ devFetchAllLearningPathsAndIntroVideoIdsForDelete().then(async (all) => {
203
+ await Promise.all([
204
+ db.contentProgress.eraseProgressMany(all.intros, null),
205
+ ...all.learning_paths.map((id) =>
206
+ db.contentProgress.eraseProgress(id, {id, type: COLLECTION_TYPE.LEARNING_PATH})
207
+ )
208
+ ])
209
+ }),
210
+ POST(url, {}),
211
+ ])
200
212
  }
201
213
 
202
214
  /**
@@ -457,20 +469,20 @@ interface completeMethodIntroVideo {
457
469
  }
458
470
  /**
459
471
  * Handles completion of method intro video and other related actions.
460
- * @param introVideoId - The method intro video content ID.
472
+ * @param introVideoId - The method intro video content ID. If not provided, does not `complete` intro video.
461
473
  * @param brand
462
474
  * @returns {Promise<Array>} response - The response object.
463
475
  * @returns {Promise<Object|null>} response.intro_video_response - The intro video completion response or null if already completed.
464
476
  * @returns {Promise<Object>} response.active_path_response - The set active learning path response.
465
477
  */
466
478
  export async function completeMethodIntroVideo(
467
- introVideoId: number,
479
+ introVideoId: number|null,
468
480
  brand: string
469
481
  ): Promise<completeMethodIntroVideo> {
470
482
  let response = {} as completeMethodIntroVideo
471
483
 
472
484
  const [intro_video_response, methodStructure] = await Promise.all([
473
- completeIfNotCompleted(introVideoId),
485
+ introVideoId ? completeIfNotCompleted(introVideoId) : Promise.resolve(null),
474
486
  fetchMethodV2Structure(brand)
475
487
  ])
476
488
  response.intro_video_response = intro_video_response
@@ -520,13 +532,25 @@ export async function completeLearningPathIntroVideo(
520
532
  let response = {} as completeLearningPathIntroVideo
521
533
  const collection: CollectionObject = { id: learningPathId, type: COLLECTION_TYPE.LEARNING_PATH }
522
534
 
535
+ const [anyIntroComplete, activePath] = await Promise.all([
536
+ hasAnyMethodV2IntroCompleted(),
537
+ getActivePath(brand)
538
+ ])
539
+
540
+ let lateMethodSetup = false
541
+ // check if the method intro was watched elsewhere; then we have to give user active path for this brand.
542
+ if (anyIntroComplete && !activePath) {
543
+ completeMethodIntroVideo(null, brand) // no need to await.
544
+ lateMethodSetup = true
545
+ }
546
+
523
547
  if (!lessonsToImport) {
524
548
  response.learning_path_reset_response = await resetIfPossible(learningPathId, collection)
525
549
  } else {
526
550
  response.lesson_import_response = await contentStatusCompletedMany(lessonsToImport, collection)
527
551
 
528
552
  const activePath = await getActivePath(brand)
529
- if (activePath.active_learning_path_id === learningPathId) {
553
+ if (activePath.active_learning_path_id === learningPathId && !lateMethodSetup) { // don't update dailies if they were just set by completeMethodIntroVideoCompleteActions.
530
554
  response.update_dailies_response = await updateDailySession(brand, new Date(), true)
531
555
  }
532
556
  }