musora-content-services 2.3.21 → 2.3.22
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 +2 -0
- package/package.json +1 -1
- package/src/index.d.ts +7 -0
- package/src/index.js +6 -0
- package/src/services/railcontent.js +5 -1
- package/src/services/userActivity.js +81 -0
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
|
+
### [2.3.22](https://github.com/railroadmedia/musora-content-services/compare/v2.3.21...v2.3.22) (2025-05-05)
|
|
6
|
+
|
|
5
7
|
### [2.3.21](https://github.com/railroadmedia/musora-content-services/compare/v2.3.20...v2.3.21) (2025-05-02)
|
|
6
8
|
|
|
7
9
|
### [2.3.20](https://github.com/railroadmedia/musora-content-services/compare/v2.3.19...v2.3.20) (2025-04-30)
|
package/package.json
CHANGED
package/src/index.d.ts
CHANGED
|
@@ -53,6 +53,10 @@ import {
|
|
|
53
53
|
recordWatchSession
|
|
54
54
|
} from './services/contentProgress.js';
|
|
55
55
|
|
|
56
|
+
import {
|
|
57
|
+
addContextToContent
|
|
58
|
+
} from './contentAggregator.js';
|
|
59
|
+
|
|
56
60
|
import {
|
|
57
61
|
verifyLocalDataContext
|
|
58
62
|
} from './services/dataContext.js';
|
|
@@ -215,6 +219,7 @@ import {
|
|
|
215
219
|
} from './services/user/sessions.js';
|
|
216
220
|
|
|
217
221
|
import {
|
|
222
|
+
calculateLongestStreaks,
|
|
218
223
|
createPracticeNotes,
|
|
219
224
|
deletePracticeSession,
|
|
220
225
|
getPracticeNotes,
|
|
@@ -233,6 +238,7 @@ import {
|
|
|
233
238
|
declare module 'musora-content-services' {
|
|
234
239
|
export {
|
|
235
240
|
addItemToPlaylist,
|
|
241
|
+
addContextToContent,
|
|
236
242
|
applyCloudflareWrapper,
|
|
237
243
|
applySanityTransformations,
|
|
238
244
|
assignModeratorToComment,
|
|
@@ -240,6 +246,7 @@ declare module 'musora-content-services' {
|
|
|
240
246
|
assignmentStatusReset,
|
|
241
247
|
blockUser,
|
|
242
248
|
buildImageSRC,
|
|
249
|
+
calculateLongestStreaks,
|
|
243
250
|
closeComment,
|
|
244
251
|
contentStatusCompleted,
|
|
245
252
|
contentStatusReset,
|
package/src/index.js
CHANGED
|
@@ -84,6 +84,9 @@ import {
|
|
|
84
84
|
isBucketUrl,
|
|
85
85
|
verifyImageSRC
|
|
86
86
|
} from './services/imageSRCVerify.js';
|
|
87
|
+
import {
|
|
88
|
+
addContextToContent
|
|
89
|
+
} from './contentAggregator.js';
|
|
87
90
|
|
|
88
91
|
import {
|
|
89
92
|
assignModeratorToComment,
|
|
@@ -215,6 +218,7 @@ import {
|
|
|
215
218
|
} from './services/user/sessions.js';
|
|
216
219
|
|
|
217
220
|
import {
|
|
221
|
+
calculateLongestStreaks,
|
|
218
222
|
createPracticeNotes,
|
|
219
223
|
deletePracticeSession,
|
|
220
224
|
getPracticeNotes,
|
|
@@ -239,6 +243,7 @@ export {
|
|
|
239
243
|
assignmentStatusReset,
|
|
240
244
|
blockUser,
|
|
241
245
|
buildImageSRC,
|
|
246
|
+
calculateLongestStreaks,
|
|
242
247
|
closeComment,
|
|
243
248
|
contentStatusCompleted,
|
|
244
249
|
contentStatusReset,
|
|
@@ -407,4 +412,5 @@ export {
|
|
|
407
412
|
updateUserPractice,
|
|
408
413
|
verifyImageSRC,
|
|
409
414
|
verifyLocalDataContext,
|
|
415
|
+
addContextToContent
|
|
410
416
|
};
|
|
@@ -290,6 +290,10 @@ async function patchDataHandler(url, data) {
|
|
|
290
290
|
return fetchHandler(url, 'patch', null, data)
|
|
291
291
|
}
|
|
292
292
|
|
|
293
|
+
async function putDataHandler(url, data) {
|
|
294
|
+
return fetchHandler(url, 'put', null, data)
|
|
295
|
+
}
|
|
296
|
+
|
|
293
297
|
async function deleteDataHandler(url, data) {
|
|
294
298
|
return fetchHandler(url, 'delete')
|
|
295
299
|
}
|
|
@@ -726,7 +730,7 @@ export async function editComment(commentId, comment) {
|
|
|
726
730
|
const data = {
|
|
727
731
|
comment: comment,
|
|
728
732
|
}
|
|
729
|
-
return await
|
|
733
|
+
return await putDataHandler(url, data)
|
|
730
734
|
}
|
|
731
735
|
|
|
732
736
|
/**
|
|
@@ -688,6 +688,87 @@ function calculateStreaks(practices, includeStreakMessage = false) {
|
|
|
688
688
|
return { currentDailyStreak, currentWeeklyStreak, streakMessage };
|
|
689
689
|
}
|
|
690
690
|
|
|
691
|
+
/**
|
|
692
|
+
* Calculates the longest daily, weekly streaks and totalPracticeSeconds from user practice dates.
|
|
693
|
+
* @returns {{ longestDailyStreak: number, longestWeeklyStreak: number, totalPracticeSeconds:number }}
|
|
694
|
+
*/
|
|
695
|
+
export async function calculateLongestStreaks() {
|
|
696
|
+
let data = await userActivityContext.getData()
|
|
697
|
+
let practices = data?.[DATA_KEY_PRACTICES] ?? {}
|
|
698
|
+
let totalPracticeSeconds = 0;
|
|
699
|
+
// Calculate total practice duration
|
|
700
|
+
for (const date in practices) {
|
|
701
|
+
for (const entry of practices[date]) {
|
|
702
|
+
totalPracticeSeconds += entry.duration_seconds;
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
let practiceDates = Object.keys(practices)
|
|
707
|
+
.map(dateStr => {
|
|
708
|
+
const [y, m, d] = dateStr.split('-').map(Number);
|
|
709
|
+
const newDate = new Date();
|
|
710
|
+
newDate.setFullYear(y, m - 1, d);
|
|
711
|
+
return newDate;
|
|
712
|
+
})
|
|
713
|
+
.sort((a, b) => a - b);
|
|
714
|
+
|
|
715
|
+
if (!practiceDates || practiceDates.length === 0) {
|
|
716
|
+
return {longestDailyStreak: 0, longestWeeklyStreak: 0, totalPracticeSeconds: 0};
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
// Normalize to Date objects
|
|
720
|
+
const normalizedDates = [
|
|
721
|
+
...new Set(practiceDates.map(d => {
|
|
722
|
+
const date = new Date(d);
|
|
723
|
+
date.setHours(0, 0, 0, 0);
|
|
724
|
+
return date.getTime();
|
|
725
|
+
}))
|
|
726
|
+
].sort((a, b) => a - b);
|
|
727
|
+
|
|
728
|
+
// ----- Daily Streak -----
|
|
729
|
+
let longestDailyStreak = 1;
|
|
730
|
+
let currentDailyStreak = 1;
|
|
731
|
+
for (let i = 1; i < normalizedDates.length; i++) {
|
|
732
|
+
const diffInDays = (normalizedDates[i] - normalizedDates[i - 1]) / (1000 * 60 * 60 * 24);
|
|
733
|
+
if (diffInDays === 1) {
|
|
734
|
+
currentDailyStreak++;
|
|
735
|
+
longestDailyStreak = Math.max(longestDailyStreak, currentDailyStreak);
|
|
736
|
+
} else {
|
|
737
|
+
currentDailyStreak = 1;
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
// ----- Weekly Streak -----
|
|
742
|
+
const weekStartDates = [
|
|
743
|
+
...new Set(normalizedDates.map(ts => {
|
|
744
|
+
const d = new Date(ts);
|
|
745
|
+
const day = d.getDay();
|
|
746
|
+
const diff = d.getDate() - day + (day === 0 ? -6 : 1); // adjust to Monday
|
|
747
|
+
d.setDate(diff);
|
|
748
|
+
return d.getTime(); // timestamp for Monday
|
|
749
|
+
}))
|
|
750
|
+
].sort((a, b) => a - b);
|
|
751
|
+
|
|
752
|
+
let longestWeeklyStreak = 1;
|
|
753
|
+
let currentWeeklyStreak = 1;
|
|
754
|
+
|
|
755
|
+
for (let i = 1; i < weekStartDates.length; i++) {
|
|
756
|
+
const diffInWeeks = (weekStartDates[i] - weekStartDates[i - 1]) / (1000 * 60 * 60 * 24 * 7);
|
|
757
|
+
if (diffInWeeks === 1) {
|
|
758
|
+
currentWeeklyStreak++;
|
|
759
|
+
longestWeeklyStreak = Math.max(longestWeeklyStreak, currentWeeklyStreak);
|
|
760
|
+
} else {
|
|
761
|
+
currentWeeklyStreak = 1;
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
return {
|
|
766
|
+
longestDailyStreak,
|
|
767
|
+
longestWeeklyStreak,
|
|
768
|
+
totalPracticeSeconds
|
|
769
|
+
};
|
|
770
|
+
}
|
|
771
|
+
|
|
691
772
|
|
|
692
773
|
|
|
693
774
|
|