musora-content-services 1.0.156 → 1.0.157
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/.github/workflows/node.js.yml +0 -0
- package/CHANGELOG.md +2 -0
- package/README.md +0 -0
- package/babel.config.js +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/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/jest.config.js +0 -0
- package/jsdoc.json +0 -0
- package/link_mcs.sh +0 -0
- package/package.json +1 -1
- package/src/contentMetaData.js +0 -0
- package/src/filterBuilder.js +22 -26
- package/src/index.d.ts +8 -1
- package/src/index.js +8 -1
- package/src/services/config.js +0 -0
- package/src/services/contentLikes.js +0 -0
- package/src/services/contentProgress.js +29 -23
- package/src/services/lastUpdated.js +18 -0
- package/src/services/railcontent.js +13 -23
- package/src/services/sanity.js +558 -555
- package/src/services/userPermissions.js +26 -0
- package/test/contentLikes.test.js +2 -3
- package/test/contentProgress.test.js +7 -7
- package/test/initializeTests.js +23 -0
- package/test/lastUpdated.test.js +22 -0
- package/test/localStorageMock.js +0 -0
- package/test/log.js +0 -0
- package/test/sanityQueryService.test.js +29 -58
- package/test/userPermissions.test.js +19 -0
- package/tools/generate-index.js +0 -0
package/src/services/sanity.js
CHANGED
|
@@ -23,8 +23,9 @@ import {
|
|
|
23
23
|
|
|
24
24
|
import {globalConfig} from "./config";
|
|
25
25
|
|
|
26
|
-
import {
|
|
26
|
+
import {fetchAllCompletedStates, fetchCurrentSongComplete} from './railcontent.js';
|
|
27
27
|
import {arrayToStringRepresentation, FilterBuilder} from "../filterBuilder";
|
|
28
|
+
import {fetchUserPermissions} from "./userPermissions";
|
|
28
29
|
|
|
29
30
|
/**
|
|
30
31
|
* Exported functions that are excluded from index generation.
|
|
@@ -32,21 +33,22 @@ import {arrayToStringRepresentation, FilterBuilder} from "../filterBuilder";
|
|
|
32
33
|
* @type {string[]}
|
|
33
34
|
*/
|
|
34
35
|
const excludeFromGeneratedIndex = [];
|
|
36
|
+
|
|
35
37
|
/**
|
|
36
|
-
* Fetch a song by its document ID from Sanity.
|
|
37
|
-
*
|
|
38
|
-
* @param {string} documentId - The ID of the document to fetch.
|
|
39
|
-
* @returns {Promise<Object|null>} - A promise that resolves to an object containing the song data or null if not found.
|
|
40
|
-
*
|
|
41
|
-
* @example
|
|
42
|
-
* fetchSongById('abc123')
|
|
43
|
-
* .then(song => console.log(song))
|
|
44
|
-
* .catch(error => console.error(error));
|
|
45
|
-
*/
|
|
38
|
+
* Fetch a song by its document ID from Sanity.
|
|
39
|
+
*
|
|
40
|
+
* @param {string} documentId - The ID of the document to fetch.
|
|
41
|
+
* @returns {Promise<Object|null>} - A promise that resolves to an object containing the song data or null if not found.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* fetchSongById('abc123')
|
|
45
|
+
* .then(song => console.log(song))
|
|
46
|
+
* .catch(error => console.error(error));
|
|
47
|
+
*/
|
|
46
48
|
export async function fetchSongById(documentId) {
|
|
47
49
|
const fields = getFieldsForContentType('song');
|
|
48
50
|
const filterParams = {};
|
|
49
|
-
const query = buildQuery(
|
|
51
|
+
const query = await buildQuery(
|
|
50
52
|
`_type == "song" && railcontent_id == ${documentId}`,
|
|
51
53
|
filterParams,
|
|
52
54
|
fields,
|
|
@@ -57,48 +59,48 @@ export async function fetchSongById(documentId) {
|
|
|
57
59
|
}
|
|
58
60
|
|
|
59
61
|
/**
|
|
60
|
-
* Fetch all artists with lessons available for a specific brand.
|
|
61
|
-
*
|
|
62
|
-
* @param {string} brand - The brand for which to fetch artists.
|
|
63
|
-
* @returns {Promise<Object|null>} - A promise that resolves to an array of artist objects or null if not found.
|
|
64
|
-
*
|
|
65
|
-
* @example
|
|
66
|
-
* fetchArtists('drumeo')
|
|
67
|
-
* .then(artists => console.log(artists))
|
|
68
|
-
* .catch(error => console.error(error));
|
|
69
|
-
*/
|
|
62
|
+
* Fetch all artists with lessons available for a specific brand.
|
|
63
|
+
*
|
|
64
|
+
* @param {string} brand - The brand for which to fetch artists.
|
|
65
|
+
* @returns {Promise<Object|null>} - A promise that resolves to an array of artist objects or null if not found.
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* fetchArtists('drumeo')
|
|
69
|
+
* .then(artists => console.log(artists))
|
|
70
|
+
* .catch(error => console.error(error));
|
|
71
|
+
*/
|
|
70
72
|
export async function fetchArtists(brand) {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
+
const filter = await new FilterBuilder(`_type == "song" && brand == "${brand}" && references(^._id)`, {bypassPermissions: true}).buildFilter();
|
|
74
|
+
const query = `
|
|
73
75
|
*[_type == "artist"]{
|
|
74
76
|
name,
|
|
75
77
|
"lessonsCount": count(*[${filter}])
|
|
76
78
|
}[lessonsCount > 0]`;
|
|
77
|
-
|
|
79
|
+
return fetchSanity(query, true, {processNeedAccess: false});
|
|
78
80
|
}
|
|
79
81
|
|
|
80
82
|
/**
|
|
81
|
-
* Fetch current number of artists for songs within a brand.
|
|
82
|
-
* @param {string} brand - The current brand.
|
|
83
|
-
* @returns {Promise<int|null>} - The fetched count of artists.
|
|
84
|
-
*/
|
|
83
|
+
* Fetch current number of artists for songs within a brand.
|
|
84
|
+
* @param {string} brand - The current brand.
|
|
85
|
+
* @returns {Promise<int|null>} - The fetched count of artists.
|
|
86
|
+
*/
|
|
85
87
|
export async function fetchSongArtistCount(brand) {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
+
const query = `count(*[_type == 'artist']{'lessonsCount': count(*[_type == 'song' && brand == '${brand}' && references(^._id)]._id)}[lessonsCount > 0])`;
|
|
89
|
+
return fetchSanity(query, true, {processNeedAccess: false});
|
|
88
90
|
}
|
|
89
91
|
|
|
90
92
|
/**
|
|
91
|
-
* Fetch related songs for a specific brand and song ID.
|
|
92
|
-
*
|
|
93
|
-
* @param {string} brand - The brand for which to fetch related songs.
|
|
94
|
-
* @param {string} songId - The ID of the song to find related songs for.
|
|
95
|
-
* @returns {Promise<Object|null>} - A promise that resolves to an array of related song objects or null if not found.
|
|
96
|
-
*
|
|
97
|
-
* @example
|
|
98
|
-
* fetchRelatedSongs('drumeo', '12345')
|
|
99
|
-
* .then(relatedSongs => console.log(relatedSongs))
|
|
100
|
-
* .catch(error => console.error(error));
|
|
101
|
-
*/
|
|
93
|
+
* Fetch related songs for a specific brand and song ID.
|
|
94
|
+
*
|
|
95
|
+
* @param {string} brand - The brand for which to fetch related songs.
|
|
96
|
+
* @param {string} songId - The ID of the song to find related songs for.
|
|
97
|
+
* @returns {Promise<Object|null>} - A promise that resolves to an array of related song objects or null if not found.
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* fetchRelatedSongs('drumeo', '12345')
|
|
101
|
+
* .then(relatedSongs => console.log(relatedSongs))
|
|
102
|
+
* .catch(error => console.error(error));
|
|
103
|
+
*/
|
|
102
104
|
export async function fetchRelatedSongs(brand, songId) {
|
|
103
105
|
const query = `
|
|
104
106
|
*[_type == "song" && railcontent_id == ${songId}]{
|
|
@@ -190,29 +192,29 @@ export async function fetchRelatedSongs(brand, songId) {
|
|
|
190
192
|
* .catch(error => console.error(error));
|
|
191
193
|
*/
|
|
192
194
|
export async function fetchAllSongs(brand, {
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
195
|
+
page = 1,
|
|
196
|
+
limit = 10,
|
|
197
|
+
searchTerm = "",
|
|
198
|
+
sort = "-published_on",
|
|
199
|
+
includedFields = [],
|
|
200
|
+
groupBy = ""
|
|
199
201
|
}) {
|
|
200
202
|
return fetchAll(brand, 'song', {page, limit, searchTerm, sort, includedFields, groupBy});
|
|
201
203
|
}
|
|
202
204
|
|
|
203
205
|
/**
|
|
204
|
-
* Fetch filter options for a specific brand.
|
|
205
|
-
*
|
|
206
|
-
* @param {string} brand - The brand for which to fetch filter options.
|
|
207
|
-
* @returns {Promise<Object|null>} - A promise that resolves to an object containing filter options or null if not found.
|
|
208
|
-
*
|
|
209
|
-
* @example
|
|
210
|
-
* fetchSongFilterOptions('drumeo')
|
|
211
|
-
* .then(options => console.log(options))
|
|
212
|
-
* .catch(error => console.error(error));
|
|
213
|
-
*/
|
|
206
|
+
* Fetch filter options for a specific brand.
|
|
207
|
+
*
|
|
208
|
+
* @param {string} brand - The brand for which to fetch filter options.
|
|
209
|
+
* @returns {Promise<Object|null>} - A promise that resolves to an object containing filter options or null if not found.
|
|
210
|
+
*
|
|
211
|
+
* @example
|
|
212
|
+
* fetchSongFilterOptions('drumeo')
|
|
213
|
+
* .then(options => console.log(options))
|
|
214
|
+
* .catch(error => console.error(error));
|
|
215
|
+
*/
|
|
214
216
|
export async function fetchSongFilterOptions(brand) {
|
|
215
|
-
|
|
217
|
+
const query = `
|
|
216
218
|
{
|
|
217
219
|
"difficulty": [
|
|
218
220
|
{"type": "Introductory", "count": count(*[_type == 'song' && brand == '${brand}' && difficulty_string == "Introductory"]._id)},
|
|
@@ -231,17 +233,17 @@ export async function fetchSongFilterOptions(brand) {
|
|
|
231
233
|
]
|
|
232
234
|
}`;
|
|
233
235
|
|
|
234
|
-
|
|
236
|
+
return fetchSanity(query, true);
|
|
235
237
|
}
|
|
236
238
|
|
|
237
239
|
/**
|
|
238
|
-
* Fetch the total count of songs for a specific brand.
|
|
239
|
-
* @param {string} brand - The brand for which to fetch the song count.
|
|
240
|
-
* @returns {Promise<number|null>} - The total count of songs or null if an error occurs.
|
|
241
|
-
*/
|
|
240
|
+
* Fetch the total count of songs for a specific brand.
|
|
241
|
+
* @param {string} brand - The brand for which to fetch the song count.
|
|
242
|
+
* @returns {Promise<number|null>} - The total count of songs or null if an error occurs.
|
|
243
|
+
*/
|
|
242
244
|
export async function fetchSongCount(brand) {
|
|
243
|
-
|
|
244
|
-
|
|
245
|
+
const query = `count(*[_type == 'song' && brand == "${brand}"])`;
|
|
246
|
+
return fetchSanity(query, true, {processNeedAccess: false});
|
|
245
247
|
}
|
|
246
248
|
|
|
247
249
|
/**
|
|
@@ -256,29 +258,29 @@ export async function fetchSongCount(brand) {
|
|
|
256
258
|
* @example
|
|
257
259
|
* fetchWorkouts('drumeo')
|
|
258
260
|
* .then(workouts => console.log(workouts))
|
|
259
|
-
* .catch(error => console.error(error));
|
|
261
|
+
* .catch(error => console.error(error));
|
|
260
262
|
*/
|
|
261
263
|
export async function fetchWorkouts(brand) {
|
|
262
|
-
|
|
263
|
-
|
|
264
|
+
const fields = getFieldsForContentType('workout');
|
|
265
|
+
const query = `*[_type == 'workout' && brand == '${brand}'] [0...5] {
|
|
264
266
|
${fields.toString()}
|
|
265
267
|
} | order(published_on desc)[0...5]`
|
|
266
|
-
|
|
268
|
+
return fetchSanity(query, true);
|
|
267
269
|
}
|
|
268
270
|
|
|
269
271
|
/**
|
|
270
|
-
* Fetch the latest new releases for a specific brand.
|
|
271
|
-
* @param {string} brand - The brand for which to fetch new releases.
|
|
272
|
-
* @returns {Promise<Object|null>} - The fetched new releases data or null if not found.
|
|
273
|
-
*/
|
|
274
|
-
export async function fetchNewReleases(brand, {
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
272
|
+
* Fetch the latest new releases for a specific brand.
|
|
273
|
+
* @param {string} brand - The brand for which to fetch new releases.
|
|
274
|
+
* @returns {Promise<Object|null>} - The fetched new releases data or null if not found.
|
|
275
|
+
*/
|
|
276
|
+
export async function fetchNewReleases(brand, {page = 1, limit = 20, sort = "-published_on"} = {}) {
|
|
277
|
+
const newTypes = getNewReleasesTypes(brand);
|
|
278
|
+
const typesString = arrayToStringRepresentation(newTypes);
|
|
279
|
+
const start = (page - 1) * limit;
|
|
280
|
+
const end = start + limit;
|
|
281
|
+
const sortOrder = getSortOrder(sort);
|
|
282
|
+
const filter = `_type in ${typesString} && brand == '${brand}'`;
|
|
283
|
+
const fields = `
|
|
282
284
|
"id": railcontent_id,
|
|
283
285
|
title,
|
|
284
286
|
"image": thumbnail.asset->url,
|
|
@@ -292,41 +294,41 @@ export async function fetchNewReleases(brand, { page = 1, limit = 20, sort="-pub
|
|
|
292
294
|
web_url_path,
|
|
293
295
|
"permission_id": permission[]->railcontent_id,
|
|
294
296
|
`;
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
297
|
+
const filterParams = {};
|
|
298
|
+
const query = await buildQuery(
|
|
299
|
+
filter,
|
|
300
|
+
filterParams,
|
|
301
|
+
fields,
|
|
302
|
+
{
|
|
303
|
+
sortOrder: sortOrder,
|
|
304
|
+
start,
|
|
305
|
+
end: end,
|
|
306
|
+
});
|
|
307
|
+
return fetchSanity(query, true);
|
|
306
308
|
}
|
|
307
309
|
|
|
308
310
|
|
|
309
311
|
/**
|
|
310
|
-
* Fetch upcoming events for a specific brand.
|
|
311
|
-
*
|
|
312
|
-
* @param {string} brand - The brand for which to fetch upcoming events.
|
|
313
|
-
* @returns {Promise<Object|null>} - A promise that resolves to an array of upcoming event objects or null if not found.
|
|
314
|
-
*
|
|
315
|
-
* @example
|
|
316
|
-
* fetchUpcomingEvents('drumeo', {
|
|
317
|
-
* page: 2,
|
|
318
|
-
* limit: 20,
|
|
319
|
-
* })
|
|
320
|
-
* .then(events => console.log(events))
|
|
321
|
-
* .catch(error => console.error(error));
|
|
322
|
-
*/
|
|
323
|
-
export async function fetchUpcomingEvents(brand, {
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
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
|
+
* page: 2,
|
|
320
|
+
* limit: 20,
|
|
321
|
+
* })
|
|
322
|
+
* .then(events => console.log(events))
|
|
323
|
+
* .catch(error => console.error(error));
|
|
324
|
+
*/
|
|
325
|
+
export async function fetchUpcomingEvents(brand, {page = 1, limit = 10} = {}) {
|
|
326
|
+
const liveTypes = getUpcomingEventsTypes(brand);
|
|
327
|
+
const typesString = arrayToStringRepresentation(liveTypes);
|
|
328
|
+
const now = getSanityDate(new Date());
|
|
329
|
+
const start = (page - 1) * limit;
|
|
330
|
+
const end = start + limit;
|
|
331
|
+
const fields = `
|
|
330
332
|
"id": railcontent_id,
|
|
331
333
|
title,
|
|
332
334
|
"image": thumbnail.asset->url,
|
|
@@ -339,16 +341,16 @@ export async function fetchUpcomingEvents(brand, { page = 1, limit = 10 } = {})
|
|
|
339
341
|
"type": _type,
|
|
340
342
|
web_url_path,
|
|
341
343
|
"permission_id": permission[]->railcontent_id,`;
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
344
|
+
const query = buildRawQuery(
|
|
345
|
+
`_type in ${typesString} && brand == '${brand}' && published_on > '${now}' && status == 'scheduled'`,
|
|
346
|
+
fields,
|
|
347
|
+
{
|
|
348
|
+
sortOrder: 'published_on asc',
|
|
349
|
+
start: start,
|
|
350
|
+
end: end,
|
|
351
|
+
},
|
|
352
|
+
);
|
|
353
|
+
return fetchSanity(query, true);
|
|
352
354
|
}
|
|
353
355
|
|
|
354
356
|
/**
|
|
@@ -365,16 +367,16 @@ export async function fetchUpcomingEvents(brand, { page = 1, limit = 10 } = {})
|
|
|
365
367
|
* .then(content => console.log(content))
|
|
366
368
|
* .catch(error => console.error(error));
|
|
367
369
|
*/
|
|
368
|
-
export async function fetchScheduledReleases(brand, {
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
370
|
+
export async function fetchScheduledReleases(brand, {page = 1, limit = 10}) {
|
|
371
|
+
const upcomingTypes = getUpcomingEventsTypes(brand);
|
|
372
|
+
const newTypes = getNewReleasesTypes(brand);
|
|
373
|
+
|
|
374
|
+
const scheduledTypes = merge(upcomingTypes, newTypes)
|
|
375
|
+
const typesString = arrayJoinWithQuotes(scheduledTypes);
|
|
376
|
+
const now = getSanityDate(new Date());
|
|
377
|
+
const start = (page - 1) * limit;
|
|
378
|
+
const end = start + limit;
|
|
379
|
+
const query = `*[_type in [${typesString}] && brand == '${brand}' && status in ['published','scheduled'] && published_on > '${now}']{
|
|
378
380
|
"id": railcontent_id,
|
|
379
381
|
title,
|
|
380
382
|
"image": thumbnail.asset->url,
|
|
@@ -388,21 +390,21 @@ export async function fetchScheduledReleases(brand, { page = 1, limit = 10 }) {
|
|
|
388
390
|
web_url_path,
|
|
389
391
|
"permission_id": permission[]->railcontent_id,
|
|
390
392
|
} | order(published_on asc)[${start}...${end}]`;
|
|
391
|
-
|
|
393
|
+
return fetchSanity(query, true);
|
|
392
394
|
}
|
|
393
395
|
|
|
394
396
|
/**
|
|
395
|
-
* Fetch content by a specific Railcontent ID.
|
|
396
|
-
*
|
|
397
|
-
* @param {string} id - The Railcontent ID of the content to fetch.
|
|
398
|
-
* @param {string} contentType - The document type of content to fetch
|
|
399
|
-
* @returns {Promise<Object|null>} - A promise that resolves to the content object or null if not found.
|
|
400
|
-
*
|
|
401
|
-
* @example
|
|
402
|
-
* fetchByRailContentId('abc123')
|
|
403
|
-
* .then(content => console.log(content))
|
|
404
|
-
* .catch(error => console.error(error));
|
|
405
|
-
*/
|
|
397
|
+
* Fetch content by a specific Railcontent ID.
|
|
398
|
+
*
|
|
399
|
+
* @param {string} id - The Railcontent ID of the content to fetch.
|
|
400
|
+
* @param {string} contentType - The document type of content to fetch
|
|
401
|
+
* @returns {Promise<Object|null>} - A promise that resolves to the content object or null if not found.
|
|
402
|
+
*
|
|
403
|
+
* @example
|
|
404
|
+
* fetchByRailContentId('abc123')
|
|
405
|
+
* .then(content => console.log(content))
|
|
406
|
+
* .catch(error => console.error(error));
|
|
407
|
+
*/
|
|
406
408
|
export async function fetchByRailContentId(id, contentType) {
|
|
407
409
|
|
|
408
410
|
const query = buildRawQuery(
|
|
@@ -417,24 +419,24 @@ export async function fetchByRailContentId(id, contentType) {
|
|
|
417
419
|
}
|
|
418
420
|
|
|
419
421
|
/**
|
|
420
|
-
* Fetch content by an array of Railcontent IDs.
|
|
421
|
-
*
|
|
422
|
-
* @param {Array<string>} ids - The array of Railcontent IDs of the content to fetch.
|
|
423
|
-
* @param {string} [contentType] - The content type the IDs to add needed fields to the response.
|
|
424
|
-
* @returns {Promise<Array<Object>|null>} - A promise that resolves to an array of content objects or null if not found.
|
|
425
|
-
*
|
|
426
|
-
* @example
|
|
427
|
-
* fetchByRailContentIds(['abc123', 'def456', 'ghi789'])
|
|
428
|
-
* .then(contents => console.log(contents))
|
|
429
|
-
* .catch(error => console.error(error));
|
|
430
|
-
*/
|
|
422
|
+
* Fetch content by an array of Railcontent IDs.
|
|
423
|
+
*
|
|
424
|
+
* @param {Array<string>} ids - The array of Railcontent IDs of the content to fetch.
|
|
425
|
+
* @param {string} [contentType] - The content type the IDs to add needed fields to the response.
|
|
426
|
+
* @returns {Promise<Array<Object>|null>} - A promise that resolves to an array of content objects or null if not found.
|
|
427
|
+
*
|
|
428
|
+
* @example
|
|
429
|
+
* fetchByRailContentIds(['abc123', 'def456', 'ghi789'])
|
|
430
|
+
* .then(contents => console.log(contents))
|
|
431
|
+
* .catch(error => console.error(error));
|
|
432
|
+
*/
|
|
431
433
|
export async function fetchByRailContentIds(ids, contentType = undefined) {
|
|
432
|
-
|
|
434
|
+
const idsString = ids.join(',');
|
|
433
435
|
|
|
434
|
-
|
|
436
|
+
const query = `*[railcontent_id in [${idsString}]]{
|
|
435
437
|
${getFieldsForContentType(contentType)}
|
|
436
438
|
}`
|
|
437
|
-
|
|
439
|
+
return fetchSanity(query, true);
|
|
438
440
|
}
|
|
439
441
|
|
|
440
442
|
/**
|
|
@@ -469,15 +471,15 @@ export async function fetchByRailContentIds(ids, contentType = undefined) {
|
|
|
469
471
|
* .catch(error => console.error(error));
|
|
470
472
|
*/
|
|
471
473
|
export async function fetchAll(brand, type, {
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
474
|
+
page = 1,
|
|
475
|
+
limit = 10,
|
|
476
|
+
searchTerm = "",
|
|
477
|
+
sort = "-published_on",
|
|
478
|
+
includedFields = [],
|
|
479
|
+
groupBy = "",
|
|
480
|
+
progressIds = undefined,
|
|
481
|
+
useDefaultFields = true,
|
|
482
|
+
customFields = [],
|
|
481
483
|
} = {}) {
|
|
482
484
|
let config = contentTypeConfig[type] ?? {};
|
|
483
485
|
let additionalFields = config?.fields ?? [];
|
|
@@ -492,8 +494,8 @@ export async function fetchAll(brand, type, {
|
|
|
492
494
|
// Construct the search filter
|
|
493
495
|
const searchFilter = searchTerm
|
|
494
496
|
? groupBy !== "" ?
|
|
495
|
-
|
|
496
|
-
|
|
497
|
+
`&& (^.name match "${searchTerm}*" || title match "${searchTerm}*")`
|
|
498
|
+
: `&& (artist->name match "${searchTerm}*" || instructor[]->name match "${searchTerm}*" || title match "${searchTerm}*" || name match "${searchTerm}*")`
|
|
497
499
|
: "";
|
|
498
500
|
|
|
499
501
|
// Construct the included fields filter, replacing 'difficulty' with 'difficulty_string'
|
|
@@ -508,7 +510,7 @@ export async function fetchAll(brand, type, {
|
|
|
508
510
|
// Determine the sort order
|
|
509
511
|
const sortOrder = getSortOrder(sort);
|
|
510
512
|
|
|
511
|
-
let fields = useDefaultFields ?
|
|
513
|
+
let fields = useDefaultFields ? customFields.concat(DEFAULT_FIELDS, additionalFields) : customFields;
|
|
512
514
|
let fieldsString = fields.join(',');
|
|
513
515
|
|
|
514
516
|
// Determine the group by clause
|
|
@@ -532,7 +534,7 @@ export async function fetchAll(brand, type, {
|
|
|
532
534
|
`;
|
|
533
535
|
filter = `_type == '${groupBy}' && count(*[brand == '${brand}' && ^._id == ${groupBy}._ref ${typeFilter} ${searchFilter} ${includedFieldsFilter} ${progressFilter}]._id) > 0`;
|
|
534
536
|
} else if (groupBy !== "") {
|
|
535
|
-
const webUrlPath = (groupBy == 'genre')?'/genres':'';
|
|
537
|
+
const webUrlPath = (groupBy == 'genre') ? '/genres' : '';
|
|
536
538
|
const lessonsFilter = `brand == '${brand}' && ^._id in ${groupBy}[]._ref ${typeFilter} ${searchFilter} ${includedFieldsFilter} ${progressFilter}`;
|
|
537
539
|
entityFieldsString = `
|
|
538
540
|
'id': railcontent_id,
|
|
@@ -562,8 +564,7 @@ export async function fetchAll(brand, type, {
|
|
|
562
564
|
return fetchSanity(query, true);
|
|
563
565
|
}
|
|
564
566
|
|
|
565
|
-
export function getSortOrder(sort= '-published_on', groupBy)
|
|
566
|
-
{
|
|
567
|
+
export function getSortOrder(sort = '-published_on', groupBy) {
|
|
567
568
|
// Determine the sort order
|
|
568
569
|
let sortOrder = '';
|
|
569
570
|
const isDesc = sort.startsWith('-');
|
|
@@ -586,69 +587,69 @@ export function getSortOrder(sort= '-published_on', groupBy)
|
|
|
586
587
|
}
|
|
587
588
|
|
|
588
589
|
/**
|
|
589
|
-
* Fetches all available filter options based on brand, filters, and various optional criteria.
|
|
590
|
-
*
|
|
591
|
-
* This function constructs a query to retrieve the total number of results and filter options such as difficulty, instrument type, and genre.
|
|
592
|
-
* The filter options are dynamically generated based on the provided filters, style, artist, and content type.
|
|
593
|
-
* If a coachId is provided, the content type must be 'coach-lessons'.
|
|
594
|
-
*
|
|
595
|
-
* @param {string} brand - Brand to filter.
|
|
596
|
-
* @param {string[]} filters - Key-value pairs to filter the query.
|
|
597
|
-
* @param {string} [style] - Optional style/genre filter.
|
|
598
|
-
* @param {string} [artist] - Optional artist name filter.
|
|
599
|
-
* @param {string} contentType - Content type (e.g., 'song', 'lesson').
|
|
600
|
-
* @param {string} [term] - Optional search term for title, album, artist, or genre.
|
|
601
|
-
* @param {Array<string>} [progressIds] - Optional array of progress IDs to filter by.
|
|
602
|
-
* @param {string} [coachId] - Optional coach ID (only valid if contentType is 'coach-lessons').
|
|
603
|
-
* @param {boolean} [includeTabs=false] - Whether to include tabs in the returned metadata.
|
|
604
|
-
* @returns {Promise<Object>} - The filter options and metadata.
|
|
605
|
-
* @throws {Error} If coachId is provided but contentType isn't 'coach-lessons'.
|
|
606
|
-
*
|
|
607
|
-
* @example
|
|
608
|
-
* // Fetch filter options for 'song' content type:
|
|
609
|
-
* fetchAllFilterOptions('myBrand', [], 'Rock', 'John Doe', 'song', 'Love')
|
|
610
|
-
* .then(options => console.log(options))
|
|
611
|
-
* .catch(error => console.error(error));
|
|
612
|
-
*
|
|
613
|
-
* @example
|
|
614
|
-
* // Fetch filter options for a coach's lessons with coachId:
|
|
615
|
-
* fetchAllFilterOptions('myBrand', [], 'Rock', 'John Doe', 'coach-lessons', 'Love', undefined, '123')
|
|
616
|
-
* .then(options => console.log(options))
|
|
617
|
-
* .catch(error => console.error(error));
|
|
618
|
-
*/
|
|
590
|
+
* Fetches all available filter options based on brand, filters, and various optional criteria.
|
|
591
|
+
*
|
|
592
|
+
* This function constructs a query to retrieve the total number of results and filter options such as difficulty, instrument type, and genre.
|
|
593
|
+
* The filter options are dynamically generated based on the provided filters, style, artist, and content type.
|
|
594
|
+
* If a coachId is provided, the content type must be 'coach-lessons'.
|
|
595
|
+
*
|
|
596
|
+
* @param {string} brand - Brand to filter.
|
|
597
|
+
* @param {string[]} filters - Key-value pairs to filter the query.
|
|
598
|
+
* @param {string} [style] - Optional style/genre filter.
|
|
599
|
+
* @param {string} [artist] - Optional artist name filter.
|
|
600
|
+
* @param {string} contentType - Content type (e.g., 'song', 'lesson').
|
|
601
|
+
* @param {string} [term] - Optional search term for title, album, artist, or genre.
|
|
602
|
+
* @param {Array<string>} [progressIds] - Optional array of progress IDs to filter by.
|
|
603
|
+
* @param {string} [coachId] - Optional coach ID (only valid if contentType is 'coach-lessons').
|
|
604
|
+
* @param {boolean} [includeTabs=false] - Whether to include tabs in the returned metadata.
|
|
605
|
+
* @returns {Promise<Object>} - The filter options and metadata.
|
|
606
|
+
* @throws {Error} If coachId is provided but contentType isn't 'coach-lessons'.
|
|
607
|
+
*
|
|
608
|
+
* @example
|
|
609
|
+
* // Fetch filter options for 'song' content type:
|
|
610
|
+
* fetchAllFilterOptions('myBrand', [], 'Rock', 'John Doe', 'song', 'Love')
|
|
611
|
+
* .then(options => console.log(options))
|
|
612
|
+
* .catch(error => console.error(error));
|
|
613
|
+
*
|
|
614
|
+
* @example
|
|
615
|
+
* // Fetch filter options for a coach's lessons with coachId:
|
|
616
|
+
* fetchAllFilterOptions('myBrand', [], 'Rock', 'John Doe', 'coach-lessons', 'Love', undefined, '123')
|
|
617
|
+
* .then(options => console.log(options))
|
|
618
|
+
* .catch(error => console.error(error));
|
|
619
|
+
*/
|
|
619
620
|
export async function fetchAllFilterOptions(
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
621
|
+
brand,
|
|
622
|
+
filters = [],
|
|
623
|
+
style,
|
|
624
|
+
artist,
|
|
625
|
+
contentType,
|
|
626
|
+
term,
|
|
627
|
+
progressIds,
|
|
628
|
+
coachId,
|
|
629
|
+
includeTabs = false,
|
|
629
630
|
) {
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
631
|
+
if (coachId && contentType !== 'coach-lessons') {
|
|
632
|
+
throw new Error(`Invalid contentType: '${contentType}' for coachId. It must be 'coach-lessons'.`);
|
|
633
|
+
}
|
|
633
634
|
|
|
634
|
-
|
|
635
|
-
|
|
635
|
+
const includedFieldsFilter = filters?.length ? filtersToGroq(filters) : undefined;
|
|
636
|
+
const progressFilter = progressIds ? `&& railcontent_id in [${progressIds.join(',')}]` : "";
|
|
636
637
|
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
638
|
+
const constructCommonFilter = (excludeFilter) => {
|
|
639
|
+
const filterWithoutOption = excludeFilter ? filtersToGroq(filters, excludeFilter) : includedFieldsFilter;
|
|
640
|
+
return coachId
|
|
641
|
+
? `brand == '${brand}' && references(*[_type=='instructor' && railcontent_id == ${coachId}]._id) ${filterWithoutOption || ''}`
|
|
642
|
+
: `_type == '${contentType}' && brand == "${brand}"${style && excludeFilter !== "style" ? ` && '${style}' in genre[]->name` : ''}${artist && excludeFilter !== "artist" ? ` && artist->name == '${artist}'` : ''} ${progressFilter} ${filterWithoutOption || ''}`;
|
|
643
|
+
};
|
|
643
644
|
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
645
|
+
const metaData = processMetadata(brand, contentType, true);
|
|
646
|
+
const allowableFilters = metaData?.allowableFilters || [];
|
|
647
|
+
const tabs = metaData?.tabs || [];
|
|
648
|
+
const catalogName = metaData?.shortname || metaData?.name;
|
|
648
649
|
|
|
649
|
-
|
|
650
|
+
const dynamicFilterOptions = allowableFilters.map(filter => getFilterOptions(filter, constructCommonFilter(filter), contentType, brand)).join(' ');
|
|
650
651
|
|
|
651
|
-
|
|
652
|
+
const query = `
|
|
652
653
|
{
|
|
653
654
|
"meta": {
|
|
654
655
|
"totalResults": count(*[${constructCommonFilter()}
|
|
@@ -659,28 +660,28 @@ export async function fetchAllFilterOptions(
|
|
|
659
660
|
}
|
|
660
661
|
}`;
|
|
661
662
|
|
|
662
|
-
|
|
663
|
+
const results = await fetchSanity(query, true, {processNeedAccess: false});
|
|
663
664
|
|
|
664
|
-
|
|
665
|
+
return includeTabs ? {...results, tabs, catalogName} : results;
|
|
665
666
|
}
|
|
666
667
|
|
|
667
668
|
|
|
668
669
|
/**
|
|
669
|
-
* Fetch children content by Railcontent ID.
|
|
670
|
-
* @param {string} railcontentId - The Railcontent ID of the parent content.
|
|
671
|
-
* @param {string} [contentType] - The content type the IDs to add needed fields to the response.
|
|
672
|
-
* @returns {Promise<Array<Object>|null>} - The fetched children content data or [] if not found.
|
|
673
|
-
*/
|
|
670
|
+
* Fetch children content by Railcontent ID.
|
|
671
|
+
* @param {string} railcontentId - The Railcontent ID of the parent content.
|
|
672
|
+
* @param {string} [contentType] - The content type the IDs to add needed fields to the response.
|
|
673
|
+
* @returns {Promise<Array<Object>|null>} - The fetched children content data or [] if not found.
|
|
674
|
+
*/
|
|
674
675
|
export async function fetchChildren(railcontentId, contentType) {
|
|
675
|
-
|
|
676
|
+
const query = `*[railcontent_id == ${railcontentId}]{
|
|
676
677
|
title,
|
|
677
678
|
|
|
678
679
|
'children': child[]->{
|
|
679
680
|
${getFieldsForContentType(contentType)}
|
|
680
681
|
},
|
|
681
682
|
}[0..1]`;
|
|
682
|
-
|
|
683
|
-
|
|
683
|
+
let parent = await fetchSanity(query, false);
|
|
684
|
+
return parent['children'] ?? [];
|
|
684
685
|
}
|
|
685
686
|
|
|
686
687
|
/**
|
|
@@ -701,44 +702,44 @@ export async function fetchParentByRailContentId(railcontentId) {
|
|
|
701
702
|
}
|
|
702
703
|
|
|
703
704
|
/**
|
|
704
|
-
* Fetch the Methods (learning-paths) for a specific brand.
|
|
705
|
-
* @param {string} brand - The brand for which to fetch methods.
|
|
706
|
-
* @returns {Promise<Object|null>} - The fetched methods data or null if not found.
|
|
707
|
-
*/
|
|
705
|
+
* Fetch the Methods (learning-paths) for a specific brand.
|
|
706
|
+
* @param {string} brand - The brand for which to fetch methods.
|
|
707
|
+
* @returns {Promise<Object|null>} - The fetched methods data or null if not found.
|
|
708
|
+
*/
|
|
708
709
|
export async function fetchMethods(brand) {
|
|
709
710
|
const query = `*[_type == 'learning-path' && brand == '${brand}'] {
|
|
710
|
-
${
|
|
711
|
+
${getFieldsForContentType()}
|
|
711
712
|
} | order(published_on asc)`
|
|
712
|
-
|
|
713
|
+
return fetchSanity(query, true);
|
|
713
714
|
}
|
|
714
715
|
|
|
715
716
|
/**
|
|
716
|
-
* Fetch the Foundations 2019.
|
|
717
|
-
* @param {string} slug - The slug of the method.
|
|
718
|
-
* @returns {Promise<Object|null>} - The fetched foundation data or null if not found.
|
|
719
|
-
*/
|
|
717
|
+
* Fetch the Foundations 2019.
|
|
718
|
+
* @param {string} slug - The slug of the method.
|
|
719
|
+
* @returns {Promise<Object|null>} - The fetched foundation data or null if not found.
|
|
720
|
+
*/
|
|
720
721
|
export async function fetchFoundation(slug) {
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
return fetchSanity(query, false);
|
|
722
|
+
const filterParams = {};
|
|
723
|
+
const query = await buildQuery(
|
|
724
|
+
`_type == 'foundation' && slug.current == "${slug}"`,
|
|
725
|
+
filterParams,
|
|
726
|
+
getFieldsForContentType('foundation'),
|
|
727
|
+
{
|
|
728
|
+
sortOrder: 'published_on asc',
|
|
729
|
+
isSingle: true,
|
|
730
|
+
}
|
|
731
|
+
);
|
|
732
|
+
return fetchSanity(query, false);
|
|
732
733
|
}
|
|
733
734
|
|
|
734
735
|
/**
|
|
735
|
-
* Fetch the Method (learning-paths) for a specific brand.
|
|
736
|
-
* @param {string} brand - The brand for which to fetch methods.
|
|
737
|
-
* @param {string} slug - The slug of the method.
|
|
738
|
-
* @returns {Promise<Object|null>} - The fetched methods data or null if not found.
|
|
739
|
-
*/
|
|
736
|
+
* Fetch the Method (learning-paths) for a specific brand.
|
|
737
|
+
* @param {string} brand - The brand for which to fetch methods.
|
|
738
|
+
* @param {string} slug - The slug of the method.
|
|
739
|
+
* @returns {Promise<Object|null>} - The fetched methods data or null if not found.
|
|
740
|
+
*/
|
|
740
741
|
export async function fetchMethod(brand, slug) {
|
|
741
|
-
|
|
742
|
+
const query = `*[_type == 'learning-path' && brand == "${brand}" && slug.current == "${slug}"] {
|
|
742
743
|
"description": ${descriptionField},
|
|
743
744
|
"instructors":instructor[]->name,
|
|
744
745
|
published_on,
|
|
@@ -768,16 +769,16 @@ export async function fetchMethod(brand, slug) {
|
|
|
768
769
|
xp,
|
|
769
770
|
}
|
|
770
771
|
} | order(published_on asc)`
|
|
771
|
-
return fetchSanity(query, false);
|
|
772
|
+
return fetchSanity(query, false);
|
|
772
773
|
}
|
|
773
774
|
|
|
774
775
|
/**
|
|
775
|
-
* Fetch the child courses for a specific method by Railcontent ID.
|
|
776
|
-
* @param {string} railcontentId - The Railcontent ID of the current lesson.
|
|
777
|
-
* @returns {Promise<Object|null>} - The fetched next lesson data or null if not found.
|
|
778
|
-
*/
|
|
776
|
+
* Fetch the child courses for a specific method by Railcontent ID.
|
|
777
|
+
* @param {string} railcontentId - The Railcontent ID of the current lesson.
|
|
778
|
+
* @returns {Promise<Object|null>} - The fetched next lesson data or null if not found.
|
|
779
|
+
*/
|
|
779
780
|
export async function fetchMethodChildren(railcontentId) {
|
|
780
|
-
|
|
781
|
+
const query = `*[railcontent_id == ${railcontentId}]{
|
|
781
782
|
child_count,
|
|
782
783
|
"id": railcontent_id,
|
|
783
784
|
"description": ${descriptionField},
|
|
@@ -788,20 +789,20 @@ export async function fetchMethodChildren(railcontentId) {
|
|
|
788
789
|
${getFieldsForContentType('method')}
|
|
789
790
|
},
|
|
790
791
|
}[0..1]`;
|
|
791
|
-
|
|
792
|
+
return fetchSanity(query, true);
|
|
792
793
|
}
|
|
793
794
|
|
|
794
795
|
/**
|
|
795
|
-
* Fetch the next lesson for a specific method by Railcontent ID.
|
|
796
|
-
* @param {string} railcontentId - The Railcontent ID of the current lesson.
|
|
796
|
+
* Fetch the next lesson for a specific method by Railcontent ID.
|
|
797
|
+
* @param {string} railcontentId - The Railcontent ID of the current lesson.
|
|
797
798
|
* @param {string} methodId - The RailcontentID of the method
|
|
798
|
-
* @returns {Promise<Object|null>} - The fetched next lesson data or null if not found.
|
|
799
|
-
*/
|
|
799
|
+
* @returns {Promise<Object|null>} - The fetched next lesson data or null if not found.
|
|
800
|
+
*/
|
|
800
801
|
export async function fetchMethodNextLesson(railcontentId, methodId) {
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
802
|
+
const sortedChildren = await fetchMethodChildrenIds(methodId);
|
|
803
|
+
const index = sortedChildren.indexOf(railcontentId);
|
|
804
|
+
const childIndex = sortedChildren[index + 1];
|
|
805
|
+
return childIndex ? await fetchByRailContentId(childIndex) : null;
|
|
805
806
|
}
|
|
806
807
|
|
|
807
808
|
/**
|
|
@@ -818,18 +819,22 @@ export async function fetchMethodPreviousNextLesson(railcontentId, methodId) {
|
|
|
818
819
|
const sortedChildren = await fetchMethodChildrenIds(methodId);
|
|
819
820
|
const index = sortedChildren.indexOf(Number(railcontentId));
|
|
820
821
|
let nextId = sortedChildren[index + 1];
|
|
821
|
-
let previousId = sortedChildren[index
|
|
822
|
+
let previousId = sortedChildren[index - 1];
|
|
822
823
|
let nextPrev = await fetchByRailContentIds([nextId, previousId]);
|
|
823
|
-
const nextLesson = nextPrev.find((elem) => {
|
|
824
|
-
|
|
824
|
+
const nextLesson = nextPrev.find((elem) => {
|
|
825
|
+
return elem['id'] === nextId
|
|
826
|
+
});
|
|
827
|
+
const prevLesson = nextPrev.find((elem) => {
|
|
828
|
+
return elem['id'] === previousId
|
|
829
|
+
});
|
|
825
830
|
return {nextLesson, prevLesson};
|
|
826
831
|
}
|
|
827
832
|
|
|
828
833
|
/**
|
|
829
|
-
* Fetch all children of a specific method by Railcontent ID.
|
|
830
|
-
* @param {string} railcontentId - The Railcontent ID of the method.
|
|
831
|
-
* @returns {Promise<Array<Object>|null>} - The fetched children data or null if not found.
|
|
832
|
-
*/
|
|
834
|
+
* Fetch all children of a specific method by Railcontent ID.
|
|
835
|
+
* @param {string} railcontentId - The Railcontent ID of the method.
|
|
836
|
+
* @returns {Promise<Array<Object>|null>} - The fetched children data or null if not found.
|
|
837
|
+
*/
|
|
833
838
|
export async function fetchMethodChildrenIds(railcontentId) {
|
|
834
839
|
const query = `*[ railcontent_id == ${railcontentId}]{
|
|
835
840
|
'children': child[]-> {
|
|
@@ -849,25 +854,24 @@ export async function fetchMethodChildrenIds(railcontentId) {
|
|
|
849
854
|
return getChildrenToDepth(allChildren, 4);
|
|
850
855
|
}
|
|
851
856
|
|
|
852
|
-
function getChildrenToDepth(parent, depth = 1)
|
|
853
|
-
{
|
|
857
|
+
function getChildrenToDepth(parent, depth = 1) {
|
|
854
858
|
let allChildrenIds = [];
|
|
855
859
|
if (parent && parent['children'] && depth > 0) {
|
|
856
860
|
parent['children'].forEach((child) => {
|
|
857
|
-
if(!child['children']) {
|
|
861
|
+
if (!child['children']) {
|
|
858
862
|
allChildrenIds.push(child['id']);
|
|
859
863
|
}
|
|
860
|
-
allChildrenIds = allChildrenIds.concat(getChildrenToDepth(child, depth-1));
|
|
864
|
+
allChildrenIds = allChildrenIds.concat(getChildrenToDepth(child, depth - 1));
|
|
861
865
|
})
|
|
862
866
|
}
|
|
863
867
|
return allChildrenIds;
|
|
864
868
|
}
|
|
865
869
|
|
|
866
870
|
/**
|
|
867
|
-
* Fetch the next and previous lessons for a specific lesson by Railcontent ID.
|
|
868
|
-
* @param {string} railcontentId - The Railcontent ID of the current lesson.
|
|
869
|
-
* @returns {Promise<Object|null>} - The fetched next and previous lesson data or null if found.
|
|
870
|
-
*/
|
|
871
|
+
* Fetch the next and previous lessons for a specific lesson by Railcontent ID.
|
|
872
|
+
* @param {string} railcontentId - The Railcontent ID of the current lesson.
|
|
873
|
+
* @returns {Promise<Object|null>} - The fetched next and previous lesson data or null if found.
|
|
874
|
+
*/
|
|
871
875
|
export async function fetchNextPreviousLesson(railcontentId) {
|
|
872
876
|
const document = await fetchLessonContent(railcontentId);
|
|
873
877
|
if (document.parent_content_data && document.parent_content_data.length > 0) {
|
|
@@ -950,7 +954,7 @@ export async function fetchLessonContent(railContentId) {
|
|
|
950
954
|
parent_content_data,
|
|
951
955
|
sort,
|
|
952
956
|
xp`;
|
|
953
|
-
const query = buildQuery(
|
|
957
|
+
const query = await buildQuery(
|
|
954
958
|
`railcontent_id == ${railContentId}`,
|
|
955
959
|
filterParams,
|
|
956
960
|
fields,
|
|
@@ -958,15 +962,15 @@ export async function fetchLessonContent(railContentId) {
|
|
|
958
962
|
isSingle: true,
|
|
959
963
|
}
|
|
960
964
|
);
|
|
961
|
-
|
|
965
|
+
return fetchSanity(query, false);
|
|
962
966
|
}
|
|
963
967
|
|
|
964
968
|
/**
|
|
965
|
-
* Fetch related lessons for a specific lesson by RailContent ID and type.
|
|
966
|
-
* @param {string} railContentId - The RailContent ID of the current lesson.
|
|
967
|
-
* @param {string} brand - The current brand.
|
|
968
|
-
* @returns {Promise<Array<Object>|null>} - The fetched related lessons data or null if not found.
|
|
969
|
-
*/
|
|
969
|
+
* Fetch related lessons for a specific lesson by RailContent ID and type.
|
|
970
|
+
* @param {string} railContentId - The RailContent ID of the current lesson.
|
|
971
|
+
* @param {string} brand - The current brand.
|
|
972
|
+
* @returns {Promise<Array<Object>|null>} - The fetched related lessons data or null if not found.
|
|
973
|
+
*/
|
|
970
974
|
export async function fetchRelatedLessons(railContentId, brand) {
|
|
971
975
|
const query = `*[railcontent_id == ${railContentId} && brand == "${brand}" && references(*[_type=='permission']._id)]{
|
|
972
976
|
_type, parent_type, railcontent_id,
|
|
@@ -981,13 +985,13 @@ export async function fetchRelatedLessons(railContentId, brand) {
|
|
|
981
985
|
}
|
|
982
986
|
|
|
983
987
|
/**
|
|
984
|
-
* Fetch related method lessons for a specific lesson by RailContent ID and type.
|
|
985
|
-
* @param {string} railContentId - The RailContent ID of the current lesson.
|
|
986
|
-
* @param {string} brand - The current brand.
|
|
987
|
-
* @returns {Promise<Array<Object>|null>} - The fetched related lessons
|
|
988
|
-
*/
|
|
988
|
+
* Fetch related method lessons for a specific lesson by RailContent ID and type.
|
|
989
|
+
* @param {string} railContentId - The RailContent ID of the current lesson.
|
|
990
|
+
* @param {string} brand - The current brand.
|
|
991
|
+
* @returns {Promise<Array<Object>|null>} - The fetched related lessons
|
|
992
|
+
*/
|
|
989
993
|
export async function fetchRelatedMethodLessons(railContentId, brand) {
|
|
990
|
-
|
|
994
|
+
const query = `*[railcontent_id == ${railContentId} && brand == "${brand}"]{
|
|
991
995
|
"id":_id,
|
|
992
996
|
"related_lessons": *[references(^._id)][0].child[]->{
|
|
993
997
|
"id": railcontent_id,
|
|
@@ -1001,57 +1005,57 @@ export async function fetchRelatedMethodLessons(railContentId, brand) {
|
|
|
1001
1005
|
}
|
|
1002
1006
|
}
|
|
1003
1007
|
}`
|
|
1004
|
-
|
|
1008
|
+
return fetchSanity(query, false);
|
|
1005
1009
|
}
|
|
1006
1010
|
|
|
1007
1011
|
/**
|
|
1008
|
-
* Fetch all packs.
|
|
1009
|
-
* @param {string} brand - The brand for which to fetch packs.
|
|
1010
|
-
* @param {string} [searchTerm=""] - The search term to filter packs.
|
|
1011
|
-
* @param {string} [sort="-published_on"] - The field to sort the packs by.
|
|
1012
|
-
* @param {number} [params.page=1] - The page number for pagination.
|
|
1013
|
-
* @param {number} [params.limit=10] - The number of items per page.
|
|
1014
|
-
* @returns {Promise<Array<Object>|null>} - The fetched pack content data or null if not found.
|
|
1015
|
-
*/
|
|
1012
|
+
* Fetch all packs.
|
|
1013
|
+
* @param {string} brand - The brand for which to fetch packs.
|
|
1014
|
+
* @param {string} [searchTerm=""] - The search term to filter packs.
|
|
1015
|
+
* @param {string} [sort="-published_on"] - The field to sort the packs by.
|
|
1016
|
+
* @param {number} [params.page=1] - The page number for pagination.
|
|
1017
|
+
* @param {number} [params.limit=10] - The number of items per page.
|
|
1018
|
+
* @returns {Promise<Array<Object>|null>} - The fetched pack content data or null if not found.
|
|
1019
|
+
*/
|
|
1016
1020
|
export async function fetchAllPacks(brand, sort = "-published_on", searchTerm = "", page = 1, limit = 10) {
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1021
|
+
const sortOrder = getSortOrder(sort);
|
|
1022
|
+
const filter = `_type == 'pack' && brand == '${brand}' && title match "${searchTerm}*"`
|
|
1023
|
+
const filterParams = {};
|
|
1024
|
+
const fields = getFieldsForContentType('pack');
|
|
1025
|
+
const start = (page - 1) * limit;
|
|
1026
|
+
const end = start + limit;
|
|
1027
|
+
|
|
1028
|
+
const query = await buildQuery(
|
|
1029
|
+
filter,
|
|
1030
|
+
filterParams,
|
|
1031
|
+
getFieldsForContentType('pack'),
|
|
1032
|
+
{
|
|
1033
|
+
logo_image_url: 'logo_image_url.asset->url',
|
|
1034
|
+
sortOrder: sortOrder,
|
|
1035
|
+
start,
|
|
1036
|
+
end
|
|
1037
|
+
}
|
|
1038
|
+
);
|
|
1039
|
+
return fetchSanity(query, true);
|
|
1036
1040
|
}
|
|
1037
1041
|
|
|
1038
1042
|
/**
|
|
1039
|
-
* Fetch all content for a specific pack by Railcontent ID.
|
|
1040
|
-
* @param {string} railcontentId - The Railcontent ID of the pack.
|
|
1041
|
-
* @returns {Promise<Array<Object>|null>} - The fetched pack content data or null if not found.
|
|
1042
|
-
*/
|
|
1043
|
+
* Fetch all content for a specific pack by Railcontent ID.
|
|
1044
|
+
* @param {string} railcontentId - The Railcontent ID of the pack.
|
|
1045
|
+
* @returns {Promise<Array<Object>|null>} - The fetched pack content data or null if not found.
|
|
1046
|
+
*/
|
|
1043
1047
|
export async function fetchPackAll(railcontentId) {
|
|
1044
|
-
|
|
1048
|
+
return fetchByRailContentId(railcontentId, 'pack');
|
|
1045
1049
|
}
|
|
1046
1050
|
|
|
1047
1051
|
export async function fetchLiveEvent(brand) {
|
|
1048
1052
|
//calendarIDs taken from addevent.php
|
|
1049
1053
|
// TODO import instructor calendars to Sanity
|
|
1050
1054
|
let defaultCalendarID = '';
|
|
1051
|
-
switch(brand) {
|
|
1055
|
+
switch (brand) {
|
|
1052
1056
|
case ('drumeo'):
|
|
1053
1057
|
defaultCalendarID = 'GP142387';
|
|
1054
|
-
|
|
1058
|
+
break;
|
|
1055
1059
|
case ('pianote'):
|
|
1056
1060
|
defaultCalendarID = 'be142408';
|
|
1057
1061
|
break;
|
|
@@ -1101,7 +1105,7 @@ export async function fetchLiveEvent(brand) {
|
|
|
1101
1105
|
* .catch(error => console.error(error));
|
|
1102
1106
|
*/
|
|
1103
1107
|
export async function fetchPackChildren(railcontentId) {
|
|
1104
|
-
|
|
1108
|
+
return fetchChildren(railcontentId, 'pack-children');
|
|
1105
1109
|
}
|
|
1106
1110
|
|
|
1107
1111
|
/**
|
|
@@ -1115,10 +1119,10 @@ export async function fetchPackChildren(railcontentId) {
|
|
|
1115
1119
|
* .catch(error => console.error(error));
|
|
1116
1120
|
*/
|
|
1117
1121
|
export async function fetchPackData(id) {
|
|
1118
|
-
|
|
1122
|
+
const query = `*[railcontent_id == ${id}]{
|
|
1119
1123
|
${getFieldsForContentType("pack")}
|
|
1120
1124
|
} [0...1]`;
|
|
1121
|
-
|
|
1125
|
+
return fetchSanity(query, false);
|
|
1122
1126
|
}
|
|
1123
1127
|
|
|
1124
1128
|
/**
|
|
@@ -1132,11 +1136,11 @@ export async function fetchPackData(id) {
|
|
|
1132
1136
|
* .catch(error => console.error(error));
|
|
1133
1137
|
*/
|
|
1134
1138
|
export async function fetchChallengeOverview(id) {
|
|
1135
|
-
|
|
1136
|
-
|
|
1139
|
+
// WIP
|
|
1140
|
+
const query = `*[railcontent_id == ${id}]{
|
|
1137
1141
|
${getFieldsForContentType("challenge")}
|
|
1138
1142
|
} [0...1]`;
|
|
1139
|
-
|
|
1143
|
+
return fetchSanity(query, false);
|
|
1140
1144
|
}
|
|
1141
1145
|
|
|
1142
1146
|
/**
|
|
@@ -1157,32 +1161,32 @@ export async function fetchChallengeOverview(id) {
|
|
|
1157
1161
|
* .catch(error => console.error(error));
|
|
1158
1162
|
*/
|
|
1159
1163
|
export async function fetchCoachLessons(brand, id, {
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1164
|
+
sortOrder = '-published_on',
|
|
1165
|
+
searchTerm = '',
|
|
1166
|
+
page = 1,
|
|
1167
|
+
limit = 20,
|
|
1168
|
+
includedFields = [],
|
|
1165
1169
|
} = {}) {
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1170
|
+
const fieldsString = getFieldsForContentType();
|
|
1171
|
+
const start = (page - 1) * limit;
|
|
1172
|
+
const end = start + limit;
|
|
1173
|
+
const searchFilter = searchTerm ? `&& title match "${searchTerm}*"` : ''
|
|
1174
|
+
const includedFieldsFilter = includedFields.length > 0
|
|
1171
1175
|
? filtersToGroq(includedFields)
|
|
1172
1176
|
: "";
|
|
1173
|
-
|
|
1177
|
+
const filter = `brand == '${brand}' ${searchFilter} ${includedFieldsFilter} && references(*[_type=='instructor' && railcontent_id == ${id}]._id)`;
|
|
1174
1178
|
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1179
|
+
sortOrder = getSortOrder(sortOrder);
|
|
1180
|
+
const query = buildEntityAndTotalQuery(
|
|
1181
|
+
filter,
|
|
1182
|
+
fieldsString,
|
|
1183
|
+
{
|
|
1184
|
+
sortOrder: sortOrder,
|
|
1185
|
+
start: start,
|
|
1186
|
+
end: end,
|
|
1187
|
+
},
|
|
1188
|
+
);
|
|
1189
|
+
return fetchSanity(query, true);
|
|
1186
1190
|
}
|
|
1187
1191
|
|
|
1188
1192
|
/**
|
|
@@ -1196,7 +1200,7 @@ export async function fetchCoachLessons(brand, id, {
|
|
|
1196
1200
|
* .catch(error => console.error(error));
|
|
1197
1201
|
*/
|
|
1198
1202
|
export async function fetchCourseOverview(id) {
|
|
1199
|
-
|
|
1203
|
+
return fetchByRailContentId(id, 'course');
|
|
1200
1204
|
}
|
|
1201
1205
|
|
|
1202
1206
|
/**
|
|
@@ -1210,21 +1214,21 @@ export async function fetchCourseOverview(id) {
|
|
|
1210
1214
|
* .catch(error => console.error(error));
|
|
1211
1215
|
*/
|
|
1212
1216
|
export async function fetchParentForDownload(id) {
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1217
|
+
const query = buildRawQuery(
|
|
1218
|
+
`railcontent_id == ${id}`,
|
|
1219
|
+
getFieldsForContentType('parent-download'),
|
|
1220
|
+
{
|
|
1221
|
+
isSingle: true,
|
|
1222
|
+
},
|
|
1223
|
+
);
|
|
1220
1224
|
|
|
1221
|
-
|
|
1225
|
+
return fetchSanity(query, false);
|
|
1222
1226
|
}
|
|
1223
1227
|
|
|
1224
1228
|
/**
|
|
1225
1229
|
* Fetch the data needed for the coach screen.
|
|
1226
1230
|
* @param {string} id - The Railcontent ID of the coach
|
|
1227
|
-
*
|
|
1231
|
+
*
|
|
1228
1232
|
* @returns {Promise<Object|null>} - The lessons for the instructor or null if not found.
|
|
1229
1233
|
*
|
|
1230
1234
|
* @example
|
|
@@ -1233,30 +1237,30 @@ export async function fetchParentForDownload(id) {
|
|
|
1233
1237
|
* .catch(error => console.error(error));
|
|
1234
1238
|
*/
|
|
1235
1239
|
export async function fetchByReference(brand, {
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1240
|
+
sortOrder = '-published_on',
|
|
1241
|
+
searchTerm = '',
|
|
1242
|
+
page = 1,
|
|
1243
|
+
limit = 20,
|
|
1244
|
+
includedFields = [],
|
|
1241
1245
|
} = {}) {
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1246
|
+
const fieldsString = getFieldsForContentType();
|
|
1247
|
+
const start = (page - 1) * limit;
|
|
1248
|
+
const end = start + limit;
|
|
1249
|
+
const searchFilter = searchTerm ? `&& title match "${searchTerm}*"` : '';
|
|
1250
|
+
const includedFieldsFilter = includedFields.length > 0
|
|
1247
1251
|
? includedFields.join(' && ')
|
|
1248
1252
|
: "";
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1253
|
+
const filter = `brand == '${brand}' ${searchFilter} && references(*[${includedFieldsFilter}]._id)`;
|
|
1254
|
+
const query = buildEntityAndTotalQuery(
|
|
1255
|
+
filter,
|
|
1256
|
+
fieldsString,
|
|
1257
|
+
{
|
|
1258
|
+
sortOrder: getSortOrder(sortOrder),
|
|
1259
|
+
start: start,
|
|
1260
|
+
end: end,
|
|
1261
|
+
},
|
|
1262
|
+
);
|
|
1263
|
+
return fetchSanity(query, true);
|
|
1260
1264
|
}
|
|
1261
1265
|
|
|
1262
1266
|
/**
|
|
@@ -1279,28 +1283,28 @@ export async function fetchByReference(brand, {
|
|
|
1279
1283
|
* .catch(error => console.error(error));
|
|
1280
1284
|
*/
|
|
1281
1285
|
export async function fetchArtistLessons(brand, name, contentType, {
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1286
|
+
sort = '-published_on',
|
|
1287
|
+
searchTerm = '',
|
|
1288
|
+
page = 1,
|
|
1289
|
+
limit = 10,
|
|
1290
|
+
includedFields = [],
|
|
1291
|
+
progressIds = undefined,
|
|
1288
1292
|
} = {}) {
|
|
1289
1293
|
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1294
|
+
const fieldsString = DEFAULT_FIELDS.join(',');
|
|
1295
|
+
const start = (page - 1) * limit;
|
|
1296
|
+
const end = start + limit;
|
|
1297
|
+
const searchFilter = searchTerm ? `&& title match "${searchTerm}*"` : ''
|
|
1298
|
+
const sortOrder = getSortOrder(sort);
|
|
1299
|
+
const addType = contentType && Array.isArray(contentType) ? `_type in ['${contentType.join("', '")}'] &&` : contentType ? `_type == '${contentType}' && ` : ''
|
|
1300
|
+
const includedFieldsFilter = includedFields.length > 0
|
|
1301
|
+
? filtersToGroq(includedFields)
|
|
1302
|
+
: "";
|
|
1299
1303
|
|
|
1300
|
-
|
|
1301
|
-
|
|
1304
|
+
// limits the results to supplied progressIds for started & completed filters
|
|
1305
|
+
const progressFilter = progressIds !== undefined ? `&& railcontent_id in [${progressIds.join(',')}]` : "";
|
|
1302
1306
|
|
|
1303
|
-
|
|
1307
|
+
const query = `{
|
|
1304
1308
|
"entity":
|
|
1305
1309
|
*[_type == 'artist' && name == '${name}']
|
|
1306
1310
|
{'type': _type, name, 'thumbnail_url':thumbnail_url.asset->url,
|
|
@@ -1309,7 +1313,7 @@ export async function fetchArtistLessons(brand, name, contentType, {
|
|
|
1309
1313
|
[${start}...${end}]}
|
|
1310
1314
|
|order(${sortOrder})
|
|
1311
1315
|
}`;
|
|
1312
|
-
|
|
1316
|
+
return fetchSanity(query, true);
|
|
1313
1317
|
}
|
|
1314
1318
|
|
|
1315
1319
|
/**
|
|
@@ -1331,26 +1335,26 @@ export async function fetchArtistLessons(brand, name, contentType, {
|
|
|
1331
1335
|
* .catch(error => console.error(error));
|
|
1332
1336
|
*/
|
|
1333
1337
|
export async function fetchGenreLessons(brand, name, contentType, {
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1338
|
+
sort = '-published_on',
|
|
1339
|
+
searchTerm = '',
|
|
1340
|
+
page = 1,
|
|
1341
|
+
limit = 10,
|
|
1342
|
+
includedFields = [],
|
|
1343
|
+
progressIds = undefined,
|
|
1340
1344
|
} = {}) {
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1345
|
+
const fieldsString = DEFAULT_FIELDS.join(',');
|
|
1346
|
+
const start = (page - 1) * limit;
|
|
1347
|
+
const end = start + limit;
|
|
1348
|
+
const searchFilter = searchTerm ? `&& title match "${searchTerm}*"` : ''
|
|
1349
|
+
const sortOrder = getSortOrder(sort);
|
|
1350
|
+
const addType = contentType ? `_type == '${contentType}' && ` : ''
|
|
1351
|
+
const includedFieldsFilter = includedFields.length > 0
|
|
1352
|
+
? filtersToGroq(includedFields)
|
|
1353
|
+
: "";
|
|
1354
|
+
// limits the results to supplied progressIds for started & completed filters
|
|
1355
|
+
const progressFilter = progressIds !== undefined ? `&& railcontent_id in [${progressIds.join(',')}]` : "";
|
|
1356
|
+
|
|
1357
|
+
const query = `{
|
|
1354
1358
|
"entity":
|
|
1355
1359
|
*[_type == 'genre' && name == '${name}']
|
|
1356
1360
|
{'type': _type, name, 'thumbnail_url':thumbnail_url.asset->url,
|
|
@@ -1359,7 +1363,7 @@ export async function fetchGenreLessons(brand, name, contentType, {
|
|
|
1359
1363
|
[${start}...${end}]}
|
|
1360
1364
|
|order(${sortOrder})
|
|
1361
1365
|
}`;
|
|
1362
|
-
|
|
1366
|
+
return fetchSanity(query, true);
|
|
1363
1367
|
}
|
|
1364
1368
|
|
|
1365
1369
|
export async function fetchTopLevelParentId(railcontentId) {
|
|
@@ -1433,7 +1437,6 @@ function populateHierarchyLookups(currentLevel, data, parentId) {
|
|
|
1433
1437
|
}
|
|
1434
1438
|
|
|
1435
1439
|
|
|
1436
|
-
|
|
1437
1440
|
/**
|
|
1438
1441
|
*
|
|
1439
1442
|
* @param {string} query - The GROQ query to execute against the Sanity API.
|
|
@@ -1451,83 +1454,89 @@ function populateHierarchyLookups(currentLevel, data, parentId) {
|
|
|
1451
1454
|
|
|
1452
1455
|
export async function fetchSanity(query,
|
|
1453
1456
|
isList,
|
|
1454
|
-
{
|
|
1455
|
-
|
|
1457
|
+
{
|
|
1458
|
+
customPostProcess = null,
|
|
1459
|
+
processNeedAccess = true,
|
|
1460
|
+
} = {}
|
|
1456
1461
|
) {
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1462
|
+
// Check the config object before proceeding
|
|
1463
|
+
if (!checkSanityConfig(globalConfig)) {
|
|
1464
|
+
return null;
|
|
1465
|
+
}
|
|
1466
|
+
|
|
1467
|
+
if (globalConfig.sanityConfig.debug) {
|
|
1468
|
+
console.log("fetchSanity Query:", query);
|
|
1469
|
+
}
|
|
1470
|
+
const perspective = globalConfig.sanityConfig.perspective ?? 'published';
|
|
1471
|
+
const encodedQuery = encodeURIComponent(query);
|
|
1472
|
+
const api = globalConfig.sanityConfig.useCachedAPI ? 'apicdn' : 'api';
|
|
1473
|
+
const url = `https://${globalConfig.sanityConfig.projectId}.${api}.sanity.io/v${globalConfig.sanityConfig.version}/data/query/${globalConfig.sanityConfig.dataset}?perspective=${perspective}&query=${encodedQuery}`;
|
|
1474
|
+
const headers = {
|
|
1475
|
+
'Authorization': `Bearer ${globalConfig.sanityConfig.token}`,
|
|
1476
|
+
'Content-Type': 'application/json'
|
|
1477
|
+
};
|
|
1478
|
+
|
|
1479
|
+
try {
|
|
1480
|
+
let promisesResult = await Promise.all([
|
|
1481
|
+
fetch(url, {headers}),
|
|
1482
|
+
processNeedAccess ? fetchUserPermissions() : null
|
|
1483
|
+
]);
|
|
1484
|
+
const response = promisesResult[0];
|
|
1485
|
+
const userPermissions = promisesResult[1]?.permissions;
|
|
1486
|
+
|
|
1487
|
+
if (!response.ok) {
|
|
1488
|
+
throw new Error(`Sanity API error: ${response.status} - ${response.statusText}`);
|
|
1489
|
+
}
|
|
1490
|
+
const result = await response.json();
|
|
1491
|
+
if (result.result) {
|
|
1492
|
+
if (globalConfig.sanityConfig.debug) {
|
|
1493
|
+
console.log("fetchSanity Results:", result);
|
|
1494
|
+
}
|
|
1495
|
+
let results = isList ? result.result : result.result[0];
|
|
1496
|
+
results = processNeedAccess ? await needsAccessDecorator(results, userPermissions) : results;
|
|
1497
|
+
return customPostProcess ? customPostProcess(results) : results;
|
|
1498
|
+
} else {
|
|
1499
|
+
throw new Error('No results found');
|
|
1500
|
+
}
|
|
1501
|
+
} catch (error) {
|
|
1502
|
+
console.error('fetchSanity: Fetch error:', error);
|
|
1503
|
+
return null;
|
|
1504
|
+
}
|
|
1494
1505
|
}
|
|
1495
1506
|
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
}
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
return results;
|
|
1507
|
+
function needsAccessDecorator(results, userPermissions) {
|
|
1508
|
+
if (globalConfig.sanityConfig.useDummyRailContentMethods) return results;
|
|
1509
|
+
|
|
1510
|
+
userPermissions = new Set(userPermissions);
|
|
1511
|
+
|
|
1512
|
+
if (Array.isArray(results)) {
|
|
1513
|
+
results.forEach((result) => {
|
|
1514
|
+
result['need_access'] = doesUserNeedAccessToContent(result, userPermissions);
|
|
1515
|
+
});
|
|
1516
|
+
} else if (results.entity && Array.isArray(results.entity)) {
|
|
1517
|
+
// Group By
|
|
1518
|
+
results.entity.forEach((result) => {
|
|
1519
|
+
if (result.lessons) {
|
|
1520
|
+
result.lessons.forEach((lesson) => {
|
|
1521
|
+
lesson['need_access'] = doesUserNeedAccessToContent(lesson, userPermissions); // Updated to check lesson access
|
|
1522
|
+
});
|
|
1523
|
+
} else {
|
|
1524
|
+
result['need_access'] = doesUserNeedAccessToContent(result, userPermissions);
|
|
1525
|
+
}
|
|
1526
|
+
});
|
|
1527
|
+
} else if (results.related_lessons && Array.isArray(results.related_lessons)) {
|
|
1528
|
+
results.related_lessons.forEach((result) => {
|
|
1529
|
+
result['need_access'] = doesUserNeedAccessToContent(result, userPermissions);
|
|
1530
|
+
})
|
|
1531
|
+
} else {
|
|
1532
|
+
results['need_access'] = doesUserNeedAccessToContent(results, userPermissions);
|
|
1533
|
+
}
|
|
1534
|
+
|
|
1535
|
+
return results;
|
|
1526
1536
|
}
|
|
1527
1537
|
|
|
1528
|
-
function doesUserNeedAccessToContent(result, userPermissions)
|
|
1529
|
-
|
|
1530
|
-
const permissions = new Set(result?.permission_id ?? []);
|
|
1538
|
+
function doesUserNeedAccessToContent(result, userPermissions) {
|
|
1539
|
+
const permissions = new Set(result?.permission_id ?? []);
|
|
1531
1540
|
if (permissions.size === 0) {
|
|
1532
1541
|
return false;
|
|
1533
1542
|
}
|
|
@@ -1539,12 +1548,6 @@ function doesUserNeedAccessToContent(result, userPermissions)
|
|
|
1539
1548
|
return true;
|
|
1540
1549
|
}
|
|
1541
1550
|
|
|
1542
|
-
async function getUserPermissions()
|
|
1543
|
-
{
|
|
1544
|
-
return await fetchUserPermissions();
|
|
1545
|
-
}
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
1551
|
/**
|
|
1549
1552
|
* Fetch CatalogueMetadata from Sanity. This information may be duplicated in the contentTypeConfig.js.
|
|
1550
1553
|
* It's an ongoing discussion (Aug 2024), but it's been included here if necessary
|
|
@@ -1558,8 +1561,8 @@ async function getUserPermissions()
|
|
|
1558
1561
|
* .then(data => console.log(data))
|
|
1559
1562
|
* .catch(error => console.error(error));
|
|
1560
1563
|
*/
|
|
1561
|
-
export async function fetchCatalogMetadata(contentType)
|
|
1562
|
-
|
|
1564
|
+
export async function fetchCatalogMetadata(contentType) {
|
|
1565
|
+
const query = `*[_type == 'CatalogMetadata']{
|
|
1563
1566
|
catalog_type,
|
|
1564
1567
|
brand,
|
|
1565
1568
|
groq_results,
|
|
@@ -1568,7 +1571,7 @@ export async function fetchCatalogMetadata(contentType)
|
|
|
1568
1571
|
modal_text,
|
|
1569
1572
|
sort_by,
|
|
1570
1573
|
}`
|
|
1571
|
-
return fetchSanity(query, false, {processNeedAccess:false});
|
|
1574
|
+
return fetchSanity(query, false, {processNeedAccess: false});
|
|
1572
1575
|
}
|
|
1573
1576
|
|
|
1574
1577
|
/**
|
|
@@ -1616,43 +1619,43 @@ export async function fetchMetadata(brand, type) {
|
|
|
1616
1619
|
|
|
1617
1620
|
//Helper Functions
|
|
1618
1621
|
function arrayJoinWithQuotes(array, delimiter = ',') {
|
|
1619
|
-
|
|
1620
|
-
|
|
1622
|
+
const wrapped = array.map(value => `'${value}'`);
|
|
1623
|
+
return wrapped.join(delimiter)
|
|
1621
1624
|
}
|
|
1622
1625
|
|
|
1623
1626
|
function getSanityDate(date) {
|
|
1624
|
-
|
|
1627
|
+
return date.toISOString();
|
|
1625
1628
|
}
|
|
1626
1629
|
|
|
1627
1630
|
const merge = (a, b, predicate = (a, b) => a === b) => {
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1631
|
+
const c = [...a]; // copy to avoid side effects
|
|
1632
|
+
// add all items from B to copy C if they're not already present
|
|
1633
|
+
b.forEach((bItem) => (c.some((cItem) => predicate(bItem, cItem)) ? null : c.push(bItem)))
|
|
1634
|
+
return c;
|
|
1632
1635
|
}
|
|
1633
1636
|
|
|
1634
1637
|
function checkSanityConfig(config) {
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1638
|
+
if (!config.sanityConfig.token) {
|
|
1639
|
+
console.warn('fetchSanity: The "token" property is missing in the config object.');
|
|
1640
|
+
return false;
|
|
1641
|
+
}
|
|
1642
|
+
if (!config.sanityConfig.projectId) {
|
|
1643
|
+
console.warn('fetchSanity: The "projectId" property is missing in the config object.');
|
|
1644
|
+
return false;
|
|
1645
|
+
}
|
|
1646
|
+
if (!config.sanityConfig.dataset) {
|
|
1647
|
+
console.warn('fetchSanity: The "dataset" property is missing in the config object.');
|
|
1648
|
+
return false;
|
|
1649
|
+
}
|
|
1650
|
+
if (!config.sanityConfig.version) {
|
|
1651
|
+
console.warn('fetchSanity: The "version" property is missing in the config object.');
|
|
1652
|
+
return false;
|
|
1653
|
+
}
|
|
1654
|
+
return true;
|
|
1652
1655
|
}
|
|
1653
1656
|
|
|
1654
1657
|
|
|
1655
|
-
function
|
|
1658
|
+
function buildRawQuery(
|
|
1656
1659
|
filter = '',
|
|
1657
1660
|
fields = '...',
|
|
1658
1661
|
{
|
|
@@ -1671,7 +1674,7 @@ function buildRawQuery(
|
|
|
1671
1674
|
}
|
|
1672
1675
|
|
|
1673
1676
|
|
|
1674
|
-
function
|
|
1677
|
+
async function buildQuery(
|
|
1675
1678
|
baseFilter = '',
|
|
1676
1679
|
filterParams = {},
|
|
1677
1680
|
fields = '...',
|
|
@@ -1682,11 +1685,11 @@ function buildQuery(
|
|
|
1682
1685
|
isSingle = false,
|
|
1683
1686
|
},
|
|
1684
1687
|
) {
|
|
1685
|
-
const filter = new FilterBuilder(baseFilter, filterParams).buildFilter();
|
|
1688
|
+
const filter = await new FilterBuilder(baseFilter, filterParams).buildFilter();
|
|
1686
1689
|
return buildRawQuery(filter, fields, {sortOrder, start, end, isSingle});
|
|
1687
1690
|
}
|
|
1688
1691
|
|
|
1689
|
-
function
|
|
1692
|
+
function buildEntityAndTotalQuery(
|
|
1690
1693
|
filter = '',
|
|
1691
1694
|
fields = '...',
|
|
1692
1695
|
{
|
|
@@ -1709,9 +1712,9 @@ function buildEntityAndTotalQuery(
|
|
|
1709
1712
|
}
|
|
1710
1713
|
|
|
1711
1714
|
|
|
1712
|
-
function getFilterOptions(option, commonFilter,contentType, brand){
|
|
1715
|
+
function getFilterOptions(option, commonFilter, contentType, brand) {
|
|
1713
1716
|
let filterGroq = '';
|
|
1714
|
-
const types = Array.from(new Set([...coachLessonsTypes
|
|
1717
|
+
const types = Array.from(new Set([...coachLessonsTypes, ...showsTypes[brand]]));
|
|
1715
1718
|
|
|
1716
1719
|
switch (option) {
|
|
1717
1720
|
case "difficulty":
|