musora-content-services 1.0.156 → 1.0.157

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 (57) 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/fonts/Montserrat/Montserrat-Bold.eot +0 -0
  6. package/docs/fonts/Montserrat/Montserrat-Bold.ttf +0 -0
  7. package/docs/fonts/Montserrat/Montserrat-Bold.woff +0 -0
  8. package/docs/fonts/Montserrat/Montserrat-Bold.woff2 +0 -0
  9. package/docs/fonts/Montserrat/Montserrat-Regular.eot +0 -0
  10. package/docs/fonts/Montserrat/Montserrat-Regular.ttf +0 -0
  11. package/docs/fonts/Montserrat/Montserrat-Regular.woff +0 -0
  12. package/docs/fonts/Montserrat/Montserrat-Regular.woff2 +0 -0
  13. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.eot +0 -0
  14. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.svg +0 -0
  15. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.ttf +0 -0
  16. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff +0 -0
  17. package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff2 +0 -0
  18. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.eot +0 -0
  19. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.svg +0 -0
  20. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.ttf +0 -0
  21. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff +0 -0
  22. package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff2 +0 -0
  23. package/docs/scripts/collapse.js +0 -0
  24. package/docs/scripts/commonNav.js +0 -0
  25. package/docs/scripts/linenumber.js +0 -0
  26. package/docs/scripts/nav.js +0 -0
  27. package/docs/scripts/polyfill.js +0 -0
  28. package/docs/scripts/prettify/Apache-License-2.0.txt +0 -0
  29. package/docs/scripts/prettify/lang-css.js +0 -0
  30. package/docs/scripts/prettify/prettify.js +0 -0
  31. package/docs/scripts/search.js +0 -0
  32. package/docs/styles/jsdoc.css +0 -0
  33. package/docs/styles/prettify.css +0 -0
  34. package/jest.config.js +0 -0
  35. package/jsdoc.json +0 -0
  36. package/link_mcs.sh +0 -0
  37. package/package.json +1 -1
  38. package/src/contentMetaData.js +0 -0
  39. package/src/filterBuilder.js +22 -26
  40. package/src/index.d.ts +8 -1
  41. package/src/index.js +8 -1
  42. package/src/services/config.js +0 -0
  43. package/src/services/contentLikes.js +0 -0
  44. package/src/services/contentProgress.js +29 -23
  45. package/src/services/lastUpdated.js +18 -0
  46. package/src/services/railcontent.js +13 -23
  47. package/src/services/sanity.js +558 -555
  48. package/src/services/userPermissions.js +26 -0
  49. package/test/contentLikes.test.js +2 -3
  50. package/test/contentProgress.test.js +7 -7
  51. package/test/initializeTests.js +23 -0
  52. package/test/lastUpdated.test.js +22 -0
  53. package/test/localStorageMock.js +0 -0
  54. package/test/log.js +0 -0
  55. package/test/sanityQueryService.test.js +29 -58
  56. package/test/userPermissions.test.js +19 -0
  57. package/tools/generate-index.js +0 -0
@@ -23,8 +23,9 @@ import {
23
23
 
24
24
  import {globalConfig} from "./config";
25
25
 
26
- import { fetchUserPermissions, fetchAllCompletedStates, fetchCurrentSongComplete } from './railcontent.js';
26
+ import {fetchAllCompletedStates, fetchCurrentSongComplete} from './railcontent.js';
27
27
  import {arrayToStringRepresentation, FilterBuilder} from "../filterBuilder";
28
+ import {fetchUserPermissions} from "./userPermissions";
28
29
 
29
30
  /**
30
31
  * Exported functions that are excluded from index generation.
@@ -32,21 +33,22 @@ import {arrayToStringRepresentation, FilterBuilder} from "../filterBuilder";
32
33
  * @type {string[]}
33
34
  */
34
35
  const excludeFromGeneratedIndex = [];
36
+
35
37
  /**
36
- * Fetch a song by its document ID from Sanity.
37
- *
38
- * @param {string} documentId - The ID of the document to fetch.
39
- * @returns {Promise<Object|null>} - A promise that resolves to an object containing the song data or null if not found.
40
- *
41
- * @example
42
- * fetchSongById('abc123')
43
- * .then(song => console.log(song))
44
- * .catch(error => console.error(error));
45
- */
38
+ * Fetch a song by its document ID from Sanity.
39
+ *
40
+ * @param {string} documentId - The ID of the document to fetch.
41
+ * @returns {Promise<Object|null>} - A promise that resolves to an object containing the song data or null if not found.
42
+ *
43
+ * @example
44
+ * fetchSongById('abc123')
45
+ * .then(song => console.log(song))
46
+ * .catch(error => console.error(error));
47
+ */
46
48
  export async function fetchSongById(documentId) {
47
49
  const fields = getFieldsForContentType('song');
48
50
  const filterParams = {};
49
- const query = buildQuery(
51
+ const query = await buildQuery(
50
52
  `_type == "song" && railcontent_id == ${documentId}`,
51
53
  filterParams,
52
54
  fields,
@@ -57,48 +59,48 @@ export async function fetchSongById(documentId) {
57
59
  }
58
60
 
59
61
  /**
60
- * Fetch all artists with lessons available for a specific brand.
61
- *
62
- * @param {string} brand - The brand for which to fetch artists.
63
- * @returns {Promise<Object|null>} - A promise that resolves to an array of artist objects or null if not found.
64
- *
65
- * @example
66
- * fetchArtists('drumeo')
67
- * .then(artists => console.log(artists))
68
- * .catch(error => console.error(error));
69
- */
62
+ * Fetch all artists with lessons available for a specific brand.
63
+ *
64
+ * @param {string} brand - The brand for which to fetch artists.
65
+ * @returns {Promise<Object|null>} - A promise that resolves to an array of artist objects or null if not found.
66
+ *
67
+ * @example
68
+ * fetchArtists('drumeo')
69
+ * .then(artists => console.log(artists))
70
+ * .catch(error => console.error(error));
71
+ */
70
72
  export async function fetchArtists(brand) {
71
- const filter = new FilterBuilder(`_type == "song" && brand == "${brand}" && references(^._id)`).buildFilter();
72
- const query = `
73
+ const filter = await new FilterBuilder(`_type == "song" && brand == "${brand}" && references(^._id)`, {bypassPermissions: true}).buildFilter();
74
+ const query = `
73
75
  *[_type == "artist"]{
74
76
  name,
75
77
  "lessonsCount": count(*[${filter}])
76
78
  }[lessonsCount > 0]`;
77
- return fetchSanity(query, true, {processNeedAccess:false});
79
+ return fetchSanity(query, true, {processNeedAccess: false});
78
80
  }
79
81
 
80
82
  /**
81
- * Fetch current number of artists for songs within a brand.
82
- * @param {string} brand - The current brand.
83
- * @returns {Promise<int|null>} - The fetched count of artists.
84
- */
83
+ * Fetch current number of artists for songs within a brand.
84
+ * @param {string} brand - The current brand.
85
+ * @returns {Promise<int|null>} - The fetched count of artists.
86
+ */
85
87
  export async function fetchSongArtistCount(brand) {
86
- const query = `count(*[_type == 'artist']{'lessonsCount': count(*[_type == 'song' && brand == '${brand}' && references(^._id)]._id)}[lessonsCount > 0])`;
87
- return fetchSanity(query, true, {processNeedAccess:false});
88
+ const query = `count(*[_type == 'artist']{'lessonsCount': count(*[_type == 'song' && brand == '${brand}' && references(^._id)]._id)}[lessonsCount > 0])`;
89
+ return fetchSanity(query, true, {processNeedAccess: false});
88
90
  }
89
91
 
90
92
  /**
91
- * Fetch related songs for a specific brand and song ID.
92
- *
93
- * @param {string} brand - The brand for which to fetch related songs.
94
- * @param {string} songId - The ID of the song to find related songs for.
95
- * @returns {Promise<Object|null>} - A promise that resolves to an array of related song objects or null if not found.
96
- *
97
- * @example
98
- * fetchRelatedSongs('drumeo', '12345')
99
- * .then(relatedSongs => console.log(relatedSongs))
100
- * .catch(error => console.error(error));
101
- */
93
+ * Fetch related songs for a specific brand and song ID.
94
+ *
95
+ * @param {string} brand - The brand for which to fetch related songs.
96
+ * @param {string} songId - The ID of the song to find related songs for.
97
+ * @returns {Promise<Object|null>} - A promise that resolves to an array of related song objects or null if not found.
98
+ *
99
+ * @example
100
+ * fetchRelatedSongs('drumeo', '12345')
101
+ * .then(relatedSongs => console.log(relatedSongs))
102
+ * .catch(error => console.error(error));
103
+ */
102
104
  export async function fetchRelatedSongs(brand, songId) {
103
105
  const query = `
104
106
  *[_type == "song" && railcontent_id == ${songId}]{
@@ -190,29 +192,29 @@ export async function fetchRelatedSongs(brand, songId) {
190
192
  * .catch(error => console.error(error));
191
193
  */
192
194
  export async function fetchAllSongs(brand, {
193
- page = 1,
194
- limit = 10,
195
- searchTerm = "",
196
- sort = "-published_on",
197
- includedFields = [],
198
- groupBy = ""
195
+ page = 1,
196
+ limit = 10,
197
+ searchTerm = "",
198
+ sort = "-published_on",
199
+ includedFields = [],
200
+ groupBy = ""
199
201
  }) {
200
202
  return fetchAll(brand, 'song', {page, limit, searchTerm, sort, includedFields, groupBy});
201
203
  }
202
204
 
203
205
  /**
204
- * Fetch filter options for a specific brand.
205
- *
206
- * @param {string} brand - The brand for which to fetch filter options.
207
- * @returns {Promise<Object|null>} - A promise that resolves to an object containing filter options or null if not found.
208
- *
209
- * @example
210
- * fetchSongFilterOptions('drumeo')
211
- * .then(options => console.log(options))
212
- * .catch(error => console.error(error));
213
- */
206
+ * Fetch filter options for a specific brand.
207
+ *
208
+ * @param {string} brand - The brand for which to fetch filter options.
209
+ * @returns {Promise<Object|null>} - A promise that resolves to an object containing filter options or null if not found.
210
+ *
211
+ * @example
212
+ * fetchSongFilterOptions('drumeo')
213
+ * .then(options => console.log(options))
214
+ * .catch(error => console.error(error));
215
+ */
214
216
  export async function fetchSongFilterOptions(brand) {
215
- const query = `
217
+ const query = `
216
218
  {
217
219
  "difficulty": [
218
220
  {"type": "Introductory", "count": count(*[_type == 'song' && brand == '${brand}' && difficulty_string == "Introductory"]._id)},
@@ -231,17 +233,17 @@ export async function fetchSongFilterOptions(brand) {
231
233
  ]
232
234
  }`;
233
235
 
234
- return fetchSanity(query, true);
236
+ return fetchSanity(query, true);
235
237
  }
236
238
 
237
239
  /**
238
- * Fetch the total count of songs for a specific brand.
239
- * @param {string} brand - The brand for which to fetch the song count.
240
- * @returns {Promise<number|null>} - The total count of songs or null if an error occurs.
241
- */
240
+ * Fetch the total count of songs for a specific brand.
241
+ * @param {string} brand - The brand for which to fetch the song count.
242
+ * @returns {Promise<number|null>} - The total count of songs or null if an error occurs.
243
+ */
242
244
  export async function fetchSongCount(brand) {
243
- const query = `count(*[_type == 'song' && brand == "${brand}"])`;
244
- return fetchSanity(query, true, {processNeedAccess:false});
245
+ const query = `count(*[_type == 'song' && brand == "${brand}"])`;
246
+ return fetchSanity(query, true, {processNeedAccess: false});
245
247
  }
246
248
 
247
249
  /**
@@ -256,29 +258,29 @@ export async function fetchSongCount(brand) {
256
258
  * @example
257
259
  * fetchWorkouts('drumeo')
258
260
  * .then(workouts => console.log(workouts))
259
- * .catch(error => console.error(error));
261
+ * .catch(error => console.error(error));
260
262
  */
261
263
  export async function fetchWorkouts(brand) {
262
- const fields = getFieldsForContentType('workout');
263
- const query = `*[_type == 'workout' && brand == '${brand}'] [0...5] {
264
+ const fields = getFieldsForContentType('workout');
265
+ const query = `*[_type == 'workout' && brand == '${brand}'] [0...5] {
264
266
  ${fields.toString()}
265
267
  } | order(published_on desc)[0...5]`
266
- return fetchSanity(query, true);
268
+ return fetchSanity(query, true);
267
269
  }
268
270
 
269
271
  /**
270
- * Fetch the latest new releases for a specific brand.
271
- * @param {string} brand - The brand for which to fetch new releases.
272
- * @returns {Promise<Object|null>} - The fetched new releases data or null if not found.
273
- */
274
- export async function fetchNewReleases(brand, { page = 1, limit = 20, sort="-published_on" } = {}) {
275
- const newTypes = getNewReleasesTypes(brand);
276
- const typesString = arrayToStringRepresentation(newTypes);
277
- const start = (page - 1) * limit;
278
- const end = start + limit;
279
- const sortOrder = getSortOrder(sort);
280
- const filter = `_type in ${typesString} && brand == '${brand}'`;
281
- const fields = `
272
+ * Fetch the latest new releases for a specific brand.
273
+ * @param {string} brand - The brand for which to fetch new releases.
274
+ * @returns {Promise<Object|null>} - The fetched new releases data or null if not found.
275
+ */
276
+ export async function fetchNewReleases(brand, {page = 1, limit = 20, sort = "-published_on"} = {}) {
277
+ const newTypes = getNewReleasesTypes(brand);
278
+ const typesString = arrayToStringRepresentation(newTypes);
279
+ const start = (page - 1) * limit;
280
+ const end = start + limit;
281
+ const sortOrder = getSortOrder(sort);
282
+ const filter = `_type in ${typesString} && brand == '${brand}'`;
283
+ const fields = `
282
284
  "id": railcontent_id,
283
285
  title,
284
286
  "image": thumbnail.asset->url,
@@ -292,41 +294,41 @@ export async function fetchNewReleases(brand, { page = 1, limit = 20, sort="-pub
292
294
  web_url_path,
293
295
  "permission_id": permission[]->railcontent_id,
294
296
  `;
295
- const filterParams = {};
296
- const query = buildQuery(
297
- filter,
298
- filterParams,
299
- fields,
300
- {
301
- sortOrder: sortOrder,
302
- start,
303
- end: end,
304
- });
305
- return fetchSanity(query, true);
297
+ const filterParams = {};
298
+ const query = await buildQuery(
299
+ filter,
300
+ filterParams,
301
+ fields,
302
+ {
303
+ sortOrder: sortOrder,
304
+ start,
305
+ end: end,
306
+ });
307
+ return fetchSanity(query, true);
306
308
  }
307
309
 
308
310
 
309
311
  /**
310
- * Fetch upcoming events for a specific brand.
311
- *
312
- * @param {string} brand - The brand for which to fetch upcoming events.
313
- * @returns {Promise<Object|null>} - A promise that resolves to an array of upcoming event objects or null if not found.
314
- *
315
- * @example
316
- * fetchUpcomingEvents('drumeo', {
317
- * page: 2,
318
- * limit: 20,
319
- * })
320
- * .then(events => console.log(events))
321
- * .catch(error => console.error(error));
322
- */
323
- export async function fetchUpcomingEvents(brand, { page = 1, limit = 10 } = {}) {
324
- const liveTypes = getUpcomingEventsTypes(brand);
325
- const typesString = arrayToStringRepresentation(liveTypes);
326
- const now = getSanityDate(new Date());
327
- const start = (page - 1) * limit;
328
- const end = start + limit;
329
- const fields = `
312
+ * Fetch upcoming events for a specific brand.
313
+ *
314
+ * @param {string} brand - The brand for which to fetch upcoming events.
315
+ * @returns {Promise<Object|null>} - A promise that resolves to an array of upcoming event objects or null if not found.
316
+ *
317
+ * @example
318
+ * fetchUpcomingEvents('drumeo', {
319
+ * page: 2,
320
+ * limit: 20,
321
+ * })
322
+ * .then(events => console.log(events))
323
+ * .catch(error => console.error(error));
324
+ */
325
+ export async function fetchUpcomingEvents(brand, {page = 1, limit = 10} = {}) {
326
+ const liveTypes = getUpcomingEventsTypes(brand);
327
+ const typesString = arrayToStringRepresentation(liveTypes);
328
+ const now = getSanityDate(new Date());
329
+ const start = (page - 1) * limit;
330
+ const end = start + limit;
331
+ const fields = `
330
332
  "id": railcontent_id,
331
333
  title,
332
334
  "image": thumbnail.asset->url,
@@ -339,16 +341,16 @@ export async function fetchUpcomingEvents(brand, { page = 1, limit = 10 } = {})
339
341
  "type": _type,
340
342
  web_url_path,
341
343
  "permission_id": permission[]->railcontent_id,`;
342
- const query = buildRawQuery(
343
- `_type in ${typesString} && brand == '${brand}' && published_on > '${now}' && status == 'scheduled'`,
344
- fields,
345
- {
346
- sortOrder: 'published_on asc',
347
- start: start,
348
- end: end,
349
- },
350
- );
351
- return fetchSanity(query, true);
344
+ const query = buildRawQuery(
345
+ `_type in ${typesString} && brand == '${brand}' && published_on > '${now}' && status == 'scheduled'`,
346
+ fields,
347
+ {
348
+ sortOrder: 'published_on asc',
349
+ start: start,
350
+ end: end,
351
+ },
352
+ );
353
+ return fetchSanity(query, true);
352
354
  }
353
355
 
354
356
  /**
@@ -365,16 +367,16 @@ export async function fetchUpcomingEvents(brand, { page = 1, limit = 10 } = {})
365
367
  * .then(content => console.log(content))
366
368
  * .catch(error => console.error(error));
367
369
  */
368
- export async function fetchScheduledReleases(brand, { page = 1, limit = 10 }) {
369
- const upcomingTypes = getUpcomingEventsTypes(brand);
370
- const newTypes = getNewReleasesTypes(brand);
371
-
372
- const scheduledTypes = merge(upcomingTypes, newTypes)
373
- const typesString = arrayJoinWithQuotes(scheduledTypes);
374
- const now = getSanityDate(new Date());
375
- const start = (page - 1) * limit;
376
- const end = start + limit;
377
- const query = `*[_type in [${typesString}] && brand == '${brand}' && status in ['published','scheduled'] && published_on > '${now}']{
370
+ export async function fetchScheduledReleases(brand, {page = 1, limit = 10}) {
371
+ const upcomingTypes = getUpcomingEventsTypes(brand);
372
+ const newTypes = getNewReleasesTypes(brand);
373
+
374
+ const scheduledTypes = merge(upcomingTypes, newTypes)
375
+ const typesString = arrayJoinWithQuotes(scheduledTypes);
376
+ const now = getSanityDate(new Date());
377
+ const start = (page - 1) * limit;
378
+ const end = start + limit;
379
+ const query = `*[_type in [${typesString}] && brand == '${brand}' && status in ['published','scheduled'] && published_on > '${now}']{
378
380
  "id": railcontent_id,
379
381
  title,
380
382
  "image": thumbnail.asset->url,
@@ -388,21 +390,21 @@ export async function fetchScheduledReleases(brand, { page = 1, limit = 10 }) {
388
390
  web_url_path,
389
391
  "permission_id": permission[]->railcontent_id,
390
392
  } | order(published_on asc)[${start}...${end}]`;
391
- return fetchSanity(query, true);
393
+ return fetchSanity(query, true);
392
394
  }
393
395
 
394
396
  /**
395
- * Fetch content by a specific Railcontent ID.
396
- *
397
- * @param {string} id - The Railcontent ID of the content to fetch.
398
- * @param {string} contentType - The document type of content to fetch
399
- * @returns {Promise<Object|null>} - A promise that resolves to the content object or null if not found.
400
- *
401
- * @example
402
- * fetchByRailContentId('abc123')
403
- * .then(content => console.log(content))
404
- * .catch(error => console.error(error));
405
- */
397
+ * Fetch content by a specific Railcontent ID.
398
+ *
399
+ * @param {string} id - The Railcontent ID of the content to fetch.
400
+ * @param {string} contentType - The document type of content to fetch
401
+ * @returns {Promise<Object|null>} - A promise that resolves to the content object or null if not found.
402
+ *
403
+ * @example
404
+ * fetchByRailContentId('abc123')
405
+ * .then(content => console.log(content))
406
+ * .catch(error => console.error(error));
407
+ */
406
408
  export async function fetchByRailContentId(id, contentType) {
407
409
 
408
410
  const query = buildRawQuery(
@@ -417,24 +419,24 @@ export async function fetchByRailContentId(id, contentType) {
417
419
  }
418
420
 
419
421
  /**
420
- * Fetch content by an array of Railcontent IDs.
421
- *
422
- * @param {Array<string>} ids - The array of Railcontent IDs of the content to fetch.
423
- * @param {string} [contentType] - The content type the IDs to add needed fields to the response.
424
- * @returns {Promise<Array<Object>|null>} - A promise that resolves to an array of content objects or null if not found.
425
- *
426
- * @example
427
- * fetchByRailContentIds(['abc123', 'def456', 'ghi789'])
428
- * .then(contents => console.log(contents))
429
- * .catch(error => console.error(error));
430
- */
422
+ * Fetch content by an array of Railcontent IDs.
423
+ *
424
+ * @param {Array<string>} ids - The array of Railcontent IDs of the content to fetch.
425
+ * @param {string} [contentType] - The content type the IDs to add needed fields to the response.
426
+ * @returns {Promise<Array<Object>|null>} - A promise that resolves to an array of content objects or null if not found.
427
+ *
428
+ * @example
429
+ * fetchByRailContentIds(['abc123', 'def456', 'ghi789'])
430
+ * .then(contents => console.log(contents))
431
+ * .catch(error => console.error(error));
432
+ */
431
433
  export async function fetchByRailContentIds(ids, contentType = undefined) {
432
- const idsString = ids.join(',');
434
+ const idsString = ids.join(',');
433
435
 
434
- const query = `*[railcontent_id in [${idsString}]]{
436
+ const query = `*[railcontent_id in [${idsString}]]{
435
437
  ${getFieldsForContentType(contentType)}
436
438
  }`
437
- return fetchSanity(query, true);
439
+ return fetchSanity(query, true);
438
440
  }
439
441
 
440
442
  /**
@@ -469,15 +471,15 @@ export async function fetchByRailContentIds(ids, contentType = undefined) {
469
471
  * .catch(error => console.error(error));
470
472
  */
471
473
  export async function fetchAll(brand, type, {
472
- page = 1,
473
- limit = 10,
474
- searchTerm = "",
475
- sort = "-published_on",
476
- includedFields = [],
477
- groupBy = "",
478
- progressIds = undefined,
479
- useDefaultFields = true,
480
- customFields = [],
474
+ page = 1,
475
+ limit = 10,
476
+ searchTerm = "",
477
+ sort = "-published_on",
478
+ includedFields = [],
479
+ groupBy = "",
480
+ progressIds = undefined,
481
+ useDefaultFields = true,
482
+ customFields = [],
481
483
  } = {}) {
482
484
  let config = contentTypeConfig[type] ?? {};
483
485
  let additionalFields = config?.fields ?? [];
@@ -492,8 +494,8 @@ export async function fetchAll(brand, type, {
492
494
  // Construct the search filter
493
495
  const searchFilter = searchTerm
494
496
  ? groupBy !== "" ?
495
- `&& (^.name match "${searchTerm}*" || title match "${searchTerm}*")`
496
- : `&& (artist->name match "${searchTerm}*" || instructor[]->name match "${searchTerm}*" || title match "${searchTerm}*" || name match "${searchTerm}*")`
497
+ `&& (^.name match "${searchTerm}*" || title match "${searchTerm}*")`
498
+ : `&& (artist->name match "${searchTerm}*" || instructor[]->name match "${searchTerm}*" || title match "${searchTerm}*" || name match "${searchTerm}*")`
497
499
  : "";
498
500
 
499
501
  // Construct the included fields filter, replacing 'difficulty' with 'difficulty_string'
@@ -508,7 +510,7 @@ export async function fetchAll(brand, type, {
508
510
  // Determine the sort order
509
511
  const sortOrder = getSortOrder(sort);
510
512
 
511
- let fields = useDefaultFields ? customFields.concat(DEFAULT_FIELDS, additionalFields) : customFields;
513
+ let fields = useDefaultFields ? customFields.concat(DEFAULT_FIELDS, additionalFields) : customFields;
512
514
  let fieldsString = fields.join(',');
513
515
 
514
516
  // Determine the group by clause
@@ -532,7 +534,7 @@ export async function fetchAll(brand, type, {
532
534
  `;
533
535
  filter = `_type == '${groupBy}' && count(*[brand == '${brand}' && ^._id == ${groupBy}._ref ${typeFilter} ${searchFilter} ${includedFieldsFilter} ${progressFilter}]._id) > 0`;
534
536
  } else if (groupBy !== "") {
535
- const webUrlPath = (groupBy == 'genre')?'/genres':'';
537
+ const webUrlPath = (groupBy == 'genre') ? '/genres' : '';
536
538
  const lessonsFilter = `brand == '${brand}' && ^._id in ${groupBy}[]._ref ${typeFilter} ${searchFilter} ${includedFieldsFilter} ${progressFilter}`;
537
539
  entityFieldsString = `
538
540
  'id': railcontent_id,
@@ -562,8 +564,7 @@ export async function fetchAll(brand, type, {
562
564
  return fetchSanity(query, true);
563
565
  }
564
566
 
565
- export function getSortOrder(sort= '-published_on', groupBy)
566
- {
567
+ export function getSortOrder(sort = '-published_on', groupBy) {
567
568
  // Determine the sort order
568
569
  let sortOrder = '';
569
570
  const isDesc = sort.startsWith('-');
@@ -586,69 +587,69 @@ export function getSortOrder(sort= '-published_on', groupBy)
586
587
  }
587
588
 
588
589
  /**
589
- * Fetches all available filter options based on brand, filters, and various optional criteria.
590
- *
591
- * This function constructs a query to retrieve the total number of results and filter options such as difficulty, instrument type, and genre.
592
- * The filter options are dynamically generated based on the provided filters, style, artist, and content type.
593
- * If a coachId is provided, the content type must be 'coach-lessons'.
594
- *
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'.
606
- *
607
- * @example
608
- * // Fetch filter options for 'song' content type:
609
- * fetchAllFilterOptions('myBrand', [], 'Rock', 'John Doe', 'song', 'Love')
610
- * .then(options => console.log(options))
611
- * .catch(error => console.error(error));
612
- *
613
- * @example
614
- * // Fetch filter options for a coach's lessons with coachId:
615
- * fetchAllFilterOptions('myBrand', [], 'Rock', 'John Doe', 'coach-lessons', 'Love', undefined, '123')
616
- * .then(options => console.log(options))
617
- * .catch(error => console.error(error));
618
- */
590
+ * Fetches all available filter options based on brand, filters, and various optional criteria.
591
+ *
592
+ * This function constructs a query to retrieve the total number of results and filter options such as difficulty, instrument type, and genre.
593
+ * The filter options are dynamically generated based on the provided filters, style, artist, and content type.
594
+ * If a coachId is provided, the content type must be 'coach-lessons'.
595
+ *
596
+ * @param {string} brand - Brand to filter.
597
+ * @param {string[]} filters - Key-value pairs to filter the query.
598
+ * @param {string} [style] - Optional style/genre filter.
599
+ * @param {string} [artist] - Optional artist name filter.
600
+ * @param {string} contentType - Content type (e.g., 'song', 'lesson').
601
+ * @param {string} [term] - Optional search term for title, album, artist, or genre.
602
+ * @param {Array<string>} [progressIds] - Optional array of progress IDs to filter by.
603
+ * @param {string} [coachId] - Optional coach ID (only valid if contentType is 'coach-lessons').
604
+ * @param {boolean} [includeTabs=false] - Whether to include tabs in the returned metadata.
605
+ * @returns {Promise<Object>} - The filter options and metadata.
606
+ * @throws {Error} If coachId is provided but contentType isn't 'coach-lessons'.
607
+ *
608
+ * @example
609
+ * // Fetch filter options for 'song' content type:
610
+ * fetchAllFilterOptions('myBrand', [], 'Rock', 'John Doe', 'song', 'Love')
611
+ * .then(options => console.log(options))
612
+ * .catch(error => console.error(error));
613
+ *
614
+ * @example
615
+ * // Fetch filter options for a coach's lessons with coachId:
616
+ * fetchAllFilterOptions('myBrand', [], 'Rock', 'John Doe', 'coach-lessons', 'Love', undefined, '123')
617
+ * .then(options => console.log(options))
618
+ * .catch(error => console.error(error));
619
+ */
619
620
  export async function fetchAllFilterOptions(
620
- brand,
621
- filters = [],
622
- style,
623
- artist,
624
- contentType,
625
- term,
626
- progressIds,
627
- coachId,
628
- includeTabs = false,
621
+ brand,
622
+ filters = [],
623
+ style,
624
+ artist,
625
+ contentType,
626
+ term,
627
+ progressIds,
628
+ coachId,
629
+ includeTabs = false,
629
630
  ) {
630
- if (coachId && contentType !== 'coach-lessons') {
631
- throw new Error(`Invalid contentType: '${contentType}' for coachId. It must be 'coach-lessons'.`);
632
- }
631
+ if (coachId && contentType !== 'coach-lessons') {
632
+ throw new Error(`Invalid contentType: '${contentType}' for coachId. It must be 'coach-lessons'.`);
633
+ }
633
634
 
634
- const includedFieldsFilter = filters?.length ? filtersToGroq(filters) : undefined;
635
- const progressFilter = progressIds ? `&& railcontent_id in [${progressIds.join(',')}]` : "";
635
+ const includedFieldsFilter = filters?.length ? filtersToGroq(filters) : undefined;
636
+ const progressFilter = progressIds ? `&& railcontent_id in [${progressIds.join(',')}]` : "";
636
637
 
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
- };
638
+ const constructCommonFilter = (excludeFilter) => {
639
+ const filterWithoutOption = excludeFilter ? filtersToGroq(filters, excludeFilter) : includedFieldsFilter;
640
+ return coachId
641
+ ? `brand == '${brand}' && references(*[_type=='instructor' && railcontent_id == ${coachId}]._id) ${filterWithoutOption || ''}`
642
+ : `_type == '${contentType}' && brand == "${brand}"${style && excludeFilter !== "style" ? ` && '${style}' in genre[]->name` : ''}${artist && excludeFilter !== "artist" ? ` && artist->name == '${artist}'` : ''} ${progressFilter} ${filterWithoutOption || ''}`;
643
+ };
643
644
 
644
- const metaData = processMetadata(brand, contentType, true);
645
- const allowableFilters = metaData?.allowableFilters || [];
646
- const tabs = metaData?.tabs || [];
647
- const catalogName = metaData?.shortname || metaData?.name;
645
+ const metaData = processMetadata(brand, contentType, true);
646
+ const allowableFilters = metaData?.allowableFilters || [];
647
+ const tabs = metaData?.tabs || [];
648
+ const catalogName = metaData?.shortname || metaData?.name;
648
649
 
649
- const dynamicFilterOptions = allowableFilters.map(filter => getFilterOptions(filter, constructCommonFilter(filter), contentType, brand)).join(' ');
650
+ const dynamicFilterOptions = allowableFilters.map(filter => getFilterOptions(filter, constructCommonFilter(filter), contentType, brand)).join(' ');
650
651
 
651
- const query = `
652
+ const query = `
652
653
  {
653
654
  "meta": {
654
655
  "totalResults": count(*[${constructCommonFilter()}
@@ -659,28 +660,28 @@ export async function fetchAllFilterOptions(
659
660
  }
660
661
  }`;
661
662
 
662
- const results = await fetchSanity(query, true, { processNeedAccess: false });
663
+ const results = await fetchSanity(query, true, {processNeedAccess: false});
663
664
 
664
- return includeTabs ? { ...results, tabs, catalogName } : results;
665
+ return includeTabs ? {...results, tabs, catalogName} : results;
665
666
  }
666
667
 
667
668
 
668
669
  /**
669
- * Fetch children content by Railcontent ID.
670
- * @param {string} railcontentId - The Railcontent ID of the parent content.
671
- * @param {string} [contentType] - The content type the IDs to add needed fields to the response.
672
- * @returns {Promise<Array<Object>|null>} - The fetched children content data or [] if not found.
673
- */
670
+ * Fetch children content by Railcontent ID.
671
+ * @param {string} railcontentId - The Railcontent ID of the parent content.
672
+ * @param {string} [contentType] - The content type the IDs to add needed fields to the response.
673
+ * @returns {Promise<Array<Object>|null>} - The fetched children content data or [] if not found.
674
+ */
674
675
  export async function fetchChildren(railcontentId, contentType) {
675
- const query = `*[railcontent_id == ${railcontentId}]{
676
+ const query = `*[railcontent_id == ${railcontentId}]{
676
677
  title,
677
678
 
678
679
  'children': child[]->{
679
680
  ${getFieldsForContentType(contentType)}
680
681
  },
681
682
  }[0..1]`;
682
- let parent = await fetchSanity(query, false);
683
- return parent['children'] ?? [];
683
+ let parent = await fetchSanity(query, false);
684
+ return parent['children'] ?? [];
684
685
  }
685
686
 
686
687
  /**
@@ -701,44 +702,44 @@ export async function fetchParentByRailContentId(railcontentId) {
701
702
  }
702
703
 
703
704
  /**
704
- * Fetch the Methods (learning-paths) for a specific brand.
705
- * @param {string} brand - The brand for which to fetch methods.
706
- * @returns {Promise<Object|null>} - The fetched methods data or null if not found.
707
- */
705
+ * Fetch the Methods (learning-paths) for a specific brand.
706
+ * @param {string} brand - The brand for which to fetch methods.
707
+ * @returns {Promise<Object|null>} - The fetched methods data or null if not found.
708
+ */
708
709
  export async function fetchMethods(brand) {
709
710
  const query = `*[_type == 'learning-path' && brand == '${brand}'] {
710
- ${ getFieldsForContentType() }
711
+ ${getFieldsForContentType()}
711
712
  } | order(published_on asc)`
712
- return fetchSanity(query, true);
713
+ return fetchSanity(query, true);
713
714
  }
714
715
 
715
716
  /**
716
- * Fetch the Foundations 2019.
717
- * @param {string} slug - The slug of the method.
718
- * @returns {Promise<Object|null>} - The fetched foundation data or null if not found.
719
- */
717
+ * Fetch the Foundations 2019.
718
+ * @param {string} slug - The slug of the method.
719
+ * @returns {Promise<Object|null>} - The fetched foundation data or null if not found.
720
+ */
720
721
  export async function fetchFoundation(slug) {
721
- const filterParams = {};
722
- const query = buildQuery(
723
- `_type == 'foundation' && slug.current == "${slug}"`,
724
- filterParams,
725
- getFieldsForContentType('foundation'),
726
- {
727
- sortOrder: 'published_on asc',
728
- isSingle: true,
729
- }
730
- );
731
- return fetchSanity(query, false);
722
+ const filterParams = {};
723
+ const query = await buildQuery(
724
+ `_type == 'foundation' && slug.current == "${slug}"`,
725
+ filterParams,
726
+ getFieldsForContentType('foundation'),
727
+ {
728
+ sortOrder: 'published_on asc',
729
+ isSingle: true,
730
+ }
731
+ );
732
+ return fetchSanity(query, false);
732
733
  }
733
734
 
734
735
  /**
735
- * Fetch the Method (learning-paths) for a specific brand.
736
- * @param {string} brand - The brand for which to fetch methods.
737
- * @param {string} slug - The slug of the method.
738
- * @returns {Promise<Object|null>} - The fetched methods data or null if not found.
739
- */
736
+ * Fetch the Method (learning-paths) for a specific brand.
737
+ * @param {string} brand - The brand for which to fetch methods.
738
+ * @param {string} slug - The slug of the method.
739
+ * @returns {Promise<Object|null>} - The fetched methods data or null if not found.
740
+ */
740
741
  export async function fetchMethod(brand, slug) {
741
- const query = `*[_type == 'learning-path' && brand == "${brand}" && slug.current == "${slug}"] {
742
+ const query = `*[_type == 'learning-path' && brand == "${brand}" && slug.current == "${slug}"] {
742
743
  "description": ${descriptionField},
743
744
  "instructors":instructor[]->name,
744
745
  published_on,
@@ -768,16 +769,16 @@ export async function fetchMethod(brand, slug) {
768
769
  xp,
769
770
  }
770
771
  } | order(published_on asc)`
771
- return fetchSanity(query, false);
772
+ return fetchSanity(query, false);
772
773
  }
773
774
 
774
775
  /**
775
- * Fetch the child courses for a specific method by Railcontent ID.
776
- * @param {string} railcontentId - The Railcontent ID of the current lesson.
777
- * @returns {Promise<Object|null>} - The fetched next lesson data or null if not found.
778
- */
776
+ * Fetch the child courses for a specific method by Railcontent ID.
777
+ * @param {string} railcontentId - The Railcontent ID of the current lesson.
778
+ * @returns {Promise<Object|null>} - The fetched next lesson data or null if not found.
779
+ */
779
780
  export async function fetchMethodChildren(railcontentId) {
780
- const query = `*[railcontent_id == ${railcontentId}]{
781
+ const query = `*[railcontent_id == ${railcontentId}]{
781
782
  child_count,
782
783
  "id": railcontent_id,
783
784
  "description": ${descriptionField},
@@ -788,20 +789,20 @@ export async function fetchMethodChildren(railcontentId) {
788
789
  ${getFieldsForContentType('method')}
789
790
  },
790
791
  }[0..1]`;
791
- return fetchSanity(query, true);
792
+ return fetchSanity(query, true);
792
793
  }
793
794
 
794
795
  /**
795
- * Fetch the next lesson for a specific method by Railcontent ID.
796
- * @param {string} railcontentId - The Railcontent ID of the current lesson.
796
+ * Fetch the next lesson for a specific method by Railcontent ID.
797
+ * @param {string} railcontentId - The Railcontent ID of the current lesson.
797
798
  * @param {string} methodId - The RailcontentID of the method
798
- * @returns {Promise<Object|null>} - The fetched next lesson data or null if not found.
799
- */
799
+ * @returns {Promise<Object|null>} - The fetched next lesson data or null if not found.
800
+ */
800
801
  export async function fetchMethodNextLesson(railcontentId, methodId) {
801
- const sortedChildren = await fetchMethodChildrenIds(methodId);
802
- const index = sortedChildren.indexOf(railcontentId);
803
- const childIndex = sortedChildren[index + 1];
804
- return childIndex ? await fetchByRailContentId(childIndex) : null;
802
+ const sortedChildren = await fetchMethodChildrenIds(methodId);
803
+ const index = sortedChildren.indexOf(railcontentId);
804
+ const childIndex = sortedChildren[index + 1];
805
+ return childIndex ? await fetchByRailContentId(childIndex) : null;
805
806
  }
806
807
 
807
808
  /**
@@ -818,18 +819,22 @@ export async function fetchMethodPreviousNextLesson(railcontentId, methodId) {
818
819
  const sortedChildren = await fetchMethodChildrenIds(methodId);
819
820
  const index = sortedChildren.indexOf(Number(railcontentId));
820
821
  let nextId = sortedChildren[index + 1];
821
- let previousId = sortedChildren[index -1];
822
+ let previousId = sortedChildren[index - 1];
822
823
  let nextPrev = await fetchByRailContentIds([nextId, previousId]);
823
- const nextLesson = nextPrev.find((elem) => {return elem['id'] === nextId});
824
- const prevLesson = nextPrev.find((elem) => {return elem['id'] === previousId});
824
+ const nextLesson = nextPrev.find((elem) => {
825
+ return elem['id'] === nextId
826
+ });
827
+ const prevLesson = nextPrev.find((elem) => {
828
+ return elem['id'] === previousId
829
+ });
825
830
  return {nextLesson, prevLesson};
826
831
  }
827
832
 
828
833
  /**
829
- * Fetch all children of a specific method by Railcontent ID.
830
- * @param {string} railcontentId - The Railcontent ID of the method.
831
- * @returns {Promise<Array<Object>|null>} - The fetched children data or null if not found.
832
- */
834
+ * Fetch all children of a specific method by Railcontent ID.
835
+ * @param {string} railcontentId - The Railcontent ID of the method.
836
+ * @returns {Promise<Array<Object>|null>} - The fetched children data or null if not found.
837
+ */
833
838
  export async function fetchMethodChildrenIds(railcontentId) {
834
839
  const query = `*[ railcontent_id == ${railcontentId}]{
835
840
  'children': child[]-> {
@@ -849,25 +854,24 @@ export async function fetchMethodChildrenIds(railcontentId) {
849
854
  return getChildrenToDepth(allChildren, 4);
850
855
  }
851
856
 
852
- function getChildrenToDepth(parent, depth = 1)
853
- {
857
+ function getChildrenToDepth(parent, depth = 1) {
854
858
  let allChildrenIds = [];
855
859
  if (parent && parent['children'] && depth > 0) {
856
860
  parent['children'].forEach((child) => {
857
- if(!child['children']) {
861
+ if (!child['children']) {
858
862
  allChildrenIds.push(child['id']);
859
863
  }
860
- allChildrenIds = allChildrenIds.concat(getChildrenToDepth(child, depth-1));
864
+ allChildrenIds = allChildrenIds.concat(getChildrenToDepth(child, depth - 1));
861
865
  })
862
866
  }
863
867
  return allChildrenIds;
864
868
  }
865
869
 
866
870
  /**
867
- * Fetch the next and previous lessons for a specific lesson by Railcontent ID.
868
- * @param {string} railcontentId - The Railcontent ID of the current lesson.
869
- * @returns {Promise<Object|null>} - The fetched next and previous lesson data or null if found.
870
- */
871
+ * Fetch the next and previous lessons for a specific lesson by Railcontent ID.
872
+ * @param {string} railcontentId - The Railcontent ID of the current lesson.
873
+ * @returns {Promise<Object|null>} - The fetched next and previous lesson data or null if found.
874
+ */
871
875
  export async function fetchNextPreviousLesson(railcontentId) {
872
876
  const document = await fetchLessonContent(railcontentId);
873
877
  if (document.parent_content_data && document.parent_content_data.length > 0) {
@@ -950,7 +954,7 @@ export async function fetchLessonContent(railContentId) {
950
954
  parent_content_data,
951
955
  sort,
952
956
  xp`;
953
- const query = buildQuery(
957
+ const query = await buildQuery(
954
958
  `railcontent_id == ${railContentId}`,
955
959
  filterParams,
956
960
  fields,
@@ -958,15 +962,15 @@ export async function fetchLessonContent(railContentId) {
958
962
  isSingle: true,
959
963
  }
960
964
  );
961
- return fetchSanity(query, false);
965
+ return fetchSanity(query, false);
962
966
  }
963
967
 
964
968
  /**
965
- * Fetch related lessons for a specific lesson by RailContent ID and type.
966
- * @param {string} railContentId - The RailContent ID of the current lesson.
967
- * @param {string} brand - The current brand.
968
- * @returns {Promise<Array<Object>|null>} - The fetched related lessons data or null if not found.
969
- */
969
+ * Fetch related lessons for a specific lesson by RailContent ID and type.
970
+ * @param {string} railContentId - The RailContent ID of the current lesson.
971
+ * @param {string} brand - The current brand.
972
+ * @returns {Promise<Array<Object>|null>} - The fetched related lessons data or null if not found.
973
+ */
970
974
  export async function fetchRelatedLessons(railContentId, brand) {
971
975
  const query = `*[railcontent_id == ${railContentId} && brand == "${brand}" && references(*[_type=='permission']._id)]{
972
976
  _type, parent_type, railcontent_id,
@@ -981,13 +985,13 @@ export async function fetchRelatedLessons(railContentId, brand) {
981
985
  }
982
986
 
983
987
  /**
984
- * Fetch related method lessons for a specific lesson by RailContent ID and type.
985
- * @param {string} railContentId - The RailContent ID of the current lesson.
986
- * @param {string} brand - The current brand.
987
- * @returns {Promise<Array<Object>|null>} - The fetched related lessons
988
- */
988
+ * Fetch related method lessons for a specific lesson by RailContent ID and type.
989
+ * @param {string} railContentId - The RailContent ID of the current lesson.
990
+ * @param {string} brand - The current brand.
991
+ * @returns {Promise<Array<Object>|null>} - The fetched related lessons
992
+ */
989
993
  export async function fetchRelatedMethodLessons(railContentId, brand) {
990
- const query = `*[railcontent_id == ${railContentId} && brand == "${brand}"]{
994
+ const query = `*[railcontent_id == ${railContentId} && brand == "${brand}"]{
991
995
  "id":_id,
992
996
  "related_lessons": *[references(^._id)][0].child[]->{
993
997
  "id": railcontent_id,
@@ -1001,57 +1005,57 @@ export async function fetchRelatedMethodLessons(railContentId, brand) {
1001
1005
  }
1002
1006
  }
1003
1007
  }`
1004
- return fetchSanity(query, false);
1008
+ return fetchSanity(query, false);
1005
1009
  }
1006
1010
 
1007
1011
  /**
1008
- * Fetch all packs.
1009
- * @param {string} brand - The brand for which to fetch packs.
1010
- * @param {string} [searchTerm=""] - The search term to filter packs.
1011
- * @param {string} [sort="-published_on"] - The field to sort the packs by.
1012
- * @param {number} [params.page=1] - The page number for pagination.
1013
- * @param {number} [params.limit=10] - The number of items per page.
1014
- * @returns {Promise<Array<Object>|null>} - The fetched pack content data or null if not found.
1015
- */
1012
+ * Fetch all packs.
1013
+ * @param {string} brand - The brand for which to fetch packs.
1014
+ * @param {string} [searchTerm=""] - The search term to filter packs.
1015
+ * @param {string} [sort="-published_on"] - The field to sort the packs by.
1016
+ * @param {number} [params.page=1] - The page number for pagination.
1017
+ * @param {number} [params.limit=10] - The number of items per page.
1018
+ * @returns {Promise<Array<Object>|null>} - The fetched pack content data or null if not found.
1019
+ */
1016
1020
  export async function fetchAllPacks(brand, sort = "-published_on", searchTerm = "", page = 1, limit = 10) {
1017
- const sortOrder = getSortOrder(sort);
1018
- const filter = `_type == 'pack' && brand == '${brand}' && title match "${searchTerm}*"`
1019
- const filterParams = {};
1020
- const fields = getFieldsForContentType('pack');
1021
- const start = (page - 1) * limit;
1022
- const end = start + limit;
1023
-
1024
- const query = buildQuery(
1025
- filter,
1026
- filterParams,
1027
- getFieldsForContentType('pack'),
1028
- {
1029
- logo_image_url: 'logo_image_url.asset->url',
1030
- sortOrder: sortOrder,
1031
- start,
1032
- end
1033
- }
1034
- );
1035
- return fetchSanity(query, true);
1021
+ const sortOrder = getSortOrder(sort);
1022
+ const filter = `_type == 'pack' && brand == '${brand}' && title match "${searchTerm}*"`
1023
+ const filterParams = {};
1024
+ const fields = getFieldsForContentType('pack');
1025
+ const start = (page - 1) * limit;
1026
+ const end = start + limit;
1027
+
1028
+ const query = await buildQuery(
1029
+ filter,
1030
+ filterParams,
1031
+ getFieldsForContentType('pack'),
1032
+ {
1033
+ logo_image_url: 'logo_image_url.asset->url',
1034
+ sortOrder: sortOrder,
1035
+ start,
1036
+ end
1037
+ }
1038
+ );
1039
+ return fetchSanity(query, true);
1036
1040
  }
1037
1041
 
1038
1042
  /**
1039
- * Fetch all content for a specific pack by Railcontent ID.
1040
- * @param {string} railcontentId - The Railcontent ID of the pack.
1041
- * @returns {Promise<Array<Object>|null>} - The fetched pack content data or null if not found.
1042
- */
1043
+ * Fetch all content for a specific pack by Railcontent ID.
1044
+ * @param {string} railcontentId - The Railcontent ID of the pack.
1045
+ * @returns {Promise<Array<Object>|null>} - The fetched pack content data or null if not found.
1046
+ */
1043
1047
  export async function fetchPackAll(railcontentId) {
1044
- return fetchByRailContentId(railcontentId, 'pack');
1048
+ return fetchByRailContentId(railcontentId, 'pack');
1045
1049
  }
1046
1050
 
1047
1051
  export async function fetchLiveEvent(brand) {
1048
1052
  //calendarIDs taken from addevent.php
1049
1053
  // TODO import instructor calendars to Sanity
1050
1054
  let defaultCalendarID = '';
1051
- switch(brand) {
1055
+ switch (brand) {
1052
1056
  case ('drumeo'):
1053
1057
  defaultCalendarID = 'GP142387';
1054
- break;
1058
+ break;
1055
1059
  case ('pianote'):
1056
1060
  defaultCalendarID = 'be142408';
1057
1061
  break;
@@ -1101,7 +1105,7 @@ export async function fetchLiveEvent(brand) {
1101
1105
  * .catch(error => console.error(error));
1102
1106
  */
1103
1107
  export async function fetchPackChildren(railcontentId) {
1104
- return fetchChildren(railcontentId, 'pack-children');
1108
+ return fetchChildren(railcontentId, 'pack-children');
1105
1109
  }
1106
1110
 
1107
1111
  /**
@@ -1115,10 +1119,10 @@ export async function fetchPackChildren(railcontentId) {
1115
1119
  * .catch(error => console.error(error));
1116
1120
  */
1117
1121
  export async function fetchPackData(id) {
1118
- const query = `*[railcontent_id == ${id}]{
1122
+ const query = `*[railcontent_id == ${id}]{
1119
1123
  ${getFieldsForContentType("pack")}
1120
1124
  } [0...1]`;
1121
- return fetchSanity(query, false);
1125
+ return fetchSanity(query, false);
1122
1126
  }
1123
1127
 
1124
1128
  /**
@@ -1132,11 +1136,11 @@ export async function fetchPackData(id) {
1132
1136
  * .catch(error => console.error(error));
1133
1137
  */
1134
1138
  export async function fetchChallengeOverview(id) {
1135
- // WIP
1136
- const query = `*[railcontent_id == ${id}]{
1139
+ // WIP
1140
+ const query = `*[railcontent_id == ${id}]{
1137
1141
  ${getFieldsForContentType("challenge")}
1138
1142
  } [0...1]`;
1139
- return fetchSanity(query, false);
1143
+ return fetchSanity(query, false);
1140
1144
  }
1141
1145
 
1142
1146
  /**
@@ -1157,32 +1161,32 @@ export async function fetchChallengeOverview(id) {
1157
1161
  * .catch(error => console.error(error));
1158
1162
  */
1159
1163
  export async function fetchCoachLessons(brand, id, {
1160
- sortOrder = '-published_on',
1161
- searchTerm = '',
1162
- page = 1,
1163
- limit = 20,
1164
- includedFields = [],
1164
+ sortOrder = '-published_on',
1165
+ searchTerm = '',
1166
+ page = 1,
1167
+ limit = 20,
1168
+ includedFields = [],
1165
1169
  } = {}) {
1166
- const fieldsString = getFieldsForContentType();
1167
- const start = (page - 1) * limit;
1168
- const end = start + limit;
1169
- const searchFilter = searchTerm ? `&& title match "${searchTerm}*"`: ''
1170
- const includedFieldsFilter = includedFields.length > 0
1170
+ const fieldsString = getFieldsForContentType();
1171
+ const start = (page - 1) * limit;
1172
+ const end = start + limit;
1173
+ const searchFilter = searchTerm ? `&& title match "${searchTerm}*"` : ''
1174
+ const includedFieldsFilter = includedFields.length > 0
1171
1175
  ? filtersToGroq(includedFields)
1172
1176
  : "";
1173
- const filter = `brand == '${brand}' ${searchFilter} ${includedFieldsFilter} && references(*[_type=='instructor' && railcontent_id == ${id}]._id)`;
1177
+ const filter = `brand == '${brand}' ${searchFilter} ${includedFieldsFilter} && references(*[_type=='instructor' && railcontent_id == ${id}]._id)`;
1174
1178
 
1175
- sortOrder = getSortOrder(sortOrder);
1176
- const query = buildEntityAndTotalQuery(
1177
- filter,
1178
- fieldsString,
1179
- {
1180
- sortOrder: sortOrder,
1181
- start: start,
1182
- end: end,
1183
- },
1184
- );
1185
- return fetchSanity(query, true);
1179
+ sortOrder = getSortOrder(sortOrder);
1180
+ const query = buildEntityAndTotalQuery(
1181
+ filter,
1182
+ fieldsString,
1183
+ {
1184
+ sortOrder: sortOrder,
1185
+ start: start,
1186
+ end: end,
1187
+ },
1188
+ );
1189
+ return fetchSanity(query, true);
1186
1190
  }
1187
1191
 
1188
1192
  /**
@@ -1196,7 +1200,7 @@ export async function fetchCoachLessons(brand, id, {
1196
1200
  * .catch(error => console.error(error));
1197
1201
  */
1198
1202
  export async function fetchCourseOverview(id) {
1199
- return fetchByRailContentId(id, 'course');
1203
+ return fetchByRailContentId(id, 'course');
1200
1204
  }
1201
1205
 
1202
1206
  /**
@@ -1210,21 +1214,21 @@ export async function fetchCourseOverview(id) {
1210
1214
  * .catch(error => console.error(error));
1211
1215
  */
1212
1216
  export async function fetchParentForDownload(id) {
1213
- const query = buildRawQuery(
1214
- `railcontent_id == ${id}`,
1215
- getFieldsForContentType('parent-download'),
1216
- {
1217
- isSingle: true,
1218
- },
1219
- );
1217
+ const query = buildRawQuery(
1218
+ `railcontent_id == ${id}`,
1219
+ getFieldsForContentType('parent-download'),
1220
+ {
1221
+ isSingle: true,
1222
+ },
1223
+ );
1220
1224
 
1221
- return fetchSanity(query, false);
1225
+ return fetchSanity(query, false);
1222
1226
  }
1223
1227
 
1224
1228
  /**
1225
1229
  * Fetch the data needed for the coach screen.
1226
1230
  * @param {string} id - The Railcontent ID of the coach
1227
- *
1231
+ *
1228
1232
  * @returns {Promise<Object|null>} - The lessons for the instructor or null if not found.
1229
1233
  *
1230
1234
  * @example
@@ -1233,30 +1237,30 @@ export async function fetchParentForDownload(id) {
1233
1237
  * .catch(error => console.error(error));
1234
1238
  */
1235
1239
  export async function fetchByReference(brand, {
1236
- sortOrder = '-published_on',
1237
- searchTerm = '',
1238
- page = 1,
1239
- limit = 20,
1240
- includedFields = [],
1240
+ sortOrder = '-published_on',
1241
+ searchTerm = '',
1242
+ page = 1,
1243
+ limit = 20,
1244
+ includedFields = [],
1241
1245
  } = {}) {
1242
- const fieldsString = getFieldsForContentType();
1243
- const start = (page - 1) * limit;
1244
- const end = start + limit;
1245
- const searchFilter = searchTerm ? `&& title match "${searchTerm}*"`: '';
1246
- const includedFieldsFilter = includedFields.length > 0
1246
+ const fieldsString = getFieldsForContentType();
1247
+ const start = (page - 1) * limit;
1248
+ const end = start + limit;
1249
+ const searchFilter = searchTerm ? `&& title match "${searchTerm}*"` : '';
1250
+ const includedFieldsFilter = includedFields.length > 0
1247
1251
  ? includedFields.join(' && ')
1248
1252
  : "";
1249
- const filter = `brand == '${brand}' ${searchFilter} && references(*[${includedFieldsFilter}]._id)`;
1250
- const query = buildEntityAndTotalQuery(
1251
- filter,
1252
- fieldsString,
1253
- {
1254
- sortOrder: getSortOrder(sortOrder),
1255
- start: start,
1256
- end: end,
1257
- },
1258
- );
1259
- return fetchSanity(query, true);
1253
+ const filter = `brand == '${brand}' ${searchFilter} && references(*[${includedFieldsFilter}]._id)`;
1254
+ const query = buildEntityAndTotalQuery(
1255
+ filter,
1256
+ fieldsString,
1257
+ {
1258
+ sortOrder: getSortOrder(sortOrder),
1259
+ start: start,
1260
+ end: end,
1261
+ },
1262
+ );
1263
+ return fetchSanity(query, true);
1260
1264
  }
1261
1265
 
1262
1266
  /**
@@ -1279,28 +1283,28 @@ export async function fetchByReference(brand, {
1279
1283
  * .catch(error => console.error(error));
1280
1284
  */
1281
1285
  export async function fetchArtistLessons(brand, name, contentType, {
1282
- sort = '-published_on',
1283
- searchTerm = '',
1284
- page = 1,
1285
- limit = 10,
1286
- includedFields = [],
1287
- progressIds = undefined,
1286
+ sort = '-published_on',
1287
+ searchTerm = '',
1288
+ page = 1,
1289
+ limit = 10,
1290
+ includedFields = [],
1291
+ progressIds = undefined,
1288
1292
  } = {}) {
1289
1293
 
1290
- const fieldsString = DEFAULT_FIELDS.join(',');
1291
- const start = (page - 1) * limit;
1292
- const end = start + limit;
1293
- const searchFilter = searchTerm ? `&& title match "${searchTerm}*"`: ''
1294
- const sortOrder = getSortOrder(sort);
1295
- const addType = contentType && Array.isArray(contentType) ? `_type in ['${contentType.join("', '")}'] &&` : contentType ? `_type == '${contentType}' && `:''
1296
- const includedFieldsFilter = includedFields.length > 0
1297
- ? filtersToGroq(includedFields)
1298
- : "";
1294
+ const fieldsString = DEFAULT_FIELDS.join(',');
1295
+ const start = (page - 1) * limit;
1296
+ const end = start + limit;
1297
+ const searchFilter = searchTerm ? `&& title match "${searchTerm}*"` : ''
1298
+ const sortOrder = getSortOrder(sort);
1299
+ const addType = contentType && Array.isArray(contentType) ? `_type in ['${contentType.join("', '")}'] &&` : contentType ? `_type == '${contentType}' && ` : ''
1300
+ const includedFieldsFilter = includedFields.length > 0
1301
+ ? filtersToGroq(includedFields)
1302
+ : "";
1299
1303
 
1300
- // limits the results to supplied progressIds for started & completed filters
1301
- const progressFilter = progressIds !== undefined ? `&& railcontent_id in [${progressIds.join(',')}]` : "";
1304
+ // limits the results to supplied progressIds for started & completed filters
1305
+ const progressFilter = progressIds !== undefined ? `&& railcontent_id in [${progressIds.join(',')}]` : "";
1302
1306
 
1303
- const query = `{
1307
+ const query = `{
1304
1308
  "entity":
1305
1309
  *[_type == 'artist' && name == '${name}']
1306
1310
  {'type': _type, name, 'thumbnail_url':thumbnail_url.asset->url,
@@ -1309,7 +1313,7 @@ export async function fetchArtistLessons(brand, name, contentType, {
1309
1313
  [${start}...${end}]}
1310
1314
  |order(${sortOrder})
1311
1315
  }`;
1312
- return fetchSanity(query, true);
1316
+ return fetchSanity(query, true);
1313
1317
  }
1314
1318
 
1315
1319
  /**
@@ -1331,26 +1335,26 @@ export async function fetchArtistLessons(brand, name, contentType, {
1331
1335
  * .catch(error => console.error(error));
1332
1336
  */
1333
1337
  export async function fetchGenreLessons(brand, name, contentType, {
1334
- sort = '-published_on',
1335
- searchTerm = '',
1336
- page = 1,
1337
- limit = 10,
1338
- includedFields = [],
1339
- progressIds = undefined,
1338
+ sort = '-published_on',
1339
+ searchTerm = '',
1340
+ page = 1,
1341
+ limit = 10,
1342
+ includedFields = [],
1343
+ progressIds = undefined,
1340
1344
  } = {}) {
1341
- const fieldsString = DEFAULT_FIELDS.join(',');
1342
- const start = (page - 1) * limit;
1343
- const end = start + limit;
1344
- const searchFilter = searchTerm ? `&& title match "${searchTerm}*"`: ''
1345
- const sortOrder = getSortOrder(sort);
1346
- const addType = contentType ? `_type == '${contentType}' && `:''
1347
- const includedFieldsFilter = includedFields.length > 0
1348
- ? filtersToGroq(includedFields)
1349
- : "";
1350
- // limits the results to supplied progressIds for started & completed filters
1351
- const progressFilter = progressIds !== undefined ? `&& railcontent_id in [${progressIds.join(',')}]` : "";
1352
-
1353
- const query = `{
1345
+ const fieldsString = DEFAULT_FIELDS.join(',');
1346
+ const start = (page - 1) * limit;
1347
+ const end = start + limit;
1348
+ const searchFilter = searchTerm ? `&& title match "${searchTerm}*"` : ''
1349
+ const sortOrder = getSortOrder(sort);
1350
+ const addType = contentType ? `_type == '${contentType}' && ` : ''
1351
+ const includedFieldsFilter = includedFields.length > 0
1352
+ ? filtersToGroq(includedFields)
1353
+ : "";
1354
+ // limits the results to supplied progressIds for started & completed filters
1355
+ const progressFilter = progressIds !== undefined ? `&& railcontent_id in [${progressIds.join(',')}]` : "";
1356
+
1357
+ const query = `{
1354
1358
  "entity":
1355
1359
  *[_type == 'genre' && name == '${name}']
1356
1360
  {'type': _type, name, 'thumbnail_url':thumbnail_url.asset->url,
@@ -1359,7 +1363,7 @@ export async function fetchGenreLessons(brand, name, contentType, {
1359
1363
  [${start}...${end}]}
1360
1364
  |order(${sortOrder})
1361
1365
  }`;
1362
- return fetchSanity(query, true);
1366
+ return fetchSanity(query, true);
1363
1367
  }
1364
1368
 
1365
1369
  export async function fetchTopLevelParentId(railcontentId) {
@@ -1433,7 +1437,6 @@ function populateHierarchyLookups(currentLevel, data, parentId) {
1433
1437
  }
1434
1438
 
1435
1439
 
1436
-
1437
1440
  /**
1438
1441
  *
1439
1442
  * @param {string} query - The GROQ query to execute against the Sanity API.
@@ -1451,83 +1454,89 @@ function populateHierarchyLookups(currentLevel, data, parentId) {
1451
1454
 
1452
1455
  export async function fetchSanity(query,
1453
1456
  isList,
1454
- { customPostProcess = null,
1455
- processNeedAccess = true,} = {}
1457
+ {
1458
+ customPostProcess = null,
1459
+ processNeedAccess = true,
1460
+ } = {}
1456
1461
  ) {
1457
- // Check the config object before proceeding
1458
- if (!checkSanityConfig(globalConfig)) {
1459
- return null;
1460
- }
1461
-
1462
- if (globalConfig.sanityConfig.debug) {
1463
- console.log("fetchSanity Query:", query);
1464
- }
1465
- const perspective = globalConfig.sanityConfig.perspective ?? 'published';
1466
- const encodedQuery = encodeURIComponent(query);
1467
- const api = globalConfig.sanityConfig.useCachedAPI ? 'apicdn' : 'api';
1468
- const url = `https://${globalConfig.sanityConfig.projectId}.${api}.sanity.io/v${globalConfig.sanityConfig.version}/data/query/${globalConfig.sanityConfig.dataset}?perspective=${perspective}&query=${encodedQuery}`;
1469
- const headers = {
1470
- 'Authorization': `Bearer ${globalConfig.sanityConfig.token}`,
1471
- 'Content-Type': 'application/json'
1472
- };
1473
-
1474
- try {
1475
- const response = await fetch(url, {headers});
1476
- if (!response.ok) {
1477
- throw new Error(`Sanity API error: ${response.status} - ${response.statusText}`);
1478
- }
1479
- const result = await response.json();
1480
- if (result.result) {
1481
- if (globalConfig.sanityConfig.debug) {
1482
- console.log("fetchSanity Results:", result);
1483
- }
1484
- let results = isList ? result.result : result.result[0];
1485
- results = processNeedAccess ? await needsAccessDecorator(results) : results;
1486
- return customPostProcess ? customPostProcess(results) : results;
1487
- } else {
1488
- throw new Error('No results found');
1489
- }
1490
- } catch (error) {
1491
- console.error('fetchSanity: Fetch error:', error);
1492
- return null;
1493
- }
1462
+ // Check the config object before proceeding
1463
+ if (!checkSanityConfig(globalConfig)) {
1464
+ return null;
1465
+ }
1466
+
1467
+ if (globalConfig.sanityConfig.debug) {
1468
+ console.log("fetchSanity Query:", query);
1469
+ }
1470
+ const perspective = globalConfig.sanityConfig.perspective ?? 'published';
1471
+ const encodedQuery = encodeURIComponent(query);
1472
+ const api = globalConfig.sanityConfig.useCachedAPI ? 'apicdn' : 'api';
1473
+ const url = `https://${globalConfig.sanityConfig.projectId}.${api}.sanity.io/v${globalConfig.sanityConfig.version}/data/query/${globalConfig.sanityConfig.dataset}?perspective=${perspective}&query=${encodedQuery}`;
1474
+ const headers = {
1475
+ 'Authorization': `Bearer ${globalConfig.sanityConfig.token}`,
1476
+ 'Content-Type': 'application/json'
1477
+ };
1478
+
1479
+ try {
1480
+ let promisesResult = await Promise.all([
1481
+ fetch(url, {headers}),
1482
+ processNeedAccess ? fetchUserPermissions() : null
1483
+ ]);
1484
+ const response = promisesResult[0];
1485
+ const userPermissions = promisesResult[1]?.permissions;
1486
+
1487
+ if (!response.ok) {
1488
+ throw new Error(`Sanity API error: ${response.status} - ${response.statusText}`);
1489
+ }
1490
+ const result = await response.json();
1491
+ if (result.result) {
1492
+ if (globalConfig.sanityConfig.debug) {
1493
+ console.log("fetchSanity Results:", result);
1494
+ }
1495
+ let results = isList ? result.result : result.result[0];
1496
+ results = processNeedAccess ? await needsAccessDecorator(results, userPermissions) : results;
1497
+ return customPostProcess ? customPostProcess(results) : results;
1498
+ } else {
1499
+ throw new Error('No results found');
1500
+ }
1501
+ } catch (error) {
1502
+ console.error('fetchSanity: Fetch error:', error);
1503
+ return null;
1504
+ }
1494
1505
  }
1495
1506
 
1496
- async function needsAccessDecorator(results) {
1497
- if (globalConfig.sanityConfig.useDummyRailContentMethods) return results;
1498
-
1499
- let userPermissions = await getUserPermissions();
1500
- userPermissions = new Set(userPermissions);
1501
-
1502
- if (Array.isArray(results)) {
1503
- results.forEach((result) => {
1504
- result['need_access'] = doesUserNeedAccessToContent(result, userPermissions);
1505
- });
1506
- } else if (results.entity && Array.isArray(results.entity)) {
1507
- // Group By
1508
- results.entity.forEach((result) => {
1509
- if (result.lessons) {
1510
- result.lessons.forEach((lesson) => {
1511
- lesson['need_access'] = doesUserNeedAccessToContent(lesson, userPermissions); // Updated to check lesson access
1512
- });
1513
- } else {
1514
- result['need_access'] = doesUserNeedAccessToContent(result, userPermissions);
1515
- }
1516
- });
1517
- } else if (results.related_lessons && Array.isArray(results.related_lessons)) {
1518
- results.related_lessons.forEach((result) => {
1519
- result['need_access'] = doesUserNeedAccessToContent(result, userPermissions);
1520
- })
1521
- } else {
1522
- results['need_access'] = doesUserNeedAccessToContent(results, userPermissions);
1523
- }
1524
-
1525
- return results;
1507
+ function needsAccessDecorator(results, userPermissions) {
1508
+ if (globalConfig.sanityConfig.useDummyRailContentMethods) return results;
1509
+
1510
+ userPermissions = new Set(userPermissions);
1511
+
1512
+ if (Array.isArray(results)) {
1513
+ results.forEach((result) => {
1514
+ result['need_access'] = doesUserNeedAccessToContent(result, userPermissions);
1515
+ });
1516
+ } else if (results.entity && Array.isArray(results.entity)) {
1517
+ // Group By
1518
+ results.entity.forEach((result) => {
1519
+ if (result.lessons) {
1520
+ result.lessons.forEach((lesson) => {
1521
+ lesson['need_access'] = doesUserNeedAccessToContent(lesson, userPermissions); // Updated to check lesson access
1522
+ });
1523
+ } else {
1524
+ result['need_access'] = doesUserNeedAccessToContent(result, userPermissions);
1525
+ }
1526
+ });
1527
+ } else if (results.related_lessons && Array.isArray(results.related_lessons)) {
1528
+ results.related_lessons.forEach((result) => {
1529
+ result['need_access'] = doesUserNeedAccessToContent(result, userPermissions);
1530
+ })
1531
+ } else {
1532
+ results['need_access'] = doesUserNeedAccessToContent(results, userPermissions);
1533
+ }
1534
+
1535
+ return results;
1526
1536
  }
1527
1537
 
1528
- function doesUserNeedAccessToContent(result, userPermissions)
1529
- {
1530
- const permissions = new Set(result?.permission_id ?? []);
1538
+ function doesUserNeedAccessToContent(result, userPermissions) {
1539
+ const permissions = new Set(result?.permission_id ?? []);
1531
1540
  if (permissions.size === 0) {
1532
1541
  return false;
1533
1542
  }
@@ -1539,12 +1548,6 @@ function doesUserNeedAccessToContent(result, userPermissions)
1539
1548
  return true;
1540
1549
  }
1541
1550
 
1542
- async function getUserPermissions()
1543
- {
1544
- return await fetchUserPermissions();
1545
- }
1546
-
1547
-
1548
1551
  /**
1549
1552
  * Fetch CatalogueMetadata from Sanity. This information may be duplicated in the contentTypeConfig.js.
1550
1553
  * It's an ongoing discussion (Aug 2024), but it's been included here if necessary
@@ -1558,8 +1561,8 @@ async function getUserPermissions()
1558
1561
  * .then(data => console.log(data))
1559
1562
  * .catch(error => console.error(error));
1560
1563
  */
1561
- export async function fetchCatalogMetadata(contentType)
1562
- { const query = `*[_type == 'CatalogMetadata']{
1564
+ export async function fetchCatalogMetadata(contentType) {
1565
+ const query = `*[_type == 'CatalogMetadata']{
1563
1566
  catalog_type,
1564
1567
  brand,
1565
1568
  groq_results,
@@ -1568,7 +1571,7 @@ export async function fetchCatalogMetadata(contentType)
1568
1571
  modal_text,
1569
1572
  sort_by,
1570
1573
  }`
1571
- return fetchSanity(query, false, {processNeedAccess:false});
1574
+ return fetchSanity(query, false, {processNeedAccess: false});
1572
1575
  }
1573
1576
 
1574
1577
  /**
@@ -1616,43 +1619,43 @@ export async function fetchMetadata(brand, type) {
1616
1619
 
1617
1620
  //Helper Functions
1618
1621
  function arrayJoinWithQuotes(array, delimiter = ',') {
1619
- const wrapped = array.map(value => `'${value}'`);
1620
- return wrapped.join(delimiter)
1622
+ const wrapped = array.map(value => `'${value}'`);
1623
+ return wrapped.join(delimiter)
1621
1624
  }
1622
1625
 
1623
1626
  function getSanityDate(date) {
1624
- return date.toISOString();
1627
+ return date.toISOString();
1625
1628
  }
1626
1629
 
1627
1630
  const merge = (a, b, predicate = (a, b) => a === b) => {
1628
- const c = [...a]; // copy to avoid side effects
1629
- // add all items from B to copy C if they're not already present
1630
- b.forEach((bItem) => (c.some((cItem) => predicate(bItem, cItem)) ? null : c.push(bItem)))
1631
- return c;
1631
+ const c = [...a]; // copy to avoid side effects
1632
+ // add all items from B to copy C if they're not already present
1633
+ b.forEach((bItem) => (c.some((cItem) => predicate(bItem, cItem)) ? null : c.push(bItem)))
1634
+ return c;
1632
1635
  }
1633
1636
 
1634
1637
  function checkSanityConfig(config) {
1635
- if (!config.sanityConfig.token) {
1636
- console.warn('fetchSanity: The "token" property is missing in the config object.');
1637
- return false;
1638
- }
1639
- if (!config.sanityConfig.projectId) {
1640
- console.warn('fetchSanity: The "projectId" property is missing in the config object.');
1641
- return false;
1642
- }
1643
- if (!config.sanityConfig.dataset) {
1644
- console.warn('fetchSanity: The "dataset" property is missing in the config object.');
1645
- return false;
1646
- }
1647
- if (!config.sanityConfig.version) {
1648
- console.warn('fetchSanity: The "version" property is missing in the config object.');
1649
- return false;
1650
- }
1651
- return true;
1638
+ if (!config.sanityConfig.token) {
1639
+ console.warn('fetchSanity: The "token" property is missing in the config object.');
1640
+ return false;
1641
+ }
1642
+ if (!config.sanityConfig.projectId) {
1643
+ console.warn('fetchSanity: The "projectId" property is missing in the config object.');
1644
+ return false;
1645
+ }
1646
+ if (!config.sanityConfig.dataset) {
1647
+ console.warn('fetchSanity: The "dataset" property is missing in the config object.');
1648
+ return false;
1649
+ }
1650
+ if (!config.sanityConfig.version) {
1651
+ console.warn('fetchSanity: The "version" property is missing in the config object.');
1652
+ return false;
1653
+ }
1654
+ return true;
1652
1655
  }
1653
1656
 
1654
1657
 
1655
- function buildRawQuery(
1658
+ function buildRawQuery(
1656
1659
  filter = '',
1657
1660
  fields = '...',
1658
1661
  {
@@ -1671,7 +1674,7 @@ function buildRawQuery(
1671
1674
  }
1672
1675
 
1673
1676
 
1674
- function buildQuery(
1677
+ async function buildQuery(
1675
1678
  baseFilter = '',
1676
1679
  filterParams = {},
1677
1680
  fields = '...',
@@ -1682,11 +1685,11 @@ function buildQuery(
1682
1685
  isSingle = false,
1683
1686
  },
1684
1687
  ) {
1685
- const filter = new FilterBuilder(baseFilter, filterParams).buildFilter();
1688
+ const filter = await new FilterBuilder(baseFilter, filterParams).buildFilter();
1686
1689
  return buildRawQuery(filter, fields, {sortOrder, start, end, isSingle});
1687
1690
  }
1688
1691
 
1689
- function buildEntityAndTotalQuery(
1692
+ function buildEntityAndTotalQuery(
1690
1693
  filter = '',
1691
1694
  fields = '...',
1692
1695
  {
@@ -1709,9 +1712,9 @@ function buildEntityAndTotalQuery(
1709
1712
  }
1710
1713
 
1711
1714
 
1712
- function getFilterOptions(option, commonFilter,contentType, brand){
1715
+ function getFilterOptions(option, commonFilter, contentType, brand) {
1713
1716
  let filterGroq = '';
1714
- const types = Array.from(new Set([...coachLessonsTypes,...showsTypes[brand]]));
1717
+ const types = Array.from(new Set([...coachLessonsTypes, ...showsTypes[brand]]));
1715
1718
 
1716
1719
  switch (option) {
1717
1720
  case "difficulty":