musora-content-services 1.0.59 → 1.0.62
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 +6 -0
- package/docs/config.js.html +2 -2
- package/docs/index.html +2 -2
- package/docs/module-Config.html +2 -2
- package/docs/module-Railcontent-Services.html +2 -2
- package/docs/module-Sanity-Services.html +851 -97
- package/docs/railcontent.js.html +2 -2
- package/docs/sanity.js.html +189 -150
- package/package.json +1 -1
- package/src/contentTypeConfig.js +71 -2
- package/src/index.d.ts +6 -2
- package/src/index.js +10 -2
- package/src/services/sanity.js +181 -141
- package/test/sanityQueryService.test.js +78 -13
package/src/index.d.ts
CHANGED
|
@@ -14,8 +14,10 @@ import {
|
|
|
14
14
|
fetchByRailContentIds,
|
|
15
15
|
fetchAll,
|
|
16
16
|
fetchAllFilterOptions,
|
|
17
|
+
fetchMethods,
|
|
18
|
+
fetchMethod,
|
|
17
19
|
fetchMethodNextLesson,
|
|
18
|
-
|
|
20
|
+
fetchMethodChildrenIds,
|
|
19
21
|
fetchNextPreviousLesson,
|
|
20
22
|
fetchRelatedLessons,
|
|
21
23
|
fetchPackAll,
|
|
@@ -43,8 +45,10 @@ declare module 'musora-content-services' {
|
|
|
43
45
|
fetchByRailContentIds,
|
|
44
46
|
fetchAll,
|
|
45
47
|
fetchAllFilterOptions,
|
|
48
|
+
fetchMethods,
|
|
49
|
+
fetchMethod,
|
|
46
50
|
fetchMethodNextLesson,
|
|
47
|
-
|
|
51
|
+
fetchMethodChildrenIds,
|
|
48
52
|
fetchNextPreviousLesson,
|
|
49
53
|
fetchRelatedLessons,
|
|
50
54
|
fetchPackAll,
|
package/src/index.js
CHANGED
|
@@ -16,14 +16,18 @@ import {
|
|
|
16
16
|
fetchAll,
|
|
17
17
|
fetchAllFilterOptions,
|
|
18
18
|
fetchMethodNextLesson,
|
|
19
|
+
fetchMethod,
|
|
19
20
|
fetchMethods,
|
|
20
|
-
|
|
21
|
+
fetchMethodChildrenIds,
|
|
21
22
|
fetchNextPreviousLesson,
|
|
22
23
|
fetchRelatedLessons,
|
|
23
24
|
fetchPackAll,
|
|
24
25
|
fetchPackChildren,
|
|
25
26
|
fetchLessonContent,
|
|
26
27
|
fetchCourseOverview,
|
|
28
|
+
fetchChildren,
|
|
29
|
+
fetchParentByRailContentId,
|
|
30
|
+
fetchMethodPreviousNextLesson,
|
|
27
31
|
} from './services/sanity.js';
|
|
28
32
|
|
|
29
33
|
import {
|
|
@@ -50,8 +54,9 @@ export {
|
|
|
50
54
|
fetchAll,
|
|
51
55
|
fetchAllFilterOptions,
|
|
52
56
|
fetchMethods,
|
|
57
|
+
fetchMethod,
|
|
53
58
|
fetchMethodNextLesson,
|
|
54
|
-
|
|
59
|
+
fetchMethodChildrenIds,
|
|
55
60
|
fetchNextPreviousLesson,
|
|
56
61
|
fetchRelatedLessons,
|
|
57
62
|
fetchPackAll,
|
|
@@ -61,4 +66,7 @@ export {
|
|
|
61
66
|
fetchAllCompletedStates,
|
|
62
67
|
fetchContentInProgress,
|
|
63
68
|
fetchCourseOverview,
|
|
69
|
+
fetchChildren,
|
|
70
|
+
fetchParentByRailContentId,
|
|
71
|
+
fetchMethodPreviousNextLesson,
|
|
64
72
|
}
|
package/src/services/sanity.js
CHANGED
|
@@ -1,23 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @module Sanity-Services
|
|
3
3
|
*/
|
|
4
|
-
import {contentTypeConfig} from "../contentTypeConfig";
|
|
4
|
+
import {assignmentsField, contentTypeConfig, DEFAULT_FIELDS, getFieldsForContentType} from "../contentTypeConfig";
|
|
5
5
|
import {globalConfig} from "./config";
|
|
6
6
|
|
|
7
7
|
import { fetchAllCompletedStates, fetchCurrentSongComplete } from './railcontent.js';
|
|
8
8
|
|
|
9
|
-
const DEFAULT_FIELDS = [
|
|
10
|
-
'"id": railcontent_id',
|
|
11
|
-
'railcontent_id',
|
|
12
|
-
'"type": _type',
|
|
13
|
-
'title',
|
|
14
|
-
'"image": thumbnail.asset->url',
|
|
15
|
-
'difficulty',
|
|
16
|
-
'difficulty_string',
|
|
17
|
-
'web_url_path',
|
|
18
|
-
'published_on'
|
|
19
|
-
];
|
|
20
|
-
|
|
21
9
|
/**
|
|
22
10
|
* Fetch a song by its document ID from Sanity.
|
|
23
11
|
*
|
|
@@ -30,25 +18,10 @@ const DEFAULT_FIELDS = [
|
|
|
30
18
|
* .catch(error => console.error(error));
|
|
31
19
|
*/
|
|
32
20
|
export async function fetchSongById(documentId) {
|
|
33
|
-
const fields = [
|
|
34
|
-
'"id": railcontent_id',
|
|
35
|
-
'railcontent_id',
|
|
36
|
-
'"type": _type',
|
|
37
|
-
'description',
|
|
38
|
-
'title',
|
|
39
|
-
'"thumbnail_url": thumbnail.asset->url',
|
|
40
|
-
'"style": genre[0]->name',
|
|
41
|
-
'"artist": artist->name',
|
|
42
|
-
'album',
|
|
43
|
-
'instrumentless',
|
|
44
|
-
'soundslice',
|
|
45
|
-
'"resources": resource[]{resource_url, resource_name}',
|
|
46
|
-
'"url": web_url_path',
|
|
47
|
-
];
|
|
48
21
|
|
|
49
22
|
const query = `
|
|
50
23
|
*[_type == "song" && railcontent_id == ${documentId}]{
|
|
51
|
-
${
|
|
24
|
+
${getFieldsForContentType('song', true)}
|
|
52
25
|
}`;
|
|
53
26
|
|
|
54
27
|
return fetchSanity(query, false);
|
|
@@ -249,10 +222,10 @@ export async function fetchSongCount(brand) {
|
|
|
249
222
|
* Fetch the latest workouts for a specific brand, including completion status and progress.
|
|
250
223
|
* This function retrieves up to five of the latest workout content for a given brand, sorted in descending order by their publication date.
|
|
251
224
|
* It also includes completion status and progress percentage for each workout by fetching additional data about user progress.
|
|
252
|
-
*
|
|
225
|
+
*
|
|
253
226
|
* @param {string} brand - The brand for which to fetch workouts (e.g., 'drumeo', 'pianote').
|
|
254
227
|
* @returns {Promise<Array<Object>|null>} - A promise that resolves to an array of workout data objects with additional properties for completion status and progress percentage, or null if no workouts are found.
|
|
255
|
-
*
|
|
228
|
+
*
|
|
256
229
|
* @example
|
|
257
230
|
* fetchWorkouts('drumeo')
|
|
258
231
|
* .then(workouts => console.log(workouts))
|
|
@@ -263,12 +236,12 @@ export async function fetchWorkouts(brand) {
|
|
|
263
236
|
"id": railcontent_id,
|
|
264
237
|
title,
|
|
265
238
|
"image": thumbnail.asset->url,
|
|
266
|
-
|
|
267
|
-
|
|
239
|
+
${artistOrInstructor()},
|
|
240
|
+
${artistOrInstructorAsArray()},
|
|
268
241
|
difficulty,
|
|
269
242
|
difficulty_string,
|
|
270
243
|
length_in_seconds,
|
|
271
|
-
published_on
|
|
244
|
+
published_on,;
|
|
272
245
|
"type": _type,
|
|
273
246
|
web_url_path,
|
|
274
247
|
} | order(published_on desc)[0...5]`
|
|
@@ -356,17 +329,9 @@ export async function fetchUpcomingEvents(brand) {
|
|
|
356
329
|
* .then(content => console.log(content))
|
|
357
330
|
* .catch(error => console.error(error));
|
|
358
331
|
*/
|
|
359
|
-
export async function fetchByRailContentId(id) {
|
|
332
|
+
export async function fetchByRailContentId(id, contentType) {
|
|
360
333
|
const query = `*[railcontent_id == ${id}]{
|
|
361
|
-
|
|
362
|
-
title,
|
|
363
|
-
"image": thumbnail.asset->url,
|
|
364
|
-
"artist_name": artist->name,
|
|
365
|
-
artist,
|
|
366
|
-
difficulty,
|
|
367
|
-
difficulty_string,
|
|
368
|
-
web_url_path,
|
|
369
|
-
published_on
|
|
334
|
+
${getFieldsForContentType(contentType)}
|
|
370
335
|
}`
|
|
371
336
|
return fetchSanity(query, false);
|
|
372
337
|
}
|
|
@@ -384,10 +349,9 @@ export async function fetchByRailContentId(id) {
|
|
|
384
349
|
* .catch(error => console.error(error));
|
|
385
350
|
*/
|
|
386
351
|
export async function fetchByRailContentIds(ids, contentType = undefined) {
|
|
387
|
-
const fields = contentType ? DEFAULT_FIELDS.concat(contentTypeConfig?.[contentType]?.fields ?? []) : DEFAULT_FIELDS;
|
|
388
352
|
const idsString = ids.join(',');
|
|
389
353
|
const query = `*[railcontent_id in [${idsString}]]{
|
|
390
|
-
${
|
|
354
|
+
${getFieldsForContentType(contentType)}
|
|
391
355
|
}`
|
|
392
356
|
return fetchSanity(query, true);
|
|
393
357
|
}
|
|
@@ -448,37 +412,7 @@ export async function fetchAll(brand, type, {
|
|
|
448
412
|
: "";
|
|
449
413
|
|
|
450
414
|
// Determine the sort order
|
|
451
|
-
|
|
452
|
-
switch (sort) {
|
|
453
|
-
case "slug":
|
|
454
|
-
if(groupBy){
|
|
455
|
-
sortOrder = "name asc";
|
|
456
|
-
} else {
|
|
457
|
-
sortOrder = "title asc";
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
break;
|
|
461
|
-
case "published_on":
|
|
462
|
-
sortOrder = "published_on asc";
|
|
463
|
-
break;
|
|
464
|
-
case "-published_on":
|
|
465
|
-
sortOrder = "published_on desc";
|
|
466
|
-
break;
|
|
467
|
-
case "-slug":
|
|
468
|
-
if(groupBy){
|
|
469
|
-
sortOrder = "name desc";
|
|
470
|
-
} else {
|
|
471
|
-
sortOrder = "title desc";
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
break;
|
|
475
|
-
case "-popularity":
|
|
476
|
-
sortOrder = "popularity desc";
|
|
477
|
-
break;
|
|
478
|
-
default:
|
|
479
|
-
sortOrder = "published_on asc";
|
|
480
|
-
break;
|
|
481
|
-
}
|
|
415
|
+
const sortOrder = getSortOrder(sort);
|
|
482
416
|
|
|
483
417
|
let fields = DEFAULT_FIELDS.concat(additionalFields);
|
|
484
418
|
let fieldsString = fields.join(',');
|
|
@@ -537,6 +471,28 @@ export async function fetchAll(brand, type, {
|
|
|
537
471
|
return fetchSanity(query, true);
|
|
538
472
|
}
|
|
539
473
|
|
|
474
|
+
export function getSortOrder(sort= '-published_on', groupBy)
|
|
475
|
+
{
|
|
476
|
+
// Determine the sort order
|
|
477
|
+
let sortOrder = '';
|
|
478
|
+
const isDesc = sort.startsWith('-');
|
|
479
|
+
sort = isDesc ? sort.substring(1) : sort;
|
|
480
|
+
switch (sort) {
|
|
481
|
+
case "slug":
|
|
482
|
+
sortOrder = groupBy ? 'name' : "title";
|
|
483
|
+
break;
|
|
484
|
+
case "popularity":
|
|
485
|
+
sortOrder = "popularity";
|
|
486
|
+
break;
|
|
487
|
+
case "published_on":
|
|
488
|
+
default:
|
|
489
|
+
sortOrder = "published_on";
|
|
490
|
+
break;
|
|
491
|
+
}
|
|
492
|
+
sortOrder += isDesc ? ' desc' : ' asc';
|
|
493
|
+
return sortOrder;
|
|
494
|
+
}
|
|
495
|
+
|
|
540
496
|
/**
|
|
541
497
|
* Fetches all available filter options based on various criteria such as brand, filters, style, artist, content type, and search term.
|
|
542
498
|
*
|
|
@@ -574,10 +530,10 @@ export async function fetchAllFilterOptions(
|
|
|
574
530
|
return `&& ${key} == "${value}"`;
|
|
575
531
|
}).join(' ')
|
|
576
532
|
: undefined;
|
|
577
|
-
|
|
533
|
+
|
|
578
534
|
const commonFilter = `_type == '${contentType}' && brand == "${brand}"${style ? ` && '${style}' in genre[]->name` : ''}${artist ? ` && artist->name == '${artist}'` : ''} ${filtersToGroq ? filtersToGroq : ''}`;
|
|
579
535
|
const query = `
|
|
580
|
-
{
|
|
536
|
+
{
|
|
581
537
|
"meta": {
|
|
582
538
|
"totalResults": count(*[${commonFilter}
|
|
583
539
|
${term ? ` && (title match "${term}" || album match "${term}" || artist->name match "${term}" || genre[]->name match "${term}")` : ''}]),
|
|
@@ -606,22 +562,33 @@ export async function fetchAllFilterOptions(
|
|
|
606
562
|
/**
|
|
607
563
|
* Fetch children content by Railcontent ID.
|
|
608
564
|
* @param {string} railcontentId - The Railcontent ID of the parent content.
|
|
609
|
-
* @returns {Promise<Array<Object>|null>} - The fetched children content data or
|
|
565
|
+
* @returns {Promise<Array<Object>|null>} - The fetched children content data or [] if not found.
|
|
610
566
|
*/
|
|
611
567
|
export async function fetchChildren(railcontentId) {
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
568
|
+
const query = `*[railcontent_id == ${railcontentId}]{
|
|
569
|
+
'children': child[]->{
|
|
570
|
+
${getFieldsForContentType()}
|
|
571
|
+
},
|
|
572
|
+
}[0..1]`;
|
|
573
|
+
let parent = await fetchSanity(query, true);
|
|
574
|
+
return parent[0]['children'] ?? [];
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
/**
|
|
578
|
+
*
|
|
579
|
+
* @param railcontentId - railcontent id of the child
|
|
580
|
+
* @returns {Promise<Array<string>|null>} - The fetched parent content data or [] if not found
|
|
581
|
+
*/
|
|
582
|
+
export async function fetchParentByRailContentId(railcontentId) {
|
|
583
|
+
const query = `*[railcontent_id == ${railcontentId}]{
|
|
584
|
+
'parents': array::unique([
|
|
585
|
+
...(*[references(^._id)]{
|
|
586
|
+
${getFieldsForContentType()}
|
|
587
|
+
})
|
|
588
|
+
])
|
|
589
|
+
}[0...1]`;
|
|
590
|
+
let child = await fetchSanity(query, true);
|
|
591
|
+
return child[0]['parents'][0] ?? [];
|
|
625
592
|
}
|
|
626
593
|
|
|
627
594
|
/**
|
|
@@ -633,50 +600,76 @@ export async function fetchMethods(brand) {
|
|
|
633
600
|
//TODOS
|
|
634
601
|
//ADD INSTRUCTORS AND POSITION
|
|
635
602
|
const query = `*[_type == 'learning-path' && brand == '${brand}'] {
|
|
636
|
-
|
|
637
|
-
difficulty_string,
|
|
638
|
-
"description": description[0].children[0].text,
|
|
639
|
-
hide_from_recsys,
|
|
640
|
-
"image": thumbnail.asset->url,
|
|
641
|
-
"instructors":instructor[]->name,
|
|
642
|
-
"lesson_count": child_count,
|
|
643
|
-
length_in_seconds,
|
|
644
|
-
permission,
|
|
645
|
-
popularity,
|
|
603
|
+
${getFieldsForContentType('method')}
|
|
646
604
|
"position": count(*[_type == 'learning-path' && brand == '${brand}' && (published_on < ^.published_on || (published_on == ^.published_on && _id < ^._id))]) + 1,
|
|
647
|
-
|
|
648
|
-
railcontent_id,
|
|
649
|
-
"slug": slug.current,
|
|
650
|
-
status,
|
|
651
|
-
"thumbnail_logo": logo_image_url.asset->url,
|
|
652
|
-
title,
|
|
653
|
-
total_xp,
|
|
654
|
-
"type": _type,
|
|
655
|
-
"url": web_url_path,
|
|
656
|
-
xp
|
|
657
|
-
}`
|
|
605
|
+
} | order(published_on asc)`
|
|
658
606
|
return fetchSanity(query, true);
|
|
659
607
|
}
|
|
660
608
|
|
|
609
|
+
/**
|
|
610
|
+
* Fetch the Method (learning-paths) for a specific brand.
|
|
611
|
+
* @param {string} brand - The brand for which to fetch methods.
|
|
612
|
+
* @param {string} slug - The slug of the method.
|
|
613
|
+
* @returns {Promise<Object|null>} - The fetched methods data or null if not found.
|
|
614
|
+
*/
|
|
615
|
+
export async function fetchMethod(brand, slug) {
|
|
616
|
+
const query = `*[_type == 'learning-path' && brand == "${brand}" && slug.current == "${slug}"] {
|
|
617
|
+
"description": description[0].children[0].text,
|
|
618
|
+
"instructors":instructor[]->name,
|
|
619
|
+
published_on,
|
|
620
|
+
"id": railcontent_id,
|
|
621
|
+
railcontent_id,
|
|
622
|
+
"slug": slug.current,
|
|
623
|
+
status,
|
|
624
|
+
title,
|
|
625
|
+
video,
|
|
626
|
+
"type": _type,
|
|
627
|
+
"levels": child[]->
|
|
628
|
+
{
|
|
629
|
+
"id": railcontent_id,
|
|
630
|
+
published_on,
|
|
631
|
+
"thumbnail_url": thumbnail.asset->url,
|
|
632
|
+
"instructor": instructor[]->{name},
|
|
633
|
+
title,
|
|
634
|
+
"description": description[0].children[0].text,
|
|
635
|
+
}
|
|
636
|
+
} | order(published_on asc)`
|
|
637
|
+
return fetchSanity(query, false);
|
|
638
|
+
}
|
|
639
|
+
|
|
661
640
|
/**
|
|
662
641
|
* Fetch the next lesson for a specific method by Railcontent ID.
|
|
663
642
|
* @param {string} railcontentId - The Railcontent ID of the current lesson.
|
|
643
|
+
* @param {string} methodId - The RailcontentID of the method
|
|
664
644
|
* @returns {Promise<Object|null>} - The fetched next lesson data or null if not found.
|
|
665
645
|
*/
|
|
666
|
-
export async function fetchMethodNextLesson(railcontentId) {
|
|
667
|
-
|
|
668
|
-
const
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
646
|
+
export async function fetchMethodNextLesson(railcontentId, methodId) {
|
|
647
|
+
const sortedChildren = await fetchMethodChildrenIds(methodId);
|
|
648
|
+
const index = sortedChildren.indexOf(railcontentId);
|
|
649
|
+
const childIndex = sortedChildren[index + 1];
|
|
650
|
+
return childIndex ? await fetchByRailContentId(childIndex) : null;
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
|
|
654
|
+
/**
|
|
655
|
+
* Fetch the next lesson for a specific method by Railcontent ID.
|
|
656
|
+
* @param {string} railcontentId - The Railcontent ID of the current lesson.
|
|
657
|
+
* @param {string} methodId - The RailcontentID of the method
|
|
658
|
+
* @returns {Promise<Object|null>} - object with `nextLesson` and `previousLesson` attributes
|
|
659
|
+
* @example
|
|
660
|
+
* fetchMethodPreviousNextLesson(241284, 241247)
|
|
661
|
+
* .then(data => { console.log('nextLesson', data.nextLesson); console.log('prevlesson', data.prevLesson);})
|
|
662
|
+
* .catch(error => console.error(error));
|
|
663
|
+
*/
|
|
664
|
+
export async function fetchMethodPreviousNextLesson(railcontentId, methodId) {
|
|
665
|
+
const sortedChildren = await fetchMethodChildrenIds(methodId);
|
|
666
|
+
const index = sortedChildren.indexOf(railcontentId);
|
|
667
|
+
let nextId = sortedChildren[index + 1];
|
|
668
|
+
let previousId = sortedChildren[index -1];
|
|
669
|
+
let nextPrev = await fetchByRailContentIds([nextId, previousId]);
|
|
670
|
+
const nextLesson = nextPrev.find((elem) => {return elem['id'] === nextId});
|
|
671
|
+
const prevLesson = nextPrev.find((elem) => {return elem['id'] === previousId});
|
|
672
|
+
return {nextLesson, prevLesson};
|
|
680
673
|
}
|
|
681
674
|
|
|
682
675
|
/**
|
|
@@ -684,11 +677,37 @@ export async function fetchMethodNextLesson(railcontentId) {
|
|
|
684
677
|
* @param {string} railcontentId - The Railcontent ID of the method.
|
|
685
678
|
* @returns {Promise<Array<Object>|null>} - The fetched children data or null if not found.
|
|
686
679
|
*/
|
|
687
|
-
export async function
|
|
680
|
+
export async function fetchMethodChildrenIds(railcontentId) {
|
|
688
681
|
//TODO: Implement getByParentId include sum XP
|
|
689
|
-
|
|
682
|
+
const query = `*[_type == 'learning-path' && railcontent_id == ${railcontentId}]{
|
|
683
|
+
'children': child[]-> {
|
|
684
|
+
'id': railcontent_id,
|
|
685
|
+
'children': child[]-> {
|
|
686
|
+
'id': railcontent_id,
|
|
687
|
+
'children': child[]-> {
|
|
688
|
+
'id': railcontent_id,
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
}`;
|
|
693
|
+
let allChildren = await fetchSanity(query, false);
|
|
694
|
+
return getChildrenToDepth(allChildren, 4);;
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
function getChildrenToDepth(parent, depth = 1)
|
|
698
|
+
{
|
|
699
|
+
let allChildrenIds = [];
|
|
700
|
+
if (parent['children']) {
|
|
701
|
+
parent['children'].forEach((child) => {
|
|
702
|
+
allChildrenIds.push(child['id']);
|
|
703
|
+
allChildrenIds = allChildrenIds.concat(getChildrenToDepth(child, depth-1));
|
|
704
|
+
})
|
|
705
|
+
}
|
|
706
|
+
return allChildrenIds;
|
|
690
707
|
}
|
|
691
708
|
|
|
709
|
+
|
|
710
|
+
|
|
692
711
|
/**
|
|
693
712
|
* Fetch the next and previous lessons for a specific lesson by Railcontent ID.
|
|
694
713
|
* @param {string} railcontentId - The Railcontent ID of the current lesson.
|
|
@@ -727,22 +746,15 @@ export async function fetchLessonContent(railContentId) {
|
|
|
727
746
|
chapter_description,
|
|
728
747
|
chapter_timecode,
|
|
729
748
|
"chapter_thumbnail_url": chapter_thumbnail_url.asset->url
|
|
730
|
-
},
|
|
749
|
+
},
|
|
731
750
|
"coaches": instructor[]-> {
|
|
732
|
-
name,
|
|
751
|
+
name,
|
|
733
752
|
"id":_id,
|
|
734
753
|
"coach_profile_image":thumbnail_url.asset->url
|
|
735
754
|
},
|
|
736
755
|
"instructors":instructor[]->name,
|
|
737
756
|
instructor[]->,
|
|
738
|
-
|
|
739
|
-
"id": railcontent_id,
|
|
740
|
-
"soundslice_slug": assignment_soundslice,
|
|
741
|
-
"title": assignment_title,
|
|
742
|
-
"sheet_music_image_url": assignment_sheet_music_image,
|
|
743
|
-
"timecode": assignment_timecode,
|
|
744
|
-
"description": assignment_description
|
|
745
|
-
},
|
|
757
|
+
${assignmentsField}
|
|
746
758
|
video}`
|
|
747
759
|
return fetchSanity(query, false);
|
|
748
760
|
}
|
|
@@ -808,7 +820,7 @@ export async function fetchPackChildren(railcontentId) {
|
|
|
808
820
|
* Fetch the data needed for the Course Overview screen.
|
|
809
821
|
* @param {string} id - The Railcontent ID of the course
|
|
810
822
|
* @returns {Promise<Object|null>} - The course information and lessons or null if not found.
|
|
811
|
-
*
|
|
823
|
+
*
|
|
812
824
|
* @example
|
|
813
825
|
* fetchCourseOverview('course123')
|
|
814
826
|
* .then(course => console.log(course))
|
|
@@ -893,6 +905,32 @@ export async function fetchSanity(query, isList) {
|
|
|
893
905
|
}
|
|
894
906
|
}
|
|
895
907
|
|
|
908
|
+
/**
|
|
909
|
+
* Fetch CatalogueMetadata from Sanity. This information may be duplicated in the contentTypeConfig.js.
|
|
910
|
+
* It's an ongoing discussion (Aug 2024), but it's been included here if necessary
|
|
911
|
+
*
|
|
912
|
+
* @param {string} contentType - name of the contentype to pull
|
|
913
|
+
* @returns {Promise<Object|null>} - A promise that resolves to the fetched data or null if an error occurs or no results are found.
|
|
914
|
+
*
|
|
915
|
+
* @example
|
|
916
|
+
*
|
|
917
|
+
* fetchCatalogMetadata('song')
|
|
918
|
+
* .then(data => console.log(data))
|
|
919
|
+
* .catch(error => console.error(error));
|
|
920
|
+
*/
|
|
921
|
+
export async function fetchCatalogMetadata(contentType)
|
|
922
|
+
{ const query = `*[_type == 'CatalogMetadata']{
|
|
923
|
+
catalog_type,
|
|
924
|
+
brand,
|
|
925
|
+
groq_results,
|
|
926
|
+
groq_search_fields,
|
|
927
|
+
meta_data_groq,
|
|
928
|
+
modal_text,
|
|
929
|
+
sort_by,
|
|
930
|
+
}`
|
|
931
|
+
return fetchSanity(query, false);
|
|
932
|
+
}
|
|
933
|
+
|
|
896
934
|
|
|
897
935
|
//Helper Functions
|
|
898
936
|
function arrayJoinWithQuotes(array, delimiter = ',') {
|
|
@@ -923,3 +961,5 @@ function checkSanityConfig(config) {
|
|
|
923
961
|
}
|
|
924
962
|
return true;
|
|
925
963
|
}
|
|
964
|
+
|
|
965
|
+
|
|
@@ -16,12 +16,17 @@ const {
|
|
|
16
16
|
fetchAll,
|
|
17
17
|
fetchAllFilterOptions,
|
|
18
18
|
fetchMethodNextLesson,
|
|
19
|
-
|
|
19
|
+
fetchMethodChildrenIds,
|
|
20
20
|
fetchNextPreviousLesson,
|
|
21
21
|
fetchRelatedLessons,
|
|
22
22
|
fetchPackAll,
|
|
23
23
|
fetchPackChildren,
|
|
24
|
-
fetchLessonContent
|
|
24
|
+
fetchLessonContent,
|
|
25
|
+
getSortOrder,
|
|
26
|
+
fetchParentByRailContentId,
|
|
27
|
+
fetchChildren,
|
|
28
|
+
fetchMethod,
|
|
29
|
+
fetchMethods,
|
|
25
30
|
} = require('../src/services/sanity.js');
|
|
26
31
|
|
|
27
32
|
describe('Sanity Queries', function () {
|
|
@@ -42,7 +47,7 @@ describe('Sanity Queries', function () {
|
|
|
42
47
|
test('fetchSongById', async () => {
|
|
43
48
|
const id = 380094;
|
|
44
49
|
const response = await fetchSongById(id);
|
|
45
|
-
expect(response.
|
|
50
|
+
expect(response.id).toBe(id);
|
|
46
51
|
|
|
47
52
|
});
|
|
48
53
|
|
|
@@ -62,14 +67,14 @@ describe('Sanity Queries', function () {
|
|
|
62
67
|
test('fetchByRailContentId', async () => {
|
|
63
68
|
const id = 380094;
|
|
64
69
|
const response = await fetchByRailContentId(id);
|
|
65
|
-
expect(response.
|
|
70
|
+
expect(response.id).toBe(id);
|
|
66
71
|
});
|
|
67
72
|
|
|
68
73
|
test('fetchByRailContentIds', async () => {
|
|
69
74
|
const id = 380094;
|
|
70
75
|
const id2 = 402204;
|
|
71
76
|
const response = await fetchByRailContentIds([id, id2]);
|
|
72
|
-
const returnedIds = response.map((x) => x.
|
|
77
|
+
const returnedIds = response.map((x) => x.id);
|
|
73
78
|
expect(returnedIds).toContain(id);
|
|
74
79
|
expect(returnedIds).toContain(id2);
|
|
75
80
|
expect(returnedIds.length).toBe(2);
|
|
@@ -79,7 +84,7 @@ describe('Sanity Queries', function () {
|
|
|
79
84
|
test('fetchLessonContent', async () => {
|
|
80
85
|
const id = 380094;
|
|
81
86
|
const response = await fetchLessonContent(id);
|
|
82
|
-
expect(response.
|
|
87
|
+
expect(response.id).toBe(id);
|
|
83
88
|
});
|
|
84
89
|
|
|
85
90
|
test('fetchAllSongs', async () => {
|
|
@@ -101,7 +106,7 @@ describe('Sanity Queries', function () {
|
|
|
101
106
|
test('fetchAllWorkouts', async () => {
|
|
102
107
|
const response = await fetchAll('drumeo', 'workout',{});
|
|
103
108
|
console.log(response);
|
|
104
|
-
expect(response.entity[0].
|
|
109
|
+
expect(response.entity[0].id).toBeDefined();
|
|
105
110
|
});
|
|
106
111
|
|
|
107
112
|
test('fetchAllChallenges', async () => {
|
|
@@ -117,10 +122,70 @@ describe('Sanity Queries', function () {
|
|
|
117
122
|
expect(response.entity[0].challenge_state_text).toBeDefined();
|
|
118
123
|
|
|
119
124
|
});
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
125
|
+
|
|
126
|
+
test('fetchRelatedLessons', async () => {
|
|
127
|
+
const id = 380094;
|
|
128
|
+
const document = await fetchByRailContentId(id);
|
|
129
|
+
let artist = document.artist.name;
|
|
130
|
+
const response = await fetchRelatedLessons(id, 'singeo', 'song');
|
|
131
|
+
let relatedDoc = await fetchByRailContentId(response.related_lessons[0].id);
|
|
132
|
+
// match on artist or any genre
|
|
133
|
+
let isMatch = artist === relatedDoc.artist.name;
|
|
134
|
+
isMatch = isMatch || document.genre.some((genre) => {
|
|
135
|
+
return relatedDoc.genre.some((relatedGenre) => {
|
|
136
|
+
return genre._ref === relatedGenre._ref;
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
expect(isMatch).toBeTruthy();
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
test('fetchChildren', async () => {
|
|
143
|
+
// complement test to fetchParentByRailContentId
|
|
144
|
+
const id = 191338; ////https://web-staging-one.musora.com/admin/studio/publishing/structure/play-along;play-along_191338
|
|
145
|
+
const expectedChildID = 191492;
|
|
146
|
+
const response = await fetchChildren(id);
|
|
147
|
+
console.log('num children', response.length);
|
|
148
|
+
console.log(response);
|
|
149
|
+
|
|
150
|
+
expect(response.length > 0).toBeTruthy();
|
|
151
|
+
const foundExpectedChild = response.some((child) => {
|
|
152
|
+
return child['id'] = expectedChildID;
|
|
153
|
+
});
|
|
154
|
+
expect(foundExpectedChild).toBeTruthy();
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
test('fetchParentByRailContentId', async () => {
|
|
158
|
+
// complement test to fetchChildren
|
|
159
|
+
const childId = 191492; // child of https://web-staging-one.musora.com/admin/studio/publishing/structure/play-along;play-along_191338
|
|
160
|
+
const expectedParent = 191338;
|
|
161
|
+
const response = await fetchParentByRailContentId(childId);
|
|
162
|
+
expect(response['id']).toBe(expectedParent);
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
test('getSortOrder', () => {
|
|
166
|
+
let sort = getSortOrder()
|
|
167
|
+
expect(sort).toBe('published_on desc');
|
|
168
|
+
sort = getSortOrder('slug')
|
|
169
|
+
expect(sort).toBe('title asc');
|
|
170
|
+
sort = getSortOrder('-slug')
|
|
171
|
+
expect(sort).toBe('title desc');
|
|
172
|
+
sort = getSortOrder('-slug', true)
|
|
173
|
+
expect(sort).toBe('name desc');
|
|
174
|
+
sort = getSortOrder('published-on')
|
|
175
|
+
expect(sort).toBe('published_on asc');
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
test('fetchMethod', async () => {
|
|
179
|
+
const response = await fetchMethod('drumeo', 'drumeo-method');
|
|
180
|
+
//console.log(response);
|
|
181
|
+
expect(response).toBeDefined();
|
|
182
|
+
expect(response.levels.length).toBeGreaterThan(0);
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
test('fetchMethods', async () => {
|
|
186
|
+
const response = await fetchMethods('drumeo');
|
|
187
|
+
//console.log(response);
|
|
188
|
+
expect(response.length).toBeGreaterThan(0);
|
|
189
|
+
expect(response[0].type).toBe('learning-path');
|
|
190
|
+
});
|
|
126
191
|
});
|