musora-content-services 2.31.2 → 2.33.0

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 (61) hide show
  1. package/.coderabbit.yaml +5 -0
  2. package/CHANGELOG.md +27 -0
  3. package/docs/ContentOrganization.html +2 -2
  4. package/docs/Gamification.html +2 -2
  5. package/docs/UserManagementSystem.html +2 -2
  6. package/docs/api_types.js.html +2 -2
  7. package/docs/config.js.html +2 -8
  8. package/docs/content-org_content-org.js.html +2 -2
  9. package/docs/content-org_guided-courses.ts.html +118 -0
  10. package/docs/content-org_playlists-types.js.html +12 -2
  11. package/docs/content-org_playlists.js.html +16 -16
  12. package/docs/content.js.html +71 -39
  13. package/docs/gamification_awards.js.html +54 -35
  14. package/docs/gamification_awards.ts.html +160 -0
  15. package/docs/gamification_gamification.js.html +2 -2
  16. package/docs/gamification_types.js.html +7 -25
  17. package/docs/global.html +250 -494
  18. package/docs/index.html +2 -2
  19. package/docs/module-Accounts.html +108 -0
  20. package/docs/module-Awards.html +196 -11
  21. package/docs/module-Config.html +4 -8
  22. package/docs/module-Content-Services-V2.html +455 -8
  23. package/docs/module-GuidedCourses.html +108 -0
  24. package/docs/module-Interests.html +2 -2
  25. package/docs/module-Permissions.html +2 -2
  26. package/docs/module-Playlists.html +18 -17
  27. package/docs/module-Railcontent-Services.html +479 -35
  28. package/docs/module-Sanity-Services.html +45 -173
  29. package/docs/module-Sessions.html +2 -2
  30. package/docs/module-UserActivity.html +189 -21
  31. package/docs/module-UserChat.html +2 -2
  32. package/docs/module-UserManagement.html +410 -8
  33. package/docs/module-UserNotifications.html +203 -8
  34. package/docs/module-UserProfile.html +2 -2
  35. package/docs/railcontent.js.html +65 -37
  36. package/docs/sanity.js.html +120 -185
  37. package/docs/userActivity.js.html +448 -466
  38. package/docs/user_account.ts.html +138 -0
  39. package/docs/user_chat.js.html +2 -2
  40. package/docs/user_interests.js.html +2 -2
  41. package/docs/user_management.js.html +33 -2
  42. package/docs/user_notifications.js.html +27 -5
  43. package/docs/user_permissions.js.html +2 -2
  44. package/docs/user_profile.js.html +3 -9
  45. package/docs/user_sessions.js.html +2 -2
  46. package/docs/user_types.js.html +10 -2
  47. package/docs/user_user-management-system.js.html +2 -2
  48. package/jsdoc.json +11 -1
  49. package/package.json +5 -1
  50. package/src/contentTypeConfig.js +6 -1
  51. package/src/index.d.ts +14 -2
  52. package/src/index.js +14 -2
  53. package/src/services/api/types.ts +22 -0
  54. package/src/services/gamification/awards.ts +86 -0
  55. package/src/services/sanity.js +14 -19
  56. package/src/services/user/account.ts +24 -0
  57. package/src/services/user/management.js +31 -0
  58. package/src/services/user/types.js +8 -0
  59. package/src/services/userActivity.js +5 -5
  60. package/src/services/gamification/awards.js +0 -93
  61. package/src/services/gamification/types.js +0 -8
package/jsdoc.json CHANGED
@@ -12,9 +12,19 @@
12
12
  "src/services/railcontent.js",
13
13
  "src/index.js"
14
14
  ],
15
- "includePattern": ".js$",
15
+ "includePattern": "(.js|.ts$)",
16
16
  "excludePattern": "(node_modules/|docs)"
17
17
  },
18
+ "plugins": [
19
+ "node_modules/jsdoc-babel"
20
+ ],
21
+ "babel": {
22
+ "extensions": ["ts"],
23
+ "ignore": ["**/*.(test|spec).ts"],
24
+ "babelrc": false,
25
+ "presets": [["@babel/preset-env", { "targets": { "node": true } }], "@babel/preset-typescript"],
26
+ "plugins": ["@babel/plugin-transform-class-properties", "@babel/plugin-transform-object-rest-spread"]
27
+ },
18
28
  "opts": {
19
29
  "destination": "./docs",
20
30
  "recurse": true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "musora-content-services",
3
- "version": "2.31.2",
3
+ "version": "2.33.0",
4
4
  "description": "A package for Musoras content services ",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -21,9 +21,13 @@
21
21
  },
22
22
  "homepage": "https://github.com/railroadmedia/musora-content-services#readme",
23
23
  "devDependencies": {
24
+ "@babel/plugin-transform-class-properties": "^7.27.1",
25
+ "@babel/plugin-transform-object-rest-spread": "^7.28.0",
26
+ "@babel/preset-typescript": "^7.27.1",
24
27
  "dotenv": "^16.4.5",
25
28
  "jest": "^29.7.0",
26
29
  "jsdoc": "^4.0.3",
30
+ "jsdoc-babel": "^0.5.0",
27
31
  "prettier": "3.4.2",
28
32
  "standard-version": "^9.5.0",
29
33
  "ts-jest": "^29.2.4"
@@ -9,12 +9,17 @@ export const SONG_TYPES = ['song', 'play-along', 'jam-track', 'song-tutorial-chi
9
9
  // Single hierarchy refers to only one element in the hierarchy has video lessons, not that they have a single parent
10
10
  export const SINGLE_PARENT_TYPES = ['course-part', 'pack-bundle-lesson', 'song-tutorial-children']
11
11
 
12
+ export const artistField = `select(
13
+ defined(artist) => artist->{ 'name': name, 'thumbnail': thumbnail_url.asset->url},
14
+ defined(parent_content_data) => *[_type == ^.parent_content_data[0].type && railcontent_id == ^.parent_content_data[0].id][0].artist->{ 'name': name, 'thumbnail': thumbnail_url.asset->url}
15
+ )`
16
+
12
17
  export const DEFAULT_FIELDS = [
13
18
  "'sanity_id' : _id",
14
19
  "'id': railcontent_id",
15
20
  'railcontent_id',
16
21
  artistOrInstructorName(),
17
- "'artist': artist->{ 'name': name, 'thumbnail': thumbnail_url.asset->url}",
22
+ `'artist': ${artistField}`,
18
23
  'title',
19
24
  "'image': thumbnail.asset->url",
20
25
  "'thumbnail': thumbnail.asset->url",
package/src/index.d.ts CHANGED
@@ -95,8 +95,9 @@ import {
95
95
  } from './services/forum.js';
96
96
 
97
97
  import {
98
- fetchAwardsForUser
99
- } from './services/gamification/awards.js';
98
+ fetchAwardsForUser,
99
+ fetchCertificate
100
+ } from './services/gamification/awards.ts';
100
101
 
101
102
  import {
102
103
  applyCloudflareWrapper,
@@ -219,6 +220,8 @@ import {
219
220
  } from './services/sanity.js';
220
221
 
221
222
  import {
223
+ confirmEmailChange,
224
+ requestEmailChange,
222
225
  resetPassword,
223
226
  sendAccountSetupEmail,
224
227
  sendPasswordResetEmail,
@@ -241,9 +244,12 @@ import {
241
244
 
242
245
  import {
243
246
  blockUser,
247
+ blockedUsers,
244
248
  deletePicture,
245
249
  getUserData,
250
+ isDisplayNameAvailable,
246
251
  unblockUser,
252
+ updateDisplayName,
247
253
  uploadPicture,
248
254
  uploadPictureFromS3
249
255
  } from './services/user/management.js';
@@ -312,9 +318,11 @@ declare module 'musora-content-services' {
312
318
  applySanityTransformations,
313
319
  assignModeratorToComment,
314
320
  blockUser,
321
+ blockedUsers,
315
322
  buildImageSRC,
316
323
  calculateLongestStreaks,
317
324
  closeComment,
325
+ confirmEmailChange,
318
326
  contentStatusCompleted,
319
327
  contentStatusReset,
320
328
  convertToTimeZone,
@@ -344,6 +352,7 @@ declare module 'musora-content-services' {
344
352
  fetchByRailContentIds,
345
353
  fetchByReference,
346
354
  fetchCarouselCardData,
355
+ fetchCertificate,
347
356
  fetchChatAndLiveEnvent,
348
357
  fetchChatSettings,
349
358
  fetchCoachLessons,
@@ -463,6 +472,7 @@ declare module 'musora-content-services' {
463
472
  isBucketUrl,
464
473
  isContentLiked,
465
474
  isContentLikedByIds,
475
+ isDisplayNameAvailable,
466
476
  isNextDay,
467
477
  isSameDate,
468
478
  jumpToContinueContent,
@@ -502,6 +512,7 @@ declare module 'musora-content-services' {
502
512
  replyToComment,
503
513
  reportComment,
504
514
  reportPlaylist,
515
+ requestEmailChange,
505
516
  reset,
506
517
  resetPassword,
507
518
  restoreComment,
@@ -527,6 +538,7 @@ declare module 'musora-content-services' {
527
538
  unlikeContent,
528
539
  unlikePlaylist,
529
540
  unpinProgressRow,
541
+ updateDisplayName,
530
542
  updateNotificationSetting,
531
543
  updatePlaylist,
532
544
  updatePracticeNotes,
package/src/index.js CHANGED
@@ -95,8 +95,9 @@ import {
95
95
  } from './services/forum.js';
96
96
 
97
97
  import {
98
- fetchAwardsForUser
99
- } from './services/gamification/awards.js';
98
+ fetchAwardsForUser,
99
+ fetchCertificate
100
+ } from './services/gamification/awards.ts';
100
101
 
101
102
  import {
102
103
  applyCloudflareWrapper,
@@ -219,6 +220,8 @@ import {
219
220
  } from './services/sanity.js';
220
221
 
221
222
  import {
223
+ confirmEmailChange,
224
+ requestEmailChange,
222
225
  resetPassword,
223
226
  sendAccountSetupEmail,
224
227
  sendPasswordResetEmail,
@@ -241,9 +244,12 @@ import {
241
244
 
242
245
  import {
243
246
  blockUser,
247
+ blockedUsers,
244
248
  deletePicture,
245
249
  getUserData,
250
+ isDisplayNameAvailable,
246
251
  unblockUser,
252
+ updateDisplayName,
247
253
  uploadPicture,
248
254
  uploadPictureFromS3
249
255
  } from './services/user/management.js';
@@ -311,9 +317,11 @@ export {
311
317
  applySanityTransformations,
312
318
  assignModeratorToComment,
313
319
  blockUser,
320
+ blockedUsers,
314
321
  buildImageSRC,
315
322
  calculateLongestStreaks,
316
323
  closeComment,
324
+ confirmEmailChange,
317
325
  contentStatusCompleted,
318
326
  contentStatusReset,
319
327
  convertToTimeZone,
@@ -343,6 +351,7 @@ export {
343
351
  fetchByRailContentIds,
344
352
  fetchByReference,
345
353
  fetchCarouselCardData,
354
+ fetchCertificate,
346
355
  fetchChatAndLiveEnvent,
347
356
  fetchChatSettings,
348
357
  fetchCoachLessons,
@@ -462,6 +471,7 @@ export {
462
471
  isBucketUrl,
463
472
  isContentLiked,
464
473
  isContentLikedByIds,
474
+ isDisplayNameAvailable,
465
475
  isNextDay,
466
476
  isSameDate,
467
477
  jumpToContinueContent,
@@ -501,6 +511,7 @@ export {
501
511
  replyToComment,
502
512
  reportComment,
503
513
  reportPlaylist,
514
+ requestEmailChange,
504
515
  reset,
505
516
  resetPassword,
506
517
  restoreComment,
@@ -526,6 +537,7 @@ export {
526
537
  unlikeContent,
527
538
  unlikePlaylist,
528
539
  unpinProgressRow,
540
+ updateDisplayName,
529
541
  updateNotificationSetting,
530
542
  updatePlaylist,
531
543
  updatePracticeNotes,
@@ -0,0 +1,22 @@
1
+ export interface PaginatedMeta {
2
+ current_page: number
3
+ from: number
4
+ to: number
5
+ per_page: number
6
+ last_page: number
7
+ total: number
8
+ path: string
9
+ }
10
+
11
+ export interface PaginatedLinks {
12
+ first: string
13
+ last: string
14
+ next: string
15
+ prev: string
16
+ }
17
+
18
+ export interface PaginatedResponse<T> {
19
+ meta: PaginatedMeta
20
+ links: PaginatedLinks
21
+ data: Array<T>
22
+ }
@@ -0,0 +1,86 @@
1
+ /**
2
+ * @module Awards
3
+ */
4
+
5
+ import { HttpClient } from '../../infrastructure/http/HttpClient'
6
+ import { PaginatedResponse } from '../api/types'
7
+ import { globalConfig } from '../config'
8
+
9
+ const baseUrl = `/api/gamification`
10
+
11
+ export interface Award {
12
+ id: number
13
+ user_id: number
14
+ completed_at: string // ISO-8601 timestamp
15
+ completion_data: Object
16
+ award_id: number
17
+ type: string
18
+ title: string
19
+ badge: string
20
+ }
21
+
22
+ export interface Certificate {
23
+ id: number
24
+ user_name: string
25
+ user_id: number
26
+ completed_at: string // ISO-8601 timestamp
27
+ message: string
28
+ award_id: number
29
+ type: string
30
+ title: string
31
+ musora_logo: string
32
+ musora_logo_64: string
33
+ brand_logo: string
34
+ brand_logo_64: string
35
+ ribbon_image: string
36
+ ribbon_image_64: string
37
+ award_image: string
38
+ award_image_64: string
39
+
40
+ instructor_signature?: string
41
+ instructor_signature_64?: string
42
+ }
43
+ /**
44
+ * Get awards for a specific user.
45
+ *
46
+ * NOTE: needs error handling for the response from http client
47
+ * (Alexandre: I'm doing it in a different branch/PR: https://github.com/railroadmedia/musora-content-services/pull/349)
48
+ * NOTE: This function still expects brand because FE passes the argument. It is ignored for now
49
+ *
50
+ * @param {number} userId - The user ID. If not provided, the authenticated user is used instead.
51
+ * @param {string} _brand - The brand to fetch the awards for.
52
+ * @param {number|null} [page=1] - Page attribute for pagination
53
+ * @param {number|null} [limit=5] - Limit how many items to return
54
+ * @returns {Promise<PaginatedResponse<Award>>} - The awards for the user.
55
+ */
56
+ export async function fetchAwardsForUser(
57
+ userId: number,
58
+ _brand: string,
59
+ page: number = 1,
60
+ limit: number = 5
61
+ ): Promise<PaginatedResponse<Award>> {
62
+ const httpClient = new HttpClient(globalConfig.baseUrl, globalConfig.sessionConfig.token)
63
+ const response = await httpClient.get<PaginatedResponse<Award>>(
64
+ `${baseUrl}/v1/users/${userId}/awards?limit=${limit}&page=${page}`
65
+ )
66
+
67
+ return response
68
+ }
69
+
70
+ /**
71
+ * Get certificate data for a completed user award
72
+ *
73
+ * NOTE: needs error handling for the response from http client
74
+ * (Alexandre: I'm doing it in a different branch/PR: https://github.com/railroadmedia/musora-content-services/pull/349)
75
+ * NOTE: This function still expects brand because FE passes the argument. It is ignored for now
76
+ *
77
+ * @param {number} userAwardId - The user award progress id
78
+ * @returns {Promise<Certificate>} - The certificate data for the completed user award.
79
+ */
80
+ export async function fetchCertificate(userAwardId: number): Promise<Certificate> {
81
+ const httpClient = new HttpClient(globalConfig.baseUrl, globalConfig.sessionConfig.token)
82
+ const response = await httpClient.get<Certificate>(
83
+ `${baseUrl}/v1/users/certificate/${userAwardId}`
84
+ )
85
+ return response
86
+ }
@@ -1298,33 +1298,28 @@ export async function fetchSiblingContent(railContentId, brand= null)
1298
1298
  /**
1299
1299
  * Fetch lessons related to a specific lesson by RailContent ID and type.
1300
1300
  * @param {string} railContentId - The RailContent ID of the current lesson.
1301
- * @param {string} brand - The current brand.
1302
1301
  * @returns {Promise<Array<Object>|null>} - The fetched related lessons data or null if not found.
1303
1302
  */
1304
- export async function fetchRelatedLessons(railContentId, brand) {
1305
- const filterSameTypeAndSortOrder = await new FilterBuilder(
1306
- `_type==^._type && _type in ${JSON.stringify(typeWithSortOrder)} && brand == "${brand}" && railcontent_id !=${railContentId}`
1307
- ).buildFilter()
1308
- const filterSameType = await new FilterBuilder(
1309
- `_type==^._type && !(_type in ${JSON.stringify(typeWithSortOrder)}) && !(defined(parent_type)) && brand == "${brand}" && railcontent_id !=${railContentId}`
1310
- ).buildFilter()
1311
- const filterSongSameArtist = await new FilterBuilder(
1312
- `_type=="song" && _type==^._type && brand == "${brand}" && references(^.artist->_id) && railcontent_id !=${railContentId}`
1303
+ export async function fetchRelatedLessons(railContentId)
1304
+ {
1305
+ const defaultFilterFields = `_type==^._type && brand == ^.brand && railcontent_id != ${railContentId}`
1306
+
1307
+ const filterSameArtist = await new FilterBuilder(
1308
+ `${defaultFilterFields} && references(^.artist->_id)`
1313
1309
  ).buildFilter()
1314
- const filterSongSameGenre = await new FilterBuilder(
1315
- `_type=="song" && _type==^._type && brand == "${brand}" && references(^.genre[]->_id) && railcontent_id !=${railContentId}`
1310
+ const filterSameGenre = await new FilterBuilder(
1311
+ `${defaultFilterFields} && references(^.genre[]->_id)`
1316
1312
  ).buildFilter()
1313
+
1317
1314
  const queryFields = `_id, "id":railcontent_id, published_on, "instructor": instructor[0]->name, title, "thumbnail":thumbnail.asset->url, length_in_seconds, status, "type": _type, difficulty, difficulty_string, railcontent_id, artist->,"permission_id": permission[]->railcontent_id,_type, "genre": genre[]->name`
1318
- const queryFieldsWithSort = queryFields + ', sort'
1319
- const query = `*[railcontent_id == ${railContentId} && brand == "${brand}" && (!defined(permission) || references(*[_type=='permission']._id))]{
1315
+
1316
+ const query = `*[railcontent_id == ${railContentId} && (!defined(permission) || references(*[_type=='permission']._id))]{
1320
1317
  _type, parent_type, railcontent_id,
1321
1318
  "related_lessons" : array::unique([
1322
- ...(*[${filterSongSameArtist}]{${queryFields}}|order(published_on desc, title asc)[0...10]),
1323
- ...(*[${filterSongSameGenre}]{${queryFields}}|order(published_on desc, title asc)[0...10]),
1324
- ...(*[${filterSameTypeAndSortOrder}]{${queryFieldsWithSort}}|order(sort asc, title asc)[0...10]),
1325
- ...(*[${filterSameType}]{${queryFields}}|order(published_on desc, title asc)[0...10])
1326
- ,
1319
+ ...(*[${filterSameArtist}]{${queryFields}}|order(published_on desc, title asc)[0...10]),
1320
+ ...(*[${filterSameGenre}]{${queryFields}}|order(published_on desc, title asc)[0...10]),
1327
1321
  ])[0...10]}`
1322
+
1328
1323
  return await fetchSanity(query, false)
1329
1324
  }
1330
1325
 
@@ -64,3 +64,27 @@ export async function resetPassword({
64
64
  token,
65
65
  })
66
66
  }
67
+
68
+ /**
69
+ * @param {string} email - The new email address to set for the user.
70
+ * @param {string} password - The current password of the user for verification.
71
+ * @returns {Promise<void|HttpError>} - A promise that resolves when the email change request is made.
72
+ */
73
+ export async function requestEmailChange(
74
+ email: string,
75
+ password: string
76
+ ): Promise<void | HttpError> {
77
+ const apiUrl = `/api/user-management-system/v1/accounts/${globalConfig.sessionConfig.userId}/email-change`
78
+ const httpClient = new HttpClient(globalConfig.baseUrl, globalConfig.sessionConfig.token)
79
+ return httpClient.post(apiUrl, { email, password })
80
+ }
81
+
82
+ /**
83
+ * @param {string} token - The token sent to the user's email for verification.
84
+ * @returns {Promise<void|HttpError>} - A promise that resolves when the email change is confirmed.
85
+ */
86
+ export async function confirmEmailChange(token: string): Promise<void | HttpError> {
87
+ const apiUrl = `/api/user-management-system/v1/accounts/email-change/confirm`
88
+ const httpClient = new HttpClient(globalConfig.baseUrl, globalConfig.sessionConfig.token)
89
+ return httpClient.post(apiUrl, { token })
90
+ }
@@ -9,6 +9,16 @@ import { HttpClient } from '../../infrastructure/http/HttpClient'
9
9
 
10
10
  const baseUrl = `/api/user-management-system`
11
11
 
12
+ /**
13
+ * Fetches the blocked users for the current user.
14
+ * @returns {Promise<Array<BlockedUsersDTO>>}
15
+ */
16
+ export async function blockedUsers() {
17
+ const url = `${baseUrl}/v1/users/${globalConfig.sessionConfig.userId}/blocked`
18
+ const httpClient = new HttpClient(globalConfig.baseUrl, globalConfig.sessionConfig.token)
19
+ return httpClient.get(url)
20
+ }
21
+
12
22
  /**
13
23
  * Block the provided user
14
24
  * @param userId
@@ -116,3 +126,24 @@ export async function getUserData(userId = globalConfig.sessionConfig.userId) {
116
126
  const httpClient = new HttpClient(globalConfig.baseUrl, globalConfig.sessionConfig.token)
117
127
  return httpClient.get(apiUrl)
118
128
  }
129
+
130
+ /**
131
+ * @param displayName - The display name to check for availability.
132
+ * @returns {Promise<{ available: boolean }>} - An object indicating if the display name is available.
133
+ */
134
+ export async function isDisplayNameAvailable(displayName) {
135
+ const apiUrl = `${baseUrl}/v1/users/display-names/available?display_name=${encodeURIComponent(displayName)}`
136
+ const httpClient = new HttpClient(globalConfig.baseUrl, globalConfig.sessionConfig.token)
137
+ return httpClient.get(apiUrl)
138
+ }
139
+
140
+ /**
141
+ * @param newDisplayName - The new display name to set for the user.
142
+ * @returns {Promise<User>} - A promise that resolves when the display name is updated.
143
+ */
144
+ export async function updateDisplayName(newDisplayName) {
145
+ const apiUrl = `${baseUrl}/v1/users/${globalConfig.sessionConfig.userId}/display-name`
146
+ const httpClient = new HttpClient(globalConfig.baseUrl, globalConfig.sessionConfig.token)
147
+ return httpClient.put(apiUrl, { display_name: newDisplayName })
148
+ }
149
+
@@ -134,3 +134,11 @@
134
134
  * @property {number} forum_post_likes
135
135
  * @property {number} experience_points
136
136
  */
137
+
138
+ /**
139
+ * @typedef {Object} BlockedUsersDTO
140
+ *
141
+ * @property {number} id
142
+ * @property {string} display_name
143
+ * @property {string|null} profile_picture_url
144
+ */
@@ -995,6 +995,7 @@ function generateContentsMap(contents, playlistsContents) {
995
995
  const existingShows = new Set()
996
996
  const contentsMap = new Map()
997
997
  const childToParentMap = {}
998
+ if (!contents) return contentsMap
998
999
  contents.forEach((content) => {
999
1000
  if (Array.isArray(content.parent_content_data) && content.parent_content_data.length > 0) {
1000
1001
  childToParentMap[content.id] =
@@ -1073,20 +1074,20 @@ export async function getProgressRows({ brand = null, limit = 8 } = {}) {
1073
1074
  nonPlaylistContentIds.push(userPinnedItem.id)
1074
1075
  }
1075
1076
  const [playlistsContents, contents] = await Promise.all([
1076
- addContextToContent(fetchByRailContentIds, playlistEngagedOnContents, 'progress-tracker', {
1077
+ playlistEngagedOnContents ? addContextToContent(fetchByRailContentIds, playlistEngagedOnContents, 'progress-tracker', {
1077
1078
  addNextLesson: true,
1078
1079
  addNavigateTo: true,
1079
1080
  addProgressStatus: true,
1080
1081
  addProgressPercentage: true,
1081
1082
  addProgressTimestamp: true,
1082
- }),
1083
- addContextToContent(fetchByRailContentIds, nonPlaylistContentIds, 'progress-tracker', brand, {
1083
+ }) : Promise.resolve([]),
1084
+ nonPlaylistContentIds ? addContextToContent(fetchByRailContentIds, nonPlaylistContentIds, 'progress-tracker', brand, {
1084
1085
  addNextLesson: true,
1085
1086
  addNavigateTo: true,
1086
1087
  addProgressStatus: true,
1087
1088
  addProgressPercentage: true,
1088
1089
  addProgressTimestamp: true,
1089
- }),
1090
+ }) : Promise.resolve([]),
1090
1091
  ])
1091
1092
  const contentsMap = generateContentsMap(contents, playlistsContents)
1092
1093
  let combined = await extractPinnedItemsAndSortAllItems(
@@ -1103,7 +1104,6 @@ export async function getProgressRows({ brand = null, limit = 8 } = {}) {
1103
1104
  item.type === 'playlist' ? processPlaylistItem(item) : processContentItem(item)
1104
1105
  )
1105
1106
  )
1106
- console.log('HomePageProgressRows results: remove before merge', results)
1107
1107
  return {
1108
1108
  type: TabResponseType.PROGRESS_ROWS,
1109
1109
  displayBrowseAll: combined.length > limit,
@@ -1,93 +0,0 @@
1
- /**
2
- * @module Awards
3
- */
4
- import '../api/types.js'
5
- import './types.js'
6
-
7
- /**
8
- * Get awards for a specific user.
9
- *
10
- * @param {number|null} userId - The user ID. If not provided, the authenticated user is used instead.
11
- * @param {string|null} brand - Brand
12
- * @param {number|null} page - Page attribute for pagination
13
- * @param {number|null} limit - Limit how many items to return
14
- * @returns {Promise<PaginatedResponse<Award>>} - The awards for the user.
15
- */
16
- export async function fetchAwardsForUser(userId, brand, page = 1, limit = 20) {
17
- // TODO: connect to the API to get the user awards
18
- return {
19
- data: [
20
- {
21
- id: 1,
22
- title: '30-Day Drummer',
23
- challenge_title: '30-Day Drummer',
24
- award:
25
- 'https://cdn.sanity.io/files/4032r8py/staging/5c7449ea40f09a096451a48e4a58e4452244e38d.png',
26
- badge:
27
- 'https://cdn.sanity.io/files/4032r8py/staging/5c7449ea40f09a096451a48e4a58e4452244e38d.png',
28
- date_completed: '2021-01-01',
29
- award_text:
30
- 'You received this award for completing 30-Day Drummer with a perfect streak. You practiced a total of 123 minutes over the past 30 days.',
31
- description:
32
- 'You received this award for completing 30-Day Drummer with a perfect streak. You practiced a total of 123 minutes over the past 30 days.',
33
- },
34
- {
35
- id: 2,
36
- title: '30-Day Bass',
37
- challenge_title: '30-Day Bass',
38
- award:
39
- 'https://cdn.sanity.io/files/4032r8py/production/b7efb6a2f0bd57e87dd13f85b1c3b0c876272b7c.png',
40
- badge:
41
- 'https://cdn.sanity.io/files/4032r8py/production/b7efb6a2f0bd57e87dd13f85b1c3b0c876272b7c.png',
42
- date_completed: '2022-02-02',
43
- award_text:
44
- 'You received this award for completing 30-Day Bass with a perfect streak. You practiced a total of 123 minutes over the past 30 days.',
45
- description:
46
- 'You received this award for completing 30-Day Bass with a perfect streak. You practiced a total of 123 minutes over the past 30 days.',
47
- },
48
- {
49
- id: 3,
50
- title: 'New Piano Players Start Here',
51
- challenge_title: 'New Piano Players Start Here',
52
- award:
53
- 'https://cdn.sanity.io/files/4032r8py/staging/94e663015da362b41695f5d6f3a8ca3f8317e1b5.png',
54
- badge:
55
- 'https://cdn.sanity.io/files/4032r8py/staging/94e663015da362b41695f5d6f3a8ca3f8317e1b5.png',
56
- date_completed: '2023-03-03',
57
- award_text:
58
- 'You received this award for completing New Piano Players Start Here with a perfect streak. You practiced a total of 123 minutes over the past 30 days.',
59
- description:
60
- 'You received this award for completing New Piano Players Start Here with a perfect streak. You practiced a total of 123 minutes over the past 30 days.',
61
- },
62
- {
63
- id: 4,
64
- title: 'Ear Training For Singers',
65
- challenge_title: 'Ear Training For Singers',
66
- award:
67
- 'https://cdn.sanity.io/files/4032r8py/staging/24fc36e8351d7994bfe8fb5c63c577cf5ed16dc9.png',
68
- badge:
69
- 'https://cdn.sanity.io/files/4032r8py/staging/24fc36e8351d7994bfe8fb5c63c577cf5ed16dc9.png',
70
- date_completed: '2024-04-04',
71
- award_text:
72
- 'You received this award for completing Ear Training For Singers with a perfect streak. You practiced a total of 123 minutes over the past 30 days.',
73
- description:
74
- 'You received this award for completing Ear Training For Singers with a perfect streak. You practiced a total of 123 minutes over the past 30 days.',
75
- },
76
- ],
77
- meta: {
78
- current_page: 1,
79
- from: 1,
80
- to: 15,
81
- per_page: 15,
82
- last_page: 1,
83
- total: 4,
84
- path: 'to be implemented when BE is ready',
85
- },
86
- links: {
87
- first: 'to be implemented when BE is ready',
88
- last: 'to be implemented when BE is ready',
89
- next: 'to be implemented when BE is ready',
90
- prev: 'to be implemented when BE is ready',
91
- },
92
- }
93
- }
@@ -1,8 +0,0 @@
1
- /**
2
- * @typedef {Object} Award
3
- * @property {number} id - Unique identifier for the award.
4
- * @property {string} title - The title of the award.
5
- * @property {string} badge - URL of the award badge image.
6
- * @property {string} description - Description of the award.
7
- * @property {Date} date_completed - Date when the award was completed.
8
- */