musora-content-services 2.94.8 → 2.95.1
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/.claude/settings.local.json +18 -0
- package/CHANGELOG.md +18 -0
- package/CLAUDE.md +408 -0
- package/babel.config.cjs +10 -0
- package/jsdoc.json +2 -1
- package/package.json +2 -2
- package/src/constants/award-assets.js +35 -0
- package/src/filterBuilder.js +7 -2
- package/src/index.d.ts +26 -5
- package/src/index.js +26 -5
- package/src/services/awards/award-callbacks.js +165 -0
- package/src/services/awards/award-query.js +495 -0
- package/src/services/awards/internal/.indexignore +1 -0
- package/src/services/awards/internal/award-definitions.js +239 -0
- package/src/services/awards/internal/award-events.js +102 -0
- package/src/services/awards/internal/award-manager.js +162 -0
- package/src/services/awards/internal/certificate-builder.js +66 -0
- package/src/services/awards/internal/completion-data-generator.js +84 -0
- package/src/services/awards/internal/content-progress-observer.js +137 -0
- package/src/services/awards/internal/image-utils.js +62 -0
- package/src/services/awards/internal/message-generator.js +17 -0
- package/src/services/awards/internal/types.js +5 -0
- package/src/services/awards/types.d.ts +79 -0
- package/src/services/awards/types.js +101 -0
- package/src/services/config.js +24 -4
- package/src/services/content-org/learning-paths.ts +19 -15
- package/src/services/gamification/awards.ts +114 -83
- package/src/services/progress-events.js +58 -0
- package/src/services/progress-row/method-card.js +20 -5
- package/src/services/sanity.js +1 -1
- package/src/services/sync/fetch.ts +10 -2
- package/src/services/sync/manager.ts +6 -0
- package/src/services/sync/models/ContentProgress.ts +5 -6
- package/src/services/sync/models/UserAwardProgress.ts +55 -0
- package/src/services/sync/models/index.ts +1 -0
- package/src/services/sync/repositories/content-progress.ts +47 -25
- package/src/services/sync/repositories/index.ts +1 -0
- package/src/services/sync/repositories/practices.ts +16 -1
- package/src/services/sync/repositories/user-award-progress.ts +133 -0
- package/src/services/sync/repository-proxy.ts +6 -0
- package/src/services/sync/retry.ts +12 -11
- package/src/services/sync/schema/index.ts +18 -3
- package/src/services/sync/store/index.ts +53 -8
- package/src/services/sync/store/push-coalescer.ts +3 -3
- package/src/services/sync/store-configs.ts +7 -1
- package/src/services/userActivity.js +0 -1
- package/test/HttpClient.test.js +6 -6
- package/test/awards/award-alacarte-observer.test.js +196 -0
- package/test/awards/award-auto-refresh.test.js +83 -0
- package/test/awards/award-calculations.test.js +33 -0
- package/test/awards/award-certificate-display.test.js +328 -0
- package/test/awards/award-collection-edge-cases.test.js +210 -0
- package/test/awards/award-collection-filtering.test.js +285 -0
- package/test/awards/award-completion-flow.test.js +213 -0
- package/test/awards/award-exclusion-handling.test.js +273 -0
- package/test/awards/award-multi-lesson.test.js +241 -0
- package/test/awards/award-observer-integration.test.js +325 -0
- package/test/awards/award-query-messages.test.js +438 -0
- package/test/awards/award-user-collection.test.js +412 -0
- package/test/awards/duplicate-prevention.test.js +118 -0
- package/test/awards/helpers/completion-mock.js +54 -0
- package/test/awards/helpers/index.js +3 -0
- package/test/awards/helpers/mock-setup.js +69 -0
- package/test/awards/helpers/progress-emitter.js +39 -0
- package/test/awards/message-generator.test.js +162 -0
- package/test/initializeTests.js +6 -0
- package/test/mockData/award-definitions.js +171 -0
- package/test/sync/models/award-database-integration.test.js +519 -0
- package/tools/generate-index.cjs +9 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { AwardMessageGenerator } from '../../src/services/awards/internal/message-generator'
|
|
2
|
+
|
|
3
|
+
describe('AwardMessageGenerator', () => {
|
|
4
|
+
const mockCompletionData = {
|
|
5
|
+
content_title: 'Blues Foundations',
|
|
6
|
+
completed_at: '2023-09-17T14:19:21.000Z',
|
|
7
|
+
days_user_practiced: 14,
|
|
8
|
+
practice_minutes: 180
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
describe('generatePopupMessage', () => {
|
|
12
|
+
test('generates correct message with content title', () => {
|
|
13
|
+
const message = AwardMessageGenerator.generatePopupMessage(mockCompletionData)
|
|
14
|
+
|
|
15
|
+
expect(message).toContain('Blues Foundations')
|
|
16
|
+
expect(message).toContain('14 days')
|
|
17
|
+
expect(message).toContain('180 minutes')
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
test('uses correct practice time in message', () => {
|
|
21
|
+
const customData = {
|
|
22
|
+
...mockCompletionData,
|
|
23
|
+
practice_minutes: 450
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const message = AwardMessageGenerator.generatePopupMessage(customData)
|
|
27
|
+
|
|
28
|
+
expect(message).toContain('450 minutes')
|
|
29
|
+
expect(message).not.toContain('180 minutes')
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
test('uses correct days in message', () => {
|
|
33
|
+
const customData = {
|
|
34
|
+
...mockCompletionData,
|
|
35
|
+
days_user_practiced: 30
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const message = AwardMessageGenerator.generatePopupMessage(customData)
|
|
39
|
+
|
|
40
|
+
expect(message).toContain('30 days')
|
|
41
|
+
expect(message).not.toContain('14 days')
|
|
42
|
+
})
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
describe('generateCertificateMessage', () => {
|
|
46
|
+
test('generates certificate message without custom text', () => {
|
|
47
|
+
const message = AwardMessageGenerator.generateCertificateMessage(
|
|
48
|
+
mockCompletionData
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
expect(message).toContain('180 minutes')
|
|
52
|
+
expect(message).toContain('Blues Foundations')
|
|
53
|
+
expect(message).toContain('Well Done!')
|
|
54
|
+
expect(message).toContain('certificate of completion')
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
test('includes custom text when provided', () => {
|
|
58
|
+
const message = AwardMessageGenerator.generateCertificateMessage(
|
|
59
|
+
mockCompletionData,
|
|
60
|
+
'This is a bonus message.'
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
expect(message).toContain('This is a bonus message.')
|
|
64
|
+
expect(message).toContain('180 minutes')
|
|
65
|
+
expect(message).toContain('Blues Foundations')
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
test('handles custom text with proper spacing', () => {
|
|
69
|
+
const message = AwardMessageGenerator.generateCertificateMessage(
|
|
70
|
+
mockCompletionData,
|
|
71
|
+
'Keep up the great work!'
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
expect(message).toContain('completion. Keep up the great work!')
|
|
75
|
+
expect(message).not.toContain(' ')
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
test('works without custom text', () => {
|
|
79
|
+
const message = AwardMessageGenerator.generateCertificateMessage(
|
|
80
|
+
mockCompletionData,
|
|
81
|
+
undefined
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
expect(message).toContain('completion.')
|
|
85
|
+
expect(message).toContain('Well Done!')
|
|
86
|
+
expect(message.includes('completion.. Well Done')).toBe(false)
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
test('includes content title from completion data', () => {
|
|
90
|
+
const customData = {
|
|
91
|
+
...mockCompletionData,
|
|
92
|
+
content_title: 'Advanced Jazz Techniques'
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const message = AwardMessageGenerator.generateCertificateMessage(customData)
|
|
96
|
+
|
|
97
|
+
expect(message).toContain('Advanced Jazz Techniques')
|
|
98
|
+
expect(message).not.toContain('Blues Foundations')
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
test('includes practice minutes from completion data', () => {
|
|
102
|
+
const customData = {
|
|
103
|
+
...mockCompletionData,
|
|
104
|
+
practice_minutes: 500
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const message = AwardMessageGenerator.generateCertificateMessage(customData)
|
|
108
|
+
|
|
109
|
+
expect(message).toContain('500 minutes')
|
|
110
|
+
expect(message).not.toContain('180 minutes')
|
|
111
|
+
})
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
describe('edge cases', () => {
|
|
115
|
+
test('handles zero practice minutes', () => {
|
|
116
|
+
const zeroData = {
|
|
117
|
+
...mockCompletionData,
|
|
118
|
+
practice_minutes: 0
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const popupMessage = AwardMessageGenerator.generatePopupMessage(zeroData)
|
|
122
|
+
const certMessage = AwardMessageGenerator.generateCertificateMessage(zeroData)
|
|
123
|
+
|
|
124
|
+
expect(popupMessage).toContain('0 minutes')
|
|
125
|
+
expect(certMessage).toContain('0 minutes')
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
test('handles single day practiced with correct grammar', () => {
|
|
129
|
+
const oneDayData = {
|
|
130
|
+
...mockCompletionData,
|
|
131
|
+
days_user_practiced: 1
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const message = AwardMessageGenerator.generatePopupMessage(oneDayData)
|
|
135
|
+
|
|
136
|
+
expect(message).toContain('1 day')
|
|
137
|
+
expect(message).not.toContain('1 days')
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
test('handles very large practice times', () => {
|
|
141
|
+
const largeData = {
|
|
142
|
+
...mockCompletionData,
|
|
143
|
+
practice_minutes: 10000
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const message = AwardMessageGenerator.generateCertificateMessage(largeData)
|
|
147
|
+
|
|
148
|
+
expect(message).toContain('10000 minutes')
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
test('handles zero days practiced', () => {
|
|
152
|
+
const zeroDaysData = {
|
|
153
|
+
...mockCompletionData,
|
|
154
|
+
days_user_practiced: 0
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const popupMessage = AwardMessageGenerator.generatePopupMessage(zeroDaysData)
|
|
158
|
+
|
|
159
|
+
expect(popupMessage).toContain('0 days')
|
|
160
|
+
})
|
|
161
|
+
})
|
|
162
|
+
})
|
package/test/initializeTests.js
CHANGED
|
@@ -39,6 +39,12 @@ export async function initializeTestService(useLive = false, isAdmin = false) {
|
|
|
39
39
|
debug: process.env.DEBUG === 'true' || false,
|
|
40
40
|
useDummyRailContentMethods: true,
|
|
41
41
|
},
|
|
42
|
+
railcontentConfig: {
|
|
43
|
+
baseUrl: process.env.RAILCONTENT_BASE_URL || 'https://test.musora.com',
|
|
44
|
+
token: token,
|
|
45
|
+
userId: userId,
|
|
46
|
+
authToken: token
|
|
47
|
+
},
|
|
42
48
|
sessionConfig: { token: token, userId: userId, authToken: token },
|
|
43
49
|
baseUrl: process.env.RAILCONTENT_BASE_URL,
|
|
44
50
|
localStorage: new LocalStorageMock(),
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
export const mockAwardDefinitions = [
|
|
2
|
+
{
|
|
3
|
+
_id: '0238b1e5-ebee-42b3-9390-91467d113575',
|
|
4
|
+
award: 'https://cdn.sanity.io/files/4032r8py/staging/309b154d38165788c47674e5c7607d66944d5dde.png',
|
|
5
|
+
award_custom_text: null,
|
|
6
|
+
badge: 'https://cdn.sanity.io/files/4032r8py/staging/309b154d38165788c47674e5c7607d66944d5dde.png',
|
|
7
|
+
brand: 'drumeo',
|
|
8
|
+
child_ids: [416448],
|
|
9
|
+
content_id: 416446,
|
|
10
|
+
content_title: 'Adrian Guided Course Test',
|
|
11
|
+
content_type: 'guided-course',
|
|
12
|
+
instructor_name: 'Aaron Graham',
|
|
13
|
+
instructor_signature: 'https://cdn.sanity.io/files/4032r8py/staging/2e89dcaea7b76bba8c499e80d660e45fe2c06a16.png',
|
|
14
|
+
is_active: true,
|
|
15
|
+
logo: null,
|
|
16
|
+
name: 'Adrian Guided Course Test Award',
|
|
17
|
+
type: 'content-award'
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
_id: '0f49cb6a-1b23-4628-968e-15df02ffad7f',
|
|
21
|
+
award: 'https://cdn.sanity.io/files/4032r8py/staging/d9bdc3a9a7ac688a114264b5804a7add117d6a0f.png',
|
|
22
|
+
award_custom_text: 'Huzzah congratz',
|
|
23
|
+
badge: 'https://cdn.sanity.io/files/4032r8py/staging/8fb18f7645f9b1820629f7ee643bdeb771da7e28.png',
|
|
24
|
+
brand: 'pianote',
|
|
25
|
+
child_ids: [417045, 417046, 417047, 417048],
|
|
26
|
+
content_id: 417049,
|
|
27
|
+
content_title: 'Enrolling w/ Kickoff, has product GC (EC)',
|
|
28
|
+
content_type: 'guided-course',
|
|
29
|
+
instructor_name: 'Lisa Witt',
|
|
30
|
+
instructor_signature: null,
|
|
31
|
+
is_active: true,
|
|
32
|
+
logo: 'https://cdn.sanity.io/images/4032r8py/staging/dca075e5107fddb33b78778d67f6fce03501f579-2000x1033.svg',
|
|
33
|
+
name: 'Enrolling w/ Kickoff, has product GC (EC)',
|
|
34
|
+
type: 'content-award'
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
_id: '1575d0df-63ff-4611-a472-230e3e688660',
|
|
38
|
+
award: 'https://cdn.sanity.io/files/4032r8py/staging/ac68a54931fd8952b8c86844ed341d76ebdc079c.png',
|
|
39
|
+
award_custom_text: null,
|
|
40
|
+
badge: 'https://cdn.sanity.io/files/4032r8py/staging/f3df910730c5722f52e777c8fc63d6a53bda91ec.png',
|
|
41
|
+
brand: 'drumeo',
|
|
42
|
+
child_ids: [
|
|
43
|
+
416467, 416468, 416469, 416470, 416471, 416472, 416473,
|
|
44
|
+
416474, 416475, 416476, 416477, 416478, 416479, 416480, 416481,
|
|
45
|
+
416482, 416483, 416484, 416485, 416486, 416487, 416488, 416489
|
|
46
|
+
],
|
|
47
|
+
content_id: 416464,
|
|
48
|
+
content_title: '30-Day Drummer GC',
|
|
49
|
+
content_type: 'guided-course',
|
|
50
|
+
instructor_name: 'Domino Santantonio',
|
|
51
|
+
instructor_signature: null,
|
|
52
|
+
is_active: true,
|
|
53
|
+
logo: null,
|
|
54
|
+
name: '30 day drummer awardzz',
|
|
55
|
+
type: 'content-award'
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
_id: '361f3034-c6c9-45f7-bbfb-0d58dbe14411',
|
|
59
|
+
award: 'https://cdn.sanity.io/files/4032r8py/staging/20e9a8258d00818074f472700d2ca97d91956e80.png',
|
|
60
|
+
award_custom_text: 'AN AWARD!',
|
|
61
|
+
badge: 'https://cdn.sanity.io/files/4032r8py/staging/da59100c0b16e446700c9285e827b4545766a7b3.png',
|
|
62
|
+
brand: 'drumeo',
|
|
63
|
+
child_ids: [
|
|
64
|
+
417105, 417111, 417117, 417106, 417112, 417118, 417107, 417113,
|
|
65
|
+
417119, 416951, 417108, 416952, 417114, 416953, 417121, 416954,
|
|
66
|
+
417109, 416955, 417115, 416956, 417122, 416957
|
|
67
|
+
],
|
|
68
|
+
content_id: 417140,
|
|
69
|
+
content_title: 'Learn To Play The Drums',
|
|
70
|
+
content_type: 'learning-path-v2',
|
|
71
|
+
instructor_name: null,
|
|
72
|
+
instructor_signature: null,
|
|
73
|
+
is_active: true,
|
|
74
|
+
logo: null,
|
|
75
|
+
name: 'Learning Path 1 Award',
|
|
76
|
+
type: 'content-award'
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
_id: '7e54cfbd-1543-462f-944a-19f3efb96aa0',
|
|
80
|
+
award: 'https://cdn.sanity.io/files/4032r8py/staging/d20959255e9dbc5d955214b86b7dfe8db4cccde3.png',
|
|
81
|
+
award_custom_text: 'asadadsafaafafafad yay',
|
|
82
|
+
badge: 'https://cdn.sanity.io/files/4032r8py/staging/fdb15efdc07061a6ff54fdf7dd1b6101d4d6dd54.png',
|
|
83
|
+
brand: 'pianote',
|
|
84
|
+
child_ids: [417035, 417036, 417038],
|
|
85
|
+
content_id: 417039,
|
|
86
|
+
content_title: 'Enrolling w/o Kickoff, no product GC (LS101)',
|
|
87
|
+
content_type: 'course',
|
|
88
|
+
instructor_name: 'Lisa Witt',
|
|
89
|
+
instructor_signature: null,
|
|
90
|
+
is_active: true,
|
|
91
|
+
logo: 'https://cdn.sanity.io/images/4032r8py/staging/6ad3b1671d072e866233ee6b471d12c69afff0d0-469x177.png',
|
|
92
|
+
name: 'Enrolling w/o Kickoff, no product GC (LS101)',
|
|
93
|
+
type: 'content-award'
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
_id: 'cae0d533-faeb-4a96-a6b5-07ef8c7861ab',
|
|
97
|
+
award: 'https://cdn.sanity.io/files/4032r8py/staging/2e791954fcf7b0fcf32b55bf194395ccdd7228f6.png',
|
|
98
|
+
award_custom_text: null,
|
|
99
|
+
badge: 'https://cdn.sanity.io/files/4032r8py/staging/1cef6272cc2fd7d1b948c80a995c29cf2a8b47b2.png',
|
|
100
|
+
brand: 'drumeo',
|
|
101
|
+
child_ids: [416451, 416453, 416454, 416456, 416457, 416458, 416459, 416460, 416461, 416463],
|
|
102
|
+
content_id: 416450,
|
|
103
|
+
content_title: '10-Day Fills GC',
|
|
104
|
+
content_type: 'guided-course',
|
|
105
|
+
instructor_name: 'Domino Santantonio',
|
|
106
|
+
instructor_signature: null,
|
|
107
|
+
is_active: true,
|
|
108
|
+
logo: null,
|
|
109
|
+
name: 'The Chris award',
|
|
110
|
+
type: 'content-award'
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
_id: 'f7743699-13e0-4c4e-bfec-94a816cfec3e',
|
|
114
|
+
award: 'https://cdn.sanity.io/files/4032r8py/staging/d20959255e9dbc5d955214b86b7dfe8db4cccde3.png',
|
|
115
|
+
award_custom_text: 'You did it!! Yaaay',
|
|
116
|
+
badge: 'https://cdn.sanity.io/files/4032r8py/staging/ccb12884b7acf0c2a1b0f5dc69be6e93d95228ed.png',
|
|
117
|
+
brand: 'drumeo',
|
|
118
|
+
child_ids: [416444, 416445],
|
|
119
|
+
content_id: 416442,
|
|
120
|
+
content_title: 'Development GC 1',
|
|
121
|
+
content_type: 'guided-course',
|
|
122
|
+
instructor_name: 'BABY BOY DRUMMER',
|
|
123
|
+
instructor_signature: 'https://cdn.sanity.io/files/4032r8py/staging/da66880e96fb8288e6d54ed0de3e7be4564c7989.pdf',
|
|
124
|
+
is_active: true,
|
|
125
|
+
logo: 'https://cdn.sanity.io/images/4032r8py/staging/d20959255e9dbc5d955214b86b7dfe8db4cccde3-722x834.png',
|
|
126
|
+
name: "Adrian's cool award",
|
|
127
|
+
type: 'content-award'
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
_id: 'a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d',
|
|
131
|
+
award: 'https://cdn.sanity.io/files/4032r8py/staging/test-skill-pack-award.png',
|
|
132
|
+
award_custom_text: null,
|
|
133
|
+
badge: 'https://cdn.sanity.io/files/4032r8py/staging/test-skill-pack-badge.png',
|
|
134
|
+
brand: 'drumeo',
|
|
135
|
+
child_ids: [418001, 418002, 418003],
|
|
136
|
+
content_id: 418000,
|
|
137
|
+
content_title: 'Drum Rudiments Pack',
|
|
138
|
+
content_type: 'skill-pack',
|
|
139
|
+
instructor_name: 'Domino Santantonio',
|
|
140
|
+
instructor_signature: null,
|
|
141
|
+
is_active: true,
|
|
142
|
+
logo: null,
|
|
143
|
+
name: 'Drum Rudiments Pack Award',
|
|
144
|
+
type: 'content-award'
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
_id: 'b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e',
|
|
148
|
+
award: 'https://cdn.sanity.io/files/4032r8py/staging/test-learning-path-award.png',
|
|
149
|
+
award_custom_text: null,
|
|
150
|
+
badge: 'https://cdn.sanity.io/files/4032r8py/staging/test-learning-path-badge.png',
|
|
151
|
+
brand: 'drumeo',
|
|
152
|
+
child_ids: [418003, 418004, 418005],
|
|
153
|
+
content_id: 418010,
|
|
154
|
+
content_title: 'Beginner Drum Journey',
|
|
155
|
+
content_type: 'learning-path-v2',
|
|
156
|
+
instructor_name: 'Domino Santantonio',
|
|
157
|
+
instructor_signature: null,
|
|
158
|
+
is_active: true,
|
|
159
|
+
logo: null,
|
|
160
|
+
name: 'Beginner Drum Journey Award',
|
|
161
|
+
type: 'content-award'
|
|
162
|
+
}
|
|
163
|
+
]
|
|
164
|
+
|
|
165
|
+
export const getAwardByContentId = (contentId) => {
|
|
166
|
+
return mockAwardDefinitions.find(award => award.content_id === contentId)
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export const getAwardById = (awardId) => {
|
|
170
|
+
return mockAwardDefinitions.find(award => award._id === awardId)
|
|
171
|
+
}
|