musora-content-services 1.0.142 → 1.0.143

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/.github/workflows/node.js.yml +0 -0
  2. package/CHANGELOG.md +2 -0
  3. package/README.md +0 -0
  4. package/babel.config.js +0 -0
  5. package/docs/config.js.html +8 -4
  6. package/docs/fonts/Montserrat/Montserrat-Bold.eot +0 -0
  7. package/docs/fonts/Montserrat/Montserrat-Bold.ttf +0 -0
  8. package/docs/fonts/Montserrat/Montserrat-Bold.woff +0 -0
  9. package/docs/fonts/Montserrat/Montserrat-Bold.woff2 +0 -0
  10. package/docs/fonts/Montserrat/Montserrat-Regular.eot +0 -0
  11. package/docs/fonts/Montserrat/Montserrat-Regular.ttf +0 -0
  12. package/docs/fonts/Montserrat/Montserrat-Regular.woff +0 -0
  13. package/docs/fonts/Montserrat/Montserrat-Regular.woff2 +0 -0
  14. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.eot +0 -0
  15. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.svg +0 -0
  16. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.ttf +0 -0
  17. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff +0 -0
  18. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff2 +0 -0
  19. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.eot +0 -0
  20. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.svg +0 -0
  21. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.ttf +0 -0
  22. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff +0 -0
  23. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff2 +0 -0
  24. package/docs/index.html +2 -2
  25. package/docs/module-Config.html +30 -5
  26. package/docs/module-Railcontent-Services.html +2 -2
  27. package/docs/module-Sanity-Services.html +285 -46
  28. package/docs/railcontent.js.html +19 -2
  29. package/docs/sanity.js.html +79 -73
  30. package/docs/scripts/collapse.js +0 -0
  31. package/docs/scripts/commonNav.js +0 -0
  32. package/docs/scripts/linenumber.js +0 -0
  33. package/docs/scripts/nav.js +0 -0
  34. package/docs/scripts/polyfill.js +0 -0
  35. package/docs/scripts/prettify/Apache-License-2.0.txt +0 -0
  36. package/docs/scripts/prettify/lang-css.js +0 -0
  37. package/docs/scripts/prettify/prettify.js +0 -0
  38. package/docs/scripts/search.js +0 -0
  39. package/docs/styles/jsdoc.css +0 -0
  40. package/docs/styles/prettify.css +0 -0
  41. package/jest.config.js +0 -0
  42. package/jsdoc.json +0 -0
  43. package/package.json +1 -1
  44. package/src/contentMetaData.js +0 -0
  45. package/src/filterBuilder.js +0 -0
  46. package/src/index.d.ts +6 -0
  47. package/src/index.js +6 -0
  48. package/src/services/config.js +0 -0
  49. package/src/services/contentLikes.js +0 -0
  50. package/src/services/dataContext.js +0 -0
  51. package/src/services/railcontent.js +17 -0
  52. package/src/services/sanity.js +55 -71
  53. package/test/contentLikes.test.js +0 -0
  54. package/test/localStorageMock.js +0 -0
  55. package/test/log.js +0 -0
  56. package/test/sanityQueryService.test.js +0 -0
  57. package/tools/generate-index.js +0 -0
  58. package/test/playlists.test.js +0 -86
@@ -586,101 +586,84 @@ export function getSortOrder(sort= '-published_on', groupBy)
586
586
  }
587
587
 
588
588
  /**
589
- * Fetches all available filter options based on various criteria such as brand, filters, style, artist, content type, and search term.
589
+ * Fetches all available filter options based on brand, filters, and various optional criteria.
590
590
  *
591
591
  * This function constructs a query to retrieve the total number of results and filter options such as difficulty, instrument type, and genre.
592
592
  * The filter options are dynamically generated based on the provided filters, style, artist, and content type.
593
593
  * If a coachId is provided, the content type must be 'coach-lessons'.
594
594
  *
595
- * @param {string} brand - The brand for which to fetch the filter options.
596
- * @param {string[]} filters - Additional filters to apply to the query in the format of a key,value array. eg. ['difficulty,Intermediate', 'genre,rock']
597
- * @param {string} [style] - Optional style or genre to filter the results. If provided, the query will check if the style exists in the genre array.
598
- * @param {string} [artist] - Optional artist name to filter the results. If provided, the query will check if the artist's name matches.
599
- * @param {string} contentType - The content type to fetch (e.g., 'song', 'lesson').
600
- * @param {string} [term] - Optional search term to match against various fields such as title, album, artist name, and genre.
601
- * @param {Array<string>} [progressIds=undefined] - An array of railcontent IDs to filter the results by. Used for filtering by progress.
602
- * @param {string} [coachId=undefined] - Optional coach ID to filter the results by a specific coach. If provided, contentType must be 'coach-lessons'.
603
- * @returns {Promise<Object|null>} - A promise that resolves to an object containing the total results and filter options, or null if the query fails.
595
+ * @param {string} brand - Brand to filter.
596
+ * @param {string[]} filters - Key-value pairs to filter the query.
597
+ * @param {string} [style] - Optional style/genre filter.
598
+ * @param {string} [artist] - Optional artist name filter.
599
+ * @param {string} contentType - Content type (e.g., 'song', 'lesson').
600
+ * @param {string} [term] - Optional search term for title, album, artist, or genre.
601
+ * @param {Array<string>} [progressIds] - Optional array of progress IDs to filter by.
602
+ * @param {string} [coachId] - Optional coach ID (only valid if contentType is 'coach-lessons').
603
+ * @param {boolean} [includeTabs=false] - Whether to include tabs in the returned metadata.
604
+ * @returns {Promise<Object>} - The filter options and metadata.
605
+ * @throws {Error} If coachId is provided but contentType isn't 'coach-lessons'.
604
606
  *
605
- * @throws {Error} Will throw an error if coachId is provided but contentType is not 'coach-lessons'.
606
- *
607
607
  * @example
608
- * // Example usage:
609
- * fetchAllFilterOptions('myBrand', '', 'Rock', 'John Doe', 'song', 'Love')
608
+ * // Fetch filter options for 'song' content type:
609
+ * fetchAllFilterOptions('myBrand', [], 'Rock', 'John Doe', 'song', 'Love')
610
610
  * .then(options => console.log(options))
611
611
  * .catch(error => console.error(error));
612
612
  *
613
613
  * @example
614
- * // Example usage with coachId:
615
- * fetchAllFilterOptions('myBrand', '', 'Rock', 'John Doe', 'coach-lessons', 'Love', undefined, '123')
614
+ * // Fetch filter options for a coach's lessons with coachId:
615
+ * fetchAllFilterOptions('myBrand', [], 'Rock', 'John Doe', 'coach-lessons', 'Love', undefined, '123')
616
616
  * .then(options => console.log(options))
617
617
  * .catch(error => console.error(error));
618
618
  */
619
619
  export async function fetchAllFilterOptions(
620
- brand,
621
- filters = [],
622
- style,
623
- artist,
624
- contentType,
625
- term,
626
- progressIds = undefined,
627
- coachId = undefined, // New parameter for coach ID
620
+ brand,
621
+ filters = [],
622
+ style,
623
+ artist,
624
+ contentType,
625
+ term,
626
+ progressIds,
627
+ coachId,
628
+ includeTabs = false,
628
629
  ) {
629
- console.log('brand', brand)
630
- if (coachId && contentType !== 'coach-lessons') {
631
- throw new Error(`Invalid contentType: '${contentType}' for coachId. It must be 'coach-lessons'.`);
632
- }
633
-
634
- filters = Array.isArray(filters) ? filters : [];
635
- const includedFieldsFilter = filters?.length > 0 ? filtersToGroq(filters) : undefined;
636
-
637
- const progressFilter = progressIds !== undefined ?
638
- `&& railcontent_id in [${progressIds.join(',')}]` : "";
630
+ if (coachId && contentType !== 'coach-lessons') {
631
+ throw new Error(`Invalid contentType: '${contentType}' for coachId. It must be 'coach-lessons'.`);
632
+ }
639
633
 
640
- // General common filter logic
641
- let commonFilter;
634
+ const includedFieldsFilter = filters?.length ? filtersToGroq(filters) : undefined;
635
+ const progressFilter = progressIds ? `&& railcontent_id in [${progressIds.join(',')}]` : "";
642
636
 
643
- if (coachId) {
644
- // Coach-specific filtering
645
- commonFilter = `brand == '${brand}' && references(*[_type=='instructor' && railcontent_id == ${coachId}]._id) ${includedFieldsFilter ? includedFieldsFilter : ''}`;
646
- } else {
647
- // Regular content filtering
648
- commonFilter = `_type == '${contentType}' && brand == "${brand}"${style ? ` && '${style}' in genre[]->name` : ''}${artist ? ` && artist->name == '${artist}'` : ''} ${progressFilter} ${includedFieldsFilter ? includedFieldsFilter : ''}`;
649
- }
637
+ const constructCommonFilter = (excludeFilter) => {
638
+ const filterWithoutOption = excludeFilter ? filtersToGroq(filters, excludeFilter) : includedFieldsFilter;
639
+ return coachId
640
+ ? `brand == '${brand}' && references(*[_type=='instructor' && railcontent_id == ${coachId}]._id) ${filterWithoutOption || ''}`
641
+ : `_type == '${contentType}' && brand == "${brand}"${style && excludeFilter !== "style" ? ` && '${style}' in genre[]->name` : ''}${artist && excludeFilter !== "artist" ? ` && artist->name == '${artist}'` : ''} ${progressFilter} ${filterWithoutOption || ''}`;
642
+ };
650
643
 
651
- // Determine metadata and allowable filters (handle coach lessons if coachId exists)
652
- const metaData = processMetadata(brand, contentType, true);
653
- const allowableFilters = metaData?.allowableFilters || [];
644
+ const metaData = processMetadata(brand, contentType, true);
645
+ const allowableFilters = metaData?.allowableFilters || [];
646
+ const tabs = metaData?.tabs || [];
654
647
 
655
- // Dynamic filter options construction
656
- const dynamicFilterOptions = allowableFilters.map(filter => {
657
- let includedFieldsFilterWithoutSelectedOption = filters?.length > 0 ? filtersToGroq(filters, filter) : undefined;
658
- let commonFilterWithoutSelectedOption;
648
+ const dynamicFilterOptions = allowableFilters.map(filter => getFilterOptions(filter, constructCommonFilter(filter), contentType, brand)).join(' ');
659
649
 
660
- if (coachId) {
661
- commonFilterWithoutSelectedOption = `brand == '${brand}' && references(*[_type=='instructor' && railcontent_id == ${coachId}]._id) ${includedFieldsFilterWithoutSelectedOption ? includedFieldsFilterWithoutSelectedOption : ''}`;
662
- } else {
663
- // Regular content filter without the selected option
664
- commonFilterWithoutSelectedOption = `_type == '${contentType}' && brand == "${brand}"${(style && filter !== "style") ? ` && '${style}' in genre[]->name` : ''}${(artist && filter !== "artist") ? ` && artist->name == '${artist}'` : ''} ${includedFieldsFilterWithoutSelectedOption ? includedFieldsFilterWithoutSelectedOption : ''}`;
665
- }
650
+ const query = `
651
+ {
652
+ "meta": {
653
+ "totalResults": count(*[${constructCommonFilter()}
654
+ ${term ? ` && (title match "${term}" || album match "${term}" || artist->name match "${term}" || genre[]->name match "${term}")` : ''}]),
655
+ "filterOptions": {
656
+ ${dynamicFilterOptions}
657
+ }
658
+ }
659
+ }`;
666
660
 
667
- // Call getFilterOptions with the modified common filter
668
- return getFilterOptions(filter, commonFilterWithoutSelectedOption, contentType, brand);
669
- }).join(' ');
661
+ const results = await fetchSanity(query, true, { processNeedAccess: false });
670
662
 
671
- const query = `
672
- {
673
- "meta": {
674
- "totalResults": count(*[${commonFilter}
675
- ${term ? ` && (title match "${term}" || album match "${term}" || artist->name match "${term}" || genre[]->name match "${term}")` : ''}]),
676
- "filterOptions": {
677
- ${dynamicFilterOptions}
678
- }
679
- }
680
- }`;
681
- return fetchSanity(query, true, {processNeedAccess:false});
663
+ return includeTabs ? { ...results, tabs } : results;
682
664
  }
683
665
 
666
+
684
667
  /**
685
668
  * Fetch children content by Railcontent ID.
686
669
  * @param {string} railcontentId - The Railcontent ID of the parent content.
@@ -961,7 +944,8 @@ export async function fetchLessonContent(railContentId) {
961
944
  mp3_yes_drums_yes_click_url,
962
945
  "permission_id": permission[]->railcontent_id,
963
946
  parent_content_data,
964
- sort`;
947
+ sort,
948
+ xp`;
965
949
  const query = buildQuery(
966
950
  `railcontent_id == ${railContentId}`,
967
951
  filterParams,
File without changes
File without changes
package/test/log.js CHANGED
File without changes
File without changes
File without changes
@@ -1,86 +0,0 @@
1
- import {isContentLiked, dataContext, likeContent, unlikeContent} from "../src/services/contentLikes";
2
- import {LocalStorageMock} from "./localStorageMock";
3
- import {initializeService} from "../src";
4
-
5
- const railContentModule = require('../src/services/railcontent.js')
6
-
7
- describe('playlistsContext', function () {
8
- let mock = null;
9
- const testVersion = 1;
10
-
11
- beforeEach(() => {
12
- initializeService({localStorage: new LocalStorageMock()});
13
- mock = jest.spyOn(dataContext, 'fetchData');
14
- var json = JSON.parse(`{"version":${testVersion},"data":[308516,308515,308514,308518]}`);
15
- mock.mockImplementation(() => json);
16
- });
17
-
18
- test('contentLiked', async () => {
19
- let result = await isContentLiked(308516);
20
- expect(result).toBe(true);
21
- });
22
-
23
- test('contentNotLiked', async () => {
24
- let result = await isContentLiked(121111);
25
- expect(result).toBe(false);
26
- });
27
-
28
- test('ensureOnlyOneServerFetchRequest', async () => {
29
- dataContext.clearCache();
30
- await isContentLiked(308516);
31
- await isContentLiked(308514);
32
- await isContentLiked(121111);
33
- expect(dataContext.fetchData).toHaveBeenCalledTimes(1);
34
- });
35
-
36
- test('ensureDataPulledFromLocalCache', async () => {
37
- dataContext.clearCache();
38
- await isContentLiked(308516);
39
- dataContext.clearContext();
40
- await isContentLiked(308514);
41
- expect(dataContext.fetchData).toHaveBeenCalledTimes(1);
42
- });
43
-
44
- test('likeContent', async () => {
45
- mock = jest.spyOn(railContentModule, 'postContentLiked');
46
- var json = JSON.parse(`{"version":${testVersion + 1}}`);
47
- mock.mockImplementation(() => json);
48
-
49
- dataContext.clearCache();
50
- let isLiked = await isContentLiked(111111);
51
- expect(isLiked).toBe(false);
52
-
53
- await likeContent(111111);
54
- isLiked = await isContentLiked(111111);
55
- expect(isLiked).toBe(true);
56
-
57
- dataContext.clearContext();
58
- isLiked = await isContentLiked(111111);
59
- expect(isLiked).toBe(true);
60
-
61
- expect(dataContext.version()).toBe(testVersion + 1);
62
- });
63
-
64
-
65
- test('unlikeContent', async () => {
66
- mock = jest.spyOn(railContentModule, 'postContentUnliked');
67
- var json = JSON.parse(`{"version":${testVersion + 1}}`);
68
- mock.mockImplementation(() => json);
69
-
70
- dataContext.clearCache();
71
- let isLiked = await isContentLiked(308516);
72
- expect(isLiked).toBe(true);
73
-
74
- await unlikeContent(308516);
75
- console.log(dataContext.context);
76
- isLiked = await isContentLiked(308516);
77
- expect(isLiked).toBe(false);
78
-
79
- dataContext.clearContext();
80
- isLiked = await isContentLiked(308516);
81
- expect(isLiked).toBe(false);
82
-
83
- expect(dataContext.version()).toBe(testVersion + 1);
84
- });
85
-
86
- });