musora-content-services 1.0.121 → 1.0.123

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 (52) hide show
  1. package/.github/workflows/node.js.yml +0 -0
  2. package/CHANGELOG.md +4 -0
  3. package/README.md +0 -0
  4. package/babel.config.js +0 -0
  5. package/docs/config.js.html +7 -3
  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 +1 -1
  25. package/docs/module-Config.html +28 -3
  26. package/docs/module-Railcontent-Services.html +7 -7
  27. package/docs/module-Sanity-Services.html +426 -48
  28. package/docs/railcontent.js.html +37 -47
  29. package/docs/sanity.js.html +69 -12
  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/link_mcs.sh +0 -0
  44. package/package.json +1 -1
  45. package/src/contentMetaData.js +11 -0
  46. package/src/contentTypeConfig.js +6 -2
  47. package/src/services/railcontent.js +0 -2
  48. package/src/services/sanity.js +66 -11
  49. package/test/localStorageMock.js +0 -0
  50. package/test/log.js +0 -0
  51. package/test/sanityQueryService.test.js +39 -0
  52. package/tools/generate-index.js +0 -0
@@ -49,7 +49,7 @@
49
49
  * @module Railcontent-Services
50
50
  */
51
51
 
52
- const { globalConfig } = require('./config');
52
+ const {globalConfig} = require('./config');
53
53
 
54
54
 
55
55
  /**
@@ -71,10 +71,11 @@ export async function fetchCompletedState(content_id) {
71
71
  };
72
72
 
73
73
  try {
74
- const response = await fetchAbsolute(url, { headers });
74
+ const response = await fetchAbsolute(url, {headers});
75
75
  const result = await response.json();
76
76
 
77
- if (result && result[content_id]) { return result[content_id]; // Return the correct object
77
+ if (result && result[content_id]) {
78
+ return result[content_id]; // Return the correct object
78
79
  } else {
79
80
  return null; // Handle unexpected structure
80
81
  }
@@ -103,7 +104,7 @@ export async function fetchVimeoData(vimeo_id) {
103
104
  };
104
105
 
105
106
  try {
106
- const response = await fetchAbsolute(url, { headers });
107
+ const response = await fetchAbsolute(url, {headers});
107
108
  const result = await response.json();
108
109
 
109
110
  if (result) {
@@ -138,9 +139,9 @@ export async function fetchAllCompletedStates(contentIds) {
138
139
  };
139
140
 
140
141
  try {
141
- const response = await fetchAbsolute(url, { headers });
142
+ const response = await fetchAbsolute(url, {headers});
142
143
  const result = await response.json();
143
- if(result){
144
+ if (result) {
144
145
  return result;
145
146
  } else {
146
147
  console.log('result not json');
@@ -170,9 +171,9 @@ export async function fetchSongsInProgress(brand) {
170
171
  };
171
172
 
172
173
  try {
173
- const response = await fetchAbsolute(url, { headers });
174
+ const response = await fetchAbsolute(url, {headers});
174
175
  const result = await response.json();
175
- if(result){
176
+ if (result) {
176
177
  //console.log('fetchSongsInProgress', result);
177
178
  return result;
178
179
  } else {
@@ -197,12 +198,12 @@ export async function fetchSongsInProgress(brand) {
197
198
  * .then(songs => console.log(songs))
198
199
  * .catch(error => console.error(error));
199
200
  */
200
- export async function fetchContentInProgress(type="all", brand, { page, limit } = {}) {
201
+ export async function fetchContentInProgress(type = "all", brand, {page, limit} = {}) {
201
202
  let url;
202
203
  const limitString = limit ? `&limit=${limit}` : '';
203
204
  const pageString = page ? `&page=${page}` : '';
204
205
 
205
- if(type === "all") {
206
+ if (type === "all") {
206
207
  url = `/content/in_progress/${globalConfig.railcontentConfig.userId}?brand=${brand}${limitString}${pageString}`;
207
208
  } else {
208
209
  url = `/content/in_progress/${globalConfig.railcontentConfig.userId}?content_type=${type}&brand=${brand}${limitString}${pageString}`;
@@ -212,9 +213,9 @@ export async function fetchContentInProgress(type="all", brand, { page, limit }
212
213
  'X-CSRF-TOKEN': globalConfig.railcontentConfig.token
213
214
  };
214
215
  try {
215
- const response = await fetchAbsolute(url, { headers });
216
+ const response = await fetchAbsolute(url, {headers});
216
217
  const result = await response.json();
217
- if(result){
218
+ if (result) {
218
219
  //console.log('contentInProgress', result);
219
220
  return result;
220
221
  } else {
@@ -239,12 +240,12 @@ export async function fetchContentInProgress(type="all", brand, { page, limit }
239
240
  * .then(songs => console.log(songs))
240
241
  * .catch(error => console.error(error));
241
242
  */
242
- export async function fetchCompletedContent(type="all", brand, { page, limit } = {}) {
243
+ export async function fetchCompletedContent(type = "all", brand, {page, limit} = {}) {
243
244
  let url;
244
245
  const limitString = limit ? `&limit=${limit}` : '';
245
246
  const pageString = page ? `&page=${page}` : '';
246
247
 
247
- if(type === "all") {
248
+ if (type === "all") {
248
249
  url = `/content/completed/${globalConfig.railcontentConfig.userId}?brand=${brand}${limitString}${pageString}`;
249
250
  } else {
250
251
  url = `/content/completed/${globalConfig.railcontentConfig.userId}?content_type=${type}&brand=${brand}${limitString}${pageString}`;
@@ -254,9 +255,9 @@ export async function fetchCompletedContent(type="all", brand, { page, limit } =
254
255
  'X-CSRF-TOKEN': globalConfig.railcontentConfig.token
255
256
  };
256
257
  try {
257
- const response = await fetchAbsolute(url, { headers });
258
+ const response = await fetchAbsolute(url, {headers});
258
259
  const result = await response.json();
259
- if(result){
260
+ if (result) {
260
261
  //console.log('completed content', result);
261
262
  return result;
262
263
  } else {
@@ -286,32 +287,11 @@ export async function fetchContentPageUserData(contentId) {
286
287
  'X-CSRF-TOKEN': globalConfig.railcontentConfig.token
287
288
  };
288
289
 
289
- try {
290
- const response = await fetchAbsolute(url, { headers });
291
- const result = await response.json();
292
- if(result){
293
- console.log('fetchContentPageUserData', result);
294
- return result;
295
- } else {
296
- console.log('result not json');
297
- }
298
- } catch (error) {
299
- console.error('Fetch error:', error);
300
- return null;
301
- }
302
- }
303
-
304
- export async function fetchUserContext() {
305
- let url = `/content/user_data_all`;
306
- const headers = {
307
- 'Content-Type': 'application/json',
308
- 'X-CSRF-TOKEN': globalConfig.railcontentConfig.token
309
- };
310
290
  try {
311
291
  const response = await fetchAbsolute(url, {headers});
312
292
  const result = await response.json();
313
293
  if (result) {
314
- console.log('fetchUserContext', result);
294
+ console.log('fetchContentPageUserData', result);
315
295
  return result;
316
296
  } else {
317
297
  console.log('result not json');
@@ -334,11 +314,16 @@ export async function fetchUserPermissions() {
334
314
  return fetchHandler(url, 'get') ?? [];
335
315
  }
336
316
 
337
- export async function fetchHandler(url, method = "get") {
338
- const headers = {
317
+ async function fetchDataHandler(url, dataVersion, method = "get") {
318
+ return fetchHandler(url, method, dataVersion);
319
+ }
320
+
321
+ export async function fetchHandler(url, method = "get", dataVersion = null) {
322
+ let headers = {
339
323
  'Content-Type': 'application/json',
340
- 'X-CSRF-TOKEN': globalConfig.railcontentConfig.token
324
+ 'X-CSRF-TOKEN': globalConfig.railcontentConfig.token,
341
325
  };
326
+ if (dataVersion) headers['Data-Version'] = dataVersion;
342
327
  try {
343
328
  const response = await fetchAbsolute(url, {method, headers});
344
329
  const result = await response.json();
@@ -353,18 +338,23 @@ export async function fetchHandler(url, method = "get") {
353
338
  return null;
354
339
  }
355
340
 
356
- export async function fetchLikeContent(contentId) {
357
- let url = `/content/${contentId}/like`;
341
+ export async function fetchUserLikes(currentVersion) {
342
+ let url = `/content/user/likes/all`;
343
+ return fetchDataHandler(url, currentVersion);
344
+ }
345
+
346
+ export async function postContentLiked(contentId) {
347
+ let url = `/content/user/likes/like/${contentId}`;
358
348
  return await fetchHandler(url, "post");
359
349
  }
360
350
 
361
- export async function fetchUnlikeContent(contentId) {
362
- let url = `/content/${contentId}/unlike`;
351
+ export async function postContentUnliked(contentId) {
352
+ let url = `/content/user/likes/unlike/${contentId}`;
363
353
  return await fetchHandler(url, "post");
364
354
  }
365
355
 
366
356
  function fetchAbsolute(url, params) {
367
- if(globalConfig.railcontentConfig.baseUrl) {
357
+ if (globalConfig.railcontentConfig.baseUrl) {
368
358
  if (url.startsWith('/')) {
369
359
  return fetch(globalConfig.railcontentConfig.baseUrl + url, params)
370
360
  }
@@ -384,7 +374,7 @@ function fetchAbsolute(url, params) {
384
374
  <br class="clear">
385
375
 
386
376
  <footer>
387
- Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.3</a> on Fri Sep 27 2024 21:58:51 GMT+0000 (Coordinated Universal Time) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
377
+ Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.3</a> on Wed Oct 02 2024 12:20:08 GMT+0000 (Coordinated Universal Time) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
388
378
  </footer>
389
379
 
390
380
  <script>prettyPrint();</script>
@@ -60,6 +60,7 @@ import {
60
60
  getUpcomingEventsTypes,
61
61
  showsTypes,
62
62
  getNewReleasesTypes,
63
+ coachLessonsTypes
63
64
  } from "../contentTypeConfig";
64
65
 
65
66
  import {
@@ -623,6 +624,7 @@ export function getSortOrder(sort= '-published_on', groupBy)
623
624
  *
624
625
  * This function constructs a query to retrieve the total number of results and filter options such as difficulty, instrument type, and genre.
625
626
  * The filter options are dynamically generated based on the provided filters, style, artist, and content type.
627
+ * If a coachId is provided, the content type must be 'coach-lessons'.
626
628
  *
627
629
  * @param {string} brand - The brand for which to fetch the filter options.
628
630
  * @param {string[]} filters - Additional filters to apply to the query in the format of a key,value array. eg. ['difficulty,Intermediate', 'genre,rock']
@@ -631,13 +633,22 @@ export function getSortOrder(sort= '-published_on', groupBy)
631
633
  * @param {string} contentType - The content type to fetch (e.g., 'song', 'lesson').
632
634
  * @param {string} [term] - Optional search term to match against various fields such as title, album, artist name, and genre.
633
635
  * @param {Array&lt;string>} [progressIds=undefined] - An array of railcontent IDs to filter the results by. Used for filtering by progress.
636
+ * @param {string} [coachId=undefined] - Optional coach ID to filter the results by a specific coach. If provided, contentType must be 'coach-lessons'.
634
637
  * @returns {Promise&lt;Object|null>} - A promise that resolves to an object containing the total results and filter options, or null if the query fails.
635
638
  *
639
+ * @throws {Error} Will throw an error if coachId is provided but contentType is not 'coach-lessons'.
640
+ *
636
641
  * @example
637
642
  * // Example usage:
638
643
  * fetchAllFilterOptions('myBrand', '', 'Rock', 'John Doe', 'song', 'Love')
639
644
  * .then(options => console.log(options))
640
645
  * .catch(error => console.error(error));
646
+ *
647
+ * @example
648
+ * // Example usage with coachId:
649
+ * fetchAllFilterOptions('myBrand', '', 'Rock', 'John Doe', 'coach-lessons', 'Love', undefined, '123')
650
+ * .then(options => console.log(options))
651
+ * .catch(error => console.error(error));
641
652
  */
642
653
  export async function fetchAllFilterOptions(
643
654
  brand,
@@ -646,25 +657,48 @@ export async function fetchAllFilterOptions(
646
657
  artist,
647
658
  contentType,
648
659
  term,
649
- progressIds = undefined
660
+ progressIds = undefined,
661
+ coachId = undefined, // New parameter for coach ID
650
662
  ) {
663
+ if (coachId &amp;&amp; contentType !== 'coach-lessons') {
664
+ throw new Error(`Invalid contentType: '${contentType}' for coachId. It must be 'coach-lessons'.`);
665
+ }
666
+
651
667
  filters = Array.isArray(filters) ? filters : [];
652
668
  const includedFieldsFilter = filters?.length > 0 ? filtersToGroq(filters) : undefined;
653
669
 
654
670
  const progressFilter = progressIds !== undefined ?
655
671
  `&amp;&amp; railcontent_id in [${progressIds.join(',')}]` : "";
656
672
 
657
- const commonFilter = `_type == '${contentType}' &amp;&amp; brand == "${brand}"${style ? ` &amp;&amp; '${style}' in genre[]->name` : ''}${artist ? ` &amp;&amp; artist->name == '${artist}'` : ''} ${progressFilter} ${includedFieldsFilter ? includedFieldsFilter : ''}`;
673
+ // General common filter logic
674
+ let commonFilter;
675
+
676
+ if (coachId) {
677
+ // Coach-specific filtering
678
+ commonFilter = `brand == '${brand}' &amp;&amp; references(*[_type=='instructor' &amp;&amp; railcontent_id == ${coachId}]._id) ${includedFieldsFilter ? includedFieldsFilter : ''}`;
679
+ } else {
680
+ // Regular content filtering
681
+ commonFilter = `_type == '${contentType}' &amp;&amp; brand == "${brand}"${style ? ` &amp;&amp; '${style}' in genre[]->name` : ''}${artist ? ` &amp;&amp; artist->name == '${artist}'` : ''} ${progressFilter} ${includedFieldsFilter ? includedFieldsFilter : ''}`;
682
+ }
683
+
684
+ // Determine metadata and allowable filters (handle coach lessons if coachId exists)
658
685
  const metaData = processMetadata(brand, contentType, true);
659
686
  const allowableFilters = metaData?.allowableFilters || [];
660
687
 
688
+ // Dynamic filter options construction
661
689
  const dynamicFilterOptions = allowableFilters.map(filter => {
662
- // Create a modified common filter for each allowable filter
663
690
  let includedFieldsFilterWithoutSelectedOption = filters?.length > 0 ? filtersToGroq(filters, filter) : undefined;
664
- const commonFilterWithoutSelectedOption = `_type == '${contentType}' &amp;&amp; brand == "${brand}"${(style &amp;&amp; filter !== "style") ? ` &amp;&amp; '${style}' in genre[]->name` : ''}${(artist &amp;&amp; filter !== "artist") ? ` &amp;&amp; artist->name == '${artist}'` : ''} ${includedFieldsFilterWithoutSelectedOption ? includedFieldsFilterWithoutSelectedOption : ''}`;
691
+ let commonFilterWithoutSelectedOption;
692
+
693
+ if (coachId) {
694
+ commonFilterWithoutSelectedOption = `brand == '${brand}' &amp;&amp; references(*[_type=='instructor' &amp;&amp; railcontent_id == ${coachId}]._id) ${includedFieldsFilterWithoutSelectedOption ? includedFieldsFilterWithoutSelectedOption : ''}`;
695
+ } else {
696
+ // Regular content filter without the selected option
697
+ commonFilterWithoutSelectedOption = `_type == '${contentType}' &amp;&amp; brand == "${brand}"${(style &amp;&amp; filter !== "style") ? ` &amp;&amp; '${style}' in genre[]->name` : ''}${(artist &amp;&amp; filter !== "artist") ? ` &amp;&amp; artist->name == '${artist}'` : ''} ${includedFieldsFilterWithoutSelectedOption ? includedFieldsFilterWithoutSelectedOption : ''}`;
698
+ }
665
699
 
666
700
  // Call getFilterOptions with the modified common filter
667
- return getFilterOptions(filter, commonFilterWithoutSelectedOption, contentType);
701
+ return getFilterOptions(filter, commonFilterWithoutSelectedOption, contentType, brand);
668
702
  }).join(' ');
669
703
 
670
704
  const query = `
@@ -920,7 +954,7 @@ export async function fetchLessonContent(railContentId) {
920
954
  "thumbnail_url":thumbnail.asset->url,
921
955
  "url": web_url_path,
922
956
  soundslice_slug,
923
- description,
957
+ "description": description[0].children[0].text,
924
958
  "chapters": chapter[]{
925
959
  chapter_description,
926
960
  chapter_timecode,
@@ -936,6 +970,7 @@ export async function fetchLessonContent(railContentId) {
936
970
  "id":_id,
937
971
  name,
938
972
  short_bio,
973
+ "biography": short_bio[0].children[0].text,
939
974
  web_url_path,
940
975
  "coach_card_image": coach_card_image.asset->url,
941
976
  },
@@ -983,7 +1018,7 @@ export async function fetchRelatedLessons(railContentId, brand) {
983
1018
  * Fetch related method lessons for a specific lesson by RailContent ID and type.
984
1019
  * @param {string} railContentId - The RailContent ID of the current lesson.
985
1020
  * @param {string} brand - The current brand.
986
- * @returns {Promise&lt;Object>|null>} - The fetched related lessons
1021
+ * @returns {Promise&lt;Array&lt;Object>|null>} - The fetched related lessons
987
1022
  */
988
1023
  export async function fetchRelatedMethodLessons(railContentId, brand) {
989
1024
  const query = `*[railcontent_id == ${railContentId} &amp;&amp; brand == "${brand}"]{
@@ -1119,6 +1154,8 @@ export async function fetchChallengeOverview(id) {
1119
1154
  difficulty_string,
1120
1155
  difficulty,
1121
1156
  "type": _type,
1157
+ is_always_unlocked,
1158
+ is_bonus_content,
1122
1159
  }
1123
1160
  } [0...1]`;
1124
1161
  return fetchSanity(query, false);
@@ -1126,8 +1163,15 @@ export async function fetchChallengeOverview(id) {
1126
1163
 
1127
1164
  /**
1128
1165
  * Fetch the data needed for the coach screen.
1166
+ * @param {string} brand - The brand for which to fetch coach lessons
1129
1167
  * @param {string} id - The Railcontent ID of the coach
1130
1168
  * @returns {Promise&lt;Object|null>} - The lessons for the instructor or null if not found.
1169
+ * @param {Object} params - Parameters for pagination, filtering and sorting.
1170
+ * @param {string} [params.sortOrder="-published_on"] - The field to sort the lessons by.
1171
+ * @param {string} [params.searchTerm=""] - The search term to filter content by title.
1172
+ * @param {number} [params.page=1] - The page number for pagination.
1173
+ * @param {number} [params.limit=10] - The number of items per page.
1174
+ * @param {Array&lt;string>} [params.includedFields=[]] - Additional filters to apply to the query in the format of a key,value array. eg. ['difficulty,Intermediate', 'genre,rock'].
1131
1175
  *
1132
1176
  * @example
1133
1177
  * fetchCoachLessons('coach123')
@@ -1139,12 +1183,17 @@ export async function fetchCoachLessons(brand, id, {
1139
1183
  searchTerm = '',
1140
1184
  page = 1,
1141
1185
  limit = 20,
1186
+ includedFields = [],
1142
1187
  } = {}) {
1143
1188
  const fieldsString = getFieldsForContentType();
1144
1189
  const start = (page - 1) * limit;
1145
1190
  const end = start + limit;
1146
1191
  const searchFilter = searchTerm ? `&amp;&amp; title match "${searchTerm}*"`: ''
1147
- const filter = `brand == '${brand}' ${searchFilter} &amp;&amp; references(*[_type=='instructor' &amp;&amp; railcontent_id == ${id}]._id)`;
1192
+ const includedFieldsFilter = includedFields.length > 0
1193
+ ? filtersToGroq(includedFields)
1194
+ : "";
1195
+ const filter = `brand == '${brand}' ${searchFilter} ${includedFieldsFilter} &amp;&amp; references(*[_type=='instructor' &amp;&amp; railcontent_id == ${id}]._id)`;
1196
+
1148
1197
  sortOrder = getSortOrder(sortOrder);
1149
1198
  const query = buildEntityAndTotalQuery(
1150
1199
  filter,
@@ -1418,7 +1467,7 @@ export async function fetchCatalogMetadata(contentType)
1418
1467
  * Fetch shows data for a brand.
1419
1468
  *
1420
1469
  * @param brand - The brand for which to fetch shows.
1421
- * @returns {Promise&lt;[]>}
1470
+ * @returns {Promise&lt;{name, description, type: *, thumbnailUrl}>}
1422
1471
  *
1423
1472
  * @example
1424
1473
  *
@@ -1552,8 +1601,10 @@ function buildEntityAndTotalQuery(
1552
1601
  }
1553
1602
 
1554
1603
 
1555
- function getFilterOptions(option, commonFilter,contentType){
1604
+ function getFilterOptions(option, commonFilter,contentType, brand){
1556
1605
  let filterGroq = '';
1606
+ const types = Array.from(new Set([...coachLessonsTypes,...showsTypes[brand]]));
1607
+
1557
1608
  switch (option) {
1558
1609
  case "difficulty":
1559
1610
  filterGroq = `
@@ -1565,6 +1616,12 @@ function getFilterOptions(option, commonFilter,contentType){
1565
1616
  {"type": "Expert", "count": count(*[${commonFilter} &amp;&amp; difficulty_string == "Expert" ])}
1566
1617
  ][count > 0],`;
1567
1618
  break;
1619
+ case "type":
1620
+ const dynamicTypeOptions = types.map(filter => {
1621
+ return `{"type": "${filter}", "count": count(*[${commonFilter} &amp;&amp; _type == "${filter}"])}`
1622
+ }).join(', ');
1623
+ filterGroq = `"type": [${dynamicTypeOptions}][count > 0],`;
1624
+ break;
1568
1625
  case "genre":
1569
1626
  case "essential":
1570
1627
  case "focus":
@@ -1573,7 +1630,7 @@ function getFilterOptions(option, commonFilter,contentType){
1573
1630
  case "lifestyle":
1574
1631
  case "creativity":
1575
1632
  filterGroq = `
1576
- "${option}": *[_type == '${option}' &amp;&amp; '${contentType}' in filter_types] {
1633
+ "${option}": *[_type == '${option}' ${contentType ? ` &amp;&amp; '${contentType}' in filter_types` : ''} ] {
1577
1634
  "type": name,
1578
1635
  "count": count(*[${commonFilter} &amp;&amp; references(^._id)])
1579
1636
  }[count > 0],`;
@@ -1652,7 +1709,7 @@ function cleanUpGroq(query) {
1652
1709
  <br class="clear">
1653
1710
 
1654
1711
  <footer>
1655
- Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.3</a> on Fri Sep 27 2024 21:58:51 GMT+0000 (Coordinated Universal Time) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
1712
+ Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.3</a> on Wed Oct 02 2024 12:20:08 GMT+0000 (Coordinated Universal Time) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
1656
1713
  </footer>
1657
1714
 
1658
1715
  <script>prettyPrint();</script>
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
package/jest.config.js CHANGED
File without changes
package/jsdoc.json CHANGED
File without changes
package/link_mcs.sh CHANGED
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "musora-content-services",
3
- "version": "1.0.121",
3
+ "version": "1.0.123",
4
4
  "description": "A package for Musoras content services ",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
@@ -192,6 +192,9 @@ const commonMetadata ={
192
192
  ],
193
193
  modalText: 'Workouts are fun play-along lessons that help hone your musical skills. They cover various topics, and have multiple difficulty and duration options — so there’s always a perfect Workout for you. Just pick one, press start, and play along!',
194
194
  },
195
+ 'coach-lessons':{
196
+ allowableFilters: ['difficulty', 'genre', 'essential','theory','lifestyle','type'],
197
+ }
195
198
  }
196
199
  const contentMetadata = {
197
200
  'drumeo': {
@@ -703,6 +706,14 @@ const contentMetadata = {
703
706
  'pack': {
704
707
  allowableFilters: ['difficulty', 'genre', 'essential', 'theory', 'lifestyle'],
705
708
  },
709
+ 'odd-times': {
710
+ thumbnailUrl: 'https://musora.com/cdn-cgi/imagedelivery/0Hon__GSkIjm-B_W77SWCA/1bf6fc7a-d1a5-4934-d322-b9f6da454000/public',
711
+ name: 'Odd Times With Aaron Edgar',
712
+ shortname: 'Episodes',
713
+ icon: 'icon-shows',
714
+ allowableFilters: [],
715
+ sortBy: 'sort',
716
+ },
706
717
  },
707
718
  'pianote':{
708
719
  'instructor': {
@@ -44,7 +44,7 @@ const contentWithSortField = {
44
44
  ]
45
45
  }
46
46
  const showsTypes = {
47
- 'drumeo': ['drum-fest-international-2022', 'spotlight', 'the-history-of-electronic-drums', 'backstage-secret', 'quick-tips', 'question-and-answer', 'student-collaboration',
47
+ 'drumeo': ['odd-times','drum-fest-international-2022', 'spotlight', 'the-history-of-electronic-drums', 'backstage-secret', 'quick-tips', 'question-and-answer', 'student-collaboration',
48
48
  'live', 'podcast', 'solo', 'boot-camp', 'gear-guide', 'performance', 'in-rhythm', 'challenges', 'on-the-road', 'diy-drum-experiment', 'rhythmic-adventures-of-captain-carson',
49
49
  'study-the-greats', 'rhythms-from-another-planet', 'tama', 'paiste-cymbals', 'behind-the-scenes', 'exploring-beats', 'sonor'
50
50
  ],
@@ -53,6 +53,7 @@ const showsTypes = {
53
53
  'singeo': ['student-review', 'question-and-answer']
54
54
  }
55
55
 
56
+ const coachLessonsTypes = ['course', 'course-part', 'coach-stream', 'student-focus', 'quick-tips', 'pack', 'semester-pack', 'question-and-answer', 'song-tutorial', 'song-tutorial-children', 'workout'];
56
57
 
57
58
  let contentTypeConfig = {
58
59
  'song': {
@@ -370,8 +371,10 @@ function filtersToGroq(filters, selectedFilters = []) {
370
371
  return `instrumentless == ${value}`;
371
372
  } else if (key === 'difficulty' && !selectedFilters.includes(key)) {
372
373
  return `difficulty_string == "${value}"`;
374
+ } else if (key === 'type' && !selectedFilters.includes(key)) {
375
+ return `_type == "${value}"`;
373
376
  } else if (!selectedFilters.includes(key)) {
374
- return `&& ${key} == ${/^\d+$/.test(value) ? value : `"$${value}"`}`;
377
+ return ` ${key} == ${/^\d+$/.test(value) ? value : `"$${value}"`}`;
375
378
  }
376
379
  }).filter(Boolean).join(' || ');
377
380
 
@@ -402,4 +405,5 @@ module.exports = {
402
405
  getNewReleasesTypes,
403
406
  getUpcomingEventsTypes,
404
407
  showsTypes,
408
+ coachLessonsTypes
405
409
  }
@@ -256,8 +256,6 @@ export async function fetchContentPageUserData(contentId) {
256
256
  }
257
257
 
258
258
  export async function fetchUserPermissions() {
259
- //TODO: Should be investigate why throw 500 errors on MA
260
- return [];
261
259
  let url = `/content/user_data_permissions`;
262
260
  const headers = {
263
261
  'Content-Type': 'application/json',