musora-content-services 2.122.0 → 2.122.3

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 (231) hide show
  1. package/.coderabbit.yaml +0 -0
  2. package/.editorconfig +0 -0
  3. package/.github/pull_request_template.md +0 -0
  4. package/.github/workflows/conventional-commits.yaml +0 -0
  5. package/.github/workflows/docs.js.yml +0 -0
  6. package/.github/workflows/node.js.yml +0 -0
  7. package/.prettierignore +0 -0
  8. package/.prettierrc +0 -0
  9. package/CHANGELOG.md +19 -0
  10. package/CLAUDE.md +0 -0
  11. package/README.md +0 -0
  12. package/babel.config.cjs +0 -0
  13. package/jest.config.js +0 -0
  14. package/jsdoc.json +0 -0
  15. package/package.json +1 -1
  16. package/src/constants/award-assets.js +0 -0
  17. package/src/constants/membership-permissions.ts +0 -0
  18. package/src/contentTypeConfig.js +4 -3
  19. package/src/filterBuilder.js +0 -0
  20. package/src/index.d.ts +0 -0
  21. package/src/index.js +0 -0
  22. package/src/infrastructure/http/HttpClient.ts +0 -0
  23. package/src/infrastructure/http/executors/FetchRequestExecutor.ts +0 -0
  24. package/src/infrastructure/http/index.ts +0 -0
  25. package/src/infrastructure/http/interfaces/HeaderProvider.ts +0 -0
  26. package/src/infrastructure/http/interfaces/HttpError.ts +0 -0
  27. package/src/infrastructure/http/interfaces/NetworkError.ts +0 -0
  28. package/src/infrastructure/http/interfaces/RequestExecutor.ts +0 -0
  29. package/src/infrastructure/http/interfaces/RequestOptions.ts +0 -0
  30. package/src/infrastructure/http/providers/DefaultHeaderProvider.ts +0 -0
  31. package/src/lib/ads/monoid.ts +0 -0
  32. package/src/lib/ads/semigroup.ts +0 -0
  33. package/src/lib/brands.ts +0 -0
  34. package/src/lib/lastUpdated.js +0 -0
  35. package/src/lib/sanity/filter.ts +0 -0
  36. package/src/lib/sanity/query.ts +0 -0
  37. package/src/services/api/types.js +0 -0
  38. package/src/services/api/types.ts +0 -0
  39. package/src/services/awards/award-callbacks.js +0 -0
  40. package/src/services/awards/award-query.js +0 -0
  41. package/src/services/awards/internal/.indexignore +0 -0
  42. package/src/services/awards/internal/award-definitions.js +0 -0
  43. package/src/services/awards/internal/award-events.js +0 -0
  44. package/src/services/awards/internal/award-manager.js +0 -0
  45. package/src/services/awards/internal/certificate-builder.js +0 -0
  46. package/src/services/awards/internal/completion-data-generator.js +0 -0
  47. package/src/services/awards/internal/content-progress-observer.js +0 -0
  48. package/src/services/awards/internal/image-utils.js +0 -0
  49. package/src/services/awards/internal/message-generator.js +0 -0
  50. package/src/services/awards/internal/types.js +0 -0
  51. package/src/services/awards/types.d.ts +0 -0
  52. package/src/services/awards/types.js +0 -0
  53. package/src/services/config.js +0 -0
  54. package/src/services/content/artist.ts +0 -0
  55. package/src/services/content/content.ts +0 -0
  56. package/src/services/content/genre.ts +0 -0
  57. package/src/services/content/instructor.ts +0 -0
  58. package/src/services/content-org/content-org.js +0 -0
  59. package/src/services/content-org/guided-courses.ts +0 -0
  60. package/src/services/content-org/learning-paths.ts +64 -48
  61. package/src/services/content-org/playlists-types.js +0 -0
  62. package/src/services/content-org/playlists.js +0 -0
  63. package/src/services/content.js +0 -0
  64. package/src/services/contentAggregator.js +0 -0
  65. package/src/services/contentLikes.js +0 -0
  66. package/src/services/contentProgress.js +20 -10
  67. package/src/services/dataContext.js +0 -0
  68. package/src/services/dateUtils.js +0 -0
  69. package/src/services/eventsAPI.js +0 -0
  70. package/src/services/forums/categories.ts +0 -0
  71. package/src/services/forums/forums.ts +0 -0
  72. package/src/services/forums/posts.ts +0 -0
  73. package/src/services/forums/threads.ts +0 -0
  74. package/src/services/forums/types.ts +0 -0
  75. package/src/services/gamification/awards.ts +0 -0
  76. package/src/services/gamification/gamification.js +0 -0
  77. package/src/services/imageSRCBuilder.js +0 -0
  78. package/src/services/imageSRCVerify.js +0 -0
  79. package/src/services/liveTesting.ts +0 -0
  80. package/src/services/permissions/PermissionsAdapter.ts +0 -0
  81. package/src/services/permissions/PermissionsAdapterFactory.ts +0 -0
  82. package/src/services/permissions/PermissionsV1Adapter.ts +0 -0
  83. package/src/services/permissions/PermissionsV2Adapter.ts +0 -0
  84. package/src/services/permissions/README.md +0 -0
  85. package/src/services/permissions/index.ts +0 -0
  86. package/src/services/progress-events.js +0 -0
  87. package/src/services/progress-row/base.js +7 -3
  88. package/src/services/progress-row/rows/.indexignore +0 -0
  89. package/src/services/progress-row/rows/content-card.js +0 -0
  90. package/src/services/progress-row/rows/method-card.js +1 -1
  91. package/src/services/progress-row/rows/playlist-card.js +0 -0
  92. package/src/services/railcontent.js +0 -0
  93. package/src/services/recommendations.js +0 -0
  94. package/src/services/reporting/README.md +0 -0
  95. package/src/services/reporting/reporting.ts +0 -0
  96. package/src/services/reporting/types.ts +0 -0
  97. package/src/services/sanity.js +1 -1
  98. package/src/services/sentry/.indexignore +0 -0
  99. package/src/services/sentry/index.ts +0 -0
  100. package/src/services/sync/.indexignore +0 -0
  101. package/src/services/sync/adapters/factory.ts +0 -0
  102. package/src/services/sync/adapters/lokijs.ts +0 -0
  103. package/src/services/sync/adapters/sqlite.ts +0 -0
  104. package/src/services/sync/context/index.ts +0 -0
  105. package/src/services/sync/context/providers/base.ts +0 -0
  106. package/src/services/sync/context/providers/connectivity.ts +0 -0
  107. package/src/services/sync/context/providers/durability.ts +0 -0
  108. package/src/services/sync/context/providers/index.ts +0 -0
  109. package/src/services/sync/context/providers/session.ts +0 -0
  110. package/src/services/sync/context/providers/tabs.ts +0 -0
  111. package/src/services/sync/context/providers/visibility.ts +0 -0
  112. package/src/services/sync/database/factory.ts +0 -0
  113. package/src/services/sync/effects/index.ts +0 -0
  114. package/src/services/sync/effects/logout-warning.ts +0 -0
  115. package/src/services/sync/errors/boundary.ts +0 -0
  116. package/src/services/sync/errors/index.ts +0 -0
  117. package/src/services/sync/errors/validators.ts +0 -0
  118. package/src/services/sync/fetch.ts +0 -0
  119. package/src/services/sync/index.ts +0 -0
  120. package/src/services/sync/manager.ts +0 -0
  121. package/src/services/sync/models/Base.ts +0 -0
  122. package/src/services/sync/models/ContentLike.ts +0 -0
  123. package/src/services/sync/models/ContentProgress.ts +0 -0
  124. package/src/services/sync/models/Practice.ts +0 -0
  125. package/src/services/sync/models/PracticeDayNote.ts +0 -0
  126. package/src/services/sync/models/UserAwardProgress.ts +0 -0
  127. package/src/services/sync/models/index.ts +0 -0
  128. package/src/services/sync/repositories/base.ts +2 -16
  129. package/src/services/sync/repositories/content-likes.ts +0 -0
  130. package/src/services/sync/repositories/content-progress.ts +7 -4
  131. package/src/services/sync/repositories/index.ts +0 -0
  132. package/src/services/sync/repositories/practice-day-notes.ts +0 -0
  133. package/src/services/sync/repositories/practices.ts +0 -0
  134. package/src/services/sync/repositories/user-award-progress.ts +0 -0
  135. package/src/services/sync/repository-proxy.ts +0 -0
  136. package/src/services/sync/resolver.ts +0 -0
  137. package/src/services/sync/retry.ts +0 -0
  138. package/src/services/sync/run-scope.ts +0 -0
  139. package/src/services/sync/schema/index.ts +0 -0
  140. package/src/services/sync/serializers/index.ts +0 -0
  141. package/src/services/sync/serializers/model.ts +0 -0
  142. package/src/services/sync/serializers/raw.ts +0 -0
  143. package/src/services/sync/store/index.ts +4 -2
  144. package/src/services/sync/store/push-coalescer.ts +0 -0
  145. package/src/services/sync/store-configs.ts +0 -0
  146. package/src/services/sync/strategies/base.ts +0 -0
  147. package/src/services/sync/strategies/index.ts +0 -0
  148. package/src/services/sync/strategies/initial.ts +0 -0
  149. package/src/services/sync/strategies/polling.ts +0 -0
  150. package/src/services/sync/telemetry/flood-prevention.ts +0 -0
  151. package/src/services/sync/telemetry/index.ts +0 -0
  152. package/src/services/sync/telemetry/sampling.ts +0 -0
  153. package/src/services/sync/utils/event-emitter.ts +0 -0
  154. package/src/services/sync/utils/index.ts +0 -0
  155. package/src/services/sync/utils/throttle.ts +0 -0
  156. package/src/services/sync/utils/timers.ts +0 -0
  157. package/src/services/types.js +0 -0
  158. package/src/services/urlBuilder.ts +0 -0
  159. package/src/services/user/chat.js +0 -0
  160. package/src/services/user/interests.js +0 -0
  161. package/src/services/user/management.js +0 -0
  162. package/src/services/user/memberships.ts +0 -0
  163. package/src/services/user/notifications.js +0 -0
  164. package/src/services/user/onboarding.ts +0 -0
  165. package/src/services/user/payments.ts +0 -0
  166. package/src/services/user/permissions.js +0 -0
  167. package/src/services/user/profile.js +0 -0
  168. package/src/services/user/sessions.js +0 -0
  169. package/src/services/user/types.d.ts +0 -0
  170. package/src/services/user/types.js +0 -0
  171. package/src/services/user/user-management-system.js +0 -0
  172. package/src/services/userActivity.js +0 -0
  173. package/test/HttpClient.test.js +0 -0
  174. package/test/awards/award-alacarte-observer.test.js +0 -0
  175. package/test/awards/award-auto-refresh.test.js +0 -0
  176. package/test/awards/award-calculations.test.js +0 -0
  177. package/test/awards/award-certificate-display.test.js +0 -0
  178. package/test/awards/award-collection-edge-cases.test.js +0 -0
  179. package/test/awards/award-collection-filtering.test.js +0 -0
  180. package/test/awards/award-completion-flow.test.js +0 -0
  181. package/test/awards/award-exclusion-handling.test.js +0 -0
  182. package/test/awards/award-multi-lesson.test.js +0 -0
  183. package/test/awards/award-observer-integration.test.js +0 -0
  184. package/test/awards/award-query-messages.test.js +0 -0
  185. package/test/awards/award-user-collection.test.js +0 -0
  186. package/test/awards/duplicate-prevention.test.js +0 -0
  187. package/test/awards/helpers/completion-mock.js +0 -0
  188. package/test/awards/helpers/index.js +0 -0
  189. package/test/awards/helpers/mock-setup.js +0 -0
  190. package/test/awards/helpers/progress-emitter.js +0 -0
  191. package/test/awards/message-generator.test.js +0 -0
  192. package/test/content.test.js +0 -0
  193. package/test/contentLikes.test.js +0 -0
  194. package/test/contentProgress.test.js +0 -0
  195. package/test/dataContext.test.js +0 -0
  196. package/test/forum.test.js +0 -0
  197. package/test/imageSRCBuilder.test.js +0 -0
  198. package/test/imageSRCVerify.test.js +0 -0
  199. package/test/initializeTests.js +0 -0
  200. package/test/learningPaths.test.js +0 -0
  201. package/test/lib/__snapshots__/filter.test.ts.snap +0 -0
  202. package/test/lib/filter.test.ts +0 -0
  203. package/test/lib/lastUpdated.test.js +0 -0
  204. package/test/lib/query.test.ts +0 -0
  205. package/test/live/contentProgressLive.test.js +0 -0
  206. package/test/live/railcontentLive.test.js +0 -0
  207. package/test/localStorageMock.js +0 -0
  208. package/test/log.js +0 -0
  209. package/test/mockData/award-definitions.js +0 -0
  210. package/test/mockData/mockData_fetchByRailContentIds_one_content.json +0 -0
  211. package/test/mockData/mockData_progress_content.json +0 -0
  212. package/test/mockData/mockData_sanity_progress_content.json +0 -0
  213. package/test/mockData/mockData_user_practices.json +0 -0
  214. package/test/notifications.test.js +0 -0
  215. package/test/progressRows.test.js +0 -0
  216. package/test/sanityQueryService.test.js +0 -0
  217. package/test/streakMessage.test.js +0 -0
  218. package/test/sync/adapter.ts +0 -0
  219. package/test/sync/initialize-sync-manager.js +0 -0
  220. package/test/sync/models/award-database-integration.test.js +0 -0
  221. package/test/user/permissions.test.js +0 -0
  222. package/test/userActivity.test.js +0 -0
  223. package/tools/generate-index.cjs +0 -0
  224. package/.claude/settings.local.json +0 -16
  225. package/.yarnrc.yml +0 -1
  226. package/check_content.js +0 -30
  227. package/check_content.mjs +0 -32
  228. package/test/logout.test.js +0 -199
  229. package/test/reporting.test.js +0 -132
  230. package/test_owned_navigate.js +0 -74
  231. package/tsconfig.json +0 -17
package/.coderabbit.yaml CHANGED
File without changes
package/.editorconfig CHANGED
File without changes
File without changes
File without changes
File without changes
File without changes
package/.prettierignore CHANGED
File without changes
package/.prettierrc CHANGED
File without changes
package/CHANGELOG.md CHANGED
@@ -2,6 +2,25 @@
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.122.3](https://github.com/railroadmedia/musora-content-services/compare/v2.122.2...v2.122.3) (2026-01-23)
6
+
7
+ ### [2.122.2](https://github.com/railroadmedia/musora-content-services/compare/v2.122.1...v2.122.2) (2026-01-23)
8
+
9
+
10
+ ### Bug Fixes
11
+
12
+ * broken method index ([#735](https://github.com/railroadmedia/musora-content-services/issues/735)) ([126f985](https://github.com/railroadmedia/musora-content-services/commit/126f985866f60bcca1d1ddb2dd97ba8847ff4219))
13
+
14
+ ### [2.122.1](https://github.com/railroadmedia/musora-content-services/compare/v2.122.0...v2.122.1) (2026-01-23)
15
+
16
+
17
+ ### Bug Fixes
18
+
19
+ * handle global live streams ([#727](https://github.com/railroadmedia/musora-content-services/issues/727)) ([e0ed5f3](https://github.com/railroadmedia/musora-content-services/commit/e0ed5f398f61a2188beae56a05547494862a16b7))
20
+ * removes tentative progress call functionality ([#716](https://github.com/railroadmedia/musora-content-services/issues/716)) ([a167d3b](https://github.com/railroadmedia/musora-content-services/commit/a167d3b94c1d2ef6df9a7f76e4c4ea4c71f9bfb5))
21
+ * **T3PS-1562:** hide nonpinned method card ([#721](https://github.com/railroadmedia/musora-content-services/issues/721)) ([cc250ee](https://github.com/railroadmedia/musora-content-services/commit/cc250ee072cac976fc7389eb86e77eff1230b73a))
22
+ * **T3PS-1579:** fix reset bubbling ([#718](https://github.com/railroadmedia/musora-content-services/issues/718)) ([a9490a8](https://github.com/railroadmedia/musora-content-services/commit/a9490a85aeb4df947770a265543fa6782e30b436))
23
+
5
24
  ## [2.122.0](https://github.com/railroadmedia/musora-content-services/compare/v2.118.1...v2.122.0) (2026-01-22)
6
25
 
7
26
 
package/CLAUDE.md CHANGED
File without changes
package/README.md CHANGED
File without changes
package/babel.config.cjs CHANGED
File without changes
package/jest.config.js CHANGED
File without changes
package/jsdoc.json CHANGED
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "musora-content-services",
3
- "version": "2.122.0",
3
+ "version": "2.122.3",
4
4
  "description": "A package for Musoras content services ",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
File without changes
File without changes
@@ -145,6 +145,7 @@ export const liveFields = `
145
145
  "thumbnail": thumbnail.asset->url,
146
146
  ${artistOrInstructorName()},
147
147
  difficulty_string,
148
+ railcontent_id,
148
149
  "instructors": ${instructorField},
149
150
  'videoId': coalesce(live_event_stream_id, video.external_id)
150
151
  `
@@ -647,9 +648,9 @@ export function getIntroVideoFields(type) {
647
648
  `"id": railcontent_id`,
648
649
  'title',
649
650
  'brand',
650
- `"instructor": *[_type == "method-v2" && brand == ^.brand && references(^._id)][0].${instructorField}`,
651
- `"difficulty": *[_type == "method-v2" && brand == ^.brand && references(^._id)][0].difficulty`,
652
- `"difficulty_string": *[_type == "method-v2" && brand == ^.brand][0].difficulty_string`,
651
+ `"instructor": ${instructorField}`,
652
+ `difficulty`,
653
+ `difficulty_string`,
653
654
  `"type": _type`,
654
655
  'brand',
655
656
  `"description": ${descriptionField}`,
File without changes
package/src/index.d.ts CHANGED
File without changes
package/src/index.js CHANGED
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
package/src/lib/brands.ts CHANGED
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -56,17 +56,20 @@ interface CollectionObject {
56
56
  * @param userDate - local datetime. must have date and time - format 2025-10-31T13:45:00
57
57
  * @param forceRefresh - force cache refresh
58
58
  */
59
- export async function getDailySession(brand: string, userDate: Date, forceRefresh: boolean = false) {
59
+ export async function getDailySession(
60
+ brand: string,
61
+ userDate: Date,
62
+ forceRefresh: boolean = false
63
+ ) {
60
64
  const dateWithTimezone = formatLocalDateTime(userDate)
61
65
  const url: string = `${LEARNING_PATHS_PATH}/daily-session/get?brand=${brand}&userDate=${encodeURIComponent(dateWithTimezone)}`
62
66
  try {
63
- const response = await dataPromiseGET(url, forceRefresh) as DailySessionResponse
67
+ const response = (await dataPromiseGET(url, forceRefresh)) as DailySessionResponse
64
68
  if (!response) {
65
69
  return await updateDailySession(brand, userDate, false)
66
70
  }
67
71
  dailySessionPromise = null // reset promise after successful fetch
68
72
  return response as DailySessionResponse
69
-
70
73
  } catch (error: any) {
71
74
  if (error.status === 204) {
72
75
  return await updateDailySession(brand, userDate, false)
@@ -88,16 +91,23 @@ export async function updateDailySession(
88
91
  ) {
89
92
  const dateWithTimezone = formatLocalDateTime(userDate)
90
93
  const url: string = `${LEARNING_PATHS_PATH}/daily-session/create`
91
- const body = { brand: brand, userDate: dateWithTimezone, keepFirstLearningPath: keepFirstLearningPath }
94
+ const body = {
95
+ brand: brand,
96
+ userDate: dateWithTimezone,
97
+ keepFirstLearningPath: keepFirstLearningPath,
98
+ }
99
+ try {
100
+ const response = (await POST(url, body)) as DailySessionResponse
92
101
 
93
- const response = await POST(url, body) as DailySessionResponse
102
+ if (response) {
103
+ const urlGet: string = `${LEARNING_PATHS_PATH}/daily-session/get?brand=${brand}&userDate=${encodeURIComponent(dateWithTimezone)}`
104
+ dataPromiseGET(urlGet, true) // refresh cache
105
+ }
94
106
 
95
- if (response) {
96
- const urlGet: string = `${LEARNING_PATHS_PATH}/daily-session/get?brand=${brand}&userDate=${encodeURIComponent(dateWithTimezone)}`
97
- dataPromiseGET(urlGet, true) // refresh cache
107
+ return response
108
+ } catch (error: any) {
109
+ return null
98
110
  }
99
-
100
- return response
101
111
  }
102
112
 
103
113
  function formatLocalDateTime(date: Date): string {
@@ -112,7 +122,7 @@ function formatLocalDateTime(date: Date): string {
112
122
  export async function getActivePath(brand: string, forceRefresh: boolean = false) {
113
123
  const url: string = `${LEARNING_PATHS_PATH}/active-path/get?brand=${brand}`
114
124
 
115
- const response = await dataPromiseGET(url, forceRefresh) as ActiveLearningPathResponse
125
+ const response = (await dataPromiseGET(url, forceRefresh)) as ActiveLearningPathResponse
116
126
  activePathPromise = null // reset promise after successful fetch
117
127
 
118
128
  return response
@@ -127,7 +137,7 @@ export async function startLearningPath(brand: string, learningPathId: number) {
127
137
  const url: string = `${LEARNING_PATHS_PATH}/active-path/set`
128
138
  const body = { brand: brand, learning_path_id: learningPathId }
129
139
 
130
- const response = await POST(url, body) as ActiveLearningPathResponse
140
+ const response = (await POST(url, body)) as ActiveLearningPathResponse
131
141
 
132
142
  // manual BE call to avoid recursive POST<->GET calls
133
143
  if (response) {
@@ -138,16 +148,22 @@ export async function startLearningPath(brand: string, learningPathId: number) {
138
148
  return response
139
149
  }
140
150
 
141
- async function dataPromiseGET(url: string, forceRefresh: boolean): Promise<DailySessionResponse|ActiveLearningPathResponse> {
151
+ async function dataPromiseGET(
152
+ url: string,
153
+ forceRefresh: boolean
154
+ ): Promise<DailySessionResponse | ActiveLearningPathResponse> {
142
155
  if (url.includes('daily-session')) {
143
156
  if (!dailySessionPromise || forceRefresh) {
144
- dailySessionPromise = GET(url, {cache: forceRefresh ? 'reload' : 'default'}) as Promise<DailySessionResponse>
157
+ dailySessionPromise = GET(url, {
158
+ cache: forceRefresh ? 'reload' : 'default',
159
+ }) as Promise<DailySessionResponse>
145
160
  }
146
161
  return dailySessionPromise
147
-
148
162
  } else if (url.includes('active-path')) {
149
163
  if (!activePathPromise || forceRefresh) {
150
- activePathPromise = GET(url, {cache: forceRefresh ? 'reload' : 'default'}) as Promise<ActiveLearningPathResponse>
164
+ activePathPromise = GET(url, {
165
+ cache: forceRefresh ? 'reload' : 'default',
166
+ }) as Promise<ActiveLearningPathResponse>
151
167
  }
152
168
  return activePathPromise
153
169
  }
@@ -183,14 +199,10 @@ export async function getEnrichedLearningPath(learningPathId) {
183
199
  }
184
200
  )) as any
185
201
  // add awards to LP parents only
186
- response = await addContextToLearningPaths(() => response, {addAwards:true})
202
+ response = await addContextToLearningPaths(() => response, { addAwards: true })
187
203
  if (!response) return response
188
204
 
189
- response.children = mapContentToParent(
190
- response.children,
191
- LEARNING_PATH_LESSON,
192
- learningPathId
193
- )
205
+ response.children = mapContentToParent(response.children, LEARNING_PATH_LESSON, learningPathId)
194
206
  return response
195
207
  }
196
208
 
@@ -216,7 +228,7 @@ export async function getEnrichedLearningPaths(learningPathIds: number[]) {
216
228
  }
217
229
  )) as any
218
230
  // add awards to LP parents only
219
- response = await addContextToLearningPaths(() => response, {addAwards:true})
231
+ response = await addContextToLearningPaths(() => response, { addAwards: true })
220
232
 
221
233
  if (!response) return response
222
234
 
@@ -300,9 +312,9 @@ export async function fetchLearningPathLessons(
300
312
  userDate: Date
301
313
  ) {
302
314
  const learningPath = await getEnrichedLearningPath(learningPathId)
303
- let dailySession = await getDailySession(brand, userDate) as DailySessionResponse // what if the call just fails, and a DS does exist?
315
+ let dailySession = (await getDailySession(brand, userDate)) as DailySessionResponse // what if the call just fails, and a DS does exist?
304
316
  if (!dailySession) {
305
- dailySession = await updateDailySession(brand, userDate, false) as DailySessionResponse
317
+ dailySession = (await updateDailySession(brand, userDate, false)) as DailySessionResponse
306
318
  }
307
319
 
308
320
  const isActiveLearningPath = (dailySession?.active_learning_path_id || 0) == learningPathId
@@ -320,8 +332,6 @@ export async function fetchLearningPathLessons(
320
332
  let previousContentIds = []
321
333
  let previousLearningPathId = null
322
334
 
323
-
324
-
325
335
  for (const session of dailySession.daily_session) {
326
336
  if (session.learning_path_id === learningPathId) {
327
337
  todayContentIds = session.content_ids || []
@@ -361,13 +371,13 @@ export async function fetchLearningPathLessons(
361
371
  )
362
372
  }
363
373
  if (nextContentIds.length !== 0) {
364
- nextLPDailies = await getLearningPathLessonsByIds(
365
- nextContentIds,
366
- nextLearningPathId
367
- ).then(lessons => lessons.map(lesson => ({
368
- ...lesson,
369
- in_next_learning_path: learningPath.progressStatus === STATE.COMPLETED
370
- })))
374
+ nextLPDailies = await getLearningPathLessonsByIds(nextContentIds, nextLearningPathId).then(
375
+ (lessons) =>
376
+ lessons.map((lesson) => ({
377
+ ...lesson,
378
+ in_next_learning_path: learningPath.progressStatus === STATE.COMPLETED,
379
+ }))
380
+ )
371
381
  }
372
382
 
373
383
  return {
@@ -421,22 +431,28 @@ export async function completeMethodIntroVideo(
421
431
  const methodStructure = await fetchMethodV2Structure(brand)
422
432
 
423
433
  const firstLearningPathId = methodStructure.learning_paths[0].id
424
- response.active_path_response = await methodIntroVideoCompleteActions(brand, firstLearningPathId, new Date())
434
+ response.active_path_response = await methodIntroVideoCompleteActions(
435
+ brand,
436
+ firstLearningPathId,
437
+ new Date()
438
+ )
425
439
 
426
440
  response.intro_video_response = await completeIfNotCompleted(introVideoId)
427
441
 
428
442
  return response
429
443
  }
430
444
 
431
- async function methodIntroVideoCompleteActions(brand: string, learningPathId: number, userDate: Date) {
445
+ async function methodIntroVideoCompleteActions(
446
+ brand: string,
447
+ learningPathId: number,
448
+ userDate: Date
449
+ ) {
432
450
  const stringDate = userDate.toISOString().split('T')[0]
433
451
  const url: string = `${LEARNING_PATHS_PATH}/method-intro-video-complete-actions`
434
452
  const body = { brand: brand, learningPathId: learningPathId, userDate: stringDate }
435
453
  return (await POST(url, body)) as DailySessionResponse
436
454
  }
437
455
 
438
-
439
-
440
456
  interface completeLearningPathIntroVideo {
441
457
  intro_video_response: SyncWriteDTO<ContentProgress, any> | null
442
458
  learning_path_reset_response: SyncWriteDTO<ContentProgress, any> | null
@@ -465,19 +481,13 @@ export async function completeLearningPathIntroVideo(
465
481
  const collection: CollectionObject = { id: learningPathId, type: COLLECTION_TYPE.LEARNING_PATH }
466
482
 
467
483
  if (!lessonsToImport) {
468
-
469
484
  response.learning_path_reset_response = await resetIfPossible(learningPathId, collection)
470
485
  } else {
471
-
472
486
  response.lesson_import_response = await contentStatusCompletedMany(lessonsToImport, collection)
473
487
  const activePath = await getActivePath(brand)
474
488
 
475
489
  if (activePath.active_learning_path_id === learningPathId) {
476
- response.update_dailies_response = await updateDailySession(
477
- brand,
478
- new Date(),
479
- true
480
- )
490
+ response.update_dailies_response = await updateDailySession(brand, new Date(), true)
481
491
  }
482
492
  }
483
493
 
@@ -494,13 +504,19 @@ async function completeIfNotCompleted(
494
504
  return introVideoStatus !== 'completed' ? await contentStatusCompleted(contentId) : null
495
505
  }
496
506
 
497
- async function resetIfPossible(contentId: number, collection: CollectionParameter = null): Promise<SyncWriteDTO<ContentProgress, any> | null> {
507
+ async function resetIfPossible(
508
+ contentId: number,
509
+ collection: CollectionParameter = null
510
+ ): Promise<SyncWriteDTO<ContentProgress, any> | null> {
498
511
  const status = await getProgressState(contentId, collection)
499
512
 
500
513
  return status !== '' ? await contentStatusReset(contentId, collection) : null
501
514
  }
502
515
 
503
- export async function onContentCompletedLearningPathActions(contentId: number, collection: CollectionObject|null) {
516
+ export async function onContentCompletedLearningPathActions(
517
+ contentId: number,
518
+ collection: CollectionObject | null
519
+ ) {
504
520
  if (collection?.type !== COLLECTION_TYPE.LEARNING_PATH) return
505
521
  if (contentId !== collection?.id) return
506
522
 
@@ -525,5 +541,5 @@ export async function onContentCompletedLearningPathActions(contentId: number, c
525
541
  await startLearningPath(brand, nextLearningPath.id)
526
542
  const nextLearningPathData = await getEnrichedLearningPath(nextLearningPath.id)
527
543
 
528
- await contentStatusReset(nextLearningPathData.intro_video.id, {skipPush: true})
544
+ await contentStatusReset(nextLearningPathData.intro_video.id, { skipPush: true })
529
545
  }
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -531,9 +531,8 @@ async function saveContentProgress(contentId, collection, progress, currentSecon
531
531
  }
532
532
  }
533
533
 
534
- if (Object.keys(bubbledProgresses).length >= 0) {
535
- // BE bubbling/trickling currently does not work, so we utilize non-tentative pushing when learning path collection
536
- await db.contentProgress.recordProgressMany(bubbledProgresses, collection, {tentative: !isLP, skipPush: true, fromLearningPath})
534
+ if (Object.keys(bubbledProgresses).length > 0) {
535
+ await db.contentProgress.recordProgressMany(bubbledProgresses, collection, {skipPush: true, fromLearningPath})
537
536
  }
538
537
 
539
538
  if (isLP) {
@@ -567,8 +566,7 @@ async function setStartedOrCompletedStatus(contentId, collection, isCompleted, {
567
566
  ...trickleProgress(hierarchy, contentId, collection, progress),
568
567
  ...await bubbleProgress(hierarchy, contentId, collection)
569
568
  }
570
- // BE bubbling/trickling currently does not work, so we utilize non-tentative pushing when learning path collection
571
- await db.contentProgress.recordProgressMany(progresses, collection, {tentative: !isLP, skipPush: true})
569
+ await db.contentProgress.recordProgressMany(progresses, collection, {skipPush: true})
572
570
 
573
571
  if (isLP) {
574
572
  let exportProgresses = progresses
@@ -600,7 +598,7 @@ async function setStartedOrCompletedStatusMany(contentIds, collection, isComplet
600
598
  }
601
599
 
602
600
  const contents = Object.fromEntries(contentIds.map((id) => [id, progress]))
603
- const response = await db.contentProgress.recordProgressMany(contents, collection, {tentative: !isLP, skipPush: true})
601
+ const response = await db.contentProgress.recordProgressMany(contents, collection, {skipPush: true})
604
602
 
605
603
  // we assume this is used only for contents within the same hierarchy
606
604
  const hierarchy = await getHierarchy(collection.id, collection)
@@ -613,8 +611,7 @@ async function setStartedOrCompletedStatusMany(contentIds, collection, isComplet
613
611
  ...(await bubbleProgress(hierarchy, contentId, collection)),
614
612
  }
615
613
  }
616
- // BE bubbling/trickling currently does not work, so we utilize non-tentative pushing when learning path collection
617
- await db.contentProgress.recordProgressMany(progresses, collection, {tentative: !isLP, skipPush: true})
614
+ await db.contentProgress.recordProgressMany(progresses, collection, {skipPush: true})
618
615
 
619
616
  if (isLP) {
620
617
  let exportProgresses = progresses
@@ -647,8 +644,21 @@ async function resetStatus(contentId, collection = null, {skipPush = false} = {}
647
644
  ...trickleProgress(hierarchy, contentId, collection, progress),
648
645
  ...await bubbleProgress(hierarchy, contentId, collection)
649
646
  }
650
- // BE bubbling/trickling currently does not work, so we utilize non-tentative pushing when learning path collection
651
- await db.contentProgress.recordProgressMany(progresses, collection, {tentative: !isLP, skipPush: true})
647
+ // have to use different endpoints for erase vs record
648
+ const eraseProgresses = Object.fromEntries(
649
+ Object.entries(progresses).filter(([_, pct]) => pct === 0)
650
+ )
651
+ progresses = Object.fromEntries(
652
+ Object.entries(progresses).filter(([_, pct]) => pct > 0)
653
+ )
654
+
655
+ if (Object.keys(progresses).length > 0) {
656
+ await db.contentProgress.recordProgressMany(progresses, collection, {skipPush: true, fromLearningPath: isLP})
657
+ }
658
+ if (Object.keys(eraseProgresses).length > 0) {
659
+ const eraseIds = Object.keys(eraseProgresses).map(Number)
660
+ await db.contentProgress.eraseProgressMany(eraseIds, collection, {skipPush: true})
661
+ }
652
662
 
653
663
  if (isLP) {
654
664
  progresses[contentId] = progress
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -178,12 +178,16 @@ function sortCards(pinnedCard, contentCardMap, playlistCards, methodCard, limit)
178
178
  combined.push(pinnedCard)
179
179
  }
180
180
 
181
- if (!(pinnedCard && pinnedCard.progressType === 'method')) {
181
+ const progressList = Array.from(contentCardMap.values())
182
+
183
+ combined = [...combined, ...progressList, ...playlistCards]
184
+
185
+ // welcome card state will only show if pinned
186
+ if (methodCard.type !== 'method') {
182
187
  combined.push(methodCard)
183
188
  }
184
189
 
185
- const progressList = Array.from(contentCardMap.values())
186
- return mergeAndSortItems([...combined, ...progressList, ...playlistCards], limit)
190
+ return mergeAndSortItems(combined, limit)
187
191
  }
188
192
 
189
193
  function mergeAndSortItems(items, limit) {
File without changes
File without changes
@@ -111,7 +111,7 @@ export async function getMethodCard(brand) {
111
111
  }
112
112
 
113
113
  return {
114
- id: learningPath?.id,
114
+ id: 1,
115
115
  type: COLLECTION_TYPE.LEARNING_PATH,
116
116
  progressType: 'method',
117
117
  header: 'Method',
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes