musora-content-services 1.0.39 → 1.0.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
4
 
5
+ ### [1.0.40](https://github.com/railroadmedia/musora-content-services/compare/v1.0.39...v1.0.40) (2024-08-20)
6
+
5
7
  ### [1.0.39](https://github.com/railroadmedia/musora-content-services/compare/v1.0.37...v1.0.39) (2024-08-20)
6
8
 
7
9
  ### [1.0.37](https://github.com/railroadmedia/musora-content-services/compare/v1.0.35...v1.0.37) (2024-08-20)
@@ -111,7 +111,7 @@ module.exports = {
111
111
  <br class="clear">
112
112
 
113
113
  <footer>
114
- Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.3</a> on Tue Aug 20 2024 12:50:34 GMT+0000 (Coordinated Universal Time) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
114
+ Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.3</a> on Tue Aug 20 2024 14:36:28 GMT+0000 (Coordinated Universal Time) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
115
115
  </footer>
116
116
 
117
117
  <script>prettyPrint();</script>
package/docs/index.html CHANGED
@@ -110,7 +110,7 @@ Run the following to execute the tests</p>
110
110
  <br class="clear">
111
111
 
112
112
  <footer>
113
- Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.3</a> on Tue Aug 20 2024 12:50:34 GMT+0000 (Coordinated Universal Time) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
113
+ Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.3</a> on Tue Aug 20 2024 14:36:28 GMT+0000 (Coordinated Universal Time) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
114
114
  </footer>
115
115
 
116
116
  <script>prettyPrint();</script>
@@ -656,7 +656,7 @@ initializeService({
656
656
  <br class="clear">
657
657
 
658
658
  <footer>
659
- Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.3</a> on Tue Aug 20 2024 12:50:34 GMT+0000 (Coordinated Universal Time) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
659
+ Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.3</a> on Tue Aug 20 2024 14:36:28 GMT+0000 (Coordinated Universal Time) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
660
660
  </footer>
661
661
 
662
662
  <script>prettyPrint();</script>
@@ -783,7 +783,7 @@
783
783
  <br class="clear">
784
784
 
785
785
  <footer>
786
- Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.3</a> on Tue Aug 20 2024 12:50:34 GMT+0000 (Coordinated Universal Time) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
786
+ Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.3</a> on Tue Aug 20 2024 14:36:28 GMT+0000 (Coordinated Universal Time) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
787
787
  </footer>
788
788
 
789
789
  <script>prettyPrint();</script>
@@ -100,7 +100,7 @@
100
100
 
101
101
  <dt class="tag-source">Source:</dt>
102
102
  <dd class="tag-source"><ul class="dummy"><li>
103
- <a href="sanity.js.html">sanity.js</a>, <a href="sanity.js.html#line412">line 412</a>
103
+ <a href="sanity.js.html">sanity.js</a>, <a href="sanity.js.html#line465">line 465</a>
104
104
  </li></ul></dd>
105
105
 
106
106
 
@@ -593,7 +593,7 @@ The filter options are dynamically generated based on the provided filters, styl
593
593
 
594
594
  <dt class="tag-source">Source:</dt>
595
595
  <dd class="tag-source"><ul class="dummy"><li>
596
- <a href="sanity.js.html">sanity.js</a>, <a href="sanity.js.html#line554">line 554</a>
596
+ <a href="sanity.js.html">sanity.js</a>, <a href="sanity.js.html#line607">line 607</a>
597
597
  </li></ul></dd>
598
598
 
599
599
 
@@ -1566,7 +1566,7 @@ fetchAllFilterOptions('myBrand', '', 'Rock', 'John Doe', 'song', 'Love')
1566
1566
 
1567
1567
  <dt class="tag-source">Source:</dt>
1568
1568
  <dd class="tag-source"><ul class="dummy"><li>
1569
- <a href="sanity.js.html">sanity.js</a>, <a href="sanity.js.html#line345">line 345</a>
1569
+ <a href="sanity.js.html">sanity.js</a>, <a href="sanity.js.html#line398">line 398</a>
1570
1570
  </li></ul></dd>
1571
1571
 
1572
1572
 
@@ -1731,7 +1731,7 @@ fetchAllFilterOptions('myBrand', '', 'Rock', 'John Doe', 'song', 'Love')
1731
1731
 
1732
1732
  <dt class="tag-source">Source:</dt>
1733
1733
  <dd class="tag-source"><ul class="dummy"><li>
1734
- <a href="sanity.js.html">sanity.js</a>, <a href="sanity.js.html#line371">line 371</a>
1734
+ <a href="sanity.js.html">sanity.js</a>, <a href="sanity.js.html#line424">line 424</a>
1735
1735
  </li></ul></dd>
1736
1736
 
1737
1737
 
@@ -1896,7 +1896,7 @@ fetchAllFilterOptions('myBrand', '', 'Rock', 'John Doe', 'song', 'Love')
1896
1896
 
1897
1897
  <dt class="tag-source">Source:</dt>
1898
1898
  <dd class="tag-source"><ul class="dummy"><li>
1899
- <a href="sanity.js.html">sanity.js</a>, <a href="sanity.js.html#line597">line 597</a>
1899
+ <a href="sanity.js.html">sanity.js</a>, <a href="sanity.js.html#line650">line 650</a>
1900
1900
  </li></ul></dd>
1901
1901
 
1902
1902
 
@@ -2054,7 +2054,7 @@ fetchAllFilterOptions('myBrand', '', 'Rock', 'John Doe', 'song', 'Love')
2054
2054
 
2055
2055
  <dt class="tag-source">Source:</dt>
2056
2056
  <dd class="tag-source"><ul class="dummy"><li>
2057
- <a href="sanity.js.html">sanity.js</a>, <a href="sanity.js.html#line769">line 769</a>
2057
+ <a href="sanity.js.html">sanity.js</a>, <a href="sanity.js.html#line822">line 822</a>
2058
2058
  </li></ul></dd>
2059
2059
 
2060
2060
 
@@ -2219,7 +2219,7 @@ fetchAllFilterOptions('myBrand', '', 'Rock', 'John Doe', 'song', 'Love')
2219
2219
 
2220
2220
  <dt class="tag-source">Source:</dt>
2221
2221
  <dd class="tag-source"><ul class="dummy"><li>
2222
- <a href="sanity.js.html">sanity.js</a>, <a href="sanity.js.html#line675">line 675</a>
2222
+ <a href="sanity.js.html">sanity.js</a>, <a href="sanity.js.html#line728">line 728</a>
2223
2223
  </li></ul></dd>
2224
2224
 
2225
2225
 
@@ -2384,7 +2384,7 @@ fetchAllFilterOptions('myBrand', '', 'Rock', 'John Doe', 'song', 'Love')
2384
2384
 
2385
2385
  <dt class="tag-source">Source:</dt>
2386
2386
  <dd class="tag-source"><ul class="dummy"><li>
2387
- <a href="sanity.js.html">sanity.js</a>, <a href="sanity.js.html#line639">line 639</a>
2387
+ <a href="sanity.js.html">sanity.js</a>, <a href="sanity.js.html#line692">line 692</a>
2388
2388
  </li></ul></dd>
2389
2389
 
2390
2390
 
@@ -2542,7 +2542,7 @@ fetchAllFilterOptions('myBrand', '', 'Rock', 'John Doe', 'song', 'Love')
2542
2542
 
2543
2543
  <dt class="tag-source">Source:</dt>
2544
2544
  <dd class="tag-source"><ul class="dummy"><li>
2545
- <a href="sanity.js.html">sanity.js</a>, <a href="sanity.js.html#line618">line 618</a>
2545
+ <a href="sanity.js.html">sanity.js</a>, <a href="sanity.js.html#line671">line 671</a>
2546
2546
  </li></ul></dd>
2547
2547
 
2548
2548
 
@@ -2700,7 +2700,7 @@ fetchAllFilterOptions('myBrand', '', 'Rock', 'John Doe', 'song', 'Love')
2700
2700
 
2701
2701
  <dt class="tag-source">Source:</dt>
2702
2702
  <dd class="tag-source"><ul class="dummy"><li>
2703
- <a href="sanity.js.html">sanity.js</a>, <a href="sanity.js.html#line269">line 269</a>
2703
+ <a href="sanity.js.html">sanity.js</a>, <a href="sanity.js.html#line322">line 322</a>
2704
2704
  </li></ul></dd>
2705
2705
 
2706
2706
 
@@ -2858,7 +2858,7 @@ fetchAllFilterOptions('myBrand', '', 'Rock', 'John Doe', 'song', 'Love')
2858
2858
 
2859
2859
  <dt class="tag-source">Source:</dt>
2860
2860
  <dd class="tag-source"><ul class="dummy"><li>
2861
- <a href="sanity.js.html">sanity.js</a>, <a href="sanity.js.html#line649">line 649</a>
2861
+ <a href="sanity.js.html">sanity.js</a>, <a href="sanity.js.html#line702">line 702</a>
2862
2862
  </li></ul></dd>
2863
2863
 
2864
2864
 
@@ -3016,7 +3016,7 @@ fetchAllFilterOptions('myBrand', '', 'Rock', 'John Doe', 'song', 'Love')
3016
3016
 
3017
3017
  <dt class="tag-source">Source:</dt>
3018
3018
  <dd class="tag-source"><ul class="dummy"><li>
3019
- <a href="sanity.js.html">sanity.js</a>, <a href="sanity.js.html#line729">line 729</a>
3019
+ <a href="sanity.js.html">sanity.js</a>, <a href="sanity.js.html#line782">line 782</a>
3020
3020
  </li></ul></dd>
3021
3021
 
3022
3022
 
@@ -3174,7 +3174,7 @@ fetchAllFilterOptions('myBrand', '', 'Rock', 'John Doe', 'song', 'Love')
3174
3174
 
3175
3175
  <dt class="tag-source">Source:</dt>
3176
3176
  <dd class="tag-source"><ul class="dummy"><li>
3177
- <a href="sanity.js.html">sanity.js</a>, <a href="sanity.js.html#line755">line 755</a>
3177
+ <a href="sanity.js.html">sanity.js</a>, <a href="sanity.js.html#line808">line 808</a>
3178
3178
  </li></ul></dd>
3179
3179
 
3180
3180
 
@@ -3339,7 +3339,7 @@ fetchAllFilterOptions('myBrand', '', 'Rock', 'John Doe', 'song', 'Love')
3339
3339
 
3340
3340
  <dt class="tag-source">Source:</dt>
3341
3341
  <dd class="tag-source"><ul class="dummy"><li>
3342
- <a href="sanity.js.html">sanity.js</a>, <a href="sanity.js.html#line708">line 708</a>
3342
+ <a href="sanity.js.html">sanity.js</a>, <a href="sanity.js.html#line761">line 761</a>
3343
3343
  </li></ul></dd>
3344
3344
 
3345
3345
 
@@ -3710,7 +3710,7 @@ fetchAllFilterOptions('myBrand', '', 'Rock', 'John Doe', 'song', 'Love')
3710
3710
 
3711
3711
  <dt class="tag-source">Source:</dt>
3712
3712
  <dd class="tag-source"><ul class="dummy"><li>
3713
- <a href="sanity.js.html">sanity.js</a>, <a href="sanity.js.html#line810">line 810</a>
3713
+ <a href="sanity.js.html">sanity.js</a>, <a href="sanity.js.html#line863">line 863</a>
3714
3714
  </li></ul></dd>
3715
3715
 
3716
3716
 
@@ -4546,7 +4546,7 @@ fetchSanity(query, true)
4546
4546
 
4547
4547
  <dt class="tag-source">Source:</dt>
4548
4548
  <dd class="tag-source"><ul class="dummy"><li>
4549
- <a href="sanity.js.html">sanity.js</a>, <a href="sanity.js.html#line306">line 306</a>
4549
+ <a href="sanity.js.html">sanity.js</a>, <a href="sanity.js.html#line359">line 359</a>
4550
4550
  </li></ul></dd>
4551
4551
 
4552
4552
 
@@ -4705,14 +4705,15 @@ fetchSanity(query, true)
4705
4705
  <dl class="details">
4706
4706
 
4707
4707
  <dt class="tag-description">Description:</dt>
4708
- <dd class="tag-description"><ul class="dummy"><li>Fetch the latest workouts for the home page of a specific brand.
4709
- This function retrieves the latest workout content for a given brand, fetching up to five workouts. The workouts are sorted in descending order by their publication date.</li></ul></dd>
4708
+ <dd class="tag-description"><ul class="dummy"><li>Fetch the latest workouts for a specific brand, including completion status and progress.
4709
+ This function retrieves up to five of the latest workout content for a given brand, sorted in descending order by their publication date.
4710
+ It also includes completion status and progress percentage for each workout by fetching additional data about user progress.</li></ul></dd>
4710
4711
 
4711
4712
 
4712
4713
 
4713
4714
  <dt class="tag-source">Source:</dt>
4714
4715
  <dd class="tag-source"><ul class="dummy"><li>
4715
- <a href="sanity.js.html">sanity.js</a>, <a href="sanity.js.html#line247">line 247</a>
4716
+ <a href="sanity.js.html">sanity.js</a>, <a href="sanity.js.html#line250">line 250</a>
4716
4717
  </li></ul></dd>
4717
4718
 
4718
4719
 
@@ -4834,7 +4835,7 @@ This function retrieves the latest workout content for a given brand, fetching u
4834
4835
 
4835
4836
 
4836
4837
  <div class="param-desc">
4837
- - A promise that resolves to an array of workout data objects or null if no workouts are found.
4838
+ - A promise that resolves to an array of workout data objects with additional properties for completion status and progress percentage, or null if no workouts are found.
4838
4839
  </div>
4839
4840
 
4840
4841
 
@@ -4876,7 +4877,7 @@ This function retrieves the latest workout content for a given brand, fetching u
4876
4877
  <br class="clear">
4877
4878
 
4878
4879
  <footer>
4879
- Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.3</a> on Tue Aug 20 2024 12:50:34 GMT+0000 (Coordinated Universal Time) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
4880
+ Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.3</a> on Tue Aug 20 2024 14:36:28 GMT+0000 (Coordinated Universal Time) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
4880
4881
  </footer>
4881
4882
 
4882
4883
  <script>prettyPrint();</script>
@@ -201,7 +201,7 @@ export async function fetchContentInProgress(type="all", brand) {
201
201
  <br class="clear">
202
202
 
203
203
  <footer>
204
- Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.3</a> on Tue Aug 20 2024 12:50:34 GMT+0000 (Coordinated Universal Time) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
204
+ Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.3</a> on Tue Aug 20 2024 14:36:28 GMT+0000 (Coordinated Universal Time) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
205
205
  </footer>
206
206
 
207
207
  <script>prettyPrint();</script>
@@ -281,33 +281,86 @@ export async function fetchSongCount(brand) {
281
281
  }
282
282
 
283
283
  /**
284
- * Fetch the latest workouts for the home page of a specific brand.
285
- * This function retrieves the latest workout content for a given brand, fetching up to five workouts. The workouts are sorted in descending order by their publication date.
286
- * @param {string} brand - The brand for which to fetch workouts (e.g., 'drumeo', 'pianote').
287
- * @returns {Promise&lt;Array&lt;Object>|null>} - A promise that resolves to an array of workout data objects or null if no workouts are found.
288
- *
289
- * @example
290
- * fetchWorkouts('drumeo')
291
- * .then(workouts => console.log(workouts))
292
- * .catch(error => console.error(error));
293
- */
284
+ * Fetch the latest workouts for a specific brand, including completion status and progress.
285
+ * This function retrieves up to five of the latest workout content for a given brand, sorted in descending order by their publication date.
286
+ * It also includes completion status and progress percentage for each workout by fetching additional data about user progress.
287
+ *
288
+ * @param {string} brand - The brand for which to fetch workouts (e.g., 'drumeo', 'pianote').
289
+ * @returns {Promise&lt;Array&lt;Object>|null>} - A promise that resolves to an array of workout data objects with additional properties for completion status and progress percentage, or null if no workouts are found.
290
+ *
291
+ * @example
292
+ * fetchWorkouts('drumeo')
293
+ * .then(workouts => console.log(workouts))
294
+ * .catch(error => console.error(error));
295
+ */
296
+
294
297
  export async function fetchWorkouts(brand) {
295
- const query = `*[_type == 'workout' &amp;&amp; brand == '${brand}'] [0...5] {
296
- "id": railcontent_id,
297
- title,
298
- "image": thumbnail.asset->url,
299
- "artist_name": instructor[0]->name,
300
- "artists": instructor[]->name,
301
- difficulty,
302
- difficulty_string,
303
- length_in_seconds,
304
- published_on,
305
- "type": _type,
306
- web_url_path,
307
- } | order(published_on desc)[0...5]`
308
- return fetchSanity(query, true);
298
+ const query = `*[_type == 'workout' &amp;&amp; brand == '${brand}'] [0...5] {
299
+ "id": railcontent_id,
300
+ title,
301
+ "image": thumbnail.asset->url,
302
+ "artist_name": instructor[0]->name,
303
+ "artists": instructor[]->name,
304
+ difficulty,
305
+ difficulty_string,
306
+ length_in_seconds,
307
+ published_on,
308
+ "type": _type,
309
+ web_url_path,
310
+ } | order(published_on desc)[0...5]`;
311
+
312
+ try {
313
+ // Fetch the workouts
314
+ const workouts = await fetchSanity(query, true);
315
+
316
+ if (!workouts || workouts.length === 0) {
317
+ return [];
318
+ }
319
+
320
+ // Extract content IDs
321
+ const contentIds = workouts.map(workout => workout.id);
322
+
323
+ // Fetch completion states using the existing function
324
+ const completedStatesObject = await fetchAllCompletedStates(contentIds);
325
+
326
+ // Check if completedStatesObject is an object and convert to array if necessary
327
+ if (typeof completedStatesObject !== 'object' || completedStatesObject === null) {
328
+ console.error('Completed states are not an object:', completedStatesObject);
329
+ return workouts;
330
+ }
331
+
332
+ // Convert object to array and create a map for fast lookup
333
+ const completedStatesArray = Object.entries(completedStatesObject).map(([content_id, state]) => ({
334
+ content_id: parseInt(content_id, 10), // Convert key to integer if necessary
335
+ ...state
336
+ }));
337
+
338
+ const completedStatesMap = completedStatesArray.reduce((map, state) => {
339
+ map[state.content_id] = state;
340
+ return map;
341
+ }, {});
342
+
343
+ // Add completion status and progress percentage to each workout
344
+ return workouts.map(workout => {
345
+ const state = completedStatesMap[workout.id];
346
+ if (state) {
347
+ workout.completed = state.state !== "not started";
348
+ workout.progress_percent = state.percent.toString();
349
+ } else {
350
+ workout.completed = false;
351
+ workout.progress_percent = "0";
352
+ }
353
+ //console.log(workout)
354
+ return workout;
355
+ });
356
+
357
+ } catch (error) {
358
+ console.error('Error fetching workouts with completion:', error);
359
+ return [];
360
+ }
309
361
  }
310
362
 
363
+
311
364
  /**
312
365
  * Fetch the latest new releases for a specific brand.
313
366
  * @param {string} brand - The brand for which to fetch new releases.
@@ -470,44 +523,44 @@ export async function fetchAll(brand, type, {
470
523
  const start = (page - 1) * limit;
471
524
  const end = start + limit;
472
525
 
473
- // Construct the search filter
474
- const searchFilter = searchTerm
475
- ? `&amp;&amp; (artist->name match "${searchTerm}*" || title match "${searchTerm}*")`
476
- : "";
477
-
478
- // Construct the included fields filter, replacing 'difficulty' with 'difficulty_string'
479
- const includedFieldsFilter = includedFields.length > 0
480
- ? includedFields.map(field => {
481
- let [key, value] = field.split(',');
482
- if (key === 'difficulty') {
483
- key = 'difficulty_string';
484
- }
485
- return `&amp;&amp; ${key} == "${value}"`;
486
- }).join(' ')
487
- : "";
488
-
489
- // Determine the sort order
490
- let sortOrder;
491
- switch (sort) {
492
- case "slug":
493
- sortOrder = "artist->name asc";
494
- break;
495
- case "published_on":
496
- sortOrder = "published_on asc";
497
- break;
498
- case "-published_on":
499
- sortOrder = "published_on desc";
500
- break;
501
- case "-slug":
502
- sortOrder = "artist->name desc";
503
- break;
504
- case "-popularity":
505
- sortOrder = "popularity desc";
506
- break;
507
- default:
508
- sortOrder = "published_on asc";
509
- break;
510
- }
526
+ // Construct the search filter
527
+ const searchFilter = searchTerm
528
+ ? `&amp;&amp; (artist->name match "${searchTerm}*" || title match "${searchTerm}*")`
529
+ : "";
530
+
531
+ // Construct the included fields filter, replacing 'difficulty' with 'difficulty_string'
532
+ const includedFieldsFilter = includedFields.length > 0
533
+ ? includedFields.map(field => {
534
+ let [key, value] = field.split(',');
535
+ if (key === 'difficulty') {
536
+ key = 'difficulty_string';
537
+ }
538
+ return `&amp;&amp; ${key} == "${value}"`;
539
+ }).join(' ')
540
+ : "";
541
+
542
+ // Determine the sort order
543
+ let sortOrder;
544
+ switch (sort) {
545
+ case "slug":
546
+ sortOrder = "artist->name asc";
547
+ break;
548
+ case "published_on":
549
+ sortOrder = "published_on asc";
550
+ break;
551
+ case "-published_on":
552
+ sortOrder = "published_on desc";
553
+ break;
554
+ case "-slug":
555
+ sortOrder = "artist->name desc";
556
+ break;
557
+ case "-popularity":
558
+ sortOrder = "popularity desc";
559
+ break;
560
+ default:
561
+ sortOrder = "published_on asc";
562
+ break;
563
+ }
511
564
 
512
565
  let defaultFields = [
513
566
  '"id": railcontent_id',
@@ -936,7 +989,7 @@ function checkSanityConfig(config) {
936
989
  <br class="clear">
937
990
 
938
991
  <footer>
939
- Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.3</a> on Tue Aug 20 2024 12:50:34 GMT+0000 (Coordinated Universal Time) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
992
+ Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.3</a> on Tue Aug 20 2024 14:36:28 GMT+0000 (Coordinated Universal Time) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
940
993
  </footer>
941
994
 
942
995
  <script>prettyPrint();</script>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "musora-content-services",
3
- "version": "1.0.39",
3
+ "version": "1.0.40",
4
4
  "description": "A package for Musoras content services ",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
@@ -234,33 +234,86 @@ export async function fetchSongCount(brand) {
234
234
  }
235
235
 
236
236
  /**
237
- * Fetch the latest workouts for the home page of a specific brand.
238
- * This function retrieves the latest workout content for a given brand, fetching up to five workouts. The workouts are sorted in descending order by their publication date.
239
- * @param {string} brand - The brand for which to fetch workouts (e.g., 'drumeo', 'pianote').
240
- * @returns {Promise<Array<Object>|null>} - A promise that resolves to an array of workout data objects or null if no workouts are found.
241
- *
242
- * @example
243
- * fetchWorkouts('drumeo')
244
- * .then(workouts => console.log(workouts))
245
- * .catch(error => console.error(error));
246
- */
237
+ * Fetch the latest workouts for a specific brand, including completion status and progress.
238
+ * This function retrieves up to five of the latest workout content for a given brand, sorted in descending order by their publication date.
239
+ * It also includes completion status and progress percentage for each workout by fetching additional data about user progress.
240
+ *
241
+ * @param {string} brand - The brand for which to fetch workouts (e.g., 'drumeo', 'pianote').
242
+ * @returns {Promise<Array<Object>|null>} - A promise that resolves to an array of workout data objects with additional properties for completion status and progress percentage, or null if no workouts are found.
243
+ *
244
+ * @example
245
+ * fetchWorkouts('drumeo')
246
+ * .then(workouts => console.log(workouts))
247
+ * .catch(error => console.error(error));
248
+ */
249
+
247
250
  export async function fetchWorkouts(brand) {
248
- const query = `*[_type == 'workout' && brand == '${brand}'] [0...5] {
249
- "id": railcontent_id,
250
- title,
251
- "image": thumbnail.asset->url,
252
- "artist_name": instructor[0]->name,
253
- "artists": instructor[]->name,
254
- difficulty,
255
- difficulty_string,
256
- length_in_seconds,
257
- published_on,
258
- "type": _type,
259
- web_url_path,
260
- } | order(published_on desc)[0...5]`
261
- return fetchSanity(query, true);
251
+ const query = `*[_type == 'workout' && brand == '${brand}'] [0...5] {
252
+ "id": railcontent_id,
253
+ title,
254
+ "image": thumbnail.asset->url,
255
+ "artist_name": instructor[0]->name,
256
+ "artists": instructor[]->name,
257
+ difficulty,
258
+ difficulty_string,
259
+ length_in_seconds,
260
+ published_on,
261
+ "type": _type,
262
+ web_url_path,
263
+ } | order(published_on desc)[0...5]`;
264
+
265
+ try {
266
+ // Fetch the workouts
267
+ const workouts = await fetchSanity(query, true);
268
+
269
+ if (!workouts || workouts.length === 0) {
270
+ return [];
271
+ }
272
+
273
+ // Extract content IDs
274
+ const contentIds = workouts.map(workout => workout.id);
275
+
276
+ // Fetch completion states using the existing function
277
+ const completedStatesObject = await fetchAllCompletedStates(contentIds);
278
+
279
+ // Check if completedStatesObject is an object and convert to array if necessary
280
+ if (typeof completedStatesObject !== 'object' || completedStatesObject === null) {
281
+ console.error('Completed states are not an object:', completedStatesObject);
282
+ return workouts;
283
+ }
284
+
285
+ // Convert object to array and create a map for fast lookup
286
+ const completedStatesArray = Object.entries(completedStatesObject).map(([content_id, state]) => ({
287
+ content_id: parseInt(content_id, 10), // Convert key to integer if necessary
288
+ ...state
289
+ }));
290
+
291
+ const completedStatesMap = completedStatesArray.reduce((map, state) => {
292
+ map[state.content_id] = state;
293
+ return map;
294
+ }, {});
295
+
296
+ // Add completion status and progress percentage to each workout
297
+ return workouts.map(workout => {
298
+ const state = completedStatesMap[workout.id];
299
+ if (state) {
300
+ workout.completed = state.state !== "not started";
301
+ workout.progress_percent = state.percent.toString();
302
+ } else {
303
+ workout.completed = false;
304
+ workout.progress_percent = "0";
305
+ }
306
+ //console.log(workout)
307
+ return workout;
308
+ });
309
+
310
+ } catch (error) {
311
+ console.error('Error fetching workouts with completion:', error);
312
+ return [];
313
+ }
262
314
  }
263
315
 
316
+
264
317
  /**
265
318
  * Fetch the latest new releases for a specific brand.
266
319
  * @param {string} brand - The brand for which to fetch new releases.
@@ -423,44 +476,44 @@ export async function fetchAll(brand, type, {
423
476
  const start = (page - 1) * limit;
424
477
  const end = start + limit;
425
478
 
426
- // Construct the search filter
427
- const searchFilter = searchTerm
428
- ? `&& (artist->name match "${searchTerm}*" || title match "${searchTerm}*")`
429
- : "";
430
-
431
- // Construct the included fields filter, replacing 'difficulty' with 'difficulty_string'
432
- const includedFieldsFilter = includedFields.length > 0
433
- ? includedFields.map(field => {
434
- let [key, value] = field.split(',');
435
- if (key === 'difficulty') {
436
- key = 'difficulty_string';
437
- }
438
- return `&& ${key} == "${value}"`;
439
- }).join(' ')
440
- : "";
441
-
442
- // Determine the sort order
443
- let sortOrder;
444
- switch (sort) {
445
- case "slug":
446
- sortOrder = "artist->name asc";
447
- break;
448
- case "published_on":
449
- sortOrder = "published_on asc";
450
- break;
451
- case "-published_on":
452
- sortOrder = "published_on desc";
453
- break;
454
- case "-slug":
455
- sortOrder = "artist->name desc";
456
- break;
457
- case "-popularity":
458
- sortOrder = "popularity desc";
459
- break;
460
- default:
461
- sortOrder = "published_on asc";
462
- break;
463
- }
479
+ // Construct the search filter
480
+ const searchFilter = searchTerm
481
+ ? `&& (artist->name match "${searchTerm}*" || title match "${searchTerm}*")`
482
+ : "";
483
+
484
+ // Construct the included fields filter, replacing 'difficulty' with 'difficulty_string'
485
+ const includedFieldsFilter = includedFields.length > 0
486
+ ? includedFields.map(field => {
487
+ let [key, value] = field.split(',');
488
+ if (key === 'difficulty') {
489
+ key = 'difficulty_string';
490
+ }
491
+ return `&& ${key} == "${value}"`;
492
+ }).join(' ')
493
+ : "";
494
+
495
+ // Determine the sort order
496
+ let sortOrder;
497
+ switch (sort) {
498
+ case "slug":
499
+ sortOrder = "artist->name asc";
500
+ break;
501
+ case "published_on":
502
+ sortOrder = "published_on asc";
503
+ break;
504
+ case "-published_on":
505
+ sortOrder = "published_on desc";
506
+ break;
507
+ case "-slug":
508
+ sortOrder = "artist->name desc";
509
+ break;
510
+ case "-popularity":
511
+ sortOrder = "popularity desc";
512
+ break;
513
+ default:
514
+ sortOrder = "published_on asc";
515
+ break;
516
+ }
464
517
 
465
518
  let defaultFields = [
466
519
  '"id": railcontent_id',