musora-content-services 1.0.20 → 1.0.21
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/docs/config.js.html +124 -0
- package/docs/index.html +2 -2
- package/docs/module-Config.html +669 -0
- package/docs/module-Railcontent-Services.html +751 -0
- package/docs/{global.html → module-Sanity-Services.html} +52 -501
- package/docs/railcontent.js.html +178 -0
- package/docs/sanity.js.html +994 -0
- package/jsdoc.json +1 -1
- package/package.json +1 -1
- package/publish.sh +0 -0
- package/src/index.d.ts +2 -2
- package/src/index.js +32 -909
- package/src/services/config.js +52 -0
- package/src/services/railcontent.js +106 -0
- package/src/services/sanity.js +922 -0
- package/test/sanityQueryService.test.js +2 -2
- package/docs/data/search.json +0 -1
- package/docs/fonts/Inconsolata-Regular.ttf +0 -0
- package/docs/fonts/OpenSans-Bold-webfont.eot +0 -0
- package/docs/fonts/OpenSans-Bold-webfont.svg +0 -1830
- package/docs/fonts/OpenSans-Bold-webfont.woff +0 -0
- package/docs/fonts/OpenSans-BoldItalic-webfont.eot +0 -0
- package/docs/fonts/OpenSans-BoldItalic-webfont.svg +0 -1830
- package/docs/fonts/OpenSans-BoldItalic-webfont.woff +0 -0
- package/docs/fonts/OpenSans-Italic-webfont.eot +0 -0
- package/docs/fonts/OpenSans-Italic-webfont.svg +0 -1830
- package/docs/fonts/OpenSans-Italic-webfont.woff +0 -0
- package/docs/fonts/OpenSans-Light-webfont.eot +0 -0
- package/docs/fonts/OpenSans-Light-webfont.svg +0 -1831
- package/docs/fonts/OpenSans-Light-webfont.woff +0 -0
- package/docs/fonts/OpenSans-LightItalic-webfont.eot +0 -0
- package/docs/fonts/OpenSans-LightItalic-webfont.svg +0 -1835
- package/docs/fonts/OpenSans-LightItalic-webfont.woff +0 -0
- package/docs/fonts/OpenSans-Regular-webfont.eot +0 -0
- package/docs/fonts/OpenSans-Regular-webfont.svg +0 -1831
- package/docs/fonts/OpenSans-Regular-webfont.woff +0 -0
- package/docs/fonts/OpenSans-Regular.ttf +0 -0
- package/docs/fonts/OpenSans-Semibold-webfont.eot +0 -0
- package/docs/fonts/OpenSans-Semibold-webfont.svg +0 -1830
- package/docs/fonts/OpenSans-Semibold-webfont.ttf +0 -0
- package/docs/fonts/OpenSans-Semibold-webfont.woff +0 -0
- package/docs/fonts/OpenSans-SemiboldItalic-webfont.eot +0 -0
- package/docs/fonts/OpenSans-SemiboldItalic-webfont.svg +0 -1830
- package/docs/fonts/OpenSans-SemiboldItalic-webfont.ttf +0 -0
- package/docs/fonts/OpenSans-SemiboldItalic-webfont.woff +0 -0
- package/docs/fonts/WorkSans-Bold.ttf +0 -0
- package/docs/index.js.html +0 -1122
- package/docs/scripts/core.js +0 -726
- package/docs/scripts/core.min.js +0 -23
- package/docs/scripts/resize.js +0 -90
- package/docs/scripts/search.min.js +0 -6
- package/docs/scripts/third-party/Apache-License-2.0.txt +0 -202
- package/docs/scripts/third-party/fuse.js +0 -9
- package/docs/scripts/third-party/hljs-line-num-original.js +0 -369
- package/docs/scripts/third-party/hljs-line-num.js +0 -1
- package/docs/scripts/third-party/hljs-original.js +0 -5171
- package/docs/scripts/third-party/hljs.js +0 -1
- package/docs/scripts/third-party/popper.js +0 -5
- package/docs/scripts/third-party/tippy.js +0 -1
- package/docs/scripts/third-party/tocbot.js +0 -672
- package/docs/scripts/third-party/tocbot.min.js +0 -1
- package/docs/styles/clean-jsdoc-theme-base.css +0 -1159
- package/docs/styles/clean-jsdoc-theme-dark.css +0 -412
- package/docs/styles/clean-jsdoc-theme-light.css +0 -482
- package/docs/styles/clean-jsdoc-theme-scrollbar.css +0 -30
- package/docs/styles/clean-jsdoc-theme-without-scrollbar.min.css +0 -1
- package/docs/styles/clean-jsdoc-theme.min.css +0 -1
- package/docs/styles/jsdoc-default.css +0 -692
- package/docs/styles/prettify-jsdoc.css +0 -111
- package/docs/styles/prettify-tomorrow.css +0 -132
package/src/index.js
CHANGED
|
@@ -1,910 +1,34 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Fetch a song by its document ID from Sanity.
|
|
34
|
-
*
|
|
35
|
-
* @param {string} documentId - The ID of the document to fetch.
|
|
36
|
-
* @returns {Promise<Object|null>} - A promise that resolves to an object containing the song data or null if not found.
|
|
37
|
-
*
|
|
38
|
-
* @example
|
|
39
|
-
* fetchSongById('abc123')
|
|
40
|
-
* .then(song => console.log(song))
|
|
41
|
-
* .catch(error => console.error(error));
|
|
42
|
-
*/
|
|
43
|
-
async function fetchSongById(documentId) {
|
|
44
|
-
const fields = [
|
|
45
|
-
'title',
|
|
46
|
-
'"thumbnail_url": thumbnail.asset->url',
|
|
47
|
-
'"style": genre[0]->name',
|
|
48
|
-
'"artist": artist->name',
|
|
49
|
-
'album',
|
|
50
|
-
'instrumentless',
|
|
51
|
-
'soundslice',
|
|
52
|
-
'railcontent_id',
|
|
53
|
-
'"resources": resource[]{resource_url, resource_name}',
|
|
54
|
-
];
|
|
55
|
-
|
|
56
|
-
const query = `
|
|
57
|
-
*[_type == "song" && railcontent_id == ${documentId}]{
|
|
58
|
-
${fields.join(', ')}
|
|
59
|
-
}`;
|
|
60
|
-
return fetchSanity(query, false);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Fetch all artists with lessons available for a specific brand.
|
|
65
|
-
*
|
|
66
|
-
* @param {string} brand - The brand for which to fetch artists.
|
|
67
|
-
* @returns {Promise<Object|null>} - A promise that resolves to an array of artist objects or null if not found.
|
|
68
|
-
*
|
|
69
|
-
* @example
|
|
70
|
-
* fetchArtists('drumeo')
|
|
71
|
-
* .then(artists => console.log(artists))
|
|
72
|
-
* .catch(error => console.error(error));
|
|
73
|
-
*/
|
|
74
|
-
async function fetchArtists(brand) {
|
|
75
|
-
const query = `
|
|
76
|
-
*[_type == "artist"]{
|
|
77
|
-
name,
|
|
78
|
-
"lessonsCount": count(*[_type == "song" && brand == "${brand}" && references(^._id)])
|
|
79
|
-
}[lessonsCount > 0]`;
|
|
80
|
-
return fetchSanity(query, true);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Fetch current number of artists for songs within a brand.
|
|
85
|
-
* @param {string} brand - The current brand.
|
|
86
|
-
* @returns {Promise<int|null>} - The fetched count of artists.
|
|
87
|
-
*/
|
|
88
|
-
async function fetchSongArtistCount(brand) {
|
|
89
|
-
const query = `count(*[_type == 'artist']{'lessonsCount': count(*[_type == 'song' && brand == '${brand}' && references(^._id)]._id)}[lessonsCount > 0])`;
|
|
90
|
-
return fetchSanity(query, true);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* Fetch related songs for a specific brand and song ID.
|
|
95
|
-
*
|
|
96
|
-
* @param {string} brand - The brand for which to fetch related songs.
|
|
97
|
-
* @param {string} songId - The ID of the song to find related songs for.
|
|
98
|
-
* @returns {Promise<Object|null>} - A promise that resolves to an array of related song objects or null if not found.
|
|
99
|
-
*
|
|
100
|
-
* @example
|
|
101
|
-
* fetchRelatedSongs('drumeo', '12345')
|
|
102
|
-
* .then(relatedSongs => console.log(relatedSongs))
|
|
103
|
-
* .catch(error => console.error(error));
|
|
104
|
-
*/
|
|
105
|
-
async function fetchRelatedSongs(brand, songId) {
|
|
106
|
-
const query = `
|
|
107
|
-
*[_type == "song" && railcontent_id == ${songId}]{
|
|
108
|
-
"data": array::unique([
|
|
109
|
-
...(*[_type == "song" && brand == "${brand}" && railcontent_id != ${songId} && references(^.artist->_id)]{
|
|
110
|
-
"type": _type,
|
|
111
|
-
"id": railcontent_id,
|
|
112
|
-
"url": web_url_path,
|
|
113
|
-
"published_on": published_on,
|
|
114
|
-
status,
|
|
115
|
-
"fields": [
|
|
116
|
-
{
|
|
117
|
-
"key": "title",
|
|
118
|
-
"value": title
|
|
119
|
-
},
|
|
120
|
-
{
|
|
121
|
-
"key": "artist",
|
|
122
|
-
"value": artist->name
|
|
123
|
-
},
|
|
124
|
-
{
|
|
125
|
-
"key": "difficulty",
|
|
126
|
-
"value": difficulty
|
|
127
|
-
},
|
|
128
|
-
{
|
|
129
|
-
"key": "length_in_seconds",
|
|
130
|
-
"value": soundslice[0].soundslice_length_in_second
|
|
131
|
-
}
|
|
132
|
-
],
|
|
133
|
-
"data": [{
|
|
134
|
-
"key": "thumbnail_url",
|
|
135
|
-
"value": thumbnail.asset->url
|
|
136
|
-
}]
|
|
137
|
-
}[0...10]),
|
|
138
|
-
...(*[_type == "song" && brand == "${brand}" && railcontent_id != ${songId} && references(^.genre[]->_id)]{
|
|
139
|
-
"type": _type,
|
|
140
|
-
"id": railcontent_id,
|
|
141
|
-
"url": web_url_path,
|
|
142
|
-
"published_on": published_on,
|
|
143
|
-
status,
|
|
144
|
-
"fields": [
|
|
145
|
-
{
|
|
146
|
-
"key": "title",
|
|
147
|
-
"value": title
|
|
148
|
-
},
|
|
149
|
-
{
|
|
150
|
-
"key": "artist",
|
|
151
|
-
"value": artist->name
|
|
152
|
-
},
|
|
153
|
-
{
|
|
154
|
-
"key": "difficulty",
|
|
155
|
-
"value": difficulty
|
|
156
|
-
},
|
|
157
|
-
{
|
|
158
|
-
"key": "length_in_seconds",
|
|
159
|
-
"value": soundslice[0].soundslice_length_in_second
|
|
160
|
-
}
|
|
161
|
-
],
|
|
162
|
-
"data": [{
|
|
163
|
-
"key": "thumbnail_url",
|
|
164
|
-
"value": thumbnail.asset->url
|
|
165
|
-
}]
|
|
166
|
-
}[0...10])
|
|
167
|
-
])[0...10]
|
|
168
|
-
}`;
|
|
169
|
-
|
|
170
|
-
return fetchSanity(query, true);
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
/**
|
|
174
|
-
* Fetch all songs for a specific brand with pagination and search options.
|
|
175
|
-
* @param {string} brand - The brand for which to fetch songs.
|
|
176
|
-
* @param {Object} params - Parameters for pagination, filtering, and sorting.
|
|
177
|
-
* @param {number} [params.page=1] - The page number for pagination.
|
|
178
|
-
* @param {number} [params.limit=10] - The number of songs per page.
|
|
179
|
-
* @param {string} [params.searchTerm=""] - The search term to filter songs by title or artist.
|
|
180
|
-
* @param {string} [params.sort="-published_on"] - The field to sort the songs by.
|
|
181
|
-
* @param {Array<string>} [params.includedFields=[]] - The fields to include in the query.
|
|
182
|
-
* @param {string} [params.groupBy=""] - The field to group the results by.
|
|
183
|
-
* @returns {Promise<Object|null>} - The fetched song data or null if not found.
|
|
184
|
-
*
|
|
185
|
-
* @example
|
|
186
|
-
* fetchAllSongs('drumeo', {
|
|
187
|
-
* page: 2,
|
|
188
|
-
* limit: 20,
|
|
189
|
-
* searchTerm: 'rock',
|
|
190
|
-
* sort: 'published_on',
|
|
191
|
-
* includedFields: ['difficulty', 'style'],
|
|
192
|
-
* groupBy: 'artist'
|
|
193
|
-
* })
|
|
194
|
-
* .then(result => console.log(result))
|
|
195
|
-
* .catch(error => console.error(error));
|
|
196
|
-
*/
|
|
197
|
-
async function fetchAllSongs(brand, {
|
|
198
|
-
page = 1,
|
|
199
|
-
limit = 10,
|
|
200
|
-
searchTerm = "",
|
|
201
|
-
sort = "-published_on",
|
|
202
|
-
includedFields = [],
|
|
203
|
-
groupBy = ""
|
|
204
|
-
}) {
|
|
205
|
-
return fetchAll(brand, 'song', {page, limit, searchTerm, sort, includedFields, groupBy});
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
/**
|
|
209
|
-
* Fetch filter options for a specific brand.
|
|
210
|
-
*
|
|
211
|
-
* @param {string} brand - The brand for which to fetch filter options.
|
|
212
|
-
* @returns {Promise<Object|null>} - A promise that resolves to an object containing filter options or null if not found.
|
|
213
|
-
*
|
|
214
|
-
* @example
|
|
215
|
-
* fetchSongFilterOptions('drumeo')
|
|
216
|
-
* .then(options => console.log(options))
|
|
217
|
-
* .catch(error => console.error(error));
|
|
218
|
-
*/
|
|
219
|
-
async function fetchSongFilterOptions(brand) {
|
|
220
|
-
const query = `
|
|
221
|
-
{
|
|
222
|
-
"difficulty": [
|
|
223
|
-
{"type": "Introductory", "count": count(*[_type == 'song' && brand == '${brand}' && difficulty_string == "Introductory"]._id)},
|
|
224
|
-
{"type": "Beginner", "count": count(*[_type == 'song' && brand == '${brand}' && difficulty_string == "Beginner"]._id)},
|
|
225
|
-
{"type": "Intermediate", "count": count(*[_type == 'song' && brand == '${brand}' && difficulty_string == "Intermediate"]._id)},
|
|
226
|
-
{"type": "Advanced", "count": count(*[_type == 'song' && brand == '${brand}' && difficulty_string == "Advanced"]._id)},
|
|
227
|
-
{"type": "Expert", "count": count(*[_type == 'song' && brand == '${brand}' && difficulty_string == "Expert"]._id)}
|
|
228
|
-
],
|
|
229
|
-
"genre": *[_type == 'genre' && 'song' in filter_types] {
|
|
230
|
-
"type": name,
|
|
231
|
-
"count": count(*[_type == 'song' && brand == '${brand}' && references(^._id)]._id)
|
|
232
|
-
},
|
|
233
|
-
"instrumentless": [
|
|
234
|
-
{"type": "Full Song Only", "count": count(*[_type == 'song' && brand == '${brand}' && instrumentless == false]._id)},
|
|
235
|
-
{"type": "Instrument Removed", "count": count(*[_type == 'song' && brand == '${brand}' && instrumentless == true]._id)}
|
|
236
|
-
]
|
|
237
|
-
}
|
|
238
|
-
`;
|
|
239
|
-
|
|
240
|
-
return fetchSanity(query, true);
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
/**
|
|
244
|
-
* Fetch the total count of songs for a specific brand.
|
|
245
|
-
* @param {string} brand - The brand for which to fetch the song count.
|
|
246
|
-
* @returns {Promise<number|null>} - The total count of songs or null if an error occurs.
|
|
247
|
-
*/
|
|
248
|
-
async function fetchSongCount(brand) {
|
|
249
|
-
const query = `count(*[_type == 'song' && brand == "${brand}"])`;
|
|
250
|
-
return fetchSanity(query, false);
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
/**
|
|
254
|
-
* Fetch the latest workouts for the home page of a specific brand.
|
|
255
|
-
* This function retrieves the latest workout content for a given brand, fetching up to five workouts. The workouts are sorted in descending order by their publication date.
|
|
256
|
-
* @param {string} brand - The brand for which to fetch workouts (e.g., 'drumeo', 'pianote').
|
|
257
|
-
* @returns {Promise<Array<Object>|null>} - A promise that resolves to an array of workout data objects or null if no workouts are found.
|
|
258
|
-
*
|
|
259
|
-
* @example
|
|
260
|
-
* fetchWorkouts('drumeo')
|
|
261
|
-
* .then(workouts => console.log(workouts))
|
|
262
|
-
* .catch(error => console.error(error));
|
|
263
|
-
*/
|
|
264
|
-
async function fetchWorkouts(brand) {
|
|
265
|
-
const query = `*[_type == 'workout' && brand == '${brand}'] [0...5] {
|
|
266
|
-
"id": railcontent_id,
|
|
267
|
-
title,
|
|
268
|
-
"image": thumbnail.asset->url,
|
|
269
|
-
"artist_name": instructor[0]->name,
|
|
270
|
-
"artists": instructor[]->name,
|
|
271
|
-
difficulty,
|
|
272
|
-
difficulty_string,
|
|
273
|
-
length_in_seconds,
|
|
274
|
-
published_on,
|
|
275
|
-
"type": _type,
|
|
276
|
-
web_url_path,
|
|
277
|
-
} | order(published_on desc)[0...5]`
|
|
278
|
-
return fetchSanity(query, true);
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
/**
|
|
282
|
-
* Fetch the latest new releases for a specific brand.
|
|
283
|
-
* @param {string} brand - The brand for which to fetch new releases.
|
|
284
|
-
* @returns {Promise<Object|null>} - The fetched new releases data or null if not found.
|
|
285
|
-
*/
|
|
286
|
-
async function fetchNewReleases(brand) {
|
|
287
|
-
const newTypes = {
|
|
288
|
-
'drumeo': ["drum-fest-international-2022", "spotlight", "the-history-of-electronic-drums", "backstage-secrets", "quick-tips", "question-and-answer", "student-collaborations", "live-streams", "live", "podcasts", "solos", "boot-camps", "gear-guides", "performances", "in-rhythm", "challenges", "on-the-road", "diy-drum-experiments", "rhythmic-adventures-of-captain-carson", "study-the-greats", "rhythms-from-another-planet", "tama-drums", "paiste-cymbals", "behind-the-scenes", "exploring-beats", "sonor-drums", "course", "play-along", "student-focus", "coach-stream", "learning-path-level", "unit", "quick-tips", "live", "question-and-answer", "student-review", "boot-camps", "song", "chords-and-scales", "pack", "podcasts", "workout", "challenge", "challenge-part"],
|
|
289
|
-
'pianote': ["student-review", "student-reviews", "question-and-answer", "course", "play-along", "student-focus", "coach-stream", "learning-path-level", "unit", "quick-tips", "live", "question-and-answer", "student-review", "boot-camps", "song", "chords-and-scales", "pack", "podcasts", "workout", "challenge", "challenge-part"],
|
|
290
|
-
'guitareo': ["student-review", "student-reviews", "question-and-answer", "archives", "recording", "course", "play-along", "student-focus", "coach-stream", "learning-path-level", "unit", "quick-tips", "live", "question-and-answer", "student-review", "boot-camps", "song", "chords-and-scales", "pack", "podcasts", "workout", "challenge", "challenge-part"],
|
|
291
|
-
'singeo': ["student-review", "student-reviews", "question-and-answer", "course", "play-along", "student-focus", "coach-stream", "learning-path-level", "unit", "quick-tips", "live", "question-and-answer", "student-review", "boot-camps", "song", "chords-and-scales", "pack", "podcasts", "workout", "challenge", "challenge-part"],
|
|
292
|
-
'default': ["student-review", "student-reviews", "question-and-answer", "course", "play-along", "student-focus", "coach-stream", "learning-path-level", "unit", "quick-tips", "live", "question-and-answer", "student-review", "boot-camps", "song", "chords-and-scales", "pack", "podcasts", "workout", "challenge", "challenge-part"]
|
|
293
|
-
};
|
|
294
|
-
const typesString = arrayJoinWithQuotes(newTypes[brand] ?? newTypes['default']);
|
|
295
|
-
const query = `*[_type in [${typesString}] && brand == '${brand}'] | order(releaseDate desc) [0...5] {
|
|
296
|
-
"id": railcontent_id,
|
|
297
|
-
title,
|
|
298
|
-
"image": thumbnail.asset->url,
|
|
299
|
-
"artist_name": instructor[0]->name,
|
|
300
|
-
"artists": instructor[]->name,
|
|
301
|
-
difficulty,
|
|
302
|
-
difficulty_string,
|
|
303
|
-
length_in_seconds,
|
|
304
|
-
published_on,
|
|
305
|
-
"type": _type,
|
|
306
|
-
web_url_path,
|
|
307
|
-
} | order(published_on desc)[0...5]`
|
|
308
|
-
return fetchSanity(query, true);
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
/**
|
|
312
|
-
* Fetch upcoming events for a specific brand.
|
|
313
|
-
*
|
|
314
|
-
* @param {string} brand - The brand for which to fetch upcoming events.
|
|
315
|
-
* @returns {Promise<Object|null>} - A promise that resolves to an array of upcoming event objects or null if not found.
|
|
316
|
-
*
|
|
317
|
-
* @example
|
|
318
|
-
* fetchUpcomingEvents('drumeo')
|
|
319
|
-
* .then(events => console.log(events))
|
|
320
|
-
* .catch(error => console.error(error));
|
|
321
|
-
*/
|
|
322
|
-
async function fetchUpcomingEvents(brand) {
|
|
323
|
-
const baseLiveTypes = ["student-review", "student-reviews", "student-focus", "coach-stream", "live", "question-and-answer", "student-review", "boot-camps", "recording", "pack-bundle-lesson"];
|
|
324
|
-
const liveTypes = {
|
|
325
|
-
'drumeo': [...baseLiveTypes, "drum-fest-international-2022", "spotlight", "the-history-of-electronic-drums", "backstage-secrets", "quick-tips", "student-collaborations", "live-streams", "podcasts", "solos", "gear-guides", "performances", "in-rhythm", "challenges", "on-the-road", "diy-drum-experiments", "rhythmic-adventures-of-captain-carson", "study-the-greats", "rhythms-from-another-planet", "tama-drums", "paiste-cymbals", "behind-the-scenes", "exploring-beats", "sonor-drums"],
|
|
326
|
-
'pianote': baseLiveTypes,
|
|
327
|
-
'guitareo': [...baseLiveTypes, "archives"],
|
|
328
|
-
'singeo': baseLiveTypes,
|
|
329
|
-
'default': baseLiveTypes
|
|
330
|
-
};
|
|
331
|
-
const typesString = arrayJoinWithQuotes(liveTypes[brand] ?? liveTypes['default']);
|
|
332
|
-
const now = getSanityDate(new Date());
|
|
333
|
-
//TODO: status = 'scheduled' is this handled in sanity?
|
|
334
|
-
const query = `*[_type in [${typesString}] && brand == '${brand}' && published_on > '${now}']{
|
|
335
|
-
"id": railcontent_id,
|
|
336
|
-
title,
|
|
337
|
-
"image": thumbnail.asset->url,
|
|
338
|
-
"artist_name": instructor[0]->name,
|
|
339
|
-
"artists": instructor[]->name,
|
|
340
|
-
difficulty,
|
|
341
|
-
difficulty_string,
|
|
342
|
-
length_in_seconds,
|
|
343
|
-
published_on,
|
|
344
|
-
"type": _type,
|
|
345
|
-
web_url_path,
|
|
346
|
-
} | order(published_on asc)[0...5]`;
|
|
347
|
-
return fetchSanity(query, true);
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
/**
|
|
351
|
-
* Fetch upcoming events for a specific brand that are within 48 hours before their `published_on` date
|
|
352
|
-
* and are currently ongoing based on their `length_in_seconds`.
|
|
353
|
-
*
|
|
354
|
-
* This function retrieves events that have a `published_on` date within the last 48 hours or are currently
|
|
355
|
-
* ongoing based on the event's duration (`length_in_seconds`).
|
|
356
|
-
*
|
|
357
|
-
* @param {string} brand - The brand for which to fetch upcoming events (e.g., 'drumeo', 'pianote', etc.).
|
|
358
|
-
* @returns {Promise<Array<Object>|null>} - A promise that resolves to an array of event objects or null if no events are found.
|
|
359
|
-
*
|
|
360
|
-
* @example
|
|
361
|
-
* // Example usage:
|
|
362
|
-
* fetchUpcomingEvents('drumeo')
|
|
363
|
-
* .then(events => console.log(events))
|
|
364
|
-
* .catch(error => console.error(error));
|
|
365
|
-
*
|
|
366
|
-
*/
|
|
367
|
-
async function fetchLiveEvent(brand) {
|
|
368
|
-
const baseLiveTypes = ["student-review", "student-reviews", "student-focus", "coach-stream", "live", "question-and-answer", "student-review", "boot-camps", "recording", "pack-bundle-lesson"];
|
|
369
|
-
const liveTypes = {
|
|
370
|
-
'drumeo': [...baseLiveTypes, "drum-fest-international-2022", "spotlight", "the-history-of-electronic-drums", "backstage-secrets", "quick-tips", "student-collaborations", "live-streams", "podcasts", "solos", "gear-guides", "performances", "in-rhythm", "challenges", "on-the-road", "diy-drum-experiments", "rhythmic-adventures-of-captain-carson", "study-the-greats", "rhythms-from-another-planet", "tama-drums", "paiste-cymbals", "behind-the-scenes", "exploring-beats", "sonor-drums"],
|
|
371
|
-
'pianote': baseLiveTypes,
|
|
372
|
-
'guitareo': [...baseLiveTypes, "archives"],
|
|
373
|
-
'singeo': baseLiveTypes,
|
|
374
|
-
'default': baseLiveTypes
|
|
375
|
-
};
|
|
376
|
-
|
|
377
|
-
const typesString = arrayJoinWithQuotes(liveTypes[brand] ?? liveTypes['default']);
|
|
378
|
-
const now = getSanityDate(new Date());
|
|
379
|
-
const twoDaysAgo = getSanityDate(new Date(Date.now() - 48 * 60 * 60 * 1000)); // 48 hours ago
|
|
380
|
-
|
|
381
|
-
// Adjust the query to filter events based on the calculated time window
|
|
382
|
-
const query = `
|
|
383
|
-
*[_type in [${typesString}] && brand == '${brand}'
|
|
384
|
-
&& published_on > '${twoDaysAgo}'
|
|
385
|
-
|| (published_on <= '${now}' && dateTime(published_on) + length_in_seconds * 1000 > '${now}')
|
|
386
|
-
] {
|
|
387
|
-
"id": railcontent_id,
|
|
388
|
-
title,
|
|
389
|
-
"image": thumbnail.asset->url,
|
|
390
|
-
"artist_name": instructor[0]->name,
|
|
391
|
-
"artists": instructor[]->name,
|
|
392
|
-
difficulty,
|
|
393
|
-
difficulty_string,
|
|
394
|
-
length_in_seconds,
|
|
395
|
-
published_on,
|
|
396
|
-
"type": _type,
|
|
397
|
-
web_url_path,
|
|
398
|
-
} | order(published_on asc)[0]`;
|
|
399
|
-
|
|
400
|
-
return fetchSanity(query, true);
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
/**
|
|
405
|
-
* Fetch content by a specific Railcontent ID.
|
|
406
|
-
*
|
|
407
|
-
* @param {string} id - The Railcontent ID of the content to fetch.
|
|
408
|
-
* @returns {Promise<Object|null>} - A promise that resolves to the content object or null if not found.
|
|
409
|
-
*
|
|
410
|
-
* @example
|
|
411
|
-
* fetchByRailContentId('abc123')
|
|
412
|
-
* .then(content => console.log(content))
|
|
413
|
-
* .catch(error => console.error(error));
|
|
414
|
-
*/
|
|
415
|
-
async function fetchByRailContentId(id) {
|
|
416
|
-
const query = `*[railcontent_id == ${id}]{
|
|
417
|
-
railcontent_id,
|
|
418
|
-
title,
|
|
419
|
-
"image": thumbnail.asset->url,
|
|
420
|
-
"artist_name": artist->name,
|
|
421
|
-
artist,
|
|
422
|
-
difficulty,
|
|
423
|
-
difficulty_string,
|
|
424
|
-
web_url_path,
|
|
425
|
-
published_on
|
|
426
|
-
}`
|
|
427
|
-
return fetchSanity(query, false);
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
/**
|
|
431
|
-
* Fetch content by an array of Railcontent IDs.
|
|
432
|
-
*
|
|
433
|
-
* @param {Array<string>} ids - The array of Railcontent IDs of the content to fetch.
|
|
434
|
-
* @returns {Promise<Array<Object>|null>} - A promise that resolves to an array of content objects or null if not found.
|
|
435
|
-
*
|
|
436
|
-
* @example
|
|
437
|
-
* fetchByRailContentIds(['abc123', 'def456', 'ghi789'])
|
|
438
|
-
* .then(contents => console.log(contents))
|
|
439
|
-
* .catch(error => console.error(error));
|
|
440
|
-
*/
|
|
441
|
-
async function fetchByRailContentIds(ids) {
|
|
442
|
-
const idsString = ids.join(',');
|
|
443
|
-
const query = `*[railcontent_id in [${idsString}]]{
|
|
444
|
-
railcontent_id,
|
|
445
|
-
title,
|
|
446
|
-
"image": thumbnail.asset->url,
|
|
447
|
-
"artist_name": artist->name,
|
|
448
|
-
artist,
|
|
449
|
-
difficulty,
|
|
450
|
-
difficulty_string,
|
|
451
|
-
web_url_path,
|
|
452
|
-
published_on
|
|
453
|
-
}`
|
|
454
|
-
return fetchSanity(query, true);
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
/**
|
|
458
|
-
* Fetch all content for a specific brand and type with pagination, search, and grouping options.
|
|
459
|
-
* @param {string} brand - The brand for which to fetch content.
|
|
460
|
-
* @param {string} type - The content type to fetch (e.g., 'song', 'artist').
|
|
461
|
-
* @param {Object} params - Parameters for pagination, filtering, sorting, and grouping.
|
|
462
|
-
* @param {number} [params.page=1] - The page number for pagination.
|
|
463
|
-
* @param {number} [params.limit=10] - The number of items per page.
|
|
464
|
-
* @param {string} [params.searchTerm=""] - The search term to filter content by title or artist.
|
|
465
|
-
* @param {string} [params.sort="-published_on"] - The field to sort the content by.
|
|
466
|
-
* @param {Array<string>} [params.includedFields=[]] - The fields to include in the query.
|
|
467
|
-
* @param {string} [params.groupBy=""] - The field to group the results by (e.g., 'artist', 'genre').
|
|
468
|
-
* @returns {Promise<Object|null>} - The fetched content data or null if not found.
|
|
469
|
-
*
|
|
470
|
-
* @example
|
|
471
|
-
* fetchAll('drumeo', 'song', {
|
|
472
|
-
* page: 2,
|
|
473
|
-
* limit: 20,
|
|
474
|
-
* searchTerm: 'jazz',
|
|
475
|
-
* sort: '-popularity',
|
|
476
|
-
* includedFields: ['difficulty,Intermediate'],
|
|
477
|
-
* groupBy: 'artist'
|
|
478
|
-
* })
|
|
479
|
-
* .then(content => console.log(content))
|
|
480
|
-
* .catch(error => console.error(error));
|
|
481
|
-
*/
|
|
482
|
-
async function fetchAll(brand, type, {
|
|
483
|
-
page = 1,
|
|
484
|
-
limit = 10,
|
|
485
|
-
searchTerm = "",
|
|
486
|
-
sort = "-published_on",
|
|
487
|
-
includedFields = [],
|
|
488
|
-
groupBy = ""
|
|
489
|
-
}) {
|
|
490
|
-
let config = contentTypeConfig[type] ?? {};
|
|
491
|
-
let additionalFields = config?.fields ?? [];
|
|
492
|
-
let isGroupByOneToOne = (groupBy ? config?.relationships[groupBy]?.isOneToOne : false) ?? false;
|
|
493
|
-
const start = (page - 1) * limit;
|
|
494
|
-
const end = start + limit;
|
|
495
|
-
|
|
496
|
-
// Construct the search filter
|
|
497
|
-
const searchFilter = searchTerm
|
|
498
|
-
? `&& (artist->name match "${searchTerm}*" || title match "${searchTerm}*")`
|
|
499
|
-
: "";
|
|
500
|
-
|
|
501
|
-
// Construct the included fields filter, replacing 'difficulty' with 'difficulty_string'
|
|
502
|
-
const includedFieldsFilter = includedFields.length > 0
|
|
503
|
-
? includedFields.map(field => {
|
|
504
|
-
let [key, value] = field.split(',');
|
|
505
|
-
if (key === 'difficulty') {
|
|
506
|
-
key = 'difficulty_string';
|
|
507
|
-
}
|
|
508
|
-
return `&& ${key} == "${value}"`;
|
|
509
|
-
}).join(' ')
|
|
510
|
-
: "";
|
|
511
|
-
|
|
512
|
-
// Determine the sort order
|
|
513
|
-
let sortOrder;
|
|
514
|
-
switch (sort) {
|
|
515
|
-
case "slug":
|
|
516
|
-
sortOrder = "artist->name asc";
|
|
517
|
-
break;
|
|
518
|
-
case "published_on":
|
|
519
|
-
sortOrder = "published_on desc";
|
|
520
|
-
break;
|
|
521
|
-
case "-published_on":
|
|
522
|
-
sortOrder = "published_on asc";
|
|
523
|
-
break;
|
|
524
|
-
case "-slug":
|
|
525
|
-
sortOrder = "artist->name desc";
|
|
526
|
-
break;
|
|
527
|
-
case "-popularity":
|
|
528
|
-
sortOrder = "popularity desc";
|
|
529
|
-
break;
|
|
530
|
-
default:
|
|
531
|
-
sortOrder = "published_on asc";
|
|
532
|
-
break;
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
let defaultFields = ['railcontent_id',
|
|
536
|
-
'title',
|
|
537
|
-
'"image": thumbnail.asset->url',
|
|
538
|
-
'difficulty',
|
|
539
|
-
'difficulty_string',
|
|
540
|
-
'web_url_path',
|
|
541
|
-
'published_on'];
|
|
542
|
-
|
|
543
|
-
let fields = defaultFields.concat(additionalFields);
|
|
544
|
-
let fieldsString = fields.join(',');
|
|
545
|
-
|
|
546
|
-
// Determine the group by clause
|
|
547
|
-
let query = "";
|
|
548
|
-
if (groupBy !== "" && isGroupByOneToOne) {
|
|
549
|
-
query = `
|
|
550
|
-
{
|
|
551
|
-
"total": count(*[_type == '${groupBy}' && count(*[_type == '${type}' && brand == '${brand}' && ^._id == ${groupBy}._ref ]._id) > 0]),
|
|
552
|
-
"entity": *[_type == '${groupBy}' && count(*[_type == '${type}' && brand == '${brand}' && ^._id == ${groupBy}._ref ]._id) > 0]
|
|
553
|
-
{
|
|
554
|
-
'id': _id,
|
|
555
|
-
'type': _type,
|
|
556
|
-
name,
|
|
557
|
-
'head_shot_picture_url': thumbnail_url.asset->url,
|
|
558
|
-
'all_lessons_count': count(*[_type == '${type}' && brand == '${brand}' && ^._id == ${groupBy}._ref ]._id),
|
|
559
|
-
'lessons': *[_type == '${type}' && brand == '${brand}' && ^._id == ${groupBy}._ref ]{
|
|
560
|
-
${fieldsString},
|
|
561
|
-
${groupBy}
|
|
562
|
-
}[0...10]
|
|
563
|
-
}
|
|
564
|
-
|order(${sortOrder})
|
|
565
|
-
[${start}...${end}]
|
|
566
|
-
}`;
|
|
567
|
-
} else if (groupBy !== "") {
|
|
568
|
-
query = `
|
|
569
|
-
{
|
|
570
|
-
"total": count(*[_type == '${groupBy}' && count(*[_type == '${type}' && brand == '${brand}' && ^._id in ${groupBy}[]._ref]._id)>0]),
|
|
571
|
-
"entity": *[_type == '${groupBy}' && count(*[_type == '${type}' && brand == '${brand}' && ^._id in ${groupBy}[]._ref]._id) > 0]
|
|
572
|
-
{
|
|
573
|
-
'id': _id,
|
|
574
|
-
'type': _type,
|
|
575
|
-
name,
|
|
576
|
-
'head_shot_picture_url': thumbnail_url.asset->url,
|
|
577
|
-
'all_lessons_count': count(*[_type == '${type}' && brand == '${brand}' && ^._id in ${groupBy}[]._ref ]._id),
|
|
578
|
-
'lessons': *[_type == '${type}' && brand == '${brand}' && ^._id in ${groupBy}[]._ref ]{
|
|
579
|
-
${fieldsString},
|
|
580
|
-
${groupBy}
|
|
581
|
-
}[0...10]
|
|
582
|
-
}
|
|
583
|
-
|order(${sortOrder})
|
|
584
|
-
[${start}...${end}]
|
|
585
|
-
}`;
|
|
586
|
-
} else {
|
|
587
|
-
query = `
|
|
588
|
-
{
|
|
589
|
-
"entity": *[_type == '${type}' && brand == "${brand}" ${searchFilter} ${includedFieldsFilter}] | order(${sortOrder}) [${start}...${end}] {
|
|
590
|
-
${fieldsString}
|
|
591
|
-
},
|
|
592
|
-
"total": count(*[_type == '${type}' && brand == "${brand}" ${searchFilter} ${includedFieldsFilter}])
|
|
593
|
-
}
|
|
594
|
-
`;
|
|
595
|
-
}
|
|
596
|
-
|
|
597
|
-
return fetchSanity(query, true);
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
/**
|
|
601
|
-
* Fetches all available filter options based on various criteria such as brand, filters, style, artist, content type, and search term.
|
|
602
|
-
*
|
|
603
|
-
* This function constructs a query to retrieve the total number of results and filter options such as difficulty, instrument type, and genre.
|
|
604
|
-
* The filter options are dynamically generated based on the provided filters, style, artist, and content type.
|
|
605
|
-
*
|
|
606
|
-
* @param {string} brand - The brand for which to fetch the filter options.
|
|
607
|
-
* @param {string} filters - Additional filters to apply to the query, typically in the format of Sanity GROQ queries.
|
|
608
|
-
* @param {string} [style] - Optional style or genre to filter the results. If provided, the query will check if the style exists in the genre array.
|
|
609
|
-
* @param {string} [artist] - Optional artist name to filter the results. If provided, the query will check if the artist's name matches.
|
|
610
|
-
* @param {string} contentType - The content type to fetch (e.g., 'song', 'lesson').
|
|
611
|
-
* @param {string} [term] - Optional search term to match against various fields such as title, album, artist name, and genre.
|
|
612
|
-
*
|
|
613
|
-
* @returns {Promise<Object|null>} - A promise that resolves to an object containing the total results and filter options, or null if the query fails.
|
|
614
|
-
*
|
|
615
|
-
* @example
|
|
616
|
-
* // Example usage:
|
|
617
|
-
* fetchAllFilterOptions('myBrand', '', 'Rock', 'John Doe', 'song', 'Love')
|
|
618
|
-
* .then(options => console.log(options))
|
|
619
|
-
* .catch(error => console.error(error));
|
|
620
|
-
*/
|
|
621
|
-
async function fetchAllFilterOptions(
|
|
622
|
-
brand,
|
|
623
|
-
filters,
|
|
624
|
-
style,
|
|
625
|
-
artist,
|
|
626
|
-
contentType,
|
|
627
|
-
term
|
|
628
|
-
) {
|
|
629
|
-
const query = `
|
|
630
|
-
{
|
|
631
|
-
"meta": {
|
|
632
|
-
"totalResults": count(*[_type == '${contentType}' && brand == "${brand}" && ${style ? `'${style}' in genre[]->name` : `artist->name == '${artist}'`} ${filters}
|
|
633
|
-
${term ? `&& (title match "${term}" || album match "${term}" || artist->name match "${term}" || genre[]->name match "${term}")` : ''}]),
|
|
634
|
-
"filterOptions": {
|
|
635
|
-
"difficulty": [
|
|
636
|
-
{"type": "Introductory", "count": count(*[_type == '${contentType}' && brand == '${brand}' && ${style ? `'${style}' in genre[]->name` : `artist->name == '${artist}'`} && difficulty_string == "Introductory" ${filters}])},
|
|
637
|
-
{"type": "Beginner", "count": count(*[_type == '${contentType}' && brand == '${brand}' && ${style ? `'${style}' in genre[]->name` : `artist->name == '${artist}'`} && difficulty_string == "Beginner" ${filters}])},
|
|
638
|
-
{"type": "Intermediate", "count": count(*[_type == '${contentType}' && brand == '${brand}' && ${style ? `'${style}' in genre[]->name` : `artist->name == '${artist}'`} && difficulty_string == "Intermediate" ${filters}])},
|
|
639
|
-
{"type": "Advanced", "count": count(*[_type == '${contentType}' && brand == '${brand}' && ${style ? `'${style}' in genre[]->name` : `artist->name == '${artist}'`} && difficulty_string == "Advanced" ${filters}])},
|
|
640
|
-
{"type": "Expert", "count": count(*[_type == '${contentType}' && brand == '${brand}' && ${style ? `'${style}' in genre[]->name` : `artist->name == '${artist}'`} && difficulty_string == "Expert" ${filters}])}
|
|
641
|
-
][count > 0],
|
|
642
|
-
"instrumentless": [
|
|
643
|
-
{"type": "Full Song Only", "count": count(*[_type == '${contentType}' && brand == '${brand}' && ${style ? `'${style}' in genre[]->name` : `artist->name == '${artist}'`} && instrumentless == false ${filters}])},
|
|
644
|
-
{"type": "Instrument Removed", "count": count(*[_type == '${contentType}' && brand == '${brand}' && ${style ? `'${style}' in genre[]->name` : `artist->name == '${artist}'`} && instrumentless == true ${filters}])}
|
|
645
|
-
][count > 0],
|
|
646
|
-
"genre": *[_type == 'genre' && '${contentType}' in filter_types] {
|
|
647
|
-
"type": name,
|
|
648
|
-
"count": count(*[_type == '${contentType}' && brand == "${brand}" && ${style ? `'${style}' in genre[]->name` : `artist->name == '${artist}'`} && references(^._id)])
|
|
649
|
-
}[count > 0]
|
|
650
|
-
}
|
|
651
|
-
}
|
|
652
|
-
}
|
|
653
|
-
`;
|
|
654
|
-
|
|
655
|
-
return fetchSanity(query, false);
|
|
656
|
-
}
|
|
657
|
-
|
|
658
|
-
/**
|
|
659
|
-
* Fetch children content by Railcontent ID.
|
|
660
|
-
* @param {string} railcontentId - The Railcontent ID of the parent content.
|
|
661
|
-
* @returns {Promise<Array<Object>|null>} - The fetched children content data or null if not found.
|
|
662
|
-
*/
|
|
663
|
-
async function fetchChildren(railcontentId) {
|
|
664
|
-
//TODO: Implement getByParentId include sum XP
|
|
665
|
-
const query = `*[_railcontent_id == ${railcontentId}]{
|
|
666
|
-
railcontent_id,
|
|
667
|
-
title,
|
|
668
|
-
"image": thumbnail.asset->url,
|
|
669
|
-
"artist_name": artist->name,
|
|
670
|
-
artist,
|
|
671
|
-
difficulty,
|
|
672
|
-
difficulty_string,
|
|
673
|
-
web_url_path,
|
|
674
|
-
published_on
|
|
675
|
-
} | order(published_on asc)`
|
|
676
|
-
return fetchSanity(query, true);
|
|
677
|
-
}
|
|
678
|
-
|
|
679
|
-
/**
|
|
680
|
-
* Fetch the next lesson for a specific method by Railcontent ID.
|
|
681
|
-
* @param {string} railcontentId - The Railcontent ID of the current lesson.
|
|
682
|
-
* @returns {Promise<Object|null>} - The fetched next lesson data or null if not found.
|
|
683
|
-
*/
|
|
684
|
-
async function fetchMethodNextLesson(railcontentId) {
|
|
685
|
-
//TODO: Implement getNextContentForParentContentForUser
|
|
686
|
-
const query = `*[_railcontent_id == ${railcontentId}]{
|
|
687
|
-
railcontent_id,
|
|
688
|
-
title,
|
|
689
|
-
"image": thumbnail.asset->url,
|
|
690
|
-
"artist_name": artist->name,
|
|
691
|
-
artist,
|
|
692
|
-
difficulty,
|
|
693
|
-
difficulty_string,
|
|
694
|
-
web_url_path,
|
|
695
|
-
published_on
|
|
696
|
-
}`
|
|
697
|
-
return fetchSanity(query, false);
|
|
698
|
-
}
|
|
699
|
-
|
|
700
|
-
/**
|
|
701
|
-
* Fetch all children of a specific method by Railcontent ID.
|
|
702
|
-
* @param {string} railcontentId - The Railcontent ID of the method.
|
|
703
|
-
* @returns {Promise<Array<Object>|null>} - The fetched children data or null if not found.
|
|
704
|
-
*/
|
|
705
|
-
async function fetchMethodChildren(railcontentId) {
|
|
706
|
-
//TODO: Implement getByParentId include sum XP
|
|
707
|
-
return fetchChildren(railcontentId);
|
|
708
|
-
}
|
|
709
|
-
|
|
710
|
-
/**
|
|
711
|
-
* Fetch the next and previous lessons for a specific lesson by Railcontent ID.
|
|
712
|
-
* @param {string} railcontentId - The Railcontent ID of the current lesson.
|
|
713
|
-
* @returns {Promise<Object|null>} - The fetched next and previous lesson data or null if found.
|
|
714
|
-
*/
|
|
715
|
-
async function fetchNextPreviousLesson(railcontentId) {
|
|
716
|
-
//TODO: Implement getTypeNeighbouringSiblings/getNextAndPreviousLessons
|
|
717
|
-
const query = `*[_railcontent_id == ${railcontentId}]{
|
|
718
|
-
railcontent_id,
|
|
719
|
-
title,
|
|
720
|
-
"image": thumbnail.asset->url,
|
|
721
|
-
"artist_name": artist->name,
|
|
722
|
-
artist,
|
|
723
|
-
difficulty,
|
|
724
|
-
difficulty_string,
|
|
725
|
-
web_url_path,
|
|
726
|
-
published_on
|
|
727
|
-
}`
|
|
728
|
-
return fetchSanity(query, false);
|
|
729
|
-
}
|
|
730
|
-
|
|
731
|
-
/**
|
|
732
|
-
* Fetch the page data for a specific lesson by Railcontent ID.
|
|
733
|
-
* @param {string} railContentId - The Railcontent ID of the current lesson.
|
|
734
|
-
* @returns {Promise<Object|null>} - The fetched page data or null if found.
|
|
735
|
-
*
|
|
736
|
-
* @example
|
|
737
|
-
* fetchLessonContent('lesson123')
|
|
738
|
-
* .then(data => console.log(data))
|
|
739
|
-
* .catch(error => console.error(error));
|
|
740
|
-
*/
|
|
741
|
-
async function fetchLessonContent(railContentId) {
|
|
742
|
-
const query = `*[railcontent_id == ${railContentId} ]
|
|
743
|
-
{title, published_on,"type":_type, "resources": resource, difficulty, difficulty_string, brand, soundslice, instrumentless, railcontent_id, "id":railcontent_id, slug, artist->,"thumbnail_url":thumbnail.asset->url, "url": web_url_path, soundslice_slug,description,
|
|
744
|
-
"chapters": chapter[]{
|
|
745
|
-
chapter_description,
|
|
746
|
-
chapter_timecode,
|
|
747
|
-
"chapter_thumbnail_url": chapter_thumbnail_url.asset->url
|
|
748
|
-
},
|
|
749
|
-
"coaches": instructor[]-> {
|
|
750
|
-
name,
|
|
751
|
-
"id":_id,
|
|
752
|
-
"coach_profile_image":thumbnail_url.asset->url
|
|
753
|
-
},
|
|
754
|
-
"instructors":instructor[]->name,
|
|
755
|
-
instructor[]->,
|
|
756
|
-
"assignments":assignment[]{
|
|
757
|
-
"id": railcontent_id,
|
|
758
|
-
"soundslice_slug": assignment_soundslice,
|
|
759
|
-
"title": assignment_title,
|
|
760
|
-
"sheet_music_image_url": assignment_sheet_music_image,
|
|
761
|
-
"timecode": assignment_timecode,
|
|
762
|
-
"description": assignment_description
|
|
763
|
-
},
|
|
764
|
-
video}`
|
|
765
|
-
return fetchSanity(query, false);
|
|
766
|
-
}
|
|
767
|
-
|
|
768
|
-
/**
|
|
769
|
-
* Fetch related lessons for a specific lesson by RailContent ID and type.
|
|
770
|
-
* @param {string} railContentId - The RailContent ID of the current lesson.
|
|
771
|
-
* @param {string} brand - The current brand.
|
|
772
|
-
* @returns {Promise<Array<Object>|null>} - The fetched related lessons data or null if not found.
|
|
773
|
-
*/
|
|
774
|
-
async function fetchRelatedLessons(railContentId, brand) {
|
|
775
|
-
// let sort = 'published_on'
|
|
776
|
-
// if (type == 'rhythmic-adventures-of-captain-carson' ||
|
|
777
|
-
// type == 'diy-drum-experiments' ||
|
|
778
|
-
// type == 'in-rhythm') {
|
|
779
|
-
// sort = 'sort';
|
|
780
|
-
// }
|
|
781
|
-
//TODO: Implement $this->contentService->getFiltered
|
|
782
|
-
const query = `*[railcontent_id == ${railContentId} && brand == "${brand}" && references(*[_type=='permission']._id)]{
|
|
783
|
-
"related_lessons" : array::unique([
|
|
784
|
-
...(*[_type=="song" && brand == "${brand}" && references(^.artist->_id)]{_id, "id":railcontent_id, published_on, title, "thumbnail_url":thumbnail.asset->url, difficulty_string, railcontent_id, artist->}[0...11]),
|
|
785
|
-
...(*[_type=="song" && brand == "${brand}" && references(^.genre[]->_id)]{_id, "id":railcontent_id, published_on, title, "thumbnail_url":thumbnail.asset->url, difficulty_string, railcontent_id, artist->}[0...11])
|
|
786
|
-
])|order(published_on, railcontent_id)[0...11]}`;
|
|
787
|
-
return fetchSanity(query, false);
|
|
788
|
-
}
|
|
789
|
-
|
|
790
|
-
/**
|
|
791
|
-
* Fetch all content for a specific pack by Railcontent ID.
|
|
792
|
-
* @param {string} railcontentId - The Railcontent ID of the pack.
|
|
793
|
-
* @returns {Promise<Array<Object>|null>} - The fetched pack content data or null if not found.
|
|
794
|
-
*/
|
|
795
|
-
async function fetchPackAll(railcontentId) {
|
|
796
|
-
//TODO: Implement getPacks
|
|
797
|
-
const query = `*[_railcontent_id == ${railcontentId}]{
|
|
798
|
-
railcontent_id,
|
|
799
|
-
title,
|
|
800
|
-
"image": thumbnail.asset->url,
|
|
801
|
-
"artist_name": artist->name,
|
|
802
|
-
artist,
|
|
803
|
-
difficulty,
|
|
804
|
-
difficulty_string,
|
|
805
|
-
web_url_path,
|
|
806
|
-
published_on
|
|
807
|
-
} | order(published_on asc)[0...5]`
|
|
808
|
-
return fetchSanity(query, true);
|
|
809
|
-
}
|
|
810
|
-
|
|
811
|
-
/**
|
|
812
|
-
* Fetch all children of a specific pack by Railcontent ID.
|
|
813
|
-
* @param {string} railcontentId - The Railcontent ID of the pack.
|
|
814
|
-
* @returns {Promise<Array<Object>|null>} - The fetched pack children data or null if not found.
|
|
815
|
-
*
|
|
816
|
-
* @example
|
|
817
|
-
* fetchPackChildren('pack123')
|
|
818
|
-
* .then(children => console.log(children))
|
|
819
|
-
* .catch(error => console.error(error));
|
|
820
|
-
*/
|
|
821
|
-
async function fetchPackChildren(railcontentId) {
|
|
822
|
-
return fetchChildren(railcontentId, 'pack');
|
|
823
|
-
}
|
|
824
|
-
|
|
825
|
-
/**
|
|
826
|
-
* Fetch data from the Sanity API based on a provided query.
|
|
827
|
-
*
|
|
828
|
-
* @param {string} query - The GROQ query to execute against the Sanity API.
|
|
829
|
-
* @param {boolean} isList - Whether to return an array or a single result.
|
|
830
|
-
* @returns {Promise<Object|null>} - A promise that resolves to the fetched data or null if an error occurs or no results are found.
|
|
831
|
-
*
|
|
832
|
-
* @example
|
|
833
|
-
* const query = `*[_type == "song"]{title, artist->name}`;
|
|
834
|
-
* fetchSanity(query, true)
|
|
835
|
-
* .then(data => console.log(data))
|
|
836
|
-
* .catch(error => console.error(error));
|
|
837
|
-
*/
|
|
838
|
-
async function fetchSanity(query, isList) {
|
|
839
|
-
// Check the config object before proceeding
|
|
840
|
-
if (!checkConfig(globalConfig)) {
|
|
841
|
-
return null;
|
|
842
|
-
}
|
|
843
|
-
|
|
844
|
-
if (globalConfig.debug) {
|
|
845
|
-
console.log("fetchSanity Query:", query);
|
|
846
|
-
}
|
|
847
|
-
|
|
848
|
-
const encodedQuery = encodeURIComponent(query);
|
|
849
|
-
const api = globalConfig.useCachedAPI ? 'apicdn' : 'api'
|
|
850
|
-
const url = `https://${globalConfig.projectId}.${api}.sanity.io/v${globalConfig.version}/data/query/${globalConfig.dataset}?query=${encodedQuery}`;
|
|
851
|
-
const headers = {
|
|
852
|
-
'Authorization': `Bearer ${globalConfig.token}`,
|
|
853
|
-
'Content-Type': 'application/json'
|
|
854
|
-
};
|
|
855
|
-
|
|
856
|
-
try {
|
|
857
|
-
const response = await fetch(url, {headers});
|
|
858
|
-
const result = await response.json();
|
|
859
|
-
if (result.result) {
|
|
860
|
-
if (globalConfig.debug) {
|
|
861
|
-
console.log("fetchSanity Results:", result);
|
|
862
|
-
}
|
|
863
|
-
return isList ? result.result : result.result[0];
|
|
864
|
-
} else {
|
|
865
|
-
throw new Error('No results found');
|
|
866
|
-
}
|
|
867
|
-
} catch (error) {
|
|
868
|
-
console.error('fetchSanity: Fetch error:', error);
|
|
869
|
-
return null;
|
|
870
|
-
}
|
|
871
|
-
}
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
//Helper Functions
|
|
875
|
-
function arrayJoinWithQuotes(array, delimiter = ',') {
|
|
876
|
-
const wrapped = array.map(value => `'${value}'`);
|
|
877
|
-
return wrapped.join(delimiter)
|
|
878
|
-
}
|
|
879
|
-
|
|
880
|
-
function getSanityDate(date) {
|
|
881
|
-
return date.toISOString();
|
|
882
|
-
}
|
|
883
|
-
|
|
884
|
-
function checkConfig(config) {
|
|
885
|
-
if (!config.token) {
|
|
886
|
-
console.warn('fetchSanity: The "token" property is missing in the config object.');
|
|
887
|
-
return false;
|
|
888
|
-
}
|
|
889
|
-
if (!config.projectId) {
|
|
890
|
-
console.warn('fetchSanity: The "projectId" property is missing in the config object.');
|
|
891
|
-
return false;
|
|
892
|
-
}
|
|
893
|
-
if (!config.dataset) {
|
|
894
|
-
console.warn('fetchSanity: The "dataset" property is missing in the config object.');
|
|
895
|
-
return false;
|
|
896
|
-
}
|
|
897
|
-
if (!config.version) {
|
|
898
|
-
console.warn('fetchSanity: The "version" property is missing in the config object.');
|
|
899
|
-
return false;
|
|
900
|
-
}
|
|
901
|
-
return true;
|
|
902
|
-
}
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
//Main
|
|
906
|
-
module.exports = {
|
|
907
|
-
initializeSanityService,
|
|
1
|
+
import {
|
|
2
|
+
fetchSongById,
|
|
3
|
+
fetchArtists,
|
|
4
|
+
fetchSongArtistCount,
|
|
5
|
+
fetchRelatedSongs,
|
|
6
|
+
fetchAllSongs,
|
|
7
|
+
fetchSongFilterOptions,
|
|
8
|
+
fetchSongCount,
|
|
9
|
+
fetchWorkouts,
|
|
10
|
+
fetchNewReleases,
|
|
11
|
+
fetchUpcomingEvents,
|
|
12
|
+
fetchByRailContentId,
|
|
13
|
+
fetchByRailContentIds,
|
|
14
|
+
fetchAll,
|
|
15
|
+
fetchAllFilterOptions,
|
|
16
|
+
fetchMethodNextLesson,
|
|
17
|
+
fetchMethodChildren,
|
|
18
|
+
fetchNextPreviousLesson,
|
|
19
|
+
fetchRelatedLessons,
|
|
20
|
+
fetchPackAll,
|
|
21
|
+
fetchPackChildren,
|
|
22
|
+
fetchLessonContent
|
|
23
|
+
} from './services/sanity.js';
|
|
24
|
+
|
|
25
|
+
import {
|
|
26
|
+
initializeService
|
|
27
|
+
} from './services/config.js'
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
export {
|
|
31
|
+
initializeService,
|
|
908
32
|
fetchSongById,
|
|
909
33
|
fetchArtists,
|
|
910
34
|
fetchSongArtistCount,
|
|
@@ -914,7 +38,6 @@ module.exports = {
|
|
|
914
38
|
fetchSongCount,
|
|
915
39
|
fetchWorkouts,
|
|
916
40
|
fetchNewReleases,
|
|
917
|
-
fetchLiveEvent,
|
|
918
41
|
fetchUpcomingEvents,
|
|
919
42
|
fetchByRailContentId,
|
|
920
43
|
fetchByRailContentIds,
|
|
@@ -927,4 +50,4 @@ module.exports = {
|
|
|
927
50
|
fetchPackAll,
|
|
928
51
|
fetchPackChildren,
|
|
929
52
|
fetchLessonContent
|
|
930
|
-
}
|
|
53
|
+
}
|