@speakableio/core 0.1.24 → 0.1.25

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/index.js DELETED
@@ -1,2246 +0,0 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }// src/providers/SpeakableProvider.tsx
2
- var _react = require('react');
3
- var _jsxruntime = require('react/jsx-runtime');
4
- var FsCtx = _react.createContext.call(void 0, null);
5
- function SpeakableProvider({
6
- user,
7
- children,
8
- queryClient,
9
- permissions,
10
- fsClient
11
- }) {
12
- const [speakableApi, setSpeakableApi] = _react.useState.call(void 0, null);
13
- _react.useEffect.call(void 0, () => {
14
- setSpeakableApi(fsClient);
15
- }, [fsClient]);
16
- if (!speakableApi) return null;
17
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
18
- FsCtx.Provider,
19
- {
20
- value: {
21
- speakableApi,
22
- queryClient,
23
- user,
24
- permissions
25
- },
26
- children
27
- }
28
- );
29
- }
30
- function useSpeakableApi() {
31
- const ctx = _react.useContext.call(void 0, FsCtx);
32
- if (!ctx) throw new Error("useSpeakableApi must be used within a SpeakableProvider");
33
- return ctx;
34
- }
35
-
36
- // src/utils/error-handler.ts
37
- var ServiceError = class extends Error {
38
- constructor(message, originalError, code) {
39
- super(message);
40
- this.originalError = originalError;
41
- this.code = code;
42
- this.name = "ServiceError";
43
- }
44
- };
45
- function withErrorHandler(fn, serviceName) {
46
- return async (...args) => {
47
- try {
48
- return await fn(...args);
49
- } catch (error) {
50
- if (error instanceof Error && "code" in error) {
51
- const firebaseError = error;
52
- throw new ServiceError(
53
- `Error in ${serviceName}: ${firebaseError.message}`,
54
- error,
55
- firebaseError.code
56
- );
57
- }
58
- if (error instanceof Error) {
59
- throw new ServiceError(`Error in ${serviceName}: ${error.message}`, error);
60
- }
61
- throw new ServiceError(`Unknown error in ${serviceName}`, error);
62
- }
63
- };
64
- }
65
-
66
- // src/lib/firebase/api.ts
67
- var FirebaseAPI = class _FirebaseAPI {
68
- // eslint-disable-next-line @typescript-eslint/no-empty-function
69
- constructor() {
70
- this.config = null;
71
- }
72
- static getInstance() {
73
- if (!_FirebaseAPI.instance) {
74
- _FirebaseAPI.instance = new _FirebaseAPI();
75
- }
76
- return _FirebaseAPI.instance;
77
- }
78
- initialize(config) {
79
- this.config = config;
80
- }
81
- get db() {
82
- if (!this.config) throw new Error("Firebase API not initialized");
83
- return this.config.db;
84
- }
85
- get helpers() {
86
- if (!this.config) throw new Error("Firebase API not initialized");
87
- return this.config.helpers;
88
- }
89
- httpsCallable(functionName) {
90
- var _a;
91
- return (_a = this.config) == null ? void 0 : _a.httpsCallable(functionName);
92
- }
93
- logEvent(name, data) {
94
- var _a;
95
- (_a = this.config) == null ? void 0 : _a.logEvent(name, data);
96
- }
97
- accessQueryConstraints() {
98
- const { query, orderBy, limit, startAt, startAfter, endAt, endBefore } = this.helpers;
99
- return {
100
- query,
101
- orderBy,
102
- limit,
103
- startAt,
104
- startAfter,
105
- endAt,
106
- endBefore
107
- };
108
- }
109
- accessHelpers() {
110
- const { doc, collection, writeBatch, serverTimestamp, setDoc } = this.helpers;
111
- return {
112
- doc: (path) => doc(this.db, path),
113
- collection: (path) => collection(this.db, path),
114
- writeBatch: () => writeBatch(this.db),
115
- serverTimestamp,
116
- setDoc
117
- };
118
- }
119
- async getDoc(path) {
120
- const { getDoc, doc } = this.helpers;
121
- const docRef = doc(this.db, path);
122
- const docSnap = await getDoc(docRef);
123
- const data = docSnap.exists() ? {
124
- id: docSnap.id,
125
- ...docSnap.data()
126
- } : null;
127
- return {
128
- id: docSnap.id,
129
- data
130
- };
131
- }
132
- async getDocs(path, ...queryConstraints) {
133
- const { getDocs, query, collection } = this.helpers;
134
- const collectionRef = collection(this.db, path);
135
- const q = queryConstraints.length > 0 ? query(collectionRef, ...queryConstraints) : collectionRef;
136
- const querySnapshot = await getDocs(q);
137
- const data = querySnapshot.docs.map((doc) => ({
138
- id: doc.id,
139
- data: doc.data()
140
- }));
141
- return {
142
- data,
143
- querySnapshot
144
- };
145
- }
146
- async addDoc(path, data) {
147
- const { addDoc, collection } = this.helpers;
148
- const collectionRef = collection(this.db, path);
149
- const docRef = await addDoc(collectionRef, data);
150
- return {
151
- id: docRef.id,
152
- ...data
153
- };
154
- }
155
- async setDoc(path, data, options = {}) {
156
- const { setDoc, doc } = this.helpers;
157
- const docRef = doc(this.db, path);
158
- await setDoc(docRef, data, options);
159
- }
160
- async updateDoc(path, data) {
161
- const { updateDoc, doc } = this.helpers;
162
- const docRef = doc(this.db, path);
163
- await updateDoc(docRef, data);
164
- }
165
- async deleteDoc(path) {
166
- const { deleteDoc, doc } = this.helpers;
167
- const docRef = doc(this.db, path);
168
- await deleteDoc(docRef);
169
- }
170
- async runTransaction(updateFunction) {
171
- const { runTransaction } = this.helpers;
172
- return runTransaction(this.db, updateFunction);
173
- }
174
- async runBatch(operations) {
175
- const { writeBatch } = this.helpers;
176
- const batch = writeBatch(this.db);
177
- await Promise.all(operations.map((op) => op()));
178
- await batch.commit();
179
- }
180
- writeBatch() {
181
- const { writeBatch } = this.helpers;
182
- const batch = writeBatch(this.db);
183
- return batch;
184
- }
185
- };
186
- var api = FirebaseAPI.getInstance();
187
-
188
- // src/domains/assignment/assignment.constants.ts
189
- var ASSIGNMENT_ANALYTICS_TYPES = [
190
- "macro" /* Macro */,
191
- "gradebook" /* Gradebook */,
192
- "cards" /* Cards */,
193
- "student" /* Student */,
194
- "student_summary" /* StudentSummary */
195
- ];
196
- var ASSIGNMENTS_COLLECTION = "assignments";
197
- var ANALYTICS_SUBCOLLECTION = "analytics";
198
- var SCORES_SUBCOLLECTION = "scores";
199
- var refsAssignmentFiresotre = {
200
- allAssignments: () => ASSIGNMENTS_COLLECTION,
201
- assignment: (params) => `${ASSIGNMENTS_COLLECTION}/${params.id}`,
202
- assignmentAllAnalytics: (params) => `${ASSIGNMENTS_COLLECTION}/${params.id}/${ANALYTICS_SUBCOLLECTION}`,
203
- assignmentAnalytics: (params) => `${ASSIGNMENTS_COLLECTION}/${params.id}/${ANALYTICS_SUBCOLLECTION}/${params.type}`,
204
- assignmentScores: (params) => `${ASSIGNMENTS_COLLECTION}/${params.id}/${SCORES_SUBCOLLECTION}/${params.userId}`
205
- };
206
-
207
- // src/domains/assignment/services/get-assignments-score.service.ts
208
- var _getAssignmentScores = async ({
209
- assignmentId,
210
- analyticType = "macro" /* Macro */,
211
- studentId,
212
- currentUserId
213
- }) => {
214
- if (analyticType === "student" /* Student */) {
215
- const path = refsAssignmentFiresotre.assignmentScores({
216
- id: assignmentId,
217
- userId: currentUserId
218
- });
219
- const response = await api.getDoc(path);
220
- return { scores: response.data, id: assignmentId };
221
- }
222
- if (analyticType === "student_summary" /* StudentSummary */ && studentId) {
223
- const path = refsAssignmentFiresotre.assignmentScores({
224
- id: assignmentId,
225
- userId: studentId
226
- });
227
- const response = await api.getDoc(path);
228
- return { scores: response.data, id: assignmentId };
229
- }
230
- if (analyticType !== "all" /* All */ && ASSIGNMENT_ANALYTICS_TYPES.includes(analyticType)) {
231
- const ref = refsAssignmentFiresotre.assignmentAnalytics({
232
- id: assignmentId,
233
- type: analyticType
234
- });
235
- const docData = await api.getDoc(ref);
236
- return { scores: docData.data, id: assignmentId };
237
- } else if (analyticType === "all" /* All */) {
238
- const ref = refsAssignmentFiresotre.assignmentAllAnalytics({ id: assignmentId });
239
- const response = await api.getDocs(ref);
240
- const data = response.data.reduce((acc, curr) => {
241
- acc[curr.id] = curr;
242
- return acc;
243
- }, {});
244
- return { scores: data, id: assignmentId };
245
- }
246
- };
247
- var getAssignmentScores = withErrorHandler(_getAssignmentScores, "getAssignmentScores");
248
-
249
- // src/domains/assignment/services/attach-score-assignment.service.ts
250
- var _attachScoresAssignment = async ({
251
- assignments,
252
- analyticType,
253
- studentId,
254
- currentUserId
255
- }) => {
256
- const scoresPromises = assignments.map((a) => {
257
- return getAssignmentScores({
258
- assignmentId: a.id,
259
- analyticType,
260
- studentId,
261
- currentUserId
262
- });
263
- });
264
- const scores = await Promise.all(scoresPromises);
265
- const scoresObject = scores.reduce((acc, curr) => {
266
- acc[curr.id] = curr.scores;
267
- return acc;
268
- }, {});
269
- const assignmentsWithScores = assignments.map((a) => {
270
- var _a;
271
- return {
272
- ...a,
273
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/ban-ts-comment
274
- // @ts-ignore
275
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
276
- scores: (_a = scoresObject[a.id]) != null ? _a : null
277
- };
278
- });
279
- return assignmentsWithScores;
280
- };
281
- var attachScoresAssignment = withErrorHandler(
282
- _attachScoresAssignment,
283
- "attachScoresAssignment"
284
- );
285
-
286
- // src/domains/assignment/services/get-all-assignment.service.ts
287
- async function _getAllAssignments() {
288
- const path = refsAssignmentFiresotre.allAssignments();
289
- const response = await api.getDocs(path);
290
- return response.data;
291
- }
292
- var getAllAssignments = withErrorHandler(_getAllAssignments, "getAllAssignments");
293
-
294
- // src/domains/assignment/utils/check-assignment-availability.ts
295
- var _dayjs = require('dayjs'); var _dayjs2 = _interopRequireDefault(_dayjs);
296
- var checkAssignmentAvailability = (scheduledTime) => {
297
- if (!scheduledTime) return true;
298
- const scheduledDate = typeof scheduledTime === "string" ? _dayjs2.default.call(void 0, scheduledTime) : _dayjs2.default.call(void 0, scheduledTime.toDate());
299
- if (!scheduledDate.isValid()) return true;
300
- return _dayjs2.default.call(void 0, ).isAfter(scheduledDate);
301
- };
302
-
303
- // src/domains/assignment/services/get-assignment.service.ts
304
- async function _getAssignment(params) {
305
- var _a;
306
- const path = refsAssignmentFiresotre.assignment({ id: params.assignmentId });
307
- const response = await api.getDoc(path);
308
- if (!response.data) return null;
309
- const assignment = response.data;
310
- const isAvailable = checkAssignmentAvailability(assignment.scheduledTime);
311
- const assignmentWithId = {
312
- ...assignment,
313
- isAvailable,
314
- id: params.assignmentId,
315
- scheduledTime: (_a = assignment.scheduledTime) != null ? _a : null
316
- };
317
- if (params.analyticType) {
318
- const assignmentsWithScores = await attachScoresAssignment({
319
- assignments: [assignmentWithId],
320
- analyticType: params.analyticType,
321
- currentUserId: params.currentUserId
322
- });
323
- return assignmentsWithScores.length > 0 ? assignmentsWithScores[0] : assignmentWithId;
324
- }
325
- return assignmentWithId;
326
- }
327
- var getAssignment = withErrorHandler(_getAssignment, "getAssignment");
328
-
329
- // src/domains/assignment/assignment.repo.ts
330
- var createAssignmentRepo = () => {
331
- return {
332
- getAssignment,
333
- attachScoresAssignment,
334
- getAssignmentScores,
335
- getAllAssignments
336
- };
337
- };
338
-
339
- // src/domains/assignment/hooks/assignment.hooks.ts
340
- var _reactquery = require('@tanstack/react-query');
341
- var assignmentQueryKeys = {
342
- all: ["assignments"],
343
- byId: (id) => [...assignmentQueryKeys.all, id],
344
- list: () => [...assignmentQueryKeys.all, "list"]
345
- };
346
- function useAssignment({
347
- assignmentId,
348
- enabled = true,
349
- analyticType,
350
- userId
351
- }) {
352
- const { speakableApi } = useSpeakableApi();
353
- return _reactquery.useQuery.call(void 0, {
354
- queryKey: assignmentQueryKeys.byId(assignmentId),
355
- queryFn: () => speakableApi.assignmentRepo.getAssignment({
356
- assignmentId,
357
- analyticType,
358
- currentUserId: userId
359
- }),
360
- enabled
361
- });
362
- }
363
-
364
- // src/domains/cards/card.hooks.ts
365
-
366
-
367
-
368
- // src/domains/cards/card.constants.ts
369
- var FeedbackTypesCard = /* @__PURE__ */ ((FeedbackTypesCard2) => {
370
- FeedbackTypesCard2["SuggestedResponse"] = "suggested_response";
371
- FeedbackTypesCard2["Wida"] = "wida";
372
- FeedbackTypesCard2["GrammarInsights"] = "grammar_insights";
373
- FeedbackTypesCard2["Actfl"] = "actfl";
374
- FeedbackTypesCard2["ProficiencyLevel"] = "proficiency_level";
375
- return FeedbackTypesCard2;
376
- })(FeedbackTypesCard || {});
377
- var LeniencyCard = /* @__PURE__ */ ((LeniencyCard2) => {
378
- LeniencyCard2["CONFIDENCE"] = "confidence";
379
- LeniencyCard2["EASY"] = "easy";
380
- LeniencyCard2["NORMAL"] = "normal";
381
- LeniencyCard2["HARD"] = "hard";
382
- return LeniencyCard2;
383
- })(LeniencyCard || {});
384
- var LENIENCY_OPTIONS = [
385
- {
386
- label: "Build Confidence - most lenient",
387
- value: "confidence" /* CONFIDENCE */
388
- },
389
- {
390
- label: "Very Lenient",
391
- value: "easy" /* EASY */
392
- },
393
- {
394
- label: "Normal",
395
- value: "normal" /* NORMAL */
396
- },
397
- {
398
- label: "No leniency - most strict",
399
- value: "hard" /* HARD */
400
- }
401
- ];
402
- var STUDENT_LEVELS_OPTIONS = [
403
- {
404
- label: "Beginner",
405
- description: "Beginner Level: Just starting out. Can say a few basic words and phrases.",
406
- value: "beginner"
407
- },
408
- {
409
- label: "Elementary",
410
- description: "Elementary Level: Can understand simple sentences and have very basic conversations.",
411
- value: "elementary"
412
- },
413
- {
414
- label: "Intermediate",
415
- description: "Intermediate Level: Can talk about everyday topics and handle common situations.",
416
- value: "intermediate"
417
- },
418
- {
419
- label: "Advanced",
420
- description: "Advanced Level: Can speak and understand with ease, and explain ideas clearly.",
421
- value: "advanced"
422
- },
423
- {
424
- label: "Fluent",
425
- description: "Fluent Level: Speaks naturally and easily. Can use the language in work or school settings.",
426
- value: "fluent"
427
- },
428
- {
429
- label: "Native-like",
430
- description: "Native-like Level: Understands and speaks like a native. Can discuss complex ideas accurately.",
431
- value: "nativeLike"
432
- }
433
- ];
434
- var BASE_RESPOND_FIELD_VALUES = {
435
- title: "",
436
- allowRetries: true,
437
- respondTime: 180,
438
- maxCharacters: 1e3
439
- };
440
- var BASE_REPEAT_FIELD_VALUES = {
441
- repeat: 1
442
- };
443
- var BASE_MULTIPLE_CHOICE_FIELD_VALUES = {
444
- MCQType: "single",
445
- answer: ["A"],
446
- choices: [
447
- { option: "A", value: "Option A" },
448
- { option: "B", value: "Option B" },
449
- { option: "C", value: "Option C" }
450
- ]
451
- };
452
- var VerificationCardStatus = /* @__PURE__ */ ((VerificationCardStatus2) => {
453
- VerificationCardStatus2["VERIFIED"] = "VERIFIED";
454
- VerificationCardStatus2["WARNING"] = "WARNING";
455
- VerificationCardStatus2["NOT_RECOMMENDED"] = "NOT_RECOMMENDED";
456
- VerificationCardStatus2["NOT_WORKING"] = "NOT_WORKING";
457
- VerificationCardStatus2["NOT_CHECKED"] = "NOT_CHECKED";
458
- return VerificationCardStatus2;
459
- })(VerificationCardStatus || {});
460
- var CARDS_COLLECTION = "flashcards";
461
- var refsCardsFiresotre = {
462
- allCards: CARDS_COLLECTION,
463
- card: (id) => `${CARDS_COLLECTION}/${id}`
464
- };
465
-
466
- // src/domains/cards/services/get-card.service.ts
467
- async function _getCard(params) {
468
- const ref = refsCardsFiresotre.card(params.cardId);
469
- const response = await api.getDoc(ref);
470
- if (!response.data) return null;
471
- return response.data;
472
- }
473
- var getCard = withErrorHandler(_getCard, "getCard");
474
-
475
- // src/domains/cards/services/create-card.service.ts
476
- var _uuid = require('uuid');
477
-
478
- // src/domains/cards/card.model.ts
479
- var CardActivityType = /* @__PURE__ */ ((CardActivityType2) => {
480
- CardActivityType2["READ_REPEAT"] = "READ_REPEAT";
481
- CardActivityType2["VIDEO"] = "VIDEO";
482
- CardActivityType2["TEXT"] = "TEXT";
483
- CardActivityType2["READ_RESPOND"] = "READ_RESPOND";
484
- CardActivityType2["FREE_RESPONSE"] = "FREE_RESPONSE";
485
- CardActivityType2["REPEAT"] = "REPEAT";
486
- CardActivityType2["RESPOND"] = "RESPOND";
487
- CardActivityType2["RESPOND_WRITE"] = "RESPOND_WRITE";
488
- CardActivityType2["TEXT_TO_SPEECH"] = "TEXT_TO_SPEECH";
489
- CardActivityType2["MULTIPLE_CHOICE"] = "MULTIPLE_CHOICE";
490
- CardActivityType2["PODCAST"] = "PODCAST";
491
- CardActivityType2["MEDIA_PAGE"] = "MEDIA_PAGE";
492
- CardActivityType2["WRITE"] = "WRITE";
493
- CardActivityType2["SHORT_ANSWER"] = "SHORT_ANSWER";
494
- CardActivityType2["SHORT_STORY"] = "SHORT_STORY";
495
- CardActivityType2["SPEAK"] = "SPEAK";
496
- CardActivityType2["CONVERSATION"] = "CONVERSATION";
497
- CardActivityType2["CONVERSATION_WRITE"] = "CONVERSATION_WRITE";
498
- CardActivityType2["DIALOGUE"] = "DIALOGUE";
499
- CardActivityType2["INSTRUCTION"] = "INSTRUCTION";
500
- CardActivityType2["LISTEN"] = "LISTEN";
501
- CardActivityType2["READ"] = "READ";
502
- CardActivityType2["ANSWER"] = "ANSWER";
503
- return CardActivityType2;
504
- })(CardActivityType || {});
505
- var RESPOND_CARD_ACTIVITY_TYPES = [
506
- "READ_RESPOND" /* READ_RESPOND */,
507
- "RESPOND" /* RESPOND */,
508
- "RESPOND_WRITE" /* RESPOND_WRITE */,
509
- "FREE_RESPONSE" /* FREE_RESPONSE */
510
- ];
511
- var MULTIPLE_CHOICE_CARD_ACTIVITY_TYPES = ["MULTIPLE_CHOICE" /* MULTIPLE_CHOICE */];
512
- var REPEAT_CARD_ACTIVITY_TYPES = ["READ_REPEAT" /* READ_REPEAT */, "REPEAT" /* REPEAT */];
513
- var RESPOND_WRITE_CARD_ACTIVITY_TYPES = [
514
- "RESPOND_WRITE" /* RESPOND_WRITE */,
515
- "FREE_RESPONSE" /* FREE_RESPONSE */
516
- ];
517
- var RESPOND_AUDIO_CARD_ACTIVITY_TYPES = [
518
- "RESPOND" /* RESPOND */,
519
- "READ_RESPOND" /* READ_RESPOND */
520
- ];
521
- var ALLOWED_CARD_ACTIVITY_TYPES_FOR_SUMMARY = [
522
- "REPEAT" /* REPEAT */,
523
- "RESPOND" /* RESPOND */,
524
- "READ_REPEAT" /* READ_REPEAT */,
525
- "READ_RESPOND" /* READ_RESPOND */,
526
- "FREE_RESPONSE" /* FREE_RESPONSE */,
527
- "RESPOND_WRITE" /* RESPOND_WRITE */,
528
- "MULTIPLE_CHOICE" /* MULTIPLE_CHOICE */
529
- ];
530
-
531
- // src/utils/text-utils.ts
532
- var _jssha1 = require('js-sha1'); var _jssha12 = _interopRequireDefault(_jssha1);
533
- var purify = (word) => {
534
- return word.normalize("NFD").replace(/\/([^" "]*)/g, "").replace(/\([^()]*\)/g, "").replace(/([^()]*)/g, "").replace(/[\u0300-\u036f]/g, "").replace(/[-]/g, " ").replace(/[.,/#!¡¿?؟。,.?$%^&*;:{}=\-_`~()’'…\s]/g, "").replace(/\s\s+/g, " ").toLowerCase().trim();
535
- };
536
- var cleanString = (words) => {
537
- const splitWords = words == null ? void 0 : words.split("+");
538
- if (splitWords && splitWords.length === 1) {
539
- const newWord = purify(words);
540
- return newWord;
541
- } else if (splitWords && splitWords.length > 1) {
542
- const split = splitWords.map((w) => purify(w));
543
- return split;
544
- } else {
545
- return "";
546
- }
547
- };
548
- var getWordHash = (word, language) => {
549
- const cleanedWord = cleanString(word);
550
- const wordHash = _jssha12.default.call(void 0, `${language}-${cleanedWord}`);
551
- console.log("wordHash core library", wordHash);
552
- return wordHash;
553
- };
554
-
555
- // src/domains/cards/services/get-card-verification-status.service.ts
556
- var charactarLanguages = ["zh", "ja", "ko"];
557
- var getVerificationStatus = async (target_text, language) => {
558
- if ((target_text == null ? void 0 : target_text.length) < 3 && !charactarLanguages.includes(language)) {
559
- return "NOT_RECOMMENDED" /* NOT_RECOMMENDED */;
560
- }
561
- const hash = getWordHash(target_text, language);
562
- const response = await api.getDoc(`checked-pronunciations/${hash}`);
563
- try {
564
- if (response.data) {
565
- return processRecord(response.data);
566
- } else {
567
- return "NOT_CHECKED" /* NOT_CHECKED */;
568
- }
569
- } catch (e) {
570
- return "NOT_CHECKED" /* NOT_CHECKED */;
571
- }
572
- };
573
- var processRecord = (data) => {
574
- const { pronunciations = 0, fails = 0 } = data;
575
- const attempts = pronunciations + fails;
576
- const successRate = attempts > 0 ? pronunciations / attempts * 100 : 0;
577
- let newStatus = null;
578
- if (attempts < 6) {
579
- return "NOT_CHECKED" /* NOT_CHECKED */;
580
- }
581
- if (successRate > 25) {
582
- newStatus = "VERIFIED" /* VERIFIED */;
583
- } else if (successRate > 10) {
584
- newStatus = "WARNING" /* WARNING */;
585
- } else if (fails > 20 && successRate < 10 && pronunciations > 1) {
586
- newStatus = "NOT_RECOMMENDED" /* NOT_RECOMMENDED */;
587
- } else if (pronunciations === 0 && fails > 20) {
588
- newStatus = "NOT_WORKING" /* NOT_WORKING */;
589
- } else {
590
- newStatus = "NOT_CHECKED" /* NOT_CHECKED */;
591
- }
592
- return newStatus;
593
- };
594
-
595
- // src/domains/cards/services/create-card.service.ts
596
- async function _createCard({ data }) {
597
- const response = await api.addDoc(refsCardsFiresotre.allCards, data);
598
- return response;
599
- }
600
- var createCard = withErrorHandler(_createCard, "createCard");
601
- async function _createCards({ cards }) {
602
- const { writeBatch, doc } = api.accessHelpers();
603
- const batch = writeBatch();
604
- const cardsWithId = [];
605
- for (const card of cards) {
606
- const cardId = _uuid.v4.call(void 0, );
607
- const ref = doc(refsCardsFiresotre.card(cardId));
608
- const newCardObject = {
609
- ...card,
610
- id: cardId
611
- };
612
- if (card.type === "READ_REPEAT" /* READ_REPEAT */ && card.target_text && card.language) {
613
- const verificationStatus = await getVerificationStatus(card.target_text, card.language);
614
- newCardObject.verificationStatus = verificationStatus || null;
615
- }
616
- cardsWithId.push(newCardObject);
617
- batch.set(ref, newCardObject);
618
- }
619
- await batch.commit();
620
- return cardsWithId;
621
- }
622
- var createCards = withErrorHandler(_createCards, "createCards");
623
-
624
- // src/domains/cards/card.hooks.ts
625
- var cardsQueryKeys = {
626
- all: ["cards"],
627
- one: (params) => [...cardsQueryKeys.all, params.cardId]
628
- };
629
- function useCards({
630
- cardIds,
631
- enabled = true,
632
- asObject
633
- }) {
634
- const queries = _reactquery.useQueries.call(void 0, {
635
- queries: cardIds.map((cardId) => ({
636
- enabled: enabled && cardIds.length > 0,
637
- queryKey: cardsQueryKeys.one({
638
- cardId
639
- }),
640
- queryFn: () => getCard({ cardId })
641
- }))
642
- });
643
- const cards = queries.map((query) => query.data).filter(Boolean);
644
- const cardsObject = _react.useMemo.call(void 0, () => {
645
- if (!asObject) return null;
646
- return cards.reduce((acc, card) => {
647
- acc[card.id] = card;
648
- return acc;
649
- }, {});
650
- }, [asObject, cards]);
651
- return {
652
- cards,
653
- cardsObject,
654
- cardsQueries: queries
655
- };
656
- }
657
- function useCreateCard() {
658
- const { queryClient } = useSpeakableApi();
659
- const mutationCreateCard = _reactquery.useMutation.call(void 0, {
660
- mutationFn: createCard,
661
- onSuccess: (cardCreated) => {
662
- queryClient.invalidateQueries({ queryKey: cardsQueryKeys.one({ cardId: cardCreated.id }) });
663
- }
664
- });
665
- return {
666
- mutationCreateCard
667
- };
668
- }
669
- function useCreateCards() {
670
- const mutationCreateCards = _reactquery.useMutation.call(void 0, {
671
- mutationFn: createCards
672
- });
673
- return {
674
- mutationCreateCards
675
- };
676
- }
677
- function getCardFromCache({
678
- cardId,
679
- queryClient
680
- }) {
681
- return queryClient.getQueryData(cardsQueryKeys.one({ cardId }));
682
- }
683
- function updateCardInCache({
684
- cardId,
685
- card,
686
- queryClient
687
- }) {
688
- queryClient.setQueryData(cardsQueryKeys.one({ cardId }), card);
689
- }
690
-
691
- // src/domains/cards/card.repo.ts
692
- var createCardRepo = () => {
693
- return {
694
- createCard,
695
- createCards,
696
- getCard
697
- };
698
- };
699
-
700
- // src/domains/sets/set.hooks.ts
701
-
702
-
703
- // src/domains/sets/set.constants.ts
704
- var SETS_COLLECTION = "sets";
705
- var refsSetsFirestore = {
706
- allSets: SETS_COLLECTION,
707
- set: (id) => `${SETS_COLLECTION}/${id}`
708
- };
709
-
710
- // src/domains/sets/services/get-set.service.ts
711
- async function _getSet({ setId }) {
712
- const response = await api.getDoc(refsSetsFirestore.set(setId));
713
- return response.data;
714
- }
715
- var getSet = withErrorHandler(_getSet, "getSet");
716
-
717
- // src/domains/sets/set.hooks.ts
718
- var setsQueryKeys = {
719
- all: ["sets"],
720
- one: (params) => [...setsQueryKeys.all, params.setId]
721
- };
722
- var useSet = ({ setId, enabled }) => {
723
- return _reactquery.useQuery.call(void 0, {
724
- queryKey: setsQueryKeys.one({ setId }),
725
- queryFn: () => getSet({ setId }),
726
- enabled: setId !== void 0 && setId !== "" && enabled
727
- });
728
- };
729
- function getSetFromCache({
730
- setId,
731
- queryClient
732
- }) {
733
- if (!setId) return null;
734
- return queryClient.getQueryData(setsQueryKeys.one({ setId }));
735
- }
736
- function updateSetInCache({
737
- set,
738
- queryClient
739
- }) {
740
- const { id, ...setData } = set;
741
- queryClient.setQueryData(setsQueryKeys.one({ setId: id }), setData);
742
- }
743
-
744
- // src/domains/sets/set.repo.ts
745
- var createSetRepo = () => {
746
- return {
747
- getSet
748
- };
749
- };
750
-
751
- // src/domains/notification/notification.constants.ts
752
- var SPEAKABLE_NOTIFICATIONS = {
753
- NEW_ASSIGNMENT: "new_assignment",
754
- ASSESSMENT_SUBMITTED: "assessment_submitted",
755
- ASSESSMENT_SCORED: "assessment_scored",
756
- NEW_COMMENT: "NEW_COMMENT"
757
- };
758
- var SpeakableNotificationTypes = {
759
- NEW_ASSIGNMENT: "NEW_ASSIGNMENT",
760
- FEEDBACK_FROM_TEACHER: "FEEDBACK_FROM_TEACHER",
761
- MESSAGE_FROM_STUDENT: "MESSAGE_FROM_STUDENT",
762
- PHRASE_MARKED_CORRECT: "PHRASE_MARKED_CORRECT",
763
- STUDENT_PROGRESS: "STUDENT_PROGRESS",
764
- PLAYLIST_FOLLOWERS: "PLAYLIST_FOLLOWERS",
765
- PLAYLIST_PLAYS: "PLAYLIST_PLAYS",
766
- // New notifications
767
- ASSESSMENT_SUBMITTED: "ASSESSMENT_SUBMITTED",
768
- // Notification FOR TEACHER when student submits assessment
769
- ASSESSMENT_SCORED: "ASSESSMENT_SCORED",
770
- // Notification FOR STUDENT when teacher scores assessment
771
- // Comment
772
- NEW_COMMENT: "NEW_COMMENT"
773
- };
774
-
775
- // src/domains/notification/services/create-notification.service.ts
776
-
777
-
778
- // src/constants/web.constants.ts
779
- var WEB_BASE_URL = "https://app.speakable.io";
780
-
781
- // src/lib/firebase/firebase-functions.ts
782
- var SpeakableFirebaseFunctions = {
783
- updateAssignmentGradebookStatus: api.httpsCallable("updateAssignmentGradebookStatus"),
784
- onSetOpened: api.httpsCallable("onSetOpened"),
785
- updateAlgoliaIndex: api.httpsCallable("updateAlgoliaIndex"),
786
- submitAssignmentToGoogleClassroomV2: api.httpsCallable("submitAssignmentToGoogleClassroomV2"),
787
- submitLTIAssignmentScore: api.httpsCallable("submitLTIAssignmentScore"),
788
- submitAssignmentV2: api.httpsCallable("submitLTIAssignmentScoreV2"),
789
- submitAssessment: api.httpsCallable("submitAssessment"),
790
- sendAssessmentScoredEmail: api.httpsCallable("sendAssessmentScoredEmail"),
791
- createNotification: api.httpsCallable("createNotificationV2"),
792
- updateCourseAnalytics: api.httpsCallable("handleCouresAnalyticsEvent")
793
- };
794
-
795
- // src/domains/notification/services/send-notification.service.ts
796
- var _sendNotification = async (sendTo, notification) => {
797
- var _a, _b;
798
- const results = await ((_b = (_a = SpeakableFirebaseFunctions).createNotification) == null ? void 0 : _b.call(_a, {
799
- sendTo,
800
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
801
- notification
802
- }));
803
- return results;
804
- };
805
- var sendNotification = withErrorHandler(_sendNotification, "sendNotification");
806
-
807
- // src/domains/notification/services/create-notification.service.ts
808
- var createNotification = async ({
809
- data,
810
- type,
811
- userId,
812
- profile
813
- }) => {
814
- let result;
815
- switch (type) {
816
- case SPEAKABLE_NOTIFICATIONS.NEW_ASSIGNMENT:
817
- result = await handleAssignNotifPromise({ data, profile });
818
- break;
819
- case SPEAKABLE_NOTIFICATIONS.ASSESSMENT_SUBMITTED:
820
- result = await createAssessmentSubmissionNotification({
821
- data,
822
- profile,
823
- userId
824
- });
825
- break;
826
- case SPEAKABLE_NOTIFICATIONS.ASSESSMENT_SCORED:
827
- result = await createAssessmentScoredNotification({
828
- data,
829
- profile
830
- });
831
- break;
832
- default:
833
- result = null;
834
- break;
835
- }
836
- return result;
837
- };
838
- var handleAssignNotifPromise = async ({
839
- data: assignments,
840
- profile
841
- }) => {
842
- if (!assignments.length) return;
843
- try {
844
- const notifsPromises = assignments.map(async (assignment) => {
845
- const {
846
- section,
847
- section: { members },
848
- ...rest
849
- } = assignment;
850
- if (!section || !members) throw new Error("Invalid assignment data");
851
- const data = { section, sendTo: members, assignment: { ...rest } };
852
- return createNewAssignmentNotification({ data, profile });
853
- });
854
- await Promise.all(notifsPromises);
855
- return {
856
- success: true,
857
- message: "Assignment notifications sent successfully"
858
- };
859
- } catch (error) {
860
- console.error("Error in handleAssignNotifPromise:", error);
861
- throw error;
862
- }
863
- };
864
- var createNewAssignmentNotification = async ({
865
- data,
866
- profile
867
- }) => {
868
- var _a;
869
- const { assignment, sendTo } = data;
870
- const teacherName = profile.displayName || "Your teacher";
871
- const dueDate = assignment.dueDateTimestamp ? _dayjs2.default.call(void 0, assignment.dueDateTimestamp.toDate()).format("MMM Do") : null;
872
- const results = await sendNotification(sendTo, {
873
- courseId: assignment.courseId,
874
- type: SPEAKABLE_NOTIFICATIONS.NEW_ASSIGNMENT,
875
- senderName: teacherName,
876
- link: `${WEB_BASE_URL}/assignment/${assignment.id}`,
877
- messagePreview: `A new assignment "${assignment.name}" is now available. ${dueDate ? `Due ${dueDate}` : ""}`,
878
- title: "New Assignment Available!",
879
- imageUrl: (_a = profile.image) == null ? void 0 : _a.url
880
- });
881
- return results;
882
- };
883
- var createAssessmentSubmissionNotification = async ({
884
- data: assignment,
885
- profile,
886
- userId
887
- }) => {
888
- var _a;
889
- const studentName = profile.displayName || "Your student";
890
- const results = await sendNotification(assignment.owners, {
891
- courseId: assignment.courseId,
892
- type: SPEAKABLE_NOTIFICATIONS.ASSESSMENT_SUBMITTED,
893
- link: `${WEB_BASE_URL}/a/${assignment.id}?studentId=${userId}`,
894
- title: `Assessment Submitted!`,
895
- senderName: studentName,
896
- messagePreview: `${studentName} has submitted the assessment "${assignment.name}"`,
897
- imageUrl: (_a = profile.image) == null ? void 0 : _a.url
898
- });
899
- return results;
900
- };
901
- var createAssessmentScoredNotification = async ({
902
- data,
903
- profile
904
- }) => {
905
- var _a, _b, _c, _d;
906
- const { assignment, sendTo } = data;
907
- const teacherName = profile.displayName || "Your teacher";
908
- const title = `${assignment.isAssessment ? "Assessment" : "Assignment"} Reviewed!`;
909
- const messagePreview = `Your ${assignment.isAssessment ? "assessment" : "assignment"} has been reviewed by your teacher. Click to view the feedback.`;
910
- const results = await sendNotification(sendTo, {
911
- courseId: assignment.courseId,
912
- type: SPEAKABLE_NOTIFICATIONS.ASSESSMENT_SCORED,
913
- link: `${WEB_BASE_URL}/assignment/${assignment.id}`,
914
- title,
915
- messagePreview,
916
- imageUrl: (_a = profile.image) == null ? void 0 : _a.url,
917
- senderName: teacherName
918
- });
919
- await ((_d = (_c = SpeakableFirebaseFunctions).sendAssessmentScoredEmail) == null ? void 0 : _d.call(_c, {
920
- assessmentTitle: assignment.name,
921
- link: `${WEB_BASE_URL}/assignment/${assignment.id}`,
922
- senderImage: ((_b = profile.image) == null ? void 0 : _b.url) || "",
923
- studentId: sendTo[0],
924
- teacherName: profile.displayName
925
- }));
926
- return results;
927
- };
928
-
929
- // src/domains/notification/hooks/notification.hooks.ts
930
- var notificationQueryKeys = {
931
- all: ["notifications"],
932
- byId: (id) => [...notificationQueryKeys.all, id]
933
- };
934
- var useCreateNotification = () => {
935
- const { user, queryClient } = useSpeakableApi();
936
- const handleCreateNotifications = async (type, data) => {
937
- var _a, _b;
938
- const result = await createNotification({
939
- type,
940
- userId: user.auth.uid,
941
- profile: (_a = user == null ? void 0 : user.profile) != null ? _a : {},
942
- data
943
- });
944
- queryClient.invalidateQueries({
945
- queryKey: notificationQueryKeys.byId((_b = user == null ? void 0 : user.auth.uid) != null ? _b : "")
946
- });
947
- return result;
948
- };
949
- return {
950
- createNotification: handleCreateNotifications
951
- };
952
- };
953
-
954
- // src/lib/create-firebase-client.ts
955
- function createFsClientBase({
956
- db,
957
- helpers,
958
- httpsCallable,
959
- logEvent
960
- }) {
961
- const dbAsFirestore = db;
962
- api.initialize({
963
- db: dbAsFirestore,
964
- helpers,
965
- httpsCallable,
966
- logEvent
967
- });
968
- return {
969
- assignmentRepo: createAssignmentRepo(),
970
- cardRepo: createCardRepo()
971
- };
972
- }
973
-
974
- // src/domains/assignment/hooks/score-hooks.ts
975
-
976
-
977
- // src/utils/debounce.utils.ts
978
- function debounce(func, waitFor) {
979
- let timeoutId;
980
- return (...args) => new Promise((resolve, reject) => {
981
- if (timeoutId) {
982
- clearTimeout(timeoutId);
983
- }
984
- timeoutId = setTimeout(async () => {
985
- try {
986
- const result = await func(...args);
987
- resolve(result);
988
- } catch (error) {
989
- reject(error);
990
- }
991
- }, waitFor);
992
- });
993
- }
994
-
995
- // src/lib/tanstack/handle-optimistic-update-query.ts
996
- var handleOptimisticUpdate = async ({
997
- queryClient,
998
- queryKey,
999
- newData
1000
- }) => {
1001
- await queryClient.cancelQueries({
1002
- queryKey
1003
- });
1004
- const previousData = queryClient.getQueryData(queryKey);
1005
- if (previousData === void 0) {
1006
- queryClient.setQueryData(queryKey, newData);
1007
- } else {
1008
- queryClient.setQueryData(queryKey, { ...previousData, ...newData });
1009
- }
1010
- return { previousData };
1011
- };
1012
-
1013
- // src/constants/speakable-plans.ts
1014
- var FEEDBACK_PLANS = {
1015
- FEEDBACK_TRANSCRIPT: "FEEDBACK_TRANSCRIPT",
1016
- // Transcript from the audio
1017
- FEEDBACK_SUMMARY: "FEEDBACK_SUMMARY",
1018
- // Chatty summary (Free plan)
1019
- FEEDBACK_GRAMMAR_INSIGHTS: "FEEDBACK_GRAMMAR_INSIGHTS",
1020
- // Grammar insights
1021
- FEEDBACK_SUGGESTED_RESPONSE: "FEEDBACK_SUGGESTED_RESPONSE",
1022
- // Suggested Response
1023
- FEEDBACK_RUBRIC: "FEEDBACK_RUBRIC",
1024
- // Suggested Response
1025
- FEEDBACK_GRADING_STANDARDS: "FEEDBACK_GRADING_STANDARDS",
1026
- // ACTFL / WIDA Estimate
1027
- FEEDBACK_TARGET_LANGUAGE: "FEEDBACK_TARGET_LANGUAGE",
1028
- // Ability to set the feedback language to the target language of the student
1029
- FEEDBACK_DISABLE_ALLOW_RETRIES: "FEEDBACK_DISABLE_ALLOW_RETRIES"
1030
- // Turn of allow retries
1031
- };
1032
- var AUTO_GRADING_PLANS = {
1033
- AUTO_GRADING_PASS_FAIL: "AUTO_GRADING_PASS_FAIL",
1034
- // Pass / fail grading
1035
- AUTO_GRADING_RUBRICS: "AUTO_GRADING_RUBRICS",
1036
- // Autograded rubrics
1037
- AUTO_GRADING_STANDARDS_BASED: "AUTO_GRADING_STANDARDS_BASED"
1038
- // Standards based grading
1039
- };
1040
- var AI_ASSISTANT_PLANS = {
1041
- AI_ASSISTANT_DOCUMENT_UPLOADS: "AI_ASSISTANT_DOCUMENT_UPLOADS",
1042
- // Allow document uploading
1043
- AI_ASSISTANT_UNLIMITED_USE: "AI_ASSISTANT_UNLIMITED_USE"
1044
- // Allow unlimited use of AI assistant. Otherwise, limits are used.
1045
- };
1046
- var ASSIGNMENT_SETTINGS_PLANS = {
1047
- ASSESSMENTS: "ASSESSMENTS",
1048
- // Ability to create assessment assignment types
1049
- GOOGLE_CLASSROOM_GRADE_PASSBACK: "GOOGLE_CLASSROOM_GRADE_PASSBACK"
1050
- // Assignment scores can sync with classroom
1051
- };
1052
- var ANALYTICS_PLANS = {
1053
- ANALYTICS_GRADEBOOK: "ANALYTICS_GRADEBOOK",
1054
- // Access to the gradebook page
1055
- ANALYTICS_CLASSROOM_ANALYTICS: "ANALYTICS_CLASSROOM_ANALYTICS",
1056
- // Access to the classroom analytics page
1057
- ANALYTICS_STUDENT_PROGRESS_REPORTS: "ANALYTICS_STUDENT_PROGRESS_REPORTS",
1058
- // Access to the panel that shows an individual student's progress and assignments
1059
- ANALYTICS_ASSIGNMENT_RESULTS: "ANALYTICS_ASSIGNMENT_RESULTS",
1060
- // Access to the assigment RESULTS page
1061
- ANALYTICS_ORGANIZATION: "ANALYTICS_ORGANIZATION"
1062
- // Access to the organization analytics panel (for permitted admins)
1063
- };
1064
- var SPACES_PLANS = {
1065
- SPACES_CREATE_SPACE: "SPACES_CREATE_SPACE",
1066
- // Ability to create spaces
1067
- SPACES_CHECK_POINTS: "SPACES_CHECK_POINTS"
1068
- // Feature not available yet. Ability to create checkpoints for spaces for data aggregation
1069
- };
1070
- var DISCOVER_PLANS = {
1071
- DISCOVER_ORGANIZATION_LIBRARY: "DISCOVER_ORGANIZATION_LIBRARY"
1072
- // Access to the organizations shared library
1073
- };
1074
- var MEDIA_AREA_PLANS = {
1075
- MEDIA_AREA_DOCUMENT_UPLOAD: "MEDIA_AREA_DOCUMENT_UPLOAD",
1076
- MEDIA_AREA_AUDIO_FILES: "MEDIA_AREA_AUDIO_FILES"
1077
- };
1078
- var FREE_PLAN = [];
1079
- var TEACHER_PRO_PLAN = [
1080
- FEEDBACK_PLANS.FEEDBACK_TRANSCRIPT,
1081
- FEEDBACK_PLANS.FEEDBACK_SUMMARY,
1082
- FEEDBACK_PLANS.FEEDBACK_TARGET_LANGUAGE,
1083
- AUTO_GRADING_PLANS.AUTO_GRADING_PASS_FAIL,
1084
- ANALYTICS_PLANS.ANALYTICS_GRADEBOOK,
1085
- SPACES_PLANS.SPACES_CREATE_SPACE
1086
- // AUTO_GRADING_PLANS.AUTO_GRADING_STANDARDS_BASED,
1087
- ];
1088
- var SCHOOL_STARTER = [
1089
- FEEDBACK_PLANS.FEEDBACK_TRANSCRIPT,
1090
- FEEDBACK_PLANS.FEEDBACK_SUMMARY,
1091
- FEEDBACK_PLANS.FEEDBACK_GRAMMAR_INSIGHTS,
1092
- FEEDBACK_PLANS.FEEDBACK_SUGGESTED_RESPONSE,
1093
- FEEDBACK_PLANS.FEEDBACK_RUBRIC,
1094
- FEEDBACK_PLANS.FEEDBACK_GRADING_STANDARDS,
1095
- FEEDBACK_PLANS.FEEDBACK_DISABLE_ALLOW_RETRIES,
1096
- FEEDBACK_PLANS.FEEDBACK_TARGET_LANGUAGE,
1097
- AUTO_GRADING_PLANS.AUTO_GRADING_PASS_FAIL,
1098
- AUTO_GRADING_PLANS.AUTO_GRADING_RUBRICS,
1099
- AUTO_GRADING_PLANS.AUTO_GRADING_STANDARDS_BASED,
1100
- AI_ASSISTANT_PLANS.AI_ASSISTANT_DOCUMENT_UPLOADS,
1101
- AI_ASSISTANT_PLANS.AI_ASSISTANT_UNLIMITED_USE,
1102
- // ASSIGNMENT_SETTINGS_PLANS.ASSESSMENTS,
1103
- ASSIGNMENT_SETTINGS_PLANS.GOOGLE_CLASSROOM_GRADE_PASSBACK,
1104
- ANALYTICS_PLANS.ANALYTICS_GRADEBOOK,
1105
- ANALYTICS_PLANS.ANALYTICS_STUDENT_PROGRESS_REPORTS,
1106
- ANALYTICS_PLANS.ANALYTICS_CLASSROOM_ANALYTICS,
1107
- // ANALYTICS_PLANS.ANALYTICS_ORGANIZATION,
1108
- SPACES_PLANS.SPACES_CREATE_SPACE,
1109
- SPACES_PLANS.SPACES_CHECK_POINTS,
1110
- // DISCOVER_PLANS.DISCOVER_ORGANIZATION_LIBRARY,
1111
- MEDIA_AREA_PLANS.MEDIA_AREA_DOCUMENT_UPLOAD,
1112
- MEDIA_AREA_PLANS.MEDIA_AREA_AUDIO_FILES
1113
- ];
1114
- var ORGANIZATION_PLAN = [
1115
- FEEDBACK_PLANS.FEEDBACK_TRANSCRIPT,
1116
- FEEDBACK_PLANS.FEEDBACK_SUMMARY,
1117
- FEEDBACK_PLANS.FEEDBACK_GRAMMAR_INSIGHTS,
1118
- FEEDBACK_PLANS.FEEDBACK_SUGGESTED_RESPONSE,
1119
- FEEDBACK_PLANS.FEEDBACK_RUBRIC,
1120
- FEEDBACK_PLANS.FEEDBACK_GRADING_STANDARDS,
1121
- FEEDBACK_PLANS.FEEDBACK_DISABLE_ALLOW_RETRIES,
1122
- FEEDBACK_PLANS.FEEDBACK_TARGET_LANGUAGE,
1123
- AUTO_GRADING_PLANS.AUTO_GRADING_PASS_FAIL,
1124
- AUTO_GRADING_PLANS.AUTO_GRADING_RUBRICS,
1125
- AUTO_GRADING_PLANS.AUTO_GRADING_STANDARDS_BASED,
1126
- AI_ASSISTANT_PLANS.AI_ASSISTANT_DOCUMENT_UPLOADS,
1127
- AI_ASSISTANT_PLANS.AI_ASSISTANT_UNLIMITED_USE,
1128
- ASSIGNMENT_SETTINGS_PLANS.ASSESSMENTS,
1129
- ASSIGNMENT_SETTINGS_PLANS.GOOGLE_CLASSROOM_GRADE_PASSBACK,
1130
- ANALYTICS_PLANS.ANALYTICS_GRADEBOOK,
1131
- ANALYTICS_PLANS.ANALYTICS_STUDENT_PROGRESS_REPORTS,
1132
- ANALYTICS_PLANS.ANALYTICS_CLASSROOM_ANALYTICS,
1133
- ANALYTICS_PLANS.ANALYTICS_ORGANIZATION,
1134
- SPACES_PLANS.SPACES_CREATE_SPACE,
1135
- SPACES_PLANS.SPACES_CHECK_POINTS,
1136
- DISCOVER_PLANS.DISCOVER_ORGANIZATION_LIBRARY,
1137
- MEDIA_AREA_PLANS.MEDIA_AREA_DOCUMENT_UPLOAD,
1138
- MEDIA_AREA_PLANS.MEDIA_AREA_AUDIO_FILES
1139
- ];
1140
- var SpeakablePlanTypes = {
1141
- basic: "basic",
1142
- teacher_pro: "teacher_pro",
1143
- school_starter: "school_starter",
1144
- organization: "organization",
1145
- // OLD PLANS
1146
- starter: "starter",
1147
- growth: "growth",
1148
- professional: "professional"
1149
- };
1150
- var SpeakablePermissionsMap = {
1151
- [SpeakablePlanTypes.basic]: FREE_PLAN,
1152
- [SpeakablePlanTypes.starter]: TEACHER_PRO_PLAN,
1153
- [SpeakablePlanTypes.teacher_pro]: TEACHER_PRO_PLAN,
1154
- [SpeakablePlanTypes.growth]: ORGANIZATION_PLAN,
1155
- [SpeakablePlanTypes.professional]: ORGANIZATION_PLAN,
1156
- [SpeakablePlanTypes.organization]: ORGANIZATION_PLAN,
1157
- [SpeakablePlanTypes.school_starter]: SCHOOL_STARTER
1158
- };
1159
- var SpeakablePlanHierarchy = [
1160
- SpeakablePlanTypes.basic,
1161
- SpeakablePlanTypes.starter,
1162
- SpeakablePlanTypes.teacher_pro,
1163
- SpeakablePlanTypes.growth,
1164
- SpeakablePlanTypes.professional,
1165
- SpeakablePlanTypes.school_starter,
1166
- SpeakablePlanTypes.organization
1167
- ];
1168
-
1169
- // src/hooks/usePermissions.ts
1170
- var usePermissions = () => {
1171
- const { permissions } = useSpeakableApi();
1172
- const has = (permission) => {
1173
- var _a;
1174
- return (_a = permissions.permissions) == null ? void 0 : _a.includes(permission);
1175
- };
1176
- return {
1177
- plan: permissions.plan,
1178
- permissionsLoaded: permissions.loaded,
1179
- isStripePlan: permissions.isStripePlan,
1180
- refreshDate: permissions.refreshDate,
1181
- isInstitutionPlan: permissions.isInstitutionPlan,
1182
- subscriptionId: permissions.subscriptionId,
1183
- contact: permissions.contact,
1184
- hasGradebook: has(ANALYTICS_PLANS.ANALYTICS_GRADEBOOK),
1185
- hasGoogleClassroomGradePassback: has(ASSIGNMENT_SETTINGS_PLANS.GOOGLE_CLASSROOM_GRADE_PASSBACK),
1186
- hasAssessments: has(ASSIGNMENT_SETTINGS_PLANS.ASSESSMENTS),
1187
- hasSectionAnalytics: has(ANALYTICS_PLANS.ANALYTICS_CLASSROOM_ANALYTICS),
1188
- hasStudentReports: has(ANALYTICS_PLANS.ANALYTICS_STUDENT_PROGRESS_REPORTS),
1189
- permissions: permissions || [],
1190
- hasStudentPortfolios: permissions.hasStudentPortfolios,
1191
- isFreeOrgTrial: permissions.type === "free_org_trial",
1192
- freeOrgTrialExpired: permissions.freeOrgTrialExpired
1193
- };
1194
- };
1195
- var usePermissions_default = usePermissions;
1196
-
1197
- // src/hooks/useGoogleClassroom.ts
1198
- var useGoogleClassroom = () => {
1199
- const submitAssignmentToGoogleClassroom = async ({
1200
- assignment,
1201
- scores,
1202
- googleUserId = null
1203
- // optional to override the user's googleUserId
1204
- }) => {
1205
- var _a, _b;
1206
- try {
1207
- const { googleClassroomUserId = null } = scores;
1208
- const googleId = googleUserId || googleClassroomUserId;
1209
- if (!googleId)
1210
- return {
1211
- error: true,
1212
- message: "No Google Classroom ID found"
1213
- };
1214
- const { courseWorkId, maxPoints, owners, courseId } = assignment;
1215
- const draftGrade = (scores == null ? void 0 : scores.score) ? (scores == null ? void 0 : scores.score) / 100 * maxPoints : 0;
1216
- const result = await ((_b = (_a = SpeakableFirebaseFunctions).submitAssignmentToGoogleClassroomV2) == null ? void 0 : _b.call(_a, {
1217
- teacherId: owners[0],
1218
- courseId,
1219
- courseWorkId,
1220
- userId: googleId,
1221
- draftGrade
1222
- }));
1223
- return result;
1224
- } catch (error) {
1225
- return { error: true, message: error.message };
1226
- }
1227
- };
1228
- return {
1229
- submitAssignmentToGoogleClassroom
1230
- };
1231
- };
1232
-
1233
- // src/lib/firebase/firebase-analytics/grading-standard.ts
1234
- var logGradingStandardLog = (data) => {
1235
- var _a, _b;
1236
- if (data.courseId && data.type && data.level) {
1237
- (_b = (_a = SpeakableFirebaseFunctions).updateCourseAnalytics) == null ? void 0 : _b.call(_a, {
1238
- eventType: data.type || "custom",
1239
- level: data.level,
1240
- courseId: data.courseId
1241
- });
1242
- }
1243
- api.logEvent("logGradingStandard", data);
1244
- };
1245
-
1246
- // src/constants/analytics.constants.ts
1247
- var ANALYTICS_EVENT_TYPES = {
1248
- VOICE_SUCCESS: "voice_success",
1249
- VOICE_FAIL: "voice_fail",
1250
- RESPOND_CARD_SUCCESS: "respond_card_success",
1251
- RESPOND_CARD_FAIL: "respond_card_fail",
1252
- RESPOND_WRITE_CARD_SUCCESS: "respond_write_card_success",
1253
- RESPOND_WRITE_CARD_FAIL: "respond_write_card_fail",
1254
- RESPOND_FREE_PLAN: "respond_free_plan",
1255
- RESPOND_WRITE_FREE_PLAN: "respond_write_free_plan",
1256
- SUBMISSION: "assignment_submitted",
1257
- ASSIGNMENT_STARTED: "assignment_started",
1258
- CREATE_ASSIGNMENT: "create_assignment",
1259
- MC_SUCCESS: "multiple_choice_success",
1260
- MC_FAIL: "multiple_choice_fail",
1261
- ACTFL_LEVEL: "actfl_level",
1262
- WIDA_LEVEL: "wida_level"
1263
- };
1264
-
1265
- // src/lib/firebase/firebase-analytics/assignment.ts
1266
- var logOpenAssignment = (data = {}) => {
1267
- api.logEvent("open_assignment", data);
1268
- };
1269
- var logOpenActivityPreview = (data = {}) => {
1270
- api.logEvent("open_activity_preview", data);
1271
- };
1272
- var logSubmitAssignment = (data = {}) => {
1273
- var _a, _b;
1274
- (_b = (_a = SpeakableFirebaseFunctions).updateCourseAnalytics) == null ? void 0 : _b.call(_a, {
1275
- eventType: ANALYTICS_EVENT_TYPES.SUBMISSION,
1276
- ...data
1277
- });
1278
- api.logEvent(ANALYTICS_EVENT_TYPES.SUBMISSION, data);
1279
- };
1280
- var logStartAssignment = (data = {}) => {
1281
- var _a, _b;
1282
- if (data.courseId) {
1283
- (_b = (_a = SpeakableFirebaseFunctions).updateCourseAnalytics) == null ? void 0 : _b.call(_a, {
1284
- eventType: ANALYTICS_EVENT_TYPES.ASSIGNMENT_STARTED,
1285
- ...data
1286
- });
1287
- }
1288
- api.logEvent(ANALYTICS_EVENT_TYPES.ASSIGNMENT_STARTED, data);
1289
- };
1290
-
1291
- // src/domains/assignment/utils/create-default-score.ts
1292
- var defaultScore = (props) => {
1293
- const { serverTimestamp } = api.accessHelpers();
1294
- const score = {
1295
- progress: 0,
1296
- score: 0,
1297
- startDate: serverTimestamp(),
1298
- status: "IN_PROGRESS",
1299
- submitted: false,
1300
- cards: {},
1301
- lastPlayed: serverTimestamp(),
1302
- owners: props.owners,
1303
- userId: props.userId
1304
- };
1305
- if (props.googleClassroomUserId) {
1306
- score.googleClassroomUserId = props.googleClassroomUserId;
1307
- }
1308
- if (props.courseId) {
1309
- score.courseId = props.courseId;
1310
- }
1311
- return score;
1312
- };
1313
-
1314
- // src/domains/assignment/score-practice.constants.ts
1315
- var SCORES_PRACTICE_COLLECTION = "users";
1316
- var SCORES_PRACTICE_SUBCOLLECTION = "practice";
1317
- var refsScoresPractice = {
1318
- practiceScores: (params) => `${SCORES_PRACTICE_COLLECTION}/${params.userId}/${SCORES_PRACTICE_SUBCOLLECTION}/${params.setId}`,
1319
- practiceScoreHistoryRefDoc: (params) => `${SCORES_PRACTICE_COLLECTION}/${params.userId}/${SCORES_PRACTICE_SUBCOLLECTION}/${params.setId}/attempts/${params.date}`
1320
- };
1321
-
1322
- // src/domains/assignment/services/create-score.service.ts
1323
- async function _createScore(params) {
1324
- var _a, _b;
1325
- if (params.isAssignment) {
1326
- const ref = refsAssignmentFiresotre.assignmentScores({
1327
- id: params.activityId,
1328
- userId: params.userId
1329
- });
1330
- await ((_b = (_a = SpeakableFirebaseFunctions).updateAssignmentGradebookStatus) == null ? void 0 : _b.call(_a, {
1331
- assignmentId: params.activityId,
1332
- userId: params.userId,
1333
- status: "IN_PROGRESS",
1334
- score: null
1335
- }));
1336
- await api.setDoc(ref, params.scoreData, { merge: true });
1337
- return {
1338
- id: params.userId
1339
- };
1340
- } else {
1341
- const ref = refsScoresPractice.practiceScores({
1342
- userId: params.userId,
1343
- setId: params.activityId
1344
- });
1345
- await api.setDoc(ref, params.scoreData);
1346
- return {
1347
- id: params.userId
1348
- };
1349
- }
1350
- }
1351
- var createScore = withErrorHandler(_createScore, "createScore");
1352
-
1353
- // src/domains/assignment/services/get-score.service.ts
1354
- async function getAssignmentScore({
1355
- userId,
1356
- assignment,
1357
- googleClassroomUserId
1358
- }) {
1359
- const path = refsAssignmentFiresotre.assignmentScores({
1360
- id: assignment.id,
1361
- userId
1362
- });
1363
- const response = await api.getDoc(path);
1364
- if (response.data == null) {
1365
- const newScore = {
1366
- ...defaultScore({
1367
- owners: [userId],
1368
- userId,
1369
- courseId: assignment.courseId,
1370
- googleClassroomUserId
1371
- }),
1372
- assignmentId: assignment.id
1373
- };
1374
- logStartAssignment({
1375
- courseId: assignment.courseId
1376
- });
1377
- const result = await createScore({
1378
- activityId: assignment.id,
1379
- userId,
1380
- isAssignment: true,
1381
- scoreData: newScore
1382
- });
1383
- return {
1384
- ...newScore,
1385
- id: result.id
1386
- };
1387
- }
1388
- return response.data;
1389
- }
1390
- async function getPracticeScore({ userId, setId }) {
1391
- const path = refsScoresPractice.practiceScores({ userId, setId });
1392
- const response = await api.getDoc(path);
1393
- if (response.data == null) {
1394
- const newScore = {
1395
- ...defaultScore({
1396
- owners: [userId],
1397
- userId
1398
- }),
1399
- setId
1400
- };
1401
- const result = await createScore({
1402
- activityId: setId,
1403
- userId,
1404
- isAssignment: false,
1405
- scoreData: newScore
1406
- });
1407
- return {
1408
- ...newScore,
1409
- id: result.id
1410
- };
1411
- }
1412
- return response.data;
1413
- }
1414
- async function _getScore(params) {
1415
- if (params.isAssignment) {
1416
- return await getAssignmentScore({
1417
- userId: params.userId,
1418
- assignment: {
1419
- id: params.activityId,
1420
- courseId: params.courseId
1421
- },
1422
- googleClassroomUserId: params.googleClassroomUserId
1423
- });
1424
- } else {
1425
- return await getPracticeScore({
1426
- userId: params.userId,
1427
- setId: params.activityId
1428
- });
1429
- }
1430
- }
1431
- var getScore = withErrorHandler(_getScore, "getScore");
1432
-
1433
- // src/domains/assignment/utils/calculateScoreAndProgress.ts
1434
- var calculateScoreAndProgress = (scores, cardsList, weights) => {
1435
- const totalSetPoints = cardsList.reduce((acc, cardId) => {
1436
- acc += (weights == null ? void 0 : weights[cardId]) || 1;
1437
- return acc;
1438
- }, 0);
1439
- const totalPointsAwarded = Object.keys((scores == null ? void 0 : scores.cards) || {}).reduce((acc, cardId) => {
1440
- var _a, _b;
1441
- const cardScores = (_a = scores == null ? void 0 : scores.cards) == null ? void 0 : _a[cardId];
1442
- if ((cardScores == null ? void 0 : cardScores.completed) || (cardScores == null ? void 0 : cardScores.score) || (cardScores == null ? void 0 : cardScores.score) === 0) {
1443
- const score2 = (cardScores == null ? void 0 : cardScores.score) || (cardScores == null ? void 0 : cardScores.score) === 0 ? Number((_b = cardScores == null ? void 0 : cardScores.score) != null ? _b : 0) : null;
1444
- const weight = (weights == null ? void 0 : weights[cardId]) || 1;
1445
- const fraction = (score2 != null ? score2 : 0) / 100;
1446
- if (score2 || score2 === 0) {
1447
- acc += weight * fraction;
1448
- } else {
1449
- acc += weight;
1450
- }
1451
- }
1452
- return acc;
1453
- }, 0);
1454
- const totalCompletedCards = Object.keys((scores == null ? void 0 : scores.cards) || {}).reduce((acc, cardId) => {
1455
- var _a;
1456
- const cardScores = (_a = scores == null ? void 0 : scores.cards) == null ? void 0 : _a[cardId];
1457
- if ((cardScores == null ? void 0 : cardScores.completed) || (cardScores == null ? void 0 : cardScores.score) || (cardScores == null ? void 0 : cardScores.score) === 0) {
1458
- acc += 1;
1459
- }
1460
- return acc;
1461
- }, 0);
1462
- const percent = totalPointsAwarded / totalSetPoints;
1463
- const score = Math.round(percent * 100);
1464
- const progress = Math.round(totalCompletedCards / (cardsList.length || 1) * 100);
1465
- return { score, progress };
1466
- };
1467
- var calculateScoreAndProgress_default = calculateScoreAndProgress;
1468
-
1469
- // src/domains/assignment/services/update-score.service.ts
1470
- async function _updateScore(params) {
1471
- const path = params.isAssignment ? refsAssignmentFiresotre.assignmentScores({
1472
- id: params.activityId,
1473
- userId: params.userId
1474
- }) : refsScoresPractice.practiceScores({
1475
- setId: params.activityId,
1476
- userId: params.userId
1477
- });
1478
- await api.updateDoc(path, {
1479
- ...params.data
1480
- });
1481
- }
1482
- var updateScore = withErrorHandler(_updateScore, "updateScore");
1483
- async function _updateCardScore(params) {
1484
- const path = params.isAssignment ? refsAssignmentFiresotre.assignmentScores({
1485
- id: params.activityId,
1486
- userId: params.userId
1487
- }) : refsScoresPractice.practiceScores({
1488
- setId: params.activityId,
1489
- userId: params.userId
1490
- });
1491
- const updates = Object.keys(params.updates.cardScore).reduce(
1492
- (acc, key) => {
1493
- acc[`cards.${params.cardId}.${key}`] = params.updates.cardScore[key];
1494
- return acc;
1495
- },
1496
- {}
1497
- );
1498
- if (params.updates.progress) {
1499
- updates.progress = params.updates.progress;
1500
- }
1501
- if (params.updates.score) {
1502
- updates.score = params.updates.score;
1503
- }
1504
- await api.updateDoc(path, {
1505
- ...updates
1506
- });
1507
- }
1508
- var updateCardScore = withErrorHandler(_updateCardScore, "updateCardScore");
1509
-
1510
- // src/domains/assignment/services/clear-score.service.ts
1511
-
1512
- async function clearScore(params) {
1513
- var _a, _b, _c, _d, _e;
1514
- const update = {
1515
- [`cards.${params.cardId}`]: {
1516
- attempts: (_a = params.cardScores.attempts) != null ? _a : 1,
1517
- correct: (_b = params.cardScores.correct) != null ? _b : 0,
1518
- // save old score history
1519
- history: [
1520
- {
1521
- ...params.cardScores,
1522
- attempts: (_c = params.cardScores.attempts) != null ? _c : 1,
1523
- correct: (_d = params.cardScores.correct) != null ? _d : 0,
1524
- retryTime: _dayjs2.default.call(void 0, ).format("YYYY-MM-DD HH:mm:ss"),
1525
- history: null
1526
- },
1527
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
1528
- ...(_e = params.cardScores.history) != null ? _e : []
1529
- ]
1530
- }
1531
- };
1532
- const path = params.isAssignment ? refsAssignmentFiresotre.assignmentScores({
1533
- id: params.activityId,
1534
- userId: params.userId
1535
- }) : refsScoresPractice.practiceScores({
1536
- setId: params.activityId,
1537
- userId: params.userId
1538
- });
1539
- await api.updateDoc(path, update);
1540
- return {
1541
- update,
1542
- activityId: params.activityId
1543
- };
1544
- }
1545
-
1546
- // src/domains/assignment/services/submit-assignment-score.service.ts
1547
-
1548
- async function _submitAssignmentScore({
1549
- cardIds,
1550
- assignment,
1551
- setWeights,
1552
- userId,
1553
- status,
1554
- studentName
1555
- }) {
1556
- const { serverTimestamp } = api.accessHelpers();
1557
- const path = refsAssignmentFiresotre.assignmentScores({ id: assignment.id, userId });
1558
- const fieldsUpdated = {
1559
- submitted: true,
1560
- progress: 100,
1561
- submissionDate: serverTimestamp(),
1562
- status
1563
- };
1564
- if (assignment.isAssessment) {
1565
- const result = await handleAssessment(
1566
- assignment,
1567
- userId,
1568
- cardIds,
1569
- setWeights,
1570
- fieldsUpdated,
1571
- studentName
1572
- );
1573
- return result;
1574
- } else if (assignment.courseId) {
1575
- await handleCourseAssignment(assignment, userId);
1576
- }
1577
- await api.updateDoc(path, { ...fieldsUpdated });
1578
- return { success: true, fieldsUpdated };
1579
- }
1580
- var submitAssignmentScore = withErrorHandler(
1581
- _submitAssignmentScore,
1582
- "submitAssignmentScore"
1583
- );
1584
- async function handleAssessment(assignment, userId, cardIds, setWeights, fieldsUpdated, studentName) {
1585
- var _a, _b;
1586
- const path = refsAssignmentFiresotre.assignmentScores({ id: assignment.id, userId });
1587
- const response = await api.getDoc(path);
1588
- if (!response.data) {
1589
- throw new Error("Score not found");
1590
- }
1591
- const { score: scoreCalculated } = calculateScoreAndProgress_default(response.data, cardIds, setWeights);
1592
- await api.updateDoc(path, { score: scoreCalculated, status: "PENDING_REVIEW" });
1593
- await ((_b = (_a = SpeakableFirebaseFunctions).submitAssessment) == null ? void 0 : _b.call(_a, {
1594
- assignmentId: assignment.id,
1595
- assignmentTitle: assignment.name,
1596
- userId,
1597
- teacherId: assignment.owners[0],
1598
- studentName
1599
- }));
1600
- fieldsUpdated.status = "PENDING_REVIEW";
1601
- return { success: true, fieldsUpdated };
1602
- }
1603
- async function handleCourseAssignment(assignment, userId) {
1604
- var _a, _b;
1605
- await ((_b = (_a = SpeakableFirebaseFunctions) == null ? void 0 : _a.submitAssignmentV2) == null ? void 0 : _b.call(_a, {
1606
- assignmentId: assignment.id,
1607
- userId
1608
- }));
1609
- }
1610
- async function submitPracticeScore({
1611
- setId,
1612
- userId,
1613
- scores
1614
- }) {
1615
- const { serverTimestamp } = api.accessHelpers();
1616
- const date = _dayjs2.default.call(void 0, ).format("YYYY-MM-DD-HH-mm");
1617
- const ref = refsScoresPractice.practiceScoreHistoryRefDoc({ setId, userId, date });
1618
- const fieldsUpdated = {
1619
- ...scores,
1620
- submitted: true,
1621
- progress: 100,
1622
- submissionDate: serverTimestamp(),
1623
- status: "SUBMITTED"
1624
- };
1625
- await api.setDoc(ref, { ...fieldsUpdated });
1626
- const refScores = refsScoresPractice.practiceScores({ userId, setId });
1627
- await api.deleteDoc(refScores);
1628
- return { success: true, fieldsUpdated };
1629
- }
1630
-
1631
- // src/domains/assignment/hooks/score-hooks.ts
1632
- var scoreQueryKeys = {
1633
- all: ["scores"],
1634
- byId: (id) => [...scoreQueryKeys.all, id],
1635
- list: () => [...scoreQueryKeys.all, "list"]
1636
- };
1637
- function useScore({
1638
- isAssignment,
1639
- activityId,
1640
- userId = "",
1641
- courseId,
1642
- enabled = true,
1643
- googleClassroomUserId
1644
- }) {
1645
- return _reactquery.useQuery.call(void 0, {
1646
- queryFn: () => getScore({
1647
- userId,
1648
- courseId,
1649
- activityId,
1650
- googleClassroomUserId,
1651
- isAssignment
1652
- }),
1653
- queryKey: scoreQueryKeys.byId(activityId),
1654
- enabled
1655
- });
1656
- }
1657
- var debounceUpdateScore = debounce(updateScore, 1e3);
1658
- function useUpdateScore() {
1659
- const { queryClient } = useSpeakableApi();
1660
- const mutation = _reactquery.useMutation.call(void 0, {
1661
- mutationFn: debounceUpdateScore,
1662
- onMutate: (variables) => {
1663
- return handleOptimisticUpdate({
1664
- queryClient,
1665
- queryKey: scoreQueryKeys.byId(variables.activityId),
1666
- newData: variables.data
1667
- });
1668
- },
1669
- onError: (_, variables, context) => {
1670
- if (context == null ? void 0 : context.previousData)
1671
- queryClient.setQueryData(scoreQueryKeys.byId(variables.activityId), context.previousData);
1672
- },
1673
- onSettled: (_, err, variables) => {
1674
- queryClient.invalidateQueries({
1675
- queryKey: scoreQueryKeys.byId(variables.activityId)
1676
- });
1677
- }
1678
- });
1679
- return {
1680
- mutationUpdateScore: mutation
1681
- };
1682
- }
1683
- function useUpdateCardScore({
1684
- isAssignment,
1685
- activityId,
1686
- userId,
1687
- set
1688
- }) {
1689
- const { queryClient } = useSpeakableApi();
1690
- const queryKey = scoreQueryKeys.byId(activityId);
1691
- const mutation = _reactquery.useMutation.call(void 0, {
1692
- mutationFn: async ({ cardId, cardScore }) => {
1693
- const previousScores = queryClient.getQueryData(queryKey);
1694
- const { progress, score, newScoreUpdated, updatedCardScore } = getScoreUpdated({
1695
- previousScores: previousScores != null ? previousScores : {},
1696
- cardId,
1697
- set,
1698
- cardScore
1699
- });
1700
- await updateCardScore({
1701
- userId,
1702
- cardId,
1703
- isAssignment,
1704
- activityId,
1705
- updates: {
1706
- cardScore: updatedCardScore,
1707
- progress,
1708
- score
1709
- }
1710
- });
1711
- return { cardId, scoresUpdated: newScoreUpdated };
1712
- },
1713
- onMutate: ({ cardId, cardScore }) => {
1714
- queryClient.setQueryData(queryKey, (previousScore) => {
1715
- const updates = handleOptimisticScore({
1716
- score: previousScore,
1717
- cardId,
1718
- cardScore,
1719
- set
1720
- });
1721
- return {
1722
- ...previousScore,
1723
- ...updates
1724
- };
1725
- });
1726
- },
1727
- // eslint-disable-next-line no-unused-vars
1728
- onError: (error) => {
1729
- console.log(error.message);
1730
- const previousData = queryClient.getQueryData(queryKey);
1731
- if (previousData) {
1732
- queryClient.setQueryData(queryKey, previousData);
1733
- }
1734
- }
1735
- });
1736
- return {
1737
- mutationUpdateCardScore: mutation
1738
- };
1739
- }
1740
- var getScoreUpdated = ({
1741
- cardId,
1742
- cardScore,
1743
- previousScores,
1744
- set
1745
- }) => {
1746
- var _a, _b, _c, _d;
1747
- const previousCard = (_a = previousScores.cards) == null ? void 0 : _a[cardId];
1748
- const newCardScore = {
1749
- ...previousCard != null ? previousCard : {},
1750
- ...cardScore
1751
- };
1752
- const newScores = {
1753
- ...previousScores,
1754
- cards: {
1755
- ...(_b = previousScores.cards) != null ? _b : {},
1756
- [cardId]: newCardScore
1757
- }
1758
- };
1759
- const { score, progress } = calculateScoreAndProgress_default(
1760
- newScores,
1761
- (_c = set == null ? void 0 : set.content) != null ? _c : [],
1762
- (_d = set == null ? void 0 : set.weights) != null ? _d : {}
1763
- );
1764
- return {
1765
- newScoreUpdated: newScores,
1766
- updatedCardScore: cardScore,
1767
- score,
1768
- progress
1769
- };
1770
- };
1771
- var handleOptimisticScore = ({
1772
- score,
1773
- cardId,
1774
- cardScore,
1775
- set
1776
- }) => {
1777
- var _a, _b, _c;
1778
- let cards = { ...(_a = score == null ? void 0 : score.cards) != null ? _a : {} };
1779
- cards = {
1780
- ...cards,
1781
- [cardId]: {
1782
- ...cards[cardId],
1783
- ...cardScore
1784
- }
1785
- };
1786
- const { score: scoreValue, progress } = calculateScoreAndProgress_default(
1787
- // @ts-ignore
1788
- {
1789
- ...score != null ? score : {},
1790
- cards
1791
- },
1792
- (_b = set == null ? void 0 : set.content) != null ? _b : [],
1793
- (_c = set == null ? void 0 : set.weights) != null ? _c : {}
1794
- );
1795
- return { cards, score: scoreValue, progress };
1796
- };
1797
- function useClearScore() {
1798
- const { queryClient } = useSpeakableApi();
1799
- const mutation = _reactquery.useMutation.call(void 0, {
1800
- mutationFn: clearScore,
1801
- onSettled: (result) => {
1802
- var _a;
1803
- queryClient.invalidateQueries({
1804
- queryKey: scoreQueryKeys.byId((_a = result == null ? void 0 : result.activityId) != null ? _a : "")
1805
- });
1806
- }
1807
- });
1808
- return {
1809
- mutationClearScore: mutation
1810
- };
1811
- }
1812
- function useSubmitAssignmentScore({
1813
- onAssignmentSubmitted,
1814
- studentName
1815
- }) {
1816
- const { queryClient } = useSpeakableApi();
1817
- const { hasGoogleClassroomGradePassback } = usePermissions_default();
1818
- const { submitAssignmentToGoogleClassroom } = useGoogleClassroom();
1819
- const { createNotification: createNotification2 } = useCreateNotification();
1820
- const mutation = _reactquery.useMutation.call(void 0, {
1821
- mutationFn: async ({
1822
- assignment,
1823
- userId,
1824
- cardIds,
1825
- setWeights,
1826
- scores,
1827
- status
1828
- }) => {
1829
- try {
1830
- const scoreUpdated = await submitAssignmentScore({
1831
- assignment,
1832
- userId,
1833
- cardIds,
1834
- setWeights,
1835
- status,
1836
- studentName
1837
- });
1838
- if (assignment.courseWorkId != null && !assignment.isAssessment && hasGoogleClassroomGradePassback) {
1839
- await submitAssignmentToGoogleClassroom({
1840
- assignment,
1841
- scores
1842
- });
1843
- }
1844
- if (assignment.isAssessment) {
1845
- createNotification2(SpeakableNotificationTypes.ASSESSMENT_SUBMITTED, assignment);
1846
- }
1847
- if (assignment == null ? void 0 : assignment.id) {
1848
- logSubmitAssignment({
1849
- courseId: assignment == null ? void 0 : assignment.courseId
1850
- });
1851
- }
1852
- onAssignmentSubmitted(assignment.id);
1853
- queryClient.setQueryData(scoreQueryKeys.byId(assignment.id), {
1854
- ...scores,
1855
- ...scoreUpdated.fieldsUpdated
1856
- });
1857
- return {
1858
- success: true,
1859
- message: "Score submitted successfully"
1860
- };
1861
- } catch (error) {
1862
- return {
1863
- success: false,
1864
- error
1865
- };
1866
- }
1867
- }
1868
- });
1869
- return {
1870
- submitAssignmentScore: mutation.mutateAsync,
1871
- isLoading: mutation.isPending
1872
- };
1873
- }
1874
- function useSubmitPracticeScore() {
1875
- const { queryClient } = useSpeakableApi();
1876
- const mutation = _reactquery.useMutation.call(void 0, {
1877
- mutationFn: async ({
1878
- setId,
1879
- userId,
1880
- scores
1881
- }) => {
1882
- try {
1883
- await submitPracticeScore({
1884
- setId,
1885
- userId,
1886
- scores
1887
- });
1888
- queryClient.invalidateQueries({
1889
- queryKey: scoreQueryKeys.byId(setId)
1890
- });
1891
- return {
1892
- success: true,
1893
- message: "Score submitted successfully"
1894
- };
1895
- } catch (error) {
1896
- return {
1897
- success: false,
1898
- error
1899
- };
1900
- }
1901
- }
1902
- });
1903
- return {
1904
- submitPracticeScore: mutation.mutateAsync,
1905
- isLoading: mutation.isPending
1906
- };
1907
- }
1908
-
1909
- // src/hooks/useActivity.ts
1910
-
1911
-
1912
- // src/services/add-grading-standard.ts
1913
- var addGradingStandardLog = async (gradingStandard, userId) => {
1914
- logGradingStandardLog(gradingStandard);
1915
- const path = `users/${userId}/grading_standard_logs`;
1916
- await api.addDoc(path, gradingStandard);
1917
- };
1918
-
1919
- // src/hooks/useActivityTracker.ts
1920
-
1921
- function useActivityTracker({ userId }) {
1922
- const trackActivity = async ({
1923
- activityName,
1924
- activityType,
1925
- id = _uuid.v4.call(void 0, ),
1926
- language = ""
1927
- }) => {
1928
- if (userId) {
1929
- const { doc, serverTimestamp, setDoc } = api.accessHelpers();
1930
- const activityRef = doc(`users/${userId}/activity${id}`);
1931
- const timestamp = serverTimestamp();
1932
- await setDoc(activityRef, {
1933
- name: activityName,
1934
- type: activityType,
1935
- lastSeen: timestamp,
1936
- id,
1937
- language
1938
- });
1939
- }
1940
- };
1941
- return {
1942
- trackActivity
1943
- };
1944
- }
1945
-
1946
- // src/hooks/useActivity.ts
1947
- function useActivity({
1948
- id,
1949
- isAssignment,
1950
- onAssignmentSubmitted,
1951
- ltiData
1952
- }) {
1953
- var _a, _b, _c, _d;
1954
- const { queryClient, user } = useSpeakableApi();
1955
- const userId = user.auth.uid;
1956
- const assignmentQuery = useAssignment({
1957
- assignmentId: id,
1958
- userId,
1959
- enabled: isAssignment
1960
- });
1961
- const activeAssignment = assignmentQuery.data;
1962
- const setId = isAssignment ? (_a = activeAssignment == null ? void 0 : activeAssignment.setId) != null ? _a : "" : id;
1963
- const querySet = useSet({ setId });
1964
- const setData = querySet.data;
1965
- const activityId = isAssignment ? (_b = activeAssignment == null ? void 0 : activeAssignment.id) != null ? _b : "" : setId;
1966
- const { cardsObject, cardsQueries, cards } = useCards({
1967
- cardIds: (_c = setData == null ? void 0 : setData.content) != null ? _c : [],
1968
- enabled: querySet.isSuccess,
1969
- asObject: true
1970
- });
1971
- const scoreQuery = useScore({
1972
- isAssignment,
1973
- activityId: id,
1974
- userId,
1975
- courseId: activeAssignment == null ? void 0 : activeAssignment.courseId,
1976
- googleClassroomUserId: user.profile.googleClassroomUserId,
1977
- enabled: isAssignment ? assignmentQuery.isSuccess : querySet.isSuccess
1978
- });
1979
- const { mutationUpdateScore } = useUpdateScore();
1980
- const { mutationUpdateCardScore } = useUpdateCardScore({
1981
- activityId,
1982
- isAssignment,
1983
- userId,
1984
- set: (_d = querySet.data) != null ? _d : void 0
1985
- });
1986
- const { mutationClearScore } = useClearScore();
1987
- const { submitAssignmentScore: submitAssignmentScore2 } = useSubmitAssignmentScore({
1988
- onAssignmentSubmitted,
1989
- studentName: user.profile.displayName
1990
- });
1991
- const { submitPracticeScore: submitPracticeScore2 } = useSubmitPracticeScore();
1992
- const handleUpdateScore = (data) => {
1993
- mutationUpdateScore.mutate({
1994
- data,
1995
- isAssignment,
1996
- activityId,
1997
- userId
1998
- });
1999
- };
2000
- const handleUpdateCardScore = (cardId, cardScore) => {
2001
- mutationUpdateCardScore.mutate({ cardId, cardScore });
2002
- };
2003
- const onClearScore = ({
2004
- cardId,
2005
- wasCompleted = true
2006
- }) => {
2007
- var _a2, _b2;
2008
- const currentCard = cardsObject == null ? void 0 : cardsObject[cardId];
2009
- if ((currentCard == null ? void 0 : currentCard.type) === "MULTIPLE_CHOICE" /* MULTIPLE_CHOICE */ || (currentCard == null ? void 0 : currentCard.type) === "READ_REPEAT" /* READ_REPEAT */) {
2010
- return;
2011
- }
2012
- const queryKeys = scoreQueryKeys.byId(activityId);
2013
- const activeCardScores = (_b2 = (_a2 = queryClient.getQueryData(queryKeys)) == null ? void 0 : _a2.cards) == null ? void 0 : _b2[cardId];
2014
- if (activeCardScores === void 0) return;
2015
- mutationClearScore.mutate({
2016
- isAssignment,
2017
- activityId,
2018
- cardScores: activeCardScores,
2019
- cardId,
2020
- userId
2021
- });
2022
- };
2023
- const onSubmitScore = async () => {
2024
- var _a2, _b2, _c2, _d2, _e, _f, _g, _h, _i, _j, _k, _l;
2025
- try {
2026
- let results;
2027
- if (isAssignment) {
2028
- const cardScores = ((_a2 = scoreQuery.data) == null ? void 0 : _a2.cards) || {};
2029
- const hasPendingReview = Object.values(cardScores).some(
2030
- (cardScore) => cardScore.status === "pending_review"
2031
- );
2032
- results = await submitAssignmentScore2({
2033
- assignment: assignmentQuery.data,
2034
- userId,
2035
- cardIds: (_b2 = setData == null ? void 0 : setData.content) != null ? _b2 : [],
2036
- scores: scoreQuery.data,
2037
- setWeights: (_c2 = setData == null ? void 0 : setData.weights) != null ? _c2 : {},
2038
- status: hasPendingReview ? "PENDING_REVIEW" : "FINALIZED"
2039
- });
2040
- if ((_d2 = assignmentQuery.data) == null ? void 0 : _d2.ltiDeeplink) {
2041
- submitLTIScore({
2042
- maxPoints: (_e = assignmentQuery.data) == null ? void 0 : _e.maxPoints,
2043
- score: (_g = (_f = scoreQuery.data) == null ? void 0 : _f.score) != null ? _g : 0,
2044
- SERVICE_KEY: (_h = ltiData == null ? void 0 : ltiData.serviceKey) != null ? _h : "",
2045
- lineItemId: (_i = ltiData == null ? void 0 : ltiData.lineItemId) != null ? _i : "",
2046
- lti_id: (_j = ltiData == null ? void 0 : ltiData.lti_id) != null ? _j : ""
2047
- });
2048
- }
2049
- } else {
2050
- results = await submitPracticeScore2({
2051
- setId: (_l = (_k = querySet.data) == null ? void 0 : _k.id) != null ? _l : "",
2052
- userId,
2053
- scores: scoreQuery.data
2054
- });
2055
- }
2056
- return results;
2057
- } catch (error) {
2058
- return {
2059
- success: false,
2060
- error
2061
- };
2062
- }
2063
- };
2064
- const logGradingStandardEntry = ({
2065
- cardId,
2066
- gradingStandard,
2067
- type
2068
- }) => {
2069
- var _a2, _b2, _c2, _d2, _e, _f, _g, _h;
2070
- const card = cardsObject == null ? void 0 : cardsObject[cardId];
2071
- const scoresObject = queryClient.getQueryData(scoreQueryKeys.byId(activityId));
2072
- const cardScore = (_a2 = scoresObject == null ? void 0 : scoresObject.cards) == null ? void 0 : _a2[cardId];
2073
- const serverTimestamp = api.helpers.serverTimestamp;
2074
- addGradingStandardLog(
2075
- {
2076
- assignmentId: (_b2 = activeAssignment == null ? void 0 : activeAssignment.id) != null ? _b2 : "",
2077
- courseId: (_c2 = activeAssignment == null ? void 0 : activeAssignment.courseId) != null ? _c2 : "",
2078
- teacherId: (_d2 = activeAssignment == null ? void 0 : activeAssignment.owners[0]) != null ? _d2 : "",
2079
- setId: (_e = setData == null ? void 0 : setData.id) != null ? _e : "",
2080
- cardId,
2081
- level: gradingStandard.level,
2082
- justification: gradingStandard.justification,
2083
- transcript: (_f = cardScore == null ? void 0 : cardScore.transcript) != null ? _f : "",
2084
- audioUrl: (_g = cardScore == null ? void 0 : cardScore.audio) != null ? _g : "",
2085
- prompt: (_h = card == null ? void 0 : card.prompt) != null ? _h : "",
2086
- responseType: (card == null ? void 0 : card.type) === "RESPOND_WRITE" /* RESPOND_WRITE */ ? "written" : "spoken",
2087
- type,
2088
- dateMade: serverTimestamp()
2089
- },
2090
- userId
2091
- );
2092
- };
2093
- _react.useEffect.call(void 0, () => {
2094
- if (isAssignment) {
2095
- logOpenAssignment({ assignmentId: id });
2096
- } else {
2097
- logOpenActivityPreview({ setId: id });
2098
- }
2099
- }, []);
2100
- useInitActivity({
2101
- assignment: activeAssignment != null ? activeAssignment : void 0,
2102
- set: setData != null ? setData : void 0,
2103
- enabled: !!setData,
2104
- userId
2105
- });
2106
- return {
2107
- set: {
2108
- data: setData,
2109
- query: querySet
2110
- },
2111
- cards: {
2112
- data: cardsObject,
2113
- query: cardsQueries,
2114
- cardsArray: cards
2115
- },
2116
- assignment: {
2117
- data: isAssignment ? activeAssignment : void 0,
2118
- query: assignmentQuery
2119
- },
2120
- scores: {
2121
- data: scoreQuery.data,
2122
- query: scoreQuery,
2123
- actions: {
2124
- update: handleUpdateScore,
2125
- clear: onClearScore,
2126
- submit: onSubmitScore,
2127
- updateCard: handleUpdateCardScore,
2128
- logGradingStandardEntry
2129
- }
2130
- }
2131
- };
2132
- }
2133
- var useInitActivity = ({
2134
- assignment,
2135
- set,
2136
- enabled,
2137
- userId
2138
- }) => {
2139
- const { trackActivity } = useActivityTracker({ userId });
2140
- const init = () => {
2141
- var _a, _b, _c, _d, _e;
2142
- if (!enabled) return;
2143
- if (!assignment) {
2144
- trackActivity({
2145
- activityName: (_a = set == null ? void 0 : set.name) != null ? _a : "",
2146
- activityType: "set",
2147
- id: set == null ? void 0 : set.id,
2148
- language: set == null ? void 0 : set.language
2149
- });
2150
- } else if (assignment.name) {
2151
- trackActivity({
2152
- activityName: assignment.name,
2153
- activityType: assignment.isAssessment ? "assessment" : "assignment",
2154
- id: assignment.id,
2155
- language: set == null ? void 0 : set.language
2156
- });
2157
- }
2158
- if (set == null ? void 0 : set.public) {
2159
- (_c = (_b = SpeakableFirebaseFunctions) == null ? void 0 : _b.onSetOpened) == null ? void 0 : _c.call(_b, {
2160
- setId: set.id,
2161
- language: set.language
2162
- });
2163
- }
2164
- (_e = (_d = SpeakableFirebaseFunctions) == null ? void 0 : _d.updateAlgoliaIndex) == null ? void 0 : _e.call(_d, {
2165
- updatePlays: true,
2166
- objectID: set == null ? void 0 : set.id
2167
- });
2168
- };
2169
- _react.useEffect.call(void 0, () => {
2170
- init();
2171
- }, [set]);
2172
- };
2173
- var submitLTIScore = async ({
2174
- maxPoints,
2175
- score,
2176
- SERVICE_KEY,
2177
- lineItemId,
2178
- lti_id
2179
- }) => {
2180
- var _a, _b;
2181
- try {
2182
- if (!SERVICE_KEY || !lineItemId || !lti_id) {
2183
- throw new Error("Missing required LTI credentials");
2184
- }
2185
- const earnedPoints = score ? score / 100 * maxPoints : 0;
2186
- const { data } = await ((_b = (_a = SpeakableFirebaseFunctions) == null ? void 0 : _a.submitLTIAssignmentScore) == null ? void 0 : _b.call(_a, {
2187
- SERVICE_KEY,
2188
- scoreData: {
2189
- lineItemId,
2190
- userId: lti_id,
2191
- maxPoints,
2192
- earnedPoints
2193
- }
2194
- }));
2195
- return { success: true, data };
2196
- } catch (error) {
2197
- console.error("Failed to submit LTI score:", error);
2198
- return {
2199
- success: false,
2200
- error: error instanceof Error ? error : new Error("Unknown error occurred")
2201
- };
2202
- }
2203
- };
2204
-
2205
-
2206
-
2207
-
2208
-
2209
-
2210
-
2211
-
2212
-
2213
-
2214
-
2215
-
2216
-
2217
-
2218
-
2219
-
2220
-
2221
-
2222
-
2223
-
2224
-
2225
-
2226
-
2227
-
2228
-
2229
-
2230
-
2231
-
2232
-
2233
-
2234
-
2235
-
2236
-
2237
-
2238
-
2239
-
2240
-
2241
-
2242
-
2243
-
2244
-
2245
- exports.ALLOWED_CARD_ACTIVITY_TYPES_FOR_SUMMARY = ALLOWED_CARD_ACTIVITY_TYPES_FOR_SUMMARY; exports.BASE_MULTIPLE_CHOICE_FIELD_VALUES = BASE_MULTIPLE_CHOICE_FIELD_VALUES; exports.BASE_REPEAT_FIELD_VALUES = BASE_REPEAT_FIELD_VALUES; exports.BASE_RESPOND_FIELD_VALUES = BASE_RESPOND_FIELD_VALUES; exports.CardActivityType = CardActivityType; exports.FeedbackTypesCard = FeedbackTypesCard; exports.FsCtx = FsCtx; exports.LENIENCY_OPTIONS = LENIENCY_OPTIONS; exports.LeniencyCard = LeniencyCard; exports.MULTIPLE_CHOICE_CARD_ACTIVITY_TYPES = MULTIPLE_CHOICE_CARD_ACTIVITY_TYPES; exports.REPEAT_CARD_ACTIVITY_TYPES = REPEAT_CARD_ACTIVITY_TYPES; exports.RESPOND_AUDIO_CARD_ACTIVITY_TYPES = RESPOND_AUDIO_CARD_ACTIVITY_TYPES; exports.RESPOND_CARD_ACTIVITY_TYPES = RESPOND_CARD_ACTIVITY_TYPES; exports.RESPOND_WRITE_CARD_ACTIVITY_TYPES = RESPOND_WRITE_CARD_ACTIVITY_TYPES; exports.SPEAKABLE_NOTIFICATIONS = SPEAKABLE_NOTIFICATIONS; exports.STUDENT_LEVELS_OPTIONS = STUDENT_LEVELS_OPTIONS; exports.SpeakableNotificationTypes = SpeakableNotificationTypes; exports.SpeakableProvider = SpeakableProvider; exports.VerificationCardStatus = VerificationCardStatus; exports.assignmentQueryKeys = assignmentQueryKeys; exports.cardsQueryKeys = cardsQueryKeys; exports.createAssignmentRepo = createAssignmentRepo; exports.createCardRepo = createCardRepo; exports.createFsClientBase = createFsClientBase; exports.createSetRepo = createSetRepo; exports.getCardFromCache = getCardFromCache; exports.getSetFromCache = getSetFromCache; exports.refsCardsFiresotre = refsCardsFiresotre; exports.refsSetsFirestore = refsSetsFirestore; exports.setsQueryKeys = setsQueryKeys; exports.updateCardInCache = updateCardInCache; exports.updateSetInCache = updateSetInCache; exports.useActivity = useActivity; exports.useAssignment = useAssignment; exports.useCards = useCards; exports.useCreateCard = useCreateCard; exports.useCreateCards = useCreateCards; exports.useCreateNotification = useCreateNotification; exports.useSet = useSet; exports.useSpeakableApi = useSpeakableApi;
2246
- //# sourceMappingURL=index.js.map