musora-content-services 2.71.0 → 2.72.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.
- package/CHANGELOG.md +14 -0
- package/docs/ContentOrganization.html +2 -2
- package/docs/Forums.html +2 -2
- package/docs/Gamification.html +2 -2
- package/docs/TestUser.html +3 -3
- package/docs/UserManagementSystem.html +2 -2
- package/docs/api_types.js.html +2 -2
- package/docs/config.js.html +2 -2
- package/docs/content-org_content-org.js.html +2 -2
- package/docs/content-org_guided-courses.ts.html +2 -2
- package/docs/content-org_learning-paths.ts.html +94 -5
- package/docs/content-org_playlists-types.js.html +2 -2
- package/docs/content-org_playlists.js.html +2 -2
- package/docs/content.js.html +2 -2
- package/docs/forums_categories.ts.html +2 -2
- package/docs/forums_forums.ts.html +41 -41
- package/docs/forums_posts.ts.html +34 -27
- package/docs/forums_threads.ts.html +2 -2
- package/docs/gamification_awards.ts.html +2 -2
- package/docs/gamification_gamification.js.html +2 -2
- package/docs/global.html +3 -3
- package/docs/index.html +2 -2
- package/docs/liveTesting.ts.html +4 -3
- package/docs/module-Accounts.html +2 -2
- package/docs/module-Awards.html +2 -2
- package/docs/module-Config.html +2 -2
- package/docs/module-Content-Services-V2.html +2 -2
- package/docs/module-Forums.html +26 -26
- package/docs/module-GuidedCourses.html +2 -1198
- package/docs/module-Interests.html +2 -2
- package/docs/module-LearningPaths.html +1077 -0
- package/docs/module-Onboarding.html +2 -2
- package/docs/module-Payments.html +2 -2
- package/docs/module-Permissions.html +2 -2
- package/docs/module-Playlists.html +2 -2
- package/docs/module-Railcontent-Services.html +2 -2
- package/docs/module-Sanity-Services.html +32 -32
- package/docs/module-Sessions.html +2 -2
- package/docs/module-UserActivity.html +2 -2
- package/docs/module-UserChat.html +2 -2
- package/docs/module-UserManagement.html +2 -2
- package/docs/module-UserMemberships.html +2 -2
- package/docs/module-UserNotifications.html +2 -2
- package/docs/module-UserProfile.html +2 -2
- package/docs/railcontent.js.html +2 -2
- package/docs/sanity.js.html +5 -7
- package/docs/userActivity.js.html +2 -2
- package/docs/user_account.ts.html +2 -2
- package/docs/user_chat.js.html +2 -2
- package/docs/user_interests.js.html +2 -2
- package/docs/user_management.js.html +2 -2
- package/docs/user_memberships.ts.html +2 -2
- package/docs/user_notifications.js.html +2 -2
- package/docs/user_onboarding.ts.html +2 -2
- package/docs/user_payments.ts.html +2 -2
- package/docs/user_permissions.js.html +2 -2
- package/docs/user_profile.js.html +2 -2
- package/docs/user_sessions.js.html +2 -2
- package/docs/user_types.js.html +2 -2
- package/docs/user_user-management-system.js.html +2 -2
- package/package.json +1 -1
- package/src/contentTypeConfig.js +162 -105
- package/src/index.d.ts +2 -0
- package/src/index.js +2 -0
- package/src/lib/httpHelper.js +5 -0
- package/src/services/content-org/learning-paths.ts +92 -3
- package/src/services/forums/forums.ts +38 -38
- package/src/services/forums/posts.ts +32 -25
- package/test/initializeTests.js +21 -36
- package/test/learningPaths.test.js +19 -0
package/src/contentTypeConfig.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
//import {AWSUrl, CloudFrontURl} from "./services/config";
|
|
2
|
-
import {LengthFilterOptions, Tabs} from
|
|
3
|
-
import {FilterBuilder} from
|
|
2
|
+
import { LengthFilterOptions, Tabs } from './contentMetaData.js'
|
|
3
|
+
import { FilterBuilder } from './filterBuilder.js'
|
|
4
4
|
|
|
5
5
|
export const AWSUrl = 'https://s3.us-east-1.amazonaws.com/musora-web-platform'
|
|
6
6
|
export const CloudFrontURl = 'https://d3fzm1tzeyr5n3.cloudfront.net'
|
|
@@ -9,8 +9,16 @@ export const CloudFrontURl = 'https://d3fzm1tzeyr5n3.cloudfront.net'
|
|
|
9
9
|
export const SONG_TYPES = ['song', 'play-along', 'jam-track', 'song-tutorial-children']
|
|
10
10
|
// Oct 2025: It turns out content-meta categories are not really clear
|
|
11
11
|
// THis is used for the page_type field as a post processor so we include parents and children
|
|
12
|
-
|
|
13
|
-
export const SONG_TYPES_WITH_CHILDREN = [
|
|
12
|
+
// Duplicated in SanityGateway.php if you update this, update that
|
|
13
|
+
export const SONG_TYPES_WITH_CHILDREN = [
|
|
14
|
+
'song',
|
|
15
|
+
'song-part',
|
|
16
|
+
'play-along',
|
|
17
|
+
'play-along-part',
|
|
18
|
+
'jam-track',
|
|
19
|
+
'song-tutorial',
|
|
20
|
+
'song-tutorial-children',
|
|
21
|
+
]
|
|
14
22
|
// Single hierarchy refers to only one element in the hierarchy has video lessons, not that they have a single parent
|
|
15
23
|
export const SINGLE_PARENT_TYPES = ['course-part', 'pack-bundle-lesson', 'song-tutorial-children']
|
|
16
24
|
|
|
@@ -172,40 +180,51 @@ export const coachLessonsTypes = [
|
|
|
172
180
|
]
|
|
173
181
|
|
|
174
182
|
export const childContentTypeConfig = {
|
|
175
|
-
'song-tutorial': [
|
|
176
|
-
`"genre": genre[]->name`,
|
|
177
|
-
`difficulty_string`,
|
|
178
|
-
`"type": _type`,
|
|
179
|
-
]
|
|
183
|
+
'song-tutorial': [`"genre": genre[]->name`, `difficulty_string`, `"type": _type`],
|
|
180
184
|
}
|
|
181
185
|
|
|
182
|
-
export const singleLessonTypes = ['quick-tips', 'rudiment']
|
|
183
|
-
export const practiceAlongsLessonTypes = ['workout']
|
|
184
|
-
export const performancesLessonTypes = ['performance']
|
|
185
|
-
export const documentariesLessonTypes = [
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
186
|
+
export const singleLessonTypes = ['quick-tips', 'rudiment']
|
|
187
|
+
export const practiceAlongsLessonTypes = ['workout'] // challenges ->workouts
|
|
188
|
+
export const performancesLessonTypes = ['performance']
|
|
189
|
+
export const documentariesLessonTypes = [
|
|
190
|
+
'tama',
|
|
191
|
+
'sonor',
|
|
192
|
+
'history-of-electronic-drums',
|
|
193
|
+
'paiste-cymbals',
|
|
194
|
+
'backstage-secret',
|
|
195
|
+
]
|
|
196
|
+
export const liveArchivesLessonTypes = [
|
|
197
|
+
'podcast',
|
|
198
|
+
'coach-stream',
|
|
199
|
+
'question-and-answer',
|
|
200
|
+
'live-streams',
|
|
201
|
+
'live',
|
|
202
|
+
]
|
|
203
|
+
export const studentArchivesLessonTypes = [
|
|
204
|
+
'student-review',
|
|
205
|
+
'student-focus',
|
|
206
|
+
'student-collaboration',
|
|
207
|
+
]
|
|
208
|
+
export const tutorialsLessonTypes = ['song-tutorial']
|
|
209
|
+
export const transcriptionsLessonTypes = ['song']
|
|
210
|
+
export const playAlongLessonTypes = ['play-along']
|
|
211
|
+
export const jamTrackLessonTypes = ['jam-track']
|
|
192
212
|
|
|
193
213
|
export const individualLessonsTypes = [
|
|
194
214
|
...singleLessonTypes,
|
|
195
215
|
...practiceAlongsLessonTypes,
|
|
196
216
|
...liveArchivesLessonTypes,
|
|
197
|
-
...studentArchivesLessonTypes
|
|
198
|
-
]
|
|
217
|
+
...studentArchivesLessonTypes,
|
|
218
|
+
]
|
|
199
219
|
|
|
200
220
|
export const coursesLessonTypes = [
|
|
201
221
|
'course',
|
|
202
222
|
'tiered-course', // TODO: new content type
|
|
203
|
-
'guided-course'
|
|
204
|
-
|
|
205
|
-
export const skillLessonTypes = [
|
|
206
|
-
'skill-pack'
|
|
223
|
+
'guided-course',
|
|
207
224
|
]
|
|
208
225
|
|
|
226
|
+
export const skillLessonTypes = ['skill-pack']
|
|
227
|
+
|
|
209
228
|
export const showsLessonTypes = [
|
|
210
229
|
'boot-camp',
|
|
211
230
|
'diy-drum-experiment',
|
|
@@ -213,57 +232,75 @@ export const showsLessonTypes = [
|
|
|
213
232
|
'in-rhythm',
|
|
214
233
|
'rhythmic-adventures-of-captain-carson',
|
|
215
234
|
'rhythms-from-another-planet',
|
|
216
|
-
'study-the-greats'
|
|
235
|
+
'study-the-greats',
|
|
236
|
+
]
|
|
217
237
|
export const entertainmentLessonTypes = [
|
|
218
238
|
'specials', // TODO: new type
|
|
219
239
|
...documentariesLessonTypes,
|
|
220
|
-
...showsLessonTypes
|
|
221
|
-
]
|
|
222
|
-
export const collectionLessonTypes = [
|
|
223
|
-
...coursesLessonTypes,
|
|
224
|
-
...showsLessonTypes
|
|
225
|
-
];
|
|
240
|
+
...showsLessonTypes,
|
|
241
|
+
]
|
|
242
|
+
export const collectionLessonTypes = [...coursesLessonTypes, ...showsLessonTypes]
|
|
226
243
|
|
|
227
244
|
export const lessonTypesMapping = {
|
|
228
|
-
|
|
245
|
+
lessons: singleLessonTypes,
|
|
229
246
|
'practice alongs': practiceAlongsLessonTypes,
|
|
230
247
|
'live archives': liveArchivesLessonTypes,
|
|
231
|
-
|
|
248
|
+
performances: performancesLessonTypes,
|
|
232
249
|
'student archives': studentArchivesLessonTypes,
|
|
233
|
-
|
|
234
|
-
|
|
250
|
+
documentaries: documentariesLessonTypes,
|
|
251
|
+
courses: ['course'],
|
|
235
252
|
'guided courses': ['guided-course'],
|
|
236
|
-
'tiered courses': ['tiered-course'
|
|
253
|
+
'tiered courses': ['tiered-course'],
|
|
237
254
|
'skill packs': ['skill-pack'],
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
255
|
+
specials: ['specials'],
|
|
256
|
+
shows: showsLessonTypes,
|
|
257
|
+
collections: collectionLessonTypes,
|
|
258
|
+
individuals: individualLessonsTypes,
|
|
259
|
+
tutorials: tutorialsLessonTypes,
|
|
260
|
+
transcriptions: transcriptionsLessonTypes,
|
|
261
|
+
tabs: transcriptionsLessonTypes,
|
|
245
262
|
'sheet music': transcriptionsLessonTypes,
|
|
246
263
|
'play-alongs': playAlongLessonTypes,
|
|
247
264
|
'jam tracks': jamTrackLessonTypes,
|
|
248
|
-
|
|
249
|
-
'single lessons': [
|
|
250
|
-
|
|
265
|
+
entertainment: entertainmentLessonTypes,
|
|
266
|
+
'single lessons': [
|
|
267
|
+
...singleLessonTypes,
|
|
268
|
+
...liveArchivesLessonTypes,
|
|
269
|
+
...studentArchivesLessonTypes,
|
|
270
|
+
...practiceAlongsLessonTypes,
|
|
271
|
+
],
|
|
272
|
+
}
|
|
251
273
|
|
|
252
|
-
export const getNextLessonLessonParentTypes = [
|
|
274
|
+
export const getNextLessonLessonParentTypes = [
|
|
275
|
+
'course',
|
|
276
|
+
'guided-course',
|
|
277
|
+
'pack',
|
|
278
|
+
'pack-bundle',
|
|
279
|
+
'song-tutorial',
|
|
280
|
+
]
|
|
253
281
|
|
|
254
282
|
export const progressTypesMapping = {
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
283
|
+
lesson: [
|
|
284
|
+
...singleLessonTypes,
|
|
285
|
+
...practiceAlongsLessonTypes,
|
|
286
|
+
...liveArchivesLessonTypes,
|
|
287
|
+
...performancesLessonTypes,
|
|
288
|
+
...studentArchivesLessonTypes,
|
|
289
|
+
...documentariesLessonTypes,
|
|
290
|
+
'live',
|
|
291
|
+
'pack-bundle-lesson',
|
|
292
|
+
],
|
|
293
|
+
course: ['course'],
|
|
294
|
+
show: showsLessonTypes,
|
|
258
295
|
'song tutorial': [...tutorialsLessonTypes, 'song-tutorial-children'],
|
|
259
|
-
|
|
296
|
+
songs: transcriptionsLessonTypes,
|
|
260
297
|
'play along': playAlongLessonTypes,
|
|
261
298
|
'guided course': ['guided-course'],
|
|
262
|
-
|
|
263
|
-
|
|
299
|
+
pack: ['pack', 'semester-pack'],
|
|
300
|
+
method: ['learning-path'],
|
|
264
301
|
'jam track': jamTrackLessonTypes,
|
|
265
302
|
'course video': ['course-part'],
|
|
266
|
-
}
|
|
303
|
+
}
|
|
267
304
|
|
|
268
305
|
export const songs = {
|
|
269
306
|
drumeo: 'transcription',
|
|
@@ -274,23 +311,48 @@ export const songs = {
|
|
|
274
311
|
}
|
|
275
312
|
|
|
276
313
|
export const filterTypes = {
|
|
277
|
-
lessons: [
|
|
278
|
-
|
|
314
|
+
lessons: [
|
|
315
|
+
...singleLessonTypes,
|
|
316
|
+
...practiceAlongsLessonTypes,
|
|
317
|
+
...liveArchivesLessonTypes,
|
|
318
|
+
...studentArchivesLessonTypes,
|
|
319
|
+
...coursesLessonTypes,
|
|
320
|
+
...skillLessonTypes,
|
|
321
|
+
...entertainmentLessonTypes,
|
|
322
|
+
],
|
|
323
|
+
songs: [
|
|
324
|
+
...tutorialsLessonTypes,
|
|
325
|
+
...transcriptionsLessonTypes,
|
|
326
|
+
...playAlongLessonTypes,
|
|
327
|
+
...jamTrackLessonTypes,
|
|
328
|
+
],
|
|
279
329
|
}
|
|
280
330
|
|
|
281
331
|
export const recentTypes = {
|
|
282
|
-
lessons: [
|
|
332
|
+
lessons: [
|
|
333
|
+
...individualLessonsTypes,
|
|
334
|
+
'course-part',
|
|
335
|
+
'pack-bundle-lesson',
|
|
336
|
+
'guided-course-part',
|
|
337
|
+
'quick-tips',
|
|
338
|
+
],
|
|
283
339
|
songs: [...SONG_TYPES],
|
|
284
|
-
home: [
|
|
285
|
-
|
|
340
|
+
home: [
|
|
341
|
+
...individualLessonsTypes,
|
|
342
|
+
...tutorialsLessonTypes,
|
|
343
|
+
...transcriptionsLessonTypes,
|
|
344
|
+
...playAlongLessonTypes,
|
|
345
|
+
'guided-course',
|
|
346
|
+
'learning-path',
|
|
347
|
+
'live',
|
|
348
|
+
'course',
|
|
349
|
+
'pack',
|
|
350
|
+
],
|
|
286
351
|
}
|
|
287
352
|
|
|
288
353
|
export let contentTypeConfig = {
|
|
289
354
|
'tab-data': {
|
|
290
|
-
fields: [
|
|
291
|
-
'enrollment_start_time',
|
|
292
|
-
'enrollment_end_time',
|
|
293
|
-
],
|
|
355
|
+
fields: ['enrollment_start_time', 'enrollment_end_time'],
|
|
294
356
|
includeChildFields: true,
|
|
295
357
|
},
|
|
296
358
|
'progress-tracker': {
|
|
@@ -353,7 +415,7 @@ export let contentTypeConfig = {
|
|
|
353
415
|
],
|
|
354
416
|
slug: 'courses',
|
|
355
417
|
},
|
|
356
|
-
|
|
418
|
+
download: {
|
|
357
419
|
fields: [
|
|
358
420
|
`"resource": ${resourcesField}`,
|
|
359
421
|
'soundslice',
|
|
@@ -372,8 +434,7 @@ export let contentTypeConfig = {
|
|
|
372
434
|
"videoId": coalesce(live_event_stream_id, video.external_id),
|
|
373
435
|
"live_event_is_global": live_global_event == true
|
|
374
436
|
}
|
|
375
|
-
)
|
|
376
|
-
|
|
437
|
+
)`,
|
|
377
438
|
],
|
|
378
439
|
childFields: [
|
|
379
440
|
`"resource": ${resourcesField}`,
|
|
@@ -393,9 +454,8 @@ export let contentTypeConfig = {
|
|
|
393
454
|
"videoId": coalesce(live_event_stream_id, video.external_id),
|
|
394
455
|
"live_event_is_global": live_global_event == true
|
|
395
456
|
}
|
|
396
|
-
)
|
|
397
|
-
|
|
398
|
-
]
|
|
457
|
+
)`,
|
|
458
|
+
],
|
|
399
459
|
},
|
|
400
460
|
method: {
|
|
401
461
|
fields: [
|
|
@@ -519,9 +579,7 @@ export let contentTypeConfig = {
|
|
|
519
579
|
`"description": ${descriptionField}`,
|
|
520
580
|
'total_xp',
|
|
521
581
|
],
|
|
522
|
-
childFields: [
|
|
523
|
-
`"description": ${descriptionField}`,
|
|
524
|
-
]
|
|
582
|
+
childFields: [`"description": ${descriptionField}`],
|
|
525
583
|
},
|
|
526
584
|
'pack-bundle-lesson': {
|
|
527
585
|
fields: [`"resources": ${resourcesField}`],
|
|
@@ -609,23 +667,17 @@ export let contentTypeConfig = {
|
|
|
609
667
|
'exploring-beats': contentWithSortField,
|
|
610
668
|
sonor: contentWithSortField,
|
|
611
669
|
returning: {
|
|
612
|
-
fields: [
|
|
613
|
-
`quarter_published`,
|
|
614
|
-
'"thumbnail": thumbnail.asset->url',
|
|
615
|
-
]
|
|
670
|
+
fields: [`quarter_published`, '"thumbnail": thumbnail.asset->url'],
|
|
616
671
|
},
|
|
617
672
|
leaving: {
|
|
618
|
-
fields: [
|
|
619
|
-
`quarter_removed`,
|
|
620
|
-
'"thumbnail": thumbnail.asset->url',
|
|
621
|
-
]
|
|
673
|
+
fields: [`quarter_removed`, '"thumbnail": thumbnail.asset->url'],
|
|
622
674
|
},
|
|
623
|
-
|
|
675
|
+
'method-v2': [
|
|
624
676
|
`"id":_id`,
|
|
625
677
|
`"type":_type`,
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
`"intro_video": intro_video->{ ${getIntroVideoFields().join(
|
|
678
|
+
'title',
|
|
679
|
+
'brand',
|
|
680
|
+
`"intro_video": intro_video->{ ${getIntroVideoFields().join(', ')} }`,
|
|
629
681
|
`child[]->{
|
|
630
682
|
"resource": ${resourcesField},
|
|
631
683
|
total_skills,
|
|
@@ -643,22 +695,21 @@ export let contentTypeConfig = {
|
|
|
643
695
|
}
|
|
644
696
|
}`,
|
|
645
697
|
],
|
|
646
|
-
|
|
698
|
+
'method-intro': getIntroVideoFields(),
|
|
647
699
|
}
|
|
648
700
|
|
|
649
701
|
export function getIntroVideoFields() {
|
|
650
702
|
return [
|
|
651
|
-
|
|
652
|
-
|
|
703
|
+
'title',
|
|
704
|
+
'brand',
|
|
653
705
|
`"description": ${descriptionField}`,
|
|
654
706
|
`"thumbnail": thumbnail.asset->url`,
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
]
|
|
707
|
+
'length_in_seconds',
|
|
708
|
+
'video_desktop',
|
|
709
|
+
'video_mobile',
|
|
710
|
+
]
|
|
659
711
|
}
|
|
660
712
|
|
|
661
|
-
|
|
662
713
|
export const plusMembershipPermissions = 92
|
|
663
714
|
|
|
664
715
|
export function getNewReleasesTypes(brand) {
|
|
@@ -771,11 +822,14 @@ export function artistOrInstructorNameAsArray(key = 'artists') {
|
|
|
771
822
|
return `'${key}': select(artist->name != null => [artist->name], instructor[]->name)`
|
|
772
823
|
}
|
|
773
824
|
|
|
774
|
-
export async function getFieldsForContentTypeWithFilteredChildren(
|
|
825
|
+
export async function getFieldsForContentTypeWithFilteredChildren(
|
|
826
|
+
contentType,
|
|
827
|
+
asQueryString = true
|
|
828
|
+
) {
|
|
775
829
|
const childFields = getChildFieldsForContentType(contentType, true)
|
|
776
830
|
const parentFields = getFieldsForContentType(contentType, false)
|
|
777
831
|
if (childFields) {
|
|
778
|
-
const childFilter = await new FilterBuilder('', {isChildrenFilter: true}).buildFilter()
|
|
832
|
+
const childFilter = await new FilterBuilder('', { isChildrenFilter: true }).buildFilter()
|
|
779
833
|
parentFields.push(
|
|
780
834
|
`"children": child[${childFilter}]->{
|
|
781
835
|
${childFields}
|
|
@@ -788,14 +842,16 @@ export async function getFieldsForContentTypeWithFilteredChildren(contentType, a
|
|
|
788
842
|
return asQueryString ? parentFields.toString() + ',' : parentFields
|
|
789
843
|
}
|
|
790
844
|
|
|
791
|
-
export function getChildFieldsForContentType(contentType, asQueryString = true)
|
|
792
|
-
{
|
|
845
|
+
export function getChildFieldsForContentType(contentType, asQueryString = true) {
|
|
793
846
|
// When contentType is undefined/null, return DEFAULT_CHILD_FIELDS to support mixed-type queries (e.g., from Algolia)
|
|
794
847
|
if (!contentType) {
|
|
795
848
|
return asQueryString ? DEFAULT_CHILD_FIELDS.toString() + ',' : DEFAULT_CHILD_FIELDS
|
|
796
849
|
}
|
|
797
850
|
|
|
798
|
-
if (
|
|
851
|
+
if (
|
|
852
|
+
contentTypeConfig[contentType]?.childFields ||
|
|
853
|
+
contentTypeConfig[contentType]?.includeChildFields
|
|
854
|
+
) {
|
|
799
855
|
const childFields = contentType
|
|
800
856
|
? DEFAULT_CHILD_FIELDS.concat(contentTypeConfig?.[contentType]?.childFields ?? [])
|
|
801
857
|
: DEFAULT_CHILD_FIELDS
|
|
@@ -817,7 +873,7 @@ export function getFieldsForContentType(contentType, asQueryString = true) {
|
|
|
817
873
|
*/
|
|
818
874
|
function createTypeConditions(lessonTypes) {
|
|
819
875
|
if (!lessonTypes || lessonTypes.length === 0) return ''
|
|
820
|
-
const conditions = lessonTypes.map(type => `_type == '${type}'`).join(' || ')
|
|
876
|
+
const conditions = lessonTypes.map((type) => `_type == '${type}'`).join(' || ')
|
|
821
877
|
return conditions ? `(${conditions})` : ''
|
|
822
878
|
}
|
|
823
879
|
|
|
@@ -872,8 +928,9 @@ const filterHandlers = {
|
|
|
872
928
|
|
|
873
929
|
length: (value) => {
|
|
874
930
|
// Find the matching length option by name
|
|
875
|
-
const lengthOption = Object.values(LengthFilterOptions)
|
|
876
|
-
|
|
931
|
+
const lengthOption = Object.values(LengthFilterOptions).find(
|
|
932
|
+
(opt) => typeof opt === 'object' && opt.name === value
|
|
933
|
+
)
|
|
877
934
|
|
|
878
935
|
if (!lengthOption) return ''
|
|
879
936
|
|
|
@@ -912,12 +969,12 @@ const filterHandlers = {
|
|
|
912
969
|
export function filtersToGroq(filters = [], selectedFilters = [], pageName = '') {
|
|
913
970
|
// Handle railcontent_id filters separately (they use different syntax)
|
|
914
971
|
const railcontentIdFilters = filters
|
|
915
|
-
.filter(item => item.includes('railcontent_id in'))
|
|
916
|
-
.map(item => ` && ${item}`)
|
|
972
|
+
.filter((item) => item.includes('railcontent_id in'))
|
|
973
|
+
.map((item) => ` && ${item}`)
|
|
917
974
|
.join('')
|
|
918
975
|
|
|
919
976
|
// Remove railcontent_id filters from main processing
|
|
920
|
-
const regularFilters = filters.filter(item => !item.includes('railcontent_id in'))
|
|
977
|
+
const regularFilters = filters.filter((item) => !item.includes('railcontent_id in'))
|
|
921
978
|
|
|
922
979
|
// Group filters by key
|
|
923
980
|
const groupedFilters = groupFilters(regularFilters)
|
|
@@ -940,7 +997,7 @@ export function filtersToGroq(filters = [], selectedFilters = [], pageName = '')
|
|
|
940
997
|
|
|
941
998
|
// Process each value with the appropriate handler
|
|
942
999
|
const joinedValues = values
|
|
943
|
-
.map(value => {
|
|
1000
|
+
.map((value) => {
|
|
944
1001
|
const handler = filterHandlers[key]
|
|
945
1002
|
|
|
946
1003
|
if (handler) {
|
package/src/index.d.ts
CHANGED
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
} from './services/content-org/guided-courses.ts';
|
|
14
14
|
|
|
15
15
|
import {
|
|
16
|
+
fetchLearningPathLessons,
|
|
16
17
|
getActivePath,
|
|
17
18
|
getDailySession,
|
|
18
19
|
updateActivePath,
|
|
@@ -459,6 +460,7 @@ declare module 'musora-content-services' {
|
|
|
459
460
|
fetchInterests,
|
|
460
461
|
fetchLastInteractedChild,
|
|
461
462
|
fetchLatestThreads,
|
|
463
|
+
fetchLearningPathLessons,
|
|
462
464
|
fetchLeaving,
|
|
463
465
|
fetchLessonContent,
|
|
464
466
|
fetchLessonsFeaturingThisContent,
|
package/src/index.js
CHANGED
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
} from './services/content-org/guided-courses.ts';
|
|
14
14
|
|
|
15
15
|
import {
|
|
16
|
+
fetchLearningPathLessons,
|
|
16
17
|
getActivePath,
|
|
17
18
|
getDailySession,
|
|
18
19
|
updateActivePath,
|
|
@@ -458,6 +459,7 @@ export {
|
|
|
458
459
|
fetchInterests,
|
|
459
460
|
fetchLastInteractedChild,
|
|
460
461
|
fetchLatestThreads,
|
|
462
|
+
fetchLearningPathLessons,
|
|
461
463
|
fetchLeaving,
|
|
462
464
|
fetchLessonContent,
|
|
463
465
|
fetchLessonsFeaturingThisContent,
|
package/src/lib/httpHelper.js
CHANGED
|
@@ -36,6 +36,11 @@ export async function fetchJSONHandler(
|
|
|
36
36
|
} else {
|
|
37
37
|
console.error(`Fetch error: ${method} ${url} ${response.status} ${response.statusText}`)
|
|
38
38
|
console.log(response)
|
|
39
|
+
const contentType = response.headers.get('content-type')
|
|
40
|
+
if (contentType && contentType.indexOf('json') !== -1) {
|
|
41
|
+
const data = await response.json()
|
|
42
|
+
console.log(data)
|
|
43
|
+
}
|
|
39
44
|
}
|
|
40
45
|
} catch (error) {
|
|
41
46
|
console.error('Fetch error:', error)
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { fetchHandler } from '../railcontent.js'
|
|
2
|
-
|
|
2
|
+
import { fetchByRailContentId, fetchByRailContentIds, fetchMethodV2Structure } from '../sanity.js'
|
|
3
|
+
import { addContextToContent } from '../contentAggregator.js'
|
|
4
|
+
import { getProgressStateByIds } from '../contentProgress.js'
|
|
3
5
|
/**
|
|
4
|
-
* @module
|
|
6
|
+
* @module LearningPaths
|
|
5
7
|
*/
|
|
6
8
|
const BASE_PATH: string = `/api/content-org`
|
|
7
9
|
|
|
@@ -23,7 +25,11 @@ export async function getDailySession(brand: string, userDate: Date) {
|
|
|
23
25
|
* @param userDate - format 2025-10-31
|
|
24
26
|
* @param keepFirstLearningPath
|
|
25
27
|
*/
|
|
26
|
-
export async function updateDailySession(
|
|
28
|
+
export async function updateDailySession(
|
|
29
|
+
brand: string,
|
|
30
|
+
userDate: Date,
|
|
31
|
+
keepFirstLearningPath: boolean
|
|
32
|
+
) {
|
|
27
33
|
const stringDate = userDate.toISOString().split('T')[0]
|
|
28
34
|
const url: string = `${BASE_PATH}/v1/user/learning-paths/daily-session/update`
|
|
29
35
|
const body = { brand: brand, userDate: stringDate, keepFirstLearningPath: keepFirstLearningPath }
|
|
@@ -49,3 +55,86 @@ export async function updateActivePath(brand: string) {
|
|
|
49
55
|
const body = { brand: brand }
|
|
50
56
|
return await fetchHandler(url, 'POST', null, body)
|
|
51
57
|
}
|
|
58
|
+
|
|
59
|
+
/** Fetches and organizes learning path lessons.
|
|
60
|
+
*
|
|
61
|
+
* @param {number} learningPathId - The learning path ID.
|
|
62
|
+
* @param {string} brand
|
|
63
|
+
* @param {Date} userDate - Users local date - format 2025-10-31
|
|
64
|
+
* @returns {Promise<Object>} result - The result object.
|
|
65
|
+
* @returns {number} result.id - The learning path ID.
|
|
66
|
+
* @returns {string} result.thumbnail - Optional thumbnail URL for the learning path.
|
|
67
|
+
* @returns {string} result.title - The title of the learning path.
|
|
68
|
+
* @returns {boolean} result.is_active_learning_path - Whether the learning path is currently active.
|
|
69
|
+
* @returns {Array} result.all_lessons - Array of all lessons.
|
|
70
|
+
* @returns {Array} result.upcoming_lessons - Array of upcoming/additional lessons.
|
|
71
|
+
* @returns {Array} result.todays_lessons - Array of today's lessons (max 3).
|
|
72
|
+
* @returns {Array} result.next_learning_path_lessons - Array of next lessons to be taken.
|
|
73
|
+
* @returns {Array} result.completed_lessons - Array of completed lessons.
|
|
74
|
+
*/
|
|
75
|
+
export async function fetchLearningPathLessons(
|
|
76
|
+
learningPathId: number,
|
|
77
|
+
brand: string,
|
|
78
|
+
userDate: Date
|
|
79
|
+
) {
|
|
80
|
+
const [learningPath, dailySession] = await Promise.all([
|
|
81
|
+
fetchByRailContentId(learningPathId, 'learning-path-v2'),
|
|
82
|
+
getDailySession(brand, userDate),
|
|
83
|
+
])
|
|
84
|
+
|
|
85
|
+
const addContextParameters = {
|
|
86
|
+
addProgressStatus: true,
|
|
87
|
+
addProgressPercentage: true,
|
|
88
|
+
}
|
|
89
|
+
const lessons = await addContextToContent(() => learningPath.children, addContextParameters)
|
|
90
|
+
const isActiveLearningPath = (dailySession?.active_learning_path_id || 0) == learningPathId
|
|
91
|
+
const todayContentIds = dailySession.daily_session[0]?.content_ids || []
|
|
92
|
+
const nextContentIds = dailySession.daily_session[1]?.content_ids || []
|
|
93
|
+
const completedLessons = []
|
|
94
|
+
let todaysLessons = []
|
|
95
|
+
let nextLPLessons = []
|
|
96
|
+
const upcomingLessons = []
|
|
97
|
+
const lessonIds = lessons.map((lesson: any) => lesson.id).filter(Boolean)
|
|
98
|
+
|
|
99
|
+
lessons.forEach((lesson: any) => {
|
|
100
|
+
if (todayContentIds.includes(lesson.id)) {
|
|
101
|
+
todaysLessons.push(lesson)
|
|
102
|
+
} else if (nextContentIds.includes(lesson.id)) {
|
|
103
|
+
nextLPLessons.push(lesson)
|
|
104
|
+
} else if (lesson.progressStatus === 'completed') {
|
|
105
|
+
completedLessons.push(lesson)
|
|
106
|
+
} else {
|
|
107
|
+
upcomingLessons.push(lesson)
|
|
108
|
+
}
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
if (todaysLessons.length == 0 && nextLPLessons.length > 0) {
|
|
112
|
+
// Daily sessions first lessons are not part of the active learning path, but next lessons are
|
|
113
|
+
// load todays lessons from previous learning path
|
|
114
|
+
todaysLessons = await addContextToContent(
|
|
115
|
+
fetchByRailContentIds,
|
|
116
|
+
todayContentIds,
|
|
117
|
+
addContextParameters
|
|
118
|
+
)
|
|
119
|
+
} else if (nextContentIds.length > 0 && nextLPLessons.length == 0 && todaysLessons.length > 0) {
|
|
120
|
+
// Daily sessions first lessons are the active learning path and the next lessons are not
|
|
121
|
+
// load next lessons from next learning path
|
|
122
|
+
nextLPLessons = await addContextToContent(
|
|
123
|
+
fetchByRailContentIds,
|
|
124
|
+
nextContentIds,
|
|
125
|
+
addContextParameters
|
|
126
|
+
)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return {
|
|
130
|
+
id: learningPathId,
|
|
131
|
+
thumbnail: learningPath.thumbnail,
|
|
132
|
+
title: learningPath.title || '',
|
|
133
|
+
is_active_learning_path: isActiveLearningPath,
|
|
134
|
+
all_lessons: lessons,
|
|
135
|
+
upcoming_lessons: upcomingLessons,
|
|
136
|
+
todays_lessons: todaysLessons,
|
|
137
|
+
next_learning_path_lessons: nextLPLessons,
|
|
138
|
+
completed_lessons: completedLessons,
|
|
139
|
+
}
|
|
140
|
+
}
|