@orjok/commons 1.0.2 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/amplify.cjs +30 -5
- package/dist/amplify.cjs.map +1 -1
- package/dist/amplify.d.cts +5 -2
- package/dist/amplify.d.ts +5 -2
- package/dist/amplify.js +30 -5
- package/dist/amplify.js.map +1 -1
- package/dist/chunk-B4UJE3F4.js +529 -0
- package/dist/chunk-B4UJE3F4.js.map +1 -0
- package/dist/chunk-ODXD2WJN.cjs +529 -0
- package/dist/chunk-ODXD2WJN.cjs.map +1 -0
- package/dist/hooks.cjs +639 -2
- package/dist/hooks.cjs.map +1 -1
- package/dist/hooks.d.cts +162 -3
- package/dist/hooks.d.ts +162 -3
- package/dist/hooks.js +638 -1
- package/dist/hooks.js.map +1 -1
- package/dist/index.cjs +2454 -363
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +303 -15
- package/dist/index.d.ts +303 -15
- package/dist/index.js +2430 -339
- package/dist/index.js.map +1 -1
- package/dist/{client-BaOC79Nc.d.cts → notification-BoqtkNrc.d.ts} +392 -12
- package/dist/{client-Bm9aiyTx.d.ts → notification-Ctfy0m05.d.cts} +392 -12
- package/dist/{storage-DLqdJgQt.d.cts → storage-9pK8KwIM.d.cts} +4 -2
- package/dist/{storage-DLqdJgQt.d.ts → storage-9pK8KwIM.d.ts} +4 -2
- package/dist/testing.cjs +34 -3
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.d.cts +9 -2
- package/dist/testing.d.ts +9 -2
- package/dist/testing.js +34 -3
- package/dist/testing.js.map +1 -1
- package/package.json +6 -3
package/dist/index.cjs
CHANGED
|
@@ -1,4 +1,38 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
|
|
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
|
+
var _chunkODXD2WJNcjs = require('./chunk-ODXD2WJN.cjs');
|
|
34
|
+
|
|
35
|
+
// src/services/user.service.ts
|
|
2
36
|
var UserService = class {
|
|
3
37
|
constructor(network) {
|
|
4
38
|
this.network = network;
|
|
@@ -8,11 +42,12 @@ var UserService = class {
|
|
|
8
42
|
`query GetUser($id: String!) {
|
|
9
43
|
getUser(id: $id) {
|
|
10
44
|
id fullName avatarUrl avatarConfig tier subscriptionExpiresAt
|
|
11
|
-
aiEvaluationRemaining questionCount packCount contestCount
|
|
45
|
+
aiEvaluationRemaining aiQuestionGenRemaining questionCount packCount contestCount
|
|
12
46
|
EngineeringRating MedicalRating VarsityRating BCSRating
|
|
13
47
|
sscOverallRating sscPhysicsRating sscChemistryRating sscMathRating sscBiologyRating
|
|
14
48
|
hscOverallRating hscPhysicsRating hscChemistryRating hscMathRating hscBiologyRating
|
|
15
49
|
bcsOverallRating
|
|
50
|
+
xp userLevel
|
|
16
51
|
}
|
|
17
52
|
}`,
|
|
18
53
|
{ id }
|
|
@@ -20,20 +55,23 @@ var UserService = class {
|
|
|
20
55
|
return result.data.getUser;
|
|
21
56
|
}
|
|
22
57
|
async updateAvatar(input) {
|
|
58
|
+
const updateInput = { id: input.userId };
|
|
59
|
+
if (input.avatarUrl !== void 0) updateInput.avatarUrl = input.avatarUrl;
|
|
60
|
+
if (input.avatarConfig !== void 0) updateInput.avatarConfig = input.avatarConfig;
|
|
23
61
|
const result = await this.network.mutate(
|
|
24
62
|
`mutation UpdateUser($input: UpdateUserInput!) {
|
|
25
63
|
updateUser(input: $input) {
|
|
26
64
|
id fullName avatarUrl avatarConfig
|
|
27
65
|
}
|
|
28
66
|
}`,
|
|
29
|
-
{ input:
|
|
67
|
+
{ input: updateInput }
|
|
30
68
|
);
|
|
31
69
|
return result.data.updateUser;
|
|
32
70
|
}
|
|
33
|
-
async getQuestions(userId, nextToken) {
|
|
71
|
+
async getQuestions(userId, nextToken, limit = 10) {
|
|
34
72
|
const result = await this.network.query(
|
|
35
|
-
`query ListUserQuestions($owner: ID!, $nextToken: String, $sortDirection: ModelSortDirection) {
|
|
36
|
-
listQuestionObjectByOwnerAndCreatedAt(owner: $owner, sortDirection: $sortDirection, nextToken: $nextToken) {
|
|
73
|
+
`query ListUserQuestions($owner: ID!, $limit: Int, $nextToken: String, $sortDirection: ModelSortDirection) {
|
|
74
|
+
listQuestionObjectByOwnerAndCreatedAt(owner: $owner, limit: $limit, sortDirection: $sortDirection, nextToken: $nextToken) {
|
|
37
75
|
items {
|
|
38
76
|
id question imageUrl language level difficulty type voteCount
|
|
39
77
|
verificationStatus owner packId createdAt
|
|
@@ -43,14 +81,14 @@ var UserService = class {
|
|
|
43
81
|
nextToken
|
|
44
82
|
}
|
|
45
83
|
}`,
|
|
46
|
-
{ owner: userId, nextToken, sortDirection: "DESC" }
|
|
84
|
+
{ owner: userId, limit, nextToken, sortDirection: "DESC" }
|
|
47
85
|
);
|
|
48
86
|
return result.data.listQuestionObjectByOwnerAndCreatedAt;
|
|
49
87
|
}
|
|
50
|
-
async getPacks(userId, nextToken) {
|
|
88
|
+
async getPacks(userId, nextToken, limit = 10) {
|
|
51
89
|
const result = await this.network.query(
|
|
52
|
-
`query ListUserPacks($owner: ID!, $nextToken: String, $sortDirection: ModelSortDirection) {
|
|
53
|
-
listPackByOwnerAndCreatedAt(owner: $owner, sortDirection: $sortDirection, nextToken: $nextToken) {
|
|
90
|
+
`query ListUserPacks($owner: ID!, $limit: Int, $nextToken: String, $sortDirection: ModelSortDirection) {
|
|
91
|
+
listPackByOwnerAndCreatedAt(owner: $owner, limit: $limit, sortDirection: $sortDirection, nextToken: $nextToken) {
|
|
54
92
|
items {
|
|
55
93
|
id name language level difficulty questionCount automaticNumbering
|
|
56
94
|
owner subjectId chapterId topicId verificationStatus createdAt
|
|
@@ -59,7 +97,7 @@ var UserService = class {
|
|
|
59
97
|
nextToken
|
|
60
98
|
}
|
|
61
99
|
}`,
|
|
62
|
-
{ owner: userId, nextToken, sortDirection: "DESC" }
|
|
100
|
+
{ owner: userId, limit, nextToken, sortDirection: "DESC" }
|
|
63
101
|
);
|
|
64
102
|
return result.data.listPackByOwnerAndCreatedAt;
|
|
65
103
|
}
|
|
@@ -90,8 +128,59 @@ var UserService = class {
|
|
|
90
128
|
);
|
|
91
129
|
return result.data.listCourseEnrolledByUserIdAndCreatedAt.items;
|
|
92
130
|
}
|
|
131
|
+
async updateProfile(input) {
|
|
132
|
+
const result = await this.network.mutate(
|
|
133
|
+
`mutation UpdateUserProfile($input: UpdateUserInput!) {
|
|
134
|
+
updateUser(input: $input) {
|
|
135
|
+
id fullName avatarUrl avatarConfig tier subscriptionExpiresAt
|
|
136
|
+
aiEvaluationRemaining aiQuestionGenRemaining questionCount packCount contestCount
|
|
137
|
+
xp userLevel
|
|
138
|
+
}
|
|
139
|
+
}`,
|
|
140
|
+
{ input }
|
|
141
|
+
);
|
|
142
|
+
return result.data.updateUser;
|
|
143
|
+
}
|
|
144
|
+
async list(input = {}) {
|
|
145
|
+
const result = await this.network.query(
|
|
146
|
+
`query ListUsers($limit: Int, $nextToken: String, $filter: ModelUserFilterInput) {
|
|
147
|
+
listUsers(limit: $limit, nextToken: $nextToken, filter: $filter) {
|
|
148
|
+
items {
|
|
149
|
+
id fullName avatarUrl avatarConfig tier subscriptionExpiresAt
|
|
150
|
+
aiEvaluationRemaining aiQuestionGenRemaining questionCount packCount contestCount
|
|
151
|
+
xp userLevel
|
|
152
|
+
}
|
|
153
|
+
nextToken
|
|
154
|
+
}
|
|
155
|
+
}`,
|
|
156
|
+
{ limit: _nullishCoalesce(input.limit, () => ( 20)), nextToken: input.nextToken, filter: input.filter }
|
|
157
|
+
);
|
|
158
|
+
return result.data.listUsers;
|
|
159
|
+
}
|
|
93
160
|
};
|
|
94
161
|
|
|
162
|
+
// src/utils/pagination.ts
|
|
163
|
+
async function paginateWithAccumulator(fetchPage, targetLimit = 12, initialNextToken, maxIterations = 10) {
|
|
164
|
+
const accumulated = [];
|
|
165
|
+
let currentNextToken = initialNextToken;
|
|
166
|
+
let iterations = 0;
|
|
167
|
+
while (accumulated.length < targetLimit && iterations < maxIterations) {
|
|
168
|
+
iterations++;
|
|
169
|
+
const remaining = targetLimit - accumulated.length;
|
|
170
|
+
const response = await fetchPage(remaining, currentNextToken);
|
|
171
|
+
const items = _optionalChain([response, 'optionalAccess', _2 => _2.items]) || [];
|
|
172
|
+
accumulated.push(...items);
|
|
173
|
+
currentNextToken = _optionalChain([response, 'optionalAccess', _3 => _3.nextToken]);
|
|
174
|
+
if (!currentNextToken || accumulated.length >= targetLimit) {
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return {
|
|
179
|
+
items: accumulated.slice(0, targetLimit),
|
|
180
|
+
nextToken: _nullishCoalesce(currentNextToken, () => ( null))
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
|
|
95
184
|
// src/services/question.service.ts
|
|
96
185
|
var QuestionService = class {
|
|
97
186
|
constructor(network) {
|
|
@@ -99,8 +188,8 @@ var QuestionService = class {
|
|
|
99
188
|
}
|
|
100
189
|
async create(input) {
|
|
101
190
|
const result = await this.network.mutate(
|
|
102
|
-
`mutation CreateQuestion($question: String!, $answer: String!, $options: String!, $language: String!, $level: String!, $difficulty: String!, $type: String, $explanation: String, $tags: String, $imagePayload: String, $optionsImagesPayload: String, $packId: ID, $order: Int, $contestId: ID, $subjectId: ID, $chapterId: ID, $topicId: ID, $extra: String, $markingInstructions: String) {
|
|
103
|
-
createQuestion(question: $question, answer: $answer, options: $options, language: $language, level: $level, difficulty: $difficulty, type: $type, explanation: $explanation, tags: $tags, imagePayload: $imagePayload, optionsImagesPayload: $optionsImagesPayload, packId: $packId, order: $order, contestId: $contestId, subjectId: $subjectId, chapterId: $chapterId, topicId: $topicId, extra: $extra, markingInstructions: $markingInstructions) {
|
|
191
|
+
`mutation CreateQuestion($question: String!, $answer: String!, $options: String!, $language: String!, $level: String!, $publicExam: String, $difficulty: String!, $type: String, $explanation: String, $tags: String, $imagePayload: String, $optionsImagesPayload: String, $packId: ID, $order: Int, $contestId: ID, $subjectId: ID, $chapterId: ID, $topicId: ID, $extra: String, $markingInstructions: String) {
|
|
192
|
+
createQuestion(question: $question, answer: $answer, options: $options, language: $language, level: $level, publicExam: $publicExam, difficulty: $difficulty, type: $type, explanation: $explanation, tags: $tags, imagePayload: $imagePayload, optionsImagesPayload: $optionsImagesPayload, packId: $packId, order: $order, contestId: $contestId, subjectId: $subjectId, chapterId: $chapterId, topicId: $topicId, extra: $extra, markingInstructions: $markingInstructions) {
|
|
104
193
|
status questionId
|
|
105
194
|
}
|
|
106
195
|
}`,
|
|
@@ -112,7 +201,7 @@ var QuestionService = class {
|
|
|
112
201
|
const result = await this.network.query(
|
|
113
202
|
`query GetQuestion($id: String!) {
|
|
114
203
|
getQuestionObject(id: $id) {
|
|
115
|
-
id question imageUrl language level difficulty type voteCount
|
|
204
|
+
id question imageUrl language level publicExam difficulty type voteCount
|
|
116
205
|
verificationStatus owner packId subjectId chapterId topicId order createdAt
|
|
117
206
|
options { items { id content } }
|
|
118
207
|
tags { items { id tagId } }
|
|
@@ -126,7 +215,7 @@ var QuestionService = class {
|
|
|
126
215
|
const result = await this.network.query(
|
|
127
216
|
`query GetFullQuestion($id: String!) {
|
|
128
217
|
getQuestionObject(id: $id) {
|
|
129
|
-
id question answer explanation extra imageUrl language level difficulty type
|
|
218
|
+
id question answer explanation extra imageUrl language level publicExam difficulty type
|
|
130
219
|
markingInstructions voteCount verificationStatus owner packId
|
|
131
220
|
subjectId chapterId topicId order createdAt
|
|
132
221
|
options { items { id content } }
|
|
@@ -157,13 +246,30 @@ var QuestionService = class {
|
|
|
157
246
|
}`,
|
|
158
247
|
{ packId, order: { eq: order } }
|
|
159
248
|
);
|
|
160
|
-
return _nullishCoalesce(_optionalChain([result, 'access',
|
|
249
|
+
return _nullishCoalesce(_optionalChain([result, 'access', _4 => _4.data, 'access', _5 => _5.listQuestionObjectByPackIdAndOrder, 'access', _6 => _6.items, 'access', _7 => _7[0], 'optionalAccess', _8 => _8.id]), () => ( null));
|
|
250
|
+
}
|
|
251
|
+
async listByPack(packId, limit = 200, sortDirection = "ASC", nextToken) {
|
|
252
|
+
const result = await this.network.query(
|
|
253
|
+
`query ListQuestionsByPack($packId: ID!, $sortDirection: ModelSortDirection, $limit: Int, $nextToken: String) {
|
|
254
|
+
listQuestionObjectByPackIdAndOrder(packId: $packId, sortDirection: $sortDirection, limit: $limit, nextToken: $nextToken) {
|
|
255
|
+
items {
|
|
256
|
+
id question answer explanation extra imageUrl language level publicExam difficulty type
|
|
257
|
+
markingInstructions voteCount owner packId subjectId chapterId topicId order createdAt
|
|
258
|
+
options { items { id content } }
|
|
259
|
+
tags { items { id tagId } }
|
|
260
|
+
}
|
|
261
|
+
nextToken
|
|
262
|
+
}
|
|
263
|
+
}`,
|
|
264
|
+
{ packId, sortDirection, limit, nextToken }
|
|
265
|
+
);
|
|
266
|
+
return result.data.listQuestionObjectByPackIdAndOrder;
|
|
161
267
|
}
|
|
162
268
|
async update(id, fields) {
|
|
163
269
|
const result = await this.network.mutate(
|
|
164
270
|
`mutation UpdateQuestion($input: UpdateQuestionObjectInput!) {
|
|
165
271
|
updateQuestionObject(input: $input) {
|
|
166
|
-
id question answer explanation extra imageUrl language level difficulty type
|
|
272
|
+
id question answer explanation extra imageUrl language level publicExam difficulty type
|
|
167
273
|
markingInstructions voteCount owner packId subjectId chapterId topicId order createdAt
|
|
168
274
|
options { items { id content } }
|
|
169
275
|
}
|
|
@@ -172,6 +278,41 @@ var QuestionService = class {
|
|
|
172
278
|
);
|
|
173
279
|
return result.data.updateQuestionObject;
|
|
174
280
|
}
|
|
281
|
+
async updateOption(id, content) {
|
|
282
|
+
const result = await this.network.mutate(
|
|
283
|
+
`mutation UpdateOption($input: UpdateOptionInput!) {
|
|
284
|
+
updateOption(input: $input) {
|
|
285
|
+
id
|
|
286
|
+
content
|
|
287
|
+
}
|
|
288
|
+
}`,
|
|
289
|
+
{ input: { id, content } }
|
|
290
|
+
);
|
|
291
|
+
return result.data.updateOption;
|
|
292
|
+
}
|
|
293
|
+
async createOption(input) {
|
|
294
|
+
const result = await this.network.mutate(
|
|
295
|
+
`mutation CreateOption($input: CreateOptionInput!) {
|
|
296
|
+
createOption(input: $input) {
|
|
297
|
+
id
|
|
298
|
+
content
|
|
299
|
+
}
|
|
300
|
+
}`,
|
|
301
|
+
{ input }
|
|
302
|
+
);
|
|
303
|
+
return result.data.createOption;
|
|
304
|
+
}
|
|
305
|
+
async deleteOption(id) {
|
|
306
|
+
const result = await this.network.mutate(
|
|
307
|
+
`mutation DeleteOption($input: DeleteOptionInput!) {
|
|
308
|
+
deleteOption(input: $input) {
|
|
309
|
+
id
|
|
310
|
+
}
|
|
311
|
+
}`,
|
|
312
|
+
{ input: { id } }
|
|
313
|
+
);
|
|
314
|
+
return result.data.deleteOption;
|
|
315
|
+
}
|
|
175
316
|
async delete(id) {
|
|
176
317
|
const result = await this.network.mutate(
|
|
177
318
|
`mutation DeleteQuestion($input: DeleteQuestionObjectInput!) {
|
|
@@ -228,70 +369,288 @@ var QuestionService = class {
|
|
|
228
369
|
return result.data.addQuestionTag;
|
|
229
370
|
}
|
|
230
371
|
async listBySubject(input) {
|
|
231
|
-
const
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
372
|
+
const hasLanguage = Boolean(input.language && input.language !== "All" && input.language !== "Any");
|
|
373
|
+
const hasDifficulty = Boolean(input.difficulty && input.difficulty !== "All");
|
|
374
|
+
const filter = {};
|
|
375
|
+
if (input.publicExam) {
|
|
376
|
+
filter.publicExam = { eq: input.publicExam };
|
|
377
|
+
}
|
|
378
|
+
if (input.questionType && input.questionType !== "Both") {
|
|
379
|
+
filter.type = { eq: input.questionType };
|
|
380
|
+
}
|
|
381
|
+
const targetLimit = _nullishCoalesce(input.limit, () => ( 12));
|
|
382
|
+
const executeQuery = async (pageLimit, nextToken) => {
|
|
383
|
+
if (hasLanguage) {
|
|
384
|
+
const rangeKey = hasDifficulty ? `${input.language}#${input.difficulty}#` : `${input.language}#`;
|
|
385
|
+
const variables = {
|
|
386
|
+
subjectId: input.id,
|
|
387
|
+
language_difficulty_createdAt: { beginsWith: rangeKey },
|
|
388
|
+
sortDirection: _nullishCoalesce(input.sortDirection, () => ( "DESC")),
|
|
389
|
+
limit: pageLimit,
|
|
390
|
+
nextToken,
|
|
391
|
+
...Object.keys(filter).length > 0 ? { filter } : {}
|
|
392
|
+
};
|
|
393
|
+
const result = await this.network.query(
|
|
394
|
+
`query ListQuestionsBySubjectAndLangDiff($subjectId: String!, $language_difficulty_createdAt: ModelStringKeyConditionInput, $sortDirection: ModelSortDirection, $limit: Int, $nextToken: String, $filter: ModelQuestionObjectFilterInput) {
|
|
395
|
+
listQuestionObjectBySubjectIdAndLanguage_difficulty_createdAt(subjectId: $subjectId, language_difficulty_createdAt: $language_difficulty_createdAt, sortDirection: $sortDirection, limit: $limit, nextToken: $nextToken, filter: $filter) {
|
|
396
|
+
items {
|
|
397
|
+
id question imageUrl language level publicExam difficulty type voteCount
|
|
398
|
+
verificationStatus owner packId subjectId chapterId topicId createdAt
|
|
399
|
+
options { items { id content } }
|
|
400
|
+
}
|
|
401
|
+
nextToken
|
|
402
|
+
}
|
|
403
|
+
}`,
|
|
404
|
+
variables
|
|
405
|
+
);
|
|
406
|
+
return result.data.listQuestionObjectBySubjectIdAndLanguage_difficulty_createdAt;
|
|
407
|
+
} else {
|
|
408
|
+
const queryFilter = { ...filter };
|
|
409
|
+
if (hasDifficulty) {
|
|
410
|
+
queryFilter.difficulty = { eq: input.difficulty };
|
|
246
411
|
}
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
412
|
+
const variables = {
|
|
413
|
+
subjectId: input.id,
|
|
414
|
+
sortDirection: _nullishCoalesce(input.sortDirection, () => ( "DESC")),
|
|
415
|
+
limit: pageLimit,
|
|
416
|
+
nextToken,
|
|
417
|
+
...Object.keys(queryFilter).length > 0 ? { filter: queryFilter } : {}
|
|
418
|
+
};
|
|
419
|
+
const result = await this.network.query(
|
|
420
|
+
`query ListQuestionsBySubject($subjectId: String!, $sortDirection: ModelSortDirection, $limit: Int, $nextToken: String, $filter: ModelQuestionObjectFilterInput) {
|
|
421
|
+
listQuestionObjectBySubjectIdAndCreatedAt(subjectId: $subjectId, sortDirection: $sortDirection, limit: $limit, nextToken: $nextToken, filter: $filter) {
|
|
422
|
+
items {
|
|
423
|
+
id question imageUrl language level publicExam difficulty type voteCount
|
|
424
|
+
verificationStatus owner packId subjectId chapterId topicId createdAt
|
|
425
|
+
options { items { id content } }
|
|
426
|
+
}
|
|
427
|
+
nextToken
|
|
428
|
+
}
|
|
429
|
+
}`,
|
|
430
|
+
variables
|
|
431
|
+
);
|
|
432
|
+
return result.data.listQuestionObjectBySubjectIdAndCreatedAt;
|
|
433
|
+
}
|
|
434
|
+
};
|
|
435
|
+
const hasPostFilter = hasLanguage ? Object.keys(filter).length > 0 : Object.keys(filter).length > 0 || hasDifficulty;
|
|
436
|
+
if (!hasPostFilter) {
|
|
437
|
+
return executeQuery(targetLimit, input.nextToken);
|
|
438
|
+
}
|
|
439
|
+
return paginateWithAccumulator(executeQuery, targetLimit, input.nextToken);
|
|
251
440
|
}
|
|
252
441
|
async listByChapter(input) {
|
|
253
|
-
const
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
442
|
+
const hasLanguage = Boolean(input.language && input.language !== "All" && input.language !== "Any");
|
|
443
|
+
const hasDifficulty = Boolean(input.difficulty && input.difficulty !== "All");
|
|
444
|
+
const filter = {};
|
|
445
|
+
if (input.publicExam) {
|
|
446
|
+
filter.publicExam = { eq: input.publicExam };
|
|
447
|
+
}
|
|
448
|
+
if (input.questionType && input.questionType !== "Both") {
|
|
449
|
+
filter.type = { eq: input.questionType };
|
|
450
|
+
}
|
|
451
|
+
const targetLimit = _nullishCoalesce(input.limit, () => ( 12));
|
|
452
|
+
const executeQuery = async (pageLimit, nextToken) => {
|
|
453
|
+
if (hasLanguage) {
|
|
454
|
+
const rangeKey = hasDifficulty ? `${input.language}#${input.difficulty}#` : `${input.language}#`;
|
|
455
|
+
const variables = {
|
|
456
|
+
chapterId: input.id,
|
|
457
|
+
language_difficulty_createdAt: { beginsWith: rangeKey },
|
|
458
|
+
sortDirection: _nullishCoalesce(input.sortDirection, () => ( "DESC")),
|
|
459
|
+
limit: pageLimit,
|
|
460
|
+
nextToken,
|
|
461
|
+
...Object.keys(filter).length > 0 ? { filter } : {}
|
|
462
|
+
};
|
|
463
|
+
const result = await this.network.query(
|
|
464
|
+
`query ListQuestionsByChapterAndLangDiff($chapterId: String!, $language_difficulty_createdAt: ModelStringKeyConditionInput, $sortDirection: ModelSortDirection, $limit: Int, $nextToken: String, $filter: ModelQuestionObjectFilterInput) {
|
|
465
|
+
listQuestionObjectByChapterIdAndLanguage_difficulty_createdAt(chapterId: $chapterId, language_difficulty_createdAt: $language_difficulty_createdAt, sortDirection: $sortDirection, limit: $limit, nextToken: $nextToken, filter: $filter) {
|
|
466
|
+
items {
|
|
467
|
+
id question imageUrl language level publicExam difficulty type voteCount
|
|
468
|
+
verificationStatus owner packId subjectId chapterId topicId createdAt
|
|
469
|
+
options { items { id content } }
|
|
470
|
+
}
|
|
471
|
+
nextToken
|
|
472
|
+
}
|
|
473
|
+
}`,
|
|
474
|
+
variables
|
|
475
|
+
);
|
|
476
|
+
return result.data.listQuestionObjectByChapterIdAndLanguage_difficulty_createdAt;
|
|
477
|
+
} else {
|
|
478
|
+
const queryFilter = { ...filter };
|
|
479
|
+
if (hasDifficulty) {
|
|
480
|
+
queryFilter.difficulty = { eq: input.difficulty };
|
|
268
481
|
}
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
482
|
+
const variables = {
|
|
483
|
+
chapterId: input.id,
|
|
484
|
+
sortDirection: _nullishCoalesce(input.sortDirection, () => ( "DESC")),
|
|
485
|
+
limit: pageLimit,
|
|
486
|
+
nextToken,
|
|
487
|
+
...Object.keys(queryFilter).length > 0 ? { filter: queryFilter } : {}
|
|
488
|
+
};
|
|
489
|
+
const result = await this.network.query(
|
|
490
|
+
`query ListQuestionsByChapter($chapterId: String!, $sortDirection: ModelSortDirection, $limit: Int, $nextToken: String, $filter: ModelQuestionObjectFilterInput) {
|
|
491
|
+
listQuestionObjectByChapterIdAndCreatedAt(chapterId: $chapterId, sortDirection: $sortDirection, limit: $limit, nextToken: $nextToken, filter: $filter) {
|
|
492
|
+
items {
|
|
493
|
+
id question imageUrl language level publicExam difficulty type voteCount
|
|
494
|
+
verificationStatus owner packId subjectId chapterId topicId createdAt
|
|
495
|
+
options { items { id content } }
|
|
496
|
+
}
|
|
497
|
+
nextToken
|
|
498
|
+
}
|
|
499
|
+
}`,
|
|
500
|
+
variables
|
|
501
|
+
);
|
|
502
|
+
return result.data.listQuestionObjectByChapterIdAndCreatedAt;
|
|
503
|
+
}
|
|
504
|
+
};
|
|
505
|
+
const hasPostFilter = hasLanguage ? Object.keys(filter).length > 0 : Object.keys(filter).length > 0 || hasDifficulty;
|
|
506
|
+
if (!hasPostFilter) {
|
|
507
|
+
return executeQuery(targetLimit, input.nextToken);
|
|
508
|
+
}
|
|
509
|
+
return paginateWithAccumulator(executeQuery, targetLimit, input.nextToken);
|
|
273
510
|
}
|
|
274
511
|
async listByTopic(input) {
|
|
275
|
-
const
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
512
|
+
const hasLanguage = Boolean(input.language && input.language !== "All" && input.language !== "Any");
|
|
513
|
+
const hasDifficulty = Boolean(input.difficulty && input.difficulty !== "All");
|
|
514
|
+
const filter = {};
|
|
515
|
+
if (input.publicExam) {
|
|
516
|
+
filter.publicExam = { eq: input.publicExam };
|
|
517
|
+
}
|
|
518
|
+
if (input.questionType && input.questionType !== "Both") {
|
|
519
|
+
filter.type = { eq: input.questionType };
|
|
520
|
+
}
|
|
521
|
+
const targetLimit = _nullishCoalesce(input.limit, () => ( 12));
|
|
522
|
+
const executeQuery = async (pageLimit, nextToken) => {
|
|
523
|
+
if (hasLanguage) {
|
|
524
|
+
const rangeKey = hasDifficulty ? `${input.language}#${input.difficulty}#` : `${input.language}#`;
|
|
525
|
+
const variables = {
|
|
526
|
+
topicId: input.id,
|
|
527
|
+
language_difficulty_createdAt: { beginsWith: rangeKey },
|
|
528
|
+
sortDirection: _nullishCoalesce(input.sortDirection, () => ( "DESC")),
|
|
529
|
+
limit: pageLimit,
|
|
530
|
+
nextToken,
|
|
531
|
+
...Object.keys(filter).length > 0 ? { filter } : {}
|
|
532
|
+
};
|
|
533
|
+
const result = await this.network.query(
|
|
534
|
+
`query ListQuestionsByTopicAndLangDiff($topicId: String!, $language_difficulty_createdAt: ModelStringKeyConditionInput, $sortDirection: ModelSortDirection, $limit: Int, $nextToken: String, $filter: ModelQuestionObjectFilterInput) {
|
|
535
|
+
listQuestionObjectByTopicIdAndLanguage_difficulty_createdAt(topicId: $topicId, language_difficulty_createdAt: $language_difficulty_createdAt, sortDirection: $sortDirection, limit: $limit, nextToken: $nextToken, filter: $filter) {
|
|
536
|
+
items {
|
|
537
|
+
id question imageUrl language level publicExam difficulty type voteCount
|
|
538
|
+
verificationStatus owner packId subjectId chapterId topicId createdAt
|
|
539
|
+
options { items { id content } }
|
|
540
|
+
}
|
|
541
|
+
nextToken
|
|
542
|
+
}
|
|
543
|
+
}`,
|
|
544
|
+
variables
|
|
545
|
+
);
|
|
546
|
+
return result.data.listQuestionObjectByTopicIdAndLanguage_difficulty_createdAt;
|
|
547
|
+
} else {
|
|
548
|
+
const queryFilter = { ...filter };
|
|
549
|
+
if (hasDifficulty) {
|
|
550
|
+
queryFilter.difficulty = { eq: input.difficulty };
|
|
551
|
+
}
|
|
552
|
+
const variables = {
|
|
553
|
+
topicId: input.id,
|
|
554
|
+
sortDirection: _nullishCoalesce(input.sortDirection, () => ( "DESC")),
|
|
555
|
+
limit: pageLimit,
|
|
556
|
+
nextToken,
|
|
557
|
+
...Object.keys(queryFilter).length > 0 ? { filter: queryFilter } : {}
|
|
558
|
+
};
|
|
559
|
+
const result = await this.network.query(
|
|
560
|
+
`query ListQuestionsByTopic($topicId: String!, $sortDirection: ModelSortDirection, $limit: Int, $nextToken: String, $filter: ModelQuestionObjectFilterInput) {
|
|
561
|
+
listQuestionObjectByTopicIdAndCreatedAt(topicId: $topicId, sortDirection: $sortDirection, limit: $limit, nextToken: $nextToken, filter: $filter) {
|
|
562
|
+
items {
|
|
563
|
+
id question imageUrl language level publicExam difficulty type voteCount
|
|
564
|
+
verificationStatus owner packId subjectId chapterId topicId createdAt
|
|
565
|
+
options { items { id content } }
|
|
566
|
+
}
|
|
567
|
+
nextToken
|
|
568
|
+
}
|
|
569
|
+
}`,
|
|
570
|
+
variables
|
|
571
|
+
);
|
|
572
|
+
return result.data.listQuestionObjectByTopicIdAndCreatedAt;
|
|
573
|
+
}
|
|
280
574
|
};
|
|
281
|
-
const
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
575
|
+
const hasPostFilter = hasLanguage ? Object.keys(filter).length > 0 : Object.keys(filter).length > 0 || hasDifficulty;
|
|
576
|
+
if (!hasPostFilter) {
|
|
577
|
+
return executeQuery(targetLimit, input.nextToken);
|
|
578
|
+
}
|
|
579
|
+
return paginateWithAccumulator(executeQuery, targetLimit, input.nextToken);
|
|
580
|
+
}
|
|
581
|
+
async listByPublicExam(input) {
|
|
582
|
+
const hasLanguage = Boolean(input.language && input.language !== "All" && input.language !== "Any");
|
|
583
|
+
const hasDifficulty = Boolean(input.difficulty && input.difficulty !== "All");
|
|
584
|
+
const filter = {};
|
|
585
|
+
if (input.questionType && input.questionType !== "Both") {
|
|
586
|
+
filter.type = { eq: input.questionType };
|
|
587
|
+
}
|
|
588
|
+
const targetLimit = _nullishCoalesce(input.limit, () => ( 12));
|
|
589
|
+
const executeQuery = async (pageLimit, nextToken) => {
|
|
590
|
+
if (hasLanguage) {
|
|
591
|
+
const rangeKey = hasDifficulty ? `${input.language}#${input.difficulty}#` : `${input.language}#`;
|
|
592
|
+
const variables2 = {
|
|
593
|
+
publicExam: input.publicExam,
|
|
594
|
+
language_difficulty_createdAt: { beginsWith: rangeKey },
|
|
595
|
+
sortDirection: _nullishCoalesce(input.sortDirection, () => ( "DESC")),
|
|
596
|
+
limit: pageLimit,
|
|
597
|
+
nextToken,
|
|
598
|
+
...Object.keys(filter).length > 0 ? { filter } : {}
|
|
599
|
+
};
|
|
600
|
+
try {
|
|
601
|
+
const result2 = await this.network.query(
|
|
602
|
+
`query ListQuestionsByPublicExamAndLangDiff($publicExam: String!, $language_difficulty_createdAt: ModelStringKeyConditionInput, $sortDirection: ModelSortDirection, $limit: Int, $nextToken: String, $filter: ModelQuestionObjectFilterInput) {
|
|
603
|
+
listQuestionObjectByPublicExamAndLanguage_difficulty_createdAt(publicExam: $publicExam, language_difficulty_createdAt: $language_difficulty_createdAt, sortDirection: $sortDirection, limit: $limit, nextToken: $nextToken, filter: $filter) {
|
|
604
|
+
items {
|
|
605
|
+
id question imageUrl language level publicExam difficulty type voteCount
|
|
606
|
+
verificationStatus owner packId subjectId chapterId topicId createdAt
|
|
607
|
+
options { items { id content } }
|
|
608
|
+
}
|
|
609
|
+
nextToken
|
|
610
|
+
}
|
|
611
|
+
}`,
|
|
612
|
+
variables2
|
|
613
|
+
);
|
|
614
|
+
if (_optionalChain([result2, 'access', _9 => _9.data, 'optionalAccess', _10 => _10.listQuestionObjectByPublicExamAndLanguage_difficulty_createdAt])) {
|
|
615
|
+
return result2.data.listQuestionObjectByPublicExamAndLanguage_difficulty_createdAt;
|
|
288
616
|
}
|
|
289
|
-
|
|
617
|
+
} catch (e2) {
|
|
290
618
|
}
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
619
|
+
}
|
|
620
|
+
const fallbackFilter = { ...filter };
|
|
621
|
+
if (hasLanguage) {
|
|
622
|
+
fallbackFilter.language = { eq: input.language };
|
|
623
|
+
}
|
|
624
|
+
if (hasDifficulty) {
|
|
625
|
+
fallbackFilter.difficulty = { eq: input.difficulty };
|
|
626
|
+
}
|
|
627
|
+
const variables = {
|
|
628
|
+
publicExam: input.publicExam,
|
|
629
|
+
sortDirection: _nullishCoalesce(input.sortDirection, () => ( "DESC")),
|
|
630
|
+
limit: pageLimit,
|
|
631
|
+
nextToken,
|
|
632
|
+
...Object.keys(fallbackFilter).length > 0 ? { filter: fallbackFilter } : {}
|
|
633
|
+
};
|
|
634
|
+
const result = await this.network.query(
|
|
635
|
+
`query ListQuestionsByPublicExam($publicExam: String!, $sortDirection: ModelSortDirection, $limit: Int, $nextToken: String, $filter: ModelQuestionObjectFilterInput) {
|
|
636
|
+
listQuestionObjectByPublicExamAndCreatedAt(publicExam: $publicExam, sortDirection: $sortDirection, limit: $limit, nextToken: $nextToken, filter: $filter) {
|
|
637
|
+
items {
|
|
638
|
+
id question imageUrl language level publicExam difficulty type voteCount
|
|
639
|
+
verificationStatus owner packId subjectId chapterId topicId createdAt
|
|
640
|
+
options { items { id content } }
|
|
641
|
+
}
|
|
642
|
+
nextToken
|
|
643
|
+
}
|
|
644
|
+
}`,
|
|
645
|
+
variables
|
|
646
|
+
);
|
|
647
|
+
return result.data.listQuestionObjectByPublicExamAndCreatedAt;
|
|
648
|
+
};
|
|
649
|
+
const hasPostFilter = hasLanguage ? Object.keys(filter).length > 0 : Object.keys(filter).length > 0 || hasLanguage || hasDifficulty;
|
|
650
|
+
if (!hasPostFilter) {
|
|
651
|
+
return executeQuery(targetLimit, input.nextToken);
|
|
652
|
+
}
|
|
653
|
+
return paginateWithAccumulator(executeQuery, targetLimit, input.nextToken);
|
|
295
654
|
}
|
|
296
655
|
async listByRandomHash(input) {
|
|
297
656
|
const compositeKey = [input.language, input.difficulty].filter(Boolean).join("_");
|
|
@@ -305,7 +664,7 @@ var QuestionService = class {
|
|
|
305
664
|
`query ListByRandomHash($subjectId: String!, $language_difficulty_randomHash: ModelStringKeyConditionInput, $sortDirection: ModelSortDirection, $limit: Int) {
|
|
306
665
|
listQuestionObjectBySubjectIdAndLanguage_difficulty_randomHash(subjectId: $subjectId, language_difficulty_randomHash: $language_difficulty_randomHash, sortDirection: $sortDirection, limit: $limit) {
|
|
307
666
|
items {
|
|
308
|
-
id question imageUrl language level difficulty type voteCount
|
|
667
|
+
id question imageUrl language level publicExam difficulty type voteCount
|
|
309
668
|
verificationStatus owner packId subjectId chapterId topicId createdAt
|
|
310
669
|
options { items { id content } }
|
|
311
670
|
}
|
|
@@ -316,6 +675,76 @@ var QuestionService = class {
|
|
|
316
675
|
);
|
|
317
676
|
return result.data.listQuestionObjectBySubjectIdAndLanguage_difficulty_randomHash;
|
|
318
677
|
}
|
|
678
|
+
async listByLevel(input) {
|
|
679
|
+
const hasLanguage = Boolean(input.language && input.language !== "All" && input.language !== "Any");
|
|
680
|
+
const hasDifficulty = Boolean(input.difficulty && input.difficulty !== "All");
|
|
681
|
+
const filter = {};
|
|
682
|
+
if (input.publicExam) {
|
|
683
|
+
filter.publicExam = { eq: input.publicExam };
|
|
684
|
+
}
|
|
685
|
+
if (input.questionType && input.questionType !== "Both") {
|
|
686
|
+
filter.type = { eq: input.questionType };
|
|
687
|
+
}
|
|
688
|
+
const targetLimit = _nullishCoalesce(input.limit, () => ( 12));
|
|
689
|
+
const executeQuery = async (pageLimit, nextToken) => {
|
|
690
|
+
if (hasLanguage) {
|
|
691
|
+
const rangeKey = hasDifficulty ? `${input.language}#${input.difficulty}#` : `${input.language}#`;
|
|
692
|
+
const variables = {
|
|
693
|
+
level: input.level,
|
|
694
|
+
language_difficulty_createdAt: { beginsWith: rangeKey },
|
|
695
|
+
sortDirection: _nullishCoalesce(input.sortDirection, () => ( "DESC")),
|
|
696
|
+
limit: pageLimit,
|
|
697
|
+
nextToken,
|
|
698
|
+
...Object.keys(filter).length > 0 ? { filter } : {}
|
|
699
|
+
};
|
|
700
|
+
const result = await this.network.query(
|
|
701
|
+
`query ListQuestionsByLevelAndLangDiff($level: String!, $language_difficulty_createdAt: ModelStringKeyConditionInput, $sortDirection: ModelSortDirection, $limit: Int, $nextToken: String, $filter: ModelQuestionObjectFilterInput) {
|
|
702
|
+
listQuestionObjectByLevelAndLanguage_difficulty_createdAt(level: $level, language_difficulty_createdAt: $language_difficulty_createdAt, sortDirection: $sortDirection, limit: $limit, nextToken: $nextToken, filter: $filter) {
|
|
703
|
+
items {
|
|
704
|
+
id question imageUrl language level publicExam difficulty type voteCount
|
|
705
|
+
verificationStatus owner packId subjectId chapterId topicId createdAt
|
|
706
|
+
options { items { id content } }
|
|
707
|
+
}
|
|
708
|
+
nextToken
|
|
709
|
+
}
|
|
710
|
+
}`,
|
|
711
|
+
variables
|
|
712
|
+
);
|
|
713
|
+
return result.data.listQuestionObjectByLevelAndLanguage_difficulty_createdAt;
|
|
714
|
+
} else {
|
|
715
|
+
const queryFilter = { ...filter };
|
|
716
|
+
if (hasDifficulty) {
|
|
717
|
+
queryFilter.difficulty = { eq: input.difficulty };
|
|
718
|
+
}
|
|
719
|
+
const variables = {
|
|
720
|
+
level: input.level,
|
|
721
|
+
sortDirection: _nullishCoalesce(input.sortDirection, () => ( "DESC")),
|
|
722
|
+
limit: pageLimit,
|
|
723
|
+
nextToken,
|
|
724
|
+
...Object.keys(queryFilter).length > 0 ? { filter: queryFilter } : {}
|
|
725
|
+
};
|
|
726
|
+
const result = await this.network.query(
|
|
727
|
+
`query ListQuestionsByLevel($level: String!, $sortDirection: ModelSortDirection, $limit: Int, $nextToken: String, $filter: ModelQuestionObjectFilterInput) {
|
|
728
|
+
listQuestionObjectByLevelAndCreatedAt(level: $level, sortDirection: $sortDirection, limit: $limit, nextToken: $nextToken, filter: $filter) {
|
|
729
|
+
items {
|
|
730
|
+
id question imageUrl language level publicExam difficulty type voteCount
|
|
731
|
+
verificationStatus owner packId subjectId chapterId topicId createdAt
|
|
732
|
+
options { items { id content } }
|
|
733
|
+
}
|
|
734
|
+
nextToken
|
|
735
|
+
}
|
|
736
|
+
}`,
|
|
737
|
+
variables
|
|
738
|
+
);
|
|
739
|
+
return result.data.listQuestionObjectByLevelAndCreatedAt;
|
|
740
|
+
}
|
|
741
|
+
};
|
|
742
|
+
const hasPostFilter = hasLanguage ? Object.keys(filter).length > 0 : Object.keys(filter).length > 0 || hasDifficulty;
|
|
743
|
+
if (!hasPostFilter) {
|
|
744
|
+
return executeQuery(targetLimit, input.nextToken);
|
|
745
|
+
}
|
|
746
|
+
return paginateWithAccumulator(executeQuery, targetLimit, input.nextToken);
|
|
747
|
+
}
|
|
319
748
|
};
|
|
320
749
|
|
|
321
750
|
// src/services/pack.service.ts
|
|
@@ -325,8 +754,8 @@ var PackService = class {
|
|
|
325
754
|
}
|
|
326
755
|
async create(input) {
|
|
327
756
|
const result = await this.network.mutate(
|
|
328
|
-
`mutation CreatePack($name: String!, $level: String!, $language: String!, $difficulty: String!, $automaticNumbering: Boolean, $subjectId: ID, $chapterId: ID, $topicId: ID) {
|
|
329
|
-
createPackObject(name: $name, level: $level, language: $language, difficulty: $difficulty, automaticNumbering: $automaticNumbering, subjectId: $subjectId, chapterId: $chapterId, topicId: $topicId) {
|
|
757
|
+
`mutation CreatePack($name: String!, $level: String!, $publicExam: String, $language: String!, $difficulty: String!, $automaticNumbering: Boolean, $subjectId: ID, $chapterId: ID, $topicId: ID) {
|
|
758
|
+
createPackObject(name: $name, level: $level, publicExam: $publicExam, language: $language, difficulty: $difficulty, automaticNumbering: $automaticNumbering, subjectId: $subjectId, chapterId: $chapterId, topicId: $topicId) {
|
|
330
759
|
status id
|
|
331
760
|
}
|
|
332
761
|
}`,
|
|
@@ -338,7 +767,7 @@ var PackService = class {
|
|
|
338
767
|
const result = await this.network.query(
|
|
339
768
|
`query GetPack($id: ID!) {
|
|
340
769
|
getPack(id: $id) {
|
|
341
|
-
id name language level difficulty questionCount automaticNumbering
|
|
770
|
+
id name language level publicExam difficulty questionCount automaticNumbering
|
|
342
771
|
owner subjectId chapterId topicId packGroupId verificationStatus createdAt
|
|
343
772
|
tags { items { id tagId } }
|
|
344
773
|
user { id fullName avatarUrl }
|
|
@@ -352,13 +781,13 @@ var PackService = class {
|
|
|
352
781
|
const result = await this.network.query(
|
|
353
782
|
`query GetFullPack($id: ID!) {
|
|
354
783
|
getPack(id: $id) {
|
|
355
|
-
id name language level difficulty questionCount automaticNumbering
|
|
784
|
+
id name language level publicExam difficulty questionCount automaticNumbering
|
|
356
785
|
owner subjectId chapterId topicId packGroupId verificationStatus createdAt
|
|
357
786
|
tags { items { id tagId } }
|
|
358
787
|
user { id fullName avatarUrl }
|
|
359
788
|
questions(sortDirection: ASC, limit: 200) {
|
|
360
789
|
items {
|
|
361
|
-
id question answer explanation extra imageUrl language level difficulty type
|
|
790
|
+
id question answer explanation extra imageUrl language level publicExam difficulty type
|
|
362
791
|
markingInstructions voteCount owner order createdAt
|
|
363
792
|
options { items { id content } }
|
|
364
793
|
tags { items { id tagId } }
|
|
@@ -368,13 +797,33 @@ var PackService = class {
|
|
|
368
797
|
}`,
|
|
369
798
|
{ id }
|
|
370
799
|
);
|
|
371
|
-
|
|
800
|
+
const pack = result.data.getPack;
|
|
801
|
+
if (pack && pack.questions && Array.isArray(pack.questions.items)) {
|
|
802
|
+
pack.questions.items.sort((a, b) => {
|
|
803
|
+
const isWrittenA = a.type === "WRITTEN" ? 1 : 0;
|
|
804
|
+
const isWrittenB = b.type === "WRITTEN" ? 1 : 0;
|
|
805
|
+
if (isWrittenA !== isWrittenB) {
|
|
806
|
+
return isWrittenA - isWrittenB;
|
|
807
|
+
}
|
|
808
|
+
const orderA = typeof a.order === "number" ? a.order : a.order ? Number(a.order) : 0;
|
|
809
|
+
const orderB = typeof b.order === "number" ? b.order : b.order ? Number(b.order) : 0;
|
|
810
|
+
if (orderA !== orderB) {
|
|
811
|
+
if (orderA === 0) return 1;
|
|
812
|
+
if (orderB === 0) return -1;
|
|
813
|
+
return orderA - orderB;
|
|
814
|
+
}
|
|
815
|
+
const timeA = a.createdAt ? new Date(a.createdAt).getTime() : 0;
|
|
816
|
+
const timeB = b.createdAt ? new Date(b.createdAt).getTime() : 0;
|
|
817
|
+
return timeA - timeB;
|
|
818
|
+
});
|
|
819
|
+
}
|
|
820
|
+
return pack;
|
|
372
821
|
}
|
|
373
822
|
async update(id, fields) {
|
|
374
823
|
const result = await this.network.mutate(
|
|
375
824
|
`mutation UpdatePack($input: UpdatePackInput!) {
|
|
376
825
|
updatePack(input: $input) {
|
|
377
|
-
id name language level difficulty questionCount automaticNumbering
|
|
826
|
+
id name language level publicExam difficulty questionCount automaticNumbering
|
|
378
827
|
owner subjectId chapterId topicId verificationStatus createdAt
|
|
379
828
|
}
|
|
380
829
|
}`,
|
|
@@ -384,12 +833,15 @@ var PackService = class {
|
|
|
384
833
|
}
|
|
385
834
|
async delete(id) {
|
|
386
835
|
const result = await this.network.mutate(
|
|
387
|
-
`mutation
|
|
388
|
-
|
|
836
|
+
`mutation DeletePackCascade($packId: ID!) {
|
|
837
|
+
deletePackCascade(packId: $packId) { status }
|
|
389
838
|
}`,
|
|
390
|
-
{
|
|
839
|
+
{ packId: id }
|
|
391
840
|
);
|
|
392
|
-
|
|
841
|
+
if (_optionalChain([result, 'access', _11 => _11.data, 'access', _12 => _12.deletePackCascade, 'optionalAccess', _13 => _13.status]) === "success") {
|
|
842
|
+
return { id };
|
|
843
|
+
}
|
|
844
|
+
return null;
|
|
393
845
|
}
|
|
394
846
|
async verify(id, userId) {
|
|
395
847
|
const result = await this.network.mutate(
|
|
@@ -409,7 +861,27 @@ var PackService = class {
|
|
|
409
861
|
);
|
|
410
862
|
return result.data.createPackReport;
|
|
411
863
|
}
|
|
412
|
-
async submitExam(packId, selectedOptions) {
|
|
864
|
+
async submitExam(packId, selectedOptions, options) {
|
|
865
|
+
if (_optionalChain([options, 'optionalAccess', _14 => _14.functionUrl])) {
|
|
866
|
+
try {
|
|
867
|
+
const headers = { "Content-Type": "application/json" };
|
|
868
|
+
if (options.authToken) {
|
|
869
|
+
headers["Authorization"] = `Bearer ${options.authToken}`;
|
|
870
|
+
}
|
|
871
|
+
const response = await fetch(options.functionUrl, {
|
|
872
|
+
method: "POST",
|
|
873
|
+
headers,
|
|
874
|
+
body: JSON.stringify({ packId, selectedOptions: JSON.stringify(selectedOptions) })
|
|
875
|
+
});
|
|
876
|
+
if (response.ok) {
|
|
877
|
+
const data = await response.json();
|
|
878
|
+
return data;
|
|
879
|
+
}
|
|
880
|
+
console.warn(`[PackService] Function URL failed with status ${response.status}, falling back to GraphQL...`);
|
|
881
|
+
} catch (err) {
|
|
882
|
+
console.warn("[PackService] Function URL fetch error, falling back to GraphQL...", err);
|
|
883
|
+
}
|
|
884
|
+
}
|
|
413
885
|
const result = await this.network.mutate(
|
|
414
886
|
`mutation SubmitPackExam($packId: ID!, $selectedOptions: String!) {
|
|
415
887
|
submitPackExam(packId: $packId, selectedOptions: $selectedOptions) {
|
|
@@ -426,7 +898,7 @@ var PackService = class {
|
|
|
426
898
|
listPackExamResultsByOwnerAndCreatedAt(owner: $owner, sortDirection: $sortDirection, nextToken: $nextToken) {
|
|
427
899
|
items {
|
|
428
900
|
id packId selectedOptions aiEvaluations owner createdAt
|
|
429
|
-
pack { id name language level difficulty questionCount }
|
|
901
|
+
pack { id name language level publicExam difficulty questionCount }
|
|
430
902
|
}
|
|
431
903
|
nextToken
|
|
432
904
|
}
|
|
@@ -440,7 +912,7 @@ var PackService = class {
|
|
|
440
912
|
`query GetPackExamResult($id: ID!) {
|
|
441
913
|
getPackExamResults(id: $id) {
|
|
442
914
|
id packId selectedOptions aiEvaluations owner createdAt
|
|
443
|
-
pack { id name language level difficulty questionCount }
|
|
915
|
+
pack { id name language level publicExam difficulty questionCount }
|
|
444
916
|
}
|
|
445
917
|
}`,
|
|
446
918
|
{ id: resultId }
|
|
@@ -448,79 +920,462 @@ var PackService = class {
|
|
|
448
920
|
return result.data.getPackExamResults;
|
|
449
921
|
}
|
|
450
922
|
async listBySubject(input) {
|
|
451
|
-
const
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
923
|
+
const hasLanguage = Boolean(input.language && input.language !== "All" && input.language !== "Any");
|
|
924
|
+
const hasDifficulty = Boolean(input.difficulty && input.difficulty !== "All");
|
|
925
|
+
const filter = {};
|
|
926
|
+
if (input.publicExam) {
|
|
927
|
+
filter.publicExam = { eq: input.publicExam };
|
|
928
|
+
}
|
|
929
|
+
const targetLimit = _nullishCoalesce(input.limit, () => ( 12));
|
|
930
|
+
const executeQuery = async (pageLimit, nextToken) => {
|
|
931
|
+
if (hasLanguage) {
|
|
932
|
+
const rangeKey = hasDifficulty ? `${input.language}#${input.difficulty}#` : `${input.language}#`;
|
|
933
|
+
const variables = {
|
|
934
|
+
subjectId: input.id,
|
|
935
|
+
language_difficulty_createdAt: { beginsWith: rangeKey },
|
|
936
|
+
sortDirection: _nullishCoalesce(input.sortDirection, () => ( "DESC")),
|
|
937
|
+
limit: pageLimit,
|
|
938
|
+
nextToken,
|
|
939
|
+
...Object.keys(filter).length > 0 ? { filter } : {}
|
|
940
|
+
};
|
|
941
|
+
const result = await this.network.query(
|
|
942
|
+
`query ListPacksBySubjectAndLangDiff($subjectId: String!, $language_difficulty_createdAt: ModelStringKeyConditionInput, $sortDirection: ModelSortDirection, $limit: Int, $nextToken: String, $filter: ModelPackFilterInput) {
|
|
943
|
+
listPackBySubjectIdAndLanguage_difficulty_createdAt(subjectId: $subjectId, language_difficulty_createdAt: $language_difficulty_createdAt, sortDirection: $sortDirection, limit: $limit, nextToken: $nextToken, filter: $filter) {
|
|
944
|
+
items {
|
|
945
|
+
id name language level publicExam difficulty questionCount owner createdAt verificationStatus subjectId chapterId topicId
|
|
946
|
+
tags { items { id tagId } }
|
|
947
|
+
}
|
|
948
|
+
nextToken
|
|
949
|
+
}
|
|
950
|
+
}`,
|
|
951
|
+
variables
|
|
952
|
+
);
|
|
953
|
+
return result.data.listPackBySubjectIdAndLanguage_difficulty_createdAt;
|
|
954
|
+
} else {
|
|
955
|
+
const queryFilter = { ...filter };
|
|
956
|
+
if (hasDifficulty) {
|
|
957
|
+
queryFilter.difficulty = { eq: input.difficulty };
|
|
459
958
|
}
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
959
|
+
const variables = {
|
|
960
|
+
subjectId: input.id,
|
|
961
|
+
sortDirection: _nullishCoalesce(input.sortDirection, () => ( "DESC")),
|
|
962
|
+
limit: pageLimit,
|
|
963
|
+
nextToken,
|
|
964
|
+
...Object.keys(queryFilter).length > 0 ? { filter: queryFilter } : {}
|
|
965
|
+
};
|
|
966
|
+
const result = await this.network.query(
|
|
967
|
+
`query ListPacksBySubject($subjectId: String!, $sortDirection: ModelSortDirection, $limit: Int, $nextToken: String, $filter: ModelPackFilterInput) {
|
|
968
|
+
listPackBySubjectIdAndCreatedAt(subjectId: $subjectId, sortDirection: $sortDirection, limit: $limit, nextToken: $nextToken, filter: $filter) {
|
|
969
|
+
items {
|
|
970
|
+
id name language level publicExam difficulty questionCount owner createdAt verificationStatus subjectId chapterId topicId
|
|
971
|
+
tags { items { id tagId } }
|
|
972
|
+
}
|
|
973
|
+
nextToken
|
|
974
|
+
}
|
|
975
|
+
}`,
|
|
976
|
+
variables
|
|
977
|
+
);
|
|
978
|
+
return result.data.listPackBySubjectIdAndCreatedAt;
|
|
979
|
+
}
|
|
980
|
+
};
|
|
981
|
+
const hasPostFilter = hasLanguage ? Object.keys(filter).length > 0 : Object.keys(filter).length > 0 || hasDifficulty;
|
|
982
|
+
if (!hasPostFilter) {
|
|
983
|
+
return executeQuery(targetLimit, input.nextToken);
|
|
984
|
+
}
|
|
985
|
+
return paginateWithAccumulator(executeQuery, targetLimit, input.nextToken);
|
|
464
986
|
}
|
|
465
987
|
async listByChapter(input) {
|
|
466
|
-
const
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
988
|
+
const hasLanguage = Boolean(input.language && input.language !== "All" && input.language !== "Any");
|
|
989
|
+
const hasDifficulty = Boolean(input.difficulty && input.difficulty !== "All");
|
|
990
|
+
const filter = {};
|
|
991
|
+
if (input.publicExam) {
|
|
992
|
+
filter.publicExam = { eq: input.publicExam };
|
|
993
|
+
}
|
|
994
|
+
const targetLimit = _nullishCoalesce(input.limit, () => ( 12));
|
|
995
|
+
const executeQuery = async (pageLimit, nextToken) => {
|
|
996
|
+
if (hasLanguage) {
|
|
997
|
+
const rangeKey = hasDifficulty ? `${input.language}#${input.difficulty}#` : `${input.language}#`;
|
|
998
|
+
const variables = {
|
|
999
|
+
chapterId: input.id,
|
|
1000
|
+
language_difficulty_createdAt: { beginsWith: rangeKey },
|
|
1001
|
+
sortDirection: _nullishCoalesce(input.sortDirection, () => ( "DESC")),
|
|
1002
|
+
limit: pageLimit,
|
|
1003
|
+
nextToken,
|
|
1004
|
+
...Object.keys(filter).length > 0 ? { filter } : {}
|
|
1005
|
+
};
|
|
1006
|
+
const result = await this.network.query(
|
|
1007
|
+
`query ListPacksByChapterAndLangDiff($chapterId: String!, $language_difficulty_createdAt: ModelStringKeyConditionInput, $sortDirection: ModelSortDirection, $limit: Int, $nextToken: String, $filter: ModelPackFilterInput) {
|
|
1008
|
+
listPackByChapterIdAndLanguage_difficulty_createdAt(chapterId: $chapterId, language_difficulty_createdAt: $language_difficulty_createdAt, sortDirection: $sortDirection, limit: $limit, nextToken: $nextToken, filter: $filter) {
|
|
1009
|
+
items {
|
|
1010
|
+
id name language level publicExam difficulty questionCount owner createdAt verificationStatus subjectId chapterId topicId
|
|
1011
|
+
tags { items { id tagId } }
|
|
1012
|
+
}
|
|
1013
|
+
nextToken
|
|
1014
|
+
}
|
|
1015
|
+
}`,
|
|
1016
|
+
variables
|
|
1017
|
+
);
|
|
1018
|
+
return result.data.listPackByChapterIdAndLanguage_difficulty_createdAt;
|
|
1019
|
+
} else {
|
|
1020
|
+
const queryFilter = { ...filter };
|
|
1021
|
+
if (hasDifficulty) {
|
|
1022
|
+
queryFilter.difficulty = { eq: input.difficulty };
|
|
474
1023
|
}
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
1024
|
+
const variables = {
|
|
1025
|
+
chapterId: input.id,
|
|
1026
|
+
sortDirection: _nullishCoalesce(input.sortDirection, () => ( "DESC")),
|
|
1027
|
+
limit: pageLimit,
|
|
1028
|
+
nextToken,
|
|
1029
|
+
...Object.keys(queryFilter).length > 0 ? { filter: queryFilter } : {}
|
|
1030
|
+
};
|
|
1031
|
+
const result = await this.network.query(
|
|
1032
|
+
`query ListPacksByChapter($chapterId: String!, $sortDirection: ModelSortDirection, $limit: Int, $nextToken: String, $filter: ModelPackFilterInput) {
|
|
1033
|
+
listPackByChapterIdAndCreatedAt(chapterId: $chapterId, sortDirection: $sortDirection, limit: $limit, nextToken: $nextToken, filter: $filter) {
|
|
1034
|
+
items {
|
|
1035
|
+
id name language level publicExam difficulty questionCount owner createdAt verificationStatus subjectId chapterId topicId
|
|
1036
|
+
tags { items { id tagId } }
|
|
1037
|
+
}
|
|
1038
|
+
nextToken
|
|
1039
|
+
}
|
|
1040
|
+
}`,
|
|
1041
|
+
variables
|
|
1042
|
+
);
|
|
1043
|
+
return result.data.listPackByChapterIdAndCreatedAt;
|
|
1044
|
+
}
|
|
1045
|
+
};
|
|
1046
|
+
const hasPostFilter = hasLanguage ? Object.keys(filter).length > 0 : Object.keys(filter).length > 0 || hasDifficulty;
|
|
1047
|
+
if (!hasPostFilter) {
|
|
1048
|
+
return executeQuery(targetLimit, input.nextToken);
|
|
1049
|
+
}
|
|
1050
|
+
return paginateWithAccumulator(executeQuery, targetLimit, input.nextToken);
|
|
479
1051
|
}
|
|
480
1052
|
async listByTopic(input) {
|
|
481
|
-
const
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
1053
|
+
const hasLanguage = Boolean(input.language && input.language !== "All" && input.language !== "Any");
|
|
1054
|
+
const hasDifficulty = Boolean(input.difficulty && input.difficulty !== "All");
|
|
1055
|
+
const filter = {};
|
|
1056
|
+
if (input.publicExam) {
|
|
1057
|
+
filter.publicExam = { eq: input.publicExam };
|
|
1058
|
+
}
|
|
1059
|
+
const targetLimit = _nullishCoalesce(input.limit, () => ( 12));
|
|
1060
|
+
const executeQuery = async (pageLimit, nextToken) => {
|
|
1061
|
+
if (hasLanguage) {
|
|
1062
|
+
const rangeKey = hasDifficulty ? `${input.language}#${input.difficulty}#` : `${input.language}#`;
|
|
1063
|
+
const variables = {
|
|
1064
|
+
topicId: input.id,
|
|
1065
|
+
language_difficulty_createdAt: { beginsWith: rangeKey },
|
|
1066
|
+
sortDirection: _nullishCoalesce(input.sortDirection, () => ( "DESC")),
|
|
1067
|
+
limit: pageLimit,
|
|
1068
|
+
nextToken,
|
|
1069
|
+
...Object.keys(filter).length > 0 ? { filter } : {}
|
|
1070
|
+
};
|
|
1071
|
+
const result = await this.network.query(
|
|
1072
|
+
`query ListPacksByTopicAndLangDiff($topicId: String!, $language_difficulty_createdAt: ModelStringKeyConditionInput, $sortDirection: ModelSortDirection, $limit: Int, $nextToken: String, $filter: ModelPackFilterInput) {
|
|
1073
|
+
listPackByTopicIdAndLanguage_difficulty_createdAt(topicId: $topicId, language_difficulty_createdAt: $language_difficulty_createdAt, sortDirection: $sortDirection, limit: $limit, nextToken: $nextToken, filter: $filter) {
|
|
1074
|
+
items {
|
|
1075
|
+
id name language level publicExam difficulty questionCount owner createdAt verificationStatus subjectId chapterId topicId
|
|
1076
|
+
tags { items { id tagId } }
|
|
1077
|
+
}
|
|
1078
|
+
nextToken
|
|
1079
|
+
}
|
|
1080
|
+
}`,
|
|
1081
|
+
variables
|
|
1082
|
+
);
|
|
1083
|
+
return result.data.listPackByTopicIdAndLanguage_difficulty_createdAt;
|
|
1084
|
+
} else {
|
|
1085
|
+
const queryFilter = { ...filter };
|
|
1086
|
+
if (hasDifficulty) {
|
|
1087
|
+
queryFilter.difficulty = { eq: input.difficulty };
|
|
1088
|
+
}
|
|
1089
|
+
const variables = {
|
|
1090
|
+
topicId: input.id,
|
|
1091
|
+
sortDirection: _nullishCoalesce(input.sortDirection, () => ( "DESC")),
|
|
1092
|
+
limit: pageLimit,
|
|
1093
|
+
nextToken,
|
|
1094
|
+
...Object.keys(queryFilter).length > 0 ? { filter: queryFilter } : {}
|
|
1095
|
+
};
|
|
1096
|
+
const result = await this.network.query(
|
|
1097
|
+
`query ListPacksByTopic($topicId: String!, $sortDirection: ModelSortDirection, $limit: Int, $nextToken: String, $filter: ModelPackFilterInput) {
|
|
1098
|
+
listPackByTopicIdAndCreatedAt(topicId: $topicId, sortDirection: $sortDirection, limit: $limit, nextToken: $nextToken, filter: $filter) {
|
|
1099
|
+
items {
|
|
1100
|
+
id name language level publicExam difficulty questionCount owner createdAt verificationStatus subjectId chapterId topicId
|
|
1101
|
+
tags { items { id tagId } }
|
|
1102
|
+
}
|
|
1103
|
+
nextToken
|
|
1104
|
+
}
|
|
1105
|
+
}`,
|
|
1106
|
+
variables
|
|
1107
|
+
);
|
|
1108
|
+
return result.data.listPackByTopicIdAndCreatedAt;
|
|
1109
|
+
}
|
|
1110
|
+
};
|
|
1111
|
+
const hasPostFilter = hasLanguage ? Object.keys(filter).length > 0 : Object.keys(filter).length > 0 || hasDifficulty;
|
|
1112
|
+
if (!hasPostFilter) {
|
|
1113
|
+
return executeQuery(targetLimit, input.nextToken);
|
|
1114
|
+
}
|
|
1115
|
+
return paginateWithAccumulator(executeQuery, targetLimit, input.nextToken);
|
|
1116
|
+
}
|
|
1117
|
+
async listByPublicExam(input) {
|
|
1118
|
+
const hasLanguage = Boolean(input.language && input.language !== "All" && input.language !== "Any");
|
|
1119
|
+
const hasDifficulty = Boolean(input.difficulty && input.difficulty !== "All");
|
|
1120
|
+
const filter = {};
|
|
1121
|
+
const targetLimit = _nullishCoalesce(input.limit, () => ( 12));
|
|
1122
|
+
const executeQuery = async (pageLimit, nextToken) => {
|
|
1123
|
+
if (hasLanguage) {
|
|
1124
|
+
const rangeKey = hasDifficulty ? `${input.language}#${input.difficulty}#` : `${input.language}#`;
|
|
1125
|
+
const variables = {
|
|
1126
|
+
publicExam: input.publicExam,
|
|
1127
|
+
language_difficulty_createdAt: { beginsWith: rangeKey },
|
|
1128
|
+
sortDirection: _nullishCoalesce(input.sortDirection, () => ( "DESC")),
|
|
1129
|
+
limit: pageLimit,
|
|
1130
|
+
nextToken,
|
|
1131
|
+
...Object.keys(filter).length > 0 ? { filter } : {}
|
|
1132
|
+
};
|
|
1133
|
+
try {
|
|
1134
|
+
const result2 = await this.network.query(
|
|
1135
|
+
`query ListPacksByPublicExamAndLangDiff($publicExam: String!, $language_difficulty_createdAt: ModelStringKeyConditionInput, $sortDirection: ModelSortDirection, $limit: Int, $nextToken: String, $filter: ModelPackFilterInput) {
|
|
1136
|
+
listPackByPublicExamAndLanguage_difficulty_createdAt(publicExam: $publicExam, language_difficulty_createdAt: $language_difficulty_createdAt, sortDirection: $sortDirection, limit: $limit, nextToken: $nextToken, filter: $filter) {
|
|
1137
|
+
items {
|
|
1138
|
+
id name language level publicExam difficulty questionCount owner createdAt verificationStatus subjectId chapterId topicId
|
|
1139
|
+
tags { items { id tagId } }
|
|
1140
|
+
}
|
|
1141
|
+
nextToken
|
|
1142
|
+
}
|
|
1143
|
+
}`,
|
|
1144
|
+
variables
|
|
1145
|
+
);
|
|
1146
|
+
if (_optionalChain([result2, 'access', _15 => _15.data, 'optionalAccess', _16 => _16.listPackByPublicExamAndLanguage_difficulty_createdAt])) {
|
|
1147
|
+
return result2.data.listPackByPublicExamAndLanguage_difficulty_createdAt;
|
|
487
1148
|
}
|
|
488
|
-
|
|
1149
|
+
} catch (e3) {
|
|
489
1150
|
}
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
1151
|
+
}
|
|
1152
|
+
const fallbackFilter = { ...filter };
|
|
1153
|
+
if (hasLanguage) {
|
|
1154
|
+
fallbackFilter.language = { eq: input.language };
|
|
1155
|
+
}
|
|
1156
|
+
if (hasDifficulty) {
|
|
1157
|
+
fallbackFilter.difficulty = { eq: input.difficulty };
|
|
1158
|
+
}
|
|
1159
|
+
try {
|
|
1160
|
+
const variables = {
|
|
1161
|
+
publicExam: input.publicExam,
|
|
1162
|
+
sortDirection: _nullishCoalesce(input.sortDirection, () => ( "DESC")),
|
|
1163
|
+
limit: pageLimit,
|
|
1164
|
+
nextToken,
|
|
1165
|
+
...Object.keys(fallbackFilter).length > 0 ? { filter: fallbackFilter } : {}
|
|
1166
|
+
};
|
|
1167
|
+
const result2 = await this.network.query(
|
|
1168
|
+
`query ListPacksByPublicExam($publicExam: String!, $sortDirection: ModelSortDirection, $limit: Int, $nextToken: String, $filter: ModelPackFilterInput) {
|
|
1169
|
+
listPackByPublicExamAndCreatedAt(publicExam: $publicExam, sortDirection: $sortDirection, limit: $limit, nextToken: $nextToken, filter: $filter) {
|
|
1170
|
+
items {
|
|
1171
|
+
id name language level publicExam difficulty questionCount owner createdAt verificationStatus subjectId chapterId topicId
|
|
1172
|
+
tags { items { id tagId } }
|
|
1173
|
+
}
|
|
1174
|
+
nextToken
|
|
1175
|
+
}
|
|
1176
|
+
}`,
|
|
1177
|
+
variables
|
|
1178
|
+
);
|
|
1179
|
+
if (_optionalChain([result2, 'access', _17 => _17.data, 'optionalAccess', _18 => _18.listPackByPublicExamAndCreatedAt])) {
|
|
1180
|
+
return result2.data.listPackByPublicExamAndCreatedAt;
|
|
1181
|
+
}
|
|
1182
|
+
} catch (e4) {
|
|
1183
|
+
}
|
|
1184
|
+
const scanFilter = {
|
|
1185
|
+
publicExam: { eq: input.publicExam },
|
|
1186
|
+
...fallbackFilter
|
|
1187
|
+
};
|
|
1188
|
+
const result = await this.network.query(
|
|
1189
|
+
`query ListPacksFallback($filter: ModelPackFilterInput, $limit: Int, $nextToken: String) {
|
|
1190
|
+
listPacks(filter: $filter, limit: $limit, nextToken: $nextToken) {
|
|
1191
|
+
items {
|
|
1192
|
+
id name language level publicExam difficulty questionCount owner createdAt verificationStatus subjectId chapterId topicId
|
|
1193
|
+
tags { items { id tagId } }
|
|
1194
|
+
}
|
|
1195
|
+
nextToken
|
|
1196
|
+
}
|
|
1197
|
+
}`,
|
|
1198
|
+
{ filter: scanFilter, limit: pageLimit, nextToken }
|
|
1199
|
+
);
|
|
1200
|
+
return result.data.listPacks;
|
|
1201
|
+
};
|
|
1202
|
+
const hasPostFilter = hasLanguage ? Object.keys(filter).length > 0 : Object.keys(filter).length > 0 || hasLanguage || hasDifficulty;
|
|
1203
|
+
if (!hasPostFilter) {
|
|
1204
|
+
return executeQuery(targetLimit, input.nextToken);
|
|
1205
|
+
}
|
|
1206
|
+
return paginateWithAccumulator(executeQuery, targetLimit, input.nextToken);
|
|
1207
|
+
}
|
|
1208
|
+
async listByLevel(input) {
|
|
1209
|
+
const hasLanguage = Boolean(input.language && input.language !== "All" && input.language !== "Any");
|
|
1210
|
+
const hasDifficulty = Boolean(input.difficulty && input.difficulty !== "All");
|
|
1211
|
+
const filter = {};
|
|
1212
|
+
if (input.publicExam) {
|
|
1213
|
+
filter.publicExam = { eq: input.publicExam };
|
|
1214
|
+
}
|
|
1215
|
+
const targetLimit = _nullishCoalesce(input.limit, () => ( 12));
|
|
1216
|
+
const executeQuery = async (pageLimit, nextToken) => {
|
|
1217
|
+
if (hasLanguage) {
|
|
1218
|
+
const rangeKey = hasDifficulty ? `${input.language}#${input.difficulty}#` : `${input.language}#`;
|
|
1219
|
+
const variables = {
|
|
1220
|
+
level: input.level,
|
|
1221
|
+
language_difficulty_createdAt: { beginsWith: rangeKey },
|
|
1222
|
+
sortDirection: _nullishCoalesce(input.sortDirection, () => ( "DESC")),
|
|
1223
|
+
limit: pageLimit,
|
|
1224
|
+
nextToken,
|
|
1225
|
+
...Object.keys(filter).length > 0 ? { filter } : {}
|
|
1226
|
+
};
|
|
1227
|
+
const result = await this.network.query(
|
|
1228
|
+
`query ListPacksByLevelAndLangDiff($level: String!, $language_difficulty_createdAt: ModelStringKeyConditionInput, $sortDirection: ModelSortDirection, $limit: Int, $nextToken: String, $filter: ModelPackFilterInput) {
|
|
1229
|
+
listPackByLevelAndLanguage_difficulty_createdAt(level: $level, language_difficulty_createdAt: $language_difficulty_createdAt, sortDirection: $sortDirection, limit: $limit, nextToken: $nextToken, filter: $filter) {
|
|
1230
|
+
items {
|
|
1231
|
+
id name language level publicExam difficulty questionCount owner createdAt verificationStatus subjectId chapterId topicId
|
|
1232
|
+
tags { items { id tagId } }
|
|
1233
|
+
}
|
|
1234
|
+
nextToken
|
|
502
1235
|
}
|
|
503
|
-
}
|
|
504
|
-
|
|
505
|
-
|
|
1236
|
+
}`,
|
|
1237
|
+
variables
|
|
1238
|
+
);
|
|
1239
|
+
return result.data.listPackByLevelAndLanguage_difficulty_createdAt;
|
|
1240
|
+
} else {
|
|
1241
|
+
const queryFilter = { ...filter };
|
|
1242
|
+
if (hasDifficulty) {
|
|
1243
|
+
queryFilter.difficulty = { eq: input.difficulty };
|
|
1244
|
+
}
|
|
1245
|
+
const variables = {
|
|
1246
|
+
level: input.level,
|
|
1247
|
+
sortDirection: _nullishCoalesce(input.sortDirection, () => ( "DESC")),
|
|
1248
|
+
limit: pageLimit,
|
|
1249
|
+
nextToken,
|
|
1250
|
+
...Object.keys(queryFilter).length > 0 ? { filter: queryFilter } : {}
|
|
1251
|
+
};
|
|
1252
|
+
const result = await this.network.query(
|
|
1253
|
+
`query ListPacksByLevel($level: String!, $sortDirection: ModelSortDirection, $limit: Int, $nextToken: String, $filter: ModelPackFilterInput) {
|
|
1254
|
+
listPackByLevelAndCreatedAt(level: $level, sortDirection: $sortDirection, limit: $limit, nextToken: $nextToken, filter: $filter) {
|
|
1255
|
+
items {
|
|
1256
|
+
id name language level publicExam difficulty questionCount owner createdAt verificationStatus subjectId chapterId topicId
|
|
1257
|
+
tags { items { id tagId } }
|
|
1258
|
+
}
|
|
1259
|
+
nextToken
|
|
506
1260
|
}
|
|
507
1261
|
}`,
|
|
508
|
-
|
|
1262
|
+
variables
|
|
1263
|
+
);
|
|
1264
|
+
return result.data.listPackByLevelAndCreatedAt;
|
|
1265
|
+
}
|
|
1266
|
+
};
|
|
1267
|
+
const hasPostFilter = hasLanguage ? Object.keys(filter).length > 0 : Object.keys(filter).length > 0 || hasDifficulty;
|
|
1268
|
+
if (!hasPostFilter) {
|
|
1269
|
+
return executeQuery(targetLimit, input.nextToken);
|
|
1270
|
+
}
|
|
1271
|
+
return paginateWithAccumulator(executeQuery, targetLimit, input.nextToken);
|
|
1272
|
+
}
|
|
1273
|
+
async createGroup(input) {
|
|
1274
|
+
const typeLevel = input.type && input.level ? `${input.type}_${input.level}` : void 0;
|
|
1275
|
+
const mutationInput = {
|
|
1276
|
+
name: input.name,
|
|
1277
|
+
description: input.description,
|
|
1278
|
+
imageUrl: input.imageUrl,
|
|
1279
|
+
type: input.type,
|
|
1280
|
+
level: input.level,
|
|
1281
|
+
typeLevel,
|
|
1282
|
+
order: input.order
|
|
1283
|
+
};
|
|
1284
|
+
const result = await this.network.mutate(
|
|
1285
|
+
`mutation CreatePackGroup($input: CreatePackGroupInput!) {
|
|
1286
|
+
createPackGroup(input: $input) {
|
|
1287
|
+
id name description imageUrl type level typeLevel packCount order
|
|
1288
|
+
}
|
|
1289
|
+
}`,
|
|
1290
|
+
{ input: mutationInput }
|
|
509
1291
|
);
|
|
510
|
-
|
|
1292
|
+
const created = result.data.createPackGroup;
|
|
1293
|
+
if (created && input.packIds && input.packIds.length > 0) {
|
|
1294
|
+
await Promise.all(
|
|
1295
|
+
input.packIds.map((pId) => this.update(pId, { packGroupId: created.id }))
|
|
1296
|
+
);
|
|
1297
|
+
}
|
|
1298
|
+
return created;
|
|
1299
|
+
}
|
|
1300
|
+
async deleteGroup(id) {
|
|
1301
|
+
const result = await this.network.mutate(
|
|
1302
|
+
`mutation DeletePackGroup($input: DeletePackGroupInput!) {
|
|
1303
|
+
deletePackGroup(input: $input) {
|
|
1304
|
+
id
|
|
1305
|
+
}
|
|
1306
|
+
}`,
|
|
1307
|
+
{ input: { id } }
|
|
1308
|
+
);
|
|
1309
|
+
return result.data.deletePackGroup;
|
|
1310
|
+
}
|
|
1311
|
+
async listGroups(typeOrInput, level) {
|
|
1312
|
+
let type;
|
|
1313
|
+
let targetLevel;
|
|
1314
|
+
let limit;
|
|
1315
|
+
let nextToken;
|
|
1316
|
+
let sortDirection = "ASC";
|
|
1317
|
+
const isLegacyCall = typeof typeOrInput === "string";
|
|
1318
|
+
if (isLegacyCall) {
|
|
1319
|
+
type = typeOrInput;
|
|
1320
|
+
targetLevel = level;
|
|
1321
|
+
} else {
|
|
1322
|
+
type = _nullishCoalesce(typeOrInput.type, () => ( "QB"));
|
|
1323
|
+
targetLevel = typeOrInput.level;
|
|
1324
|
+
limit = typeOrInput.limit;
|
|
1325
|
+
nextToken = typeOrInput.nextToken;
|
|
1326
|
+
sortDirection = _nullishCoalesce(typeOrInput.sortDirection, () => ( "ASC"));
|
|
1327
|
+
}
|
|
1328
|
+
const queryField = targetLevel ? "listPackGroupByTypeLevelAndOrder" : "listPackGroupByTypeAndOrder";
|
|
1329
|
+
const variables = isLegacyCall ? targetLevel ? { typeLevel: `${type}_${targetLevel}`, sortDirection } : { type, sortDirection } : targetLevel ? { typeLevel: `${type}_${targetLevel}`, sortDirection, limit: _nullishCoalesce(limit, () => ( 20)), nextToken } : { type, sortDirection, limit: _nullishCoalesce(limit, () => ( 20)), nextToken };
|
|
1330
|
+
const queryString = isLegacyCall ? targetLevel ? `query ListPackGroups($typeLevel: String!, $sortDirection: ModelSortDirection) {
|
|
1331
|
+
listPackGroupByTypeLevelAndOrder(typeLevel: $typeLevel, sortDirection: $sortDirection) {
|
|
1332
|
+
items { id name description imageUrl type level typeLevel packCount order }
|
|
1333
|
+
}
|
|
1334
|
+
}` : `query ListPackGroups($type: String!, $sortDirection: ModelSortDirection) {
|
|
1335
|
+
listPackGroupByTypeAndOrder(type: $type, sortDirection: $sortDirection) {
|
|
1336
|
+
items { id name description imageUrl type level typeLevel packCount order }
|
|
1337
|
+
}
|
|
1338
|
+
}` : targetLevel ? `query ListPackGroupsByLevel($typeLevel: String!, $sortDirection: ModelSortDirection, $limit: Int, $nextToken: String) {
|
|
1339
|
+
listPackGroupByTypeLevelAndOrder(typeLevel: $typeLevel, sortDirection: $sortDirection, limit: $limit, nextToken: $nextToken) {
|
|
1340
|
+
items { id name description imageUrl type level typeLevel packCount order }
|
|
1341
|
+
nextToken
|
|
1342
|
+
}
|
|
1343
|
+
}` : `query ListPackGroupsByType($type: String!, $sortDirection: ModelSortDirection, $limit: Int, $nextToken: String) {
|
|
1344
|
+
listPackGroupByTypeAndOrder(type: $type, sortDirection: $sortDirection, limit: $limit, nextToken: $nextToken) {
|
|
1345
|
+
items { id name description imageUrl type level typeLevel packCount order }
|
|
1346
|
+
nextToken
|
|
1347
|
+
}
|
|
1348
|
+
}`;
|
|
1349
|
+
const result = await this.network.query(queryString, variables);
|
|
1350
|
+
const paginated = result.data[queryField];
|
|
1351
|
+
return isLegacyCall ? paginated.items : paginated;
|
|
511
1352
|
}
|
|
512
1353
|
async getGroup(id) {
|
|
513
1354
|
const result = await this.network.query(
|
|
514
1355
|
`query GetPackGroup($id: ID!) {
|
|
515
1356
|
getPackGroup(id: $id) {
|
|
516
1357
|
id name description imageUrl type level typeLevel packCount order
|
|
517
|
-
packs { items { id name language level difficulty questionCount owner createdAt verificationStatus } }
|
|
1358
|
+
packs { items { id name language level publicExam difficulty questionCount owner createdAt verificationStatus } }
|
|
518
1359
|
}
|
|
519
1360
|
}`,
|
|
520
1361
|
{ id }
|
|
521
1362
|
);
|
|
522
1363
|
return result.data.getPackGroup;
|
|
523
1364
|
}
|
|
1365
|
+
async list(input) {
|
|
1366
|
+
const result = await this.network.query(
|
|
1367
|
+
`query ListPacks($limit: Int, $nextToken: String) {
|
|
1368
|
+
listPacks(limit: $limit, nextToken: $nextToken) {
|
|
1369
|
+
items {
|
|
1370
|
+
id name language level publicExam difficulty questionCount owner createdAt verificationStatus packGroupId
|
|
1371
|
+
}
|
|
1372
|
+
nextToken
|
|
1373
|
+
}
|
|
1374
|
+
}`,
|
|
1375
|
+
{ limit: _nullishCoalesce(_optionalChain([input, 'optionalAccess', _19 => _19.limit]), () => ( 20)), nextToken: _optionalChain([input, 'optionalAccess', _20 => _20.nextToken]) }
|
|
1376
|
+
);
|
|
1377
|
+
return result.data.listPacks;
|
|
1378
|
+
}
|
|
524
1379
|
};
|
|
525
1380
|
|
|
526
1381
|
// src/services/contest.service.ts
|
|
@@ -557,7 +1412,7 @@ var ContestService = class {
|
|
|
557
1412
|
`query GetContestName($id: ID!) { getContest(id: $id) { name } }`,
|
|
558
1413
|
{ id }
|
|
559
1414
|
);
|
|
560
|
-
return _nullishCoalesce(_optionalChain([result, 'access',
|
|
1415
|
+
return _nullishCoalesce(_optionalChain([result, 'access', _21 => _21.data, 'access', _22 => _22.getContest, 'optionalAccess', _23 => _23.name]), () => ( null));
|
|
561
1416
|
}
|
|
562
1417
|
async list(nextToken, level) {
|
|
563
1418
|
const variables = level ? { level, sortDirection: "DESC", nextToken } : { globalPk: "ALL", sortDirection: "DESC", nextToken };
|
|
@@ -878,6 +1733,28 @@ var CourseService = class {
|
|
|
878
1733
|
);
|
|
879
1734
|
return result.data.publishCourseLiveExamResults;
|
|
880
1735
|
}
|
|
1736
|
+
async uploadCourseItem(input) {
|
|
1737
|
+
const signed = await this.getSignedURL({
|
|
1738
|
+
courseId: input.courseId,
|
|
1739
|
+
fileName: input.fileName,
|
|
1740
|
+
fileType: input.fileType,
|
|
1741
|
+
parentId: _nullishCoalesce(input.parentId, () => ( void 0))
|
|
1742
|
+
});
|
|
1743
|
+
if (signed && signed.signedURL && input.fileData) {
|
|
1744
|
+
await fetch(signed.signedURL, {
|
|
1745
|
+
method: "PUT",
|
|
1746
|
+
body: input.fileData,
|
|
1747
|
+
headers: { "Content-Type": input.fileType }
|
|
1748
|
+
});
|
|
1749
|
+
}
|
|
1750
|
+
return this.createItem({
|
|
1751
|
+
courseId: input.courseId,
|
|
1752
|
+
name: input.itemName || input.fileName,
|
|
1753
|
+
order: input.itemOrder,
|
|
1754
|
+
type: "file",
|
|
1755
|
+
parentId: _nullishCoalesce(input.parentId, () => ( void 0))
|
|
1756
|
+
});
|
|
1757
|
+
}
|
|
881
1758
|
};
|
|
882
1759
|
|
|
883
1760
|
// src/services/curriculum.service.ts
|
|
@@ -945,6 +1822,67 @@ var CurriculumService = class {
|
|
|
945
1822
|
);
|
|
946
1823
|
return result.data.listTopicByChapterId.items;
|
|
947
1824
|
}
|
|
1825
|
+
async recalculateQuestionCounts() {
|
|
1826
|
+
let nextToken = null;
|
|
1827
|
+
const counts = {};
|
|
1828
|
+
do {
|
|
1829
|
+
const res = await this.network.query(
|
|
1830
|
+
`query ListQuestionsForRecalc($nextToken: String) {
|
|
1831
|
+
listQuestionObjects(limit: 1000, nextToken: $nextToken) {
|
|
1832
|
+
items { id subjectId chapterId topicId }
|
|
1833
|
+
nextToken
|
|
1834
|
+
}
|
|
1835
|
+
}`,
|
|
1836
|
+
{ nextToken }
|
|
1837
|
+
);
|
|
1838
|
+
const items = _optionalChain([res, 'access', _24 => _24.data, 'optionalAccess', _25 => _25.listQuestionObjects, 'optionalAccess', _26 => _26.items]) || [];
|
|
1839
|
+
for (const q of items) {
|
|
1840
|
+
if (q.subjectId) counts[q.subjectId] = (counts[q.subjectId] || 0) + 1;
|
|
1841
|
+
}
|
|
1842
|
+
nextToken = _nullishCoalesce(_optionalChain([res, 'access', _27 => _27.data, 'optionalAccess', _28 => _28.listQuestionObjects, 'optionalAccess', _29 => _29.nextToken]), () => ( null));
|
|
1843
|
+
} while (nextToken);
|
|
1844
|
+
const [hscSubjects, sscSubjects] = await Promise.all([
|
|
1845
|
+
this.getSubjects("HSC").catch(() => []),
|
|
1846
|
+
this.getSubjects("SSC").catch(() => [])
|
|
1847
|
+
]);
|
|
1848
|
+
const allSubjects = [...hscSubjects, ...sscSubjects];
|
|
1849
|
+
for (const s of allSubjects) {
|
|
1850
|
+
await this.network.mutate(
|
|
1851
|
+
`mutation UpdateSubjectCount($input: UpdateSubjectInput!) {
|
|
1852
|
+
updateSubject(input: $input) { id }
|
|
1853
|
+
}`,
|
|
1854
|
+
{ input: { id: s.id, questionCount: counts[s.id] || 0 } }
|
|
1855
|
+
);
|
|
1856
|
+
}
|
|
1857
|
+
}
|
|
1858
|
+
async recalculateCreatorStats() {
|
|
1859
|
+
let nextToken = null;
|
|
1860
|
+
const userQuestionCounts = {};
|
|
1861
|
+
do {
|
|
1862
|
+
const res = await this.network.query(
|
|
1863
|
+
`query ListQuestionsForCreatorStats($nextToken: String) {
|
|
1864
|
+
listQuestionObjects(limit: 1000, nextToken: $nextToken) {
|
|
1865
|
+
items { id owner }
|
|
1866
|
+
nextToken
|
|
1867
|
+
}
|
|
1868
|
+
}`,
|
|
1869
|
+
{ nextToken }
|
|
1870
|
+
);
|
|
1871
|
+
const items = _optionalChain([res, 'access', _30 => _30.data, 'optionalAccess', _31 => _31.listQuestionObjects, 'optionalAccess', _32 => _32.items]) || [];
|
|
1872
|
+
for (const q of items) {
|
|
1873
|
+
if (q.owner) userQuestionCounts[q.owner] = (userQuestionCounts[q.owner] || 0) + 1;
|
|
1874
|
+
}
|
|
1875
|
+
nextToken = _nullishCoalesce(_optionalChain([res, 'access', _33 => _33.data, 'optionalAccess', _34 => _34.listQuestionObjects, 'optionalAccess', _35 => _35.nextToken]), () => ( null));
|
|
1876
|
+
} while (nextToken);
|
|
1877
|
+
for (const [userId, count] of Object.entries(userQuestionCounts)) {
|
|
1878
|
+
await this.network.mutate(
|
|
1879
|
+
`mutation UpdateCreatorStats($input: UpdateUserInput!) {
|
|
1880
|
+
updateUser(input: $input) { id }
|
|
1881
|
+
}`,
|
|
1882
|
+
{ input: { id: userId, questionCount: count } }
|
|
1883
|
+
);
|
|
1884
|
+
}
|
|
1885
|
+
}
|
|
948
1886
|
};
|
|
949
1887
|
|
|
950
1888
|
// src/services/media.service.ts
|
|
@@ -954,13 +1892,34 @@ var MediaService = class {
|
|
|
954
1892
|
this.storage = storage;
|
|
955
1893
|
}
|
|
956
1894
|
async uploadImage(questionId, image) {
|
|
957
|
-
const
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
1895
|
+
const payloadLength = image ? image.length : 0;
|
|
1896
|
+
console.log(`[MediaService.uploadImage] Initiating upload mutation: questionId="${questionId}", payloadLength=${payloadLength} chars`);
|
|
1897
|
+
try {
|
|
1898
|
+
const result = await this.network.mutate(
|
|
1899
|
+
`mutation UploadImage($questionId: ID!, $image: String!) {
|
|
1900
|
+
uploadImage(questionId: $questionId, image: $image) { status imageUrl }
|
|
1901
|
+
}`,
|
|
1902
|
+
{ questionId, image }
|
|
1903
|
+
);
|
|
1904
|
+
if (result.errors && result.errors.length > 0) {
|
|
1905
|
+
console.error(
|
|
1906
|
+
`[MediaService.uploadImage] GraphQL errors returned for questionId "${questionId}":`,
|
|
1907
|
+
JSON.stringify(result.errors, null, 2)
|
|
1908
|
+
);
|
|
1909
|
+
}
|
|
1910
|
+
const response = _optionalChain([result, 'access', _36 => _36.data, 'optionalAccess', _37 => _37.uploadImage]);
|
|
1911
|
+
if (!response) {
|
|
1912
|
+
console.error(`[MediaService.uploadImage] No uploadImage object returned in GraphQL response for questionId "${questionId}". Full result:`, result);
|
|
1913
|
+
} else if (response.status === "Error" || response.status === "error" || !response.imageUrl) {
|
|
1914
|
+
console.error(`[MediaService.uploadImage] Backend returned error status or missing imageUrl for questionId "${questionId}":`, response);
|
|
1915
|
+
} else {
|
|
1916
|
+
console.log(`[MediaService.uploadImage] Upload mutation success for questionId "${questionId}": imageUrl="${response.imageUrl}"`);
|
|
1917
|
+
}
|
|
1918
|
+
return response;
|
|
1919
|
+
} catch (err) {
|
|
1920
|
+
console.error(`[MediaService.uploadImage] Network/GraphQL mutation failed for questionId "${questionId}":`, err);
|
|
1921
|
+
throw err;
|
|
1922
|
+
}
|
|
964
1923
|
}
|
|
965
1924
|
async deleteImage(imageUrl) {
|
|
966
1925
|
const result = await this.network.mutate(
|
|
@@ -1023,123 +1982,423 @@ var ProgressService = class {
|
|
|
1023
1982
|
this.network = network;
|
|
1024
1983
|
}
|
|
1025
1984
|
async track(input) {
|
|
1985
|
+
const variables = {
|
|
1986
|
+
questionId: input.questionId,
|
|
1987
|
+
isCorrect: input.isCorrect,
|
|
1988
|
+
subjectId: _nullishCoalesce(input.subjectId, () => ( null)),
|
|
1989
|
+
chapterId: _nullishCoalesce(input.chapterId, () => ( null)),
|
|
1990
|
+
topicId: _nullishCoalesce(input.topicId, () => ( null))
|
|
1991
|
+
};
|
|
1026
1992
|
const result = await this.network.mutate(
|
|
1027
1993
|
`mutation TrackProgress($questionId: ID!, $isCorrect: Boolean!, $subjectId: ID, $chapterId: ID, $topicId: ID) {
|
|
1028
1994
|
trackPracticeProgress(questionId: $questionId, isCorrect: $isCorrect, subjectId: $subjectId, chapterId: $chapterId, topicId: $topicId) { status }
|
|
1029
1995
|
}`,
|
|
1030
|
-
|
|
1996
|
+
variables
|
|
1031
1997
|
);
|
|
1032
|
-
return result.data.trackPracticeProgress;
|
|
1998
|
+
return _optionalChain([result, 'access', _38 => _38.data, 'optionalAccess', _39 => _39.trackPracticeProgress]) || { status: "success" };
|
|
1033
1999
|
}
|
|
1034
2000
|
async getSubjectProgress(userId) {
|
|
2001
|
+
try {
|
|
2002
|
+
const result = await this.network.query(
|
|
2003
|
+
`query ListSubjectProgress($userId: String!) {
|
|
2004
|
+
listUserSubjectProgressByUserIdAndSubjectId(userId: $userId) {
|
|
2005
|
+
items { id userId subjectId practicedCount mistakeCount correctedCount accuracyScore }
|
|
2006
|
+
}
|
|
2007
|
+
}`,
|
|
2008
|
+
{ userId }
|
|
2009
|
+
);
|
|
2010
|
+
return _optionalChain([result, 'access', _40 => _40.data, 'optionalAccess', _41 => _41.listUserSubjectProgressByUserIdAndSubjectId, 'optionalAccess', _42 => _42.items]) || _optionalChain([result, 'access', _43 => _43.data, 'optionalAccess', _44 => _44.listUserSubjectProgressesByUserIdAndSubjectId, 'optionalAccess', _45 => _45.items]) || [];
|
|
2011
|
+
} catch (e) {
|
|
2012
|
+
console.error("Error fetching subject progress:", e);
|
|
2013
|
+
return [];
|
|
2014
|
+
}
|
|
2015
|
+
}
|
|
2016
|
+
async getChapterProgress(userId) {
|
|
2017
|
+
try {
|
|
2018
|
+
const result = await this.network.query(
|
|
2019
|
+
`query ListChapterProgress($userId: String!) {
|
|
2020
|
+
listUserChapterProgressByUserIdAndChapterId(userId: $userId) {
|
|
2021
|
+
items { id userId chapterId practicedCount mistakeCount correctedCount accuracyScore }
|
|
2022
|
+
}
|
|
2023
|
+
}`,
|
|
2024
|
+
{ userId }
|
|
2025
|
+
);
|
|
2026
|
+
return _optionalChain([result, 'access', _46 => _46.data, 'optionalAccess', _47 => _47.listUserChapterProgressByUserIdAndChapterId, 'optionalAccess', _48 => _48.items]) || _optionalChain([result, 'access', _49 => _49.data, 'optionalAccess', _50 => _50.listUserChapterProgressesByUserIdAndChapterId, 'optionalAccess', _51 => _51.items]) || [];
|
|
2027
|
+
} catch (e) {
|
|
2028
|
+
console.error("Error fetching chapter progress:", e);
|
|
2029
|
+
return [];
|
|
2030
|
+
}
|
|
2031
|
+
}
|
|
2032
|
+
async getTopicProgress(userId) {
|
|
2033
|
+
try {
|
|
2034
|
+
const result = await this.network.query(
|
|
2035
|
+
`query ListTopicProgress($userId: String!) {
|
|
2036
|
+
listUserTopicProgressByUserIdAndTopicId(userId: $userId) {
|
|
2037
|
+
items { id userId topicId practicedCount mistakeCount correctedCount accuracyScore }
|
|
2038
|
+
}
|
|
2039
|
+
}`,
|
|
2040
|
+
{ userId }
|
|
2041
|
+
);
|
|
2042
|
+
return _optionalChain([result, 'access', _52 => _52.data, 'optionalAccess', _53 => _53.listUserTopicProgressByUserIdAndTopicId, 'optionalAccess', _54 => _54.items]) || _optionalChain([result, 'access', _55 => _55.data, 'optionalAccess', _56 => _56.listUserTopicProgressesByUserIdAndTopicId, 'optionalAccess', _57 => _57.items]) || [];
|
|
2043
|
+
} catch (e) {
|
|
2044
|
+
console.error("Error fetching topic progress:", e);
|
|
2045
|
+
return [];
|
|
2046
|
+
}
|
|
2047
|
+
}
|
|
2048
|
+
async getTopicMetrics(userId) {
|
|
2049
|
+
try {
|
|
2050
|
+
const result = await this.network.query(
|
|
2051
|
+
`query ListTopicMetrics($filter: ModelUserTopicMetricFilterInput) {
|
|
2052
|
+
listUserTopicMetrics(filter: $filter) {
|
|
2053
|
+
items { id userId topicId totalAttempted totalCorrect accuracy }
|
|
2054
|
+
}
|
|
2055
|
+
}`,
|
|
2056
|
+
{ filter: { userId: { eq: userId } } }
|
|
2057
|
+
);
|
|
2058
|
+
return _optionalChain([result, 'access', _58 => _58.data, 'optionalAccess', _59 => _59.listUserTopicMetrics, 'optionalAccess', _60 => _60.items]) || [];
|
|
2059
|
+
} catch (e) {
|
|
2060
|
+
console.error("Error fetching topic metrics:", e);
|
|
2061
|
+
return [];
|
|
2062
|
+
}
|
|
2063
|
+
}
|
|
2064
|
+
async getMistakenQuestions(userId, status = "MISTAKE") {
|
|
2065
|
+
try {
|
|
2066
|
+
const result = await this.network.query(
|
|
2067
|
+
`query ListMistakes($userId: String!, $filter: ModelQuestionTrackingFilterInput) {
|
|
2068
|
+
listQuestionTrackingByUserIdAndQuestionId(userId: $userId, filter: $filter) {
|
|
2069
|
+
items { id userId questionId subjectId chapterId topicId status attempts }
|
|
2070
|
+
}
|
|
2071
|
+
}`,
|
|
2072
|
+
{ userId, filter: { status: { eq: status } } }
|
|
2073
|
+
);
|
|
2074
|
+
return _optionalChain([result, 'access', _61 => _61.data, 'optionalAccess', _62 => _62.listQuestionTrackingByUserIdAndQuestionId, 'optionalAccess', _63 => _63.items]) || _optionalChain([result, 'access', _64 => _64.data, 'optionalAccess', _65 => _65.listQuestionTrackingsByUserIdAndQuestionId, 'optionalAccess', _66 => _66.items]) || _optionalChain([result, 'access', _67 => _67.data, 'optionalAccess', _68 => _68.listQuestionTrackings, 'optionalAccess', _69 => _69.items]) || [];
|
|
2075
|
+
} catch (e) {
|
|
2076
|
+
console.error("Error fetching mistaken questions:", e);
|
|
2077
|
+
return [];
|
|
2078
|
+
}
|
|
2079
|
+
}
|
|
2080
|
+
async getCorrectedQuestions(userId) {
|
|
2081
|
+
return this.getMistakenQuestions(userId, "CORRECTED");
|
|
2082
|
+
}
|
|
2083
|
+
};
|
|
2084
|
+
|
|
2085
|
+
// src/services/ai.service.ts
|
|
2086
|
+
var AIService = class {
|
|
2087
|
+
constructor(network) {
|
|
2088
|
+
this.network = network;
|
|
2089
|
+
}
|
|
2090
|
+
async evaluateWrittenAnswer(input, options) {
|
|
2091
|
+
if (_optionalChain([options, 'optionalAccess', _70 => _70.functionUrl])) {
|
|
2092
|
+
try {
|
|
2093
|
+
const headers = { "Content-Type": "application/json" };
|
|
2094
|
+
if (options.authToken) {
|
|
2095
|
+
headers["Authorization"] = `Bearer ${options.authToken}`;
|
|
2096
|
+
}
|
|
2097
|
+
const response = await fetch(options.functionUrl, {
|
|
2098
|
+
method: "POST",
|
|
2099
|
+
headers,
|
|
2100
|
+
body: JSON.stringify(input)
|
|
2101
|
+
});
|
|
2102
|
+
if (response.ok) {
|
|
2103
|
+
const data = await response.json();
|
|
2104
|
+
return data;
|
|
2105
|
+
}
|
|
2106
|
+
console.warn(`[AIService] Function URL failed with status ${response.status}, falling back to GraphQL...`);
|
|
2107
|
+
} catch (err) {
|
|
2108
|
+
console.warn("[AIService] Function URL fetch error, falling back to GraphQL...", err);
|
|
2109
|
+
}
|
|
2110
|
+
}
|
|
1035
2111
|
const result = await this.network.query(
|
|
1036
|
-
`query
|
|
1037
|
-
|
|
1038
|
-
|
|
2112
|
+
`query EvaluateWrittenAnswer($question: String!, $userAnswer: String!, $correctAnswer: String!, $markingInstructions: String, $topicId: String, $topicName: String, $questionImageUrl: String) {
|
|
2113
|
+
evaluateWrittenAnswer(question: $question, userAnswer: $userAnswer, correctAnswer: $correctAnswer, markingInstructions: $markingInstructions, topicId: $topicId, topicName: $topicName, questionImageUrl: $questionImageUrl) {
|
|
2114
|
+
score maxScore feedback isCorrect markingExplanation improvementFeedback subquestions markLocation
|
|
1039
2115
|
}
|
|
1040
2116
|
}`,
|
|
1041
|
-
|
|
2117
|
+
input
|
|
1042
2118
|
);
|
|
1043
|
-
return result.data.
|
|
2119
|
+
return result.data.evaluateWrittenAnswer;
|
|
1044
2120
|
}
|
|
1045
|
-
|
|
2121
|
+
};
|
|
2122
|
+
|
|
2123
|
+
// src/services/news.service.ts
|
|
2124
|
+
var NewsService = class {
|
|
2125
|
+
constructor(network) {
|
|
2126
|
+
this.network = network;
|
|
2127
|
+
}
|
|
2128
|
+
async create(title, content, image, category, excerpt) {
|
|
2129
|
+
const result = await this.network.mutate(
|
|
2130
|
+
`mutation CreateNews($input: CreateNewsArticleInput!) {
|
|
2131
|
+
createNewsArticle(input: $input) { id title content image category excerpt createdAt updatedAt }
|
|
2132
|
+
}`,
|
|
2133
|
+
{ input: { title, content, image, category, excerpt } }
|
|
2134
|
+
);
|
|
2135
|
+
return result.data.createNewsArticle;
|
|
2136
|
+
}
|
|
2137
|
+
async list(nextToken) {
|
|
1046
2138
|
const result = await this.network.query(
|
|
1047
|
-
`query
|
|
1048
|
-
|
|
1049
|
-
items { id
|
|
2139
|
+
`query ListNews($nextToken: String) {
|
|
2140
|
+
listNewsArticles(nextToken: $nextToken) {
|
|
2141
|
+
items { id title content image category excerpt createdAt updatedAt }
|
|
2142
|
+
nextToken
|
|
1050
2143
|
}
|
|
1051
2144
|
}`,
|
|
1052
|
-
{
|
|
2145
|
+
{ nextToken }
|
|
1053
2146
|
);
|
|
1054
|
-
return result.data.
|
|
2147
|
+
return result.data.listNewsArticles;
|
|
1055
2148
|
}
|
|
1056
|
-
async
|
|
2149
|
+
async get(id) {
|
|
1057
2150
|
const result = await this.network.query(
|
|
1058
|
-
`query
|
|
1059
|
-
|
|
1060
|
-
items { id userId topicId practicedCount mistakeCount correctedCount accuracyScore }
|
|
1061
|
-
}
|
|
2151
|
+
`query GetNews($id: ID!) {
|
|
2152
|
+
getNewsArticle(id: $id) { id title content image category excerpt createdAt updatedAt }
|
|
1062
2153
|
}`,
|
|
1063
|
-
{
|
|
2154
|
+
{ id }
|
|
1064
2155
|
);
|
|
1065
|
-
return result.data.
|
|
2156
|
+
return result.data.getNewsArticle;
|
|
1066
2157
|
}
|
|
1067
|
-
|
|
2158
|
+
};
|
|
2159
|
+
|
|
2160
|
+
// src/services/notification.service.ts
|
|
2161
|
+
var NotificationService = class {
|
|
2162
|
+
constructor(network) {
|
|
2163
|
+
this.network = network;
|
|
2164
|
+
}
|
|
2165
|
+
/**
|
|
2166
|
+
* List broadcast announcements (ordered by category and createdAt).
|
|
2167
|
+
*/
|
|
2168
|
+
async listAnnouncements(limit = 20, nextToken) {
|
|
1068
2169
|
const result = await this.network.query(
|
|
1069
|
-
`query
|
|
1070
|
-
|
|
1071
|
-
items {
|
|
2170
|
+
`query ListAnnouncements($limit: Int, $nextToken: String) {
|
|
2171
|
+
listAnnouncements(limit: $limit, nextToken: $nextToken) {
|
|
2172
|
+
items {
|
|
2173
|
+
id title message senderType senderName senderAvatar category actionUrl priority createdAt updatedAt
|
|
2174
|
+
}
|
|
2175
|
+
nextToken
|
|
1072
2176
|
}
|
|
1073
2177
|
}`,
|
|
1074
|
-
{
|
|
2178
|
+
{ limit, nextToken }
|
|
1075
2179
|
);
|
|
1076
|
-
return result.data.
|
|
2180
|
+
return _nullishCoalesce(result.data.listAnnouncements, () => ( { items: [], nextToken: null }));
|
|
1077
2181
|
}
|
|
1078
|
-
|
|
2182
|
+
/**
|
|
2183
|
+
* List announcements by category.
|
|
2184
|
+
*/
|
|
2185
|
+
async listAnnouncementsByCategory(category = "ANNOUNCEMENT", limit = 20, nextToken) {
|
|
1079
2186
|
const result = await this.network.query(
|
|
1080
|
-
`query
|
|
1081
|
-
|
|
1082
|
-
items {
|
|
2187
|
+
`query ListAnnouncementsByCategory($category: String!, $limit: Int, $nextToken: String, $sortDirection: ModelSortDirection) {
|
|
2188
|
+
listAnnouncementByCategoryAndCreatedAt(category: $category, limit: $limit, nextToken: $nextToken, sortDirection: $sortDirection) {
|
|
2189
|
+
items {
|
|
2190
|
+
id title message senderType senderName senderAvatar category actionUrl priority createdAt updatedAt
|
|
2191
|
+
}
|
|
2192
|
+
nextToken
|
|
1083
2193
|
}
|
|
1084
2194
|
}`,
|
|
1085
|
-
{
|
|
2195
|
+
{ category, limit, nextToken, sortDirection: "DESC" }
|
|
1086
2196
|
);
|
|
1087
|
-
return result.data.
|
|
2197
|
+
return _nullishCoalesce(result.data.listAnnouncementByCategoryAndCreatedAt, () => ( {
|
|
2198
|
+
items: [],
|
|
2199
|
+
nextToken: null
|
|
2200
|
+
}));
|
|
1088
2201
|
}
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
2202
|
+
/**
|
|
2203
|
+
* Create an announcement (Admins only).
|
|
2204
|
+
*/
|
|
2205
|
+
async createAnnouncement(input) {
|
|
2206
|
+
const result = await this.network.mutate(
|
|
2207
|
+
`mutation CreateAnnouncement($input: CreateAnnouncementInput!) {
|
|
2208
|
+
createAnnouncement(input: $input) {
|
|
2209
|
+
id title message senderType senderName senderAvatar category actionUrl priority createdAt updatedAt
|
|
2210
|
+
}
|
|
2211
|
+
}`,
|
|
2212
|
+
{
|
|
2213
|
+
input: {
|
|
2214
|
+
...input,
|
|
2215
|
+
senderType: input.senderType || "ORJOK",
|
|
2216
|
+
category: input.category || "ANNOUNCEMENT",
|
|
2217
|
+
priority: input.priority || "NORMAL"
|
|
2218
|
+
}
|
|
2219
|
+
}
|
|
2220
|
+
);
|
|
2221
|
+
return result.data.createAnnouncement;
|
|
1095
2222
|
}
|
|
1096
|
-
|
|
2223
|
+
/**
|
|
2224
|
+
* Delete an announcement (Admins only).
|
|
2225
|
+
*/
|
|
2226
|
+
async deleteAnnouncement(id) {
|
|
2227
|
+
const result = await this.network.mutate(
|
|
2228
|
+
`mutation DeleteAnnouncement($input: DeleteAnnouncementInput!) {
|
|
2229
|
+
deleteAnnouncement(input: $input) { id }
|
|
2230
|
+
}`,
|
|
2231
|
+
{ input: { id } }
|
|
2232
|
+
);
|
|
2233
|
+
return Boolean(_optionalChain([result, 'access', _71 => _71.data, 'access', _72 => _72.deleteAnnouncement, 'optionalAccess', _73 => _73.id]));
|
|
2234
|
+
}
|
|
2235
|
+
/**
|
|
2236
|
+
* List user notifications for a specific user ID.
|
|
2237
|
+
*/
|
|
2238
|
+
async listUserNotifications(userId, limit = 20, nextToken) {
|
|
1097
2239
|
const result = await this.network.query(
|
|
1098
|
-
`query
|
|
1099
|
-
|
|
1100
|
-
|
|
2240
|
+
`query ListUserNotifications($userId: ID!, $limit: Int, $nextToken: String, $sortDirection: ModelSortDirection) {
|
|
2241
|
+
listUserNotificationByUserIdAndCreatedAt(userId: $userId, limit: $limit, nextToken: $nextToken, sortDirection: $sortDirection) {
|
|
2242
|
+
items {
|
|
2243
|
+
id userId title message type senderType senderName senderAvatar actionUrl isRead readAt metadata createdAt updatedAt
|
|
2244
|
+
}
|
|
2245
|
+
nextToken
|
|
2246
|
+
}
|
|
2247
|
+
}`,
|
|
2248
|
+
{ userId, limit, nextToken, sortDirection: "DESC" }
|
|
2249
|
+
);
|
|
2250
|
+
return _nullishCoalesce(result.data.listUserNotificationByUserIdAndCreatedAt, () => ( {
|
|
2251
|
+
items: [],
|
|
2252
|
+
nextToken: null
|
|
2253
|
+
}));
|
|
2254
|
+
}
|
|
2255
|
+
/**
|
|
2256
|
+
* Create a user notification (Level up, direct message, system alert).
|
|
2257
|
+
*/
|
|
2258
|
+
async createUserNotification(input) {
|
|
2259
|
+
const result = await this.network.mutate(
|
|
2260
|
+
`mutation CreateUserNotification($input: CreateUserNotificationInput!) {
|
|
2261
|
+
createUserNotification(input: $input) {
|
|
2262
|
+
id userId title message type senderType senderName senderAvatar actionUrl isRead readAt metadata createdAt updatedAt
|
|
2263
|
+
}
|
|
2264
|
+
}`,
|
|
2265
|
+
{
|
|
2266
|
+
input: {
|
|
2267
|
+
...input,
|
|
2268
|
+
isRead: false
|
|
2269
|
+
}
|
|
2270
|
+
}
|
|
2271
|
+
);
|
|
2272
|
+
return result.data.createUserNotification;
|
|
2273
|
+
}
|
|
2274
|
+
/**
|
|
2275
|
+
* Mark a personal notification as read.
|
|
2276
|
+
*/
|
|
2277
|
+
async markNotificationAsRead(id) {
|
|
2278
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
2279
|
+
const result = await this.network.mutate(
|
|
2280
|
+
`mutation UpdateUserNotification($input: UpdateUserNotificationInput!) {
|
|
2281
|
+
updateUserNotification(input: $input) {
|
|
2282
|
+
id isRead readAt
|
|
1101
2283
|
}
|
|
1102
2284
|
}`,
|
|
1103
|
-
|
|
2285
|
+
{
|
|
2286
|
+
input: {
|
|
2287
|
+
id,
|
|
2288
|
+
isRead: true,
|
|
2289
|
+
readAt: now
|
|
2290
|
+
}
|
|
2291
|
+
}
|
|
2292
|
+
);
|
|
2293
|
+
return result.data.updateUserNotification;
|
|
2294
|
+
}
|
|
2295
|
+
/**
|
|
2296
|
+
* Delete a personal user notification.
|
|
2297
|
+
*/
|
|
2298
|
+
async deleteUserNotification(id) {
|
|
2299
|
+
const result = await this.network.mutate(
|
|
2300
|
+
`mutation DeleteUserNotification($input: DeleteUserNotificationInput!) {
|
|
2301
|
+
deleteUserNotification(input: $input) { id }
|
|
2302
|
+
}`,
|
|
2303
|
+
{ input: { id } }
|
|
2304
|
+
);
|
|
2305
|
+
return Boolean(_optionalChain([result, 'access', _74 => _74.data, 'access', _75 => _75.deleteUserNotification, 'optionalAccess', _76 => _76.id]));
|
|
2306
|
+
}
|
|
2307
|
+
/**
|
|
2308
|
+
* Update the user's lastReadAnnouncementAt timestamp in DynamoDB.
|
|
2309
|
+
*/
|
|
2310
|
+
async updateLastReadAnnouncement(userId, timestamp = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
2311
|
+
const result = await this.network.mutate(
|
|
2312
|
+
`mutation UpdateUserLastRead($input: UpdateUserInput!) {
|
|
2313
|
+
updateUser(input: $input) { id lastReadAnnouncementAt }
|
|
2314
|
+
}`,
|
|
2315
|
+
{ input: { id: userId, lastReadAnnouncementAt: timestamp } }
|
|
1104
2316
|
);
|
|
1105
|
-
return result.data.
|
|
2317
|
+
return Boolean(_optionalChain([result, 'access', _77 => _77.data, 'access', _78 => _78.updateUser, 'optionalAccess', _79 => _79.id]));
|
|
1106
2318
|
}
|
|
1107
2319
|
};
|
|
1108
2320
|
|
|
1109
|
-
// src/services/
|
|
1110
|
-
var
|
|
2321
|
+
// src/services/subscription.service.ts
|
|
2322
|
+
var SubscriptionService = class {
|
|
1111
2323
|
constructor(network) {
|
|
1112
2324
|
this.network = network;
|
|
1113
2325
|
}
|
|
1114
|
-
async
|
|
2326
|
+
async createRequest(input) {
|
|
1115
2327
|
const result = await this.network.mutate(
|
|
1116
|
-
`mutation
|
|
1117
|
-
|
|
2328
|
+
`mutation CreateSubscriptionRequest($input: CreateSubscriptionRequestInput!) {
|
|
2329
|
+
createSubscriptionRequest(input: $input) {
|
|
2330
|
+
id userId userFullName userEmail itemType itemId itemTitle amount billingCycle paymentMethod senderPhone contactPhone trxId status aiEvals aiQuestions adminNotes processedAt processedBy createdAt updatedAt
|
|
2331
|
+
}
|
|
1118
2332
|
}`,
|
|
1119
|
-
{ input
|
|
2333
|
+
{ input }
|
|
1120
2334
|
);
|
|
1121
|
-
return result.data.
|
|
2335
|
+
return result.data.createSubscriptionRequest;
|
|
1122
2336
|
}
|
|
1123
|
-
async
|
|
2337
|
+
async getRequest(id) {
|
|
1124
2338
|
const result = await this.network.query(
|
|
1125
|
-
`query
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
nextToken
|
|
2339
|
+
`query GetSubscriptionRequest($id: ID!) {
|
|
2340
|
+
getSubscriptionRequest(id: $id) {
|
|
2341
|
+
id userId userFullName userEmail itemType itemId itemTitle amount billingCycle paymentMethod senderPhone contactPhone trxId status aiEvals aiQuestions adminNotes processedAt processedBy createdAt updatedAt
|
|
1129
2342
|
}
|
|
1130
2343
|
}`,
|
|
1131
|
-
{
|
|
2344
|
+
{ id }
|
|
1132
2345
|
);
|
|
1133
|
-
return result.data.
|
|
2346
|
+
return result.data.getSubscriptionRequest;
|
|
1134
2347
|
}
|
|
1135
|
-
async
|
|
2348
|
+
async listRequests(input = {}) {
|
|
2349
|
+
const limit = _nullishCoalesce(input.limit, () => ( 20));
|
|
2350
|
+
const sortDirection = _nullishCoalesce(input.sortDirection, () => ( "DESC"));
|
|
2351
|
+
if (input.status) {
|
|
2352
|
+
const result2 = await this.network.query(
|
|
2353
|
+
`query ListSubscriptionRequestsByStatus($status: String!, $sortDirection: ModelSortDirection, $limit: Int, $nextToken: String) {
|
|
2354
|
+
listSubscriptionRequestByStatusAndCreatedAt(status: $status, sortDirection: $sortDirection, limit: $limit, nextToken: $nextToken) {
|
|
2355
|
+
items {
|
|
2356
|
+
id userId userFullName userEmail itemType itemId itemTitle amount billingCycle paymentMethod senderPhone contactPhone trxId status aiEvals aiQuestions adminNotes processedAt processedBy createdAt updatedAt
|
|
2357
|
+
}
|
|
2358
|
+
nextToken
|
|
2359
|
+
}
|
|
2360
|
+
}`,
|
|
2361
|
+
{ status: input.status, sortDirection, limit, nextToken: input.nextToken }
|
|
2362
|
+
);
|
|
2363
|
+
return result2.data.listSubscriptionRequestByStatusAndCreatedAt;
|
|
2364
|
+
}
|
|
2365
|
+
if (input.userId) {
|
|
2366
|
+
const result2 = await this.network.query(
|
|
2367
|
+
`query ListSubscriptionRequestsByUser($userId: String!, $sortDirection: ModelSortDirection, $limit: Int, $nextToken: String) {
|
|
2368
|
+
listSubscriptionRequestByUserIdAndCreatedAt(userId: $userId, sortDirection: $sortDirection, limit: $limit, nextToken: $nextToken) {
|
|
2369
|
+
items {
|
|
2370
|
+
id userId userFullName userEmail itemType itemId itemTitle amount billingCycle paymentMethod senderPhone contactPhone trxId status aiEvals aiQuestions adminNotes processedAt processedBy createdAt updatedAt
|
|
2371
|
+
}
|
|
2372
|
+
nextToken
|
|
2373
|
+
}
|
|
2374
|
+
}`,
|
|
2375
|
+
{ userId: input.userId, sortDirection, limit, nextToken: input.nextToken }
|
|
2376
|
+
);
|
|
2377
|
+
return result2.data.listSubscriptionRequestByUserIdAndCreatedAt;
|
|
2378
|
+
}
|
|
1136
2379
|
const result = await this.network.query(
|
|
1137
|
-
`query
|
|
1138
|
-
|
|
2380
|
+
`query ListAllSubscriptionRequests($limit: Int, $nextToken: String, $filter: ModelSubscriptionRequestFilterInput) {
|
|
2381
|
+
listSubscriptionRequests(limit: $limit, nextToken: $nextToken, filter: $filter) {
|
|
2382
|
+
items {
|
|
2383
|
+
id userId userFullName userEmail itemType itemId itemTitle amount billingCycle paymentMethod senderPhone contactPhone trxId status aiEvals aiQuestions adminNotes processedAt processedBy createdAt updatedAt
|
|
2384
|
+
}
|
|
2385
|
+
nextToken
|
|
2386
|
+
}
|
|
1139
2387
|
}`,
|
|
1140
|
-
{
|
|
2388
|
+
{ limit, nextToken: input.nextToken, filter: input.filter }
|
|
1141
2389
|
);
|
|
1142
|
-
return result.data.
|
|
2390
|
+
return result.data.listSubscriptionRequests;
|
|
2391
|
+
}
|
|
2392
|
+
async updateRequest(input) {
|
|
2393
|
+
const result = await this.network.mutate(
|
|
2394
|
+
`mutation UpdateSubscriptionRequest($input: UpdateSubscriptionRequestInput!) {
|
|
2395
|
+
updateSubscriptionRequest(input: $input) {
|
|
2396
|
+
id userId userFullName userEmail itemType itemId itemTitle amount billingCycle paymentMethod senderPhone contactPhone trxId status aiEvals aiQuestions adminNotes processedAt processedBy createdAt updatedAt
|
|
2397
|
+
}
|
|
2398
|
+
}`,
|
|
2399
|
+
{ input }
|
|
2400
|
+
);
|
|
2401
|
+
return result.data.updateSubscriptionRequest;
|
|
1143
2402
|
}
|
|
1144
2403
|
};
|
|
1145
2404
|
|
|
@@ -1147,6 +2406,8 @@ var NewsService = class {
|
|
|
1147
2406
|
var OrjokClient = class {
|
|
1148
2407
|
constructor(config) {
|
|
1149
2408
|
this.auth = config.authProvider;
|
|
2409
|
+
this.network = config.networkProvider;
|
|
2410
|
+
this.storage = config.storageProvider;
|
|
1150
2411
|
this.users = new UserService(config.networkProvider);
|
|
1151
2412
|
this.questions = new QuestionService(config.networkProvider);
|
|
1152
2413
|
this.packs = new PackService(config.networkProvider);
|
|
@@ -1157,12 +2418,218 @@ var OrjokClient = class {
|
|
|
1157
2418
|
this.progress = new ProgressService(config.networkProvider);
|
|
1158
2419
|
this.ai = new AIService(config.networkProvider);
|
|
1159
2420
|
this.news = new NewsService(config.networkProvider);
|
|
2421
|
+
this.notifications = new NotificationService(config.networkProvider);
|
|
2422
|
+
this.subscriptions = new SubscriptionService(config.networkProvider);
|
|
1160
2423
|
}
|
|
1161
2424
|
};
|
|
1162
2425
|
function createOrjokClient(config) {
|
|
1163
2426
|
return new OrjokClient(config);
|
|
1164
2427
|
}
|
|
1165
2428
|
|
|
2429
|
+
// src/logic/avatar.ts
|
|
2430
|
+
var HAIR_COLORS = [
|
|
2431
|
+
{ name: "Original", filter: "none", hex: "#e2e8f0", brightness: 1 },
|
|
2432
|
+
{ name: "White", filter: "grayscale(100%) brightness(500%)", hex: "#ffffff", brightness: 2 },
|
|
2433
|
+
{ name: "Black", filter: "grayscale(100%) brightness(40%)", hex: "#1a202c", brightness: 0.15 },
|
|
2434
|
+
{ name: "Brown", filter: "sepia(100%) saturate(300%) hue-rotate(330deg) brightness(80%)", hex: "#7b3f00", brightness: 0.35 },
|
|
2435
|
+
{ name: "Blonde", filter: "sepia(100%) saturate(400%) hue-rotate(20deg) brightness(130%)", hex: "#e6c27a", brightness: 0.8 },
|
|
2436
|
+
{ name: "Red", filter: "sepia(100%) saturate(500%) hue-rotate(320deg) brightness(90%)", hex: "#9b2c2c", brightness: 0.4 },
|
|
2437
|
+
{ name: "Blue", filter: "sepia(100%) saturate(500%) hue-rotate(180deg) brightness(90%)", hex: "#2b6cb0", brightness: 0.4 },
|
|
2438
|
+
{ name: "Green", filter: "sepia(100%) saturate(400%) hue-rotate(80deg) brightness(90%)", hex: "#2f855a", brightness: 0.45 }
|
|
2439
|
+
];
|
|
2440
|
+
var CLOTHES_COLORS = [
|
|
2441
|
+
{ name: "Original", filter: "none", hex: "#e2e8f0", brightness: 1 },
|
|
2442
|
+
{ name: "White", filter: "grayscale(100%) brightness(500%)", hex: "#ffffff", brightness: 2 },
|
|
2443
|
+
{ name: "Black", filter: "grayscale(100%) brightness(30%)", hex: "#1a202c", brightness: 0.12 },
|
|
2444
|
+
{ name: "Red", filter: "sepia(100%) saturate(500%) hue-rotate(320deg)", hex: "#c53030", brightness: 0.45 },
|
|
2445
|
+
{ name: "Orange", filter: "sepia(100%) saturate(500%) hue-rotate(350deg)", hex: "#dd6b20", brightness: 0.55 },
|
|
2446
|
+
{ name: "Yellow", filter: "sepia(100%) saturate(500%) hue-rotate(20deg) brightness(120%)", hex: "#d69e2e", brightness: 0.8 },
|
|
2447
|
+
{ name: "Green", filter: "sepia(100%) saturate(500%) hue-rotate(80deg)", hex: "#38a169", brightness: 0.55 },
|
|
2448
|
+
{ name: "Blue", filter: "sepia(100%) saturate(500%) hue-rotate(180deg)", hex: "#3182ce", brightness: 0.45 },
|
|
2449
|
+
{ name: "Purple", filter: "sepia(100%) saturate(500%) hue-rotate(240deg)", hex: "#805ad5", brightness: 0.45 },
|
|
2450
|
+
{ name: "Pink", filter: "sepia(100%) saturate(400%) hue-rotate(290deg)", hex: "#d53f8c", brightness: 0.55 }
|
|
2451
|
+
];
|
|
2452
|
+
var COLOR_HUES = {
|
|
2453
|
+
Original: 0,
|
|
2454
|
+
Red: 0,
|
|
2455
|
+
Orange: 24,
|
|
2456
|
+
Yellow: 45,
|
|
2457
|
+
Green: 140,
|
|
2458
|
+
Blue: 210,
|
|
2459
|
+
Purple: 270,
|
|
2460
|
+
Pink: 320,
|
|
2461
|
+
Brown: 25,
|
|
2462
|
+
Blonde: 45
|
|
2463
|
+
};
|
|
2464
|
+
var RENDER_ORDER = [
|
|
2465
|
+
"Background",
|
|
2466
|
+
"Hair Back",
|
|
2467
|
+
"Clothes Back",
|
|
2468
|
+
"Skin Color Body",
|
|
2469
|
+
"Clothes Front",
|
|
2470
|
+
"Skin Color Head",
|
|
2471
|
+
"Accessories",
|
|
2472
|
+
"Facial Expression",
|
|
2473
|
+
"Beard",
|
|
2474
|
+
"Hair Front",
|
|
2475
|
+
"Eyewear",
|
|
2476
|
+
"Headwears"
|
|
2477
|
+
];
|
|
2478
|
+
var INITIAL_AVATAR_DATA = {
|
|
2479
|
+
Background: [],
|
|
2480
|
+
Hair: [],
|
|
2481
|
+
"Skin Color": [],
|
|
2482
|
+
Clothes: [],
|
|
2483
|
+
Accessories: [],
|
|
2484
|
+
Headwears: [],
|
|
2485
|
+
Eyewear: [],
|
|
2486
|
+
"Facial Expression": [],
|
|
2487
|
+
Beard: []
|
|
2488
|
+
};
|
|
2489
|
+
function getActualOptionFileName(category, baseName, config, selections) {
|
|
2490
|
+
if (baseName === "None") return null;
|
|
2491
|
+
const items = config[category] || [];
|
|
2492
|
+
const matched = items.filter((item) => item.base_name === baseName);
|
|
2493
|
+
if (matched.length === 0) return null;
|
|
2494
|
+
for (const item of matched) {
|
|
2495
|
+
if (item.conditions && item.conditions.length > 0) {
|
|
2496
|
+
const allMet = item.conditions.every((cond) => {
|
|
2497
|
+
return Object.values(selections).some(
|
|
2498
|
+
(sel) => sel && (sel.includes(cond) || cond.includes(sel))
|
|
2499
|
+
);
|
|
2500
|
+
});
|
|
2501
|
+
if (allMet) return item;
|
|
2502
|
+
}
|
|
2503
|
+
}
|
|
2504
|
+
return matched.find((item) => !item.conditions || item.conditions.length === 0) || matched[0] || null;
|
|
2505
|
+
}
|
|
2506
|
+
function parseAvatarConfig(configStr) {
|
|
2507
|
+
if (!configStr) {
|
|
2508
|
+
return { selections: {}, colors: {} };
|
|
2509
|
+
}
|
|
2510
|
+
try {
|
|
2511
|
+
const parsed = JSON.parse(configStr);
|
|
2512
|
+
return {
|
|
2513
|
+
selections: parsed.selections || {},
|
|
2514
|
+
colors: parsed.colors || {},
|
|
2515
|
+
gender: parsed.gender
|
|
2516
|
+
};
|
|
2517
|
+
} catch (e5) {
|
|
2518
|
+
return { selections: {}, colors: {} };
|
|
2519
|
+
}
|
|
2520
|
+
}
|
|
2521
|
+
function parseAvatarConfigWithDefaults(configStr, seed) {
|
|
2522
|
+
const parsed = parseAvatarConfig(configStr);
|
|
2523
|
+
const hasSelections = Object.keys(parsed.selections).length > 0;
|
|
2524
|
+
if (!hasSelections) {
|
|
2525
|
+
return generateRandomAvatarState({ seed });
|
|
2526
|
+
}
|
|
2527
|
+
return {
|
|
2528
|
+
selections: { ...parsed.selections },
|
|
2529
|
+
colors: { ...parsed.colors },
|
|
2530
|
+
gender: parsed.gender
|
|
2531
|
+
};
|
|
2532
|
+
}
|
|
2533
|
+
function serializeAvatarConfig(state) {
|
|
2534
|
+
return JSON.stringify(state);
|
|
2535
|
+
}
|
|
2536
|
+
function createSeededRandom(seedStr) {
|
|
2537
|
+
let h = 1779033703 ^ seedStr.length;
|
|
2538
|
+
for (let i = 0; i < seedStr.length; i++) {
|
|
2539
|
+
h = Math.imul(h ^ seedStr.charCodeAt(i), 3432918353);
|
|
2540
|
+
h = h << 13 | h >>> 19;
|
|
2541
|
+
}
|
|
2542
|
+
return () => {
|
|
2543
|
+
h = Math.imul(h ^ h >>> 16, 2246822507);
|
|
2544
|
+
h = Math.imul(h ^ h >>> 13, 3266489909);
|
|
2545
|
+
return ((h ^= h >>> 16) >>> 0) / 4294967296;
|
|
2546
|
+
};
|
|
2547
|
+
}
|
|
2548
|
+
function pickRandom(arr, fallback, rng = Math.random) {
|
|
2549
|
+
if (arr.length === 0) return fallback;
|
|
2550
|
+
const item = arr[Math.floor(rng() * arr.length)];
|
|
2551
|
+
return item !== void 0 ? item : fallback;
|
|
2552
|
+
}
|
|
2553
|
+
function generateRandomAvatarState(options) {
|
|
2554
|
+
const rng = _optionalChain([options, 'optionalAccess', _80 => _80.seed]) ? createSeededRandom(options.seed) : Math.random;
|
|
2555
|
+
const gender = _optionalChain([options, 'optionalAccess', _81 => _81.gender]) || (rng() > 0.5 ? "Male" : "Female");
|
|
2556
|
+
const backgrounds = ["Solid", "3 Stripes"];
|
|
2557
|
+
const skinColors = [
|
|
2558
|
+
"Light Peach",
|
|
2559
|
+
"Warm Peach",
|
|
2560
|
+
"Golden Tan",
|
|
2561
|
+
"Sand Beige",
|
|
2562
|
+
"Warm Brown",
|
|
2563
|
+
"Deep Brown"
|
|
2564
|
+
];
|
|
2565
|
+
const maleHairs = ["Clean", "Mid", "Curled", "Bald"];
|
|
2566
|
+
const femaleHairs = ["Bun", "Long", "Mid", "Short"];
|
|
2567
|
+
const clothesList = ["Tshirt", "Hoodie", "Turtleneck"];
|
|
2568
|
+
const expressions = ["Normal", "Happy", "Joyful", "Playful", "Surprised"];
|
|
2569
|
+
const eywears = ["None", "None", "None", "None", "Normal Glasses"];
|
|
2570
|
+
const headwears = ["None", "None", "None", "None", "Beanie", "HeadPhones"];
|
|
2571
|
+
const hairList = gender === "Male" ? maleHairs : femaleHairs;
|
|
2572
|
+
const bg = pickRandom(backgrounds, "Solid", rng);
|
|
2573
|
+
const skin = pickRandom(skinColors, "Light Peach", rng);
|
|
2574
|
+
const hair = pickRandom(hairList, gender === "Male" ? "Clean" : "Short", rng);
|
|
2575
|
+
const clothes = pickRandom(clothesList, "Tshirt", rng);
|
|
2576
|
+
const expression = pickRandom(expressions, "Normal", rng);
|
|
2577
|
+
const eyewear = pickRandom(eywears, "None", rng);
|
|
2578
|
+
const headwear = pickRandom(headwears, "None", rng);
|
|
2579
|
+
const hairColorPool = [
|
|
2580
|
+
"Black",
|
|
2581
|
+
"Black",
|
|
2582
|
+
"Brown",
|
|
2583
|
+
"Brown",
|
|
2584
|
+
"Blonde",
|
|
2585
|
+
"White",
|
|
2586
|
+
"Red",
|
|
2587
|
+
"Blue"
|
|
2588
|
+
];
|
|
2589
|
+
const hairColor = pickRandom(hairColorPool, "Black", rng);
|
|
2590
|
+
const clothesColorPool = [
|
|
2591
|
+
"Blue",
|
|
2592
|
+
"Red",
|
|
2593
|
+
"Green",
|
|
2594
|
+
"Orange",
|
|
2595
|
+
"Purple",
|
|
2596
|
+
"Black",
|
|
2597
|
+
"Yellow",
|
|
2598
|
+
"Pink"
|
|
2599
|
+
];
|
|
2600
|
+
const clothesColor = pickRandom(clothesColorPool, "Blue", rng);
|
|
2601
|
+
const bgColorPool = ["Blue", "Green", "Purple", "Orange", "Red", "Pink", "Original"];
|
|
2602
|
+
const bgColor = pickRandom(bgColorPool, "Blue", rng);
|
|
2603
|
+
return {
|
|
2604
|
+
selections: {
|
|
2605
|
+
Background: bg,
|
|
2606
|
+
"Hair Back": hair,
|
|
2607
|
+
"Skin Color": skin,
|
|
2608
|
+
"Clothes Back": clothes,
|
|
2609
|
+
"Clothes Front": clothes,
|
|
2610
|
+
Accessories: "None",
|
|
2611
|
+
Headwears: headwear,
|
|
2612
|
+
Eyewear: eyewear,
|
|
2613
|
+
"Facial Expression": expression,
|
|
2614
|
+
Beard: "None",
|
|
2615
|
+
"Hair Front": hair
|
|
2616
|
+
},
|
|
2617
|
+
colors: {
|
|
2618
|
+
"Background Color": bgColor,
|
|
2619
|
+
"Hair Color": hairColor,
|
|
2620
|
+
"Clothes Color": clothesColor,
|
|
2621
|
+
"Accessory Color": "Original",
|
|
2622
|
+
"Headwears Color": "Original",
|
|
2623
|
+
"Eyewear Color": "Original",
|
|
2624
|
+
"Facial Expression Color": "Original"
|
|
2625
|
+
},
|
|
2626
|
+
gender
|
|
2627
|
+
};
|
|
2628
|
+
}
|
|
2629
|
+
function generateRandomAvatarConfig(options) {
|
|
2630
|
+
return JSON.stringify(generateRandomAvatarState(options));
|
|
2631
|
+
}
|
|
2632
|
+
|
|
1166
2633
|
// src/logic/elo.ts
|
|
1167
2634
|
var TIERS = [
|
|
1168
2635
|
{ name: "Iron", minRating: 0, maxRating: 799, color: "#6B7280" },
|
|
@@ -1263,6 +2730,246 @@ function detectQuestionType(option2, option3, option4) {
|
|
|
1263
2730
|
}
|
|
1264
2731
|
return "MCQ";
|
|
1265
2732
|
}
|
|
2733
|
+
function isCorrectAnswer(selected, correct) {
|
|
2734
|
+
if (!selected || !correct) return false;
|
|
2735
|
+
const selTrim = String(selected).trim();
|
|
2736
|
+
const corrTrim = String(correct).trim();
|
|
2737
|
+
if (selTrim === corrTrim) return true;
|
|
2738
|
+
const selNum = Number(selTrim);
|
|
2739
|
+
const corrNum = Number(corrTrim);
|
|
2740
|
+
if (!isNaN(selNum) && !isNaN(corrNum) && selNum === corrNum) {
|
|
2741
|
+
return true;
|
|
2742
|
+
}
|
|
2743
|
+
return false;
|
|
2744
|
+
}
|
|
2745
|
+
function calculateDefaultExamMinutes(mode, questions) {
|
|
2746
|
+
const mcqCount = questions.filter((q) => q.type !== "WRITTEN").length;
|
|
2747
|
+
const writtenCount = questions.filter((q) => q.type === "WRITTEN").length;
|
|
2748
|
+
if (mode === "MCQ") return Math.max(1, mcqCount * 1);
|
|
2749
|
+
if (mode === "WRITTEN") return Math.max(1, writtenCount * 10);
|
|
2750
|
+
return Math.max(1, mcqCount * 1 + writtenCount * 10);
|
|
2751
|
+
}
|
|
2752
|
+
function reorderObjectKeys(obj, oldIndex, newIndex, length) {
|
|
2753
|
+
const arr = [];
|
|
2754
|
+
for (let i = 0; i < length; i++) {
|
|
2755
|
+
arr.push(obj[i]);
|
|
2756
|
+
}
|
|
2757
|
+
const [movedItem] = arr.splice(oldIndex, 1);
|
|
2758
|
+
arr.splice(newIndex, 0, movedItem);
|
|
2759
|
+
const newObj = {};
|
|
2760
|
+
arr.forEach((item, idx) => {
|
|
2761
|
+
if (item !== void 0) {
|
|
2762
|
+
newObj[idx] = item;
|
|
2763
|
+
}
|
|
2764
|
+
});
|
|
2765
|
+
return newObj;
|
|
2766
|
+
}
|
|
2767
|
+
|
|
2768
|
+
// src/logic/home.ts
|
|
2769
|
+
function mapCognitoLevelToStandardLevel(cognitoLevel) {
|
|
2770
|
+
if (!cognitoLevel) return "HSC+Admission";
|
|
2771
|
+
const normalized = cognitoLevel.trim().toLowerCase();
|
|
2772
|
+
if (normalized === "class_9" || normalized === "class_10" || normalized === "ssc") {
|
|
2773
|
+
return "SSC";
|
|
2774
|
+
}
|
|
2775
|
+
if (normalized === "class_11" || normalized === "class_12" || normalized === "admission" || normalized === "hsc" || normalized === "hsc+admission") {
|
|
2776
|
+
return "HSC+Admission";
|
|
2777
|
+
}
|
|
2778
|
+
if (normalized === "bcs" || normalized === "job") {
|
|
2779
|
+
return "BCS";
|
|
2780
|
+
}
|
|
2781
|
+
return "HSC+Admission";
|
|
2782
|
+
}
|
|
2783
|
+
function getTimeOfDayGreeting(customHour, lang = "en") {
|
|
2784
|
+
const hour = customHour !== void 0 ? customHour : (/* @__PURE__ */ new Date()).getHours();
|
|
2785
|
+
if (hour >= 5 && hour < 12) {
|
|
2786
|
+
return {
|
|
2787
|
+
greeting: lang === "bn" ? "\u09B6\u09C1\u09AD \u09B8\u0995\u09BE\u09B2" : "Good morning",
|
|
2788
|
+
period: "morning"
|
|
2789
|
+
};
|
|
2790
|
+
}
|
|
2791
|
+
if (hour >= 12 && hour < 17) {
|
|
2792
|
+
return {
|
|
2793
|
+
greeting: lang === "bn" ? "\u09B6\u09C1\u09AD \u09A6\u09C1\u09AA\u09C1\u09B0" : "Good afternoon",
|
|
2794
|
+
period: "afternoon"
|
|
2795
|
+
};
|
|
2796
|
+
}
|
|
2797
|
+
if (hour >= 17 && hour < 21) {
|
|
2798
|
+
return {
|
|
2799
|
+
greeting: lang === "bn" ? "\u09B6\u09C1\u09AD \u09B8\u09A8\u09CD\u09A7\u09CD\u09AF\u09BE" : "Good evening",
|
|
2800
|
+
period: "evening"
|
|
2801
|
+
};
|
|
2802
|
+
}
|
|
2803
|
+
return {
|
|
2804
|
+
greeting: lang === "bn" ? "\u09B6\u09C1\u09AD \u09B0\u09BE\u09A4\u09CD\u09B0\u09BF" : "Good evening",
|
|
2805
|
+
period: "night"
|
|
2806
|
+
};
|
|
2807
|
+
}
|
|
2808
|
+
function getRecommendedSubjectsForLevel(level, lang = "en") {
|
|
2809
|
+
const isBn = lang === "bn";
|
|
2810
|
+
const normalizedLevel = mapCognitoLevelToStandardLevel(level);
|
|
2811
|
+
if (normalizedLevel === "SSC") {
|
|
2812
|
+
return [
|
|
2813
|
+
{
|
|
2814
|
+
id: "ssc-physics",
|
|
2815
|
+
name: isBn ? "\u09AA\u09A6\u09BE\u09B0\u09CD\u09A5\u09AC\u09BF\u099C\u09CD\u099E\u09BE\u09A8" : "Physics",
|
|
2816
|
+
iconKey: "atom",
|
|
2817
|
+
colorClass: "from-blue-500 to-indigo-600"
|
|
2818
|
+
},
|
|
2819
|
+
{
|
|
2820
|
+
id: "ssc-chemistry",
|
|
2821
|
+
name: isBn ? "\u09B0\u09B8\u09BE\u09DF\u09A8" : "Chemistry",
|
|
2822
|
+
iconKey: "flask",
|
|
2823
|
+
colorClass: "from-emerald-500 to-teal-600"
|
|
2824
|
+
},
|
|
2825
|
+
{
|
|
2826
|
+
id: "ssc-higher-math",
|
|
2827
|
+
name: isBn ? "\u0989\u099A\u09CD\u099A\u09A4\u09B0 \u0997\u09A3\u09BF\u09A4" : "Higher Math",
|
|
2828
|
+
iconKey: "math",
|
|
2829
|
+
colorClass: "from-amber-500 to-orange-600"
|
|
2830
|
+
},
|
|
2831
|
+
{
|
|
2832
|
+
id: "ssc-general-math",
|
|
2833
|
+
name: isBn ? "\u09B8\u09BE\u09A7\u09BE\u09B0\u09A3 \u0997\u09A3\u09BF\u09A4" : "General Math",
|
|
2834
|
+
iconKey: "calculator",
|
|
2835
|
+
colorClass: "from-violet-500 to-purple-600"
|
|
2836
|
+
},
|
|
2837
|
+
{
|
|
2838
|
+
id: "ssc-biology",
|
|
2839
|
+
name: isBn ? "\u099C\u09C0\u09AC\u09AC\u09BF\u099C\u09CD\u099E\u09BE\u09A8" : "Biology",
|
|
2840
|
+
iconKey: "dna",
|
|
2841
|
+
colorClass: "from-rose-500 to-pink-600"
|
|
2842
|
+
},
|
|
2843
|
+
{
|
|
2844
|
+
id: "ssc-bangla",
|
|
2845
|
+
name: isBn ? "\u09AC\u09BE\u0982\u09B2\u09BE" : "Bangla",
|
|
2846
|
+
iconKey: "book",
|
|
2847
|
+
colorClass: "from-cyan-500 to-blue-600"
|
|
2848
|
+
}
|
|
2849
|
+
];
|
|
2850
|
+
}
|
|
2851
|
+
if (normalizedLevel === "BCS") {
|
|
2852
|
+
return [
|
|
2853
|
+
{
|
|
2854
|
+
id: "bcs-bangladesh-affairs",
|
|
2855
|
+
name: isBn ? "\u09AC\u09BE\u0982\u09B2\u09BE\u09A6\u09C7\u09B6 \u09AC\u09BF\u09B7\u09DF\u09BE\u09AC\u09B2\u09C0" : "Bangladesh Affairs",
|
|
2856
|
+
iconKey: "monument",
|
|
2857
|
+
colorClass: "from-emerald-500 to-green-600"
|
|
2858
|
+
},
|
|
2859
|
+
{
|
|
2860
|
+
id: "bcs-international-affairs",
|
|
2861
|
+
name: isBn ? "\u0986\u09A8\u09CD\u09A4\u09B0\u09CD\u099C\u09BE\u09A4\u09BF\u0995 \u09AC\u09BF\u09B7\u09DF\u09BE\u09AC\u09B2\u09C0" : "International Affairs",
|
|
2862
|
+
iconKey: "world",
|
|
2863
|
+
colorClass: "from-blue-500 to-cyan-600"
|
|
2864
|
+
},
|
|
2865
|
+
{
|
|
2866
|
+
id: "bcs-bangla",
|
|
2867
|
+
name: isBn ? "\u09AC\u09BE\u0982\u09B2\u09BE \u09AD\u09BE\u09B7\u09BE \u0993 \u09B8\u09BE\u09B9\u09BF\u09A4\u09CD\u09AF" : "Bangla Literature",
|
|
2868
|
+
iconKey: "book",
|
|
2869
|
+
colorClass: "from-amber-500 to-orange-600"
|
|
2870
|
+
},
|
|
2871
|
+
{
|
|
2872
|
+
id: "bcs-english",
|
|
2873
|
+
name: isBn ? "\u0987\u0982\u09B0\u09C7\u099C\u09BF \u09AD\u09BE\u09B7\u09BE \u0993 \u09B8\u09BE\u09B9\u09BF\u09A4\u09CD\u09AF" : "English Language",
|
|
2874
|
+
iconKey: "language",
|
|
2875
|
+
colorClass: "from-violet-500 to-purple-600"
|
|
2876
|
+
},
|
|
2877
|
+
{
|
|
2878
|
+
id: "bcs-math-mental-ability",
|
|
2879
|
+
name: isBn ? "\u0997\u09BE\u09A3\u09BF\u09A4\u09BF\u0995 \u0993 \u09AE\u09BE\u09A8\u09B8\u09BF\u0995 \u09A6\u0995\u09CD\u09B7\u09A4\u09BE" : "Math & Mental Ability",
|
|
2880
|
+
iconKey: "brain",
|
|
2881
|
+
colorClass: "from-pink-500 to-rose-600"
|
|
2882
|
+
},
|
|
2883
|
+
{
|
|
2884
|
+
id: "bcs-general-science",
|
|
2885
|
+
name: isBn ? "\u09B8\u09BE\u09A7\u09BE\u09B0\u09A3 \u09AC\u09BF\u099C\u09CD\u099E\u09BE\u09A8 \u0993 \u09AA\u09CD\u09B0\u09AF\u09C1\u0995\u09CD\u09A4\u09BF" : "General Science",
|
|
2886
|
+
iconKey: "atom",
|
|
2887
|
+
colorClass: "from-teal-500 to-emerald-600"
|
|
2888
|
+
}
|
|
2889
|
+
];
|
|
2890
|
+
}
|
|
2891
|
+
return [
|
|
2892
|
+
{
|
|
2893
|
+
id: "hsc-physics",
|
|
2894
|
+
name: isBn ? "\u09AA\u09A6\u09BE\u09B0\u09CD\u09A5\u09AC\u09BF\u099C\u09CD\u099E\u09BE\u09A8" : "Physics",
|
|
2895
|
+
iconKey: "atom",
|
|
2896
|
+
colorClass: "from-blue-500 to-indigo-600"
|
|
2897
|
+
},
|
|
2898
|
+
{
|
|
2899
|
+
id: "hsc-chemistry",
|
|
2900
|
+
name: isBn ? "\u09B0\u09B8\u09BE\u09DF\u09A8" : "Chemistry",
|
|
2901
|
+
iconKey: "flask",
|
|
2902
|
+
colorClass: "from-emerald-500 to-teal-600"
|
|
2903
|
+
},
|
|
2904
|
+
{
|
|
2905
|
+
id: "hsc-higher-math",
|
|
2906
|
+
name: isBn ? "\u0989\u099A\u09CD\u099A\u09A4\u09B0 \u0997\u09A3\u09BF\u09A4" : "Higher Math",
|
|
2907
|
+
iconKey: "math",
|
|
2908
|
+
colorClass: "from-amber-500 to-orange-600"
|
|
2909
|
+
},
|
|
2910
|
+
{
|
|
2911
|
+
id: "hsc-biology",
|
|
2912
|
+
name: isBn ? "\u099C\u09C0\u09AC\u09AC\u09BF\u099C\u09CD\u099E\u09BE\u09A8" : "Biology",
|
|
2913
|
+
iconKey: "dna",
|
|
2914
|
+
colorClass: "from-rose-500 to-pink-600"
|
|
2915
|
+
},
|
|
2916
|
+
{
|
|
2917
|
+
id: "hsc-ict",
|
|
2918
|
+
name: isBn ? "\u09A4\u09A5\u09CD\u09AF \u0993 \u09AF\u09CB\u0997\u09BE\u09AF\u09CB\u0997 \u09AA\u09CD\u09B0\u09AF\u09C1\u0995\u09CD\u09A4\u09BF" : "ICT",
|
|
2919
|
+
iconKey: "device-laptop",
|
|
2920
|
+
colorClass: "from-cyan-500 to-sky-600"
|
|
2921
|
+
},
|
|
2922
|
+
{
|
|
2923
|
+
id: "hsc-bangla",
|
|
2924
|
+
name: isBn ? "\u09AC\u09BE\u0982\u09B2\u09BE" : "Bangla",
|
|
2925
|
+
iconKey: "book",
|
|
2926
|
+
colorClass: "from-violet-500 to-purple-600"
|
|
2927
|
+
}
|
|
2928
|
+
];
|
|
2929
|
+
}
|
|
2930
|
+
function calculateStreakFromDates(activityDates) {
|
|
2931
|
+
if (!activityDates || activityDates.length === 0) {
|
|
2932
|
+
return { streak: 0, isActiveToday: false };
|
|
2933
|
+
}
|
|
2934
|
+
const uniqueDateStrings = Array.from(
|
|
2935
|
+
new Set(
|
|
2936
|
+
activityDates.map((d) => {
|
|
2937
|
+
try {
|
|
2938
|
+
return new Date(d).toISOString().split("T")[0];
|
|
2939
|
+
} catch (e6) {
|
|
2940
|
+
return null;
|
|
2941
|
+
}
|
|
2942
|
+
}).filter((d) => Boolean(d))
|
|
2943
|
+
)
|
|
2944
|
+
).sort((a, b) => a > b ? -1 : 1);
|
|
2945
|
+
if (uniqueDateStrings.length === 0) {
|
|
2946
|
+
return { streak: 0, isActiveToday: false };
|
|
2947
|
+
}
|
|
2948
|
+
const todayStr = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
2949
|
+
const yesterdayDate = /* @__PURE__ */ new Date();
|
|
2950
|
+
yesterdayDate.setDate(yesterdayDate.getDate() - 1);
|
|
2951
|
+
const yesterdayStr = yesterdayDate.toISOString().split("T")[0];
|
|
2952
|
+
const latestDate = uniqueDateStrings[0];
|
|
2953
|
+
if (!latestDate) {
|
|
2954
|
+
return { streak: 0, isActiveToday: false };
|
|
2955
|
+
}
|
|
2956
|
+
const isActiveToday = latestDate === todayStr;
|
|
2957
|
+
if (latestDate !== todayStr && latestDate !== yesterdayStr) {
|
|
2958
|
+
return { streak: 0, isActiveToday: false };
|
|
2959
|
+
}
|
|
2960
|
+
let streak = 0;
|
|
2961
|
+
const checkDate = new Date(latestDate);
|
|
2962
|
+
for (const dateStr of uniqueDateStrings) {
|
|
2963
|
+
const expectedStr = checkDate.toISOString().split("T")[0];
|
|
2964
|
+
if (dateStr === expectedStr) {
|
|
2965
|
+
streak += 1;
|
|
2966
|
+
checkDate.setDate(checkDate.getDate() - 1);
|
|
2967
|
+
} else {
|
|
2968
|
+
break;
|
|
2969
|
+
}
|
|
2970
|
+
}
|
|
2971
|
+
return { streak, isActiveToday };
|
|
2972
|
+
}
|
|
1266
2973
|
|
|
1267
2974
|
// src/logic/import-export.ts
|
|
1268
2975
|
var MAX_QUESTIONS = 200;
|
|
@@ -1280,50 +2987,50 @@ function parseFields(parts) {
|
|
|
1280
2987
|
let option3ImageUrl = "";
|
|
1281
2988
|
let option4ImageUrl = "";
|
|
1282
2989
|
if (parts.length >= 13) {
|
|
1283
|
-
extra = _nullishCoalesce(_optionalChain([parts, 'access',
|
|
1284
|
-
const rawDiff = _nullishCoalesce(_optionalChain([parts, 'access',
|
|
2990
|
+
extra = _nullishCoalesce(_optionalChain([parts, 'access', _82 => _82[7], 'optionalAccess', _83 => _83.trim, 'call', _84 => _84()]), () => ( ""));
|
|
2991
|
+
const rawDiff = _nullishCoalesce(_optionalChain([parts, 'access', _85 => _85[8], 'optionalAccess', _86 => _86.trim, 'call', _87 => _87()]), () => ( ""));
|
|
1285
2992
|
if (rawDiff) {
|
|
1286
2993
|
const cap = rawDiff.charAt(0).toUpperCase() + rawDiff.slice(1).toLowerCase();
|
|
1287
2994
|
if (cap === "Easy" || cap === "Medium" || cap === "Hard") difficulty = cap;
|
|
1288
2995
|
}
|
|
1289
|
-
subjectId = _nullishCoalesce(_optionalChain([parts, 'access',
|
|
1290
|
-
chapterId = _nullishCoalesce(_optionalChain([parts, 'access',
|
|
1291
|
-
topicId = _nullishCoalesce(_optionalChain([parts, 'access',
|
|
1292
|
-
markingInstructions = _nullishCoalesce(_optionalChain([parts, 'access',
|
|
1293
|
-
if (parts.length > 13) id = _nullishCoalesce(_optionalChain([parts, 'access',
|
|
1294
|
-
if (parts.length > 14) imageUrl = _nullishCoalesce(_optionalChain([parts, 'access',
|
|
1295
|
-
if (parts.length > 15) answerImageUrl = _nullishCoalesce(_optionalChain([parts, 'access',
|
|
1296
|
-
if (parts.length > 16) option2ImageUrl = _nullishCoalesce(_optionalChain([parts, 'access',
|
|
1297
|
-
if (parts.length > 17) option3ImageUrl = _nullishCoalesce(_optionalChain([parts, 'access',
|
|
1298
|
-
if (parts.length > 18) option4ImageUrl = _nullishCoalesce(_optionalChain([parts, 'access',
|
|
2996
|
+
subjectId = _nullishCoalesce(_optionalChain([parts, 'access', _88 => _88[9], 'optionalAccess', _89 => _89.trim, 'call', _90 => _90()]), () => ( ""));
|
|
2997
|
+
chapterId = _nullishCoalesce(_optionalChain([parts, 'access', _91 => _91[10], 'optionalAccess', _92 => _92.trim, 'call', _93 => _93()]), () => ( ""));
|
|
2998
|
+
topicId = _nullishCoalesce(_optionalChain([parts, 'access', _94 => _94[11], 'optionalAccess', _95 => _95.trim, 'call', _96 => _96()]), () => ( ""));
|
|
2999
|
+
markingInstructions = _nullishCoalesce(_optionalChain([parts, 'access', _97 => _97[12], 'optionalAccess', _98 => _98.trim, 'call', _99 => _99()]), () => ( ""));
|
|
3000
|
+
if (parts.length > 13) id = _nullishCoalesce(_optionalChain([parts, 'access', _100 => _100[13], 'optionalAccess', _101 => _101.trim, 'call', _102 => _102()]), () => ( ""));
|
|
3001
|
+
if (parts.length > 14) imageUrl = _nullishCoalesce(_optionalChain([parts, 'access', _103 => _103[14], 'optionalAccess', _104 => _104.trim, 'call', _105 => _105()]), () => ( ""));
|
|
3002
|
+
if (parts.length > 15) answerImageUrl = _nullishCoalesce(_optionalChain([parts, 'access', _106 => _106[15], 'optionalAccess', _107 => _107.trim, 'call', _108 => _108()]), () => ( ""));
|
|
3003
|
+
if (parts.length > 16) option2ImageUrl = _nullishCoalesce(_optionalChain([parts, 'access', _109 => _109[16], 'optionalAccess', _110 => _110.trim, 'call', _111 => _111()]), () => ( ""));
|
|
3004
|
+
if (parts.length > 17) option3ImageUrl = _nullishCoalesce(_optionalChain([parts, 'access', _112 => _112[17], 'optionalAccess', _113 => _113.trim, 'call', _114 => _114()]), () => ( ""));
|
|
3005
|
+
if (parts.length > 18) option4ImageUrl = _nullishCoalesce(_optionalChain([parts, 'access', _115 => _115[18], 'optionalAccess', _116 => _116.trim, 'call', _117 => _117()]), () => ( ""));
|
|
1299
3006
|
} else if (parts.length === 8) {
|
|
1300
|
-
extra = _nullishCoalesce(_optionalChain([parts, 'access',
|
|
3007
|
+
extra = _nullishCoalesce(_optionalChain([parts, 'access', _118 => _118[7], 'optionalAccess', _119 => _119.trim, 'call', _120 => _120()]), () => ( ""));
|
|
1301
3008
|
} else if (parts.length === 9) {
|
|
1302
|
-
extra = _nullishCoalesce(_optionalChain([parts, 'access',
|
|
1303
|
-
const rawDiff = _nullishCoalesce(_optionalChain([parts, 'access',
|
|
3009
|
+
extra = _nullishCoalesce(_optionalChain([parts, 'access', _121 => _121[7], 'optionalAccess', _122 => _122.trim, 'call', _123 => _123()]), () => ( ""));
|
|
3010
|
+
const rawDiff = _nullishCoalesce(_optionalChain([parts, 'access', _124 => _124[8], 'optionalAccess', _125 => _125.trim, 'call', _126 => _126()]), () => ( ""));
|
|
1304
3011
|
if (rawDiff) {
|
|
1305
3012
|
const cap = rawDiff.charAt(0).toUpperCase() + rawDiff.slice(1).toLowerCase();
|
|
1306
3013
|
if (cap === "Easy" || cap === "Medium" || cap === "Hard") difficulty = cap;
|
|
1307
3014
|
}
|
|
1308
3015
|
} else if (parts.length === 10) {
|
|
1309
|
-
subjectId = _nullishCoalesce(_optionalChain([parts, 'access',
|
|
1310
|
-
chapterId = _nullishCoalesce(_optionalChain([parts, 'access',
|
|
1311
|
-
topicId = _nullishCoalesce(_optionalChain([parts, 'access',
|
|
3016
|
+
subjectId = _nullishCoalesce(_optionalChain([parts, 'access', _127 => _127[7], 'optionalAccess', _128 => _128.trim, 'call', _129 => _129()]), () => ( ""));
|
|
3017
|
+
chapterId = _nullishCoalesce(_optionalChain([parts, 'access', _130 => _130[8], 'optionalAccess', _131 => _131.trim, 'call', _132 => _132()]), () => ( ""));
|
|
3018
|
+
topicId = _nullishCoalesce(_optionalChain([parts, 'access', _133 => _133[9], 'optionalAccess', _134 => _134.trim, 'call', _135 => _135()]), () => ( ""));
|
|
1312
3019
|
} else if (parts.length === 11) {
|
|
1313
|
-
extra = _nullishCoalesce(_optionalChain([parts, 'access',
|
|
1314
|
-
subjectId = _nullishCoalesce(_optionalChain([parts, 'access',
|
|
1315
|
-
chapterId = _nullishCoalesce(_optionalChain([parts, 'access',
|
|
1316
|
-
topicId = _nullishCoalesce(_optionalChain([parts, 'access',
|
|
3020
|
+
extra = _nullishCoalesce(_optionalChain([parts, 'access', _136 => _136[7], 'optionalAccess', _137 => _137.trim, 'call', _138 => _138()]), () => ( ""));
|
|
3021
|
+
subjectId = _nullishCoalesce(_optionalChain([parts, 'access', _139 => _139[8], 'optionalAccess', _140 => _140.trim, 'call', _141 => _141()]), () => ( ""));
|
|
3022
|
+
chapterId = _nullishCoalesce(_optionalChain([parts, 'access', _142 => _142[9], 'optionalAccess', _143 => _143.trim, 'call', _144 => _144()]), () => ( ""));
|
|
3023
|
+
topicId = _nullishCoalesce(_optionalChain([parts, 'access', _145 => _145[10], 'optionalAccess', _146 => _146.trim, 'call', _147 => _147()]), () => ( ""));
|
|
1317
3024
|
} else if (parts.length === 12) {
|
|
1318
|
-
extra = _nullishCoalesce(_optionalChain([parts, 'access',
|
|
1319
|
-
const rawDiff = _nullishCoalesce(_optionalChain([parts, 'access',
|
|
3025
|
+
extra = _nullishCoalesce(_optionalChain([parts, 'access', _148 => _148[7], 'optionalAccess', _149 => _149.trim, 'call', _150 => _150()]), () => ( ""));
|
|
3026
|
+
const rawDiff = _nullishCoalesce(_optionalChain([parts, 'access', _151 => _151[8], 'optionalAccess', _152 => _152.trim, 'call', _153 => _153()]), () => ( ""));
|
|
1320
3027
|
if (rawDiff) {
|
|
1321
3028
|
const cap = rawDiff.charAt(0).toUpperCase() + rawDiff.slice(1).toLowerCase();
|
|
1322
3029
|
if (cap === "Easy" || cap === "Medium" || cap === "Hard") difficulty = cap;
|
|
1323
3030
|
}
|
|
1324
|
-
subjectId = _nullishCoalesce(_optionalChain([parts, 'access',
|
|
1325
|
-
chapterId = _nullishCoalesce(_optionalChain([parts, 'access',
|
|
1326
|
-
topicId = _nullishCoalesce(_optionalChain([parts, 'access',
|
|
3031
|
+
subjectId = _nullishCoalesce(_optionalChain([parts, 'access', _154 => _154[9], 'optionalAccess', _155 => _155.trim, 'call', _156 => _156()]), () => ( ""));
|
|
3032
|
+
chapterId = _nullishCoalesce(_optionalChain([parts, 'access', _157 => _157[10], 'optionalAccess', _158 => _158.trim, 'call', _159 => _159()]), () => ( ""));
|
|
3033
|
+
topicId = _nullishCoalesce(_optionalChain([parts, 'access', _160 => _160[11], 'optionalAccess', _161 => _161.trim, 'call', _162 => _162()]), () => ( ""));
|
|
1327
3034
|
}
|
|
1328
3035
|
return {
|
|
1329
3036
|
id: id || void 0,
|
|
@@ -1342,18 +3049,18 @@ function parseFields(parts) {
|
|
|
1342
3049
|
}
|
|
1343
3050
|
function buildQuestion(parts) {
|
|
1344
3051
|
const tags = parts.length >= 7 && parts[6] ? parts[6].split(",").map((t) => t.trim()).filter(Boolean) : [];
|
|
1345
|
-
const opt2 = _nullishCoalesce(_optionalChain([parts, 'access',
|
|
1346
|
-
const opt3 = _nullishCoalesce(_optionalChain([parts, 'access',
|
|
1347
|
-
const opt4 = _nullishCoalesce(_optionalChain([parts, 'access',
|
|
3052
|
+
const opt2 = _nullishCoalesce(_optionalChain([parts, 'access', _163 => _163[2], 'optionalAccess', _164 => _164.trim, 'call', _165 => _165()]), () => ( ""));
|
|
3053
|
+
const opt3 = _nullishCoalesce(_optionalChain([parts, 'access', _166 => _166[3], 'optionalAccess', _167 => _167.trim, 'call', _168 => _168()]), () => ( ""));
|
|
3054
|
+
const opt4 = _nullishCoalesce(_optionalChain([parts, 'access', _169 => _169[4], 'optionalAccess', _170 => _170.trim, 'call', _171 => _171()]), () => ( ""));
|
|
1348
3055
|
const isWritten = parts.length < 6 || !opt2 && !opt3 && !opt4;
|
|
1349
3056
|
const extra = parseFields(parts);
|
|
1350
3057
|
return {
|
|
1351
|
-
question: _nullishCoalesce(_optionalChain([parts, 'access',
|
|
1352
|
-
answer: _nullishCoalesce(_optionalChain([parts, 'access',
|
|
3058
|
+
question: _nullishCoalesce(_optionalChain([parts, 'access', _172 => _172[0], 'optionalAccess', _173 => _173.trim, 'call', _174 => _174()]), () => ( "")),
|
|
3059
|
+
answer: _nullishCoalesce(_optionalChain([parts, 'access', _175 => _175[1], 'optionalAccess', _176 => _176.trim, 'call', _177 => _177()]), () => ( "")),
|
|
1353
3060
|
option2: opt2,
|
|
1354
3061
|
option3: opt3,
|
|
1355
3062
|
option4: opt4,
|
|
1356
|
-
explanation: _nullishCoalesce(_optionalChain([parts, 'access',
|
|
3063
|
+
explanation: _nullishCoalesce(_optionalChain([parts, 'access', _178 => _178[5], 'optionalAccess', _179 => _179.trim, 'call', _180 => _180()]), () => ( "")),
|
|
1357
3064
|
tags,
|
|
1358
3065
|
type: isWritten ? "WRITTEN" : "MCQ",
|
|
1359
3066
|
...extra
|
|
@@ -1404,9 +3111,9 @@ function formatQuestionsToText(questions, keyword, packSubjectId, packChapterId,
|
|
|
1404
3111
|
const activeSubject = q.subjectId || packSubjectId;
|
|
1405
3112
|
const activeChapter = q.chapterId || packChapterId;
|
|
1406
3113
|
const activeTopic = q.topicId || packTopicId;
|
|
1407
|
-
const subjectSlug = activeSubject ? _nullishCoalesce(_optionalChain([activeSubject, 'access',
|
|
1408
|
-
const chapterSlug = activeChapter ? _nullishCoalesce(_optionalChain([activeChapter, 'access',
|
|
1409
|
-
const topicSlug = activeTopic ? _nullishCoalesce(_optionalChain([activeTopic, 'access',
|
|
3114
|
+
const subjectSlug = activeSubject ? _nullishCoalesce(_optionalChain([activeSubject, 'access', _181 => _181.split, 'call', _182 => _182("::"), 'access', _183 => _183[0], 'optionalAccess', _184 => _184.trim, 'call', _185 => _185()]), () => ( "")) : "";
|
|
3115
|
+
const chapterSlug = activeChapter ? _nullishCoalesce(_optionalChain([activeChapter, 'access', _186 => _186.split, 'call', _187 => _187("::"), 'access', _188 => _188[0], 'optionalAccess', _189 => _189.trim, 'call', _190 => _190()]), () => ( "")) : "";
|
|
3116
|
+
const topicSlug = activeTopic ? _nullishCoalesce(_optionalChain([activeTopic, 'access', _191 => _191.split, 'call', _192 => _192("::"), 'access', _193 => _193[0], 'optionalAccess', _194 => _194.trim, 'call', _195 => _195()]), () => ( "")) : "";
|
|
1410
3117
|
const fields = [
|
|
1411
3118
|
q.question,
|
|
1412
3119
|
q.answer,
|
|
@@ -1439,9 +3146,9 @@ function formatQuestionsToCsv(questions, packSubjectId, packChapterId, packTopic
|
|
|
1439
3146
|
const activeSubject = q.subjectId || packSubjectId;
|
|
1440
3147
|
const activeChapter = q.chapterId || packChapterId;
|
|
1441
3148
|
const activeTopic = q.topicId || packTopicId;
|
|
1442
|
-
const subjectSlug = activeSubject ? _nullishCoalesce(_optionalChain([activeSubject, 'access',
|
|
1443
|
-
const chapterSlug = activeChapter ? _nullishCoalesce(_optionalChain([activeChapter, 'access',
|
|
1444
|
-
const topicSlug = activeTopic ? _nullishCoalesce(_optionalChain([activeTopic, 'access',
|
|
3149
|
+
const subjectSlug = activeSubject ? _nullishCoalesce(_optionalChain([activeSubject, 'access', _196 => _196.split, 'call', _197 => _197("::"), 'access', _198 => _198[0], 'optionalAccess', _199 => _199.trim, 'call', _200 => _200()]), () => ( "")) : "";
|
|
3150
|
+
const chapterSlug = activeChapter ? _nullishCoalesce(_optionalChain([activeChapter, 'access', _201 => _201.split, 'call', _202 => _202("::"), 'access', _203 => _203[0], 'optionalAccess', _204 => _204.trim, 'call', _205 => _205()]), () => ( "")) : "";
|
|
3151
|
+
const topicSlug = activeTopic ? _nullishCoalesce(_optionalChain([activeTopic, 'access', _206 => _206.split, 'call', _207 => _207("::"), 'access', _208 => _208[0], 'optionalAccess', _209 => _209.trim, 'call', _210 => _210()]), () => ( "")) : "";
|
|
1445
3152
|
return [
|
|
1446
3153
|
escapeCSV(q.question),
|
|
1447
3154
|
escapeCSV(q.answer),
|
|
@@ -1468,126 +3175,281 @@ function formatQuestionsToCsv(questions, packSubjectId, packChapterId, packTopic
|
|
|
1468
3175
|
${rows.join("\n")}`;
|
|
1469
3176
|
}
|
|
1470
3177
|
|
|
1471
|
-
// src/logic/
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
3178
|
+
// src/logic/subscription.ts
|
|
3179
|
+
var MANUAL_PAYMENT_CONFIG = {
|
|
3180
|
+
phoneNumber: "01323567688",
|
|
3181
|
+
accountType: "Personal",
|
|
3182
|
+
methods: ["BKASH", "ROCKET"]
|
|
3183
|
+
};
|
|
3184
|
+
var SUBSCRIPTION_PLANS = {
|
|
3185
|
+
FREE: {
|
|
3186
|
+
id: "FREE",
|
|
3187
|
+
tier: "FREE",
|
|
3188
|
+
titleKey: "upgrade.freeTitle",
|
|
3189
|
+
descKey: "upgrade.freeDesc",
|
|
3190
|
+
pricing: {
|
|
3191
|
+
monthly: 0,
|
|
3192
|
+
quarterly: 0,
|
|
3193
|
+
biannually: 0,
|
|
3194
|
+
annually: 0
|
|
3195
|
+
},
|
|
3196
|
+
aiQuotas: {
|
|
3197
|
+
monthly: { aiEvals: 0, aiQuestions: 0 },
|
|
3198
|
+
quarterly: { aiEvals: 0, aiQuestions: 0 },
|
|
3199
|
+
biannually: { aiEvals: 0, aiQuestions: 0 },
|
|
3200
|
+
annually: { aiEvals: 0, aiQuestions: 0 }
|
|
1486
3201
|
}
|
|
1487
|
-
|
|
3202
|
+
},
|
|
3203
|
+
PRO: {
|
|
3204
|
+
id: "PRO",
|
|
3205
|
+
tier: "PRO",
|
|
3206
|
+
titleKey: "upgrade.proTitle",
|
|
3207
|
+
descKey: "upgrade.proDesc",
|
|
3208
|
+
pricing: {
|
|
3209
|
+
monthly: 149,
|
|
3210
|
+
quarterly: 399,
|
|
3211
|
+
biannually: 699,
|
|
3212
|
+
annually: 999
|
|
3213
|
+
},
|
|
3214
|
+
aiQuotas: {
|
|
3215
|
+
monthly: { aiEvals: 0, aiQuestions: 0 },
|
|
3216
|
+
quarterly: { aiEvals: 0, aiQuestions: 0 },
|
|
3217
|
+
biannually: { aiEvals: 0, aiQuestions: 0 },
|
|
3218
|
+
annually: { aiEvals: 0, aiQuestions: 0 }
|
|
3219
|
+
}
|
|
3220
|
+
},
|
|
3221
|
+
PRO_AI: {
|
|
3222
|
+
id: "PRO_AI",
|
|
3223
|
+
tier: "PRO_AI",
|
|
3224
|
+
titleKey: "upgrade.aiTitle",
|
|
3225
|
+
descKey: "upgrade.aiDesc",
|
|
3226
|
+
pricing: {
|
|
3227
|
+
monthly: 349,
|
|
3228
|
+
quarterly: 899,
|
|
3229
|
+
biannually: 1599,
|
|
3230
|
+
annually: 2499
|
|
3231
|
+
},
|
|
3232
|
+
aiQuotas: {
|
|
3233
|
+
monthly: { aiEvals: 100, aiQuestions: 450 },
|
|
3234
|
+
quarterly: { aiEvals: 280, aiQuestions: 1100 },
|
|
3235
|
+
biannually: { aiEvals: 500, aiQuestions: 2e3 },
|
|
3236
|
+
annually: { aiEvals: 800, aiQuestions: 3e3 }
|
|
3237
|
+
}
|
|
3238
|
+
}
|
|
3239
|
+
};
|
|
3240
|
+
var AI_EVAL_BOOSTER_PACKS = [
|
|
3241
|
+
{
|
|
3242
|
+
id: "eval_booster_starter",
|
|
3243
|
+
type: "AI_EVAL",
|
|
3244
|
+
amount: 40,
|
|
3245
|
+
price: 69,
|
|
3246
|
+
titleKey: "upgrade.boosters.evalStarterTitle",
|
|
3247
|
+
descKey: "upgrade.boosters.evalStarterDesc"
|
|
3248
|
+
},
|
|
3249
|
+
{
|
|
3250
|
+
id: "eval_booster_standard",
|
|
3251
|
+
type: "AI_EVAL",
|
|
3252
|
+
amount: 100,
|
|
3253
|
+
price: 159,
|
|
3254
|
+
titleKey: "upgrade.boosters.evalStandardTitle",
|
|
3255
|
+
descKey: "upgrade.boosters.evalStandardDesc",
|
|
3256
|
+
badgeKey: "upgrade.popular"
|
|
3257
|
+
},
|
|
3258
|
+
{
|
|
3259
|
+
id: "eval_booster_mega",
|
|
3260
|
+
type: "AI_EVAL",
|
|
3261
|
+
amount: 220,
|
|
3262
|
+
price: 349,
|
|
3263
|
+
titleKey: "upgrade.boosters.evalMegaTitle",
|
|
3264
|
+
descKey: "upgrade.boosters.evalMegaDesc",
|
|
3265
|
+
badgeKey: "upgrade.bestValue"
|
|
1488
3266
|
}
|
|
1489
|
-
|
|
1490
|
-
|
|
3267
|
+
];
|
|
3268
|
+
var AI_QUESTION_BOOSTER_PACKS = [
|
|
3269
|
+
{
|
|
3270
|
+
id: "question_booster_drill",
|
|
3271
|
+
type: "AI_QUESTION",
|
|
3272
|
+
amount: 100,
|
|
3273
|
+
price: 39,
|
|
3274
|
+
titleKey: "upgrade.boosters.questionDrillTitle",
|
|
3275
|
+
descKey: "upgrade.boosters.questionDrillDesc"
|
|
3276
|
+
},
|
|
3277
|
+
{
|
|
3278
|
+
id: "question_booster_chapter",
|
|
3279
|
+
type: "AI_QUESTION",
|
|
3280
|
+
amount: 250,
|
|
3281
|
+
price: 99,
|
|
3282
|
+
titleKey: "upgrade.boosters.questionChapterTitle",
|
|
3283
|
+
descKey: "upgrade.boosters.questionChapterDesc",
|
|
3284
|
+
badgeKey: "upgrade.popular"
|
|
3285
|
+
},
|
|
3286
|
+
{
|
|
3287
|
+
id: "question_booster_exam",
|
|
3288
|
+
type: "AI_QUESTION",
|
|
3289
|
+
amount: 700,
|
|
3290
|
+
price: 249,
|
|
3291
|
+
titleKey: "upgrade.boosters.questionExamTitle",
|
|
3292
|
+
descKey: "upgrade.boosters.questionExamDesc",
|
|
3293
|
+
badgeKey: "upgrade.bestValue"
|
|
1491
3294
|
}
|
|
1492
|
-
|
|
1493
|
-
|
|
3295
|
+
];
|
|
3296
|
+
function getCycleMultiplier(cycle) {
|
|
3297
|
+
switch (cycle) {
|
|
3298
|
+
case "quarterly":
|
|
3299
|
+
return 3;
|
|
3300
|
+
case "biannually":
|
|
3301
|
+
return 6;
|
|
3302
|
+
case "annually":
|
|
3303
|
+
return 12;
|
|
3304
|
+
case "monthly":
|
|
3305
|
+
default:
|
|
3306
|
+
return 1;
|
|
1494
3307
|
}
|
|
1495
|
-
}
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
const
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
return copy;
|
|
1526
|
-
}
|
|
1527
|
-
function _resetMediaUrlWarning() {
|
|
1528
|
-
warnedNoStorage = false;
|
|
1529
|
-
}
|
|
1530
|
-
|
|
1531
|
-
// src/logic/practice.ts
|
|
1532
|
-
function aggregateSubjectMetrics(progress) {
|
|
1533
|
-
let totalPracticed = 0;
|
|
1534
|
-
let totalMistakes = 0;
|
|
1535
|
-
let totalCorrected = 0;
|
|
1536
|
-
for (const p of progress) {
|
|
1537
|
-
totalPracticed += _nullishCoalesce(p.practicedCount, () => ( 0));
|
|
1538
|
-
totalMistakes += _nullishCoalesce(p.mistakeCount, () => ( 0));
|
|
1539
|
-
totalCorrected += _nullishCoalesce(p.correctedCount, () => ( 0));
|
|
1540
|
-
}
|
|
1541
|
-
const accuracy = totalPracticed > 0 ? Math.round((totalPracticed - totalMistakes) / totalPracticed * 100) : 0;
|
|
1542
|
-
return { totalPracticed, totalMistakes, totalCorrected, accuracy };
|
|
1543
|
-
}
|
|
1544
|
-
function aggregateChapterMetrics(progress) {
|
|
1545
|
-
let totalPracticed = 0;
|
|
1546
|
-
let totalMistakes = 0;
|
|
1547
|
-
let totalCorrected = 0;
|
|
1548
|
-
for (const p of progress) {
|
|
1549
|
-
totalPracticed += _nullishCoalesce(p.practicedCount, () => ( 0));
|
|
1550
|
-
totalMistakes += _nullishCoalesce(p.mistakeCount, () => ( 0));
|
|
1551
|
-
totalCorrected += _nullishCoalesce(p.correctedCount, () => ( 0));
|
|
1552
|
-
}
|
|
1553
|
-
const accuracy = totalPracticed > 0 ? Math.round((totalPracticed - totalMistakes) / totalPracticed * 100) : 0;
|
|
1554
|
-
return { totalPracticed, totalMistakes, totalCorrected, accuracy };
|
|
1555
|
-
}
|
|
1556
|
-
function aggregateTopicMetrics(progress) {
|
|
1557
|
-
let totalPracticed = 0;
|
|
1558
|
-
let totalMistakes = 0;
|
|
1559
|
-
let totalCorrected = 0;
|
|
1560
|
-
for (const p of progress) {
|
|
1561
|
-
totalPracticed += _nullishCoalesce(p.practicedCount, () => ( 0));
|
|
1562
|
-
totalMistakes += _nullishCoalesce(p.mistakeCount, () => ( 0));
|
|
1563
|
-
totalCorrected += _nullishCoalesce(p.correctedCount, () => ( 0));
|
|
1564
|
-
}
|
|
1565
|
-
const accuracy = totalPracticed > 0 ? Math.round((totalPracticed - totalMistakes) / totalPracticed * 100) : 0;
|
|
1566
|
-
return { totalPracticed, totalMistakes, totalCorrected, accuracy };
|
|
1567
|
-
}
|
|
1568
|
-
function calculateAccuracy(practiced, mistakes) {
|
|
1569
|
-
if (practiced <= 0) return 0;
|
|
1570
|
-
return Math.round((practiced - mistakes) / practiced * 100);
|
|
1571
|
-
}
|
|
1572
|
-
|
|
1573
|
-
// src/utils/shuffle.ts
|
|
1574
|
-
function shuffle(array) {
|
|
1575
|
-
const result = [...array];
|
|
1576
|
-
let currentIndex = result.length;
|
|
1577
|
-
while (currentIndex !== 0) {
|
|
1578
|
-
const randomIndex = Math.floor(Math.random() * currentIndex);
|
|
1579
|
-
currentIndex--;
|
|
1580
|
-
[result[currentIndex], result[randomIndex]] = [result[randomIndex], result[currentIndex]];
|
|
3308
|
+
}
|
|
3309
|
+
function getPlanOriginalPrice(tier, cycle) {
|
|
3310
|
+
const normalizedTier = tier === "AI_ANNUAL" || tier === "AI_MONTHLY" ? "PRO_AI" : tier;
|
|
3311
|
+
const plan = SUBSCRIPTION_PLANS[normalizedTier] || SUBSCRIPTION_PLANS.FREE;
|
|
3312
|
+
const monthlyPrice = _nullishCoalesce(plan.pricing.monthly, () => ( 0));
|
|
3313
|
+
return monthlyPrice * getCycleMultiplier(cycle);
|
|
3314
|
+
}
|
|
3315
|
+
function getPlanPrice(tier, cycle) {
|
|
3316
|
+
const normalizedTier = tier === "AI_ANNUAL" || tier === "AI_MONTHLY" ? "PRO_AI" : tier;
|
|
3317
|
+
const plan = SUBSCRIPTION_PLANS[normalizedTier] || SUBSCRIPTION_PLANS.FREE;
|
|
3318
|
+
return _nullishCoalesce(plan.pricing[cycle], () => ( 0));
|
|
3319
|
+
}
|
|
3320
|
+
function getPlanMonthlyEquivalentPrice(tier, cycle) {
|
|
3321
|
+
const normalizedTier = tier === "AI_ANNUAL" || tier === "AI_MONTHLY" ? "PRO_AI" : tier;
|
|
3322
|
+
const plan = SUBSCRIPTION_PLANS[normalizedTier] || SUBSCRIPTION_PLANS.FREE;
|
|
3323
|
+
const cyclePrice = _nullishCoalesce(plan.pricing[cycle], () => ( 0));
|
|
3324
|
+
const multiplier = getCycleMultiplier(cycle);
|
|
3325
|
+
return Math.round(cyclePrice / multiplier);
|
|
3326
|
+
}
|
|
3327
|
+
function getPlanDiscountPercent(cycle) {
|
|
3328
|
+
switch (cycle) {
|
|
3329
|
+
case "quarterly":
|
|
3330
|
+
return 10;
|
|
3331
|
+
case "biannually":
|
|
3332
|
+
return 22;
|
|
3333
|
+
case "annually":
|
|
3334
|
+
return 44;
|
|
3335
|
+
case "monthly":
|
|
3336
|
+
default:
|
|
3337
|
+
return 0;
|
|
1581
3338
|
}
|
|
1582
|
-
return result;
|
|
1583
3339
|
}
|
|
1584
|
-
function
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
3340
|
+
function getPlanAiQuotas(tier, cycle) {
|
|
3341
|
+
const normalizedTier = tier === "AI_ANNUAL" || tier === "AI_MONTHLY" ? "PRO_AI" : tier;
|
|
3342
|
+
const plan = SUBSCRIPTION_PLANS[normalizedTier] || SUBSCRIPTION_PLANS.FREE;
|
|
3343
|
+
return _nullishCoalesce(plan.aiQuotas[cycle], () => ( { aiEvals: 0, aiQuestions: 0 }));
|
|
3344
|
+
}
|
|
3345
|
+
function isValidBangladeshiPhone(phone) {
|
|
3346
|
+
if (!phone) return false;
|
|
3347
|
+
const cleaned = phone.replace(/[\s\-()]/g, "");
|
|
3348
|
+
const regex = /^(?:\+?88)?01[3-9]\d{8}$/;
|
|
3349
|
+
return regex.test(cleaned);
|
|
3350
|
+
}
|
|
3351
|
+
function isValidTrxId(trxId) {
|
|
3352
|
+
if (!trxId) return false;
|
|
3353
|
+
const cleaned = trxId.trim();
|
|
3354
|
+
return cleaned.length >= 4 && cleaned.length <= 40;
|
|
3355
|
+
}
|
|
3356
|
+
function hasProAccess(tier, expiresAt) {
|
|
3357
|
+
if (!tier) return false;
|
|
3358
|
+
const upper = tier.toUpperCase();
|
|
3359
|
+
const isTierPro = upper === "PRO" || upper === "PRO_AI";
|
|
3360
|
+
if (!isTierPro) return false;
|
|
3361
|
+
if (!expiresAt) return true;
|
|
3362
|
+
const expTime = new Date(expiresAt).getTime();
|
|
3363
|
+
if (isNaN(expTime)) return true;
|
|
3364
|
+
return expTime > Date.now();
|
|
3365
|
+
}
|
|
3366
|
+
function hasAiTierAccess(tier, expiresAt) {
|
|
3367
|
+
if (!tier) return false;
|
|
3368
|
+
const upper = tier.toUpperCase();
|
|
3369
|
+
const isTierAi = upper === "PRO_AI";
|
|
3370
|
+
if (!isTierAi) return false;
|
|
3371
|
+
if (!expiresAt) return true;
|
|
3372
|
+
const expTime = new Date(expiresAt).getTime();
|
|
3373
|
+
if (isNaN(expTime)) return true;
|
|
3374
|
+
return expTime > Date.now();
|
|
3375
|
+
}
|
|
3376
|
+
var FREE_DAILY_PRACTICE_LIMIT = 30;
|
|
3377
|
+
function canExportPack(tier, expiresAt, isCreator) {
|
|
3378
|
+
return Boolean(isCreator || hasProAccess(tier, expiresAt));
|
|
3379
|
+
}
|
|
3380
|
+
function canAccessMistakeVault(tier, expiresAt, isCreator) {
|
|
3381
|
+
return Boolean(isCreator || hasProAccess(tier, expiresAt));
|
|
3382
|
+
}
|
|
3383
|
+
function canWatchContestSolution(tier, expiresAt, isCreator) {
|
|
3384
|
+
return Boolean(isCreator || hasProAccess(tier, expiresAt));
|
|
3385
|
+
}
|
|
3386
|
+
function shouldTrackPracticeProgress(tier, expiresAt, isCreator) {
|
|
3387
|
+
return Boolean(isCreator || hasProAccess(tier, expiresAt));
|
|
3388
|
+
}
|
|
3389
|
+
function getDailyPracticeLimit(tier, expiresAt) {
|
|
3390
|
+
if (hasProAccess(tier, expiresAt)) return null;
|
|
3391
|
+
return FREE_DAILY_PRACTICE_LIMIT;
|
|
3392
|
+
}
|
|
3393
|
+
function checkDailyPracticeLimit(dailyCount, lastPracticeDate, tier, expiresAt, todayStr) {
|
|
3394
|
+
if (hasProAccess(tier, expiresAt)) {
|
|
3395
|
+
return {
|
|
3396
|
+
allowed: true,
|
|
3397
|
+
remaining: Infinity,
|
|
3398
|
+
currentCount: dailyCount,
|
|
3399
|
+
isUnlimited: true
|
|
3400
|
+
};
|
|
3401
|
+
}
|
|
3402
|
+
const today = todayStr || (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
3403
|
+
const isSameDay = lastPracticeDate ? lastPracticeDate.startsWith(today) : false;
|
|
3404
|
+
const currentCount = isSameDay ? Number.isFinite(dailyCount) ? dailyCount : 0 : 0;
|
|
3405
|
+
const remaining = Math.max(0, FREE_DAILY_PRACTICE_LIMIT - currentCount);
|
|
3406
|
+
const allowed = currentCount < FREE_DAILY_PRACTICE_LIMIT;
|
|
3407
|
+
return {
|
|
3408
|
+
allowed,
|
|
3409
|
+
remaining,
|
|
3410
|
+
currentCount,
|
|
3411
|
+
isUnlimited: false
|
|
3412
|
+
};
|
|
3413
|
+
}
|
|
3414
|
+
function hasSufficientAiQuestionQuota(quota, requested) {
|
|
3415
|
+
if (requested <= 0) return false;
|
|
3416
|
+
return (_nullishCoalesce(quota, () => ( 0))) >= requested;
|
|
3417
|
+
}
|
|
3418
|
+
function hasSufficientAiEvalQuota(quota) {
|
|
3419
|
+
return (_nullishCoalesce(quota, () => ( 0))) > 0;
|
|
3420
|
+
}
|
|
3421
|
+
|
|
3422
|
+
// src/navigation.ts
|
|
3423
|
+
function getActiveTab(pathname) {
|
|
3424
|
+
const normalized = pathname.toLowerCase();
|
|
3425
|
+
if (normalized.startsWith("/contests") || normalized.startsWith("/contest")) {
|
|
3426
|
+
return "contests";
|
|
3427
|
+
}
|
|
3428
|
+
if (normalized.startsWith("/courses") || normalized.startsWith("/course") || normalized.startsWith("/exams")) {
|
|
3429
|
+
return "courses";
|
|
3430
|
+
}
|
|
3431
|
+
if (normalized.startsWith("/profile") || normalized.startsWith("/dashboard") || normalized.startsWith("/edit-profile")) {
|
|
3432
|
+
return "profile";
|
|
3433
|
+
}
|
|
3434
|
+
if (normalized.startsWith("/learn") || normalized.startsWith("/practice") || normalized.startsWith("/questions") || normalized.startsWith("/question") || normalized.startsWith("/bank") || normalized.startsWith("/question-bank") || normalized.startsWith("/packs") || normalized.startsWith("/pack") || normalized.startsWith("/taxonomy") || normalized.startsWith("/explore")) {
|
|
3435
|
+
return "learn";
|
|
1590
3436
|
}
|
|
3437
|
+
return "home";
|
|
3438
|
+
}
|
|
3439
|
+
function getCanonicalPath(pathname) {
|
|
3440
|
+
const normalized = pathname.toLowerCase();
|
|
3441
|
+
if (normalized === "/explore/questions") return "/learn/questions";
|
|
3442
|
+
if (normalized === "/explore/packs") return "/learn/packs";
|
|
3443
|
+
if (normalized === "/question-bank") return "/learn/bank";
|
|
3444
|
+
if (normalized === "/contest/all") return "/contests";
|
|
3445
|
+
if (normalized === "/dashboard") return "/profile";
|
|
3446
|
+
if (normalized === "/edit-profile") return "/profile/edit";
|
|
3447
|
+
return pathname;
|
|
3448
|
+
}
|
|
3449
|
+
function isAuthGatedRoute(pathname) {
|
|
3450
|
+
const normalized = pathname.toLowerCase();
|
|
3451
|
+
const isProtectedPath = normalized.includes("/exam") || normalized.includes("/enroll") || normalized.startsWith("/profile") || normalized.startsWith("/dashboard") || normalized.startsWith("/edit-profile") || normalized.startsWith("/avatar-creator") || normalized.startsWith("/practice");
|
|
3452
|
+
return isProtectedPath;
|
|
1591
3453
|
}
|
|
1592
3454
|
|
|
1593
3455
|
// src/utils/bangla-numbers.ts
|
|
@@ -1600,15 +3462,51 @@ function engToBanglaNumber(num) {
|
|
|
1600
3462
|
}
|
|
1601
3463
|
|
|
1602
3464
|
// src/utils/format-curriculum.ts
|
|
1603
|
-
function
|
|
1604
|
-
if (
|
|
3465
|
+
function extractBilingualName(name, language) {
|
|
3466
|
+
if (!name) return "";
|
|
3467
|
+
const trimmed = name.trim();
|
|
3468
|
+
const match = trimmed.match(/^(.*?)\s*[\(\[(]\s*([^\)\])]+)\s*[\)\])]\s*$/);
|
|
3469
|
+
if (!match) {
|
|
3470
|
+
return trimmed;
|
|
3471
|
+
}
|
|
3472
|
+
const part1 = _optionalChain([match, 'access', _211 => _211[1], 'optionalAccess', _212 => _212.trim, 'call', _213 => _213()]) || "";
|
|
3473
|
+
const part2 = _optionalChain([match, 'access', _214 => _214[2], 'optionalAccess', _215 => _215.trim, 'call', _216 => _216()]) || "";
|
|
3474
|
+
if (!part1 && !part2) return trimmed;
|
|
3475
|
+
if (!part1) return part2;
|
|
3476
|
+
if (!part2) return part1;
|
|
3477
|
+
const hasBengali = (text) => /[\u0980-\u09FF]/.test(text);
|
|
3478
|
+
const isPart1Bengali = hasBengali(part1);
|
|
3479
|
+
const isPart2Bengali = hasBengali(part2);
|
|
3480
|
+
let banglaPart = part1;
|
|
3481
|
+
let englishPart = part2;
|
|
3482
|
+
if (!isPart1Bengali && isPart2Bengali) {
|
|
3483
|
+
banglaPart = part2;
|
|
3484
|
+
englishPart = part1;
|
|
3485
|
+
} else {
|
|
3486
|
+
banglaPart = part1;
|
|
3487
|
+
englishPart = part2;
|
|
3488
|
+
}
|
|
3489
|
+
const lang = _optionalChain([language, 'optionalAccess', _217 => _217.toLowerCase, 'call', _218 => _218()]);
|
|
3490
|
+
if (lang === "en") {
|
|
3491
|
+
return englishPart || banglaPart || trimmed;
|
|
3492
|
+
}
|
|
3493
|
+
if (lang === "bn") {
|
|
3494
|
+
return banglaPart || englishPart || trimmed;
|
|
3495
|
+
}
|
|
3496
|
+
return trimmed;
|
|
3497
|
+
}
|
|
3498
|
+
function formatCurriculumName(idString, dbName, language) {
|
|
3499
|
+
if (dbName) {
|
|
3500
|
+
return extractBilingualName(dbName, language);
|
|
3501
|
+
}
|
|
1605
3502
|
if (!idString) return "";
|
|
1606
3503
|
const namePart = _nullishCoalesce(idString.split("::")[0], () => ( ""));
|
|
1607
3504
|
const clean = namePart.replace(/[-_]/g, " ");
|
|
1608
|
-
|
|
3505
|
+
const formatted = clean.split(/\s+/).map((word) => {
|
|
1609
3506
|
if (!word) return "";
|
|
1610
3507
|
return word.charAt(0).toUpperCase() + word.slice(1);
|
|
1611
3508
|
}).join(" ");
|
|
3509
|
+
return extractBilingualName(formatted, language);
|
|
1612
3510
|
}
|
|
1613
3511
|
|
|
1614
3512
|
// src/utils/relative-time.ts
|
|
@@ -1674,6 +3572,199 @@ function processLatexText(str) {
|
|
|
1674
3572
|
return result;
|
|
1675
3573
|
}
|
|
1676
3574
|
|
|
3575
|
+
// src/utils/time.ts
|
|
3576
|
+
function convertToBangladeshTime(isoString, locale = "en-GB") {
|
|
3577
|
+
const options = {
|
|
3578
|
+
year: "numeric",
|
|
3579
|
+
month: "long",
|
|
3580
|
+
day: "numeric",
|
|
3581
|
+
hour: "numeric",
|
|
3582
|
+
minute: "numeric",
|
|
3583
|
+
hour12: true
|
|
3584
|
+
};
|
|
3585
|
+
const date = new Date(isoString);
|
|
3586
|
+
const resolvedLocale = locale === "bn" ? "bn-BD" : locale;
|
|
3587
|
+
return date.toLocaleString(resolvedLocale, {
|
|
3588
|
+
...options,
|
|
3589
|
+
timeZone: "Asia/Dhaka"
|
|
3590
|
+
});
|
|
3591
|
+
}
|
|
3592
|
+
function getDhakaNow() {
|
|
3593
|
+
const now = /* @__PURE__ */ new Date();
|
|
3594
|
+
const parts = new Intl.DateTimeFormat("en-CA", {
|
|
3595
|
+
timeZone: "Asia/Dhaka",
|
|
3596
|
+
year: "numeric",
|
|
3597
|
+
month: "2-digit",
|
|
3598
|
+
day: "2-digit",
|
|
3599
|
+
hour: "2-digit",
|
|
3600
|
+
minute: "2-digit",
|
|
3601
|
+
second: "2-digit",
|
|
3602
|
+
hour12: false
|
|
3603
|
+
}).formatToParts(now);
|
|
3604
|
+
const get = (type) => _nullishCoalesce(_optionalChain([parts, 'access', _219 => _219.find, 'call', _220 => _220((p) => p.type === type), 'optionalAccess', _221 => _221.value]), () => ( "00"));
|
|
3605
|
+
return /* @__PURE__ */ new Date(`${get("year")}-${get("month")}-${get("day")}T${get("hour")}:${get("minute")}:${get("second")}`);
|
|
3606
|
+
}
|
|
3607
|
+
function calculateTimeLeft(endTime) {
|
|
3608
|
+
const target = new Date(endTime).getTime();
|
|
3609
|
+
const now = (/* @__PURE__ */ new Date()).getTime();
|
|
3610
|
+
const difference = target - now;
|
|
3611
|
+
if (difference <= 0 || isNaN(difference)) {
|
|
3612
|
+
return {
|
|
3613
|
+
days: 0,
|
|
3614
|
+
hours: 0,
|
|
3615
|
+
minutes: 0,
|
|
3616
|
+
seconds: 0,
|
|
3617
|
+
isEnded: true
|
|
3618
|
+
};
|
|
3619
|
+
}
|
|
3620
|
+
return {
|
|
3621
|
+
days: Math.floor(difference / (1e3 * 60 * 60 * 24)),
|
|
3622
|
+
hours: Math.floor(difference / (1e3 * 60 * 60) % 24),
|
|
3623
|
+
minutes: Math.floor(difference / 1e3 / 60 % 60),
|
|
3624
|
+
seconds: Math.floor(difference / 1e3 % 60),
|
|
3625
|
+
isEnded: false
|
|
3626
|
+
};
|
|
3627
|
+
}
|
|
3628
|
+
function formatDate(date, locale = "en-GB") {
|
|
3629
|
+
const d = typeof date === "string" ? new Date(date) : date;
|
|
3630
|
+
return d.toLocaleDateString(locale, {
|
|
3631
|
+
day: "2-digit",
|
|
3632
|
+
month: "short",
|
|
3633
|
+
year: "numeric"
|
|
3634
|
+
});
|
|
3635
|
+
}
|
|
3636
|
+
|
|
3637
|
+
// src/utils/currency.ts
|
|
3638
|
+
function formatBDT(amount) {
|
|
3639
|
+
return amount.toLocaleString("en-US");
|
|
3640
|
+
}
|
|
3641
|
+
|
|
3642
|
+
// src/utils/url.ts
|
|
3643
|
+
function getYouTubeId(url) {
|
|
3644
|
+
if (!url) return null;
|
|
3645
|
+
const regExp = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|[?&]v=)([^#&?]*).*/;
|
|
3646
|
+
const match = url.match(regExp);
|
|
3647
|
+
return match && _optionalChain([match, 'access', _222 => _222[2], 'optionalAccess', _223 => _223.length]) === 11 ? match[2] : null;
|
|
3648
|
+
}
|
|
3649
|
+
|
|
3650
|
+
// src/utils/file.ts
|
|
3651
|
+
function sanitizeFileName(name) {
|
|
3652
|
+
return name.replace(/[\s,]+/g, "_");
|
|
3653
|
+
}
|
|
3654
|
+
|
|
3655
|
+
// src/utils/guards.ts
|
|
3656
|
+
function isQuestionLevel(value) {
|
|
3657
|
+
return [
|
|
3658
|
+
"One",
|
|
3659
|
+
"Two",
|
|
3660
|
+
"Three",
|
|
3661
|
+
"Four",
|
|
3662
|
+
"Five",
|
|
3663
|
+
"Six",
|
|
3664
|
+
"Seven",
|
|
3665
|
+
"Eight",
|
|
3666
|
+
"SSC",
|
|
3667
|
+
"HSC",
|
|
3668
|
+
"Admission",
|
|
3669
|
+
"HSC+Admission",
|
|
3670
|
+
"BCS"
|
|
3671
|
+
].includes(value);
|
|
3672
|
+
}
|
|
3673
|
+
function isLanguage(value) {
|
|
3674
|
+
return ["Bangla", "English", "Any"].includes(value);
|
|
3675
|
+
}
|
|
3676
|
+
function isDifficulty(value) {
|
|
3677
|
+
return ["Easy", "Medium", "Hard"].includes(value);
|
|
3678
|
+
}
|
|
3679
|
+
function normalizeLevel(value) {
|
|
3680
|
+
if (!value) return "";
|
|
3681
|
+
const clean = value.trim().replace(/\s+/g, "+");
|
|
3682
|
+
const upper = clean.toUpperCase();
|
|
3683
|
+
if (upper === "SSC" || upper.includes("CLASS_9") || upper.includes("CLASS_10")) return "SSC";
|
|
3684
|
+
if (upper === "HSC" || upper === "ADMISSION" || upper === "HSC+ADMISSION" || upper.includes("CLASS_11") || upper.includes("CLASS_12")) return "HSC+Admission";
|
|
3685
|
+
if (upper === "BCS") return "BCS";
|
|
3686
|
+
return clean;
|
|
3687
|
+
}
|
|
3688
|
+
|
|
3689
|
+
|
|
3690
|
+
|
|
3691
|
+
|
|
3692
|
+
|
|
3693
|
+
|
|
3694
|
+
|
|
3695
|
+
|
|
3696
|
+
|
|
3697
|
+
|
|
3698
|
+
|
|
3699
|
+
|
|
3700
|
+
|
|
3701
|
+
|
|
3702
|
+
|
|
3703
|
+
|
|
3704
|
+
|
|
3705
|
+
|
|
3706
|
+
|
|
3707
|
+
|
|
3708
|
+
|
|
3709
|
+
|
|
3710
|
+
|
|
3711
|
+
|
|
3712
|
+
|
|
3713
|
+
|
|
3714
|
+
|
|
3715
|
+
|
|
3716
|
+
|
|
3717
|
+
|
|
3718
|
+
|
|
3719
|
+
|
|
3720
|
+
|
|
3721
|
+
|
|
3722
|
+
|
|
3723
|
+
|
|
3724
|
+
|
|
3725
|
+
|
|
3726
|
+
|
|
3727
|
+
|
|
3728
|
+
|
|
3729
|
+
|
|
3730
|
+
|
|
3731
|
+
|
|
3732
|
+
|
|
3733
|
+
|
|
3734
|
+
|
|
3735
|
+
|
|
3736
|
+
|
|
3737
|
+
|
|
3738
|
+
|
|
3739
|
+
|
|
3740
|
+
|
|
3741
|
+
|
|
3742
|
+
|
|
3743
|
+
|
|
3744
|
+
|
|
3745
|
+
|
|
3746
|
+
|
|
3747
|
+
|
|
3748
|
+
|
|
3749
|
+
|
|
3750
|
+
|
|
3751
|
+
|
|
3752
|
+
|
|
3753
|
+
|
|
3754
|
+
|
|
3755
|
+
|
|
3756
|
+
|
|
3757
|
+
|
|
3758
|
+
|
|
3759
|
+
|
|
3760
|
+
|
|
3761
|
+
|
|
3762
|
+
|
|
3763
|
+
|
|
3764
|
+
|
|
3765
|
+
|
|
3766
|
+
|
|
3767
|
+
|
|
1677
3768
|
|
|
1678
3769
|
|
|
1679
3770
|
|
|
@@ -1719,5 +3810,5 @@ function processLatexText(str) {
|
|
|
1719
3810
|
|
|
1720
3811
|
|
|
1721
3812
|
|
|
1722
|
-
exports.AIService = AIService; exports.ContestService = ContestService; exports.CourseService = CourseService; exports.CurriculumService = CurriculumService; exports.MediaService = MediaService; exports.MediaUrlCache = MediaUrlCache; exports.NewsService = NewsService; exports.OrjokClient = OrjokClient; exports.PackService = PackService; exports.ProgressService = ProgressService; exports.QuestionService = QuestionService; exports.UserService = UserService; exports._resetMediaUrlWarning = _resetMediaUrlWarning; exports.aggregateChapterMetrics = aggregateChapterMetrics; exports.aggregateSubjectMetrics = aggregateSubjectMetrics; exports.aggregateTopicMetrics = aggregateTopicMetrics; exports.buildImageAnswer = buildImageAnswer; exports.calculateAccuracy = calculateAccuracy; exports.calculateExamTime = calculateExamTime; exports.computeRatingDelta = computeRatingDelta; exports.createOrjokClient = createOrjokClient; exports.detectQuestionType = detectQuestionType; exports.engToBanglaNumber = engToBanglaNumber; exports.filterQuestionsByMode = filterQuestionsByMode; exports.formatCurriculumName = formatCurriculumName; exports.formatExamTime = formatExamTime; exports.formatQuestionsToCsv = formatQuestionsToCsv; exports.formatQuestionsToText = formatQuestionsToText; exports.getAllTiers = getAllTiers; exports.getEloProgress = getEloProgress; exports.getEloTier = getEloTier; exports.getRatingForSubject = getRatingForSubject; exports.getRelativeTime = getRelativeTime; exports.isImageAnswer = isImageAnswer; exports.isStorageKey = isStorageKey; exports.normalizeDifficulty = normalizeDifficulty; exports.parseCsvQuestions = parseCsvQuestions; exports.parseImageKeys = parseImageKeys; exports.parseTextQuestions = parseTextQuestions; exports.processLatexText = processLatexText; exports.resolveMediaUrl = resolveMediaUrl; exports.resolveMediaUrls = resolveMediaUrls; exports.scoreExam = scoreExam; exports.shuffle = shuffle; exports.shuffleInPlace = shuffleInPlace;
|
|
3813
|
+
exports.AIService = AIService; exports.AI_EVAL_BOOSTER_PACKS = AI_EVAL_BOOSTER_PACKS; exports.AI_QUESTION_BOOSTER_PACKS = AI_QUESTION_BOOSTER_PACKS; exports.CLOTHES_COLORS = CLOTHES_COLORS; exports.COLOR_HUES = COLOR_HUES; exports.ContestService = ContestService; exports.CourseService = CourseService; exports.CurriculumService = CurriculumService; exports.FREE_DAILY_PRACTICE_LIMIT = FREE_DAILY_PRACTICE_LIMIT; exports.HAIR_COLORS = HAIR_COLORS; exports.INITIAL_AVATAR_DATA = INITIAL_AVATAR_DATA; exports.MANUAL_PAYMENT_CONFIG = MANUAL_PAYMENT_CONFIG; exports.MediaService = MediaService; exports.MediaUrlCache = _chunkODXD2WJNcjs.MediaUrlCache; exports.NewsService = NewsService; exports.NotificationService = NotificationService; exports.OrjokClient = OrjokClient; exports.PackService = PackService; exports.ProgressService = ProgressService; exports.QuestionService = QuestionService; exports.RENDER_ORDER = RENDER_ORDER; exports.SUBSCRIPTION_PLANS = SUBSCRIPTION_PLANS; exports.SubscriptionService = SubscriptionService; exports.UserService = UserService; exports.XP_REWARDS = _chunkODXD2WJNcjs.XP_REWARDS; exports.XP_TIERS = _chunkODXD2WJNcjs.XP_TIERS; exports._resetMediaUrlWarning = _chunkODXD2WJNcjs._resetMediaUrlWarning; exports.aggregateChapterMetrics = _chunkODXD2WJNcjs.aggregateChapterMetrics; exports.aggregateSubjectMetrics = _chunkODXD2WJNcjs.aggregateSubjectMetrics; exports.aggregateTopicMetrics = _chunkODXD2WJNcjs.aggregateTopicMetrics; exports.buildImageAnswer = buildImageAnswer; exports.calculateAccuracy = _chunkODXD2WJNcjs.calculateAccuracy; exports.calculateDefaultExamMinutes = calculateDefaultExamMinutes; exports.calculateExamTime = calculateExamTime; exports.calculateStreakFromDates = calculateStreakFromDates; exports.calculateTimeLeft = calculateTimeLeft; exports.calculateUnreadCount = _chunkODXD2WJNcjs.calculateUnreadCount; exports.calculateXpReward = _chunkODXD2WJNcjs.calculateXpReward; exports.canAccessMistakeVault = canAccessMistakeVault; exports.canExportPack = canExportPack; exports.canWatchContestSolution = canWatchContestSolution; exports.checkDailyPracticeLimit = checkDailyPracticeLimit; exports.computeRatingDelta = computeRatingDelta; exports.convertToBangladeshTime = convertToBangladeshTime; exports.createOrjokClient = createOrjokClient; exports.detectQuestionType = detectQuestionType; exports.difficultyOptions = _chunkODXD2WJNcjs.difficultyOptions; exports.engToBanglaNumber = engToBanglaNumber; exports.extractBilingualName = extractBilingualName; exports.filterQuestionsByMode = filterQuestionsByMode; exports.formatBDT = formatBDT; exports.formatCurriculumName = formatCurriculumName; exports.formatDate = formatDate; exports.formatExamTime = formatExamTime; exports.formatLevelUpNotification = _chunkODXD2WJNcjs.formatLevelUpNotification; exports.formatQuestionsToCsv = formatQuestionsToCsv; exports.formatQuestionsToText = formatQuestionsToText; exports.generateRandomAvatarConfig = generateRandomAvatarConfig; exports.generateRandomAvatarState = generateRandomAvatarState; exports.getActiveTab = getActiveTab; exports.getActualOptionFileName = getActualOptionFileName; exports.getAllTiers = getAllTiers; exports.getAllXpTiers = _chunkODXD2WJNcjs.getAllXpTiers; exports.getCanonicalPath = getCanonicalPath; exports.getCycleMultiplier = getCycleMultiplier; exports.getDailyPracticeLimit = getDailyPracticeLimit; exports.getDhakaNow = getDhakaNow; exports.getEloProgress = getEloProgress; exports.getEloTier = getEloTier; exports.getLevelFromXp = _chunkODXD2WJNcjs.getLevelFromXp; exports.getPlanAiQuotas = getPlanAiQuotas; exports.getPlanDiscountPercent = getPlanDiscountPercent; exports.getPlanMonthlyEquivalentPrice = getPlanMonthlyEquivalentPrice; exports.getPlanOriginalPrice = getPlanOriginalPrice; exports.getPlanPrice = getPlanPrice; exports.getPublicExamsByLevel = _chunkODXD2WJNcjs.getPublicExamsByLevel; exports.getRatingForSubject = getRatingForSubject; exports.getRecommendedSubjectsForLevel = getRecommendedSubjectsForLevel; exports.getRelativeTime = getRelativeTime; exports.getTimeOfDayGreeting = getTimeOfDayGreeting; exports.getXpForLevel = _chunkODXD2WJNcjs.getXpForLevel; exports.getXpProgress = _chunkODXD2WJNcjs.getXpProgress; exports.getXpRequiredForNextLevel = _chunkODXD2WJNcjs.getXpRequiredForNextLevel; exports.getXpTier = _chunkODXD2WJNcjs.getXpTier; exports.getYouTubeId = getYouTubeId; exports.hasAiTierAccess = hasAiTierAccess; exports.hasProAccess = hasProAccess; exports.hasSufficientAiEvalQuota = hasSufficientAiEvalQuota; exports.hasSufficientAiQuestionQuota = hasSufficientAiQuestionQuota; exports.isAuthGatedRoute = isAuthGatedRoute; exports.isCorrectAnswer = isCorrectAnswer; exports.isDifficulty = isDifficulty; exports.isDifficultyMatch = _chunkODXD2WJNcjs.isDifficultyMatch; exports.isImageAnswer = isImageAnswer; exports.isLanguage = isLanguage; exports.isLanguageMatch = _chunkODXD2WJNcjs.isLanguageMatch; exports.isQuestionLevel = isQuestionLevel; exports.isStorageKey = _chunkODXD2WJNcjs.isStorageKey; exports.isValidBangladeshiPhone = isValidBangladeshiPhone; exports.isValidMCQ = _chunkODXD2WJNcjs.isValidMCQ; exports.isValidTrxId = isValidTrxId; exports.languageOptions = _chunkODXD2WJNcjs.languageOptions; exports.levelOptions = _chunkODXD2WJNcjs.levelOptions; exports.mapCognitoLevelToStandardLevel = mapCognitoLevelToStandardLevel; exports.mergeNotificationTimeline = _chunkODXD2WJNcjs.mergeNotificationTimeline; exports.normalizeDifficulty = normalizeDifficulty; exports.normalizeLevel = normalizeLevel; exports.paginateWithAccumulator = paginateWithAccumulator; exports.parseAvatarConfig = parseAvatarConfig; exports.parseAvatarConfigWithDefaults = parseAvatarConfigWithDefaults; exports.parseCsvQuestions = parseCsvQuestions; exports.parseImageKeys = parseImageKeys; exports.parseTextQuestions = parseTextQuestions; exports.processLatexText = processLatexText; exports.publicExamOptions = _chunkODXD2WJNcjs.publicExamOptions; exports.reorderObjectKeys = reorderObjectKeys; exports.resolveMediaUrl = _chunkODXD2WJNcjs.resolveMediaUrl; exports.resolveMediaUrls = _chunkODXD2WJNcjs.resolveMediaUrls; exports.sanitizeFileName = sanitizeFileName; exports.scoreExam = scoreExam; exports.serializeAvatarConfig = serializeAvatarConfig; exports.shouldTrackPracticeProgress = shouldTrackPracticeProgress; exports.shuffle = _chunkODXD2WJNcjs.shuffle; exports.shuffleInPlace = _chunkODXD2WJNcjs.shuffleInPlace;
|
|
1723
3814
|
//# sourceMappingURL=index.cjs.map
|