musora-content-services 2.69.1 → 2.70.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.
- package/.coderabbit.yaml +0 -0
- package/.editorconfig +0 -0
- package/.github/pull_request_template.md +0 -0
- package/.github/workflows/conventional-commits.yaml +0 -0
- package/.github/workflows/docs.js.yml +0 -0
- package/.github/workflows/node.js.yml +0 -0
- package/.prettierignore +0 -0
- package/.prettierrc +0 -0
- package/CHANGELOG.md +12 -0
- package/README.md +0 -0
- package/babel.config.cjs +0 -0
- package/docs/fonts/Montserrat/Montserrat-Bold.eot +0 -0
- package/docs/fonts/Montserrat/Montserrat-Bold.ttf +0 -0
- package/docs/fonts/Montserrat/Montserrat-Bold.woff +0 -0
- package/docs/fonts/Montserrat/Montserrat-Bold.woff2 +0 -0
- package/docs/fonts/Montserrat/Montserrat-Regular.eot +0 -0
- package/docs/fonts/Montserrat/Montserrat-Regular.ttf +0 -0
- package/docs/fonts/Montserrat/Montserrat-Regular.woff +0 -0
- package/docs/fonts/Montserrat/Montserrat-Regular.woff2 +0 -0
- package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.eot +0 -0
- package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.svg +0 -0
- package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.ttf +0 -0
- package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff +0 -0
- package/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff2 +0 -0
- package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.eot +0 -0
- package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.svg +0 -0
- package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.ttf +0 -0
- package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff +0 -0
- package/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff2 +0 -0
- package/docs/forums_discussions.js.html +0 -0
- package/docs/forums_forum.js.html +0 -0
- package/docs/gamification_awards.js.html +0 -0
- package/docs/gamification_types.js.html +0 -0
- package/docs/module-Categories.html +0 -0
- package/docs/module-ForumCategories.html +0 -0
- package/docs/module-ForumDiscussions.html +0 -0
- package/docs/module-Threads.html +0 -0
- package/docs/scripts/collapse.js +0 -0
- package/docs/scripts/commonNav.js +0 -0
- package/docs/scripts/linenumber.js +0 -0
- package/docs/scripts/nav.js +0 -0
- package/docs/scripts/polyfill.js +0 -0
- package/docs/scripts/prettify/Apache-License-2.0.txt +0 -0
- package/docs/scripts/prettify/lang-css.js +0 -0
- package/docs/scripts/prettify/prettify.js +0 -0
- package/docs/scripts/search.js +0 -0
- package/docs/styles/jsdoc.css +0 -0
- package/docs/styles/prettify.css +0 -0
- package/docs/user_memberships.js.html +0 -0
- package/jest.config.js +0 -0
- package/package.json +1 -1
- package/src/contentMetaData.js +16 -0
- package/src/contentTypeConfig.js +130 -120
- package/src/filterBuilder.js +0 -0
- package/src/infrastructure/http/HttpClient.ts +0 -0
- package/src/infrastructure/http/executors/FetchRequestExecutor.ts +0 -0
- package/src/infrastructure/http/index.ts +0 -0
- package/src/infrastructure/http/interfaces/HeaderProvider.ts +0 -0
- package/src/infrastructure/http/interfaces/HttpError.ts +0 -0
- package/src/infrastructure/http/interfaces/NetworkError.ts +0 -0
- package/src/infrastructure/http/interfaces/RequestExecutor.ts +0 -0
- package/src/infrastructure/http/interfaces/RequestOptions.ts +0 -0
- package/src/infrastructure/http/providers/DefaultHeaderProvider.ts +0 -0
- package/src/lib/httpHelper.js +0 -0
- package/src/lib/lastUpdated.js +0 -0
- package/src/services/api/types.js +0 -0
- package/src/services/api/types.ts +0 -0
- package/src/services/config.js +0 -0
- package/src/services/content-org/content-org.js +0 -0
- package/src/services/content-org/guided-courses.ts +0 -0
- package/src/services/content-org/learning-paths.ts +0 -0
- package/src/services/content-org/playlists-types.js +0 -0
- package/src/services/content-org/playlists.js +0 -0
- package/src/services/content.js +5 -6
- package/src/services/contentAggregator.js +0 -0
- package/src/services/contentLikes.js +0 -0
- package/src/services/contentProgress.js +0 -0
- package/src/services/dataContext.js +0 -0
- package/src/services/dateUtils.js +0 -0
- package/src/services/eventsAPI.js +0 -0
- package/src/services/forums/categories.ts +0 -0
- package/src/services/forums/forums.ts +0 -0
- package/src/services/forums/posts.ts +0 -0
- package/src/services/forums/threads.ts +0 -0
- package/src/services/forums/types.ts +0 -0
- package/src/services/gamification/awards.ts +0 -0
- package/src/services/gamification/gamification.js +0 -0
- package/src/services/imageSRCBuilder.js +0 -0
- package/src/services/railcontent.js +0 -0
- package/src/services/recommendations.js +0 -0
- package/src/services/sanity.js +1 -1
- package/src/services/types.js +0 -0
- package/src/services/user/account.ts +0 -0
- package/src/services/user/chat.js +0 -0
- package/src/services/user/interests.js +0 -0
- package/src/services/user/management.js +0 -0
- package/src/services/user/memberships.ts +0 -0
- package/src/services/user/notifications.js +0 -0
- package/src/services/user/onboarding.ts +0 -0
- package/src/services/user/payments.ts +0 -0
- package/src/services/user/permissions.js +0 -0
- package/src/services/user/profile.js +0 -0
- package/src/services/user/sessions.js +0 -0
- package/src/services/user/types.js +0 -0
- package/src/services/user/user-management-system.js +0 -0
- package/src/services/userActivity.js +0 -0
- package/test/HttpClient.test.js +0 -0
- package/test/content.test.js +0 -0
- package/test/contentLikes.test.js +0 -0
- package/test/contentProgress.test.js +0 -0
- package/test/dataContext.test.js +0 -0
- package/test/forum.test.js +0 -0
- package/test/imageSRCBuilder.test.js +0 -0
- package/test/imageSRCVerify.test.js +0 -0
- package/test/initializeTests.js +0 -0
- package/test/lib/lastUpdated.test.js +0 -0
- package/test/live/contentProgressLive.test.js +0 -0
- package/test/live/railcontentLive.test.js +0 -0
- package/test/localStorageMock.js +0 -0
- package/test/log.js +0 -0
- package/test/mockData/mockData_fetchByRailContentIds_one_content.json +0 -0
- package/test/mockData/mockData_progress_content.json +0 -0
- package/test/mockData/mockData_sanity_progress_content.json +0 -0
- package/test/mockData/mockData_user_practices.json +0 -0
- package/test/notifications.test.js +0 -0
- package/test/progressRows.test.js +0 -0
- package/test/sanityQueryService.test.js +0 -0
- package/test/streakMessage.test.js +0 -0
- package/test/user/permissions.test.js +0 -0
- package/test/userActivity.test.js +0 -0
- package/tools/generate-index.cjs +0 -0
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,18 @@
|
|
|
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.70.0](https://github.com/railroadmedia/musora-content-services/compare/v2.67.2...v2.70.0) (2025-11-05)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* add fields for learning path v2 ([#537](https://github.com/railroadmedia/musora-content-services/issues/537)) ([b2bcbd2](https://github.com/railroadmedia/musora-content-services/commit/b2bcbd2306afa730e5c61d6ee34fe082212dfdbb))
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Bug Fixes
|
|
14
|
+
|
|
15
|
+
* Add is_content and page_type to all content ([#507](https://github.com/railroadmedia/musora-content-services/issues/507)) ([174706b](https://github.com/railroadmedia/musora-content-services/commit/174706b736540b9d24ceaee11539df9203d2d135))
|
|
16
|
+
|
|
5
17
|
### [2.69.1](https://github.com/railroadmedia/musora-content-services/compare/v2.69.0...v2.69.1) (2025-11-04)
|
|
6
18
|
|
|
7
19
|
|
package/README.md
CHANGED
|
File without changes
|
package/babel.config.cjs
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
|
|
File without changes
|
|
File without changes
|
package/docs/module-Threads.html
CHANGED
|
File without changes
|
package/docs/scripts/collapse.js
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/docs/scripts/nav.js
CHANGED
|
File without changes
|
package/docs/scripts/polyfill.js
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/docs/scripts/search.js
CHANGED
|
File without changes
|
package/docs/styles/jsdoc.css
CHANGED
|
File without changes
|
package/docs/styles/prettify.css
CHANGED
|
File without changes
|
|
File without changes
|
package/jest.config.js
CHANGED
|
File without changes
|
package/package.json
CHANGED
package/src/contentMetaData.js
CHANGED
|
@@ -39,6 +39,19 @@ class SortingOptions {
|
|
|
39
39
|
]
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
export class LengthFilterOptions {
|
|
43
|
+
static UpTo7 = { value: '<420', name: 'Up to 7 Minutes' }
|
|
44
|
+
static From7To15 = { value: '420-900', name: '7 to 15 Minutes' }
|
|
45
|
+
static From15To30 = { value: '901-1800', name: '15 to 30 Minutes' }
|
|
46
|
+
static More30 = { value: '>1801', name: '30+ Minutes' }
|
|
47
|
+
static AllOptions = [
|
|
48
|
+
this.UpTo7.name,
|
|
49
|
+
this.From7To15.name,
|
|
50
|
+
this.From15To30.name,
|
|
51
|
+
this.More30.name,
|
|
52
|
+
]
|
|
53
|
+
}
|
|
54
|
+
|
|
42
55
|
export class Tabs {
|
|
43
56
|
static ForYou = { name: 'For You', short_name: 'For You' }
|
|
44
57
|
static Individuals = { name: 'Individuals', short_name: 'Individuals', value: 'type,individuals', cardType: 'big' }
|
|
@@ -82,6 +95,7 @@ const commonMetadata = {
|
|
|
82
95
|
name: 'Lessons',
|
|
83
96
|
filterOptions: {
|
|
84
97
|
difficulty: DIFFICULTY_STRINGS,
|
|
98
|
+
length: LengthFilterOptions.AllOptions,
|
|
85
99
|
style: ['Country/Folk', 'Funk/Disco', 'Hard Rock/Metal', 'Hip-Hop/Rap/EDM', 'Holiday/Soundtrack', 'Jazz/Blues', 'Latin/World', 'Pop/Rock', 'R&B/Soul', 'Worship/Gospel'],
|
|
86
100
|
type: LESSON_TYPE_FILTER,
|
|
87
101
|
progress: PROGRESS_NAMES,
|
|
@@ -157,6 +171,7 @@ const contentMetadata = {
|
|
|
157
171
|
name: 'Lessons',
|
|
158
172
|
filterOptions: {
|
|
159
173
|
difficulty: DIFFICULTY_STRINGS,
|
|
174
|
+
length: LengthFilterOptions.AllOptions,
|
|
160
175
|
style: ['Country/Folk', 'Funk/Disco', 'Hard Rock/Metal', 'Hip-Hop/Rap/EDM', 'Holiday/Soundtrack', 'Jazz/Blues', 'Latin/World', 'Pop/Rock', 'R&B/Soul', 'Worship/Gospel'],
|
|
161
176
|
type: LESSON_TYPE_FILTER,
|
|
162
177
|
progress: PROGRESS_NAMES,
|
|
@@ -182,6 +197,7 @@ const contentMetadata = {
|
|
|
182
197
|
name: 'Lessons',
|
|
183
198
|
filterOptions: {
|
|
184
199
|
difficulty: DIFFICULTY_STRINGS,
|
|
200
|
+
length: LengthFilterOptions.AllOptions,
|
|
185
201
|
style: ['Classical', 'Country/Folk', 'Funk/Disco', 'Hip-Hop/Rap/EDM', 'Holiday/Soundtrack', 'Jazz/Blues', 'Latin/World', 'Pop/Rock', 'R&B/Soul', 'Worship/Gospel'],
|
|
186
202
|
type: LESSON_TYPE_FILTER,
|
|
187
203
|
progress: PROGRESS_NAMES,
|
package/src/contentTypeConfig.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
//import {AWSUrl, CloudFrontURl} from "./services/config";
|
|
2
|
-
import {Tabs} from "./contentMetaData.js";
|
|
2
|
+
import {LengthFilterOptions, Tabs} from "./contentMetaData.js";
|
|
3
3
|
import {FilterBuilder} from "./filterBuilder.js";
|
|
4
4
|
|
|
5
5
|
export const AWSUrl = 'https://s3.us-east-1.amazonaws.com/musora-web-platform'
|
|
@@ -823,136 +823,142 @@ export function getFieldsForContentType(contentType, asQueryString = true) {
|
|
|
823
823
|
}
|
|
824
824
|
|
|
825
825
|
/**
|
|
826
|
-
*
|
|
827
|
-
* @param {Array<string>} filters - An array of strings that represent applied filters. This should be in the format of a key,value array. eg. ['difficulty,Intermediate',
|
|
828
|
-
* 'genre,rock']
|
|
829
|
-
* @returns {string} - A string that can be used in a groq query
|
|
826
|
+
* Helper function to create type conditions from content type arrays
|
|
830
827
|
*/
|
|
831
|
-
|
|
832
|
-
if (!
|
|
833
|
-
|
|
834
|
-
}
|
|
828
|
+
function createTypeConditions(lessonTypes) {
|
|
829
|
+
if (!lessonTypes || lessonTypes.length === 0) return ''
|
|
830
|
+
const conditions = lessonTypes.map(type => `_type == '${type}'`).join(' || ')
|
|
831
|
+
return conditions ? `(${conditions})` : ''
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
/**
|
|
835
|
+
* Filter handler registry - maps filter keys to their handler functions
|
|
836
|
+
*/
|
|
837
|
+
const filterHandlers = {
|
|
838
|
+
style: (value) => `"${value}" in genre[]->name`,
|
|
839
|
+
|
|
840
|
+
difficulty: (value) => {
|
|
841
|
+
if (value === 'Introductory') {
|
|
842
|
+
return `(difficulty_string == "Novice" || difficulty_string == "Introductory")`
|
|
843
|
+
}
|
|
844
|
+
return `difficulty_string == "${value}"`
|
|
845
|
+
},
|
|
846
|
+
|
|
847
|
+
tab: (value, pageName) => {
|
|
848
|
+
const valueLower = value.toLowerCase()
|
|
849
|
+
const tabMappings = {
|
|
850
|
+
[Tabs.Individuals.name.toLowerCase()]: individualLessonsTypes,
|
|
851
|
+
[Tabs.Collections.name.toLowerCase()]: collectionLessonTypes,
|
|
852
|
+
[Tabs.Tutorials.name.toLowerCase()]: tutorialsLessonTypes,
|
|
853
|
+
[Tabs.Transcriptions.name.toLowerCase()]: transcriptionsLessonTypes,
|
|
854
|
+
[Tabs.PlayAlongs.name.toLowerCase()]: playAlongLessonTypes,
|
|
855
|
+
[Tabs.JamTracks.name.toLowerCase()]: jamTrackLessonTypes,
|
|
856
|
+
[Tabs.ExploreAll.name.toLowerCase()]: filterTypes[pageName] || [],
|
|
857
|
+
[Tabs.RecentAll.name.toLowerCase()]: recentTypes[pageName] || [],
|
|
858
|
+
[Tabs.SingleLessons.name.toLowerCase()]: individualLessonsTypes,
|
|
859
|
+
[Tabs.Courses.name.toLowerCase()]: coursesLessonTypes,
|
|
860
|
+
[Tabs.SkillPacks.name.toLowerCase()]: skillLessonTypes,
|
|
861
|
+
[Tabs.Entertainment.name.toLowerCase()]: entertainmentLessonTypes,
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
const lessonTypes = tabMappings[valueLower]
|
|
865
|
+
if (lessonTypes) {
|
|
866
|
+
return createTypeConditions(lessonTypes)
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
return `_type == "${value}"`
|
|
870
|
+
},
|
|
871
|
+
|
|
872
|
+
type: (value) => {
|
|
873
|
+
const typeKey = value.toLowerCase()
|
|
874
|
+
const lessonTypes = lessonTypesMapping[typeKey]
|
|
875
|
+
|
|
876
|
+
if (lessonTypes) {
|
|
877
|
+
return createTypeConditions(lessonTypes)
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
return `_type == "${value}"`
|
|
881
|
+
},
|
|
882
|
+
|
|
883
|
+
length: (value) => {
|
|
884
|
+
// Find the matching length option by name
|
|
885
|
+
const lengthOption = Object.values(LengthFilterOptions)
|
|
886
|
+
.find(opt => typeof opt === 'object' && opt.name === value)
|
|
887
|
+
|
|
888
|
+
if (!lengthOption) return ''
|
|
835
889
|
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
if (
|
|
840
|
-
|
|
841
|
-
|
|
890
|
+
const optionValue = lengthOption.value
|
|
891
|
+
|
|
892
|
+
// Parse the value format: '<420', '420-900', '>1801'
|
|
893
|
+
if (optionValue.startsWith('<')) {
|
|
894
|
+
const max = parseInt(optionValue.substring(1), 10)
|
|
895
|
+
return `(length_in_seconds < ${max})`
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
if (optionValue.startsWith('>')) {
|
|
899
|
+
const min = parseInt(optionValue.substring(1), 10)
|
|
900
|
+
return `(length_in_seconds > ${min})`
|
|
842
901
|
}
|
|
843
|
-
})
|
|
844
902
|
|
|
845
|
-
|
|
846
|
-
|
|
903
|
+
if (optionValue.includes('-')) {
|
|
904
|
+
const [min, max] = optionValue.split('-').map(Number)
|
|
905
|
+
return `(length_in_seconds >= ${min} && length_in_seconds <= ${max})`
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
return ''
|
|
909
|
+
},
|
|
910
|
+
|
|
911
|
+
pageName: () => '', // pageName is meta, doesn't generate a query
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
/**
|
|
915
|
+
* Takes the included fields array and returns a string that can be used in the groq query.
|
|
916
|
+
* @param {Array<string>} filters - An array of strings that represent applied filters.
|
|
917
|
+
* Format: ['difficulty,Intermediate', 'genre,rock']
|
|
918
|
+
* @param {Array<string>} selectedFilters - Filters to exclude from processing
|
|
919
|
+
* @param {string} pageName - Current page name for context-specific filtering
|
|
920
|
+
* @returns {string} - A GROQ query filter string
|
|
921
|
+
*/
|
|
922
|
+
export function filtersToGroq(filters = [], selectedFilters = [], pageName = '') {
|
|
923
|
+
// Handle railcontent_id filters separately (they use different syntax)
|
|
924
|
+
const railcontentIdFilters = filters
|
|
925
|
+
.filter(item => item.includes('railcontent_id in'))
|
|
926
|
+
.map(item => ` && ${item}`)
|
|
927
|
+
.join('')
|
|
847
928
|
|
|
848
|
-
//
|
|
929
|
+
// Remove railcontent_id filters from main processing
|
|
930
|
+
const regularFilters = filters.filter(item => !item.includes('railcontent_id in'))
|
|
931
|
+
|
|
932
|
+
// Group filters by key
|
|
933
|
+
const groupedFilters = groupFilters(regularFilters)
|
|
934
|
+
|
|
935
|
+
// Process each filter group
|
|
849
936
|
const filterClauses = Object.entries(groupedFilters)
|
|
850
937
|
.map(([key, values]) => {
|
|
938
|
+
// Skip empty filters
|
|
851
939
|
if (!key || values.length === 0) return ''
|
|
940
|
+
|
|
941
|
+
// Handle boolean flags (is_*)
|
|
852
942
|
if (key.startsWith('is_')) {
|
|
853
943
|
return `&& ${key} == true`
|
|
854
944
|
}
|
|
855
|
-
|
|
945
|
+
|
|
946
|
+
// Skip if in selectedFilters
|
|
947
|
+
if (selectedFilters.includes(key)) {
|
|
948
|
+
return ''
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
// Process each value with the appropriate handler
|
|
856
952
|
const joinedValues = values
|
|
857
|
-
.map(
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
} else if (value.includes('+')) {
|
|
863
|
-
const min = parseInt(value, 10)
|
|
864
|
-
return `(bpm > ${min})`
|
|
865
|
-
} else {
|
|
866
|
-
return `bpm == ${value}`
|
|
867
|
-
}
|
|
868
|
-
} else if (
|
|
869
|
-
['creativity', 'essential', 'focus', 'genre', 'lifestyle', 'theory', 'topic'].includes(
|
|
870
|
-
key
|
|
871
|
-
) &&
|
|
872
|
-
!selectedFilters.includes(key)
|
|
873
|
-
) {
|
|
874
|
-
return `"${value}" in ${key}[]->name`
|
|
875
|
-
} else if (
|
|
876
|
-
['style'].includes(
|
|
877
|
-
key
|
|
878
|
-
) &&
|
|
879
|
-
!selectedFilters.includes(key)
|
|
880
|
-
) {
|
|
881
|
-
return `"${value}" in genre[]->name`
|
|
882
|
-
} else if (key === 'gear' && !selectedFilters.includes('gear')) {
|
|
883
|
-
return `gear match "${value}"`
|
|
884
|
-
} else if (key === 'instrumentless' && !selectedFilters.includes(key)) {
|
|
885
|
-
if (value === 'Full Song Only') {
|
|
886
|
-
return `(!instrumentless || instrumentless == null)`
|
|
887
|
-
} else if (value === 'Instrument Removed') {
|
|
888
|
-
return `instrumentless`
|
|
889
|
-
} else {
|
|
890
|
-
return `instrumentless == ${value}`
|
|
891
|
-
}
|
|
892
|
-
} else if (key === 'difficulty' && !selectedFilters.includes(key)) {
|
|
893
|
-
if(value === 'Introductory'){
|
|
894
|
-
return `(difficulty_string == "Novice" || difficulty_string == "Introductory" )`
|
|
895
|
-
}
|
|
896
|
-
return `difficulty_string == "${value}"`
|
|
897
|
-
} else if (key === 'tab' && !selectedFilters.includes(key)) {
|
|
898
|
-
if(value.toLowerCase() === Tabs.SingleLessons.name.toLowerCase()){
|
|
899
|
-
const conditions = individualLessonsTypes.map(lessonType => `_type == '${lessonType}'`).join(' || ');
|
|
900
|
-
return ` (${conditions})`;
|
|
901
|
-
} else if(value.toLowerCase() === Tabs.Courses.name.toLowerCase()){
|
|
902
|
-
const conditions = coursesLessonTypes.map(lessonType => `_type == '${lessonType}'`).join(' || ');
|
|
903
|
-
return ` (${conditions})`;
|
|
904
|
-
} else if(value.toLowerCase() === Tabs.Entertainment.name.toLowerCase()){
|
|
905
|
-
const conditions = entertainmentLessonTypes.map(lessonType => `_type == '${lessonType}'`).join(' || ');
|
|
906
|
-
return ` (${conditions})`;
|
|
907
|
-
} else if(value.toLowerCase() === Tabs.Tutorials.name.toLowerCase()){
|
|
908
|
-
const conditions = tutorialsLessonTypes.map(lessonType => `_type == '${lessonType}'`).join(' || ');
|
|
909
|
-
return ` (${conditions})`;
|
|
910
|
-
} else if(value.toLowerCase() === Tabs.Transcriptions.name.toLowerCase()){
|
|
911
|
-
const conditions = transcriptionsLessonTypes.map(lessonType => `_type == '${lessonType}'`).join(' || ');
|
|
912
|
-
return ` (${conditions})`;
|
|
913
|
-
} else if(value.toLowerCase() === Tabs.PlayAlongs.name.toLowerCase()){
|
|
914
|
-
const conditions = playAlongLessonTypes.map(lessonType => `_type == '${lessonType}'`).join(' || ');
|
|
915
|
-
return ` (${conditions})`;
|
|
916
|
-
} else if(value.toLowerCase() === Tabs.JamTracks.name.toLowerCase()){
|
|
917
|
-
const conditions = jamTrackLessonTypes.map(lessonType => `_type == '${lessonType}'`).join(' || ');
|
|
918
|
-
return ` (${conditions})`;
|
|
919
|
-
} else if(value.toLowerCase() === Tabs.ExploreAll.name.toLowerCase()){
|
|
920
|
-
var allLessons = filterTypes[pageName] || [];
|
|
921
|
-
const conditions = allLessons.map(lessonType => `_type == '${lessonType}'`).join(' || ');
|
|
922
|
-
if (conditions === "") return '';
|
|
923
|
-
return ` (${conditions})`;
|
|
924
|
-
}else if(value.toLowerCase() === Tabs.RecentAll.name.toLowerCase()){
|
|
925
|
-
var allLessons = recentTypes[pageName] || [];
|
|
926
|
-
const conditions = allLessons.map(lessonType => `_type == '${lessonType}'`).join(' || ');
|
|
927
|
-
if (conditions === "") return '';
|
|
928
|
-
return ` (${conditions})`;
|
|
929
|
-
}
|
|
930
|
-
return `_type == "${value}"`
|
|
931
|
-
} else if (key === 'type' && !selectedFilters.includes(key)) {
|
|
932
|
-
const typeKey = value.toLowerCase();
|
|
933
|
-
const lessonTypes = lessonTypesMapping[typeKey];
|
|
934
|
-
if (lessonTypes) {
|
|
935
|
-
const conditions = lessonTypes.map(
|
|
936
|
-
(lessonType) => `_type == '${lessonType}'`
|
|
937
|
-
).join(' || ');
|
|
938
|
-
return ` (${conditions})`;
|
|
939
|
-
}
|
|
940
|
-
return `_type == "${value}"`;
|
|
941
|
-
} else if (key === 'length_in_seconds') {
|
|
942
|
-
if (value.includes('-')) {
|
|
943
|
-
const [min, max] = value.split('-').map(Number)
|
|
944
|
-
return `(${key} > ${min} && ${key} < ${max})`
|
|
945
|
-
} else if (value.includes('+')) {
|
|
946
|
-
const min = parseInt(value, 10)
|
|
947
|
-
return `(${key} > ${min})`
|
|
948
|
-
} else {
|
|
949
|
-
return `${key} == ${value}`
|
|
950
|
-
}
|
|
951
|
-
} else if (key === 'pageName') {
|
|
952
|
-
return ` `
|
|
953
|
-
} else if (!selectedFilters.includes(key)) {
|
|
954
|
-
return ` ${key} == ${/^\d+$/.test(value) ? value : `"$${value}"`}`
|
|
953
|
+
.map(value => {
|
|
954
|
+
const handler = filterHandlers[key]
|
|
955
|
+
|
|
956
|
+
if (handler) {
|
|
957
|
+
return handler(value, pageName)
|
|
955
958
|
}
|
|
959
|
+
|
|
960
|
+
// Default handler for unknown filters
|
|
961
|
+
return `${key} == ${/^\d+$/.test(value) ? value : `"${value}"`}`
|
|
956
962
|
})
|
|
957
963
|
.filter(Boolean)
|
|
958
964
|
.join(' || ')
|
|
@@ -963,10 +969,14 @@ export function filtersToGroq(filters, selectedFilters = [], pageName = '') {
|
|
|
963
969
|
.filter(Boolean)
|
|
964
970
|
.join(' ')
|
|
965
971
|
|
|
966
|
-
|
|
967
|
-
return `${multipleIdFilters} ${filterClauses}`
|
|
972
|
+
return `${railcontentIdFilters} ${filterClauses}`.trim()
|
|
968
973
|
}
|
|
969
974
|
|
|
975
|
+
/**
|
|
976
|
+
* Groups filters by category
|
|
977
|
+
* @param {Array<string>} filters - Array of 'key,value' strings
|
|
978
|
+
* @returns {Object} - Object with keys as categories and values as arrays
|
|
979
|
+
*/
|
|
970
980
|
function groupFilters(filters) {
|
|
971
981
|
if (filters.length === 0) return {}
|
|
972
982
|
|
package/src/filterBuilder.js
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
|
package/src/lib/httpHelper.js
CHANGED
|
File without changes
|
package/src/lib/lastUpdated.js
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/src/services/config.js
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/src/services/content.js
CHANGED
|
@@ -14,7 +14,6 @@ import {
|
|
|
14
14
|
fetchLeaving, fetchScheduledAndNewReleases, fetchContentRows
|
|
15
15
|
} from './sanity.js'
|
|
16
16
|
import {TabResponseType, Tabs, capitalizeFirstLetter} from '../contentMetaData.js'
|
|
17
|
-
import {fetchHandler} from "./railcontent";
|
|
18
17
|
import {recommendations, rankCategories, rankItems} from "./recommendations";
|
|
19
18
|
import {addContextToContent} from "./contentAggregator.js";
|
|
20
19
|
|
|
@@ -90,7 +89,7 @@ export async function getTabResults(brand, pageName, tabName, {
|
|
|
90
89
|
let temp = await fetchTabData(brand, pageName, { page, limit, sort, includedFields: mergedIncludedFields, progress: progressValue });
|
|
91
90
|
|
|
92
91
|
const [ranking, contextResults] = await Promise.all([
|
|
93
|
-
sort === 'recommended' ? rankItems(brand, temp.entity.map(e => e.
|
|
92
|
+
sort === 'recommended' ? rankItems(brand, temp.entity.map(e => e.id)) : [],
|
|
94
93
|
addContextToContent(() => temp.entity, {
|
|
95
94
|
addNextLesson: true,
|
|
96
95
|
addNavigateTo: true,
|
|
@@ -100,8 +99,8 @@ export async function getTabResults(brand, pageName, tabName, {
|
|
|
100
99
|
]);
|
|
101
100
|
|
|
102
101
|
results = ranking.length === 0 ? contextResults : contextResults.sort((a, b) => {
|
|
103
|
-
const indexA = ranking.indexOf(a.
|
|
104
|
-
const indexB = ranking.indexOf(b.
|
|
102
|
+
const indexA = ranking.indexOf(a.id);
|
|
103
|
+
const indexB = ranking.indexOf(b.id);
|
|
105
104
|
return (indexA === -1 ? Infinity : indexA) - (indexB === -1 ? Infinity : indexB);
|
|
106
105
|
})
|
|
107
106
|
}
|
|
@@ -436,7 +435,7 @@ export async function getRecommendedForYou(brand, rowId = null, {
|
|
|
436
435
|
export async function getLegacyMethods(brand) {
|
|
437
436
|
|
|
438
437
|
// TODO: Replace with real data from Sanity when available with permissions
|
|
439
|
-
|
|
438
|
+
|
|
440
439
|
return [
|
|
441
440
|
{
|
|
442
441
|
id: 1,
|
|
@@ -451,4 +450,4 @@ export async function getLegacyMethods(brand) {
|
|
|
451
450
|
child_count: 12,
|
|
452
451
|
},
|
|
453
452
|
]
|
|
454
|
-
}
|
|
453
|
+
}
|
|
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
|
package/src/services/sanity.js
CHANGED
|
@@ -2187,7 +2187,7 @@ export async function fetchTabData(
|
|
|
2187
2187
|
let entityFieldsString = ''
|
|
2188
2188
|
let filter = ''
|
|
2189
2189
|
|
|
2190
|
-
filter = `brand == "${brand}" ${includedFieldsFilter} ${progressFilter}`
|
|
2190
|
+
filter = `brand == "${brand}" && (defined(railcontent_id)) ${includedFieldsFilter} ${progressFilter}`
|
|
2191
2191
|
const childrenFilter = await new FilterBuilder(``, { isChildrenFilter: true }).buildFilter()
|
|
2192
2192
|
const childrenFields = await getChildFieldsForContentType('tab-data')
|
|
2193
2193
|
const lessonCountFilter = await new FilterBuilder(`_id in ^.child[]._ref`).buildFilter()
|
package/src/services/types.js
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
|
package/test/HttpClient.test.js
CHANGED
|
File without changes
|
package/test/content.test.js
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/test/dataContext.test.js
CHANGED
|
File without changes
|
package/test/forum.test.js
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/test/initializeTests.js
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/test/localStorageMock.js
CHANGED
|
File without changes
|
package/test/log.js
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
|
package/tools/generate-index.cjs
CHANGED
|
File without changes
|