musora-content-services 2.3.7 → 2.3.9

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,15 @@
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
+ ### [2.3.9](https://github.com/railroadmedia/musora-content-services/compare/v2.3.8...v2.3.9) (2025-04-08)
6
+
7
+ ### [2.3.8](https://github.com/railroadmedia/musora-content-services/compare/v2.3.7...v2.3.8) (2025-04-08)
8
+
9
+
10
+ ### Bug Fixes
11
+
12
+ * **BEH-363:** Point homepage recommended endpoint to BE ([#208](https://github.com/railroadmedia/musora-content-services/issues/208)) ([16d3308](https://github.com/railroadmedia/musora-content-services/commit/16d3308a80c68d3fedfc75c42afa9cb2bb9ddfd5))
13
+
5
14
  ### [2.3.7](https://github.com/railroadmedia/musora-content-services/compare/v2.3.4...v2.3.7) (2025-04-07)
6
15
 
7
16
  ### [2.3.6](https://github.com/railroadmedia/musora-content-services/compare/v2.3.5...v2.3.6) (2025-04-04)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "musora-content-services",
3
- "version": "2.3.7",
3
+ "version": "2.3.9",
4
4
  "description": "A package for Musoras content services ",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
package/src/index.d.ts CHANGED
@@ -47,6 +47,14 @@ import {
47
47
  verifyLocalDataContext
48
48
  } from './services/dataContext.js';
49
49
 
50
+ import {
51
+ convertToTimeZone,
52
+ getMonday,
53
+ getWeekNumber,
54
+ isNextDay,
55
+ isSameDate
56
+ } from './services/dateUtils.js';
57
+
50
58
  import {
51
59
  getActiveDiscussions
52
60
  } from './services/forum.js';
@@ -236,6 +244,7 @@ declare module 'musora-content-services' {
236
244
  closeComment,
237
245
  contentStatusCompleted,
238
246
  contentStatusReset,
247
+ convertToTimeZone,
239
248
  countAssignmentsAndLessons,
240
249
  createComment,
241
250
  createPlaylist,
@@ -332,6 +341,7 @@ declare module 'musora-content-services' {
332
341
  getAllStartedOrCompleted,
333
342
  getContentRows,
334
343
  getLessonContentRows,
344
+ getMonday,
335
345
  getNewAndUpcoming,
336
346
  getPracticeSessions,
337
347
  getProgressPercentage,
@@ -348,10 +358,13 @@ declare module 'musora-content-services' {
348
358
  getUserMonthlyStats,
349
359
  getUserPractices,
350
360
  getUserWeeklyStats,
361
+ getWeekNumber,
351
362
  globalConfig,
352
363
  initializeService,
353
364
  isBucketUrl,
354
365
  isContentLiked,
366
+ isNextDay,
367
+ isSameDate,
355
368
  jumpToContinueContent,
356
369
  likeComment,
357
370
  likeContent,
package/src/index.js CHANGED
@@ -47,6 +47,14 @@ import {
47
47
  verifyLocalDataContext
48
48
  } from './services/dataContext.js';
49
49
 
50
+ import {
51
+ convertToTimeZone,
52
+ getMonday,
53
+ getWeekNumber,
54
+ isNextDay,
55
+ isSameDate
56
+ } from './services/dateUtils.js';
57
+
50
58
  import {
51
59
  getActiveDiscussions
52
60
  } from './services/forum.js';
@@ -235,6 +243,7 @@ export {
235
243
  closeComment,
236
244
  contentStatusCompleted,
237
245
  contentStatusReset,
246
+ convertToTimeZone,
238
247
  countAssignmentsAndLessons,
239
248
  createComment,
240
249
  createPlaylist,
@@ -331,6 +340,7 @@ export {
331
340
  getAllStartedOrCompleted,
332
341
  getContentRows,
333
342
  getLessonContentRows,
343
+ getMonday,
334
344
  getNewAndUpcoming,
335
345
  getPracticeSessions,
336
346
  getProgressPercentage,
@@ -347,10 +357,13 @@ export {
347
357
  getUserMonthlyStats,
348
358
  getUserPractices,
349
359
  getUserWeeklyStats,
360
+ getWeekNumber,
350
361
  globalConfig,
351
362
  initializeService,
352
363
  isBucketUrl,
353
364
  isContentLiked,
365
+ isNextDay,
366
+ isSameDate,
354
367
  jumpToContinueContent,
355
368
  likeComment,
356
369
  likeContent,
@@ -0,0 +1,55 @@
1
+ // dateUtils.js
2
+
3
+ export function convertToTimeZone(date, timeZone) {
4
+ const formatter = new Intl.DateTimeFormat('en-US', {
5
+ timeZone,
6
+ year: 'numeric',
7
+ month: '2-digit',
8
+ day: '2-digit',
9
+ hour: '2-digit',
10
+ minute: '2-digit',
11
+ second: '2-digit',
12
+ hour12: false,
13
+ });
14
+
15
+ const parts = formatter.formatToParts(date).reduce((acc, part) => {
16
+ if (part.type !== 'literal') acc[part.type] = part.value;
17
+ return acc;
18
+ }, {});
19
+
20
+ return new Date(`${parts.year}-${parts.month}-${parts.day}T${parts.hour}:${parts.minute}:${parts.second}`);
21
+ }
22
+ // Get start of the week (Monday)
23
+ export function getMonday(date) {
24
+ const d = new Date(date);
25
+ const day = d.getDay();
26
+ const diff = d.getDate() - day + (day === 0 ? -6 : 1);
27
+ return new Date(d.setDate(diff));
28
+ }
29
+
30
+ // Get the week number
31
+ export function getWeekNumber(d) {
32
+ let newDate = new Date(d.getTime());
33
+ newDate.setUTCDate(newDate.getUTCDate() + 4 - (newDate.getUTCDay()||7));
34
+ var yearStart = new Date(Date.UTC(newDate.getUTCFullYear(),0,1));
35
+ var weekNo = Math.ceil(( ( (newDate - yearStart) / 86400000) + 1)/7);
36
+ return weekNo;
37
+ }
38
+ //Check if two dates are the same
39
+ export function isSameDate(date1, date2, method = '') {
40
+ return date1.toISOString().split('T')[0] === date2.toISOString().split('T')[0];
41
+ }
42
+
43
+ // Check if two dates are consecutive days
44
+ export function isNextDay(prev, current) {
45
+ const prevDate = new Date(prev.getFullYear(), prev.getMonth(), prev.getDate());
46
+ const nextDate = new Date(prevDate);
47
+ nextDate.setDate(prevDate.getDate() + 1); // Add 1 day
48
+
49
+ return (
50
+ nextDate.getFullYear() === current.getFullYear() &&
51
+ nextDate.getMonth() === current.getMonth() &&
52
+ nextDate.getDate() === current.getDate()
53
+ );
54
+ }
55
+
@@ -3,6 +3,7 @@
3
3
  */
4
4
  import { globalConfig } from './config.js'
5
5
  import { fetchJSONHandler } from '../lib/httpHelper.js'
6
+ import { convertToTimeZone } from './dateUtils.js';
6
7
 
7
8
  /**
8
9
  * Exported functions that are excluded from index generation.
@@ -1175,44 +1176,42 @@ export async function editComment(commentId, comment) {
1175
1176
  }
1176
1177
 
1177
1178
  export async function fetchUserPractices(currentVersion) {
1178
- const url = `/api/user/practices/v1/practices`
1179
- const response = await fetchDataHandler(url, currentVersion)
1180
- const { data, version } = response
1181
- const userPractices = data
1179
+ const url = `/api/user/practices/v1/practices`;
1180
+ const response = await fetchDataHandler(url, currentVersion);
1181
+ const { data, version } = response;
1182
+ const userPractices = data;
1183
+
1184
+ const userTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
1182
1185
 
1183
- let formattedPractices = userPractices.reduce((acc, practice) => {
1184
- // Convert UTC date to user's local timezone
1185
- let utcDate = new Date(practice.day); // `practice.day` is in ISO format, e.g., "2025-04-01T10:42:17.000000Z"
1186
1186
 
1187
- // Extract the local date string (ignoring time) in user's timezone
1188
- let localDate = new Date(utcDate.toLocaleString('en-US', {
1189
- timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone
1190
- }));
1187
+ const formattedPractices = userPractices.reduce((acc, practice) => {
1188
+ // Convert UTC date to user's local date (still a Date object)
1189
+ const utcDate = new Date(practice.day);
1190
+ const localDate = convertToTimeZone(utcDate, userTimeZone);
1191
1191
 
1192
- // Format the date as Y-m-d (2025-03-31)
1193
- let userTimeZoneDay = localDate.getFullYear() + '-' +
1194
- (localDate.getMonth() + 1).toString().padStart(2, '0') + '-' +
1195
- localDate.getDate().toString().padStart(2, '0');
1192
+ const userTimeZoneDay =
1193
+ localDate.getFullYear() + '-' +
1194
+ String(localDate.getMonth() + 1).padStart(2, '0') + '-' +
1195
+ String(localDate.getDate()).padStart(2, '0');
1196
1196
 
1197
- // Initialize the array if the day does not exist
1198
1197
  if (!acc[userTimeZoneDay]) {
1199
- acc[userTimeZoneDay] = []
1198
+ acc[userTimeZoneDay] = [];
1200
1199
  }
1201
1200
 
1202
- // Push the practice entry into the array
1203
- acc[userTimeZoneDay].push({ id:practice.id, duration_seconds: practice.duration_seconds })
1201
+ acc[userTimeZoneDay].push({
1202
+ id: practice.id,
1203
+ duration_seconds: practice.duration_seconds,
1204
+ });
1204
1205
 
1205
- return acc
1206
- }, {})
1206
+ return acc;
1207
+ }, {});
1207
1208
 
1208
- let json = {
1209
+ return {
1209
1210
  data: {
1210
1211
  practices: formattedPractices,
1211
1212
  },
1212
- version: version,
1213
- }
1214
-
1215
- return json
1213
+ version,
1214
+ };
1216
1215
  }
1217
1216
 
1218
1217
  export async function logUserPractice(practiceDetails) {
@@ -113,16 +113,17 @@ export async function rankItems(brand, content_ids) {
113
113
  }
114
114
  }
115
115
 
116
- export async function recommendations(brand, { page = 1, limit = 10 } = {}) {
117
- let data = {
118
- brand: brand,
119
- user_id: globalConfig.sessionConfig.userId,
120
- num_recommendations: limit,
121
- }
122
- const url = `/recommendations/`
116
+ export async function recommendations(brand, { section = ''} = {}) {
117
+ section = section.toUpperCase().replace('-', '_')
118
+ const sectionString = section ? `&section=${section}` : '';
119
+ const url = `/api/content/v1/recommendations?brand=${brand}${sectionString}`
123
120
  try {
124
- const response = await fetchHandler(url, 'POST', data)
125
- return response['recommendations']
121
+ return fetchJSONHandler(
122
+ url,
123
+ globalConfig.railcontentConfig.token,
124
+ globalConfig.railcontentConfig.baseUrl,
125
+ 'get'
126
+ )
126
127
  } catch (error) {
127
128
  console.error('Fetch error:', error)
128
129
  return null
@@ -6,6 +6,7 @@ import {fetchUserPractices, logUserPractice, fetchUserPracticeMeta, fetchHandler
6
6
  import { DataContext, UserActivityVersionKey } from './dataContext.js'
7
7
  import {fetchByRailContentIds} from "./sanity";
8
8
  import {lessonTypesMapping} from "../contentTypeConfig";
9
+ import { convertToTimeZone, getMonday, getWeekNumber, isSameDate, isNextDay } from './dateUtils.js';
9
10
 
10
11
  const recentActivity = [
11
12
  { id: 5,title: '3 Easy Classical Songs For Beginners', action: 'Comment', thumbnail: 'https://cdn.sanity.io/images/4032r8py/production/8a7fb4d7473306c5fa51ba2e8867e03d44342b18-1920x1080.jpg', summary: 'Just completed the advanced groove lesson! I’m finally feeling more confident with my fills. Thanks for the clear explanations and practice tips! ', date: '2025-03-25 10:09:48' },
@@ -344,15 +345,18 @@ export async function deletePracticeSession(day) {
344
345
  if (!userPracticesIds.length) return [];
345
346
 
346
347
  const url = `/api/user/practices/v1/practices${buildQueryString(userPracticesIds)}`;
347
- await userActivityContext.update(async function (localContext) {
348
- if (localContext.data?.[DATA_KEY_PRACTICES]?.[day]) {
349
- localContext.data[DATA_KEY_PRACTICES][day] = localContext.data[DATA_KEY_PRACTICES][day].filter(
350
- practice => !userPracticesIds.includes(practice.id)
351
- );
348
+ await userActivityContext.update(
349
+ async function (localContext) {
350
+ if (localContext.data?.[DATA_KEY_PRACTICES]?.[day]) {
351
+ localContext.data[DATA_KEY_PRACTICES][day] = localContext.data[DATA_KEY_PRACTICES][day].filter(
352
+ practice => !userPracticesIds.includes(practice.id)
353
+ );
354
+ }
355
+ },
356
+ async function () {
357
+ return await fetchHandler(url, 'DELETE', null);
352
358
  }
353
- });
354
-
355
- return await fetchHandler(url, 'DELETE', null);
359
+ );
356
360
  }
357
361
 
358
362
  export async function restorePracticeSession(date) {
@@ -408,7 +412,10 @@ export async function getPracticeSessions(day) {
408
412
  return null;
409
413
  };
410
414
 
415
+ const userTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
416
+
411
417
  const formattedMeta = meta.data.map(practice => {
418
+ const utcDate = new Date(practice.created_at);
412
419
  const content = contents.find(c => c.id === practice.content_id) || {};
413
420
  return {
414
421
  id: practice.id,
@@ -422,6 +429,7 @@ export async function getPracticeSessions(day) {
422
429
  content_type: getFormattedType(content.type || ''),
423
430
  content_id: practice.content_id || null,
424
431
  content_brand: content.brand || null,
432
+ created_at: convertToTimeZone(utcDate, userTimeZone)
425
433
  };
426
434
  });
427
435
  return { data: { practices: formattedMeta, practiceDuration } };
@@ -461,37 +469,6 @@ function buildQueryString(ids, paramName = 'practice_ids') {
461
469
  return '?' + ids.map(id => `${paramName}[]=${id}`).join('&');
462
470
  }
463
471
 
464
-
465
- // Helper: Get start of the week (Monday)
466
- function getMonday(d) {
467
- d = new Date(d)
468
- var day = d.getDay(),
469
- diff = d.getDate() - day + (day == 0 ? -6 : 1) // adjust when day is sunday
470
- return new Date(d.setDate(diff))
471
- }
472
-
473
- // Helper: Get the week number
474
- function getWeekNumber(d) {
475
- let newDate = new Date(d.getTime());
476
- newDate.setUTCDate(newDate.getUTCDate() + 4 - (newDate.getUTCDay()||7));
477
- var yearStart = new Date(Date.UTC(newDate.getUTCFullYear(),0,1));
478
- var weekNo = Math.ceil(( ( (newDate - yearStart) / 86400000) + 1)/7);
479
- return weekNo;
480
- }
481
-
482
- // Helper: function to check if two dates are consecutive days
483
- function isNextDay(prev, current) {
484
- const prevDate = new Date(prev.getFullYear(), prev.getMonth(), prev.getDate());
485
- const nextDate = new Date(prevDate);
486
- nextDate.setDate(prevDate.getDate() + 1); // Add 1 day
487
-
488
- return (
489
- nextDate.getFullYear() === current.getFullYear() &&
490
- nextDate.getMonth() === current.getMonth() &&
491
- nextDate.getDate() === current.getDate()
492
- );
493
- }
494
-
495
472
  // Helper: Calculate streaks
496
473
  function calculateStreaks(practices, includeStreakMessage = false) {
497
474
  let currentDailyStreak = 0;
@@ -584,9 +561,7 @@ function calculateStreaks(practices, includeStreakMessage = false) {
584
561
  return { currentDailyStreak, currentWeeklyStreak, streakMessage };
585
562
  }
586
563
 
587
- function isSameDate(date1, date2, method = '') {
588
- return date1.toISOString().split('T')[0] === date2.toISOString().split('T')[0];
589
- }
564
+
590
565
 
591
566
 
592
567
 
File without changes
File without changes
File without changes